Sfoglia il codice sorgente

Merge commit 'bf95f89d580858f9aaa5a09ec9bc1b0b0c410ef7' into wlan-cld3.driver.lnx.2.0

Change-Id: I0923b31931ebf99ef4d3a717bba279e8bade0dfb
Linux Build Service Account 6 anni fa
parent
commit
ee4ea408f6
84 ha cambiato i file con 45463 aggiunte e 473 eliminazioni
  1. 2781 0
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h
  2. 302 0
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_cfg.h
  3. 1091 0
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h
  4. 181 0
      components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ucfg.h
  5. 2183 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c
  6. 3135 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c
  7. 3463 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c
  8. 583 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h
  9. 742 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c
  10. 1763 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c
  11. 1173 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_1x1_dbs_i.h
  12. 154 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_2g_1x1_5g.h
  13. 154 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_5g_1x1_2g.h
  14. 1394 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_i.h
  15. 900 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_no_dbs_i.h
  16. 146 0
      components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c
  17. 4 1
      components/mlme/core/inc/wlan_mlme_main.h
  18. 27 3
      components/mlme/core/src/wlan_mlme_main.c
  19. 2 0
      components/mlme/dispatcher/inc/cfg_mlme.h
  20. 137 1
      components/mlme/dispatcher/inc/cfg_mlme_dfs.h
  21. 27 0
      components/mlme/dispatcher/inc/cfg_mlme_timeout.h
  22. 74 0
      components/mlme/dispatcher/inc/cfg_mlme_wifi_pos.h
  23. 24 0
      components/mlme/dispatcher/inc/wlan_mlme_public_struct.h
  24. 131 0
      components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h
  25. 223 0
      components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c
  26. 1460 0
      components/p2p/core/src/wlan_p2p_main.c
  27. 574 0
      components/p2p/core/src/wlan_p2p_main.h
  28. 2955 0
      components/p2p/core/src/wlan_p2p_off_chan_tx.c
  29. 439 0
      components/p2p/core/src/wlan_p2p_off_chan_tx.h
  30. 929 0
      components/p2p/core/src/wlan_p2p_roc.c
  31. 247 0
      components/p2p/core/src/wlan_p2p_roc.h
  32. 128 0
      components/p2p/dispatcher/inc/wlan_p2p_cfg.h
  33. 76 0
      components/p2p/dispatcher/inc/wlan_p2p_cfg_api.h
  34. 272 0
      components/p2p/dispatcher/inc/wlan_p2p_public_struct.h
  35. 208 0
      components/p2p/dispatcher/inc/wlan_p2p_tgt_api.h
  36. 411 0
      components/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h
  37. 105 0
      components/p2p/dispatcher/src/wlan_p2p_cfg.c
  38. 432 0
      components/p2p/dispatcher/src/wlan_p2p_tgt_api.c
  39. 652 0
      components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c
  40. 140 0
      components/target_if/p2p/inc/target_if_p2p.h
  41. 474 0
      components/target_if/p2p/src/target_if_p2p.c
  42. 116 0
      components/target_if/tdls/inc/target_if_tdls.h
  43. 214 0
      components/target_if/tdls/src/target_if_tdls.c
  44. 2431 0
      components/tdls/core/src/wlan_tdls_cmds_process.c
  45. 420 0
      components/tdls/core/src/wlan_tdls_cmds_process.h
  46. 1319 0
      components/tdls/core/src/wlan_tdls_ct.c
  47. 247 0
      components/tdls/core/src/wlan_tdls_ct.h
  48. 1667 0
      components/tdls/core/src/wlan_tdls_main.c
  49. 741 0
      components/tdls/core/src/wlan_tdls_main.h
  50. 449 0
      components/tdls/core/src/wlan_tdls_mgmt.c
  51. 111 0
      components/tdls/core/src/wlan_tdls_mgmt.h
  52. 819 0
      components/tdls/core/src/wlan_tdls_peer.c
  53. 246 0
      components/tdls/core/src/wlan_tdls_peer.h
  54. 23 0
      components/tdls/core/src/wlan_tdls_txrx.c
  55. 23 0
      components/tdls/core/src/wlan_tdls_txrx.h
  56. 759 0
      components/tdls/dispatcher/inc/wlan_tdls_cfg.h
  57. 217 0
      components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h
  58. 1169 0
      components/tdls/dispatcher/inc/wlan_tdls_public_structs.h
  59. 173 0
      components/tdls/dispatcher/inc/wlan_tdls_tgt_api.h
  60. 254 0
      components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h
  61. 324 0
      components/tdls/dispatcher/src/wlan_tdls_cfg.c
  62. 383 0
      components/tdls/dispatcher/src/wlan_tdls_tgt_api.c
  63. 1127 0
      components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c
  64. 23 0
      components/tdls/dispatcher/src/wlan_tdls_utils_api.c
  65. 0 3
      core/cds/inc/cds_config.h
  66. 0 189
      core/hdd/inc/wlan_hdd_cfg.h
  67. 3 94
      core/hdd/src/wlan_hdd_cfg.c
  68. 18 7
      core/hdd/src/wlan_hdd_cfg80211.c
  69. 7 8
      core/hdd/src/wlan_hdd_hostapd.c
  70. 26 20
      core/hdd/src/wlan_hdd_main.c
  71. 0 1
      core/mac/inc/ani_global.h
  72. 2 2
      core/mac/inc/qwlan_version.h
  73. 1 1
      core/mac/src/pe/lim/lim_utils.c
  74. 0 28
      core/sap/inc/sap_api.h
  75. 2 2
      core/sap/src/sap_api_link_cntl.c
  76. 8 27
      core/sap/src/sap_fsm.c
  77. 0 15
      core/sap/src/sap_internal.h
  78. 0 64
      core/sap/src/sap_module.c
  79. 0 2
      core/sme/inc/csr_api.h
  80. 0 5
      core/sme/src/csr/csr_api_roam.c
  81. 115 0
      os_if/p2p/inc/wlan_cfg80211_p2p.h
  82. 499 0
      os_if/p2p/src/wlan_cfg80211_p2p.c
  83. 309 0
      os_if/tdls/inc/wlan_cfg80211_tdls.h
  84. 922 0
      os_if/tdls/src/wlan_cfg80211_tdls.c

+ 2781 - 0
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h

@@ -0,0 +1,2781 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WLAN_POLICY_MGR_API_H
+#define __WLAN_POLICY_MGR_API_H
+
+/**
+ * DOC: wlan_policy_mgr_api.h
+ *
+ * Concurrenct Connection Management entity
+ */
+
+/* Include files */
+#include "qdf_types.h"
+#include "qdf_status.h"
+#include "wlan_objmgr_psoc_obj.h"
+#include "wlan_policy_mgr_public_struct.h"
+
+struct target_psoc_info;
+
+typedef const enum policy_mgr_pcl_type
+	pm_dbs_pcl_second_connection_table_type
+	[PM_MAX_ONE_CONNECTION_MODE][PM_MAX_NUM_OF_MODE]
+	[PM_MAX_CONC_PRIORITY_MODE];
+
+typedef const enum policy_mgr_pcl_type
+	pm_dbs_pcl_third_connection_table_type
+	[PM_MAX_TWO_CONNECTION_MODE][PM_MAX_NUM_OF_MODE]
+	[PM_MAX_CONC_PRIORITY_MODE];
+
+typedef const enum policy_mgr_conc_next_action
+	policy_mgr_next_action_two_connection_table_type
+	[PM_MAX_ONE_CONNECTION_MODE][POLICY_MGR_MAX_BAND];
+
+typedef const enum policy_mgr_conc_next_action
+	policy_mgr_next_action_three_connection_table_type
+	[PM_MAX_TWO_CONNECTION_MODE][POLICY_MGR_MAX_BAND];
+
+#define PM_FW_MODE_STA_STA_BIT_POS       0
+#define PM_FW_MODE_STA_P2P_BIT_POS       1
+
+#define PM_FW_MODE_STA_STA_BIT_MASK      (0x1 << PM_FW_MODE_STA_STA_BIT_POS)
+#define PM_FW_MODE_STA_P2P_BIT_MASK      (0x1 << PM_FW_MODE_STA_P2P_BIT_POS)
+
+#define PM_CHANNEL_SELECT_LOGIC_STA_STA_GET(channel_select_logic_conc)  \
+	((channel_select_logic_conc & PM_FW_MODE_STA_STA_BIT_MASK) >>   \
+	 PM_FW_MODE_STA_STA_BIT_POS)
+#define PM_CHANNEL_SELECT_LOGIC_STA_P2P_GET(channel_select_logic_conc)  \
+	((channel_select_logic_conc & PM_FW_MODE_STA_P2P_BIT_MASK) >>   \
+	 PM_FW_MODE_STA_P2P_BIT_POS)
+
+/**
+ * policy_mgr_get_mcc_scc_switch() - To mcc to scc switch setting from INI
+ * @psoc: pointer to psoc
+ * @mcc_scc_switch: value to be filled
+ *
+ * This API pulls mcc to scc switch setting which is given as part of INI and
+ * stored in policy manager's CFGs.
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc,
+					      uint8_t *mcc_scc_switch);
+/**
+ * policy_mgr_get_sys_pref() - to get system preference
+ * @psoc: pointer to psoc
+ * @sys_pref: value to be filled
+ *
+ * This API pulls the system preference for policy manager to provide
+ * PCL
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_sys_pref(struct wlan_objmgr_psoc *psoc,
+					uint8_t *sys_pref);
+/**
+ * policy_mgr_set_sys_pref() - to set system preference
+ * @psoc: pointer to psoc
+ * @sys_pref: value to be applied as new INI setting
+ *
+ * This API is meant to override original INI setting for system pref
+ * with new value which is used by policy manager to provide PCL
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_set_sys_pref(struct wlan_objmgr_psoc *psoc,
+				   uint8_t sys_pref);
+/**
+ * policy_mgr_get_max_conc_cxns() - to get max num of conc connections
+ * @psoc: pointer to psoc
+ * @max_conc_cxns: value to be filled
+ *
+ * This API pulls max number of active connections which can be allowed
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_max_conc_cxns(struct wlan_objmgr_psoc *psoc,
+						uint8_t *max_conc_cxns);
+/**
+ * policy_mgr_get_conc_rule1() - to find out if conc rule1 is enabled
+ * @psoc: pointer to psoc
+ * @conc_rule1: value to be filled
+ *
+ * This API is used to find out if conc rule-1 is enabled by user
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_conc_rule1(struct wlan_objmgr_psoc *psoc,
+						uint8_t *conc_rule1);
+/**
+ * policy_mgr_get_conc_rule2() - to find out if conc rule2 is enabled
+ * @psoc: pointer to psoc
+ * @conc_rule2: value to be filled
+ *
+ * This API is used to find out if conc rule-2 is enabled by user
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_conc_rule2(struct wlan_objmgr_psoc *psoc,
+						uint8_t *conc_rule2);
+/**
+ * policy_mgr_get_dbs_selection_plcy() - DBS HW mode selection setting
+ * @psoc: pointer to psoc
+ * @dbs_selection_plcy: value to be filled
+ *
+ * This API is used to find out DBS HW mode preference.
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_dbs_selection_plcy(struct wlan_objmgr_psoc *psoc,
+						uint32_t *dbs_selection_plcy);
+/**
+ * policy_mgr_get_vdev_priority_list() - to get vdev priority list
+ * @psoc: pointer to psoc
+ * @vdev_priority_list: value to be filled
+ *
+ * This API is used to find out vdev_priority_list setting
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_vdev_priority_list(struct wlan_objmgr_psoc *psoc,
+						uint32_t *vdev_priority_list);
+/**
+ * policy_mgr_get_chnl_select_plcy() - to get channel selection policy
+ * @psoc: pointer to psoc
+ * @chnl_select_plcy: value to be filled
+ *
+ * This API is used to find out which channel selection policy has been
+ * configured
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_chnl_select_plcy(struct wlan_objmgr_psoc *psoc,
+						uint32_t *chnl_select_plcy);
+
+/**
+ * policy_mgr_get_mcc_adaptive_sch() - to get mcc adaptive scheduler
+ * @psoc: pointer to psoc
+ * @enable_mcc_adaptive_sch: value to be filled
+ *
+ * This API is used to find out if mcc adaptive scheduler enabled or disabled
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc,
+					   uint8_t *enable_mcc_adaptive_sch);
+
+/**
+ * policy_mgr_get_sta_cxn_5g_band() - to get STA's connection in 5G config
+ *
+ * @psoc: pointer to psoc
+ * @enable_sta_cxn_5g_band: value to be filled
+ *
+ * This API is used to find out if STA connection in 5G band is allowed or
+ * disallowed.
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS policy_mgr_get_sta_cxn_5g_band(struct wlan_objmgr_psoc *psoc,
+					   uint8_t *enable_sta_cxn_5g_band);
+/**
+ * policy_mgr_set_concurrency_mode() - To set concurrency mode
+ * @psoc: PSOC object data
+ * @mode: device mode
+ *
+ * This routine is called to set the concurrency mode
+ *
+ * Return: NONE
+ */
+void policy_mgr_set_concurrency_mode(struct wlan_objmgr_psoc *psoc,
+				     enum QDF_OPMODE mode);
+
+/**
+ * policy_mgr_clear_concurrency_mode() - To clear concurrency mode
+ * @psoc: PSOC object data
+ * @mode: device mode
+ *
+ * This routine is called to clear the concurrency mode
+ *
+ * Return: NONE
+ */
+void policy_mgr_clear_concurrency_mode(struct wlan_objmgr_psoc *psoc,
+				       enum QDF_OPMODE mode);
+
+/**
+ * policy_mgr_get_connection_count() - provides the count of
+ * current connections
+ * @psoc: PSOC object information
+ *
+ * This function provides the count of current connections
+ *
+ * Return: connection count
+ */
+uint32_t policy_mgr_get_connection_count(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_concurrency_mode() - return concurrency mode
+ * @psoc: PSOC object information
+ *
+ * This routine is used to retrieve concurrency mode
+ *
+ * Return: uint32_t value of concurrency mask
+ */
+uint32_t policy_mgr_get_concurrency_mode(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_search_and_check_for_session_conc() - Checks if
+ * concurrecy is allowed
+ * @psoc: PSOC object information
+ * @session_id: Session id
+ * @roam_profile: Pointer to the roam profile
+ *
+ * Searches and gets the channel number from the scan results and checks if
+ * concurrency is allowed for the given session ID
+ *
+ * Non zero channel number if concurrency is allowed, zero otherwise
+ */
+uint8_t policy_mgr_search_and_check_for_session_conc(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t session_id, void *roam_profile);
+
+/**
+ * policy_mgr_is_chnl_in_diff_band() - to check that given channel
+ * is in diff band from existing channel or not
+ * @psoc: pointer to psoc
+ * @channel: given channel
+ *
+ * This API will check that if the passed channel is in diff band than the
+ * already existing connections or not.
+ *
+ * Return: true if channel is in diff band
+ */
+bool policy_mgr_is_chnl_in_diff_band(struct wlan_objmgr_psoc *psoc,
+					    uint8_t channel);
+
+/**
+ * policy_mgr_check_for_session_conc() - Check if concurrency is
+ * allowed for a session
+ * @psoc: PSOC object information
+ * @session_id: Session ID
+ * @channel: Channel number
+ *
+ * Checks if connection is allowed for a given session_id
+ *
+ * True if the concurrency is allowed, false otherwise
+ */
+bool policy_mgr_check_for_session_conc(
+	struct wlan_objmgr_psoc *psoc, uint8_t session_id, uint8_t channel);
+
+/**
+ * policy_mgr_handle_conc_multiport() - to handle multiport concurrency
+ * @session_id: Session ID
+ * @channel: Channel number
+ *
+ * This routine will handle STA side concurrency when policy manager
+ * is enabled.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_handle_conc_multiport(
+	struct wlan_objmgr_psoc *psoc, uint8_t session_id, uint8_t channel);
+
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+/**
+ * policy_mgr_check_concurrent_intf_and_restart_sap() - Check
+ * concurrent change intf
+ * @psoc: PSOC object information
+ * @operation_channel: operation channel
+ * @vdev_id: vdev id of SAP
+ *
+ * Checks the concurrent change interface and restarts SAP
+ *
+ * Return: None
+ */
+void policy_mgr_check_concurrent_intf_and_restart_sap(
+		struct wlan_objmgr_psoc *psoc);
+#else
+static inline void policy_mgr_check_concurrent_intf_and_restart_sap(
+		struct wlan_objmgr_psoc *psoc)
+{
+
+}
+#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH */
+
+/**
+ * policy_mgr_is_mcc_in_24G() - Function to check for MCC in 2.4GHz
+ * @psoc: PSOC object information
+ *
+ * This function is used to check for MCC operation in 2.4GHz band.
+ * STA, P2P and SAP adapters are only considered.
+ *
+ * Return: True if mcc is detected in 2.4 Ghz, false otherwise
+ *
+ */
+bool policy_mgr_is_mcc_in_24G(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_change_mcc_go_beacon_interval() - Change MCC beacon interval
+ * @psoc: PSOC object information
+ * @vdev_id: vdev id
+ * @dev_mode: device mode
+ *
+ * Updates the beacon parameters of the GO in MCC scenario
+ *
+ * Return: Success or Failure depending on the overall function behavior
+ */
+QDF_STATUS policy_mgr_change_mcc_go_beacon_interval(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t vdev_id, enum QDF_OPMODE dev_mode);
+
+#if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH)
+/**
+ * policy_mgr_change_sap_channel_with_csa() - Move SAP channel using (E)CSA
+ * @psoc: PSOC object information
+ * @vdev_id: Vdev id
+ * @channel: Channel to change
+ * @ch_width: channel width to change
+ * @forced: Force to switch channel, ignore SCC/MCC check
+ *
+ * Invoke the callback function to change SAP channel using (E)CSA
+ *
+ * Return: None
+ */
+void policy_mgr_change_sap_channel_with_csa(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t vdev_id, uint32_t channel,
+		uint32_t ch_width,
+		bool forced);
+#else
+static inline void policy_mgr_change_sap_channel_with_csa(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t vdev_id, uint32_t channel,
+		uint32_t ch_width,
+		bool forced)
+{
+
+}
+#endif
+
+/**
+ * policy_mgr_set_pcl_for_existing_combo() - SET PCL for existing combo
+ * @psoc: PSOC object information
+ * @mode: Adapter mode
+ *
+ * Return: None
+ */
+void policy_mgr_set_pcl_for_existing_combo(struct wlan_objmgr_psoc *psoc,
+					   enum policy_mgr_con_mode mode);
+/**
+ * policy_mgr_incr_active_session() - increments the number of active sessions
+ * @psoc: PSOC object information
+ * @mode:	Adapter mode
+ * @session_id: session ID for the connection session
+ *
+ * This function increments the number of active sessions maintained per device
+ * mode. In the case of STA/P2P CLI/IBSS upon connection indication it is
+ * incremented; In the case of SAP/P2P GO upon bss start it is incremented
+ *
+ * Return: None
+ */
+void policy_mgr_incr_active_session(struct wlan_objmgr_psoc *psoc,
+		enum QDF_OPMODE mode, uint8_t session_id);
+
+/**
+ * policy_mgr_decr_active_session() - decrements the number of active sessions
+ * @psoc: PSOC object information
+ * @mode: Adapter mode
+ * @session_id: session ID for the connection session
+ *
+ * This function decrements the number of active sessions maintained per device
+ * mode. In the case of STA/P2P CLI/IBSS upon disconnection it is decremented
+ * In the case of SAP/P2P GO upon bss stop it is decremented
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc,
+		enum QDF_OPMODE mode, uint8_t session_id);
+
+/**
+ * policy_mgr_decr_session_set_pcl() - Decrement session count and set PCL
+ * @psoc: PSOC object information
+ * @mode: Adapter mode
+ * @session_id: Session id
+ *
+ * Decrements the active session count and sets the PCL if a STA connection
+ * exists
+ *
+ * Return: None
+ */
+void policy_mgr_decr_session_set_pcl(struct wlan_objmgr_psoc *psoc,
+		enum QDF_OPMODE mode, uint8_t session_id);
+
+/**
+ * policy_mgr_get_channel() - provide channel number of given mode and vdevid
+ * @psoc: PSOC object information
+ * @mode: given  mode
+ * @vdev_id: pointer to vdev_id
+ *
+ * This API will provide channel number of matching mode and vdevid.
+ * If vdev_id is NULL then it will match only mode
+ * If vdev_id is not NULL the it will match both mode and vdev_id
+ *
+ * Return: channel number
+ */
+uint8_t policy_mgr_get_channel(struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_con_mode mode, uint32_t *vdev_id);
+
+/**
+ * policy_mgr_get_pcl() - provides the preferred channel list for
+ * new connection
+ * @psoc: PSOC object information
+ * @mode:	Device mode
+ * @pcl_channels: PCL channels
+ * @len: length of the PCL
+ * @pcl_weight: Weights of the PCL
+ * @weight_len: Max length of the weights list
+ *
+ * This function provides the preferred channel list on which
+ * policy manager wants the new connection to come up. Various
+ * connection decision making entities will using this function
+ * to query the PCL info
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_pcl(struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_con_mode mode,
+		uint8_t *pcl_channels, uint32_t *len,
+		uint8_t *pcl_weight, uint32_t weight_len);
+
+/**
+ * policy_mgr_update_with_safe_channel_list() - provides the safe
+ * channel list
+ * @psoc: PSOC object information
+ * @pcl_channels: channel list
+ * @len: length of the list
+ * @weight_list: Weights of the PCL
+ * @weight_len: Max length of the weights list
+ *
+ * This function provides the safe channel list from the list
+ * provided after consulting the channel avoidance list
+ *
+ * Return: None
+ */
+void policy_mgr_update_with_safe_channel_list(struct wlan_objmgr_psoc *psoc,
+		uint8_t *pcl_channels, uint32_t *len,
+		uint8_t *weight_list, uint32_t weight_len);
+
+/**
+ * policy_mgr_get_nondfs_preferred_channel() - to get non-dfs preferred channel
+ *                                           for given mode
+ * @psoc: PSOC object information
+ * @mode: mode for which preferred non-dfs channel is requested
+ * @for_existing_conn: flag to indicate if preferred channel is requested
+ *                     for existing connection
+ *
+ * this routine will return non-dfs channel
+ * 1) for getting non-dfs preferred channel, first we check if there are any
+ *    other connection exist whose channel is non-dfs. if yes then return that
+ *    channel so that we can accommodate upto 3 mode concurrency.
+ * 2) if there no any other connection present then query concurrency module
+ *    to give preferred channel list. once we get preferred channel list, loop
+ *    through list to find first non-dfs channel from ascending order.
+ *
+ * Return: uint8_t non-dfs channel
+ */
+uint8_t policy_mgr_get_nondfs_preferred_channel(struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_con_mode mode, bool for_existing_conn);
+
+/**
+ * policy_mgr_is_any_nondfs_chnl_present() - Find any non-dfs
+ * channel from conc table
+ * @psoc: PSOC object information
+ * @channel: pointer to channel which needs to be filled
+ *
+ * In-case if any connection is already present whose channel is none dfs then
+ * return that channel
+ *
+ * Return: true up-on finding non-dfs channel else false
+ */
+bool policy_mgr_is_any_nondfs_chnl_present(struct wlan_objmgr_psoc *psoc,
+		uint8_t *channel);
+
+/**
+ * policy_mgr_is_any_dfs_beaconing_session_present() - to find
+ * if any DFS session
+ * @psoc: PSOC object information
+ * @channel: pointer to channel number that needs to filled
+ *
+ * If any beaconing session such as SAP or GO present and it is on DFS channel
+ * then this function will return true
+ *
+ * Return: true if session is on DFS or false if session is on non-dfs channel
+ */
+bool policy_mgr_is_any_dfs_beaconing_session_present(
+		struct wlan_objmgr_psoc *psoc, uint8_t *channel);
+
+/**
+ * policy_mgr_allow_concurrency() - Check for allowed concurrency
+ * combination consulting the PCL
+ * @psoc: PSOC object information
+ * @mode:	new connection mode
+ * @channel: channel on which new connection is coming up
+ * @bw: Bandwidth requested by the connection (optional)
+ *
+ * When a new connection is about to come up check if current
+ * concurrency combination including the new connection is
+ * allowed or not based on the HW capability
+ *
+ * Return: True/False
+ */
+bool policy_mgr_allow_concurrency(struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_con_mode mode,
+		uint8_t channel, enum hw_mode_bandwidth bw);
+
+/**
+ * policy_mgr_allow_concurrency_csa() - Check for allowed concurrency
+ * combination when channel switch
+ * @psoc:	PSOC object information
+ * @mode:	connection mode
+ * @channel:	target channel to switch
+ * @vdev_id:	vdev id of channel switch interface
+ *
+ * There is already existing SAP+GO combination but due to upper layer
+ * notifying LTE-COEX event or sending command to move one of the connections
+ * to different channel. In such cases before moving existing connection to new
+ * channel, check if new channel can co-exist with the other existing
+ * connection. For example, one SAP1 is on channel-6 and second SAP2 is on
+ * channel-36 and lets say they are doing DBS, and lets say upper layer sends
+ * LTE-COEX to move SAP1 from channel-6 to channel-149. In this case, SAP1 and
+ * SAP2 will end up doing MCC which may not be desirable result. such cases
+ * will be prevented with this API.
+ *
+ * Return: True/False
+ */
+bool policy_mgr_allow_concurrency_csa(struct wlan_objmgr_psoc *psoc,
+				      enum policy_mgr_con_mode mode,
+				      uint8_t channel,
+				      uint32_t vdev_id);
+
+/**
+ * policy_mgr_get_first_connection_pcl_table_index() - provides the
+ * row index to firstConnectionPclTable to get to the correct
+ * pcl
+ * @psoc: PSOC object information
+ *
+ * This function provides the row index to
+ * firstConnectionPclTable. The index is the preference config.
+ *
+ * Return: table index
+ */
+enum policy_mgr_conc_priority_mode
+	policy_mgr_get_first_connection_pcl_table_index(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_second_connection_pcl_table_index() - provides the
+ * row index to secondConnectionPclTable to get to the correct
+ * pcl
+ * @psoc: PSOC object information
+ *
+ * This function provides the row index to
+ * secondConnectionPclTable. The index is derived based on
+ * current connection, band on which it is on & chain mask it is
+ * using, as obtained from pm_conc_connection_list.
+ *
+ * Return: table index
+ */
+enum policy_mgr_one_connection_mode
+	policy_mgr_get_second_connection_pcl_table_index(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_third_connection_pcl_table_index() - provides the
+ * row index to thirdConnectionPclTable to get to the correct
+ * pcl
+ * @psoc: PSOC object information
+ *
+ * This function provides the row index to
+ * thirdConnectionPclTable. The index is derived based on
+ * current connection, band on which it is on & chain mask it is
+ * using, as obtained from pm_conc_connection_list.
+ *
+ * Return: table index
+ */
+enum policy_mgr_two_connection_mode
+	policy_mgr_get_third_connection_pcl_table_index(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_incr_connection_count() - adds the new connection to
+ * the current connections list
+ * @psoc: PSOC object information
+ * @vdev_id: vdev id
+ *
+ *
+ * This function adds the new connection to the current
+ * connections list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_incr_connection_count(struct wlan_objmgr_psoc *psoc,
+		uint32_t vdev_id);
+
+/**
+ * policy_mgr_update_connection_info() - updates the existing
+ * connection in the current connections list
+ * @psoc: PSOC object information
+ * @vdev_id: vdev id
+ *
+ *
+ * This function adds the new connection to the current
+ * connections list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_update_connection_info(struct wlan_objmgr_psoc *psoc,
+		uint32_t vdev_id);
+
+/**
+ * policy_mgr_decr_connection_count() - remove the old connection
+ * from the current connections list
+ * @psoc: PSOC object information
+ * @vdev_id: vdev id of the old connection
+ *
+ *
+ * This function removes the old connection from the current
+ * connections list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_decr_connection_count(struct wlan_objmgr_psoc *psoc,
+		uint32_t vdev_id);
+
+/**
+ * policy_mgr_current_connections_update() - initiates actions
+ * needed on current connections once channel has been decided
+ * for the new connection
+ * @psoc: PSOC object information
+ * @session_id: Session id
+ * @channel: Channel on which new connection will be
+ * @reason: Reason for which connection update is required
+ *
+ * This function initiates initiates actions
+ * needed on current connections once channel has been decided
+ * for the new connection. Notifies UMAC & FW as well
+ *
+ * Return: QDF_STATUS enum
+ */
+QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
+		uint32_t session_id, uint8_t channel,
+		enum policy_mgr_conn_update_reason);
+
+/**
+ * policy_mgr_is_dbs_allowed_for_concurrency() - If dbs is allowed for current
+ * concurreny
+ * @new_conn_mode: new connection mode
+ *
+ * When a new connection is about to come up, check if dbs is allowed for
+ * STA+STA or STA+P2P
+ *
+ * Return: true if dbs is allowed for STA+STA or STA+P2P else false
+ */
+bool policy_mgr_is_dbs_allowed_for_concurrency(
+		struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE new_conn_mode);
+
+/**
+ * policy_mgr_get_preferred_dbs_action_table() - get dbs action table type
+ * @psoc: Pointer to psoc
+ * @vdev_id: vdev Id
+ * @channel: channel of vdev.
+ * @reason: reason of request
+ *
+ * 1. Based on band preferred and vdev priority setting to choose the preferred
+ * dbs action.
+ * 2. This routine will be used to get DBS switching action tables.
+ * In Genoa, two action tables for DBS1 (2x2 5G + 1x1 2G), DBS2
+ *  (2x2 2G + 1x1 5G).
+ * 3. It can be used in mode change case in CSA channel switching or Roaming,
+ * opportunistic upgrade. If needs switch to DBS, we needs to query this
+ * function to get preferred DBS mode.
+ * 4. This is mainly used for dual dbs mode HW. For Legacy HW, there is
+ * only single DBS mode. This function will return PM_NOP.
+ *
+ * return : PM_NOP, PM_DBS1, PM_DBS2
+ */
+enum policy_mgr_conc_next_action
+policy_mgr_get_preferred_dbs_action_table(
+	struct wlan_objmgr_psoc *psoc,
+	uint32_t vdev_id,
+	uint8_t channel,
+	enum policy_mgr_conn_update_reason reason);
+
+/**
+ * policy_mgr_is_ibss_conn_exist() - to check if IBSS connection already present
+ * @psoc: PSOC object information
+ * @ibss_channel: pointer to ibss channel which needs to be filled
+ *
+ * this routine will check if IBSS connection already exist or no. If it
+ * exist then this routine will return true and fill the ibss_channel value.
+ *
+ * Return: true if ibss connection exist else false
+ */
+bool policy_mgr_is_ibss_conn_exist(struct wlan_objmgr_psoc *psoc,
+		uint8_t *ibss_channel);
+
+/**
+ * policy_mgr_get_conn_info() - get the current connections list
+ * @len: length of the list
+ *
+ * This function returns a pointer to the current connections
+ * list
+ *
+ * Return: pointer to connection list
+ */
+struct policy_mgr_conc_connection_info *policy_mgr_get_conn_info(
+		uint32_t *len);
+#ifdef MPC_UT_FRAMEWORK
+/**
+ * policy_mgr_incr_connection_count_utfw() - adds the new
+ * connection to the current connections list
+ * @psoc: PSOC object information
+ * @vdev_id: vdev id
+ * @tx_streams: number of transmit spatial streams
+ * @rx_streams: number of receive spatial streams
+ * @chain_mask: chain mask
+ * @type: connection type
+ * @sub_type: connection subtype
+ * @channelid: channel number
+ * @mac_id: mac id
+ *
+ * This function adds the new connection to the current
+ * connections list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_incr_connection_count_utfw(struct wlan_objmgr_psoc *psoc,
+		uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams,
+		uint32_t chain_mask, uint32_t type, uint32_t sub_type,
+		uint32_t channelid, uint32_t mac_id);
+
+/**
+ * policy_mgr_update_connection_info_utfw() - updates the
+ * existing connection in the current connections list
+ * @psoc: PSOC object information
+ * @vdev_id: vdev id
+ * @tx_streams: number of transmit spatial streams
+ * @rx_streams: number of receive spatial streams
+ * @chain_mask: chain mask
+ * @type: connection type
+ * @sub_type: connection subtype
+ * @channelid: channel number
+ * @mac_id: mac id
+ *
+ * This function updates the connection to the current
+ * connections list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_update_connection_info_utfw(struct wlan_objmgr_psoc *psoc,
+		uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams,
+		uint32_t chain_mask, uint32_t type, uint32_t sub_type,
+		uint32_t channelid, uint32_t mac_id);
+
+/**
+ * policy_mgr_decr_connection_count_utfw() - remove the old
+ * connection from the current connections list
+ * @psoc: PSOC object information
+ * @del_all: delete all entries
+ * @vdev_id: vdev id
+ *
+ * This function removes the old connection from the current
+ * connections list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_decr_connection_count_utfw(struct wlan_objmgr_psoc *psoc,
+		uint32_t del_all, uint32_t vdev_id);
+
+/**
+ * policy_mgr_get_pcl_from_first_conn_table() - Get PCL for new
+ * connection from first connection table
+ * @type: Connection mode of type 'policy_mgr_con_mode'
+ * @sys_pref: System preference
+ *
+ * Get the PCL for a new connection
+ *
+ * Return: PCL channels enum
+ */
+enum policy_mgr_pcl_type policy_mgr_get_pcl_from_first_conn_table(
+		enum policy_mgr_con_mode type,
+		enum policy_mgr_conc_priority_mode sys_pref);
+
+/**
+ * policy_mgr_get_pcl_from_second_conn_table() - Get PCL for new
+ * connection from second connection table
+ * @idx: index into first connection table
+ * @type: Connection mode of type 'policy_mgr_con_mode'
+ * @sys_pref: System preference
+ * @dbs_capable: if HW DBS capable
+ *
+ * Get the PCL for a new connection
+ *
+ * Return: PCL channels enum
+ */
+enum policy_mgr_pcl_type policy_mgr_get_pcl_from_second_conn_table(
+	enum policy_mgr_one_connection_mode idx, enum policy_mgr_con_mode type,
+	enum policy_mgr_conc_priority_mode sys_pref, uint8_t dbs_capable);
+
+/**
+ * policy_mgr_get_pcl_from_third_conn_table() - Get PCL for new
+ * connection from third connection table
+ * @idx: index into second connection table
+ * @type: Connection mode of type 'policy_mgr_con_mode'
+ * @sys_pref: System preference
+ * @dbs_capable: if HW DBS capable
+ *
+ * Get the PCL for a new connection
+ *
+ * Return: PCL channels enum
+ */
+enum policy_mgr_pcl_type policy_mgr_get_pcl_from_third_conn_table(
+	enum policy_mgr_two_connection_mode idx, enum policy_mgr_con_mode type,
+	enum policy_mgr_conc_priority_mode sys_pref, uint8_t dbs_capable);
+#else
+static inline QDF_STATUS policy_mgr_incr_connection_count_utfw(
+		struct wlan_objmgr_psoc *psoc, uint32_t vdev_id,
+		uint32_t tx_streams, uint32_t rx_streams,
+		uint32_t chain_mask, uint32_t type, uint32_t sub_type,
+		uint32_t channelid, uint32_t mac_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+static inline QDF_STATUS policy_mgr_update_connection_info_utfw(
+		struct wlan_objmgr_psoc *psoc, uint32_t vdev_id,
+		uint32_t tx_streams, uint32_t rx_streams,
+		uint32_t chain_mask, uint32_t type, uint32_t sub_type,
+		uint32_t channelid, uint32_t mac_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+static inline QDF_STATUS policy_mgr_decr_connection_count_utfw(
+		struct wlan_objmgr_psoc *psoc, uint32_t del_all,
+		uint32_t vdev_id)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * policy_mgr_convert_device_mode_to_qdf_type() - provides the
+ * type translation from HDD to policy manager type
+ * @device_mode: Generic connection mode type
+ *
+ *
+ * This function provides the type translation
+ *
+ * Return: policy_mgr_con_mode enum
+ */
+enum policy_mgr_con_mode policy_mgr_convert_device_mode_to_qdf_type(
+		enum QDF_OPMODE device_mode);
+
+/**
+ * policy_mgr_get_qdf_mode_from_pm - provides the
+ * type translation from policy manager type
+ * to generic connection mode type
+ * @device_mode: policy manager mode type
+ *
+ *
+ * This function provides the type translation
+ *
+ * Return: QDF_OPMODE enum
+ */
+enum QDF_OPMODE policy_mgr_get_qdf_mode_from_pm(
+			enum policy_mgr_con_mode device_mode);
+
+/**
+ * policy_mgr_check_n_start_opportunistic_timer - check single mac upgrade
+ * needed or not, if needed start the oppurtunistic timer.
+ * @psoc: pointer to SOC
+ *
+ * This function starts the oppurtunistic timer if hw_mode change is needed
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_check_n_start_opportunistic_timer(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_pdev_set_hw_mode() - Set HW mode command to FW
+ * @psoc: PSOC object information
+ * @session_id: Session ID
+ * @mac0_ss: MAC0 spatial stream configuration
+ * @mac0_bw: MAC0 bandwidth configuration
+ * @mac1_ss: MAC1 spatial stream configuration
+ * @mac1_bw: MAC1 bandwidth configuration
+ * @mac0_band_cap: mac0 band capability requirement
+ *     (0: Don't care, 1: 2.4G, 2: 5G)
+ * @dbs: HW DBS capability
+ * @dfs: HW Agile DFS capability
+ * @sbs: HW SBS capability
+ * @reason: Reason for connection update
+ * @next_action: next action to happen at policy mgr after
+ *		HW mode change
+ *
+ * Sends the set hw mode request to FW
+ *
+ * e.g.: To configure 2x2_80
+ *       mac0_ss = HW_MODE_SS_2x2, mac0_bw = HW_MODE_80_MHZ
+ *       mac1_ss = HW_MODE_SS_0x0, mac1_bw = HW_MODE_BW_NONE
+ *       mac0_band_cap = HW_MODE_MAC_BAND_NONE,
+ *       dbs = HW_MODE_DBS_NONE, dfs = HW_MODE_AGILE_DFS_NONE,
+ *       sbs = HW_MODE_SBS_NONE
+ * e.g.: To configure 1x1_80_1x1_40 (DBS)
+ *       mac0_ss = HW_MODE_SS_1x1, mac0_bw = HW_MODE_80_MHZ
+ *       mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ
+ *       mac0_band_cap = HW_MODE_MAC_BAND_NONE,
+ *       dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS_NONE,
+ *       sbs = HW_MODE_SBS_NONE
+ * e.g.: To configure 1x1_80_1x1_40 (Agile DFS)
+ *       mac0_ss = HW_MODE_SS_1x1, mac0_bw = HW_MODE_80_MHZ
+ *       mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ
+ *       mac0_band_cap = HW_MODE_MAC_BAND_NONE,
+ *       dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS,
+ *       sbs = HW_MODE_SBS_NONE
+ * e.g.: To configure 2x2_5g_80+1x1_2g_40
+ *       mac0_ss = HW_MODE_SS_2x2, mac0_bw = HW_MODE_80_MHZ
+ *       mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ
+ *       mac0_band_cap = HW_MODE_MAC_BAND_5G
+ *       dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS_NONE,
+ *       sbs = HW_MODE_SBS_NONE
+ * e.g.: To configure 2x2_2g_40+1x1_5g_40
+ *       mac0_ss = HW_MODE_SS_2x2, mac0_bw = HW_MODE_40_MHZ
+ *       mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ
+ *       mac0_band_cap = HW_MODE_MAC_BAND_2G
+ *       dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS_NONE,
+ *       sbs = HW_MODE_SBS_NONE
+ *
+ * Return: Success if the message made it down to the next layer
+ */
+QDF_STATUS policy_mgr_pdev_set_hw_mode(struct wlan_objmgr_psoc *psoc,
+		uint32_t session_id,
+		enum hw_mode_ss_config mac0_ss,
+		enum hw_mode_bandwidth mac0_bw,
+		enum hw_mode_ss_config mac1_ss,
+		enum hw_mode_bandwidth mac1_bw,
+		enum hw_mode_mac_band_cap mac0_band_cap,
+		enum hw_mode_dbs_capab dbs,
+		enum hw_mode_agile_dfs_capab dfs,
+		enum hw_mode_sbs_capab sbs,
+		enum policy_mgr_conn_update_reason reason,
+		uint8_t next_action);
+
+/**
+ * policy_mgr_pdev_set_hw_mode_cback() - callback invoked by
+ * other component to provide set HW mode request status
+ * @status: status of the request
+ * @cfgd_hw_mode_index: new HW mode index
+ * @num_vdev_mac_entries: Number of mac entries
+ * @vdev_mac_map: The table of vdev to mac mapping
+ * @next_action: next action to happen at policy mgr after
+ *		beacon update
+ * @reason: Reason for set HW mode
+ * @session_id: vdev id on which the request was made
+ * @context: PSOC object information
+ *
+ * This function is the callback registered with SME at set HW
+ * mode request time
+ *
+ * Return: None
+ */
+typedef void (*policy_mgr_pdev_set_hw_mode_cback)(uint32_t status,
+				uint32_t cfgd_hw_mode_index,
+				uint32_t num_vdev_mac_entries,
+				struct policy_mgr_vdev_mac_map *vdev_mac_map,
+				uint8_t next_action,
+				enum policy_mgr_conn_update_reason reason,
+				uint32_t session_id, void *context);
+
+/**
+ * policy_mgr_nss_update_cback() - callback invoked by other
+ * component to provide nss update request status
+ * @psoc: PSOC object information
+ * @tx_status: tx completion status for updated beacon with new
+ *		nss value
+ * @vdev_id: vdev id for the specific connection
+ * @next_action: next action to happen at policy mgr after
+ *		beacon update
+ * @reason: Reason for nss update
+ * @original_vdev_id: original request hwmode change vdev id
+ *
+ * This function is the callback registered with SME at nss
+ * update request time
+ *
+ * Return: None
+ */
+typedef void (*policy_mgr_nss_update_cback)(struct wlan_objmgr_psoc *psoc,
+		uint8_t tx_status,
+		uint8_t vdev_id,
+		uint8_t next_action,
+		enum policy_mgr_conn_update_reason reason,
+		uint32_t original_vdev_id);
+
+/**
+ * struct policy_mgr_sme_cbacks - SME Callbacks to be invoked
+ * from policy manager
+ * @sme_get_valid_channels: Get valid channel list
+ * @sme_get_nss_for_vdev: Get the allowed nss value for the vdev
+ * @sme_soc_set_dual_mac_config: Set the dual MAC scan & FW
+ *                             config
+ * @sme_pdev_set_hw_mode: Set the new HW mode to FW
+ * @sme_pdev_set_pcl: Set new PCL to FW
+ * @sme_nss_update_request: Update NSS value to FW
+ * @sme_change_mcc_beacon_interval: Set MCC beacon interval to FW
+ */
+struct policy_mgr_sme_cbacks {
+	QDF_STATUS (*sme_get_valid_channels)(uint8_t *chan_list,
+					     uint32_t *list_len);
+	void (*sme_get_nss_for_vdev)(enum QDF_OPMODE,
+				     uint8_t *nss_2g, uint8_t *nss_5g);
+	QDF_STATUS (*sme_soc_set_dual_mac_config)(
+		struct policy_mgr_dual_mac_config msg);
+	QDF_STATUS (*sme_pdev_set_hw_mode)(struct policy_mgr_hw_mode msg);
+	QDF_STATUS (*sme_pdev_set_pcl)(struct policy_mgr_pcl_list *msg);
+	QDF_STATUS (*sme_nss_update_request)(uint32_t vdev_id,
+		uint8_t new_nss, policy_mgr_nss_update_cback cback,
+		uint8_t next_action, struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_conn_update_reason reason,
+		uint32_t original_vdev_id);
+	QDF_STATUS (*sme_change_mcc_beacon_interval)(uint8_t session_id);
+	QDF_STATUS (*sme_get_ap_channel_from_scan)(
+		void *roam_profile,
+		void **scan_cache,
+		uint8_t *channel);
+	QDF_STATUS (*sme_scan_result_purge)(
+				void *scan_result);
+};
+
+/**
+ * struct policy_mgr_hdd_cbacks - HDD Callbacks to be invoked
+ * from policy manager
+ * @sap_restart_chan_switch_cb: Restart SAP
+ * @wlan_hdd_get_channel_for_sap_restart: Get channel to restart
+ *                      SAP
+ * @get_mode_for_non_connected_vdev: Get the mode for a non
+ *                                 connected vdev
+ * @hdd_get_device_mode: Get QDF_OPMODE type for session id (vdev id)
+ * @hdd_wapi_security_sta_exist: Get whether wapi encription station existing
+ * or not. Some hw doesn't support WAPI encryption concurrency with other
+ * encryption type.
+ */
+struct policy_mgr_hdd_cbacks {
+	void (*sap_restart_chan_switch_cb)(struct wlan_objmgr_psoc *psoc,
+				uint8_t vdev_id, uint32_t channel,
+				uint32_t channel_bw,
+				bool forced);
+	QDF_STATUS (*wlan_hdd_get_channel_for_sap_restart)(
+				struct wlan_objmgr_psoc *psoc,
+				uint8_t vdev_id, uint8_t *channel,
+				uint8_t *sec_ch);
+	enum policy_mgr_con_mode (*get_mode_for_non_connected_vdev)(
+				struct wlan_objmgr_psoc *psoc,
+				uint8_t vdev_id);
+	enum QDF_OPMODE (*hdd_get_device_mode)(uint32_t session_id);
+	bool (*hdd_wapi_security_sta_exist)(void);
+};
+
+
+/**
+ * struct policy_mgr_tdls_cbacks - TDLS Callbacks to be invoked
+ * from policy manager
+ * @set_tdls_ct_mode: Set the tdls connection tracker mode
+ * @check_is_tdls_allowed: check if tdls allowed or not
+ */
+struct policy_mgr_tdls_cbacks {
+	void (*tdls_notify_increment_session)(struct wlan_objmgr_psoc *psoc);
+	void (*tdls_notify_decrement_session)(struct wlan_objmgr_psoc *psoc);
+};
+
+/**
+ * struct policy_mgr_cdp_cbacks - CDP Callbacks to be invoked
+ * from policy manager
+ * @cdp_update_mac_id: update mac_id for vdev
+ */
+struct policy_mgr_cdp_cbacks {
+	void (*cdp_update_mac_id)(struct wlan_objmgr_psoc *soc,
+		uint8_t vdev_id, uint8_t mac_id);
+};
+
+/**
+ * struct policy_mgr_dp_cbacks - CDP Callbacks to be invoked
+ * from policy manager
+ * @hdd_disable_rx_ol_in_concurrency: Callback to disable LRO/GRO offloads
+ * @hdd_set_rx_mode_rps_cb: Callback to set RPS
+ * @hdd_ipa_set_mcc_mode_cb: Callback to set mcc mode for ipa module
+ * @hdd_v2_flow_pool_map: Callback to create vdev flow pool
+ * @hdd_v2_flow_pool_unmap: Callback to delete vdev flow pool
+ */
+struct policy_mgr_dp_cbacks {
+	void (*hdd_disable_rx_ol_in_concurrency)(bool);
+	void (*hdd_set_rx_mode_rps_cb)(bool);
+	void (*hdd_ipa_set_mcc_mode_cb)(bool);
+	void (*hdd_v2_flow_pool_map)(int);
+	void (*hdd_v2_flow_pool_unmap)(int);
+};
+
+/**
+ * struct policy_mgr_wma_cbacks - WMA Callbacks to be invoked
+ * from policy manager
+ * @wma_get_connection_info: Get the connection related info
+ *                         from wma table
+ */
+struct policy_mgr_wma_cbacks {
+	QDF_STATUS (*wma_get_connection_info)(uint8_t vdev_id,
+		struct policy_mgr_vdev_entry_info *conn_table_entry);
+};
+
+/**
+* policy_mgr_need_opportunistic_upgrade - check whether needs to change current
+* HW mode to single mac 2x2 or the other DBS mode(for Dual DBS HW only).
+* @psoc: PSOC object information
+* @reason: enum policy_mgr_conn_update_reason
+*
+*  This function is to check whether needs to change to single Mac mode.
+*  when opportunistic timer fired.  But a special case for Dual DBS HW, this
+*  function will check DBS to DBS change is required or not:
+*  1. For Dual DBS HW, if user set vdev priority list, we may need to do
+*	 DBS to DBS switching.
+*	 eg. P2P GO (2g) < SAP (5G) < STA (2g) in DBS2.
+*	 If STA down, we need to switch to DBS1: P2P GO (2g) < SAP (5g).
+*	 So, for opportunistic checking, we need to add DBS ->DBS checking
+*            as well.
+*  2. Reason code :
+*	   DBS -> Single MAC : POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC
+*	   DBS -> DBS : POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE
+*
+*  return: PM_NOP, upgrade is not needed, otherwise new action type
+*             and reason code be returned.
+*/
+enum policy_mgr_conc_next_action policy_mgr_need_opportunistic_upgrade(
+		struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_conn_update_reason *reason);
+
+/**
+ * policy_mgr_next_actions() - initiates actions needed on current
+ * connections once channel has been decided for the new
+ * connection
+ * @psoc: PSOC object information
+ * @session_id: Session id
+ * @action: action to be executed
+ * @reason: Reason for connection update
+ *
+ * This function initiates initiates actions
+ * needed on current connections once channel has been decided
+ * for the new connection. Notifies UMAC & FW as well
+ *
+ * Return: QDF_STATUS enum
+ */
+QDF_STATUS policy_mgr_next_actions(struct wlan_objmgr_psoc *psoc,
+		uint32_t session_id,
+		enum policy_mgr_conc_next_action action,
+		enum policy_mgr_conn_update_reason reason);
+
+/**
+ * policy_mgr_set_dual_mac_scan_config() - Set the dual MAC scan config
+ * @psoc: PSOC object information
+ * @dbs_val: Value of DBS bit
+ * @dbs_plus_agile_scan_val: Value of DBS plus agile scan bit
+ * @single_mac_scan_with_dbs_val: Value of Single MAC scan with DBS
+ *
+ * Set the values of scan config. For FW mode config, the existing values
+ * will be retained
+ *
+ * Return: None
+ */
+void policy_mgr_set_dual_mac_scan_config(struct wlan_objmgr_psoc *psoc,
+		uint8_t dbs_val,
+		uint8_t dbs_plus_agile_scan_val,
+		uint8_t single_mac_scan_with_dbs_val);
+
+/**
+ * policy_mgr_set_dual_mac_fw_mode_config() - Set the dual mac FW mode config
+ * @psoc: PSOC object information
+ * @dbs: DBS bit
+ * @dfs: Agile DFS bit
+ *
+ * Set the values of fw mode config. For scan config, the existing values
+ * will be retain.
+ *
+ * Return: None
+ */
+void policy_mgr_set_dual_mac_fw_mode_config(struct wlan_objmgr_psoc *psoc,
+		uint8_t dbs, uint8_t dfs);
+
+/**
+ * policy_mgr_soc_set_dual_mac_cfg_cb() - Callback for set dual mac config
+ * @status: Status of set dual mac config
+ * @scan_config: Current scan config whose status is the first param
+ * @fw_mode_config: Current FW mode config whose status is the first param
+ *
+ * Callback on setting the dual mac configuration
+ *
+ * Return: None
+ */
+void policy_mgr_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status,
+		uint32_t scan_config, uint32_t fw_mode_config);
+
+/**
+ * policy_mgr_map_concurrency_mode() - to map concurrency mode
+ * between sme and hdd
+ * @old_mode: sme provided adapter mode
+ * @new_mode: hdd provided concurrency mode
+ *
+ * This routine will map concurrency mode between sme and hdd
+ *
+ * Return: true or false
+ */
+bool policy_mgr_map_concurrency_mode(enum QDF_OPMODE *old_mode,
+				     enum policy_mgr_con_mode *new_mode);
+
+/**
+ * policy_mgr_get_channel_from_scan_result() - to get channel from scan result
+ * @psoc: PSOC object information
+ * @roam_profile: pointer to roam profile
+ * @channel: channel to be filled
+ *
+ * This routine gets channel which most likely a candidate to which STA
+ * will make connection.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_channel_from_scan_result(
+		struct wlan_objmgr_psoc *psoc,
+		void *roam_profile, uint8_t *channel);
+
+/**
+ * policy_mgr_mode_specific_num_open_sessions() - to get number of open sessions
+ *                                                for a specific mode
+ * @psoc: PSOC object information
+ * @mode: device mode
+ * @num_sessions: to store num open sessions
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_mode_specific_num_open_sessions(
+		struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE mode,
+		uint8_t *num_sessions);
+
+/**
+ * policy_mgr_mode_specific_num_active_sessions() - to get number of active
+ *               sessions for a specific mode
+ * @psoc: PSOC object information
+ * @mode: device mode
+ * @num_sessions: to store num active sessions
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_mode_specific_num_active_sessions(
+		struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE mode,
+		uint8_t *num_sessions);
+
+/**
+ * policy_mgr_concurrent_open_sessions_running() - Checks for
+ * concurrent open session
+ * @psoc: PSOC object information
+ *
+ * Checks if more than one open session is running for all the allowed modes
+ * in the driver
+ *
+ * Return: True if more than one open session exists, False otherwise
+ */
+bool policy_mgr_concurrent_open_sessions_running(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_max_concurrent_connections_reached() - Check if
+ * max conccurrency is reached
+ * @psoc: PSOC object information
+ * Checks for presence of concurrency where more than one connection exists
+ *
+ * Return: True if the max concurrency is reached, False otherwise
+ *
+ * Example:
+ *    STA + STA (wlan0 and wlan1 are connected) - returns true
+ *    STA + STA (wlan0 connected and wlan1 disconnected) - returns false
+ *    DUT with P2P-GO + P2P-CLIENT connection) - returns true
+ *
+ */
+bool policy_mgr_max_concurrent_connections_reached(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_clear_concurrent_session_count() - Clear active session count
+ * @psoc: PSOC object information
+ * Clears the active session count for all modes
+ *
+ * Return: None
+ */
+void policy_mgr_clear_concurrent_session_count(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_is_multiple_active_sta_sessions() - Check for
+ * multiple STA connections
+ * @psoc: PSOC object information
+ *
+ * Checks if multiple active STA connection are in the driver
+ *
+ * Return: True if multiple STA sessions are present, False otherwise
+ *
+ */
+bool policy_mgr_is_multiple_active_sta_sessions(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_is_sta_active_connection_exists() - Check if a STA
+ * connection is active
+ * @psoc: PSOC object information
+ *
+ * Checks if there is atleast one active STA connection in the driver
+ *
+ * Return: True if an active STA session is present, False otherwise
+ */
+bool policy_mgr_is_sta_active_connection_exists(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_concurrent_beaconing_sessions_running() - Checks
+ * for concurrent beaconing entities
+ * @psoc: PSOC object information
+ *
+ * Checks if multiple beaconing sessions are running i.e., if SAP or GO or IBSS
+ * are beaconing together
+ *
+ * Return: True if multiple entities are beaconing together, False otherwise
+ */
+bool policy_mgr_concurrent_beaconing_sessions_running(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_wait_for_connection_update() - Wait for hw mode
+ * command to get processed
+ * @psoc: PSOC object information
+ * Waits for CONNECTION_UPDATE_TIMEOUT duration until the set hw mode
+ * response sets the event connection_update_done_evt
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_wait_for_connection_update(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_reset_connection_update() - Reset connection
+ * update event
+ * @psoc: PSOC object information
+ * Resets the concurrent connection update event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_reset_connection_update(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_set_connection_update() - Set connection update
+ * event
+ * @psoc: PSOC object information
+ * Sets the concurrent connection update event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_set_connection_update(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_set_chan_switch_complete_evt() - set channel
+ * switch completion event
+ * @psoc: PSOC object information
+ * Sets the channel switch completion event.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_set_chan_switch_complete_evt(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_reset_chan_switch_complete_evt() - reset channel
+ * switch completion event
+ * @psoc: PSOC object information
+ * Resets the channel switch completion event.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_reset_chan_switch_complete_evt(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_set_opportunistic_update() - Set opportunistic
+ * update event
+ * @psoc: PSOC object information
+ * Sets the opportunistic update event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_set_opportunistic_update(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_stop_opportunistic_timer() - Stops opportunistic timer
+ * @psoc: PSOC object information
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_stop_opportunistic_timer(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_restart_opportunistic_timer() - Restarts opportunistic timer
+ * @psoc: PSOC object information
+ * @check_state: check timer state if this flag is set, else restart
+ *               irrespective of state
+ *
+ * Restarts opportunistic timer for DBS_OPPORTUNISTIC_TIME seconds.
+ * Check if current state is RUNNING if check_state is set, else
+ * restart the timer irrespective of state.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_restart_opportunistic_timer(
+		struct wlan_objmgr_psoc *psoc, bool check_state);
+
+/**
+ * policy_mgr_modify_sap_pcl_based_on_mandatory_channel() -
+ * Modify SAPs PCL based on mandatory channel list
+ * @psoc: PSOC object information
+ * @pcl_list_org: Pointer to the preferred channel list to be trimmed
+ * @weight_list_org: Pointer to the weights of the preferred channel list
+ * @pcl_len_org: Pointer to the length of the preferred chanel list
+ *
+ * Modifies the preferred channel list of SAP based on the mandatory channel
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_modify_sap_pcl_based_on_mandatory_channel(
+		struct wlan_objmgr_psoc *psoc, uint8_t *pcl_list_org,
+		uint8_t *weight_list_org, uint32_t *pcl_len_org);
+
+/**
+ * policy_mgr_update_and_wait_for_connection_update() - Update and wait for
+ * connection update
+ * @psoc: PSOC object information
+ * @session_id: Session id
+ * @channel: Channel number
+ * @reason: Reason for connection update
+ *
+ * Update the connection to either single MAC or dual MAC and wait for the
+ * update to complete
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_update_and_wait_for_connection_update(
+		struct wlan_objmgr_psoc *psoc, uint8_t session_id,
+		uint8_t channel, enum policy_mgr_conn_update_reason reason);
+
+/**
+ * policy_mgr_is_sap_mandatory_channel_set() - Checks if SAP
+ * mandatory channel is set
+ * @psoc: PSOC object information
+ * Checks if any mandatory channel is set for SAP operation
+ *
+ * Return: True if mandatory channel is set, false otherwise
+ */
+bool policy_mgr_is_sap_mandatory_channel_set(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_list_has_24GHz_channel() - Check if list contains 2.4GHz channels
+ * @channel_list: Channel list
+ * @list_len: Length of the channel list
+ *
+ * Checks if the channel list contains atleast one 2.4GHz channel
+ *
+ * Return: True if 2.4GHz channel is present, false otherwise
+ */
+bool policy_mgr_list_has_24GHz_channel(uint8_t *channel_list,
+		uint32_t list_len);
+
+/**
+ * policy_mgr_get_valid_chans() - Get the valid channel list
+ * @psoc: PSOC object information
+ * @chan_list: Pointer to the valid channel list
+ * @list_len: Pointer to the length of the valid channel list
+ *
+ * Gets the valid channel list filtered by band
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_valid_chans(struct wlan_objmgr_psoc *psoc,
+		uint8_t *chan_list, uint32_t *list_len);
+
+/**
+ * policy_mgr_get_nss_for_vdev() - Get the allowed nss value for the
+ * vdev
+ * @psoc: PSOC object information
+ * @dev_mode: connection type.
+ * @nss2g: Pointer to the 2G Nss parameter.
+ * @nss5g: Pointer to the 5G Nss parameter.
+ *
+ * Fills the 2G and 5G Nss values based on connection type.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_nss_for_vdev(struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_con_mode mode,
+		uint8_t *nss_2g, uint8_t *nss_5g);
+
+/**
+ * policy_mgr_get_sap_mandatory_channel() - Get the mandatory channel for SAP
+ * @psoc: PSOC object information
+ * @chan: Pointer to the SAP mandatory channel
+ *
+ * Gets the mandatory channel for SAP operation
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_sap_mandatory_channel(struct wlan_objmgr_psoc *psoc,
+		uint32_t *chan);
+
+/**
+ * policy_mgr_set_sap_mandatory_channels() - Set the mandatory channel for SAP
+ * @psoc: PSOC object information
+ * @channels: Channel list to be set
+ * @len: Length of the channel list
+ *
+ * Sets the channels for the mandatory channel list along with the length of
+ * of the channel list.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_set_sap_mandatory_channels(struct wlan_objmgr_psoc *psoc,
+		uint8_t *channels, uint32_t len);
+
+/**
+ * policy_mgr_is_any_mode_active_on_band_along_with_session() -
+ * Check if any connection mode is active on a band along with
+ * the given session
+ * @psoc: PSOC object information
+ * @session_id: Session along which active sessions are looked for
+ * @band: Operating frequency band of the connection
+ * POLICY_MGR_BAND_24: Looks for active connection on 2.4 GHz only
+ * POLICY_MGR_BAND_5: Looks for active connection on 5 GHz only
+ *
+ * Checks if any of the connection mode is active on a given frequency band
+ *
+ * Return: True if any connection is active on a given band, false otherwise
+ */
+bool policy_mgr_is_any_mode_active_on_band_along_with_session(
+		struct wlan_objmgr_psoc *psoc, uint8_t session_id,
+		enum policy_mgr_band band);
+
+/**
+ * policy_mgr_get_chan_by_session_id() - Get channel for a given session ID
+ * @psoc: PSOC object information
+ * @session_id: Session ID
+ * @chan: Pointer to the channel
+ *
+ * Gets the channel for a given session ID
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_chan_by_session_id(struct wlan_objmgr_psoc *psoc,
+		uint8_t session_id, uint8_t *chan);
+
+/**
+ * policy_mgr_get_mac_id_by_session_id() - Get MAC ID for a given session ID
+ * @psoc: PSOC object information
+ * @session_id: Session ID
+ * @mac_id: Pointer to the MAC ID
+ *
+ * Gets the MAC ID for a given session ID
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_mac_id_by_session_id(struct wlan_objmgr_psoc *psoc,
+		uint8_t session_id, uint8_t *mac_id);
+
+/**
+ * policy_mgr_get_mcc_session_id_on_mac() - Get MCC session's ID
+ * @psoc: PSOC object information
+ * @mac_id: MAC ID on which MCC session needs to be found
+ * @session_id: Session with which MCC combination needs to be found
+ * @mcc_session_id: Pointer to the MCC session ID
+ *
+ * Get the session ID of the MCC interface
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_mcc_session_id_on_mac(struct wlan_objmgr_psoc *psoc,
+		uint8_t mac_id, uint8_t session_id,
+		uint8_t *mcc_session_id);
+
+/**
+ * policy_mgr_get_mcc_operating_channel() - Get the MCC channel
+ * @psoc: PSOC object information
+ * @session_id: Session ID with which MCC is being done
+ *
+ * Gets the MCC channel for a given session ID.
+ *
+ * Return: '0' (INVALID_CHANNEL_ID) or valid channel number
+ */
+uint8_t policy_mgr_get_mcc_operating_channel(struct wlan_objmgr_psoc *psoc,
+		uint8_t session_id);
+
+/**
+ * policy_mgr_get_pcl_for_existing_conn() - Get PCL for existing connection
+ * @psoc: PSOC object information
+ * @mode: Connection mode of type 'policy_mgr_con_mode'
+ * @pcl_ch: Pointer to the PCL
+ * @len: Pointer to the length of the PCL
+ * @pcl_weight: Pointer to the weights of the PCL
+ * @weight_len: Max length of the weights list
+ * @all_matching_cxn_to_del: Need remove all entries before getting pcl
+ *
+ * Get the PCL for an existing connection
+ *
+ * Return: None
+ */
+QDF_STATUS policy_mgr_get_pcl_for_existing_conn(struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_con_mode mode,
+		uint8_t *pcl_ch, uint32_t *len,
+		uint8_t *weight_list, uint32_t weight_len,
+		bool all_matching_cxn_to_del);
+
+/**
+ * policy_mgr_get_valid_chan_weights() - Get the weightage for
+ * all valid channels
+ * @psoc: PSOC object information
+ * @weight: Pointer to the structure containing pcl, saved channel list and
+ * weighed channel list
+ *
+ * Provides the weightage for all valid channels. This compares the PCL list
+ * with the valid channel list. The channels present in the PCL get their
+ * corresponding weightage and the non-PCL channels get the default weightage
+ * of WEIGHT_OF_NON_PCL_CHANNELS.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_valid_chan_weights(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_pcl_chan_weights *weight);
+
+/**
+ * policy_mgr_set_hw_mode_on_channel_switch() - Set hw mode
+ * after channel switch
+ * @session_id: Session ID
+ *
+ * Sets hw mode after doing a channel switch
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_set_hw_mode_on_channel_switch(
+		struct wlan_objmgr_psoc *psoc, uint8_t session_id);
+
+/**
+ * policy_mgr_set_do_hw_mode_change_flag() - Set flag to indicate hw mode change
+ * @psoc: PSOC object information
+ * @flag: Indicate if hw mode change is required or not
+ *
+ * Set the flag to indicate whether a hw mode change is required after a
+ * vdev up or not. Flag value of true indicates that a hw mode change is
+ * required after vdev up.
+ *
+ * Return: None
+ */
+void policy_mgr_set_do_hw_mode_change_flag(struct wlan_objmgr_psoc *psoc,
+		bool flag);
+
+/**
+ * policy_mgr_is_hw_mode_change_after_vdev_up() - Check if hw
+ * mode change is needed
+ * @psoc: PSOC object information
+ * Returns the flag which indicates if a hw mode change is required after
+ * vdev up.
+ *
+ * Return: True if hw mode change is required, false otherwise
+ */
+bool policy_mgr_is_hw_mode_change_after_vdev_up(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_checkn_update_hw_mode_single_mac_mode() - Set hw_mode to SMM
+ * if required
+ * @psoc: PSOC object information
+ * @channel: channel number for the new STA connection
+ *
+ * After the STA disconnection, if the hw_mode is in DBS and the new STA
+ * connection is coming in the band in which existing connections are
+ * present, then this function stops the dbs opportunistic timer and sets
+ * the hw_mode to Single MAC mode (SMM).
+ *
+ * Return: None
+ */
+void policy_mgr_checkn_update_hw_mode_single_mac_mode(
+		struct wlan_objmgr_psoc *psoc, uint8_t channel);
+
+/**
+ * policy_mgr_dump_connection_status_info() - Dump the concurrency information
+ * @psoc: PSOC object information
+ * Prints the concurrency information such as tx/rx spatial stream, chainmask,
+ * etc.
+ *
+ * Return: None
+ */
+void policy_mgr_dump_connection_status_info(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_mode_specific_vdev_id() - provides the
+ * vdev id of the pecific mode
+ * @psoc: PSOC object information
+ * @mode: type of connection
+ *
+ * This function provides vdev id for the given mode
+ *
+ * Return: vdev id
+ */
+uint32_t policy_mgr_mode_specific_vdev_id(struct wlan_objmgr_psoc *psoc,
+					  enum policy_mgr_con_mode mode);
+
+/**
+ * policy_mgr_mode_specific_connection_count() - provides the
+ * count of connections of specific mode
+ * @psoc: PSOC object information
+ * @mode: type of connection
+ * @list: To provide the indices on pm_conc_connection_list
+ *	(optional)
+ *
+ * This function provides the count of current connections
+ *
+ * Return: connection count of specific type
+ */
+uint32_t policy_mgr_mode_specific_connection_count(
+		struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode,
+		uint32_t *list);
+
+/**
+ * policy_mgr_check_conn_with_mode_and_vdev_id() - checks if any active
+ * session with specific mode and vdev_id
+ * @psoc: PSOC object information
+ * @mode: type of connection
+ * @vdev_id: vdev_id of the connection
+ *
+ * This function checks if any active session with specific mode and vdev_id
+ * is present
+ *
+ * Return: QDF STATUS with success if active session is found, else failure
+ */
+QDF_STATUS policy_mgr_check_conn_with_mode_and_vdev_id(
+		struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode,
+		uint32_t vdev_id);
+
+/**
+ * policy_mgr_hw_mode_transition_cb() - Callback for HW mode
+ * transition from FW
+ * @old_hw_mode_index: Old HW mode index
+ * @new_hw_mode_index: New HW mode index
+ * @num_vdev_mac_entries: Number of vdev-mac id mapping that follows
+ * @vdev_mac_map: vdev-mac id map. This memory will be freed by the caller.
+ * So, make local copy if needed.
+ *
+ * Provides the old and new HW mode index set by the FW
+ *
+ * Return: None
+ */
+void policy_mgr_hw_mode_transition_cb(uint32_t old_hw_mode_index,
+		uint32_t new_hw_mode_index,
+		uint32_t num_vdev_mac_entries,
+		struct policy_mgr_vdev_mac_map *vdev_mac_map,
+		struct wlan_objmgr_psoc *context);
+
+/**
+ * policy_mgr_current_concurrency_is_mcc() - To check the current
+ * concurrency combination if it is doing MCC
+ * @psoc: PSOC object information
+ * This routine is called to check if it is doing MCC
+ *
+ * Return: True - MCC, False - Otherwise
+ */
+bool policy_mgr_current_concurrency_is_mcc(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_register_sme_cb() - register SME callbacks
+ * @psoc: PSOC object information
+ * @sme_cbacks: function pointers from SME
+ *
+ * API, allows SME to register callbacks to be invoked by policy
+ * mgr
+ *
+ * Return: SUCCESS,
+ *         Failure (if registration fails)
+ */
+QDF_STATUS policy_mgr_register_sme_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_sme_cbacks *sme_cbacks);
+
+/**
+ * policy_mgr_register_hdd_cb() - register HDD callbacks
+ * @psoc: PSOC object information
+ * @hdd_cbacks: function pointers from HDD
+ *
+ * API, allows HDD to register callbacks to be invoked by policy
+ * mgr
+ *
+ * Return: SUCCESS,
+ *         Failure (if registration fails)
+ */
+QDF_STATUS policy_mgr_register_hdd_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_hdd_cbacks *hdd_cbacks);
+
+/**
+ * policy_mgr_deregister_hdd_cb() - Deregister HDD callbacks
+ * @psoc: PSOC object information
+ *
+ * API, allows HDD to deregister callbacks
+ *
+ * Return: SUCCESS,
+ *         Failure (if de-registration fails)
+ */
+QDF_STATUS policy_mgr_deregister_hdd_cb(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_register_tdls_cb() - register TDLS callbacks
+ * @psoc: PSOC object information
+ * @tdls_cbacks: function pointers from TDLS
+ *
+ * API, allows TDLS to register callbacks to be invoked by
+ * policy mgr
+ *
+ * Return: SUCCESS,
+ *         Failure (if registration fails)
+ */
+QDF_STATUS policy_mgr_register_tdls_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_tdls_cbacks *tdls_cbacks);
+
+/**
+ * policy_mgr_register_cdp_cb() - register CDP callbacks
+ * @psoc: PSOC object information
+ * @cdp_cbacks: function pointers from CDP
+ *
+ * API, allows CDP to register callbacks to be invoked by
+ * policy mgr
+ *
+ * Return: SUCCESS,
+ *         Failure (if registration fails)
+ */
+QDF_STATUS policy_mgr_register_cdp_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_cdp_cbacks *cdp_cbacks);
+
+/**
+ * policy_mgr_register_dp_cb() - register CDP callbacks
+ * @psoc: PSOC object information
+ * @cdp_cbacks: function pointers from CDP
+ *
+ * API, allows CDP to register callbacks to be invoked by
+ * policy mgr
+ *
+ * Return: SUCCESS,
+ *         Failure (if registration fails)
+ */
+QDF_STATUS policy_mgr_register_dp_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_dp_cbacks *dp_cbacks);
+
+/**
+ * policy_mgr_register_wma_cb() - register WMA callbacks
+ * @psoc: PSOC object information
+ * @wma_cbacks: function pointers from WMA
+ *
+ * API, allows WMA to register callbacks to be invoked by policy
+ * mgr
+ *
+ * Return: SUCCESS,
+ *         Failure (if registration fails)
+ */
+QDF_STATUS policy_mgr_register_wma_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_wma_cbacks *wma_cbacks);
+
+/**
+ * policy_mgr_is_dbs_enable() - Check if master DBS control is enabled
+ * @psoc: PSOC object information
+ * Checks if the master DBS control is enabled. This will be used
+ * to override any other DBS capability
+ *
+ * Return: True if master DBS control is enabled
+ */
+bool policy_mgr_is_dbs_enable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_is_hw_dbs_capable() - Check if HW is DBS capable
+ * @psoc: PSOC object information
+ * Checks if the HW is DBS capable
+ *
+ * Return: true if the HW is DBS capable
+ */
+bool policy_mgr_is_hw_dbs_capable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_is_hw_sbs_capable() - Check if HW is SBS capable
+ * @psoc: PSOC object information
+ * Checks if the HW is SBS capable
+ *
+ * Return: true if the HW is SBS capable
+ */
+bool policy_mgr_is_hw_sbs_capable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_is_current_hwmode_dbs() - Check if current hw mode is DBS
+ * @psoc: PSOC object information
+ * Checks if current hardware mode of the system is DBS or no
+ *
+ * Return: true or false
+ */
+bool policy_mgr_is_current_hwmode_dbs(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_is_hw_dbs_2x2_capable() - if hardware is capable of dbs 2x2
+ * @psoc: PSOC object information
+ * This function checks if hw_modes supported are always capable of
+ * DBS and there is no need for downgrading while entering DBS.
+ *    true: DBS 2x2 can always be supported
+ *    false: hw_modes support DBS 1x1 as well
+ * Genoa DBS 2x2 + 1x1 will not be included.
+ *
+ * Return: true - DBS2x2, false - DBS1x1
+ */
+bool policy_mgr_is_hw_dbs_2x2_capable(struct wlan_objmgr_psoc *psoc);
+
+/*
+ * policy_mgr_is_2x2_1x1_dbs_capable() - check 2x2+1x1 DBS supported or not
+ * @psoc: PSOC object data
+ *
+ * This routine is called to check 2x2 5G + 1x1 2G (DBS1) or
+ * 2x2 2G + 1x1 5G (DBS2) support or not.
+ * Either DBS1 or DBS2 supported
+ *
+ * Return: true/false
+ */
+bool policy_mgr_is_2x2_1x1_dbs_capable(struct wlan_objmgr_psoc *psoc);
+
+/*
+ * policy_mgr_is_2x2_5G_1x1_2G_dbs_capable() - check Genoa DBS1 enabled or not
+ * @psoc: PSOC object data
+ *
+ * This routine is called to check support DBS1 or not.
+ * Notes: DBS1: 2x2 5G + 1x1 2G.
+ * This function will call policy_mgr_get_hw_mode_idx_from_dbs_hw_list to match
+ * the HW mode from hw mode list. The parameters will also be matched to
+ * 2x2 5G +2x2 2G HW mode. But firmware will not report 2x2 5G + 2x2 2G alone
+ * with 2x2 5G + 1x1 2G at same time. So, it is safe to find DBS1 with
+ * policy_mgr_get_hw_mode_idx_from_dbs_hw_list.
+ *
+ * Return: true/false
+ */
+bool policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(struct wlan_objmgr_psoc *psoc);
+
+/*
+ * policy_mgr_is_2x2_2G_1x1_5G_dbs_capable() - check Genoa DBS2 enabled or not
+ * @psoc: PSOC object data
+ *
+ * This routine is called to check support DBS2 or not.
+ * Notes: DBS2: 2x2 2G + 1x1 5G
+ *
+ * Return: true/false
+ */
+bool policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_init() - Policy Manager component initialization
+ *                 routine
+ *
+ * Return - QDF Status
+ */
+QDF_STATUS policy_mgr_init(void);
+
+/**
+ * policy_mgr_deinit() - Policy Manager component
+ *                 de-initialization routine
+ *
+ * Return - QDF Status
+ */
+QDF_STATUS policy_mgr_deinit(void);
+
+/**
+ * policy_mgr_psoc_enable() - Policy Manager component
+ *                 enable routine
+ * @psoc: PSOC object information
+ *
+ * Return - QDF Status
+ */
+QDF_STATUS policy_mgr_psoc_enable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_psoc_disable() - Policy Manager component
+ *                 disable routine
+ * @psoc: PSOC object information
+ *
+ * Return - QDF Status
+ */
+QDF_STATUS policy_mgr_psoc_disable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_psoc_open() - Policy Manager component
+ *                 open routine
+ * @psoc: PSOC object information
+ *
+ * Return - QDF Status
+ */
+QDF_STATUS policy_mgr_psoc_open(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_psoc_close() - Policy Manager component
+ *                 close routine
+ * @psoc: PSOC object information
+ *
+ * Return - QDF Status
+ */
+QDF_STATUS policy_mgr_psoc_close(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_num_dbs_hw_modes() - Get number of HW mode
+ * @psoc: PSOC object information
+ * Fetches the number of DBS HW modes returned by the FW
+ *
+ * Return: Negative value on error or returns the number of DBS HW modes
+ */
+int8_t policy_mgr_get_num_dbs_hw_modes(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_dbs_hw_modes() - Get the DBS HW modes for userspace
+ * @psoc: PSOC object information
+ * @one_by_one_dbs: 1x1 DBS capability of HW
+ * @two_by_two_dbs: 2x2 DBS capability of HW
+ *
+ * Provides the DBS HW mode capability such as whether
+ * 1x1 DBS, 2x2 DBS is supported by the HW or not.
+ *
+ * Return: Failure in case of error and 0 on success
+ *         one_by_one_dbs/two_by_two_dbs will be false,
+ *         if they are not supported.
+ *         one_by_one_dbs/two_by_two_dbs will be true,
+ *         if they are supported.
+ *         false values of one_by_one_dbs/two_by_two_dbs,
+ *         indicate DBS is disabled
+ */
+QDF_STATUS policy_mgr_get_dbs_hw_modes(struct wlan_objmgr_psoc *psoc,
+		bool *one_by_one_dbs, bool *two_by_two_dbs);
+
+/**
+ * policy_mgr_check_sta_ap_concurrent_ch_intf() - Restart SAP in STA-AP case
+ * @data: Pointer to STA adapter
+ *
+ * Restarts the SAP interface in STA-AP concurrency scenario
+ *
+ * Restart: None
+ */
+void policy_mgr_check_sta_ap_concurrent_ch_intf(void *data);
+
+/**
+ * policy_mgr_get_current_hw_mode() - Get current HW mode params
+ * @psoc: PSOC object information
+ * @hw_mode: HW mode parameters
+ *
+ * Provides the current HW mode parameters if the HW mode is initialized
+ * in the driver
+ *
+ * Return: Success if the current HW mode params are successfully populated
+ */
+QDF_STATUS policy_mgr_get_current_hw_mode(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_hw_mode_params *hw_mode);
+
+/**
+ * policy_mgr_get_dbs_plus_agile_scan_config() - Get DBS plus agile scan bit
+ * @psoc: PSOC object information
+ * Gets the DBS plus agile scan bit of concurrent_scan_config_bits
+ *
+ * Return: 0 or 1 to indicate the DBS plus agile scan bit
+ */
+bool policy_mgr_get_dbs_plus_agile_scan_config(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_single_mac_scan_with_dfs_config() - Get Single
+ * MAC scan with DFS bit
+ * @psoc: PSOC object information
+ * Gets the Single MAC scan with DFS bit of concurrent_scan_config_bits
+ *
+ * Return: 0 or 1 to indicate the Single MAC scan with DFS bit
+ */
+bool policy_mgr_get_single_mac_scan_with_dfs_config(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_set_hw_mode_change_in_progress() - Set value
+ * corresponding to policy_mgr_hw_mode_change that indicate if
+ * HW mode change is in progress
+ * @psoc: PSOC object information
+ * @value: Indicate if hw mode change is in progress
+ *
+ * Set the value corresponding to policy_mgr_hw_mode_change that
+ * indicated if hw mode change is in progress.
+ *
+ * Return: None
+ */
+void policy_mgr_set_hw_mode_change_in_progress(
+	struct wlan_objmgr_psoc *psoc, enum policy_mgr_hw_mode_change value);
+
+/**
+ * policy_mgr_is_hw_mode_change_in_progress() - Check if HW mode
+ * change is in progress.
+ * @psoc: PSOC object information
+ *
+ * Returns the corresponding policy_mgr_hw_mode_change value.
+ *
+ * Return: policy_mgr_hw_mode_change value.
+ */
+enum policy_mgr_hw_mode_change policy_mgr_is_hw_mode_change_in_progress(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_hw_mode_change_from_hw_mode_index() - Get
+ * matching HW mode from index
+ * @psoc: PSOC object information
+ * @hw_mode_index: HW mode index
+ * Returns the corresponding policy_mgr_hw_mode_change HW mode.
+ *
+ * Return: policy_mgr_hw_mode_change value.
+ */
+enum policy_mgr_hw_mode_change policy_mgr_get_hw_mode_change_from_hw_mode_index(
+	struct wlan_objmgr_psoc *psoc, uint32_t hw_mode_index);
+
+/**
+ * policy_mgr_is_scan_simultaneous_capable() - Check if scan
+ * parallelization is supported or not
+ * @psoc: PSOC object information
+ * currently scan parallelization feature support is dependent on DBS but
+ * it can be independent in future.
+ *
+ * Return: True if master DBS control is enabled
+ */
+bool policy_mgr_is_scan_simultaneous_capable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_set_user_cfg() - Function to set user cfg variables
+ * required by policy manager component
+ * @psoc: PSOC object information
+ * @user_cfg: User config valiables structure pointer
+ *
+ * This function sets the user cfg variables required by policy
+ * manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+QDF_STATUS policy_mgr_set_user_cfg(struct wlan_objmgr_psoc *psoc,
+				struct policy_mgr_user_cfg *user_cfg);
+
+/**
+ * policy_mgr_init_dbs_config() - Function to initialize DBS
+ * config in policy manager component
+ * @psoc: PSOC object information
+ * @scan_config: DBS scan config
+ * @fw_config: DBS FW config
+ *
+ * This function sets the DBS configurations required by policy
+ * manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+void policy_mgr_init_dbs_config(struct wlan_objmgr_psoc *psoc,
+		uint32_t scan_config, uint32_t fw_config);
+
+/**
+ * policy_mgr_update_dbs_scan_config() - Function to update
+ * DBS scan config in policy manager component
+ * @psoc: PSOC object information
+ *
+ * This function updates the DBS scan configurations required by
+ * policy manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+void policy_mgr_update_dbs_scan_config(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_update_dbs_fw_config() - Function to update DBS FW
+ * config in policy manager component
+ * @psoc: PSOC object information
+ *
+ * This function updates the DBS FW configurations required by
+ * policy manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+void policy_mgr_update_dbs_fw_config(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_update_dbs_req_config() - Function to update DBS
+ * request config in policy manager component
+ * @psoc: PSOC object information
+ * @scan_config: DBS scan config
+ * @fw_config: DBS FW config
+ *
+ * This function updates DBS request configurations required by
+ * policy manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+void policy_mgr_update_dbs_req_config(struct wlan_objmgr_psoc *psoc,
+		uint32_t scan_config, uint32_t fw_mode_config);
+
+/**
+ * policy_mgr_dump_dbs_hw_mode() - Function to dump DBS config
+ * @psoc: PSOC object information
+ *
+ * This function dumps the DBS configurations
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+void policy_mgr_dump_dbs_hw_mode(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_init_dbs_hw_mode() - Function to initialize DBS HW
+ * modes in policy manager component
+ * @psoc: PSOC object information
+ * @num_dbs_hw_modes: Number of HW modes
+ * @ev_wlan_dbs_hw_mode_list: HW list
+ *
+ * This function to initialize the DBS HW modes in policy
+ * manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+void policy_mgr_init_dbs_hw_mode(struct wlan_objmgr_psoc *psoc,
+				uint32_t num_dbs_hw_modes,
+				uint32_t *ev_wlan_dbs_hw_mode_list);
+
+/**
+ * policy_mgr_update_hw_mode_list() - Function to initialize DBS
+ * HW modes in policy manager component
+ * @psoc: PSOC object information
+ * @tgt_hdl: Target psoc information
+ *
+ * This function to initialize the DBS HW modes in policy
+ * manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+QDF_STATUS policy_mgr_update_hw_mode_list(struct wlan_objmgr_psoc *psoc,
+					  struct target_psoc_info *tgt_hdl);
+
+/**
+ * policy_mgr_update_hw_mode_index() - Function to update
+ * current HW mode in policy manager component
+ * @psoc: PSOC object information
+ * @new_hw_mode_index: index to new HW mode
+ *
+ * This function to update the current HW mode in policy manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+void policy_mgr_update_hw_mode_index(struct wlan_objmgr_psoc *psoc,
+		uint32_t new_hw_mode_index);
+
+/**
+ * policy_mgr_update_old_hw_mode_index() - Function to update
+ * old HW mode in policy manager component
+ * @psoc: PSOC object information
+ * @new_hw_mode_index: index to old HW mode
+ *
+ * This function to update the old HW mode in policy manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+void policy_mgr_update_old_hw_mode_index(struct wlan_objmgr_psoc *psoc,
+		uint32_t old_hw_mode_index);
+
+/**
+ * policy_mgr_update_new_hw_mode_index() - Function to update
+ * new HW mode in policy manager component
+ * @psoc: PSOC object information
+ * @new_hw_mode_index: index to new HW mode
+ *
+ * This function to update the new HW mode in policy manager
+ *
+ * Return: SUCCESS or FAILURE
+ *
+ */
+void policy_mgr_update_new_hw_mode_index(struct wlan_objmgr_psoc *psoc,
+		uint32_t new_hw_mode_index);
+
+/**
+ * policy_mgr_is_chan_ok_for_dnbs() - Function to check if a channel
+ * is OK for "Do Not Break Stream"
+ * @psoc: PSOC object information
+ * @channel: Channel to check.
+ * @ok: Pointer to flag in which status will be stored
+ * This function checks if a channel is OK for
+ * "Do Not Break Stream"
+ * Return: SUCCESS or FAILURE
+ */
+QDF_STATUS policy_mgr_is_chan_ok_for_dnbs(struct wlan_objmgr_psoc *psoc,
+			uint8_t channel, bool *ok);
+
+/**
+ * policy_mgr_get_hw_dbs_nss() - Computes DBS NSS
+ * @psoc: PSOC object information
+ * @nss_dbs: NSS info of both MAC0 and MAC1
+ * This function computes NSS info of both MAC0 and MAC1
+ *
+ * Return: uint32_t value signifies supported RF chains
+ */
+uint32_t policy_mgr_get_hw_dbs_nss(struct wlan_objmgr_psoc *psoc,
+				   struct dbs_nss *nss_dbs);
+
+/**
+ * policy_mgr_is_dnsc_set - Check if user has set
+ * "Do_Not_Switch_Channel" for the vdev passed
+ * @vdev: vdev pointer
+ *
+ * Get "Do_Not_Switch_Channel" setting for the vdev passed.
+ *
+ * Return: true for success, else false
+ */
+bool policy_mgr_is_dnsc_set(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * policy_mgr_get_updated_scan_and_fw_mode_config() - Function
+ * to get latest scan & fw config for DBS
+ * @psoc: PSOC object information
+ * @scan_config: DBS related scan config
+ * @fw_mode_config: DBS related FW config
+ * @dual_mac_disable_ini: DBS related ini config
+ * This function returns the latest DBS configuration for
+ * connection & scan, sent to FW
+ * Return: SUCCESS or FAILURE
+ */
+QDF_STATUS policy_mgr_get_updated_scan_and_fw_mode_config(
+		struct wlan_objmgr_psoc *psoc, uint32_t *scan_config,
+		uint32_t *fw_mode_config, uint32_t dual_mac_disable_ini,
+		uint32_t channel_select_logic_conc);
+
+/**
+ * policy_mgr_is_safe_channel - Check if the channel is in LTE
+ * coex channel avoidance list
+ * @psoc: PSOC object information
+ * @channel: channel to be checked
+ *
+ * Check if the channel is in LTE coex channel avoidance list.
+ *
+ * Return: true for success, else false
+ */
+bool policy_mgr_is_safe_channel(struct wlan_objmgr_psoc *psoc,
+		uint8_t channel);
+
+/**
+ * policy_mgr_is_force_scc() - checks if SCC needs to be
+ * mandated
+ * @psoc: PSOC object information
+ *
+ * This function checks if SCC needs to be mandated or not
+ *
+ * Return: True if SCC to be mandated, false otherwise
+ */
+bool policy_mgr_is_force_scc(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_valid_sap_conc_channel_check() - checks & updates
+ * the channel SAP to come up on in case of STA+SAP concurrency
+ * @psoc: PSOC object information
+ * @con_ch: pointer to the channel on which sap will come up
+ * @sap_ch: initial channel for SAP
+ *
+ * This function checks & updates the channel SAP to come up on in
+ * case of STA+SAP concurrency
+ * Return: Success if SAP can come up on a channel
+ */
+QDF_STATUS policy_mgr_valid_sap_conc_channel_check(
+	struct wlan_objmgr_psoc *psoc, uint8_t *con_ch, uint8_t sap_ch);
+
+/**
+ * policy_mgr_get_alternate_channel_for_sap() - Get an alternate
+ * channel to move the SAP to
+ * @psoc: PSOC object information
+ *
+ * This function returns an alternate channel for SAP to move to
+ * Return: The new channel for SAP
+ */
+uint8_t policy_mgr_get_alternate_channel_for_sap(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_disallow_mcc() - Check for mcc
+ *
+ * @psoc: PSOC object information
+ * @channel: channel on which new connection is coming up
+ *
+ * When a new connection is about to come up check if current
+ * concurrency combination including the new connection is
+ * causing MCC
+ *
+ * Return: True if it is causing MCC
+ */
+bool policy_mgr_disallow_mcc(struct wlan_objmgr_psoc *psoc,
+		uint8_t channel);
+
+/**
+ * policy_mgr_mode_specific_get_channel() - Get channel for a
+ * connection type
+ * @psoc: PSOC object information
+ * @chan_list: Connection type
+ *
+ * Get channel for a connection type
+ *
+ * Return: channel number
+ */
+uint8_t policy_mgr_mode_specific_get_channel(
+	struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode);
+
+/**
+ * policy_mgr_enable_disable_sap_mandatory_chan_list() - Update the value of
+ * enable_sap_mandatory_chan_list
+ * @psoc: Pointer to soc
+ * @val: value of enable_sap_mandatory_chan_list
+ *
+ * Update the value of enable_sap_mandatory_chan_list
+ *
+ * Return: void
+ */
+void policy_mgr_enable_disable_sap_mandatory_chan_list(
+		struct wlan_objmgr_psoc *psoc, bool val);
+
+/**
+ * policy_mgr_add_sap_mandatory_chan() - Add chan to SAP mandatory channel
+ * list
+ * @psoc: Pointer to soc
+ * @chan: Channel to be added
+ *
+ * Add chan to SAP mandatory channel list
+ *
+ * Return: None
+ */
+void policy_mgr_add_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc,
+		uint8_t chan);
+
+/**
+ * policy_mgr_is_sap_mandatory_chan_list_enabled() - Return the SAP mandatory
+ * channel list enabled status
+ * @psoc: Pointer to soc
+ *
+ * Get the SAP mandatory channel list enabled status
+ *
+ * Return: Enable or Disable
+ */
+bool policy_mgr_is_sap_mandatory_chan_list_enabled(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_sap_mandatory_chan_list_len() - Return the SAP mandatory
+ * channel list len
+ * @psoc: Pointer to soc
+ *
+ * Get the SAP mandatory channel list len
+ *
+ * Return: Channel list length
+ */
+uint32_t policy_mgr_get_sap_mandatory_chan_list_len(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_init_sap_mandatory_2g_chan() - Init 2.4G SAP mandatory channel
+ * list
+ * @psoc: Pointer to soc
+ *
+ * Initialize the 2.4G SAP mandatory channels
+ *
+ * Return: None
+ */
+void  policy_mgr_init_sap_mandatory_2g_chan(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_remove_sap_mandatory_chan() - Remove channel from SAP mandatory
+ * channel list
+ * @psoc: Pointer to soc
+ * @chan: channel to be removed from mandatory channel list
+ *
+ * Remove channel from SAP mandatory channel list
+ *
+ * Return: None
+ */
+void policy_mgr_remove_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc,
+		uint8_t chan);
+/*
+ * policy_set_cur_conc_system_pref - set current conc_system_pref
+ * @psoc: soc pointer
+ *
+ * Set the current concurrency system preference.
+ *
+ * Return: None
+ */
+void policy_mgr_set_cur_conc_system_pref(struct wlan_objmgr_psoc *psoc,
+		uint8_t conc_system_pref);
+/**
+ * policy_mgr_get_cur_conc_system_pref - Get current conc_system_pref
+ * @psoc: soc pointer
+ *
+ * Get the current concurrent system preference.
+ *
+ * Return: conc_system_pref
+ */
+uint8_t policy_mgr_get_cur_conc_system_pref(struct wlan_objmgr_psoc *psoc);
+/**
+ * policy_mgr_check_and_stop_opportunistic_timer - Get current
+ * state of opportunistic timer, if running, stop it and take
+ * action
+ * @psoc: soc pointer
+ * @id: Session/vdev id
+ *
+ * Get the current state of opportunistic timer, if it is
+ * running, stop it and take action.
+ *
+ * Return: None
+ */
+void policy_mgr_check_and_stop_opportunistic_timer(
+	struct wlan_objmgr_psoc *psoc, uint8_t id);
+
+/**
+ * policy_mgr_set_weight_of_dfs_passive_channels_to_zero() - set weight of dfs
+ * and passive channels to 0
+ * @psoc: pointer to soc
+ * @pcl_channels: preferred channel list
+ * @len: length of preferred channel list
+ * @weight_list: preferred channel weight list
+ * @weight_len: length of weight list
+ * This function set the weight of dfs and passive channels to 0
+ *
+ * Return: None
+ */
+void policy_mgr_set_weight_of_dfs_passive_channels_to_zero(
+		struct wlan_objmgr_psoc *psoc, uint8_t *pcl_channels,
+		uint32_t *len, uint8_t *weight_list, uint32_t weight_len);
+
+/**
+ * policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan() - check if sta+sap scc
+ * allowed on dfs chan
+ * @psoc: pointer to soc
+ * This function is used to check if sta+sap scc allowed on dfs channel
+ *
+ * Return: true if sta+sap scc is allowed on dfs channel, otherwise false
+ */
+bool policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(
+		struct wlan_objmgr_psoc *psoc);
+/**
+ * policy_mgr_is_sta_connected_2g() - check if sta connected in 2g
+ * @psoc: pointer to soc
+ *
+ * Return: true if sta is connected in 2g else false
+ */
+bool policy_mgr_is_sta_connected_2g(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_trim_acs_channel_list() - Trim the ACS channel list based
+ * on the number of active station connections
+ * @org_ch_list: ACS channel list from user space
+ * @org_ch_list_count: ACS channel count from user space
+ *
+ * Return: None
+ */
+void policy_mgr_trim_acs_channel_list(struct wlan_objmgr_psoc *psoc,
+		uint8_t *org_ch_list, uint8_t *org_ch_list_count);
+
+/**
+ * policy_mgr_is_hwmode_set_for_given_chnl() - to check for given channel
+ * if the hw mode is properly set.
+ * @psoc: pointer to psoc
+ * @channel: given channel
+ *
+ * If HW mode is properly set for given channel then it returns true else
+ * it returns false.
+ * For example, when 2x2 DBS is supported and if the first connection is
+ * coming up on 2G band then driver expects DBS HW mode to be set first
+ * before the connection can be established. Driver can call this API to
+ * find-out if HW mode is set properly.
+ *
+ * Return: true if HW mode is set properly else false
+ */
+bool policy_mgr_is_hwmode_set_for_given_chnl(struct wlan_objmgr_psoc *psoc,
+					     uint8_t channel);
+/*
+ * policy_mgr_get_connection_info() - Get info of all active connections
+ * @info: Pointer to connection info
+ *
+ * Return: Connection count
+ */
+uint32_t policy_mgr_get_connection_info(struct wlan_objmgr_psoc *psoc,
+					struct connection_info *info);
+/**
+ * policy_mgr_register_mode_change_cb() - Register mode change callback with
+ * policy manager
+ * @callback: HDD callback to be registered
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_register_mode_change_cb(struct wlan_objmgr_psoc *psoc,
+			send_mode_change_event_cb mode_change_cb);
+/**
+ * policy_mgr_deregister_mode_change_cb() - Deregister mode change callback with
+ * policy manager
+ * @callback: HDD callback to be registered
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_deregister_mode_change_cb(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_allow_sap_go_concurrency() - check whether SAP/GO concurrency is
+ * allowed.
+ * @psoc: pointer to soc
+ * @policy_mgr_con_mode: operating mode of interface to be checked
+ * @channel: new operating channel of the interface to be checked
+ * @vdev_id: vdev id of the connection to be checked, 0xff for new connection
+ *
+ * Checks whether new channel SAP/GO can co-exist with the channel of existing
+ * SAP/GO connection. This API mainly used for two purposes:
+ *
+ * 1) When new GO/SAP session is coming up and needs to check if this session's
+ * channel can co-exist with existing existing GO/SAP sessions. For example,
+ * when single radio platform comes, MCC for SAP/GO+SAP/GO is not supported, in
+ * such case this API should prevent bringing the second connection.
+ *
+ * 2) There is already existing SAP+GO combination but due to upper layer
+ * notifying LTE-COEX event or sending command to move one of the connections
+ * to different channel. In such cases before moving existing connection to new
+ * channel, check if new channel can co-exist with the other existing
+ * connection. For example, one SAP1 is on channel-6 and second SAP2 is on
+ * channel-36 and lets say they are doing DBS, and lets say upper layer sends
+ * LTE-COEX to move SAP1 from channel-6 to channel-149. In this case, SAP1 and
+ * SAP2 will end up doing MCC which may not be desirable result. such cases
+ * will be prevented with this API.
+ *
+ * Return: true or false
+ */
+bool policy_mgr_allow_sap_go_concurrency(struct wlan_objmgr_psoc *psoc,
+					 enum policy_mgr_con_mode mode,
+					 uint8_t channel,
+					 uint32_t vdev_id);
+
+/**
+ * policy_mgr_dual_beacon_on_single_mac_scc_capable() - get capability that
+ * whether support dual beacon on same channel on single MAC
+ * @psoc: pointer to soc
+ *
+ *  Return: bool: capable
+ */
+bool policy_mgr_dual_beacon_on_single_mac_scc_capable(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_dual_beacon_on_single_mac_mcc_capable() - get capability that
+ * whether support dual beacon on different channel on single MAC
+ * @psoc: pointer to soc
+ *
+ *  Return: bool: capable
+ */
+bool policy_mgr_dual_beacon_on_single_mac_mcc_capable(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_sta_sap_scc_on_lte_coex_chan() - get capability that
+ * whether support sta sap scc on lte coex chan
+ * @psoc: pointer to soc
+ *
+ *  Return: bool: capable
+ */
+bool policy_mgr_sta_sap_scc_on_lte_coex_chan(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_valid_channel_for_channel_switch() - check for valid channel for
+ * channel switch.
+ * @psoc: poniter to psoc
+ * @channel: channel to be validated.
+ * This function validates whether the given channel is valid for channel
+ * switch.
+ *
+ * Return: true or false
+ */
+bool policy_mgr_is_valid_for_channel_switch(struct wlan_objmgr_psoc *psoc,
+					    uint8_t channel);
+
+/**
+ * policy_mgr_update_user_config_sap_chan() - Update user configured channel
+ * @psoc: poniter to psoc
+ * @channel: channel to be upated
+ *
+ * Return: void
+ **/
+void policy_mgr_update_user_config_sap_chan(
+			struct wlan_objmgr_psoc *psoc, uint32_t channel);
+
+/**
+ * policy_mgr_is_sap_restart_required_after_sta_disconnect() - is sap restart
+ * required
+ * after sta disconnection
+ * @psoc: psoc object data
+ * @intf_ch: sap channel
+ *
+ * Check if SAP should be moved to a non dfs channel after STA disconnection.
+ * This API applicable only for STA+SAP SCC and ini 'sta_sap_scc_on_dfs_chan'
+ * or 'sta_sap_scc_on_lte_coex_chan' is enabled.
+ *
+ * Return: true if sap restart is required, otherwise false
+ */
+bool policy_mgr_is_sap_restart_required_after_sta_disconnect(
+			struct wlan_objmgr_psoc *psoc, uint8_t *intf_ch);
+
+/**
+ * policy_mgr_is_sta_sap_scc() - check whether SAP is doing SCC with
+ * STA
+ * @psoc: poniter to psoc
+ * @sap_ch: operating channel of SAP interface
+ * This function checks whether SAP is doing SCC with STA
+ *
+ * Return: true or false
+ */
+bool policy_mgr_is_sta_sap_scc(struct wlan_objmgr_psoc *psoc, uint8_t sap_ch);
+
+/**
+ * policy_mgr_get_hw_mode_from_idx() - Get HW mode based on index
+ * @psoc: psoc object
+ * @idx: HW mode id
+ * @hw_mode: HW mode params
+ *
+ * Fetches the HW mode parameters
+ *
+ * Return: Success if hw mode is obtained and the hw mode params
+ */
+QDF_STATUS policy_mgr_get_hw_mode_from_idx(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t idx,
+		struct policy_mgr_hw_mode_params *hw_mode);
+#endif /* __WLAN_POLICY_MGR_API_H */

+ 302 - 0
components/cmn_services/policy_mgr/inc/wlan_policy_mgr_cfg.h

@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __CFG_POLICY_MGR
+#define __CFG_POLICY_MGR
+#include "qdf_types.h"
+
+/*
+ * <ini>
+ * gWlanMccToSccSwitchMode - Control SAP channel.
+ * @Min: 0
+ * @Max: 5
+ * @Default: 0
+ *
+ * This ini is used to override SAP channel.
+ * If gWlanMccToSccSwitchMode = 0: disabled.
+ * If gWlanMccToSccSwitchMode = 1: Enable switch.
+ * If gWlainMccToSccSwitchMode = 2: Force switch with SAP restart.
+ * If gWlainMccToSccSwitchMode = 3: Force switch without SAP restart.
+ * If gWlainMccToSccSwitchMode = 4: Switch using
+ * 					fav channel(s)without SAP restart.
+ * If gWlainMccToSccSwitchMode = 5: Force switch without SAP restart.MCC allowed
+ *					in exceptional cases.
+ * If gWlainMccToSccSwitchMode = 6: Force Switch without SAP restart only in
+					user preffered band.
+ * Related: None.
+ *
+ * Supported Feature: Concurrency
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_MCC_TO_SCC_SWITCH CFG_INI_UINT(\
+					"gWlanMccToSccSwitchMode", \
+					QDF_MCC_TO_SCC_SWITCH_DISABLE, \
+					QDF_MCC_TO_SCC_SWITCH_MAX - 1, \
+					QDF_MCC_TO_SCC_SWITCH_DISABLE, \
+					CFG_VALUE_OR_DEFAULT, \
+					"Provides MCC to SCC switch mode")
+/*
+ * <ini>
+ * gSystemPref - Configure wlan system preference for PCL.
+ * @Min: 0
+ * @Max: 2
+ * @Default: 0
+ *
+ * This ini is used to configure wlan system preference option to help
+ * policy manager decide on Preferred Channel List for a new connection.
+ * For possible values refer to enum hdd_conc_priority_mode
+ *
+ * Related: None.
+ *
+ * Supported Feature: DBS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_CONC_SYS_PREF CFG_INI_UINT(\
+					"gSystemPref", 0, 2, 0, \
+					CFG_VALUE_OR_DEFAULT, \
+					"System preference to predict PCL")
+/*
+ * <ini>
+ * gMaxConcurrentActiveSessions - Maximum number of concurrent connections.
+ * @Min: 1
+ * @Max: 4
+ * @Default: 3
+ *
+ * This ini is used to configure the maximum number of concurrent connections.
+ *
+ * Related: None.
+ *
+ * Supported Feature: Concurrency
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_MAX_CONC_CXNS CFG_INI_UINT(\
+					"gMaxConcurrentActiveSessions", \
+					1, 4, 3, \
+					CFG_VALUE_OR_DEFAULT, \
+					"Config max num allowed connections")
+/*
+ * <ini>
+ * channel_select_logic_conc - Set channel selection logic
+ * for different concurrency combinations to DBS or inter band
+ * MCC. Default is DBS for STA+STA and STA+P2P.
+ * @Min: 0x00000000
+ * @Max: 0xFFFFFFFF
+ * @Default: 0x00000000
+ *
+ * 0 - inter-band MCC
+ * 1 - DBS
+ *
+ * BIT 0: STA+STA
+ * BIT 1: STA+P2P
+ * BIT 2-31: Reserved
+ *
+ * Supported Feature: STA+STA, STA+P2P
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_CHNL_SELECT_LOGIC_CONC CFG_INI_UINT(\
+						"channel_select_logic_conc",\
+						0x00000000, \
+						0xFFFFFFFF, \
+						0x00000003, \
+						CFG_VALUE_OR_DEFAULT, \
+						"Set channel selection policy for various concurrency")
+/*
+ * <ini>
+ * dbs_selection_policy - Configure dbs selection policy.
+ * @Min: 0
+ * @Max: 3
+ * @Default: 0
+ *
+ *  set band preference or Vdev preference.
+ *      bit[0] = 0: 5G 2x2 preferred to select 2x2 5G + 1x1 2G DBS mode.
+ *      bit[0] = 1: 2G 2x2 preferred to select 2x2 2G + 1x1 5G DBS mode.
+ *      bit[1] = 1: vdev priority enabled. The INI "vdev_priority_list" will
+ * specify the vdev priority.
+ *      bit[1] = 0: vdev priority disabled.
+ * This INI only take effect for Genoa dual DBS hw.
+ *
+ * Supported Feature: DBS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_DBS_SELECTION_PLCY CFG_INI_UINT(\
+					    "dbs_selection_policy", \
+					    0, 3, 0, \
+					    CFG_VALUE_OR_DEFAULT, \
+					    "Configure dbs selection policy")
+/*
+ * <ini>
+ * vdev_priority_list - Configure vdev priority list.
+ * @Min: 0
+ * @Max: 0x4444
+ * @Default: 0x4321
+ *
+ * @vdev_priority_list: vdev priority list
+ *      bit[0-3]: pri_id (policy_mgr_pri_id) of highest priority
+ *      bit[4-7]: pri_id (policy_mgr_pri_id) of second priority
+ *      bit[8-11]: pri_id (policy_mgr_pri_id) of third priority
+ *      bit[12-15]: pri_id (policy_mgr_pri_id) of fourth priority
+ *      example: 0x4321 - CLI < GO < SAP < STA
+ *      vdev priority id mapping:
+ *        PM_STA_PRI_ID = 1,
+ *        PM_SAP_PRI_ID = 2,
+ *        PM_P2P_GO_PRI_ID = 3,
+ *        PM_P2P_CLI_PRI_ID = 4,
+ * When the previous INI "dbs_selection_policy" bit[1]=1, which means
+ * the vdev 2x2 prioritization enabled. Then this INI will be used to
+ * specify the vdev type priority list. For example :
+ * dbs_selection_policy=0x2
+ * vdev_priority_list=0x4312
+ * means: default preference 2x2 band is 5G, vdev 2x2 prioritization enabled.
+ * And the priority list is CLI < GO < STA < SAP
+ *
+ * This INI only take effect for Genoa dual DBS hw.
+ *
+ * Supported Feature: DBS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_VDEV_CUSTOM_PRIORITY_LIST CFG_INI_UINT(\
+					"vdev_priority_list", \
+					0, 0x4444, 0x4321, \
+					CFG_VALUE_OR_DEFAULT, \
+					"Configure vdev priority list")
+/*
+ * <ini>
+ * gEnableCustomConcRule1 - Enable custom concurrency rule1.
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to enable/disable custom concurrency rule1.
+ * If SAP comes up first and STA comes up later then SAP needs to follow STA's
+ * channel.
+ *
+ * Related: None.
+ *
+ * Supported Feature: Concurrency
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_ENABLE_CONC_RULE1 CFG_INI_UINT(\
+					"gEnableCustomConcRule1", \
+					0, 1, 0, \
+					CFG_VALUE_OR_DEFAULT, \
+					"Enable custom concurrency rule 1")
+/*
+ * <ini>
+ * gEnableCustomConcRule2 - Enable custom concurrency rule2.
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to enable/disable custom concurrency rule2.
+ * If P2PGO comes up first and STA comes up later then P2PGO need to follow
+ * STA's channel in 5Ghz. In following if condition we are just adding sanity
+ * check to make sure that by this time P2PGO's channel is same as STA's
+ * channel.
+ *
+ * Related: None.
+ *
+ * Supported Feature: Concurrency
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_ENABLE_CONC_RULE2 CFG_INI_UINT(\
+					"gEnableCustomConcRule2", \
+					0, 1, 0, \
+					CFG_VALUE_OR_DEFAULT, \
+					"Enable custom concurrency rule 2")
+/*
+ * <ini>
+ * gEnableMCCAdaptiveScheduler - MCC Adaptive Scheduler feature.
+ * @Min: 0
+ * @Max: 1
+ * @Default: 1
+ *
+ * This ini is used to enable/disable MCC Adaptive Scheduler feature.
+ *
+ * Related: None.
+ *
+ * Supported Feature: Concurrency
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_ENABLE_MCC_ADATIVE_SCH_ENABLED_NAME CFG_INI_UINT(\
+					"gEnableMCCAdaptiveScheduler", \
+					0, 1, 1, \
+					CFG_VALUE_OR_DEFAULT, \
+					"Enable/Disable MCC Adaptive Scheduler")
+
+/*
+ * <ini>
+ * gEnableStaConnectionIn5Ghz - To enable/disable STA connection in 5G
+ * @Min: 0
+ * @Max: 1
+ * @Default: 1
+ *
+ * This ini is used to enable/disable STA connection in 5G band
+ *
+ * Related: STA
+ *
+ * Supported Feature: Concurrency
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ CFG_INI_UINT(\
+					"gEnableStaConnectionIn5Ghz", \
+					0, 1, 1, \
+					CFG_VALUE_OR_DEFAULT, \
+					"Enable/Disable STA connection in 5G")
+
+#define CFG_POLICY_MGR_ALL \
+		CFG(CFG_MCC_TO_SCC_SWITCH) \
+		CFG(CFG_CONC_SYS_PREF) \
+		CFG(CFG_MAX_CONC_CXNS) \
+		CFG(CFG_DBS_SELECTION_PLCY) \
+		CFG(CFG_VDEV_CUSTOM_PRIORITY_LIST) \
+		CFG(CFG_CHNL_SELECT_LOGIC_CONC) \
+		CFG(CFG_ENABLE_CONC_RULE1) \
+		CFG(CFG_ENABLE_CONC_RULE2) \
+		CFG(CFG_ENABLE_MCC_ADATIVE_SCH_ENABLED_NAME)\
+		CFG(CFG_ENABLE_STA_CONNECTION_IN_5GHZ)
+#endif

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

@@ -0,0 +1,1091 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WLAN_POLICY_MGR_PUBLIC_STRUCT_H
+#define __WLAN_POLICY_MGR_PUBLIC_STRUCT_H
+
+/**
+ * DOC: wlan_policy_mgr_public_struct.h
+ *
+ * Concurrenct Connection Management entity
+ */
+
+/* Include files */
+#include <wmi_unified_api.h>
+
+#define POLICY_MGR_MAX_CHANNEL_LIST 128
+
+/**
+ *  Some max value greater than the max length of the channel list
+ */
+#define MAX_WEIGHT_OF_PCL_CHANNELS 255
+/**
+ *  Some fixed weight difference between the groups
+ */
+#define PCL_GROUPS_WEIGHT_DIFFERENCE 20
+
+/**
+ * Currently max, only 3 groups are possible as per 'enum policy_mgr_pcl_type'.
+ * i.e., in a PCL only 3 groups of channels can be present
+ * e.g., SCC channel on 2.4 Ghz, SCC channel on 5 Ghz & 5 Ghz channels.
+ * Group 1 has highest priority, group 2 has the next higher priority
+ * and so on.
+ */
+#define WEIGHT_OF_GROUP1_PCL_CHANNELS MAX_WEIGHT_OF_PCL_CHANNELS
+#define WEIGHT_OF_GROUP2_PCL_CHANNELS \
+	(WEIGHT_OF_GROUP1_PCL_CHANNELS - PCL_GROUPS_WEIGHT_DIFFERENCE)
+#define WEIGHT_OF_GROUP3_PCL_CHANNELS \
+	(WEIGHT_OF_GROUP2_PCL_CHANNELS - PCL_GROUPS_WEIGHT_DIFFERENCE)
+#define WEIGHT_OF_GROUP4_PCL_CHANNELS \
+	(WEIGHT_OF_GROUP3_PCL_CHANNELS - PCL_GROUPS_WEIGHT_DIFFERENCE)
+
+#define WEIGHT_OF_NON_PCL_CHANNELS 1
+#define WEIGHT_OF_DISALLOWED_CHANNELS 0
+
+#define MAX_MAC 2
+
+#define MAX_NUMBER_OF_CONC_CONNECTIONS 3
+
+typedef int (*send_mode_change_event_cb)(void);
+
+/**
+ * enum hw_mode_ss_config - Possible spatial stream configuration
+ * @HW_MODE_SS_0x0: Unused Tx and Rx of MAC
+ * @HW_MODE_SS_1x1: 1 Tx SS and 1 Rx SS
+ * @HW_MODE_SS_2x2: 2 Tx SS and 2 Rx SS
+ * @HW_MODE_SS_3x3: 3 Tx SS and 3 Rx SS
+ * @HW_MODE_SS_4x4: 4 Tx SS and 4 Rx SS
+ *
+ * Note: Right now only 1x1 and 2x2 are being supported. Other modes should
+ * be added when supported. Asymmetric configuration like 1x2, 2x1 are also
+ * not supported now. But, they are still valid. Right now, Tx/Rx SS support is
+ * 4 bits long. So, we can go upto 15x15
+ */
+enum hw_mode_ss_config {
+	HW_MODE_SS_0x0,
+	HW_MODE_SS_1x1,
+	HW_MODE_SS_2x2,
+	HW_MODE_SS_3x3,
+	HW_MODE_SS_4x4,
+};
+
+/**
+ * enum hw_mode_dbs_capab - DBS HW mode capability
+ * @HW_MODE_DBS_NONE: Non DBS capable
+ * @HW_MODE_DBS: DBS capable
+ */
+enum hw_mode_dbs_capab {
+	HW_MODE_DBS_NONE,
+	HW_MODE_DBS,
+};
+
+/**
+ * enum hw_mode_agile_dfs_capab - Agile DFS HW mode capability
+ * @HW_MODE_AGILE_DFS_NONE: Non Agile DFS capable
+ * @HW_MODE_AGILE_DFS: Agile DFS capable
+ */
+enum hw_mode_agile_dfs_capab {
+	HW_MODE_AGILE_DFS_NONE,
+	HW_MODE_AGILE_DFS,
+};
+
+/**
+ * enum hw_mode_sbs_capab - SBS HW mode capability
+ * @HW_MODE_SBS_NONE: Non SBS capable
+ * @HW_MODE_SBS: SBS capable
+ */
+enum hw_mode_sbs_capab {
+	HW_MODE_SBS_NONE,
+	HW_MODE_SBS,
+};
+
+/**
+ * enum hw_mode_mac_band_cap - mac band capability
+ * @HW_MODE_MAC_BAND_NONE: No band requirement.
+ * @HW_MODE_MAC_BAND_2G: 2G band supported.
+ * @HW_MODE_MAC_BAND_5G: 5G band supported.
+ *
+ * To add HW_MODE_MAC_BAND_NONE value to help to
+ * match the HW DBS mode in hw mode list.
+ * Other enum values should match with WMI header:
+ * typedef enum {
+ *   WLAN_2G_CAPABILITY = 0x1,
+ *   WLAN_5G_CAPABILITY = 0x2,
+ * } WLAN_BAND_CAPABILITY;
+ */
+enum hw_mode_mac_band_cap {
+	HW_MODE_MAC_BAND_NONE = 0,
+	HW_MODE_MAC_BAND_2G = WLAN_2G_CAPABILITY,
+	HW_MODE_MAC_BAND_5G = WLAN_5G_CAPABILITY,
+};
+
+/**
+ * enum policy_mgr_pcl_group_id - Identifies the pcl groups to be used
+ * @POLICY_MGR_PCL_GROUP_ID1_ID2: Use weights of group1 and group2
+ * @POLICY_MGR_PCL_GROUP_ID2_ID3: Use weights of group2 and group3
+ * @POLICY_MGR_PCL_GROUP_ID3_ID4: Use weights of group3 and group4
+ *
+ * Since maximum of three groups are possible, this will indicate which
+ * PCL group needs to be used.
+ */
+enum policy_mgr_pcl_group_id {
+	POLICY_MGR_PCL_GROUP_ID1_ID2,
+	POLICY_MGR_PCL_GROUP_ID2_ID3,
+	POLICY_MGR_PCL_GROUP_ID3_ID4,
+};
+
+/**
+ * policy_mgr_pcl_channel_order - Order in which the PCL is requested
+ * @POLICY_MGR_PCL_ORDER_NONE: no order
+ * @POLICY_MGR_PCL_ORDER_24G_THEN_5G: 2.4 Ghz channel followed by 5 Ghz channel
+ * @POLICY_MGR_PCL_ORDER_5G_THEN_2G: 5 Ghz channel followed by 2.4 Ghz channel
+ *
+ * Order in which the PCL is requested
+ */
+enum policy_mgr_pcl_channel_order {
+	POLICY_MGR_PCL_ORDER_NONE,
+	POLICY_MGR_PCL_ORDER_24G_THEN_5G,
+	POLICY_MGR_PCL_ORDER_5G_THEN_2G,
+};
+
+/**
+ * enum policy_mgr_max_rx_ss - Maximum number of receive spatial streams
+ * @POLICY_MGR_RX_NSS_1: Receive Nss = 1
+ * @POLICY_MGR_RX_NSS_2: Receive Nss = 2
+ * @POLICY_MGR_RX_NSS_3: Receive Nss = 3
+ * @POLICY_MGR_RX_NSS_4: Receive Nss = 4
+ * @POLICY_MGR_RX_NSS_5: Receive Nss = 5
+ * @POLICY_MGR_RX_NSS_6: Receive Nss = 6
+ * @POLICY_MGR_RX_NSS_7: Receive Nss = 7
+ * @POLICY_MGR_RX_NSS_8: Receive Nss = 8
+ *
+ * Indicates the maximum number of spatial streams that the STA can receive
+ */
+enum policy_mgr_max_rx_ss {
+	POLICY_MGR_RX_NSS_1 = 0,
+	POLICY_MGR_RX_NSS_2 = 1,
+	POLICY_MGR_RX_NSS_3 = 2,
+	POLICY_MGR_RX_NSS_4 = 3,
+	POLICY_MGR_RX_NSS_5 = 4,
+	POLICY_MGR_RX_NSS_6 = 5,
+	POLICY_MGR_RX_NSS_7 = 6,
+	POLICY_MGR_RX_NSS_8 = 7,
+	POLICY_MGR_RX_NSS_MAX,
+};
+
+/**
+ * enum policy_mgr_chain_mode - Chain Mask tx & rx combination.
+ *
+ * @POLICY_MGR_ONE_ONE: One for Tx, One for Rx
+ * @POLICY_MGR_TWO_TWO: Two for Tx, Two for Rx
+ * @POLICY_MGR_MAX_NO_OF_CHAIN_MODE: Max place holder
+ *
+ * These are generic IDs that identify the various roles
+ * in the software system
+ */
+enum policy_mgr_chain_mode {
+	POLICY_MGR_ONE_ONE = 0,
+	POLICY_MGR_TWO_TWO,
+	POLICY_MGR_MAX_NO_OF_CHAIN_MODE
+};
+
+/**
+ * enum policy_mgr_conc_priority_mode - t/p, powersave, latency.
+ *
+ * @PM_THROUGHPUT: t/p is the priority
+ * @PM_POWERSAVE: powersave is the priority
+ * @PM_LATENCY: latency is the priority
+ * @PM_MAX_CONC_PRIORITY_MODE: Max place holder
+ *
+ * These are generic IDs that identify the various roles
+ * in the software system
+ */
+enum policy_mgr_conc_priority_mode {
+	PM_THROUGHPUT = 0,
+	PM_POWERSAVE,
+	PM_LATENCY,
+	PM_MAX_CONC_PRIORITY_MODE
+};
+
+/**
+ * enum policy_mgr_con_mode - concurrency mode for PCL table
+ *
+ * @PM_STA_MODE: station mode
+ * @PM_SAP_MODE: SAP mode
+ * @PM_P2P_CLIENT_MODE: P2P client mode
+ * @PM_P2P_GO_MODE: P2P Go mode
+ * @PM_IBSS_MODE: IBSS mode
+ * @PM_NDI_MODE: NDI mode
+ * @PM_MAX_NUM_OF_MODE: max value place holder
+ */
+enum policy_mgr_con_mode {
+	PM_STA_MODE = 0,
+	PM_SAP_MODE,
+	PM_P2P_CLIENT_MODE,
+	PM_P2P_GO_MODE,
+	PM_IBSS_MODE,
+	PM_NDI_MODE,
+	PM_MAX_NUM_OF_MODE
+};
+
+/**
+ * enum policy_mgr_mac_use - MACs that are used
+ * @POLICY_MGR_MAC0: Only MAC0 is used
+ * @POLICY_MGR_MAC1: Only MAC1 is used
+ * @POLICY_MGR_MAC0_AND_MAC1: Both MAC0 and MAC1 are used
+ */
+enum policy_mgr_mac_use {
+	POLICY_MGR_MAC0 = 1,
+	POLICY_MGR_MAC1 = 2,
+	POLICY_MGR_MAC0_AND_MAC1 = 3
+};
+
+/**
+ * enum policy_mgr_pcl_type - Various types of Preferred channel list (PCL).
+ *
+ * @PM_NONE: No channel preference
+ * @PM_24G: 2.4 Ghz channels only
+ * @PM_5G: 5 Ghz channels only
+ * @PM_SCC_CH: SCC channel only
+ * @PM_MCC_CH: MCC channels only
+ * @PM_SBS_CH: SBS channels only
+ * @PM_SCC_CH_24G: SCC channel & 2.4 Ghz channels
+ * @PM_SCC_CH_5G: SCC channel & 5 Ghz channels
+ * @PM_24G_SCC_CH: 2.4 Ghz channels & SCC channel
+ * @PM_5G_SCC_CH: 5 Ghz channels & SCC channel
+ * @PM_SCC_ON_5_SCC_ON_24_24G: SCC channel on 5 Ghz, SCC
+ *	channel on 2.4 Ghz & 2.4 Ghz channels
+ * @PM_SCC_ON_5_SCC_ON_24_5G: SCC channel on 5 Ghz, SCC channel
+ *	on 2.4 Ghz & 5 Ghz channels
+ * @PM_SCC_ON_24_SCC_ON_5_24G: SCC channel on 2.4 Ghz, SCC
+ *	channel on 5 Ghz & 2.4 Ghz channels
+ * @PM_SCC_ON_24_SCC_ON_5_5G: SCC channel on 2.4 Ghz, SCC
+ *	channel on 5 Ghz & 5 Ghz channels
+ * @PM_SCC_ON_5_SCC_ON_24: SCC channel on 5 Ghz, SCC channel on
+ *	2.4 Ghz
+ * @PM_SCC_ON_24_SCC_ON_5: SCC channel on 2.4 Ghz, SCC channel
+ *	on 5 Ghz
+ * @PM_MCC_CH_24G: MCC channels & 2.4 Ghz channels
+ * @PM_MCC_CH_5G:  MCC channels & 5 Ghz channels
+ * @PM_24G_MCC_CH: 2.4 Ghz channels & MCC channels
+ * @PM_5G_MCC_CH: 5 Ghz channels & MCC channels
+ * @PM_SBS_CH_5G: SBS channels & rest of 5 Ghz channels
+ * @PM_24G_SCC_CH_SBS_CH: 2.4 Ghz channels, SCC channel & SBS channels
+ * @PM_24G_SCC_CH_SBS_CH_5G: 2.4 Ghz channels, SCC channel,
+ *      SBS channels & rest of the 5G channels
+ * @PM_24G_SBS_CH_MCC_CH: 2.4 Ghz channels, SBS channels & MCC channels
+ * @PM_MAX_PCL_TYPE: Max place holder
+ *
+ * These are generic IDs that identify the various roles
+ * in the software system
+ */
+enum policy_mgr_pcl_type {
+	PM_NONE = 0,
+	PM_24G,
+	PM_5G,
+	PM_SCC_CH,
+	PM_MCC_CH,
+	PM_SBS_CH,
+	PM_SCC_CH_24G,
+	PM_SCC_CH_5G,
+	PM_24G_SCC_CH,
+	PM_5G_SCC_CH,
+	PM_SCC_ON_5_SCC_ON_24_24G,
+	PM_SCC_ON_5_SCC_ON_24_5G,
+	PM_SCC_ON_24_SCC_ON_5_24G,
+	PM_SCC_ON_24_SCC_ON_5_5G,
+	PM_SCC_ON_5_SCC_ON_24,
+	PM_SCC_ON_24_SCC_ON_5,
+	PM_MCC_CH_24G,
+	PM_MCC_CH_5G,
+	PM_24G_MCC_CH,
+	PM_5G_MCC_CH,
+	PM_SBS_CH_5G,
+	PM_24G_SCC_CH_SBS_CH,
+	PM_24G_SCC_CH_SBS_CH_5G,
+	PM_24G_SBS_CH_MCC_CH,
+
+	PM_MAX_PCL_TYPE
+};
+
+/**
+ * enum policy_mgr_one_connection_mode - Combination of first connection
+ * type, band & spatial stream used.
+ *
+ * @PM_STA_24_1x1: STA connection using [email protected] Ghz
+ * @PM_STA_24_2x2: STA connection using [email protected] Ghz
+ * @PM_STA_5_1x1: STA connection using 1x1@5 Ghz
+ * @PM_STA_5_2x2: STA connection using 2x2@5 Ghz
+ * @PM_P2P_CLI_24_1x1: P2P Client connection using [email protected] Ghz
+ * @PM_P2P_CLI_24_2x2: P2P Client connection using [email protected] Ghz
+ * @PM_P2P_CLI_5_1x1: P2P Client connection using 1x1@5 Ghz
+ * @PM_P2P_CLI_5_2x2: P2P Client connection using 2x2@5 Ghz
+ * @PM_P2P_GO_24_1x1: P2P GO connection using [email protected] Ghz
+ * @PM_P2P_GO_24_2x2: P2P GO connection using [email protected] Ghz
+ * @PM_P2P_GO_5_1x1: P2P GO connection using 1x1@5 Ghz
+ * @PM_P2P_GO_5_2x2: P2P GO connection using 2x2@5 Ghz
+ * @PM_SAP_24_1x1: SAP connection using [email protected] Ghz
+ * @PM_SAP_24_2x2: SAP connection using [email protected] Ghz
+ * @PM_SAP_5_1x1: SAP connection using 1x1@5 Ghz
+ * @PM_SAP_5_1x1: SAP connection using 2x2@5 Ghz
+ * @PM_IBSS_24_1x1:  IBSS connection using [email protected] Ghz
+ * @PM_IBSS_24_2x2:  IBSS connection using [email protected] Ghz
+ * @PM_IBSS_5_1x1:  IBSS connection using 1x1@5 Ghz
+ * @PM_IBSS_5_2x2:  IBSS connection using 2x2@5 Ghz
+ * @PM_MAX_ONE_CONNECTION_MODE: Max place holder
+ *
+ * These are generic IDs that identify the various roles
+ * in the software system
+ */
+enum policy_mgr_one_connection_mode {
+	PM_STA_24_1x1 = 0,
+	PM_STA_24_2x2,
+	PM_STA_5_1x1,
+	PM_STA_5_2x2,
+	PM_P2P_CLI_24_1x1,
+	PM_P2P_CLI_24_2x2,
+	PM_P2P_CLI_5_1x1,
+	PM_P2P_CLI_5_2x2,
+	PM_P2P_GO_24_1x1,
+	PM_P2P_GO_24_2x2,
+	PM_P2P_GO_5_1x1,
+	PM_P2P_GO_5_2x2,
+	PM_SAP_24_1x1,
+	PM_SAP_24_2x2,
+	PM_SAP_5_1x1,
+	PM_SAP_5_2x2,
+	PM_IBSS_24_1x1,
+	PM_IBSS_24_2x2,
+	PM_IBSS_5_1x1,
+	PM_IBSS_5_2x2,
+
+	PM_MAX_ONE_CONNECTION_MODE
+};
+
+/**
+ * enum policy_mgr_two_connection_mode - Combination of first two
+ * connections type, concurrency state, band & spatial stream
+ * used.
+ *
+ * @PM_STA_SAP_SCC_24_1x1: STA & SAP connection on SCC using
+ *			[email protected] Ghz
+ * @PM_STA_SAP_SCC_24_2x2: STA & SAP connection on SCC using
+ *			[email protected] Ghz
+ * @PM_STA_SAP_MCC_24_1x1: STA & SAP connection on MCC using
+ *			[email protected] Ghz
+ * @PM_STA_SAP_MCC_24_2x2: STA & SAP connection on MCC using
+ *			[email protected] Ghz
+ * @PM_STA_SAP_SCC_5_1x1: STA & SAP connection on SCC using
+ *			1x1@5 Ghz
+ * @PM_STA_SAP_SCC_5_2x2: STA & SAP connection on SCC using
+ *			2x2@5 Ghz
+ * @PM_STA_SAP_MCC_5_1x1: STA & SAP connection on MCC using
+ *			1x1@5 Ghz
+ * @PM_STA_SAP_MCC_5_2x2: STA & SAP connection on MCC using
+ *			2x2@5 Ghz
+ * @PM_STA_SAP_DBS_1x1: STA & SAP connection on DBS using 1x1
+ * @PM_STA_SAP_DBS_2x2: STA & SAP connection on DBS using 2x2
+ * @PM_STA_SAP_SBS_5_1x1: STA & SAP connection on 5G SBS using 1x1
+ * @PM_STA_P2P_GO_SCC_24_1x1: STA & P2P GO connection on SCC
+ *			using [email protected] Ghz
+ * @PM_STA_P2P_GO_SCC_24_2x2: STA & P2P GO connection on SCC
+ *			using [email protected] Ghz
+ * @PM_STA_P2P_GO_MCC_24_1x1: STA & P2P GO connection on MCC
+ *			using [email protected] Ghz
+ * @PM_STA_P2P_GO_MCC_24_2x2: STA & P2P GO connection on MCC
+ *			using [email protected] Ghz
+ * @PM_STA_P2P_GO_SCC_5_1x1: STA & P2P GO connection on SCC
+ *			using 1x1@5 Ghz
+ * @PM_STA_P2P_GO_SCC_5_2x2: STA & P2P GO connection on SCC
+ *			using 2x2@5 Ghz
+ * @PM_STA_P2P_GO_MCC_5_1x1: STA & P2P GO connection on MCC
+ *			using 1x1@5 Ghz
+ * @PM_STA_P2P_GO_MCC_5_2x2: STA & P2P GO connection on MCC
+ *			using 2x2@5 Ghz
+ * @PM_STA_P2P_GO_DBS_1x1: STA & P2P GO connection on DBS using
+ *			1x1
+ * @PM_STA_P2P_GO_DBS_2x2: STA & P2P GO connection on DBS using
+ *			2x2
+ * @PM_STA_P2P_GO_SBS_5_1x1: STA & P2P GO connection on 5G SBS
+ *			using 1x1
+ * @PM_STA_P2P_CLI_SCC_24_1x1: STA & P2P CLI connection on SCC
+ *			using [email protected] Ghz
+ * @PM_STA_P2P_CLI_SCC_24_2x2: STA & P2P CLI connection on SCC
+ *			using [email protected] Ghz
+ * @PM_STA_P2P_CLI_MCC_24_1x1: STA & P2P CLI connection on MCC
+ *			using [email protected] Ghz
+ * @PM_STA_P2P_CLI_MCC_24_2x2: STA & P2P CLI connection on MCC
+ *			using [email protected] Ghz
+ * @PM_STA_P2P_CLI_SCC_5_1x1: STA & P2P CLI connection on SCC
+ *			using 1x1@5 Ghz
+ * @PM_STA_P2P_CLI_SCC_5_2x2: STA & P2P CLI connection on SCC
+ *			using 2x2@5 Ghz
+ * @PM_STA_P2P_CLI_MCC_5_1x1: STA & P2P CLI connection on MCC
+ *			using 1x1@5 Ghz
+ * @PM_STA_P2P_CLI_MCC_5_2x2: STA & P2P CLI connection on MCC
+ *			using 2x2@5 Ghz
+ * @PM_STA_P2P_CLI_DBS_1x1: STA & P2P CLI connection on DBS
+ *			using 1x1
+ * @PM_STA_P2P_CLI_DBS_2x2: STA & P2P CLI connection on DBS
+ *			using 2x2
+ * @PM_STA_P2P_CLI_SBS_5_1x1: STA & P2P CLI connection on 5G
+ *			SBS using 1x1
+ * @PM_P2P_GO_P2P_CLI_SCC_24_1x1: P2P GO & CLI connection on
+ *			SCC using [email protected] Ghz
+ * @PM_P2P_GO_P2P_CLI_SCC_24_2x2: P2P GO & CLI connection on
+ *			SCC using [email protected] Ghz
+ * @PM_P2P_GO_P2P_CLI_MCC_24_1x1: P2P GO & CLI connection on
+ *			MCC using [email protected] Ghz
+ * @PM_P2P_GO_P2P_CLI_MCC_24_2x2: P2P GO & CLI connection on
+ *			MCC using [email protected] Ghz
+ * @PM_P2P_GO_P2P_CLI_SCC_5_1x1: P2P GO & CLI connection on
+ *			SCC using 1x1@5 Ghz
+ * @PM_P2P_GO_P2P_CLI_SCC_5_2x2: P2P GO & CLI connection on
+ *			SCC using 2x2@5 Ghz
+ * @PM_P2P_GO_P2P_CLI_MCC_5_1x1: P2P GO & CLI connection on
+ *			MCC using 1x1@5 Ghz
+ * @PM_P2P_GO_P2P_CLI_MCC_5_2x2: P2P GO & CLI connection on
+ *			MCC using 2x2@5 Ghz
+ * @PM_P2P_GO_P2P_CLI_DBS_1x1: P2P GO & CLI connection on DBS
+ *			using 1x1
+ * @PM_P2P_GO_P2P_CLI_DBS_2x2: P2P GO & P2P CLI connection
+ *			on DBS using 2x2
+ * @PM_P2P_GO_P2P_CLI_SBS_5_1x1: P2P GO & P2P CLI connection
+ *			on 5G SBS using 1x1
+ * @PM_P2P_GO_SAP_SCC_24_1x1: P2P GO & SAP connection on
+ *			SCC using [email protected] Ghz
+ * @PM_P2P_GO_SAP_SCC_24_2x2: P2P GO & SAP connection on
+ *			SCC using [email protected] Ghz
+ * @PM_P2P_GO_SAP_MCC_24_1x1: P2P GO & SAP connection on
+ *			MCC using [email protected] Ghz
+ * @PM_P2P_GO_SAP_MCC_24_2x2: P2P GO & SAP connection on
+ *			MCC using [email protected] Ghz
+ * @PM_P2P_GO_SAP_SCC_5_1x1: P2P GO & SAP connection on
+ *			SCC using 1x1@5 Ghz
+ * @PM_P2P_GO_SAP_SCC_5_2x2: P2P GO & SAP connection on
+ *			SCC using 2x2@5 Ghz
+ * @PM_P2P_GO_SAP_MCC_5_1x1: P2P GO & SAP connection on
+ *			MCC using 1x1@5 Ghz
+ * @PM_P2P_GO_SAP_MCC_5_2x2: P2P GO & SAP connection on
+ *			MCC using 2x2@5 Ghz
+ * @PM_P2P_GO_SAP_DBS_1x1: P2P GO & SAP connection on DBS using
+ *			1x1
+ * @PM_P2P_GO_SAP_DBS_2x2: P2P GO & SAP connection on DBS using
+ *			2x2
+ * @PM_P2P_GO_SAP_SBS_5_1x1: P2P GO & SAP connection on 5G SBS
+ *			using 1x1
+ * @PM_P2P_CLI_SAP_SCC_24_1x1: CLI & SAP connection on SCC using
+ *			[email protected] Ghz
+ * @PM_P2P_CLI_SAP_SCC_24_2x2: CLI & SAP connection on SCC using
+ *			[email protected] Ghz
+ * @PM_P2P_CLI_SAP_MCC_24_1x1: CLI & SAP connection on MCC using
+ *			[email protected] Ghz
+ * @PM_P2P_CLI_SAP_MCC_24_2x2: CLI & SAP connection on MCC using
+ *			[email protected] Ghz
+ * @PM_P2P_CLI_SAP_SCC_5_1x1: CLI & SAP connection on SCC using
+ *			1x1@5 Ghz
+ * @PM_P2P_CLI_SAP_SCC_5_2x2: CLI & SAP connection on SCC using
+ *			2x2@5 Ghz
+ * @PM_P2P_CLI_SAP_MCC_5_1x1: CLI & SAP connection on MCC using
+ *			1x1@5 Ghz
+ * @PM_P2P_CLI_SAP_MCC_5_2x2: CLI & SAP connection on MCC using
+ *			2x2@5 Ghz
+ * @POLICY_MGR_P2P_STA_SAP_MCC_24_5_1x1: CLI and SAP connecting on MCC
+ *			in 2.4 and 5GHz 1x1
+ * @POLICY_MGR_P2P_STA_SAP_MCC_24_5_2x2: CLI and SAP connecting on MCC
+ *			in 2.4 and 5GHz 2x2
+ * @PM_P2P_CLI_SAP_DBS_1x1,: CLI & SAP connection on DBS using 1x1
+ * @PM_P2P_CLI_SAP_DBS_2x2: P2P CLI & SAP connection on DBS using
+ *			2x2
+ * @PM_P2P_CLI_SAP_SBS_5_1x1: P2P CLI & SAP connection on 5G SBS
+ *			using 1x1
+ * @PM_SAP_SAP_SCC_24_1x1: SAP & SAP connection on
+ *			SCC using [email protected] Ghz
+ * @PM_SAP_SAP_SCC_24_2x2: SAP & SAP connection on
+ *			SCC using [email protected] Ghz
+ * @PM_SAP_SAP_MCC_24_1x1: SAP & SAP connection on
+ *			MCC using [email protected] Ghz
+ * @PM_SAP_SAP_MCC_24_2x2: SAP & SAP connection on
+ *			MCC using [email protected] Ghz
+ * @PM_SAP_SAP_SCC_5_1x1: SAP & SAP connection on
+ *			SCC using 1x1@5 Ghz
+ * @PM_SAP_SAP_SCC_5_2x2: SAP & SAP connection on
+ *			SCC using 2x2@5 Ghz
+ * @PM_SAP_SAP_MCC_5_1x1: SAP & SAP connection on
+ *			MCC using 1x1@5 Ghz
+ * @PM_SAP_SAP_MCC_5_2x2: SAP & SAP connection on
+ *          MCC using 2x2@5 Ghz
+ * @PM_SAP_SAP_MCC_24_5_1x1: SAP & SAP connection on
+ *			MCC in 2.4 and 5GHz 1x1
+ * @PM_SAP_SAP_MCC_24_5_2x2: SAP & SAP connection on
+ *			MCC in 2.4 and 5GHz 2x2
+ * @PM_SAP_SAP_DBS_1x1: SAP & SAP connection on DBS using
+ *			1x1
+ * @PM_SAP_SAP_DBS_2x2: SAP & SAP connection on DBS using 2x2
+ * @PM_SAP_SAP_SBS_5_1x1: SAP & SAP connection on 5G SBS using 1x1
+ * @PM_STA_STA_SCC_24_1x1: STA & STA connection on
+ *			SCC using [email protected] Ghz
+ * @PM_STA_STA_SCC_24_2x2: STA & STA connection on
+ *			SCC using [email protected] Ghz
+ * @PM_STA_STA_MCC_24_1x1: STA & STA connection on
+ *			MCC using [email protected] Ghz
+ * @PM_STA_STA_MCC_24_2x2: STA & STA connection on
+ *			MCC using [email protected] Ghz
+ * @PM_STA_STA_SCC_5_1x1: STA & STA connection on
+ *			SCC using 1x1@5 Ghz
+ * @PM_STA_STA_SCC_5_2x2: STA & STA connection on
+ *			SCC using 2x2@5 Ghz
+ * @PM_STA_STA_MCC_5_1x1: STA & STA connection on
+ *			MCC using 1x1@5 Ghz
+ * @PM_STA_STA_MCC_5_2x2: STA & STA connection on
+ *          MCC using 2x2@5 Ghz
+ * @PM_STA_STA_MCC_24_5_1x1: STA & STA connection on
+ *			MCC in 2.4 and 5GHz 1x1
+ * @PM_STA_STA_MCC_24_5_2x2: STA & STA connection on
+ *			MCC in 2.4 and 5GHz 2x2
+ * @PM_STA_STA_DBS_1x1: STA & STA connection on DBS using
+ *			1x1
+ * @PM_STA_STA_DBS_2x2: STA & STA connection on DBS using 2x2
+ * @PM_STA_STA_SBS_5_1x1: STA & STA connection on 5G SBS using 1x1
+ *
+ * These are generic IDs that identify the various roles in the
+ * software system
+ */
+enum policy_mgr_two_connection_mode {
+	PM_STA_SAP_SCC_24_1x1 = 0,
+	PM_STA_SAP_SCC_24_2x2,
+	PM_STA_SAP_MCC_24_1x1,
+	PM_STA_SAP_MCC_24_2x2,
+	PM_STA_SAP_SCC_5_1x1,
+	PM_STA_SAP_SCC_5_2x2,
+	PM_STA_SAP_MCC_5_1x1,
+	PM_STA_SAP_MCC_5_2x2,
+	PM_STA_SAP_MCC_24_5_1x1,
+	PM_STA_SAP_MCC_24_5_2x2,
+	PM_STA_SAP_DBS_1x1,
+	PM_STA_SAP_DBS_2x2,
+	PM_STA_SAP_SBS_5_1x1,
+	PM_STA_P2P_GO_SCC_24_1x1,
+	PM_STA_P2P_GO_SCC_24_2x2,
+	PM_STA_P2P_GO_MCC_24_1x1,
+	PM_STA_P2P_GO_MCC_24_2x2,
+	PM_STA_P2P_GO_SCC_5_1x1,
+	PM_STA_P2P_GO_SCC_5_2x2,
+	PM_STA_P2P_GO_MCC_5_1x1,
+	PM_STA_P2P_GO_MCC_5_2x2,
+	PM_STA_P2P_GO_MCC_24_5_1x1,
+	PM_STA_P2P_GO_MCC_24_5_2x2,
+	PM_STA_P2P_GO_DBS_1x1,
+	PM_STA_P2P_GO_DBS_2x2,
+	PM_STA_P2P_GO_SBS_5_1x1,
+	PM_STA_P2P_CLI_SCC_24_1x1,
+	PM_STA_P2P_CLI_SCC_24_2x2,
+	PM_STA_P2P_CLI_MCC_24_1x1,
+	PM_STA_P2P_CLI_MCC_24_2x2,
+	PM_STA_P2P_CLI_SCC_5_1x1,
+	PM_STA_P2P_CLI_SCC_5_2x2,
+	PM_STA_P2P_CLI_MCC_5_1x1,
+	PM_STA_P2P_CLI_MCC_5_2x2,
+	PM_STA_P2P_CLI_MCC_24_5_1x1,
+	PM_STA_P2P_CLI_MCC_24_5_2x2,
+	PM_STA_P2P_CLI_DBS_1x1,
+	PM_STA_P2P_CLI_DBS_2x2,
+	PM_STA_P2P_CLI_SBS_5_1x1,
+	PM_P2P_GO_P2P_CLI_SCC_24_1x1,
+	PM_P2P_GO_P2P_CLI_SCC_24_2x2,
+	PM_P2P_GO_P2P_CLI_MCC_24_1x1,
+	PM_P2P_GO_P2P_CLI_MCC_24_2x2,
+	PM_P2P_GO_P2P_CLI_SCC_5_1x1,
+	PM_P2P_GO_P2P_CLI_SCC_5_2x2,
+	PM_P2P_GO_P2P_CLI_MCC_5_1x1,
+	PM_P2P_GO_P2P_CLI_MCC_5_2x2,
+	PM_P2P_GO_P2P_CLI_MCC_24_5_1x1,
+	PM_P2P_GO_P2P_CLI_MCC_24_5_2x2,
+	PM_P2P_GO_P2P_CLI_DBS_1x1,
+	PM_P2P_GO_P2P_CLI_DBS_2x2,
+	PM_P2P_GO_P2P_CLI_SBS_5_1x1,
+	PM_P2P_GO_SAP_SCC_24_1x1,
+	PM_P2P_GO_SAP_SCC_24_2x2,
+	PM_P2P_GO_SAP_MCC_24_1x1,
+	PM_P2P_GO_SAP_MCC_24_2x2,
+	PM_P2P_GO_SAP_SCC_5_1x1,
+	PM_P2P_GO_SAP_SCC_5_2x2,
+	PM_P2P_GO_SAP_MCC_5_1x1,
+	PM_P2P_GO_SAP_MCC_5_2x2,
+	PM_P2P_GO_SAP_MCC_24_5_1x1,
+	PM_P2P_GO_SAP_MCC_24_5_2x2,
+	PM_P2P_GO_SAP_DBS_1x1,
+	PM_P2P_GO_SAP_DBS_2x2,
+	PM_P2P_GO_SAP_SBS_5_1x1,
+	PM_P2P_CLI_SAP_SCC_24_1x1,
+	PM_P2P_CLI_SAP_SCC_24_2x2,
+	PM_P2P_CLI_SAP_MCC_24_1x1,
+	PM_P2P_CLI_SAP_MCC_24_2x2,
+	PM_P2P_CLI_SAP_SCC_5_1x1,
+	PM_P2P_CLI_SAP_SCC_5_2x2,
+	PM_P2P_CLI_SAP_MCC_5_1x1,
+	PM_P2P_CLI_SAP_MCC_5_2x2,
+	PM_P2P_CLI_SAP_MCC_24_5_1x1,
+	PM_P2P_CLI_SAP_MCC_24_5_2x2,
+	PM_P2P_CLI_SAP_DBS_1x1,
+	PM_P2P_CLI_SAP_DBS_2x2,
+	PM_P2P_CLI_SAP_SBS_5_1x1,
+	PM_SAP_SAP_SCC_24_1x1,
+	PM_SAP_SAP_SCC_24_2x2,
+	PM_SAP_SAP_MCC_24_1x1,
+	PM_SAP_SAP_MCC_24_2x2,
+	PM_SAP_SAP_SCC_5_1x1,
+	PM_SAP_SAP_SCC_5_2x2,
+	PM_SAP_SAP_MCC_5_1x1,
+	PM_SAP_SAP_MCC_5_2x2,
+	PM_SAP_SAP_MCC_24_5_1x1,
+	PM_SAP_SAP_MCC_24_5_2x2,
+	PM_SAP_SAP_DBS_1x1,
+	PM_SAP_SAP_DBS_2x2,
+	PM_SAP_SAP_SBS_5_1x1,
+	PM_STA_STA_SCC_24_1x1,
+	PM_STA_STA_SCC_24_2x2,
+	PM_STA_STA_MCC_24_1x1,
+	PM_STA_STA_MCC_24_2x2,
+	PM_STA_STA_SCC_5_1x1,
+	PM_STA_STA_SCC_5_2x2,
+	PM_STA_STA_MCC_5_1x1,
+	PM_STA_STA_MCC_5_2x2,
+	PM_STA_STA_MCC_24_5_1x1,
+	PM_STA_STA_MCC_24_5_2x2,
+	PM_STA_STA_DBS_1x1,
+	PM_STA_STA_DBS_2x2,
+	PM_STA_STA_SBS_5_1x1,
+
+	PM_MAX_TWO_CONNECTION_MODE
+};
+
+/**
+ * enum policy_mgr_conc_next_action - actions to be taken on old
+ * connections.
+ *
+ * @PM_NOP: No action
+ * @PM_DBS: switch to DBS mode
+ * @PM_DBS_DOWNGRADE: switch to DBS mode & downgrade to 1x1
+ * @PM_DBS_UPGRADE: switch to DBS mode & upgrade to 2x2
+ * @PM_SINGLE_MAC: switch to MCC/SCC mode
+ * @PM_SINGLE_MAC_UPGRADE: switch to MCC/SCC mode & upgrade to 2x2
+ * @PM_SBS: switch to SBS mode
+ * @PM_SBS_DOWNGRADE: switch to SBS mode & downgrade to 1x1
+ * @PM_DOWNGRADE: downgrade to 1x1
+ * @PM_UPGRADE: upgrade to 2x2
+ * @PM_DBS1: switch to DBS 1
+ * @PM_DBS1_DOWNGRADE: downgrade 2G beaconing entity to 1x1 and switch to DBS1.
+ * @PM_DBS2: switch to DBS 2
+ * @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_MAX_CONC_PRIORITY_MODE: Max place holder
+ *
+ * These are generic IDs that identify the various roles
+ * in the software system
+ */
+enum policy_mgr_conc_next_action {
+	PM_NOP = 0,
+	PM_DBS,
+	PM_DBS_DOWNGRADE,
+	PM_DBS_UPGRADE,
+	PM_SINGLE_MAC,
+	PM_SINGLE_MAC_UPGRADE,
+	PM_SBS,
+	PM_SBS_DOWNGRADE,
+	PM_DOWNGRADE,
+	PM_UPGRADE,
+	PM_DBS1,
+	PM_DBS1_DOWNGRADE,
+	PM_DBS2,
+	PM_DBS2_DOWNGRADE,
+	PM_UPGRADE_5G,
+	PM_UPGRADE_2G,
+
+	PM_MAX_CONC_NEXT_ACTION
+};
+
+/**
+ * enum policy_mgr_band - wifi band.
+ *
+ * @POLICY_MGR_BAND_24: 2.4 Ghz band
+ * @POLICY_MGR_BAND_5: 5 Ghz band
+ * @POLICY_MGR_ANY: to specify all band
+ * @POLICY_MGR_MAX_BAND: Max place holder
+ *
+ * These are generic IDs that identify the various roles
+ * in the software system
+ */
+enum policy_mgr_band {
+	POLICY_MGR_BAND_24 = 0,
+	POLICY_MGR_BAND_5,
+	POLICY_MGR_ANY,
+	POLICY_MGR_MAX_BAND = POLICY_MGR_ANY,
+};
+
+/**
+ * enum policy_mgr_conn_update_reason: Reason for conc connection update
+ * @POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN: Set probable operating channel
+ * @POLICY_MGR_UPDATE_REASON_JOIN_IBSS: Join IBSS
+ * @POLICY_MGR_UPDATE_REASON_UT: Unit test related
+ * @POLICY_MGR_UPDATE_REASON_START_AP: Start AP
+ * @POLICY_MGR_UPDATE_REASON_NORMAL_STA: Connection to Normal STA
+ * @POLICY_MGR_UPDATE_REASON_HIDDEN_STA: Connection to Hidden STA
+ * @POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC: Opportunistic HW mode update
+ * @POLICY_MGR_UPDATE_REASON_NSS_UPDATE: NSS update
+ * @POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH: Channel switch
+ * @POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_STA: Channel switch for STA
+ * @POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE: In Dual DBS HW, if the vdev based
+ *        2x2 preference enabled, the vdev down may cause prioritized active
+ *        vdev change, then DBS hw mode may needs to change from one DBS mode
+ *        to the other DBS mode. This reason code indicates such condition.
+ */
+enum policy_mgr_conn_update_reason {
+	POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN,
+	POLICY_MGR_UPDATE_REASON_JOIN_IBSS,
+	POLICY_MGR_UPDATE_REASON_UT,
+	POLICY_MGR_UPDATE_REASON_START_AP,
+	POLICY_MGR_UPDATE_REASON_NORMAL_STA,
+	POLICY_MGR_UPDATE_REASON_HIDDEN_STA,
+	POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC,
+	POLICY_MGR_UPDATE_REASON_NSS_UPDATE,
+	POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH,
+	POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_STA,
+	POLICY_MGR_UPDATE_REASON_PRE_CAC,
+	POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE,
+};
+
+/**
+ * enum hw_mode_bandwidth - bandwidth of wifi channel.
+ *
+ * @HW_MODE_5_MHZ: 5 Mhz bandwidth
+ * @HW_MODE_10_MHZ: 10 Mhz bandwidth
+ * @HW_MODE_20_MHZ: 20 Mhz bandwidth
+ * @HW_MODE_40_MHZ: 40 Mhz bandwidth
+ * @HW_MODE_80_MHZ: 80 Mhz bandwidth
+ * @HW_MODE_80_PLUS_80_MHZ: 80 Mhz plus 80 Mhz bandwidth
+ * @HW_MODE_160_MHZ: 160 Mhz bandwidth
+ * @HW_MODE_MAX_BANDWIDTH: Max place holder
+ *
+ * These are generic IDs that identify the various roles
+ * in the software system
+ */
+enum hw_mode_bandwidth {
+	HW_MODE_BW_NONE,
+	HW_MODE_5_MHZ,
+	HW_MODE_10_MHZ,
+	HW_MODE_20_MHZ,
+	HW_MODE_40_MHZ,
+	HW_MODE_80_MHZ,
+	HW_MODE_80_PLUS_80_MHZ,
+	HW_MODE_160_MHZ,
+	HW_MODE_MAX_BANDWIDTH
+};
+
+/**
+ * enum set_hw_mode_status - Status of set HW mode command
+ * @SET_HW_MODE_STATUS_OK: command successful
+ * @SET_HW_MODE_STATUS_EINVAL: Requested invalid hw_mode
+ * @SET_HW_MODE_STATUS_ECANCELED: HW mode change cancelled
+ * @SET_HW_MODE_STATUS_ENOTSUP: HW mode not supported
+ * @SET_HW_MODE_STATUS_EHARDWARE: HW mode change prevented by hardware
+ * @SET_HW_MODE_STATUS_EPENDING: HW mode change is pending
+ * @SET_HW_MODE_STATUS_ECOEX: HW mode change conflict with Coex
+ */
+enum set_hw_mode_status {
+	SET_HW_MODE_STATUS_OK,
+	SET_HW_MODE_STATUS_EINVAL,
+	SET_HW_MODE_STATUS_ECANCELED,
+	SET_HW_MODE_STATUS_ENOTSUP,
+	SET_HW_MODE_STATUS_EHARDWARE,
+	SET_HW_MODE_STATUS_EPENDING,
+	SET_HW_MODE_STATUS_ECOEX,
+};
+
+typedef void (*dual_mac_cb)(enum set_hw_mode_status status,
+		uint32_t scan_config,
+		uint32_t fw_mode_config);
+/**
+ * enum policy_mgr_hw_mode_change - identify the HW mode switching to.
+ *
+ * @POLICY_MGR_HW_MODE_NOT_IN_PROGRESS: HW mode change not in progress
+ * @POLICY_MGR_SMM_IN_PROGRESS: switching to SMM mode
+ * @POLICY_MGR_DBS_IN_PROGRESS: switching to DBS mode
+ * @POLICY_MGR_SBS_IN_PROGRESS: switching to SBS mode
+ *
+ * These are generic IDs that identify the various roles
+ * in the software system
+ */
+enum policy_mgr_hw_mode_change {
+	POLICY_MGR_HW_MODE_NOT_IN_PROGRESS = 0,
+	POLICY_MGR_SMM_IN_PROGRESS,
+	POLICY_MGR_DBS_IN_PROGRESS,
+	POLICY_MGR_SBS_IN_PROGRESS
+};
+
+/**
+ * enum dbs_support - structure to define INI values and their meaning
+ *
+ * @ENABLE_DBS_CXN_AND_SCAN: Enable DBS support for connection and scan
+ * @DISABLE_DBS_CXN_AND_SCAN: Disable DBS support for connection and scan
+ * @DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN: disable dbs support for
+ * connection but keep dbs support for scan
+ * @DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN_WITH_ASYNC_SCAN_OFF: disable dbs support
+ * for connection but keep dbs for scan but switch off the async scan
+ * @ENABLE_DBS_CXN_AND_ENABLE_SCAN_WITH_ASYNC_SCAN_OFF: enable dbs support for
+ * connection and scan but switch off the async scan
+ * @ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN: Enable DBS support for connection and
+ * disable DBS support for scan
+ * @ENABLE_DBS_CXN_AND_DISABLE_SIMULTANEOUS_SCAN: Enable DBS
+ * support for connection and disable simultaneous scan from
+ * upper layer (DBS scan remains enabled in FW)
+ */
+enum dbs_support {
+	ENABLE_DBS_CXN_AND_SCAN,
+	DISABLE_DBS_CXN_AND_SCAN,
+	DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN,
+	DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN_WITH_ASYNC_SCAN_OFF,
+	ENABLE_DBS_CXN_AND_ENABLE_SCAN_WITH_ASYNC_SCAN_OFF,
+	ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN,
+	ENABLE_DBS_CXN_AND_DISABLE_SIMULTANEOUS_SCAN,
+};
+
+/**
+ * struct policy_mgr_conc_connection_info - information of all existing
+ * connections in the wlan system
+ *
+ * @mode: connection type
+ * @chan: channel of the connection
+ * @bw: channel bandwidth used for the connection
+ * @mac: The HW mac it is running
+ * @chain_mask: The original capability advertised by HW
+ * @original_nss: nss negotiated at connection time
+ * @vdev_id: vdev id of the connection
+ * @in_use: if the table entry is active
+ */
+struct policy_mgr_conc_connection_info {
+	enum policy_mgr_con_mode mode;
+	uint8_t       chan;
+	enum hw_mode_bandwidth bw;
+	uint8_t       mac;
+	enum policy_mgr_chain_mode chain_mask;
+	uint32_t      original_nss;
+	uint32_t      vdev_id;
+	bool          in_use;
+};
+
+/**
+ * struct policy_mgr_hw_mode_params - HW mode params
+ * @mac0_tx_ss: MAC0 Tx spatial stream
+ * @mac0_rx_ss: MAC0 Rx spatial stream
+ * @mac1_tx_ss: MAC1 Tx spatial stream
+ * @mac1_rx_ss: MAC1 Rx spatial stream
+ * @mac0_bw: MAC0 bandwidth
+ * @mac1_bw: MAC1 bandwidth
+ * @mac0_band_cap: mac0 band (5g/2g) capability
+ * @dbs_cap: DBS capabality
+ * @agile_dfs_cap: Agile DFS capabality
+ * @action_type: for dbs mode, the field indicates the "Action type" to be
+ * used to switch to the mode. To help the hw mode validation.
+ */
+struct policy_mgr_hw_mode_params {
+	uint8_t mac0_tx_ss;
+	uint8_t mac0_rx_ss;
+	uint8_t mac1_tx_ss;
+	uint8_t mac1_rx_ss;
+	uint8_t mac0_bw;
+	uint8_t mac1_bw;
+	uint8_t mac0_band_cap;
+	uint8_t dbs_cap;
+	uint8_t agile_dfs_cap;
+	uint8_t sbs_cap;
+	enum policy_mgr_conc_next_action action_type;
+};
+
+/**
+ * struct policy_mgr_vdev_mac_map - vdev id-mac id map
+ * @vdev_id: VDEV id
+ * @mac_id: MAC id
+ */
+struct policy_mgr_vdev_mac_map {
+	uint32_t vdev_id;
+	uint32_t mac_id;
+};
+
+/**
+ * struct policy_mgr_dual_mac_config - Dual MAC configuration
+ * @scan_config: Scan configuration
+ * @fw_mode_config: FW mode configuration
+ * @set_dual_mac_cb: Callback function to be executed on response to the command
+ */
+struct policy_mgr_dual_mac_config {
+	uint32_t scan_config;
+	uint32_t fw_mode_config;
+	dual_mac_cb set_dual_mac_cb;
+};
+
+/**
+ * struct policy_mgr_hw_mode - Format of set HW mode
+ * @hw_mode_index: Index of HW mode to be set
+ * @set_hw_mode_cb: HDD set HW mode callback
+ * @reason: Reason for HW mode change
+ * @session_id: Session id
+ * @next_action: next action to happen at policy mgr
+ * @context: psoc context
+ */
+struct policy_mgr_hw_mode {
+	uint32_t hw_mode_index;
+	void *set_hw_mode_cb;
+	enum policy_mgr_conn_update_reason reason;
+	uint32_t session_id;
+	uint8_t next_action;
+	struct wlan_objmgr_psoc *context;
+};
+
+/**
+ * struct policy_mgr_pcl_list - Format of PCL
+ * @pcl_list: List of preferred channels
+ * @weight_list: Weights of the PCL
+ * @pcl_len: Number of channels in the PCL
+ */
+struct policy_mgr_pcl_list {
+	uint8_t pcl_list[POLICY_MGR_MAX_CHANNEL_LIST];
+	uint8_t weight_list[POLICY_MGR_MAX_CHANNEL_LIST];
+	uint32_t pcl_len;
+};
+
+/**
+ * struct policy_mgr_pcl_chan_weights - Params to get the valid weighed list
+ * @pcl_list: Preferred channel list already sorted in the order of preference
+ * @pcl_len: Length of the PCL
+ * @saved_chan_list: Valid channel list updated as part of
+ * WMA_UPDATE_CHAN_LIST_REQ
+ * @saved_num_chan: Length of the valid channel list
+ * @weighed_valid_list: Weights of the valid channel list. This will have one
+ * to one mapping with valid_chan_list. FW expects channel order and size to be
+ * as per the list provided in WMI_SCAN_CHAN_LIST_CMDID.
+ * @weight_list: Weights assigned by policy manager
+ */
+struct policy_mgr_pcl_chan_weights {
+	uint8_t pcl_list[POLICY_MGR_MAX_CHANNEL_LIST];
+	uint32_t pcl_len;
+	uint8_t saved_chan_list[POLICY_MGR_MAX_CHANNEL_LIST];
+	uint32_t saved_num_chan;
+	uint8_t weighed_valid_list[POLICY_MGR_MAX_CHANNEL_LIST];
+	uint8_t weight_list[POLICY_MGR_MAX_CHANNEL_LIST];
+};
+
+/**
+ * struct policy_mgr_vdev_entry_info - vdev related param to be
+ * used by policy manager
+ * @type: type
+ * @sub_type: sub type
+ * @mhz: channel frequency in MHz
+ * @chan_width: channel bandwidth
+ * @mac_id: the mac on which vdev is on
+ */
+struct policy_mgr_vdev_entry_info {
+	uint32_t type;
+	uint32_t sub_type;
+	uint32_t mhz;
+	uint32_t chan_width;
+	uint32_t mac_id;
+};
+
+/**
+ * struct dbs_hw_mode_info - WLAN_DBS_HW_MODES_TLV Format
+ * @tlv_header: TLV header, TLV tag and len; tag equals WMITLV_TAG_ARRAY_UINT32
+ * @hw_mode_list: WLAN_DBS_HW_MODE_LIST entries
+ */
+struct dbs_hw_mode_info {
+	uint32_t tlv_header;
+	uint32_t *hw_mode_list;
+};
+
+/**
+ * struct dual_mac_config - Dual MAC configurations
+ * @prev_scan_config: Previous scan configuration
+ * @prev_fw_mode_config: Previous FW mode configuration
+ * @cur_scan_config: Current scan configuration
+ * @cur_fw_mode_config: Current FW mode configuration
+ * @req_scan_config: Requested scan configuration
+ * @req_fw_mode_config: Requested FW mode configuration
+ */
+struct dual_mac_config {
+	uint32_t prev_scan_config;
+	uint32_t prev_fw_mode_config;
+	uint32_t cur_scan_config;
+	uint32_t cur_fw_mode_config;
+	uint32_t req_scan_config;
+	uint32_t req_fw_mode_config;
+};
+
+/**
+ * enum policy_mgr_pri_id - vdev type priority id
+ * @PM_STA_PRI_ID: station vdev type priority id
+ * @PM_SAP_PRI_ID: sap vdev type priority id
+ * @PM_P2P_GO_PRI_ID: p2p go vdev type priority id
+ * @PM_P2P_CLI_PRI_ID: p2p cli vdev type priority id
+ * @PM_MAX_PRI_ID: vdev type priority id max value
+ */
+enum policy_mgr_pri_id {
+	PM_STA_PRI_ID = 1,
+	PM_SAP_PRI_ID,
+	PM_P2P_GO_PRI_ID,
+	PM_P2P_CLI_PRI_ID,
+	PM_MAX_PRI_ID = 0xF,
+};
+
+#define PM_GET_BAND_PREFERRED(_policy_) ((_policy_) & 0x1)
+#define PM_GET_VDEV_PRIORITY_ENABLED(_policy_) (((_policy_) & 0x2) >> 1)
+
+/**
+ * struct policy_mgr_user_cfg - Policy manager user config variables
+ * @enable2x2: 2x2 chain mask user config
+ * @sub_20_mhz_enabled: Is 5 or 10 Mhz enabled
+ */
+struct policy_mgr_user_cfg {
+	bool enable2x2;
+	bool sub_20_mhz_enabled;
+	bool is_sta_sap_scc_allowed_on_dfs_chan;
+	uint32_t sta_sap_scc_on_lte_coex_chan;
+};
+
+/**
+ * struct dbs_nss - Number of spatial streams in DBS mode
+ * @mac0_ss: Number of spatial streams on MAC0
+ * @mac1_ss: Number of spatial streams on MAC1
+ */
+struct dbs_nss {
+	enum hw_mode_ss_config mac0_ss;
+	enum hw_mode_ss_config mac1_ss;
+};
+
+/**
+ * struct connection_info - connection information
+ * @mac_id: The HW mac it is running
+ * @vdev_id: vdev id
+ * @channel: channel of the connection
+ */
+struct connection_info {
+	uint8_t mac_id;
+	uint8_t vdev_id;
+	uint8_t channel;
+};
+#endif /* __WLAN_POLICY_MGR_PUBLIC_STRUCT_H */

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

@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef __WLAN_POLICY_MGR_UCFG
+#define __WLAN_POLICY_MGR_UCFG
+#include "wlan_objmgr_psoc_obj.h"
+#include "wlan_objmgr_global_obj.h"
+#include "qdf_status.h"
+
+
+/**
+ * ucfg_policy_mgr_psoc_open() - This API sets CFGs to policy manager context
+ *
+ * This API pulls policy manager's context from PSOC and initialize the CFG
+ * structure of policy manager.
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_psoc_open(struct wlan_objmgr_psoc *psoc);
+/**
+ * ucfg_policy_mgr_psoc_close() - This API resets CFGs for policy manager ctx
+ *
+ * This API pulls policy manager's context from PSOC and resets the CFG
+ * structure of policy manager.
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+void ucfg_policy_mgr_psoc_close(struct wlan_objmgr_psoc *psoc);
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+/**
+ * ucfg_policy_mgr_get_mcc_scc_switch() - To mcc to scc switch setting from INI
+ * @psoc: pointer to psoc
+ * @mcc_scc_switch: value to be filled
+ *
+ * This API pulls mcc to scc switch setting which is given as part of INI and
+ * stored in policy manager's CFGs.
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc,
+					      uint8_t *mcc_scc_switch);
+#else
+static inline
+QDF_STATUS ucfg_policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc,
+					      uint8_t *mcc_scc_switch)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif //FEATURE_WLAN_MCC_TO_SCC_SWITCH
+/**
+ * ucfg_policy_mgr_get_sys_pref() - to get system preference
+ * @psoc: pointer to psoc
+ * @sys_pref: value to be filled
+ *
+ * This API pulls the system preference for policy manager to provide
+ * PCL
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_get_sys_pref(struct wlan_objmgr_psoc *psoc,
+					uint8_t *sys_pref);
+/**
+ * ucfg_policy_mgr_set_sys_pref() - to set system preference
+ * @psoc: pointer to psoc
+ * @sys_pref: value to be applied as new INI setting
+ *
+ * This API is meant to override original INI setting for system pref
+ * with new value which is used by policy manager to provide PCL
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_set_sys_pref(struct wlan_objmgr_psoc *psoc,
+					uint8_t sys_pref);
+/**
+ * ucfg_policy_mgr_get_max_conc_cxns() - to get max num of conc connections
+ * @psoc: pointer to psoc
+ * @max_conc_cxns: value to be filled
+ *
+ * This API pulls max number of active connections which can be allowed
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_get_max_conc_cxns(struct wlan_objmgr_psoc *psoc,
+						uint8_t *max_conc_cxns);
+/**
+ * ucfg_policy_mgr_get_conc_rule1() - to find out if conc rule1 is enabled
+ * @psoc: pointer to psoc
+ * @conc_rule1: value to be filled
+ *
+ * This API is used to find out if conc rule-1 is enabled by user
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_get_conc_rule1(struct wlan_objmgr_psoc *psoc,
+						uint8_t *conc_rule1);
+/**
+ * ucfg_policy_mgr_get_conc_rule2() - to find out if conc rule2 is enabled
+ * @psoc: pointer to psoc
+ * @conc_rule2: value to be filled
+ *
+ * This API is used to find out if conc rule-2 is enabled by user
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_get_conc_rule2(struct wlan_objmgr_psoc *psoc,
+						uint8_t *conc_rule2);
+/**
+ * ucfg_policy_mgr_get_dbs_selection_plcy() - DBS HW mode selection setting
+ * @psoc: pointer to psoc
+ * @dbs_selection_plcy: value to be filled
+ *
+ * This API is used to find out DBS HW mode preference.
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_get_dbs_selection_plcy(struct wlan_objmgr_psoc *psoc,
+						uint32_t *dbs_selection_plcy);
+/**
+ * ucfg_policy_mgr_get_vdev_priority_list() - to get vdev priority list
+ * @psoc: pointer to psoc
+ * @vdev_priority_list: value to be filled
+ *
+ * This API is used to find out vdev_priority_list setting
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_get_vdev_priority_list(struct wlan_objmgr_psoc *psoc,
+						uint32_t *vdev_priority_list);
+/**
+ * policy_mgr_get_chnl_select_plcy() - to get channel selection policy
+ * @psoc: pointer to psoc
+ * @chnl_select_plcy: value to be filled
+ *
+ * This API is used to find out which channel selection policy has been
+ * configured
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_get_chnl_select_plcy(struct wlan_objmgr_psoc *psoc,
+						uint32_t *chnl_select_plcy);
+/**
+ * policy_mgr_get_mcc_adaptive_sch() - to get mcc adaptive scheduler
+ * @psoc: pointer to psoc
+ * @enable_mcc_adaptive_sch: value to be filled
+ *
+ * This API is used to find out if mcc adaptive scheduler enabled or disabled
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS
+ucfg_policy_mgr_get_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc,
+				     uint8_t *enable_mcc_adaptive_sch);
+
+/**
+ * ucfg_policy_mgr_get_sta_cxn_5g_band() - to get STA's connection in 5G config
+ *
+ * @psoc: pointer to psoc
+ * @enable_sta_cxn_5g_band: value to be filled
+ *
+ * This API is used to find out if STA connection in 5G band is allowed or
+ * disallowed.
+ *
+ * Return: QDF_STATUS_SUCCESS up on success and any other status for failure.
+ */
+QDF_STATUS ucfg_policy_mgr_get_sta_cxn_5g_band(struct wlan_objmgr_psoc *psoc,
+					       uint8_t *enable_sta_cxn_5g_band);
+#endif //__WLAN_POLICY_MGR_UCFG

+ 2183 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c

@@ -0,0 +1,2183 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_policy_mgr_action.c
+ *
+ * WLAN Concurrenct Connection Management APIs
+ *
+ */
+
+/* Include files */
+
+#include "wlan_policy_mgr_api.h"
+#include "wlan_policy_mgr_tables_no_dbs_i.h"
+#include "wlan_policy_mgr_i.h"
+#include "qdf_types.h"
+#include "qdf_trace.h"
+#include "wlan_objmgr_global_obj.h"
+#include "qdf_platform.h"
+
+enum policy_mgr_conc_next_action (*policy_mgr_get_current_pref_hw_mode_ptr)
+	(struct wlan_objmgr_psoc *psoc);
+
+void policy_mgr_hw_mode_transition_cb(uint32_t old_hw_mode_index,
+			uint32_t new_hw_mode_index,
+			uint32_t num_vdev_mac_entries,
+			struct policy_mgr_vdev_mac_map *vdev_mac_map,
+			struct wlan_objmgr_psoc *context)
+{
+	QDF_STATUS status;
+	struct policy_mgr_hw_mode_params hw_mode;
+	uint32_t i;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(context);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return;
+	}
+
+	if (!vdev_mac_map) {
+		policy_mgr_err("vdev_mac_map is NULL");
+		return;
+	}
+
+	policy_mgr_debug("old_hw_mode_index=%d, new_hw_mode_index=%d",
+		old_hw_mode_index, new_hw_mode_index);
+
+	for (i = 0; i < num_vdev_mac_entries; i++)
+		policy_mgr_debug("vdev_id:%d mac_id:%d",
+			vdev_mac_map[i].vdev_id,
+			vdev_mac_map[i].mac_id);
+
+	status = policy_mgr_get_hw_mode_from_idx(context,
+				new_hw_mode_index, &hw_mode);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Get HW mode failed: %d", status);
+		return;
+	}
+
+	policy_mgr_debug("MAC0: TxSS:%d, RxSS:%d, Bw:%d band_cap:%d",
+			 hw_mode.mac0_tx_ss, hw_mode.mac0_rx_ss,
+			 hw_mode.mac0_bw, hw_mode.mac0_band_cap);
+	policy_mgr_debug("MAC1: TxSS:%d, RxSS:%d, Bw:%d",
+			 hw_mode.mac1_tx_ss, hw_mode.mac1_rx_ss,
+			 hw_mode.mac1_bw);
+	policy_mgr_debug("DBS:%d, Agile DFS:%d, SBS:%d",
+			 hw_mode.dbs_cap, hw_mode.agile_dfs_cap,
+			 hw_mode.sbs_cap);
+
+	/* update pm_conc_connection_list */
+	policy_mgr_update_hw_mode_conn_info(context, num_vdev_mac_entries,
+					  vdev_mac_map,
+					  hw_mode);
+
+	if (pm_ctx->mode_change_cb)
+		pm_ctx->mode_change_cb();
+
+	return;
+}
+
+QDF_STATUS policy_mgr_check_n_start_opportunistic_timer(
+		struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("PM ctx not valid. Oppurtunistic timer cannot start");
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (policy_mgr_need_opportunistic_upgrade(psoc, NULL)) {
+	/* let's start the timer */
+	qdf_mc_timer_stop(&pm_ctx->dbs_opportunistic_timer);
+	status = qdf_mc_timer_start(
+				&pm_ctx->dbs_opportunistic_timer,
+				DBS_OPPORTUNISTIC_TIME * 1000);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		policy_mgr_err("Failed to start dbs opportunistic timer");
+	}
+	return status;
+}
+
+QDF_STATUS policy_mgr_pdev_set_hw_mode(struct wlan_objmgr_psoc *psoc,
+		uint32_t session_id,
+		enum hw_mode_ss_config mac0_ss,
+		enum hw_mode_bandwidth mac0_bw,
+		enum hw_mode_ss_config mac1_ss,
+		enum hw_mode_bandwidth mac1_bw,
+		enum hw_mode_mac_band_cap mac0_band_cap,
+		enum hw_mode_dbs_capab dbs,
+		enum hw_mode_agile_dfs_capab dfs,
+		enum hw_mode_sbs_capab sbs,
+		enum policy_mgr_conn_update_reason reason,
+		uint8_t next_action)
+{
+	int8_t hw_mode_index;
+	struct policy_mgr_hw_mode msg;
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/*
+	 * if HW is not capable of doing 2x2 or ini config disabled 2x2, don't
+	 * allow to request FW for 2x2
+	 */
+	if ((HW_MODE_SS_2x2 == mac0_ss) && (!pm_ctx->user_cfg.enable2x2)) {
+		policy_mgr_debug("2x2 is not allowed downgrading to 1x1 for mac0");
+		mac0_ss = HW_MODE_SS_1x1;
+	}
+	if ((HW_MODE_SS_2x2 == mac1_ss) && (!pm_ctx->user_cfg.enable2x2)) {
+		policy_mgr_debug("2x2 is not allowed downgrading to 1x1 for mac1");
+		mac1_ss = HW_MODE_SS_1x1;
+	}
+
+	hw_mode_index = policy_mgr_get_hw_mode_idx_from_dbs_hw_list(psoc,
+			mac0_ss, mac0_bw, mac1_ss, mac1_bw, mac0_band_cap,
+			dbs, dfs, sbs);
+	if (hw_mode_index < 0) {
+		policy_mgr_err("Invalid HW mode index obtained");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	msg.hw_mode_index = hw_mode_index;
+	msg.set_hw_mode_cb = (void *)policy_mgr_pdev_set_hw_mode_cb;
+	msg.reason = reason;
+	msg.session_id = session_id;
+	msg.next_action = next_action;
+	msg.context = psoc;
+
+	policy_mgr_debug("set hw mode to sme: hw_mode_index: %d session:%d reason:%d",
+		msg.hw_mode_index, msg.session_id, msg.reason);
+
+	status = pm_ctx->sme_cbacks.sme_pdev_set_hw_mode(msg);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to set hw mode to SME");
+		return status;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+enum policy_mgr_conc_next_action policy_mgr_need_opportunistic_upgrade(
+		struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_conn_update_reason *reason)
+{
+	uint32_t conn_index;
+	enum policy_mgr_conc_next_action upgrade = PM_NOP;
+	enum policy_mgr_conc_next_action preferred_dbs_action;
+	uint8_t mac = 0;
+	struct policy_mgr_hw_mode_params hw_mode;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		goto exit;
+	}
+
+	if (policy_mgr_is_hw_dbs_capable(psoc) == false) {
+		policy_mgr_err("driver isn't dbs capable, no further action needed");
+		goto exit;
+	}
+
+	status = policy_mgr_get_current_hw_mode(psoc, &hw_mode);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("policy_mgr_get_current_hw_mode failed");
+		goto exit;
+	}
+	if (!hw_mode.dbs_cap) {
+		policy_mgr_debug("current HW mode is non-DBS capable");
+		goto exit;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	/* Are both mac's still in use */
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		conn_index++) {
+		policy_mgr_debug("index:%d mac:%d in_use:%d chan:%d org_nss:%d",
+			conn_index,
+			pm_conc_connection_list[conn_index].mac,
+			pm_conc_connection_list[conn_index].in_use,
+			pm_conc_connection_list[conn_index].chan,
+			pm_conc_connection_list[conn_index].original_nss);
+		if ((pm_conc_connection_list[conn_index].mac == 0) &&
+			pm_conc_connection_list[conn_index].in_use) {
+			mac |= POLICY_MGR_MAC0;
+			if (POLICY_MGR_MAC0_AND_MAC1 == mac) {
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				goto done;
+			}
+		} else if ((pm_conc_connection_list[conn_index].mac == 1) &&
+			pm_conc_connection_list[conn_index].in_use) {
+			mac |= POLICY_MGR_MAC1;
+			if (policy_mgr_is_hw_dbs_2x2_capable(psoc) &&
+			    WLAN_REG_IS_24GHZ_CH(
+				    pm_conc_connection_list[conn_index].chan)
+			    ) {
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				policy_mgr_debug("2X2 DBS capable with 2.4 GHZ connection");
+				goto done;
+			}
+			if (POLICY_MGR_MAC0_AND_MAC1 == mac) {
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				goto done;
+			}
+		}
+	}
+	/* Let's request for single MAC mode */
+	upgrade = PM_SINGLE_MAC;
+	if (reason)
+		*reason = POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC;
+	/* Is there any connection had an initial connection with 2x2 */
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		conn_index++) {
+		if ((pm_conc_connection_list[conn_index].original_nss == 2) &&
+			pm_conc_connection_list[conn_index].in_use) {
+			upgrade = PM_SINGLE_MAC_UPGRADE;
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+			goto done;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+done:
+	if (upgrade == PM_NOP && hw_mode.dbs_cap &&
+	    policy_mgr_is_2x2_1x1_dbs_capable(psoc)) {
+		preferred_dbs_action =
+			policy_mgr_get_preferred_dbs_action_table(
+					psoc, INVALID_VDEV_ID, 0, 0);
+		if (hw_mode.action_type == PM_DBS1 &&
+		    preferred_dbs_action == PM_DBS2) {
+			upgrade = PM_DBS2_DOWNGRADE;
+			if (reason)
+				*reason =
+				POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE;
+		} else if (hw_mode.action_type == PM_DBS2 &&
+		    preferred_dbs_action == PM_DBS1) {
+			upgrade = PM_DBS1_DOWNGRADE;
+			if (reason)
+				*reason =
+				POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE;
+		}
+	}
+exit:
+	return upgrade;
+}
+
+QDF_STATUS policy_mgr_update_connection_info(struct wlan_objmgr_psoc *psoc,
+					uint32_t vdev_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint32_t conn_index = 0;
+	bool found = false;
+	struct policy_mgr_vdev_entry_info conn_table_entry;
+	enum policy_mgr_chain_mode chain_mask = POLICY_MGR_ONE_ONE;
+	uint8_t nss_2g, nss_5g;
+	enum policy_mgr_con_mode mode;
+	uint8_t chan;
+	uint32_t nss = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+		if (vdev_id == pm_conc_connection_list[conn_index].vdev_id) {
+			/* debug msg */
+			found = true;
+			break;
+		}
+		conn_index++;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	if (!found) {
+		/* err msg */
+		policy_mgr_err("can't find vdev_id %d in pm_conc_connection_list",
+			vdev_id);
+		return status;
+	}
+	if (pm_ctx->wma_cbacks.wma_get_connection_info) {
+		status = pm_ctx->wma_cbacks.wma_get_connection_info(
+				vdev_id, &conn_table_entry);
+		if (QDF_STATUS_SUCCESS != status) {
+			policy_mgr_err("can't find vdev_id %d in connection table",
+			vdev_id);
+			return status;
+		}
+	} else {
+		policy_mgr_err("wma_get_connection_info is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mode = policy_mgr_get_mode(conn_table_entry.type,
+					conn_table_entry.sub_type);
+	chan = wlan_reg_freq_to_chan(pm_ctx->pdev, conn_table_entry.mhz);
+	status = policy_mgr_get_nss_for_vdev(psoc, mode, &nss_2g, &nss_5g);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		if ((WLAN_REG_IS_24GHZ_CH(chan) && (nss_2g > 1)) ||
+			(WLAN_REG_IS_5GHZ_CH(chan) && (nss_5g > 1)))
+			chain_mask = POLICY_MGR_TWO_TWO;
+		else
+			chain_mask = POLICY_MGR_ONE_ONE;
+		nss = (WLAN_REG_IS_24GHZ_CH(chan)) ? nss_2g : nss_5g;
+	} else {
+		policy_mgr_err("Error in getting nss");
+	}
+
+	policy_mgr_debug("update PM connection table for vdev:%d", vdev_id);
+
+	/* add the entry */
+	policy_mgr_update_conc_list(psoc, conn_index,
+			mode,
+			chan,
+			policy_mgr_get_bw(conn_table_entry.chan_width),
+			conn_table_entry.mac_id,
+			chain_mask,
+			nss, vdev_id, true, true);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_update_and_wait_for_connection_update(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t session_id,
+		uint8_t channel,
+		enum policy_mgr_conn_update_reason reason)
+{
+	QDF_STATUS status;
+
+	policy_mgr_debug("session:%d channel:%d reason:%d",
+		session_id, channel, reason);
+
+	status = policy_mgr_reset_connection_update(psoc);
+	if (QDF_IS_STATUS_ERROR(status))
+		policy_mgr_err("clearing event failed");
+
+	status = policy_mgr_current_connections_update(psoc,
+				session_id, channel, reason);
+	if (QDF_STATUS_E_FAILURE == status) {
+		policy_mgr_err("connections update failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Wait only when status is success */
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		status = policy_mgr_wait_for_connection_update(psoc);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			policy_mgr_err("qdf wait for event failed");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * policy_mgr_is_dbs_allowed_for_concurrency() - If dbs is allowed for current
+ * concurreny
+ * @new_conn_mode: new connection mode
+ *
+ * When a new connection is about to come up, check if dbs is allowed for
+ * STA+STA or STA+P2P
+ *
+ * Return: true if dbs is allowed for STA+STA or STA+P2P else false
+ */
+bool policy_mgr_is_dbs_allowed_for_concurrency(
+		struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE new_conn_mode)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t count, dbs_for_sta_sta, dbs_for_sta_p2p;
+	bool ret = true;
+	uint32_t ch_sel_plcy;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return ret;
+	}
+
+	count = policy_mgr_get_connection_count(psoc);
+
+	if (count != 1 || new_conn_mode == QDF_MAX_NO_OF_MODE)
+		return ret;
+
+	ch_sel_plcy = pm_ctx->cfg.chnl_select_plcy;
+	dbs_for_sta_sta = PM_CHANNEL_SELECT_LOGIC_STA_STA_GET(ch_sel_plcy);
+	dbs_for_sta_p2p = PM_CHANNEL_SELECT_LOGIC_STA_P2P_GET(ch_sel_plcy);
+
+	switch (pm_conc_connection_list[0].mode) {
+	case PM_STA_MODE:
+		switch (new_conn_mode) {
+		case QDF_STA_MODE:
+			if (!dbs_for_sta_sta)
+				return false;
+			break;
+		case QDF_P2P_DEVICE_MODE:
+		case QDF_P2P_CLIENT_MODE:
+		case QDF_P2P_GO_MODE:
+			if (!dbs_for_sta_p2p)
+				return false;
+			break;
+		default:
+			break;
+		}
+		break;
+	case PM_P2P_CLIENT_MODE:
+	case PM_P2P_GO_MODE:
+		switch (new_conn_mode) {
+		case QDF_STA_MODE:
+			if (!dbs_for_sta_p2p)
+				return false;
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+bool policy_mgr_is_chnl_in_diff_band(struct wlan_objmgr_psoc *psoc,
+					    uint8_t channel)
+{
+	uint8_t i, pm_chnl;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	/*
+	 * check given channel against already existing connections'
+	 * channels. if they differ then channels are in different bands
+	 */
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) {
+		pm_chnl = pm_conc_connection_list[i].chan;
+		if (pm_conc_connection_list[i].in_use)
+			if (!WLAN_REG_IS_SAME_BAND_CHANNELS(channel, pm_chnl)) {
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				policy_mgr_debug("channel is in diff band");
+				return true;
+			}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return false;
+}
+
+bool policy_mgr_is_hwmode_set_for_given_chnl(struct wlan_objmgr_psoc *psoc,
+					     uint8_t channel)
+{
+	enum policy_mgr_band band;
+	bool is_hwmode_dbs, is_2x2_dbs;
+
+	if (policy_mgr_is_hw_dbs_capable(psoc) == false)
+		return true;
+
+	if (WLAN_REG_IS_24GHZ_CH(channel))
+		band = POLICY_MGR_BAND_24;
+	else
+		band = POLICY_MGR_BAND_5;
+
+	is_hwmode_dbs = policy_mgr_is_current_hwmode_dbs(psoc);
+	is_2x2_dbs = policy_mgr_is_hw_dbs_2x2_capable(psoc);
+	/*
+	 * If HW supports 2x2 chains in DBS HW mode and if DBS HW mode is not
+	 * yet set then this is the right time to block the connection.
+	 */
+	if ((band == POLICY_MGR_BAND_24) && is_2x2_dbs && !is_hwmode_dbs) {
+		policy_mgr_err("HW mode is not yet in DBS!!!!!");
+		return false;
+	}
+
+	/*
+	 * If HW supports 1x1 chains DBS HW mode and if first connection is
+	 * 2G or 5G band and if second connection is coming up in diffrent
+	 * band than the first connection and if current HW mode is not yet
+	 * set in DBS then this is the right time to block the connection.
+	 */
+	if (policy_mgr_is_chnl_in_diff_band(psoc, channel) && !is_hwmode_dbs) {
+		policy_mgr_err("Given channel & existing conn is diff band & HW mode is not yet in DBS !!!!");
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * policy_mgr_pri_id_to_con_mode() - convert policy_mgr_pri_id to
+ * policy_mgr_con_mode
+ * @pri_id: policy_mgr_pri_id
+ *
+ * The help function converts policy_mgr_pri_id type to  policy_mgr_con_mode
+ * type.
+ *
+ * Return: policy_mgr_con_mode type.
+ */
+static
+enum policy_mgr_con_mode policy_mgr_pri_id_to_con_mode(
+	enum policy_mgr_pri_id pri_id)
+{
+	switch (pri_id) {
+	case PM_STA_PRI_ID:
+		return PM_STA_MODE;
+	case PM_SAP_PRI_ID:
+		return PM_SAP_MODE;
+	case PM_P2P_GO_PRI_ID:
+		return PM_P2P_GO_MODE;
+	case PM_P2P_CLI_PRI_ID:
+		return PM_P2P_CLIENT_MODE;
+	default:
+		return PM_MAX_NUM_OF_MODE;
+	}
+}
+
+enum policy_mgr_conc_next_action
+policy_mgr_get_preferred_dbs_action_table(
+	struct wlan_objmgr_psoc *psoc,
+	uint32_t vdev_id,
+	uint8_t channel,
+	enum policy_mgr_conn_update_reason reason)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	enum policy_mgr_con_mode pri_conn_mode = PM_MAX_NUM_OF_MODE;
+	enum policy_mgr_con_mode new_conn_mode = PM_MAX_NUM_OF_MODE;
+	enum QDF_OPMODE new_conn_op_mode = QDF_MAX_NO_OF_MODE;
+	bool band_pref_5g = true;
+	bool vdev_priority_enabled = false;
+	bool dbs_2x2_5g_1x1_2g_supported;
+	bool dbs_2x2_2g_1x1_5g_supported;
+	uint32_t vdev_pri_list, vdev_pri_id;
+	uint8_t chan_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1];
+	uint8_t vdev_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1];
+	uint32_t vdev_count = 0;
+	uint32_t i;
+	bool found;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return PM_NOP;
+	}
+	dbs_2x2_5g_1x1_2g_supported =
+		policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(psoc);
+	dbs_2x2_2g_1x1_5g_supported =
+		policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(psoc);
+	policy_mgr_debug("target support DBS1 %d DBS2 %d",
+			 dbs_2x2_5g_1x1_2g_supported,
+			 dbs_2x2_2g_1x1_5g_supported);
+	/*
+	 * If both DBS1 and DBS2 not supported, this should be Legacy Single
+	 * DBS mode HW. The policy_mgr_psoc_enable has setup the correct
+	 * action tables.
+	 */
+	if (!dbs_2x2_5g_1x1_2g_supported && !dbs_2x2_2g_1x1_5g_supported)
+		return PM_NOP;
+	if (!dbs_2x2_5g_1x1_2g_supported) {
+		band_pref_5g = false;
+		policy_mgr_debug("target only supports DBS2!");
+		goto DONE;
+	}
+	if (!dbs_2x2_2g_1x1_5g_supported) {
+		policy_mgr_debug("target only supports DBS1!");
+		goto DONE;
+	}
+	if (PM_GET_BAND_PREFERRED(pm_ctx->cfg.dbs_selection_plcy) == 1)
+		band_pref_5g = false;
+
+	if (PM_GET_VDEV_PRIORITY_ENABLED(
+	    pm_ctx->cfg.dbs_selection_plcy) == 1 &&
+	    pm_ctx->cfg.vdev_priority_list)
+		vdev_priority_enabled = true;
+
+	if (!vdev_priority_enabled)
+		goto DONE;
+
+	if (vdev_id != INVALID_VDEV_ID && channel) {
+		if (pm_ctx->hdd_cbacks.hdd_get_device_mode)
+			new_conn_op_mode = pm_ctx->hdd_cbacks.
+					hdd_get_device_mode(vdev_id);
+
+		new_conn_mode = policy_mgr_convert_device_mode_to_qdf_type(
+			new_conn_op_mode);
+		if (new_conn_mode == PM_MAX_NUM_OF_MODE)
+			policy_mgr_debug("new vdev %d op_mode %d chan %d reason %d: not prioritized",
+					 vdev_id, new_conn_op_mode,
+					 channel, reason);
+		else
+			policy_mgr_debug("new vdev %d op_mode %d chan %d : reason %d",
+					 vdev_id, new_conn_op_mode, channel,
+					 reason);
+	}
+	vdev_pri_list = pm_ctx->cfg.vdev_priority_list;
+	while (vdev_pri_list) {
+		vdev_pri_id = vdev_pri_list & 0xF;
+		pri_conn_mode = policy_mgr_pri_id_to_con_mode(vdev_pri_id);
+		if (pri_conn_mode == PM_MAX_NUM_OF_MODE) {
+			policy_mgr_debug("vdev_pri_id %d prioritization not supported",
+					 vdev_pri_id);
+			goto NEXT;
+		}
+		vdev_count = policy_mgr_get_mode_specific_conn_info(
+				psoc, chan_list, vdev_list, pri_conn_mode);
+		/**
+		 * Take care of duplication case, the vdev id may
+		 * exist in the conn list already with old chan.
+		 * Replace with new chan before make decision.
+		 */
+		found = false;
+		for (i = 0; i < vdev_count; i++) {
+			policy_mgr_debug("[%d] vdev %d chan %d conn_mode %d",
+					 i, vdev_list[i], chan_list[i],
+					 pri_conn_mode);
+
+			if (new_conn_mode == pri_conn_mode &&
+			    vdev_list[i] == vdev_id) {
+				chan_list[i] = channel;
+				found = true;
+			}
+		}
+		/**
+		 * The new coming vdev should be added to the list to
+		 * make decision if it is prioritized.
+		 */
+		if (!found && new_conn_mode == pri_conn_mode) {
+			chan_list[vdev_count] = channel;
+			vdev_list[vdev_count++] = vdev_id;
+		}
+		/**
+		 * if more than one vdev has same priority, keep "band_pref_5g"
+		 * value as default band preference setting.
+		 */
+		if (vdev_count > 1)
+			break;
+		/**
+		 * select the only active vdev (or new coming vdev) chan as
+		 * preferred band.
+		 */
+		if (vdev_count > 0) {
+			band_pref_5g = WLAN_REG_IS_5GHZ_CH(chan_list[0]);
+			break;
+		}
+NEXT:
+		vdev_pri_list >>= 4;
+	}
+DONE:
+	policy_mgr_debug("band_pref_5g %d", band_pref_5g);
+	if (band_pref_5g)
+		return PM_DBS1;
+	else
+		return PM_DBS2;
+}
+
+/**
+ * policy_mgr_get_second_conn_action_table() - get second conn action table
+ * @psoc: Pointer to psoc
+ * @vdev_id: vdev Id
+ * @channel: channel of vdev.
+ * @reason: reason of request
+ *
+ * Get the action table based on current HW Caps and INI user preference.
+ * This function will be called by policy_mgr_current_connections_update during
+ * DBS action decision.
+ *
+ * return : action table address
+ */
+static policy_mgr_next_action_two_connection_table_type *
+policy_mgr_get_second_conn_action_table(
+	struct wlan_objmgr_psoc *psoc,
+	uint32_t vdev_id,
+	uint8_t channel,
+	enum policy_mgr_conn_update_reason reason)
+{
+	enum policy_mgr_conc_next_action preferred_action;
+
+	if (!policy_mgr_is_2x2_1x1_dbs_capable(psoc))
+		return next_action_two_connection_table;
+
+	preferred_action = policy_mgr_get_preferred_dbs_action_table(
+				psoc, vdev_id, channel, reason);
+	switch (preferred_action) {
+	case PM_DBS2:
+		return next_action_two_connection_2x2_2g_1x1_5g_table;
+	default:
+		return next_action_two_connection_table;
+	}
+}
+
+/**
+ * policy_mgr_get_third_conn_action_table() - get third connection action table
+ * @psoc: Pointer to psoc
+ * @vdev_id: vdev Id
+ * @channel: channel of vdev.
+ * @reason: reason of request
+ *
+ * Get the action table based on current HW Caps and INI user preference.
+ * This function will be called by policy_mgr_current_connections_update during
+ * DBS action decision.
+ *
+ * return : action table address
+ */
+static policy_mgr_next_action_three_connection_table_type *
+policy_mgr_get_third_conn_action_table(
+	struct wlan_objmgr_psoc *psoc,
+	uint32_t vdev_id,
+	uint8_t channel,
+	enum policy_mgr_conn_update_reason reason)
+{
+	enum policy_mgr_conc_next_action preferred_action;
+
+	if (!policy_mgr_is_2x2_1x1_dbs_capable(psoc))
+		return next_action_three_connection_table;
+
+	preferred_action = policy_mgr_get_preferred_dbs_action_table(
+				psoc, vdev_id, channel, reason);
+	switch (preferred_action) {
+	case PM_DBS2:
+		return next_action_three_connection_2x2_2g_1x1_5g_table;
+	default:
+		return next_action_three_connection_table;
+	}
+}
+
+QDF_STATUS policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc,
+		uint32_t session_id,
+		uint8_t channel,
+		enum policy_mgr_conn_update_reason reason)
+{
+	enum policy_mgr_conc_next_action next_action = PM_NOP;
+	uint32_t num_connections = 0;
+	enum policy_mgr_one_connection_mode second_index = 0;
+	enum policy_mgr_two_connection_mode third_index = 0;
+	policy_mgr_next_action_two_connection_table_type *second_conn_table;
+	policy_mgr_next_action_three_connection_table_type *third_conn_table;
+	enum policy_mgr_band band;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	enum QDF_OPMODE new_conn_mode = QDF_MAX_NO_OF_MODE;
+
+	if (policy_mgr_is_hw_dbs_capable(psoc) == false) {
+		policy_mgr_err("driver isn't dbs capable, no further action needed");
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+	if (WLAN_REG_IS_24GHZ_CH(channel))
+		band = POLICY_MGR_BAND_24;
+	else
+		band = POLICY_MGR_BAND_5;
+
+	num_connections = policy_mgr_get_connection_count(psoc);
+
+	policy_mgr_debug("num_connections=%d channel=%d",
+		num_connections, channel);
+
+	switch (num_connections) {
+	case 0:
+		if (band == POLICY_MGR_BAND_24)
+			if (policy_mgr_is_hw_dbs_2x2_capable(psoc))
+				next_action = PM_DBS;
+			else
+				next_action = PM_NOP;
+		else
+			next_action = PM_NOP;
+		break;
+	case 1:
+		second_index =
+			policy_mgr_get_second_connection_pcl_table_index(psoc);
+		if (PM_MAX_ONE_CONNECTION_MODE == second_index) {
+			policy_mgr_err(
+			"couldn't find index for 2nd connection next action table");
+			goto done;
+		}
+		second_conn_table = policy_mgr_get_second_conn_action_table(
+			psoc, session_id, channel, reason);
+		next_action = (*second_conn_table)[second_index][band];
+		break;
+	case 2:
+		third_index =
+			policy_mgr_get_third_connection_pcl_table_index(psoc);
+		if (PM_MAX_TWO_CONNECTION_MODE == third_index) {
+			policy_mgr_err(
+			"couldn't find index for 3rd connection next action table");
+			goto done;
+		}
+		third_conn_table = policy_mgr_get_third_conn_action_table(
+			psoc, session_id, channel, reason);
+		next_action = (*third_conn_table)[third_index][band];
+		break;
+	default:
+		policy_mgr_err("unexpected num_connections value %d",
+			num_connections);
+		break;
+	}
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		goto done;
+	}
+
+	if (pm_ctx->hdd_cbacks.hdd_get_device_mode)
+		new_conn_mode = pm_ctx->hdd_cbacks.
+					hdd_get_device_mode(session_id);
+
+	/*
+	 * Based on channel_select_logic_conc ini, hw mode is set
+	 * when second connection is about to come up that results
+	 * in STA+STA and STA+P2P concurrency.
+	 * 1) If MCC is set and if current hw mode is dbs, hw mode
+	 *  should be set to single mac for above concurrency.
+	 * 2) If MCC is set and if current hw mode is not dbs, hw
+	 *  mode change is not required.
+	 */
+	if (policy_mgr_is_current_hwmode_dbs(psoc) &&
+		!policy_mgr_is_dbs_allowed_for_concurrency(psoc, new_conn_mode))
+		next_action = PM_SINGLE_MAC;
+	else if (!policy_mgr_is_current_hwmode_dbs(psoc) &&
+		!policy_mgr_is_dbs_allowed_for_concurrency(psoc, new_conn_mode))
+		next_action = PM_NOP;
+
+	if (PM_NOP != next_action)
+		status = policy_mgr_next_actions(psoc, session_id,
+						next_action, reason);
+	else
+		status = QDF_STATUS_E_NOSUPPORT;
+
+	policy_mgr_debug(
+		"idx2=%d idx3=%d next_action=%d, band=%d status=%d reason=%d session_id=%d",
+		second_index, third_index, next_action, band, status,
+		reason, session_id);
+
+done:
+	return status;
+}
+
+/**
+ * policy_mgr_validate_dbs_switch() - Check DBS action valid or not
+ * @psoc: Pointer to psoc
+ * @session_id: vdev id
+ * @action: action requested
+ * @reason: reason of hw mode change
+ *
+ * This routine will check the current hw mode with requested action.
+ * If we are already in the mode, the caller will do nothing.
+ * This will be called by policy_mgr_next_actions to check the action needed
+ * or not.
+ *
+ * return : QDF_STATUS_SUCCESS, action is allowed.
+ *          QDF_STATUS_E_ALREADY, action is not needed.
+ *          QDF_STATUS_E_FAILURE, error happens.
+ *          QDF_STATUS_E_NOSUPPORT, the requested mode not supported.
+ */
+static
+QDF_STATUS policy_mgr_validate_dbs_switch(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t session_id,
+		enum policy_mgr_conc_next_action action,
+		enum policy_mgr_conn_update_reason reason)
+{
+	QDF_STATUS status;
+	struct policy_mgr_hw_mode_params hw_mode;
+
+	/* check for the current HW index to see if really need any action */
+	status = policy_mgr_get_current_hw_mode(psoc, &hw_mode);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("policy_mgr_get_current_hw_mode failed");
+		return status;
+	}
+
+	if (hw_mode.sbs_cap) {
+		if ((action == PM_SBS) || (action == PM_SBS_DOWNGRADE)) {
+			if (!policy_mgr_is_hw_sbs_capable(psoc)) {
+				/* No action */
+				policy_mgr_notice("firmware is not sbs capable");
+				return QDF_STATUS_E_NOSUPPORT;
+			}
+			/* current mode is already SBS nothing to be
+			 * done
+			 */
+			 policy_mgr_notice("current mode is already SBS");
+			return QDF_STATUS_E_ALREADY;
+		} else {
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+
+	if (!hw_mode.dbs_cap) {
+		if (action == PM_SINGLE_MAC ||
+		    action == PM_SINGLE_MAC_UPGRADE) {
+			policy_mgr_notice("current mode is already single MAC");
+			return QDF_STATUS_E_ALREADY;
+		} else {
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+	/**
+	 * If already in DBS, no need to request DBS again (HL, Napier).
+	 * For dual DBS HW, in case DBS1 -> DBS2 or DBS2 -> DBS1
+	 * switching, we need to check the current DBS mode is same as
+	 * requested or not.
+	 */
+	if (policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(psoc) ||
+	    policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(psoc)) {
+		policy_mgr_info("curr dbs action %d new action %d",
+				hw_mode.action_type, action);
+		if (hw_mode.action_type == PM_DBS1 &&
+		    ((action == PM_DBS1 ||
+		    action == PM_DBS1_DOWNGRADE))) {
+			policy_mgr_err("driver is already in DBS_5G_2x2_24G_1x1 (%d), no further action %d needed",
+				       hw_mode.action_type, action);
+			return QDF_STATUS_E_ALREADY;
+		} else if (hw_mode.action_type == PM_DBS2 &&
+			   ((action == PM_DBS2 ||
+			   action == PM_DBS2_DOWNGRADE))) {
+			policy_mgr_err("driver is already in DBS_24G_2x2_5G_1x1 (%d), no further action %d needed",
+				       hw_mode.action_type, action);
+			return QDF_STATUS_E_ALREADY;
+		}
+	} else if ((action == PM_DBS_DOWNGRADE) || (action == PM_DBS) ||
+		   (action == PM_DBS_UPGRADE)) {
+		policy_mgr_err("driver is already in %s mode, no further action needed",
+			       (hw_mode.dbs_cap) ? "dbs" : "non dbs");
+		return QDF_STATUS_E_ALREADY;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_next_actions(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t session_id,
+		enum policy_mgr_conc_next_action action,
+		enum policy_mgr_conn_update_reason reason)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct dbs_nss nss_dbs = {0};
+	struct policy_mgr_hw_mode_params hw_mode;
+	enum policy_mgr_conc_next_action next_action;
+
+	if (policy_mgr_is_hw_dbs_capable(psoc) == false) {
+		policy_mgr_err("driver isn't dbs capable, no further action needed");
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+
+	/* check for the current HW index to see if really need any action */
+	status = policy_mgr_get_current_hw_mode(psoc, &hw_mode);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("policy_mgr_get_current_hw_mode failed");
+		return status;
+	}
+
+	/* check for the current HW index to see if really need any action */
+	status = policy_mgr_validate_dbs_switch(psoc, session_id, action,
+						reason);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err(" not take action %d reason %d session %d status %d",
+			       action, reason, session_id, status);
+		return status;
+	}
+
+	switch (action) {
+	case PM_DBS_DOWNGRADE:
+		/*
+		* check if we have a beaconing entity that is using 2x2. If yes,
+		* update the beacon template & notify FW. Once FW confirms
+		*  beacon updated, send down the HW mode change req
+		*/
+		status = policy_mgr_complete_action(psoc, POLICY_MGR_RX_NSS_1,
+					PM_DBS, reason, session_id);
+		break;
+	case PM_DBS:
+		(void)policy_mgr_get_hw_dbs_nss(psoc, &nss_dbs);
+
+		status = policy_mgr_pdev_set_hw_mode(psoc, session_id,
+						     nss_dbs.mac0_ss,
+						     HW_MODE_80_MHZ,
+						     nss_dbs.mac1_ss,
+						     HW_MODE_40_MHZ,
+						     HW_MODE_MAC_BAND_NONE,
+						     HW_MODE_DBS,
+						     HW_MODE_AGILE_DFS_NONE,
+						     HW_MODE_SBS_NONE,
+						     reason, PM_NOP);
+		break;
+	case PM_SINGLE_MAC_UPGRADE:
+		/*
+		 * change the HW mode first before the NSS upgrade
+		 */
+		status = policy_mgr_pdev_set_hw_mode(psoc, session_id,
+						HW_MODE_SS_2x2,
+						HW_MODE_80_MHZ,
+						HW_MODE_SS_0x0, HW_MODE_BW_NONE,
+						HW_MODE_MAC_BAND_NONE,
+						HW_MODE_DBS_NONE,
+						HW_MODE_AGILE_DFS_NONE,
+						HW_MODE_SBS_NONE,
+						reason, PM_UPGRADE);
+		break;
+	case PM_SINGLE_MAC:
+		status = policy_mgr_pdev_set_hw_mode(psoc, session_id,
+						HW_MODE_SS_2x2,
+						HW_MODE_80_MHZ,
+						HW_MODE_SS_0x0, HW_MODE_BW_NONE,
+						HW_MODE_MAC_BAND_NONE,
+						HW_MODE_DBS_NONE,
+						HW_MODE_AGILE_DFS_NONE,
+						HW_MODE_SBS_NONE,
+						reason, PM_NOP);
+		break;
+	case PM_DBS_UPGRADE:
+		status = policy_mgr_pdev_set_hw_mode(psoc, session_id,
+						HW_MODE_SS_2x2,
+						HW_MODE_80_MHZ,
+						HW_MODE_SS_2x2, HW_MODE_80_MHZ,
+						HW_MODE_MAC_BAND_NONE,
+						HW_MODE_DBS,
+						HW_MODE_AGILE_DFS_NONE,
+						HW_MODE_SBS_NONE,
+						reason, PM_UPGRADE);
+		break;
+	case PM_SBS_DOWNGRADE:
+		status = policy_mgr_complete_action(psoc, POLICY_MGR_RX_NSS_1,
+					PM_SBS, reason, session_id);
+		break;
+	case PM_SBS:
+		status = policy_mgr_pdev_set_hw_mode(psoc, session_id,
+						HW_MODE_SS_1x1,
+						HW_MODE_80_MHZ,
+						HW_MODE_SS_1x1, HW_MODE_80_MHZ,
+						HW_MODE_MAC_BAND_NONE,
+						HW_MODE_DBS,
+						HW_MODE_AGILE_DFS_NONE,
+						HW_MODE_SBS,
+						reason, PM_NOP);
+		break;
+	case PM_DOWNGRADE:
+		/*
+		 * check if we have a beaconing entity that advertised 2x2
+		 * intially. If yes, update the beacon template & notify FW.
+		 */
+		status = policy_mgr_nss_update(psoc, POLICY_MGR_RX_NSS_1,
+					PM_NOP, POLICY_MGR_ANY, reason,
+					session_id);
+		break;
+	case PM_UPGRADE:
+		/*
+		 * check if we have a beaconing entity that advertised 2x2
+		 * intially. If yes, update the beacon template & notify FW.
+		 */
+		status = policy_mgr_nss_update(psoc, POLICY_MGR_RX_NSS_2,
+					PM_NOP, POLICY_MGR_ANY, reason,
+					session_id);
+		break;
+	case PM_DBS1_DOWNGRADE:
+		status = policy_mgr_complete_action(psoc, POLICY_MGR_RX_NSS_1,
+						    PM_DBS1, reason,
+						    session_id);
+		break;
+	case PM_DBS2_DOWNGRADE:
+		status = policy_mgr_complete_action(psoc, POLICY_MGR_RX_NSS_1,
+						    PM_DBS2, reason,
+						    session_id);
+		break;
+	case PM_DBS1:
+		/*
+		 * PM_DBS1 (2x2 5G + 1x1 2G) will support 5G 2x2. If previous
+		 * mode is DBS, that should be 2x2 2G + 1x1 5G mode and
+		 * the 5G band was downgraded to 1x1. So, we need to
+		 * upgrade 5G vdevs after hw mode change.
+		 */
+		if (hw_mode.dbs_cap)
+			next_action = PM_UPGRADE_5G;
+		else
+			next_action = PM_NOP;
+		status = policy_mgr_pdev_set_hw_mode(
+					psoc, session_id,
+					HW_MODE_SS_2x2,
+					HW_MODE_80_MHZ,
+					HW_MODE_SS_1x1, HW_MODE_40_MHZ,
+					HW_MODE_MAC_BAND_5G,
+					HW_MODE_DBS,
+					HW_MODE_AGILE_DFS_NONE,
+					HW_MODE_SBS_NONE,
+					reason, next_action);
+		break;
+	case PM_DBS2:
+		/*
+		 * PM_DBS2 (2x2 2G + 1x1 5G) will support 2G 2x2. If previous
+		 * mode is DBS, that should be 2x2 5G + 1x1 2G mode and
+		 * the 2G band was downgraded to 1x1. So, we need to
+		 * upgrade 5G vdevs after hw mode change.
+		 */
+		if (hw_mode.dbs_cap)
+			next_action = PM_UPGRADE_2G;
+		else
+			next_action = PM_NOP;
+		status = policy_mgr_pdev_set_hw_mode(
+						psoc, session_id,
+						HW_MODE_SS_2x2,
+						HW_MODE_40_MHZ,
+						HW_MODE_SS_1x1, HW_MODE_40_MHZ,
+						HW_MODE_MAC_BAND_2G,
+						HW_MODE_DBS,
+						HW_MODE_AGILE_DFS_NONE,
+						HW_MODE_SBS_NONE,
+						reason, next_action);
+		break;
+	case PM_UPGRADE_5G:
+		status = policy_mgr_nss_update(
+					psoc, POLICY_MGR_RX_NSS_2,
+					PM_NOP, POLICY_MGR_BAND_5, reason,
+					session_id);
+		break;
+	case PM_UPGRADE_2G:
+		status = policy_mgr_nss_update(
+					psoc, POLICY_MGR_RX_NSS_2,
+					PM_NOP, POLICY_MGR_BAND_24, reason,
+					session_id);
+		break;
+	default:
+		policy_mgr_err("unexpected action value %d", action);
+		status = QDF_STATUS_E_FAILURE;
+		break;
+	}
+
+	return status;
+}
+
+QDF_STATUS policy_mgr_handle_conc_multiport(struct wlan_objmgr_psoc *psoc,
+		uint8_t session_id, uint8_t channel)
+{
+	QDF_STATUS status;
+
+	if (!policy_mgr_check_for_session_conc(psoc, session_id, channel)) {
+		policy_mgr_err("Conc not allowed for the session %d",
+			session_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = policy_mgr_reset_connection_update(psoc);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		policy_mgr_err("clearing event failed");
+
+	status = policy_mgr_current_connections_update(psoc, session_id,
+			channel,
+			POLICY_MGR_UPDATE_REASON_NORMAL_STA);
+	if (QDF_STATUS_E_FAILURE == status) {
+		policy_mgr_err("connections update failed");
+		return status;
+	}
+
+	return status;
+}
+
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+void policy_mgr_update_user_config_sap_chan(
+			struct wlan_objmgr_psoc *psoc, uint32_t channel)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid pm context and failed to update the user config sap channel");
+		return;
+	}
+	pm_ctx->user_config_sap_channel = channel;
+}
+
+/**
+ * policy_mgr_is_restart_sap_allowed() - Check if restart SAP
+ * allowed during SCC -> MCC switch
+ * @psoc: PSOC object data
+ * @mcc_to_scc_switch: MCC to SCC switch enabled user config
+ *
+ * Check if restart SAP allowed during SCC->MCC switch
+ *
+ * Restart: true or false
+ */
+static bool policy_mgr_is_restart_sap_allowed(
+	struct wlan_objmgr_psoc *psoc,
+	uint32_t mcc_to_scc_switch)
+{
+	uint32_t sta_ap_bit_mask = QDF_STA_MASK | QDF_SAP_MASK;
+	uint32_t sta_go_bit_mask = QDF_STA_MASK | QDF_P2P_GO_MASK;
+
+	if ((mcc_to_scc_switch == QDF_MCC_TO_SCC_SWITCH_DISABLE) ||
+		!policy_mgr_concurrent_open_sessions_running(psoc) ||
+		!(((policy_mgr_get_concurrency_mode(psoc) & sta_ap_bit_mask)
+			== sta_ap_bit_mask) ||
+		((mcc_to_scc_switch ==
+		QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION) &&
+		((policy_mgr_get_concurrency_mode(psoc) & sta_go_bit_mask)
+			== sta_go_bit_mask)))) {
+		policy_mgr_debug("MCC switch disabled or not concurrent STA/SAP, STA/GO");
+		return false;
+	}
+
+	return true;
+}
+
+bool policy_mgr_is_safe_channel(struct wlan_objmgr_psoc *psoc,
+		uint8_t channel)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool is_safe = true;
+	uint8_t j;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return is_safe;
+	}
+
+
+	if (pm_ctx->unsafe_channel_count == 0) {
+		policy_mgr_debug("There are no unsafe channels");
+		return is_safe;
+	}
+
+	for (j = 0; j < pm_ctx->unsafe_channel_count; j++) {
+		if (channel == pm_ctx->unsafe_channel_list[j]) {
+			is_safe = false;
+			policy_mgr_warn("CH %d is not safe", channel);
+			break;
+		}
+	}
+
+	return is_safe;
+}
+
+bool policy_mgr_is_sap_restart_required_after_sta_disconnect(
+			struct wlan_objmgr_psoc *psoc, uint8_t *intf_ch)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint8_t sap_chan = policy_mgr_mode_specific_get_channel(psoc,
+								PM_SAP_MODE);
+	bool sta_sap_scc_on_dfs_chan =
+		policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc);
+
+	*intf_ch = 0;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid pm context");
+		return false;
+	}
+
+	policy_mgr_debug("sta_sap_scc_on_dfs_chan %u, sap_chan %u",
+			 sta_sap_scc_on_dfs_chan, sap_chan);
+
+	if ((!sta_sap_scc_on_dfs_chan ||
+	     !(sap_chan && WLAN_REG_IS_5GHZ_CH(sap_chan) &&
+	       (wlan_reg_get_channel_state(pm_ctx->pdev, sap_chan) ==
+			CHANNEL_STATE_DFS))) &&
+	    (!policy_mgr_sta_sap_scc_on_lte_coex_chan(psoc) ||
+	      policy_mgr_is_safe_channel(psoc, sap_chan))) {
+		return false;
+	}
+
+	*intf_ch = pm_ctx->user_config_sap_channel;
+	policy_mgr_debug("Standalone SAP is not allowed on DFS channel, Move it to channel %u",
+			 *intf_ch);
+
+	return true;
+}
+
+static void __policy_mgr_check_sta_ap_concurrent_ch_intf(void *data)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct policy_mgr_psoc_priv_obj *pm_ctx = NULL;
+	struct sta_ap_intf_check_work_ctx *work_info = NULL;
+	uint32_t mcc_to_scc_switch, cc_count = 0, i;
+	QDF_STATUS status;
+	uint8_t channel, sec_ch;
+	uint8_t operating_channel[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint8_t vdev_id[MAX_NUMBER_OF_CONC_CONNECTIONS];
+
+	if (qdf_is_module_state_transitioning()) {
+		policy_mgr_err("Module transition in progress");
+		goto end;
+	}
+
+	work_info = (struct sta_ap_intf_check_work_ctx *) data;
+	if (!work_info) {
+		policy_mgr_err("Invalid work_info");
+		goto end;
+	}
+
+	psoc = work_info->psoc;
+	if (!psoc) {
+		policy_mgr_err("Invalid psoc");
+		goto end;
+	}
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		goto end;
+	}
+	mcc_to_scc_switch =
+		policy_mgr_get_mcc_to_scc_switch_mode(psoc);
+
+	policy_mgr_info("Concurrent open sessions running: %d",
+		policy_mgr_concurrent_open_sessions_running(psoc));
+
+	if (!policy_mgr_is_restart_sap_allowed(psoc, mcc_to_scc_switch))
+		goto end;
+
+	cc_count = policy_mgr_get_mode_specific_conn_info(psoc,
+					&operating_channel[cc_count],
+					&vdev_id[cc_count],
+					PM_SAP_MODE);
+	policy_mgr_debug("Number of concurrent SAP: %d", cc_count);
+	if (cc_count < MAX_NUMBER_OF_CONC_CONNECTIONS)
+		cc_count = cc_count +
+				policy_mgr_get_mode_specific_conn_info
+					(psoc,
+					&operating_channel[cc_count],
+					&vdev_id[cc_count],
+					PM_P2P_GO_MODE);
+	policy_mgr_debug("Number of beaconing entities (SAP + GO):%d",
+							cc_count);
+	if (!cc_count) {
+		policy_mgr_err("Could not retrieve SAP/GO operating channel&vdevid");
+		goto end;
+	}
+
+	policy_mgr_debug("wait if channel switch is already in progress");
+	status = qdf_wait_single_event(
+				&pm_ctx->channel_switch_complete_evt,
+				CHANNEL_SWITCH_COMPLETE_TIMEOUT);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("wait for event failed, still continue with channel switch");
+	}
+	if (!pm_ctx->hdd_cbacks.wlan_hdd_get_channel_for_sap_restart) {
+		policy_mgr_err("SAP restart get channel callback in NULL");
+		goto end;
+	}
+	if (cc_count < MAX_NUMBER_OF_CONC_CONNECTIONS)
+		for (i = 0; i < cc_count; i++) {
+			status = pm_ctx->hdd_cbacks.
+				wlan_hdd_get_channel_for_sap_restart
+					(psoc,
+					vdev_id[i], &channel, &sec_ch);
+			if (status == QDF_STATUS_SUCCESS) {
+				policy_mgr_info("SAP restarts due to MCC->SCC switch, old chan :%d new chan: %d"
+					, operating_channel[i], channel);
+				break;
+			}
+		}
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to switch SAP channel");
+end:
+	if (work_info) {
+		qdf_mem_free(work_info);
+		if (pm_ctx)
+			pm_ctx->sta_ap_intf_check_work_info = NULL;
+	}
+}
+
+void policy_mgr_check_sta_ap_concurrent_ch_intf(void *data)
+{
+	qdf_ssr_protect(__func__);
+	__policy_mgr_check_sta_ap_concurrent_ch_intf(data);
+	qdf_ssr_unprotect(__func__);
+}
+
+static bool policy_mgr_valid_sta_channel_check(struct wlan_objmgr_psoc *psoc,
+		uint8_t sta_channel)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return false;
+	}
+
+	if ((wlan_reg_is_dfs_ch(pm_ctx->pdev, sta_channel) &&
+		(!policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc))) ||
+		wlan_reg_is_passive_or_disable_ch(pm_ctx->pdev, sta_channel) ||
+		!policy_mgr_is_safe_channel(psoc, sta_channel)) {
+		if (policy_mgr_is_hw_dbs_capable(psoc))
+			return true;
+		else
+			return false;
+	}
+	else
+		return true;
+}
+
+QDF_STATUS policy_mgr_valid_sap_conc_channel_check(
+	struct wlan_objmgr_psoc *psoc, uint8_t *con_ch, uint8_t sap_ch)
+{
+	uint8_t channel = *con_ch;
+	uint8_t temp_channel = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool sta_sap_scc_on_dfs_chan;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/*
+	 * if force SCC is set, Check if conc channel is DFS
+	 * or passive or part of LTE avoided channel list.
+	 * In that case move SAP to other band if DBS is supported,
+	 * return otherwise
+	 */
+	if (!policy_mgr_is_force_scc(psoc))
+		return QDF_STATUS_SUCCESS;
+
+	/*
+	 * if interference is 0, check if it is DBS case. If DBS case
+	 * return from here. If SCC, check further if SAP can move to
+	 * STA's channel.
+	 */
+	if (!channel &&
+		(sap_ch != policy_mgr_mode_specific_get_channel(
+			psoc, PM_STA_MODE)))
+		return QDF_STATUS_SUCCESS;
+	else if (!channel)
+		channel = sap_ch;
+
+	sta_sap_scc_on_dfs_chan =
+		policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc);
+
+	if (policy_mgr_valid_sta_channel_check(psoc, channel)) {
+		if (wlan_reg_is_dfs_ch(pm_ctx->pdev, channel) ||
+		    wlan_reg_is_passive_or_disable_ch(pm_ctx->pdev, channel) ||
+		    !(policy_mgr_sta_sap_scc_on_lte_coex_chan(psoc) ||
+		      policy_mgr_is_safe_channel(psoc, channel)) ||
+		    (!reg_is_etsi13_srd_chan_allowed_master_mode(pm_ctx->pdev)
+		    && reg_is_etsi13_srd_chan(pm_ctx->pdev, channel))) {
+			if (wlan_reg_is_dfs_ch(pm_ctx->pdev, channel) &&
+			    sta_sap_scc_on_dfs_chan) {
+				policy_mgr_debug("STA SAP SCC is allowed on DFS channel");
+				goto update_chan;
+			}
+
+			if (policy_mgr_is_hw_dbs_capable(psoc)) {
+				temp_channel =
+				policy_mgr_get_alternate_channel_for_sap(psoc);
+				policy_mgr_debug("temp_channel is %d",
+					temp_channel);
+				if (temp_channel) {
+					channel = temp_channel;
+				} else {
+					if (WLAN_REG_IS_5GHZ_CH(channel))
+						channel = PM_24_GHZ_CHANNEL_6;
+					else
+						channel = PM_5_GHZ_CHANNEL_36;
+				}
+				if (!policy_mgr_is_safe_channel(
+					psoc, channel)) {
+					policy_mgr_warn(
+						"Can't have concurrency on %d as it is not safe",
+						channel);
+					return QDF_STATUS_E_FAILURE;
+				}
+			} else {
+				policy_mgr_warn("Can't have concurrency on %d",
+					channel);
+				return QDF_STATUS_E_FAILURE;
+			}
+		}
+	}
+
+update_chan:
+	if (channel != sap_ch)
+		*con_ch = channel;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * policy_mgr_check_concurrent_intf_and_restart_sap() - Check
+ * concurrent change intf
+ * @psoc: PSOC object information
+ * @operation_channel: operation channel
+ * @vdev_id: vdev id of SAP
+ *
+ * Checks the concurrent change interface and restarts SAP
+ *
+ * Return: None
+ */
+void policy_mgr_check_concurrent_intf_and_restart_sap(
+		struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t mcc_to_scc_switch;
+	uint8_t operating_channel[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
+	uint8_t vdev_id[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0};
+	uint32_t cc_count = 0;
+	bool restart_sap = false;
+	uint8_t sap_ch;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return;
+	}
+	if (policy_mgr_get_connection_count(psoc) == 1) {
+		/*
+		 * If STA+SAP sessions are on DFS channel and STA+SAP SCC is
+		 * enabled on DFS channel then move the SAP out of DFS channel
+		 * as soon as STA gets disconnect.
+		 * If STA+SAP sessions are on unsafe channel and STA+SAP SCC is
+		 * enabled on unsafe channel then move the SAP to safe channel
+		 * as soon as STA disconnected.
+		 */
+		if (policy_mgr_is_sap_restart_required_after_sta_disconnect(
+							psoc, &sap_ch)) {
+			policy_mgr_debug("move the SAP to configured channel %u",
+					 sap_ch);
+			restart_sap = true;
+			goto sap_restart;
+		}
+	}
+
+	/*
+	 * force SCC with STA+STA+SAP will need some additional logic
+	 */
+	cc_count = policy_mgr_get_mode_specific_conn_info(psoc,
+					&operating_channel[cc_count],
+					&vdev_id[cc_count], PM_STA_MODE);
+	if (!cc_count) {
+		policy_mgr_debug("Could not get STA operating channel&vdevid");
+		return;
+	}
+
+	mcc_to_scc_switch =
+		policy_mgr_get_mcc_to_scc_switch_mode(psoc);
+	policy_mgr_info("MCC to SCC switch: %d chan: %d",
+			mcc_to_scc_switch, operating_channel[0]);
+
+	if (!policy_mgr_is_restart_sap_allowed(psoc, mcc_to_scc_switch)) {
+		policy_mgr_debug(
+			"No action taken at check_concurrent_intf_and_restart_sap");
+		return;
+	}
+
+sap_restart:
+	/*
+	 * If sta_sap_scc_on_dfs_chan is true then standalone SAP is not
+	 * allowed on DFS channel. SAP is allowed on DFS channel only when STA
+	 * is already connected on that channel.
+	 * In following condition restart_sap will be true if
+	 * sta_sap_scc_on_dfs_chan is true and SAP is on DFS channel.
+	 * This scenario can come if STA+SAP are operating on DFS channel and
+	 * STA gets disconnected.
+	 */
+	if (restart_sap ||
+	    ((mcc_to_scc_switch != QDF_MCC_TO_SCC_SWITCH_DISABLE) &&
+	    policy_mgr_valid_sta_channel_check(psoc, operating_channel[0]) &&
+	    !pm_ctx->sta_ap_intf_check_work_info)) {
+		struct sta_ap_intf_check_work_ctx *work_info;
+		work_info = qdf_mem_malloc(
+			sizeof(struct sta_ap_intf_check_work_ctx));
+		pm_ctx->sta_ap_intf_check_work_info = work_info;
+		if (work_info) {
+			work_info->psoc = psoc;
+			qdf_create_work(0, &pm_ctx->sta_ap_intf_check_work,
+				policy_mgr_check_sta_ap_concurrent_ch_intf,
+				work_info);
+			qdf_sched_work(0, &pm_ctx->sta_ap_intf_check_work);
+			policy_mgr_info(
+				"Checking for Concurrent Change interference");
+		}
+	}
+}
+#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH */
+
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+/**
+ * policy_mgr_change_sap_channel_with_csa() - Move SAP channel using (E)CSA
+ * @psoc: PSOC object information
+ * @vdev_id: Vdev id
+ * @channel: Channel to change
+ * @ch_width: channel width to change
+ * @forced: Force to switch channel, ignore SCC/MCC check
+ *
+ * Invoke the callback function to change SAP channel using (E)CSA
+ *
+ * Return: None
+ */
+void policy_mgr_change_sap_channel_with_csa(struct wlan_objmgr_psoc *psoc,
+					    uint8_t vdev_id, uint32_t channel,
+					    uint32_t ch_width,
+					    bool forced)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return;
+	}
+
+	if (pm_ctx->hdd_cbacks.sap_restart_chan_switch_cb) {
+		policy_mgr_info("SAP change change without restart");
+		pm_ctx->hdd_cbacks.sap_restart_chan_switch_cb(psoc,
+				vdev_id, channel, ch_width, forced);
+	}
+}
+#endif
+
+QDF_STATUS policy_mgr_wait_for_connection_update(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *policy_mgr_context;
+
+	policy_mgr_context = policy_mgr_get_context(psoc);
+	if (!policy_mgr_context) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = qdf_wait_single_event(
+			&policy_mgr_context->connection_update_done_evt,
+			CONNECTION_UPDATE_TIMEOUT);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("wait for event failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_reset_connection_update(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *policy_mgr_context;
+
+	policy_mgr_context = policy_mgr_get_context(psoc);
+	if (!policy_mgr_context) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = qdf_event_reset(
+		&policy_mgr_context->connection_update_done_evt);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("clear event failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_set_connection_update(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *policy_mgr_context;
+
+	policy_mgr_context = policy_mgr_get_context(psoc);
+	if (!policy_mgr_context) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = qdf_event_set(&policy_mgr_context->connection_update_done_evt);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("set event failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_set_chan_switch_complete_evt(
+		struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *policy_mgr_context;
+
+	policy_mgr_context = policy_mgr_get_context(psoc);
+
+	if (!policy_mgr_context) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+	status = qdf_event_set(
+			&policy_mgr_context->channel_switch_complete_evt);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("set event failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_reset_chan_switch_complete_evt(
+		struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *policy_mgr_context;
+
+	policy_mgr_context = policy_mgr_get_context(psoc);
+
+	if (!policy_mgr_context) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+	status = qdf_event_reset(
+			&policy_mgr_context->channel_switch_complete_evt);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("reset event failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_set_opportunistic_update(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *policy_mgr_context;
+
+	policy_mgr_context = policy_mgr_get_context(psoc);
+	if (!policy_mgr_context) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = qdf_event_set(
+			&policy_mgr_context->opportunistic_update_done_evt);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("set event failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_stop_opportunistic_timer(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *policy_mgr_ctx;
+
+	policy_mgr_ctx = policy_mgr_get_context(psoc);
+	if (!policy_mgr_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (policy_mgr_ctx->dbs_opportunistic_timer.state !=
+	    QDF_TIMER_STATE_RUNNING)
+		return QDF_STATUS_SUCCESS;
+
+	qdf_mc_timer_stop(&policy_mgr_ctx->dbs_opportunistic_timer);
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_restart_opportunistic_timer(
+		struct wlan_objmgr_psoc *psoc, bool check_state)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct policy_mgr_psoc_priv_obj *policy_mgr_ctx;
+
+	policy_mgr_ctx = policy_mgr_get_context(psoc);
+	if (!policy_mgr_ctx) {
+		policy_mgr_err("Invalid context");
+		return status;
+	}
+
+	if (check_state &&
+			QDF_TIMER_STATE_RUNNING !=
+			policy_mgr_ctx->dbs_opportunistic_timer.state)
+		return status;
+
+	qdf_mc_timer_stop(&policy_mgr_ctx->dbs_opportunistic_timer);
+
+	status = qdf_mc_timer_start(
+			&policy_mgr_ctx->dbs_opportunistic_timer,
+			DBS_OPPORTUNISTIC_TIME * 1000);
+
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("failed to start opportunistic timer");
+		return status;
+	}
+
+	return status;
+}
+
+QDF_STATUS policy_mgr_set_hw_mode_on_channel_switch(
+			struct wlan_objmgr_psoc *psoc, uint8_t session_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE, qdf_status;
+	enum policy_mgr_conc_next_action action;
+
+	if (!policy_mgr_is_hw_dbs_capable(psoc)) {
+		policy_mgr_err("PM/DBS is disabled");
+		return status;
+	}
+
+	action = (*policy_mgr_get_current_pref_hw_mode_ptr)(psoc);
+	if ((action != PM_DBS_DOWNGRADE) &&
+	    (action != PM_SINGLE_MAC_UPGRADE) &&
+	    (action != PM_DBS1_DOWNGRADE) &&
+	    (action != PM_DBS2_DOWNGRADE)) {
+		policy_mgr_err("Invalid action: %d", action);
+		status = QDF_STATUS_SUCCESS;
+		goto done;
+	}
+
+	policy_mgr_debug("action:%d session id:%d", action, session_id);
+
+	/* Opportunistic timer is started, PM will check if MCC upgrade can be
+	 * done on timer expiry. This avoids any possible ping pong effect
+	 * as well.
+	 */
+	if (action == PM_SINGLE_MAC_UPGRADE) {
+		qdf_status = policy_mgr_restart_opportunistic_timer(
+			psoc, false);
+		if (QDF_IS_STATUS_SUCCESS(qdf_status))
+			policy_mgr_debug("opportunistic timer for MCC upgrade");
+		goto done;
+	}
+
+	/* For DBS, we want to move right away to DBS mode */
+	status = policy_mgr_next_actions(psoc, session_id, action,
+			POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("no set hw mode command was issued");
+		goto done;
+	}
+done:
+	/* success must be returned only when a set hw mode was done */
+	return status;
+}
+
+void policy_mgr_checkn_update_hw_mode_single_mac_mode(
+		struct wlan_objmgr_psoc *psoc, uint8_t channel)
+{
+	uint8_t i;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	if (QDF_TIMER_STATE_RUNNING ==
+		pm_ctx->dbs_opportunistic_timer.state)
+		qdf_mc_timer_stop(&pm_ctx->dbs_opportunistic_timer);
+
+	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) {
+			if (!WLAN_REG_IS_SAME_BAND_CHANNELS(channel,
+				pm_conc_connection_list[i].chan)) {
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				policy_mgr_debug("DBS required");
+				return;
+			}
+			if (policy_mgr_is_hw_dbs_2x2_capable(psoc) &&
+			    (WLAN_REG_IS_24GHZ_CH(channel) ||
+			    WLAN_REG_IS_24GHZ_CH
+				(pm_conc_connection_list[i].chan))) {
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				policy_mgr_debug("DBS required");
+				return;
+			}
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	pm_dbs_opportunistic_timer_handler((void *)psoc);
+}
+
+void policy_mgr_check_and_stop_opportunistic_timer(
+	struct wlan_objmgr_psoc *psoc, uint8_t id)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	enum policy_mgr_conc_next_action action = PM_NOP;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	enum policy_mgr_conn_update_reason reason;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+	if (QDF_TIMER_STATE_RUNNING ==
+		pm_ctx->dbs_opportunistic_timer.state) {
+		qdf_mc_timer_stop(&pm_ctx->dbs_opportunistic_timer);
+		action = policy_mgr_need_opportunistic_upgrade(psoc, &reason);
+		if (action) {
+			qdf_event_reset(&pm_ctx->opportunistic_update_done_evt);
+			status = policy_mgr_next_actions(psoc, id, action,
+							 reason);
+			if (status != QDF_STATUS_SUCCESS) {
+				policy_mgr_err("Failed in policy_mgr_next_actions");
+				return;
+			}
+			status = qdf_wait_single_event(
+					&pm_ctx->opportunistic_update_done_evt,
+					CONNECTION_UPDATE_TIMEOUT);
+
+			if (!QDF_IS_STATUS_SUCCESS(status)) {
+				policy_mgr_err("wait for event failed");
+				return;
+			}
+		}
+	}
+}
+
+void policy_mgr_set_hw_mode_change_in_progress(
+	struct wlan_objmgr_psoc *psoc, enum policy_mgr_hw_mode_change value)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	pm_ctx->hw_mode_change_in_progress = value;
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	policy_mgr_debug("hw_mode_change_in_progress:%d", value);
+}
+
+enum policy_mgr_hw_mode_change policy_mgr_is_hw_mode_change_in_progress(
+	struct wlan_objmgr_psoc *psoc)
+{
+	enum policy_mgr_hw_mode_change value;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	value = POLICY_MGR_HW_MODE_NOT_IN_PROGRESS;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return value;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	value = pm_ctx->hw_mode_change_in_progress;
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return value;
+}
+
+enum policy_mgr_hw_mode_change policy_mgr_get_hw_mode_change_from_hw_mode_index(
+	struct wlan_objmgr_psoc *psoc, uint32_t hw_mode_index)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	struct policy_mgr_hw_mode_params hw_mode;
+	enum policy_mgr_hw_mode_change value
+		= POLICY_MGR_HW_MODE_NOT_IN_PROGRESS;
+	QDF_STATUS status;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return value;
+	}
+
+	status = policy_mgr_get_hw_mode_from_idx(psoc, hw_mode_index, &hw_mode);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to get HW mode index");
+		return value;
+	}
+
+	if (hw_mode.dbs_cap) {
+		policy_mgr_info("DBS is requested with HW (%d)",
+		hw_mode_index);
+		value = POLICY_MGR_DBS_IN_PROGRESS;
+		goto ret_value;
+	}
+
+	if (hw_mode.sbs_cap) {
+		policy_mgr_info("SBS is requested with HW (%d)",
+		hw_mode_index);
+		value = POLICY_MGR_SBS_IN_PROGRESS;
+		goto ret_value;
+	}
+
+	value = POLICY_MGR_SMM_IN_PROGRESS;
+	policy_mgr_info("SMM is requested with HW (%d)", hw_mode_index);
+
+ret_value:
+	return value;
+}
+
+#ifdef MPC_UT_FRAMEWORK
+QDF_STATUS policy_mgr_update_connection_info_utfw(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams,
+		uint32_t chain_mask, uint32_t type, uint32_t sub_type,
+		uint32_t channelid, uint32_t mac_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint32_t conn_index = 0, found = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+		if (vdev_id == pm_conc_connection_list[conn_index].vdev_id) {
+			/* debug msg */
+			found = 1;
+			break;
+		}
+		conn_index++;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	if (!found) {
+		/* err msg */
+		policy_mgr_err("can't find vdev_id %d in pm_conc_connection_list",
+			vdev_id);
+		return status;
+	}
+	policy_mgr_debug("--> updating entry at index[%d]", conn_index);
+
+	policy_mgr_update_conc_list(psoc, conn_index,
+			policy_mgr_get_mode(type, sub_type),
+			channelid, HW_MODE_20_MHZ,
+			mac_id, chain_mask, 0, vdev_id, true, true);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_incr_connection_count_utfw(struct wlan_objmgr_psoc *psoc,
+		uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams,
+		uint32_t chain_mask, uint32_t type, uint32_t sub_type,
+		uint32_t channelid, uint32_t mac_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint32_t conn_index = 0;
+	bool update_conn = true;
+	enum policy_mgr_con_mode mode;
+
+	conn_index = policy_mgr_get_connection_count(psoc);
+	if (MAX_NUMBER_OF_CONC_CONNECTIONS <= conn_index) {
+		/* err msg */
+		policy_mgr_err("exceeded max connection limit %d",
+			MAX_NUMBER_OF_CONC_CONNECTIONS);
+		return status;
+	}
+	policy_mgr_debug("--> filling entry at index[%d]", conn_index);
+
+	mode = policy_mgr_get_mode(type, sub_type);
+	if (mode == PM_STA_MODE || mode == PM_P2P_CLIENT_MODE)
+		update_conn = false;
+
+	policy_mgr_update_conc_list(psoc, conn_index,
+				mode,
+				channelid, HW_MODE_20_MHZ,
+				mac_id, chain_mask, 0, vdev_id, true,
+				update_conn);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_decr_connection_count_utfw(struct wlan_objmgr_psoc *psoc,
+		uint32_t del_all, uint32_t vdev_id)
+{
+	QDF_STATUS status;
+
+	if (del_all) {
+		status = policy_mgr_psoc_disable(psoc);
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			policy_mgr_err("Policy manager initialization failed");
+			return QDF_STATUS_E_FAILURE;
+		}
+		status = policy_mgr_psoc_enable(psoc);
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			policy_mgr_err("Policy manager initialization failed");
+			return QDF_STATUS_E_FAILURE;
+		}
+	} else {
+		policy_mgr_decr_connection_count(psoc, vdev_id);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+enum policy_mgr_pcl_type policy_mgr_get_pcl_from_first_conn_table(
+		enum policy_mgr_con_mode type,
+		enum policy_mgr_conc_priority_mode sys_pref)
+{
+	if ((sys_pref >= PM_MAX_CONC_PRIORITY_MODE) ||
+		(type >= PM_MAX_NUM_OF_MODE))
+		return PM_MAX_PCL_TYPE;
+	return first_connection_pcl_table[type][sys_pref];
+}
+
+enum policy_mgr_pcl_type policy_mgr_get_pcl_from_second_conn_table(
+	enum policy_mgr_one_connection_mode idx, enum policy_mgr_con_mode type,
+	enum policy_mgr_conc_priority_mode sys_pref, uint8_t dbs_capable)
+{
+	if ((idx >= PM_MAX_ONE_CONNECTION_MODE) ||
+		(sys_pref >= PM_MAX_CONC_PRIORITY_MODE) ||
+		(type >= PM_MAX_NUM_OF_MODE))
+		return PM_MAX_PCL_TYPE;
+	if (dbs_capable)
+		return (*second_connection_pcl_dbs_table)[idx][type][sys_pref];
+	else
+		return second_connection_pcl_nodbs_table[idx][type][sys_pref];
+}
+
+enum policy_mgr_pcl_type policy_mgr_get_pcl_from_third_conn_table(
+	enum policy_mgr_two_connection_mode idx, enum policy_mgr_con_mode type,
+	enum policy_mgr_conc_priority_mode sys_pref, uint8_t dbs_capable)
+{
+	if ((idx >= PM_MAX_TWO_CONNECTION_MODE) ||
+		(sys_pref >= PM_MAX_CONC_PRIORITY_MODE) ||
+		(type >= PM_MAX_NUM_OF_MODE))
+		return PM_MAX_PCL_TYPE;
+	if (dbs_capable)
+		return (*third_connection_pcl_dbs_table)[idx][type][sys_pref];
+	else
+		return third_connection_pcl_nodbs_table[idx][type][sys_pref];
+}
+#endif

+ 3135 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c

@@ -0,0 +1,3135 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_policy_mgr_core.c
+ *
+ * WLAN Concurrenct Connection Management functions
+ *
+ */
+
+/* Include files */
+
+#include "wlan_policy_mgr_i.h"
+#include "qdf_types.h"
+#include "qdf_trace.h"
+#include "wlan_objmgr_global_obj.h"
+
+#define POLICY_MGR_MAX_CON_STRING_LEN   100
+
+struct policy_mgr_conc_connection_info
+	pm_conc_connection_list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+
+struct policy_mgr_psoc_priv_obj *policy_mgr_get_context(
+		struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	pm_ctx = (struct policy_mgr_psoc_priv_obj *)
+			wlan_objmgr_psoc_get_comp_private_obj(psoc,
+				WLAN_UMAC_COMP_POLICY_MGR);
+	return pm_ctx;
+}
+
+/**
+ * policy_mgr_get_updated_scan_config() - Get the updated scan configuration
+ * @scan_config: Pointer containing the updated scan config
+ * @dbs_scan: 0 or 1 indicating if DBS scan needs to be enabled/disabled
+ * @dbs_plus_agile_scan: 0 or 1 indicating if DBS plus agile scan needs to be
+ * enabled/disabled
+ * @single_mac_scan_with_dfs: 0 or 1 indicating if single MAC scan with DFS
+ * needs to be enabled/disabled
+ *
+ * Takes the current scan configuration and set the necessary scan config
+ * bits to either 0/1 and provides the updated value to the caller who
+ * can use this to pass it on to the FW
+ *
+ * Return: 0 on success
+ */
+QDF_STATUS policy_mgr_get_updated_scan_config(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t *scan_config,
+		bool dbs_scan,
+		bool dbs_plus_agile_scan,
+		bool single_mac_scan_with_dfs)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*scan_config = pm_ctx->dual_mac_cfg.cur_scan_config;
+
+	WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(*scan_config, dbs_scan);
+	WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(*scan_config,
+			dbs_plus_agile_scan);
+	WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(*scan_config,
+			single_mac_scan_with_dfs);
+
+	policy_mgr_debug("scan_config:%x ", *scan_config);
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * policy_mgr_get_updated_fw_mode_config() - Get the updated fw
+ * mode configuration
+ * @fw_mode_config: Pointer containing the updated fw mode config
+ * @dbs: 0 or 1 indicating if DBS needs to be enabled/disabled
+ * @agile_dfs: 0 or 1 indicating if agile DFS needs to be enabled/disabled
+ *
+ * Takes the current fw mode configuration and set the necessary fw mode config
+ * bits to either 0/1 and provides the updated value to the caller who
+ * can use this to pass it on to the FW
+ *
+ * Return: 0 on success
+ */
+QDF_STATUS policy_mgr_get_updated_fw_mode_config(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t *fw_mode_config,
+		bool dbs,
+		bool agile_dfs)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config;
+
+	WMI_DBS_FW_MODE_CFG_DBS_SET(*fw_mode_config, dbs);
+	WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(*fw_mode_config, agile_dfs);
+
+	policy_mgr_debug("fw_mode_config:%x ", *fw_mode_config);
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * policy_mgr_is_dual_mac_disabled_in_ini() - Check if dual mac
+ * is disabled in INI
+ *
+ * Checks if the dual mac feature is disabled in INI
+ *
+ * Return: true if the dual mac connection is disabled from INI
+ */
+bool policy_mgr_is_dual_mac_disabled_in_ini(
+		struct wlan_objmgr_psoc *psoc)
+{
+	bool is_disabled = false;
+	enum dbs_support dbs_type = wlan_objmgr_psoc_get_dual_mac_disable(psoc);
+
+	/*
+	 * If DBS support for connection is disabled through INI then assume
+	 * that DBS is not supported, so that policy manager takes
+	 * the decision considering non-dbs cases only.
+	 *
+	 * For DBS scan check the INI value explicitly
+	 */
+	switch (dbs_type) {
+	case DISABLE_DBS_CXN_AND_SCAN:
+	case DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN:
+	case DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN_WITH_ASYNC_SCAN_OFF:
+		is_disabled = true;
+		break;
+	default:
+		break;
+	}
+
+	return is_disabled;
+}
+
+uint32_t policy_mgr_get_mcc_to_scc_switch_mode(
+	struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return 0;
+	}
+
+	return pm_ctx->cfg.mcc_to_scc_switch;
+}
+
+/**
+ * policy_mgr_get_dbs_config() - Get DBS bit
+ *
+ * Gets the DBS bit of fw_mode_config_bits
+ *
+ * Return: 0 or 1 to indicate the DBS bit
+ */
+bool policy_mgr_get_dbs_config(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t fw_mode_config;
+
+	if (policy_mgr_is_dual_mac_disabled_in_ini(psoc))
+		return false;
+
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		/* We take that it is disabled and proceed */
+		return false;
+	}
+	fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config;
+
+	return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config);
+}
+
+/**
+ * policy_mgr_get_agile_dfs_config() - Get Agile DFS bit
+ *
+ * Gets the Agile DFS bit of fw_mode_config_bits
+ *
+ * Return: 0 or 1 to indicate the Agile DFS bit
+ */
+bool policy_mgr_get_agile_dfs_config(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t fw_mode_config;
+
+	if (policy_mgr_is_dual_mac_disabled_in_ini(psoc))
+		return false;
+
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		/* We take that it is disabled and proceed */
+		return false;
+	}
+	fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config;
+
+	return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config);
+}
+
+/**
+ * policy_mgr_get_dbs_scan_config() - Get DBS scan bit
+ *
+ * Gets the DBS scan bit of concurrent_scan_config_bits
+ *
+ * Return: 0 or 1 to indicate the DBS scan bit
+ */
+bool policy_mgr_get_dbs_scan_config(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t scan_config;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	if (policy_mgr_is_dual_mac_disabled_in_ini(psoc))
+		return false;
+
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		/* We take that it is disabled and proceed */
+		return false;
+	}
+	scan_config = pm_ctx->dual_mac_cfg.cur_scan_config;
+
+	return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config);
+}
+
+/**
+ * policy_mgr_get_tx_rx_ss_from_config() - Get Tx/Rx spatial
+ * stream from HW mode config
+ * @mac_ss: Config which indicates the HW mode as per 'hw_mode_ss_config'
+ * @tx_ss: Contains the Tx spatial stream
+ * @rx_ss: Contains the Rx spatial stream
+ *
+ * Returns the number of spatial streams of Tx and Rx
+ *
+ * Return: None
+ */
+void policy_mgr_get_tx_rx_ss_from_config(enum hw_mode_ss_config mac_ss,
+		uint32_t *tx_ss, uint32_t *rx_ss)
+{
+	switch (mac_ss) {
+	case HW_MODE_SS_0x0:
+		*tx_ss = 0;
+		*rx_ss = 0;
+		break;
+	case HW_MODE_SS_1x1:
+		*tx_ss = 1;
+		*rx_ss = 1;
+		break;
+	case HW_MODE_SS_2x2:
+		*tx_ss = 2;
+		*rx_ss = 2;
+		break;
+	case HW_MODE_SS_3x3:
+		*tx_ss = 3;
+		*rx_ss = 3;
+		break;
+	case HW_MODE_SS_4x4:
+		*tx_ss = 4;
+		*rx_ss = 4;
+		break;
+	default:
+		*tx_ss = 0;
+		*rx_ss = 0;
+	}
+}
+
+/**
+ * policy_mgr_get_matching_hw_mode_index() - Get matching HW mode index
+ * @psoc: psoc handle
+ * @mac0_tx_ss: Number of tx spatial streams of MAC0
+ * @mac0_rx_ss: Number of rx spatial streams of MAC0
+ * @mac0_bw: Bandwidth of MAC0 of type 'hw_mode_bandwidth'
+ * @mac1_tx_ss: Number of tx spatial streams of MAC1
+ * @mac1_rx_ss: Number of rx spatial streams of MAC1
+ * @mac1_bw: Bandwidth of MAC1 of type 'hw_mode_bandwidth'
+ * @mac0_band_cap: mac0 band capability requirement
+ *     (0: Don't care, 1: 2.4G, 2: 5G)
+ * @dbs: DBS capability of type 'hw_mode_dbs_capab'
+ * @dfs: Agile DFS capability of type 'hw_mode_agile_dfs_capab'
+ * @sbs: SBS capability of type 'hw_mode_sbs_capab'
+ *
+ * Fetches the HW mode index corresponding to the HW mode provided.
+ * In Genoa two DBS HW modes (2x2 5G + 1x1 2G, 2x2 2G + 1x1 5G),
+ * the "ss" number and "bw" value are not enough to specify the expected
+ * HW mode. But in both HW mode, the mac0 can support either 5G or 2G.
+ * So, the Parameter "mac0_band_cap" will specify the expected band support
+ * requirement on mac 0 to find the expected HW mode.
+ *
+ * Return: Positive hw mode index in case a match is found or a negative
+ * value, otherwise
+ */
+int8_t policy_mgr_get_matching_hw_mode_index(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t mac0_tx_ss, uint32_t mac0_rx_ss,
+		enum hw_mode_bandwidth mac0_bw,
+		uint32_t mac1_tx_ss, uint32_t mac1_rx_ss,
+		enum hw_mode_bandwidth mac1_bw,
+		enum hw_mode_mac_band_cap mac0_band_cap,
+		enum hw_mode_dbs_capab dbs,
+		enum hw_mode_agile_dfs_capab dfs,
+		enum hw_mode_sbs_capab sbs)
+{
+	uint32_t i;
+	uint32_t t_mac0_tx_ss, t_mac0_rx_ss, t_mac0_bw;
+	uint32_t t_mac1_tx_ss, t_mac1_rx_ss, t_mac1_bw;
+	uint32_t dbs_mode, agile_dfs_mode, sbs_mode;
+	uint32_t t_mac0_band_cap;
+	int8_t found = -EINVAL;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return found;
+	}
+
+	for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) {
+		t_mac0_tx_ss = POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		if (t_mac0_tx_ss < mac0_tx_ss)
+			continue;
+
+		t_mac0_rx_ss = POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		if (t_mac0_rx_ss < mac0_rx_ss)
+			continue;
+
+		t_mac0_bw = POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		/*
+		 * Firmware advertises max bw capability as CBW 80+80
+		 * for single MAC. Thus CBW 20/40/80 should also be
+		 * supported, if CBW 80+80 is supported.
+		 */
+		if (t_mac0_bw < mac0_bw)
+			continue;
+
+		t_mac1_tx_ss = POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		if (t_mac1_tx_ss < mac1_tx_ss)
+			continue;
+
+		t_mac1_rx_ss = POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		if (t_mac1_rx_ss < mac1_rx_ss)
+			continue;
+
+		t_mac1_bw = POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		if (t_mac1_bw < mac1_bw)
+			continue;
+
+		dbs_mode = POLICY_MGR_HW_MODE_DBS_MODE_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		if (dbs_mode != dbs)
+			continue;
+
+		agile_dfs_mode = POLICY_MGR_HW_MODE_AGILE_DFS_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		if (agile_dfs_mode != dfs)
+			continue;
+
+		sbs_mode = POLICY_MGR_HW_MODE_SBS_MODE_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		if (sbs_mode != sbs)
+			continue;
+
+		t_mac0_band_cap = POLICY_MGR_HW_MODE_MAC0_BAND_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		if (mac0_band_cap && t_mac0_band_cap != mac0_band_cap)
+			continue;
+
+		found = POLICY_MGR_HW_MODE_ID_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+
+		policy_mgr_debug("hw_mode id %d found at %d", found, i);
+
+		break;
+	}
+	return found;
+}
+
+/**
+ * policy_mgr_get_hw_mode_from_dbs_hw_list() - Get hw_mode index
+ * @mac0_ss: MAC0 spatial stream configuration
+ * @mac0_bw: MAC0 bandwidth configuration
+ * @mac1_ss: MAC1 spatial stream configuration
+ * @mac1_bw: MAC1 bandwidth configuration
+ * @mac0_band_cap: mac0 band capability requirement
+ *     (0: Don't care, 1: 2.4G, 2: 5G)
+ * @dbs: HW DBS capability
+ * @dfs: HW Agile DFS capability
+ * @sbs: HW SBS capability
+ *
+ * Get the HW mode index corresponding to the HW modes spatial stream,
+ * bandwidth, DBS, Agile DFS and SBS capability
+ *
+ * In Genoa two DBS HW modes (2x2 5G + 1x1 2G, 2x2 2G + 1x1 5G),
+ * the "ss" number and "bw" value are not enough to specify the expected
+ * HW mode. But in both HW mode, the mac0 can support either 5G or 2G.
+ * So, the Parameter "mac0_band_cap" will specify the expected band support
+ * requirement on mac 0 to find the expected HW mode.
+ *
+ * Return: Index number if a match is found or -negative value if not found
+ */
+int8_t policy_mgr_get_hw_mode_idx_from_dbs_hw_list(
+		struct wlan_objmgr_psoc *psoc,
+		enum hw_mode_ss_config mac0_ss,
+		enum hw_mode_bandwidth mac0_bw,
+		enum hw_mode_ss_config mac1_ss,
+		enum hw_mode_bandwidth mac1_bw,
+		enum hw_mode_mac_band_cap mac0_band_cap,
+		enum hw_mode_dbs_capab dbs,
+		enum hw_mode_agile_dfs_capab dfs,
+		enum hw_mode_sbs_capab sbs)
+{
+	uint32_t mac0_tx_ss, mac0_rx_ss;
+	uint32_t mac1_tx_ss, mac1_rx_ss;
+
+	policy_mgr_get_tx_rx_ss_from_config(mac0_ss, &mac0_tx_ss, &mac0_rx_ss);
+	policy_mgr_get_tx_rx_ss_from_config(mac1_ss, &mac1_tx_ss, &mac1_rx_ss);
+
+	policy_mgr_debug("MAC0: TxSS=%d, RxSS=%d, BW=%d band=%d",
+			 mac0_tx_ss, mac0_rx_ss, mac0_bw, mac0_band_cap);
+	policy_mgr_debug("MAC1: TxSS=%d, RxSS=%d, BW=%d",
+			 mac1_tx_ss, mac1_rx_ss, mac1_bw);
+	policy_mgr_debug("DBS=%d, Agile DFS=%d, SBS=%d",
+			 dbs, dfs, sbs);
+
+	return policy_mgr_get_matching_hw_mode_index(psoc, mac0_tx_ss,
+						mac0_rx_ss,
+						mac0_bw,
+						mac1_tx_ss, mac1_rx_ss,
+						mac1_bw,
+						mac0_band_cap,
+						dbs, dfs, sbs);
+}
+
+/**
+ * policy_mgr_get_hw_mode_from_idx() - Get HW mode based on index
+ * @psoc: psoc object
+ * @idx: HW mode id
+ * @hw_mode: HW mode params
+ *
+ * Fetches the HW mode parameters
+ *
+ * Return: Success if hw mode is obtained and the hw mode params
+ */
+QDF_STATUS policy_mgr_get_hw_mode_from_idx(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t idx,
+		struct policy_mgr_hw_mode_params *hw_mode)
+{
+	uint32_t param;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint8_t mac0_min_ss;
+	uint8_t mac1_min_ss;
+	uint32_t i, hw_mode_id;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (!pm_ctx->num_dbs_hw_modes) {
+		policy_mgr_err("No dbs hw modes available");
+		return QDF_STATUS_E_FAILURE;
+	}
+	for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) {
+		param = pm_ctx->hw_mode.hw_mode_list[i];
+		hw_mode_id = POLICY_MGR_HW_MODE_ID_GET(param);
+		if (hw_mode_id == idx)
+			break;
+	}
+	if (i >= pm_ctx->num_dbs_hw_modes) {
+		policy_mgr_err("hw mode id %d not found", idx);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	param = pm_ctx->hw_mode.hw_mode_list[i];
+
+	hw_mode->mac0_tx_ss = POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(param);
+	hw_mode->mac0_rx_ss = POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(param);
+	hw_mode->mac0_bw = POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(param);
+	hw_mode->mac1_tx_ss = POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(param);
+	hw_mode->mac1_rx_ss = POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(param);
+	hw_mode->mac1_bw = POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET(param);
+	hw_mode->mac0_band_cap = POLICY_MGR_HW_MODE_MAC0_BAND_GET(param);
+	hw_mode->dbs_cap = POLICY_MGR_HW_MODE_DBS_MODE_GET(param);
+	hw_mode->agile_dfs_cap = POLICY_MGR_HW_MODE_AGILE_DFS_GET(param);
+	hw_mode->sbs_cap = POLICY_MGR_HW_MODE_SBS_MODE_GET(param);
+	if (hw_mode->dbs_cap) {
+		mac0_min_ss = QDF_MIN(hw_mode->mac0_tx_ss, hw_mode->mac0_rx_ss);
+		mac1_min_ss = QDF_MIN(hw_mode->mac1_tx_ss, hw_mode->mac1_rx_ss);
+		if (hw_mode->mac0_band_cap == WLAN_5G_CAPABILITY &&
+		    mac0_min_ss && mac1_min_ss &&
+		    mac0_min_ss > mac1_min_ss)
+			hw_mode->action_type = PM_DBS1;
+		else if (hw_mode->mac0_band_cap == WLAN_2G_CAPABILITY &&
+			 mac0_min_ss && mac1_min_ss &&
+			 mac0_min_ss > mac1_min_ss)
+			hw_mode->action_type = PM_DBS2;
+		else
+			hw_mode->action_type = PM_DBS;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * policy_mgr_get_old_and_new_hw_index() - Get the old and new HW index
+ * @old_hw_mode_index: Value at this pointer contains the old HW mode index
+ * Default value when not configured is POLICY_MGR_DEFAULT_HW_MODE_INDEX
+ * @new_hw_mode_index: Value at this pointer contains the new HW mode index
+ * Default value when not configured is POLICY_MGR_DEFAULT_HW_MODE_INDEX
+ *
+ * Get the old and new HW index configured in the driver
+ *
+ * Return: Failure in case the HW mode indices cannot be fetched and Success
+ * otherwise. When no HW mode transition has happened the values of
+ * old_hw_mode_index and new_hw_mode_index will be the same.
+ */
+QDF_STATUS policy_mgr_get_old_and_new_hw_index(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t *old_hw_mode_index,
+		uint32_t *new_hw_mode_index)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*old_hw_mode_index = pm_ctx->old_hw_mode_index;
+	*new_hw_mode_index = pm_ctx->new_hw_mode_index;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * policy_mgr_update_conc_list() - Update the concurrent connection list
+ * @conn_index: Connection index
+ * @mode: Mode
+ * @chan: Channel
+ * @bw: Bandwidth
+ * @mac: Mac id
+ * @chain_mask: Chain mask
+ * @vdev_id: vdev id
+ * @in_use: Flag to indicate if the index is in use or not
+ * @update_conn: Flag to indicate if mode change event should
+ *  be sent or not
+ *
+ * Updates the index value of the concurrent connection list
+ *
+ * Return: None
+ */
+void policy_mgr_update_conc_list(struct wlan_objmgr_psoc *psoc,
+		uint32_t conn_index,
+		enum policy_mgr_con_mode mode,
+		uint8_t chan,
+		enum hw_mode_bandwidth bw,
+		uint8_t mac,
+		enum policy_mgr_chain_mode chain_mask,
+		uint32_t original_nss,
+		uint32_t vdev_id,
+		bool in_use,
+		bool update_conn)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool mcc_mode;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	if (conn_index >= MAX_NUMBER_OF_CONC_CONNECTIONS) {
+		policy_mgr_err("Number of connections exceeded conn_index: %d",
+			conn_index);
+		return;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	pm_conc_connection_list[conn_index].mode = mode;
+	pm_conc_connection_list[conn_index].chan = chan;
+	pm_conc_connection_list[conn_index].bw = bw;
+	pm_conc_connection_list[conn_index].mac = mac;
+	pm_conc_connection_list[conn_index].chain_mask = chain_mask;
+	pm_conc_connection_list[conn_index].original_nss = original_nss;
+	pm_conc_connection_list[conn_index].vdev_id = vdev_id;
+	pm_conc_connection_list[conn_index].in_use = in_use;
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	/*
+	 * For STA and P2P client mode, the mode change event sent as part
+	 * of the callback causes delay in processing M1 frame at supplicant
+	 * resulting in cert test case failure. The mode change event is sent
+	 * as part of add key for STA and P2P client mode.
+	 */
+	if (pm_ctx->mode_change_cb && update_conn)
+		pm_ctx->mode_change_cb();
+
+	policy_mgr_dump_connection_status_info(psoc);
+	if (pm_ctx->cdp_cbacks.cdp_update_mac_id)
+		pm_ctx->cdp_cbacks.cdp_update_mac_id(psoc, vdev_id, mac);
+
+	/* IPA only cares about STA or SAP mode */
+	if (mode == PM_STA_MODE || mode == PM_SAP_MODE) {
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+		if (pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb)
+			pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb(mcc_mode);
+	}
+}
+
+/**
+ * policy_mgr_store_and_del_conn_info() - Store and del a connection info
+ * @mode: Mode whose entry has to be deleted
+ * @all_matching_cxn_to_del: All the specified mode entries should be deleted
+ * @info: Struture array pointer where the connection info will be saved
+ * @num_cxn_del: Number of connection which are going to be deleted
+ *
+ * Saves the connection info corresponding to the provided mode
+ * and deleted that corresponding entry based on vdev from the
+ * connection info structure
+ *
+ * Return: None
+ */
+void policy_mgr_store_and_del_conn_info(struct wlan_objmgr_psoc *psoc,
+	enum policy_mgr_con_mode mode, bool all_matching_cxn_to_del,
+	struct policy_mgr_conc_connection_info *info, uint8_t *num_cxn_del)
+{
+	int32_t conn_index = 0;
+	uint32_t found_index = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	if (!num_cxn_del) {
+		policy_mgr_err("num_cxn_del is NULL");
+		return;
+	}
+	*num_cxn_del = 0;
+	if (!info) {
+		policy_mgr_err("Invalid connection info");
+		return;
+	}
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+		if (mode == pm_conc_connection_list[conn_index].mode) {
+			/*
+			 * Storing the connection entry which will be
+			 * temporarily deleted.
+			 */
+			info[found_index] = pm_conc_connection_list[conn_index];
+			/* Deleting the connection entry */
+			policy_mgr_decr_connection_count(psoc,
+					info[found_index].vdev_id);
+			policy_mgr_debug("Stored %d (%d), deleted STA entry with vdev id %d, index %d",
+					 info[found_index].vdev_id,
+					 info[found_index].mode,
+					 info[found_index].vdev_id, conn_index);
+			found_index++;
+			if (all_matching_cxn_to_del)
+				continue;
+			else
+				break;
+		}
+		conn_index++;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	if (!found_index) {
+		*num_cxn_del = 0;
+		policy_mgr_err("Mode:%d not available in the conn info", mode);
+	} else {
+		*num_cxn_del = found_index;
+		policy_mgr_err("Mode:%d number of conn %d temp del",
+				mode, *num_cxn_del);
+	}
+
+	/*
+	 * Caller should set the PCL and restore the connection entry
+	 * in conn info.
+	 */
+}
+
+void policy_mgr_store_and_del_conn_info_by_vdev_id(
+			struct wlan_objmgr_psoc *psoc,
+			uint32_t vdev_id,
+			struct policy_mgr_conc_connection_info *info,
+			uint8_t *num_cxn_del)
+{
+	uint32_t conn_index = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	if (!info || !num_cxn_del) {
+		policy_mgr_err("Invalid parameters");
+		return;
+	}
+	*num_cxn_del = 0;
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+	     conn_index++) {
+		if ((pm_conc_connection_list[conn_index].vdev_id == vdev_id) &&
+		    pm_conc_connection_list[conn_index].in_use) {
+			*num_cxn_del = 1;
+			break;
+		}
+	}
+	/*
+	 * Storing the connection entry which will be
+	 * temporarily deleted.
+	 */
+	if (*num_cxn_del == 1) {
+		*info = pm_conc_connection_list[conn_index];
+		/* Deleting the connection entry */
+		policy_mgr_decr_connection_count(
+			psoc,
+			pm_conc_connection_list[conn_index].vdev_id);
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+}
+
+/**
+ * policy_mgr_restore_deleted_conn_info() - Restore connection info
+ * @info: An array saving connection info that is to be restored
+ * @num_cxn_del: Number of connection temporary deleted
+ *
+ * Restores the connection info of STA that was saved before
+ * updating the PCL to the FW
+ *
+ * Return: None
+ */
+void policy_mgr_restore_deleted_conn_info(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_conc_connection_info *info,
+		uint8_t num_cxn_del)
+{
+	uint32_t conn_index;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	if (MAX_NUMBER_OF_CONC_CONNECTIONS <= num_cxn_del || 0 == num_cxn_del) {
+		policy_mgr_err("Failed to restore %d/%d deleted information",
+				num_cxn_del, MAX_NUMBER_OF_CONC_CONNECTIONS);
+		return;
+	}
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	conn_index = policy_mgr_get_connection_count(psoc);
+	if (MAX_NUMBER_OF_CONC_CONNECTIONS <= conn_index) {
+		policy_mgr_err("Failed to restore the deleted information %d/%d",
+			conn_index, MAX_NUMBER_OF_CONC_CONNECTIONS);
+		return;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	qdf_mem_copy(&pm_conc_connection_list[conn_index], info,
+			num_cxn_del * sizeof(*info));
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	policy_mgr_debug("Restored the deleleted conn info, vdev:%d, index:%d",
+		info->vdev_id, conn_index);
+}
+
+/**
+ * policy_mgr_update_hw_mode_conn_info() - Update connection
+ * info based on HW mode
+ * @num_vdev_mac_entries: Number of vdev-mac id entries that follow
+ * @vdev_mac_map: Mapping of vdev-mac id
+ * @hw_mode: HW mode
+ *
+ * Updates the connection info parameters based on the new HW mode
+ *
+ * Return: None
+ */
+void policy_mgr_update_hw_mode_conn_info(struct wlan_objmgr_psoc *psoc,
+				uint32_t num_vdev_mac_entries,
+				struct policy_mgr_vdev_mac_map *vdev_mac_map,
+				struct policy_mgr_hw_mode_params hw_mode)
+{
+	uint32_t i, conn_index, found;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (i = 0; i < num_vdev_mac_entries; i++) {
+		conn_index = 0;
+		found = 0;
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (vdev_mac_map[i].vdev_id ==
+				pm_conc_connection_list[conn_index].vdev_id) {
+				found = 1;
+				break;
+			}
+			conn_index++;
+		}
+		if (found) {
+			pm_conc_connection_list[conn_index].mac =
+				vdev_mac_map[i].mac_id;
+			policy_mgr_debug("vdev:%d, mac:%d",
+			  pm_conc_connection_list[conn_index].vdev_id,
+			  pm_conc_connection_list[conn_index].mac);
+			if (pm_ctx->cdp_cbacks.cdp_update_mac_id)
+				pm_ctx->cdp_cbacks.cdp_update_mac_id(
+					psoc,
+					vdev_mac_map[i].vdev_id,
+					vdev_mac_map[i].mac_id);
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	policy_mgr_dump_connection_status_info(psoc);
+}
+
+void policy_mgr_pdev_set_hw_mode_cb(uint32_t status,
+				uint32_t cfgd_hw_mode_index,
+				uint32_t num_vdev_mac_entries,
+				struct policy_mgr_vdev_mac_map *vdev_mac_map,
+				uint8_t next_action,
+				enum policy_mgr_conn_update_reason reason,
+				uint32_t session_id, void *context)
+{
+	QDF_STATUS ret;
+	struct policy_mgr_hw_mode_params hw_mode;
+	uint32_t i;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(context);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	policy_mgr_set_hw_mode_change_in_progress(context,
+		POLICY_MGR_HW_MODE_NOT_IN_PROGRESS);
+
+	if (status != SET_HW_MODE_STATUS_OK) {
+		policy_mgr_err("Set HW mode failed with status %d", status);
+		return;
+	}
+
+	if (!vdev_mac_map) {
+		policy_mgr_err("vdev_mac_map is NULL");
+		return;
+	}
+
+	policy_mgr_debug("cfgd_hw_mode_index=%d", cfgd_hw_mode_index);
+
+	for (i = 0; i < num_vdev_mac_entries; i++)
+		policy_mgr_debug("vdev_id:%d mac_id:%d",
+				vdev_mac_map[i].vdev_id,
+				vdev_mac_map[i].mac_id);
+
+	ret = policy_mgr_get_hw_mode_from_idx(context, cfgd_hw_mode_index,
+			&hw_mode);
+	if (ret != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Get HW mode failed: %d", ret);
+		return;
+	}
+
+	policy_mgr_debug("MAC0: TxSS:%d, RxSS:%d, Bw:%d, band_cap %d",
+			 hw_mode.mac0_tx_ss, hw_mode.mac0_rx_ss,
+			 hw_mode.mac0_bw, hw_mode.mac0_band_cap);
+	policy_mgr_debug("MAC1: TxSS:%d, RxSS:%d, Bw:%d",
+			 hw_mode.mac1_tx_ss, hw_mode.mac1_rx_ss,
+			 hw_mode.mac1_bw);
+	policy_mgr_debug("DBS:%d, Agile DFS:%d, SBS:%d",
+			 hw_mode.dbs_cap, hw_mode.agile_dfs_cap,
+			 hw_mode.sbs_cap);
+
+	/* update pm_conc_connection_list */
+	policy_mgr_update_hw_mode_conn_info(context, num_vdev_mac_entries,
+			vdev_mac_map,
+			hw_mode);
+	if (pm_ctx->mode_change_cb)
+		pm_ctx->mode_change_cb();
+
+	ret = policy_mgr_set_connection_update(context);
+	if (!QDF_IS_STATUS_SUCCESS(ret))
+		policy_mgr_err("ERROR: set connection_update_done event failed");
+
+	if (PM_NOP != next_action)
+		policy_mgr_next_actions(context, session_id,
+			next_action, reason);
+	else {
+		policy_mgr_debug("No action needed right now");
+		ret = policy_mgr_set_opportunistic_update(context);
+		if (!QDF_IS_STATUS_SUCCESS(ret))
+			policy_mgr_err("ERROR: set opportunistic_update event failed");
+	}
+
+	return;
+}
+
+/**
+ * policy_mgr_dump_current_concurrency_one_connection() - To dump the
+ * current concurrency info with one connection
+ * @cc_mode: connection string
+ * @length: Maximum size of the string
+ *
+ * This routine is called to dump the concurrency info
+ *
+ * Return: length of the string
+ */
+static uint32_t policy_mgr_dump_current_concurrency_one_connection(
+		char *cc_mode, uint32_t length)
+{
+	uint32_t count = 0;
+	enum policy_mgr_con_mode mode;
+
+	mode = pm_conc_connection_list[0].mode;
+
+	switch (mode) {
+	case PM_STA_MODE:
+		count = strlcat(cc_mode, "STA",
+					length);
+		break;
+	case PM_SAP_MODE:
+		count = strlcat(cc_mode, "SAP",
+					length);
+		break;
+	case PM_P2P_CLIENT_MODE:
+		count = strlcat(cc_mode, "P2P CLI",
+					length);
+		break;
+	case PM_P2P_GO_MODE:
+		count = strlcat(cc_mode, "P2P GO",
+					length);
+		break;
+	case PM_IBSS_MODE:
+		count = strlcat(cc_mode, "IBSS",
+					length);
+		break;
+	default:
+		policy_mgr_err("unexpected mode %d", mode);
+		break;
+	}
+
+	return count;
+}
+
+/**
+ * policy_mgr_dump_current_concurrency_two_connection() - To dump the
+ * current concurrency info with two connections
+ * @cc_mode: connection string
+ * @length: Maximum size of the string
+ *
+ * This routine is called to dump the concurrency info
+ *
+ * Return: length of the string
+ */
+static uint32_t policy_mgr_dump_current_concurrency_two_connection(
+		char *cc_mode, uint32_t length)
+{
+	uint32_t count = 0;
+	enum policy_mgr_con_mode mode;
+
+	mode = pm_conc_connection_list[1].mode;
+
+	switch (mode) {
+	case PM_STA_MODE:
+		count = policy_mgr_dump_current_concurrency_one_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+STA",
+					length);
+		break;
+	case PM_SAP_MODE:
+		count = policy_mgr_dump_current_concurrency_one_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+SAP",
+					length);
+		break;
+	case PM_P2P_CLIENT_MODE:
+		count = policy_mgr_dump_current_concurrency_one_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+P2P CLI",
+					length);
+		break;
+	case PM_P2P_GO_MODE:
+		count = policy_mgr_dump_current_concurrency_one_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+P2P GO",
+					length);
+		break;
+	case PM_IBSS_MODE:
+		count = policy_mgr_dump_current_concurrency_one_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+IBSS",
+					length);
+		break;
+	default:
+		policy_mgr_err("unexpected mode %d", mode);
+		break;
+	}
+
+	return count;
+}
+
+/**
+ * policy_mgr_dump_current_concurrency_three_connection() - To dump the
+ * current concurrency info with three connections
+ * @cc_mode: connection string
+ * @length: Maximum size of the string
+ *
+ * This routine is called to dump the concurrency info
+ *
+ * Return: length of the string
+ */
+static uint32_t policy_mgr_dump_current_concurrency_three_connection(
+		char *cc_mode, uint32_t length)
+{
+	uint32_t count = 0;
+	enum policy_mgr_con_mode mode;
+
+	mode = pm_conc_connection_list[2].mode;
+
+	switch (mode) {
+	case PM_STA_MODE:
+		count = policy_mgr_dump_current_concurrency_two_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+STA",
+					length);
+		break;
+	case PM_SAP_MODE:
+		count = policy_mgr_dump_current_concurrency_two_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+SAP",
+					length);
+		break;
+	case PM_P2P_CLIENT_MODE:
+		count = policy_mgr_dump_current_concurrency_two_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+P2P CLI",
+					length);
+		break;
+	case PM_P2P_GO_MODE:
+		count = policy_mgr_dump_current_concurrency_two_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+P2P GO",
+					length);
+		break;
+	case PM_IBSS_MODE:
+		count = policy_mgr_dump_current_concurrency_two_connection(
+				cc_mode, length);
+		count += strlcat(cc_mode, "+IBSS",
+					length);
+		break;
+	default:
+		policy_mgr_err("unexpected mode %d", mode);
+		break;
+	}
+
+	return count;
+}
+
+/**
+ * policy_mgr_dump_dbs_concurrency() - To dump the dbs concurrency
+ * combination
+ * @cc_mode: connection string
+ *
+ * This routine is called to dump the concurrency info
+ *
+ * Return: None
+ */
+static void policy_mgr_dump_dbs_concurrency(struct wlan_objmgr_psoc *psoc,
+					char *cc_mode, uint32_t length)
+{
+	char buf[4] = {0};
+	uint8_t mac = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	strlcat(cc_mode, " DBS", length);
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (pm_conc_connection_list[0].mac ==
+		pm_conc_connection_list[1].mac) {
+		if (pm_conc_connection_list[0].chan ==
+			pm_conc_connection_list[1].chan)
+			strlcat(cc_mode,
+				" with SCC for 1st two connections on mac ",
+				length);
+		else
+			strlcat(cc_mode,
+				" with MCC for 1st two connections on mac ",
+				length);
+		mac = pm_conc_connection_list[0].mac;
+	}
+	if (pm_conc_connection_list[0].mac == pm_conc_connection_list[2].mac) {
+		if (pm_conc_connection_list[0].chan ==
+			pm_conc_connection_list[2].chan)
+			strlcat(cc_mode,
+				" with SCC for 1st & 3rd connections on mac ",
+				length);
+		else
+			strlcat(cc_mode,
+				" with MCC for 1st & 3rd connections on mac ",
+				length);
+		mac = pm_conc_connection_list[0].mac;
+	}
+	if (pm_conc_connection_list[1].mac == pm_conc_connection_list[2].mac) {
+		if (pm_conc_connection_list[1].chan ==
+			pm_conc_connection_list[2].chan)
+			strlcat(cc_mode,
+				" with SCC for 2nd & 3rd connections on mac ",
+				length);
+		else
+			strlcat(cc_mode,
+				" with MCC for 2nd & 3rd connections on mac ",
+				length);
+		mac = pm_conc_connection_list[1].mac;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	snprintf(buf, sizeof(buf), "%d ", mac);
+	strlcat(cc_mode, buf, length);
+}
+
+/**
+ * policy_mgr_dump_current_concurrency() - To dump the current
+ * concurrency combination
+ *
+ * This routine is called to dump the concurrency info
+ *
+ * Return: None
+ */
+void policy_mgr_dump_current_concurrency(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t num_connections = 0;
+	char cc_mode[POLICY_MGR_MAX_CON_STRING_LEN] = {0};
+	uint32_t count = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	num_connections = policy_mgr_get_connection_count(psoc);
+
+	switch (num_connections) {
+	case 1:
+		policy_mgr_dump_current_concurrency_one_connection(cc_mode,
+					sizeof(cc_mode));
+		policy_mgr_err("%s Standalone", cc_mode);
+		break;
+	case 2:
+		count = policy_mgr_dump_current_concurrency_two_connection(
+			cc_mode, sizeof(cc_mode));
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		if (pm_conc_connection_list[0].chan ==
+			pm_conc_connection_list[1].chan) {
+			strlcat(cc_mode, " SCC", sizeof(cc_mode));
+		} else if (pm_conc_connection_list[0].mac ==
+					pm_conc_connection_list[1].mac) {
+			strlcat(cc_mode, " MCC", sizeof(cc_mode));
+		} else
+			strlcat(cc_mode, " DBS", sizeof(cc_mode));
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		policy_mgr_err("%s", cc_mode);
+		break;
+	case 3:
+		count = policy_mgr_dump_current_concurrency_three_connection(
+			cc_mode, sizeof(cc_mode));
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		if ((pm_conc_connection_list[0].chan ==
+			pm_conc_connection_list[1].chan) &&
+			(pm_conc_connection_list[0].chan ==
+				pm_conc_connection_list[2].chan)){
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				strlcat(cc_mode, " SCC",
+						sizeof(cc_mode));
+		} else if ((pm_conc_connection_list[0].mac ==
+				pm_conc_connection_list[1].mac)
+				&& (pm_conc_connection_list[0].mac ==
+					pm_conc_connection_list[2].mac)) {
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+					strlcat(cc_mode, " MCC on single MAC",
+						sizeof(cc_mode));
+		} else {
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+			policy_mgr_dump_dbs_concurrency(psoc, cc_mode,
+					sizeof(cc_mode));
+		}
+		policy_mgr_err("%s", cc_mode);
+		break;
+	default:
+		policy_mgr_err("unexpected num_connections value %d",
+			num_connections);
+		break;
+	}
+
+	return;
+}
+
+/**
+ * policy_mgr_pdev_set_pcl() - Sets PCL to FW
+ * @mode: adapter mode
+ *
+ * Fetches the PCL and sends the PCL to SME
+ * module which in turn will send the WMI
+ * command WMI_PDEV_SET_PCL_CMDID to the fw
+ *
+ * Return: None
+ */
+void policy_mgr_pdev_set_pcl(struct wlan_objmgr_psoc *psoc,
+				enum QDF_OPMODE mode)
+{
+	QDF_STATUS status;
+	enum policy_mgr_con_mode con_mode;
+	struct policy_mgr_pcl_list pcl;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	pcl.pcl_len = 0;
+
+	switch (mode) {
+	case QDF_STA_MODE:
+		con_mode = PM_STA_MODE;
+		break;
+	case QDF_P2P_CLIENT_MODE:
+		con_mode = PM_P2P_CLIENT_MODE;
+		break;
+	case QDF_P2P_GO_MODE:
+		con_mode = PM_P2P_GO_MODE;
+		break;
+	case QDF_SAP_MODE:
+		con_mode = PM_SAP_MODE;
+		break;
+	case QDF_IBSS_MODE:
+		con_mode = PM_IBSS_MODE;
+		break;
+	default:
+		policy_mgr_err("Unable to set PCL to FW: %d", mode);
+		return;
+	}
+
+	policy_mgr_debug("get pcl to set it to the FW");
+
+	status = policy_mgr_get_pcl(psoc, con_mode,
+			pcl.pcl_list, &pcl.pcl_len,
+			pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list));
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Unable to set PCL to FW, Get PCL failed");
+		return;
+	}
+
+	status = pm_ctx->sme_cbacks.sme_pdev_set_pcl(&pcl);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Send soc set PCL to SME failed");
+	else
+		policy_mgr_debug("Set PCL to FW for mode:%d", mode);
+}
+
+/**
+ * policy_mgr_set_pcl_for_existing_combo() - Set PCL for existing connection
+ * @mode: Connection mode of type 'policy_mgr_con_mode'
+ *
+ * Set the PCL for an existing connection
+ *
+ * Return: None
+ */
+void policy_mgr_set_pcl_for_existing_combo(
+		struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode)
+{
+	struct policy_mgr_conc_connection_info
+			info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} };
+	enum QDF_OPMODE pcl_mode;
+	uint8_t num_cxn_del = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	pcl_mode = policy_mgr_get_qdf_mode_from_pm(mode);
+	if (pcl_mode == QDF_MAX_NO_OF_MODE)
+		return;
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (policy_mgr_mode_specific_connection_count(psoc, mode, NULL) > 0) {
+		/* Check, store and temp delete the mode's parameter */
+		policy_mgr_store_and_del_conn_info(psoc, mode, false,
+						info, &num_cxn_del);
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		/* Set the PCL to the FW since connection got updated */
+		policy_mgr_pdev_set_pcl(psoc, pcl_mode);
+		policy_mgr_debug("Set PCL to FW for mode:%d", mode);
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		/* Restore the connection info */
+		policy_mgr_restore_deleted_conn_info(psoc, info, num_cxn_del);
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+}
+
+static uint32_t pm_get_vdev_id_of_first_conn_idx(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t conn_index = 0, vdev_id = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return conn_index;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+	     conn_index++)  {
+		if (pm_conc_connection_list[conn_index].in_use) {
+			vdev_id = pm_conc_connection_list[conn_index].vdev_id;
+			break;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	if (conn_index == MAX_NUMBER_OF_CONC_CONNECTIONS)
+		policy_mgr_debug("Use default vdev_id:%d for opportunistic upgrade",
+				 vdev_id);
+	else
+		policy_mgr_debug("Use vdev_id:%d for opportunistic upgrade",
+				 vdev_id);
+
+	return vdev_id;
+}
+
+/**
+ * pm_dbs_opportunistic_timer_handler() - handler of
+ * dbs_opportunistic_timer
+ * @data:  context
+ *
+ * handler for dbs_opportunistic_timer
+ *
+ * Return: None
+ */
+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;
+
+	if (!psoc) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	/* if we still need it */
+	action = policy_mgr_need_opportunistic_upgrade(psoc, &reason);
+	policy_mgr_debug("action:%d", action);
+	if (!action)
+		return;
+	session_id = pm_get_vdev_id_of_first_conn_idx(psoc);
+	policy_mgr_next_actions(psoc, session_id, action,
+				reason);
+}
+
+/**
+ * policy_mgr_get_connection_for_vdev_id() - provides the
+ * perticular connection with the requested vdev id
+ * @vdev_id: vdev id of the connection
+ *
+ * This function provides the specific connection with the
+ * requested vdev id
+ *
+ * Return: index in the connection table
+ */
+static uint32_t policy_mgr_get_connection_for_vdev_id(
+		struct wlan_objmgr_psoc *psoc, uint32_t vdev_id)
+{
+	uint32_t conn_index = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return conn_index;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		 conn_index++) {
+		if ((pm_conc_connection_list[conn_index].vdev_id == vdev_id) &&
+			pm_conc_connection_list[conn_index].in_use) {
+			break;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return conn_index;
+}
+
+/**
+ * policy_mgr_get_mode() - Get mode from type and subtype
+ * @type: type
+ * @subtype: subtype
+ *
+ * Get the concurrency mode from the type and subtype
+ * of the interface
+ *
+ * Return: policy_mgr_con_mode
+ */
+enum policy_mgr_con_mode policy_mgr_get_mode(uint8_t type,
+		uint8_t subtype)
+{
+	enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE;
+
+	if (type == WMI_VDEV_TYPE_AP) {
+		switch (subtype) {
+		case 0:
+			mode = PM_SAP_MODE;
+			break;
+		case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO:
+			mode = PM_P2P_GO_MODE;
+			break;
+		default:
+			policy_mgr_err("Unknown subtype %d for type %d",
+				subtype, type);
+			break;
+		}
+	} else if (type == WMI_VDEV_TYPE_STA) {
+		switch (subtype) {
+		case 0:
+			mode = PM_STA_MODE;
+			break;
+		case WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT:
+			mode = PM_P2P_CLIENT_MODE;
+			break;
+		default:
+			policy_mgr_err("Unknown subtype %d for type %d",
+				subtype, type);
+			break;
+		}
+	} else if (type == WMI_VDEV_TYPE_IBSS) {
+		mode = PM_IBSS_MODE;
+	} else {
+		policy_mgr_err("Unknown type %d", type);
+	}
+
+	return mode;
+}
+
+/**
+ * policy_mgr_get_bw() - Get channel bandwidth type used by WMI
+ * @chan_width: channel bandwidth type defined by host
+ *
+ * Get the channel bandwidth type used by WMI
+ *
+ * Return: hw_mode_bandwidth
+ */
+enum hw_mode_bandwidth policy_mgr_get_bw(enum phy_ch_width chan_width)
+{
+	enum hw_mode_bandwidth bw = HW_MODE_BW_NONE;
+
+	switch (chan_width) {
+	case CH_WIDTH_20MHZ:
+		bw = HW_MODE_20_MHZ;
+		break;
+	case CH_WIDTH_40MHZ:
+		bw = HW_MODE_40_MHZ;
+		break;
+	case CH_WIDTH_80MHZ:
+		bw = HW_MODE_80_MHZ;
+		break;
+	case CH_WIDTH_160MHZ:
+		bw = HW_MODE_160_MHZ;
+		break;
+	case CH_WIDTH_80P80MHZ:
+		bw = HW_MODE_80_PLUS_80_MHZ;
+		break;
+	case CH_WIDTH_5MHZ:
+		bw = HW_MODE_5_MHZ;
+		break;
+	case CH_WIDTH_10MHZ:
+		bw = HW_MODE_10_MHZ;
+		break;
+	default:
+		policy_mgr_err("Unknown channel BW type %d", chan_width);
+		break;
+	}
+
+	return bw;
+}
+
+/**
+ * policy_mgr_get_sbs_channels() - provides the sbs channel(s)
+ * with respect to current connection(s)
+ * @channels:	the channel(s) on which current connection(s) is
+ * @len:	Number of channels
+ * @pcl_weight: Pointer to the weights of PCL
+ * @weight_len: Max length of the weight list
+ * @index: Index from which the weight list needs to be populated
+ * @group_id: Next available groups for weight assignment
+ * @available_5g_channels: List of available 5g channels
+ * @available_5g_channels_len: Length of the 5g channels list
+ * @add_5g_channels: If this flag is true append 5G channel list as well
+ *
+ * This function provides the channel(s) on which current
+ * connection(s) is/are
+ *
+ * Return: QDF_STATUS
+ */
+
+static QDF_STATUS policy_mgr_get_sbs_channels(uint8_t *channels,
+		uint32_t *len, uint8_t *pcl_weight, uint32_t weight_len,
+		uint32_t *index, enum policy_mgr_pcl_group_id group_id,
+		uint8_t *available_5g_channels,
+		uint32_t available_5g_channels_len,
+		bool add_5g_channels)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint32_t conn_index = 0, num_channels = 0;
+	uint32_t num_5g_channels = 0, cur_5g_channel = 0;
+	uint8_t remaining_5g_Channels[QDF_MAX_NUM_CHAN] = {};
+	uint32_t remaining_channel_index = 0;
+	uint32_t j = 0, i = 0, weight1, weight2;
+
+	if ((NULL == channels) || (NULL == len)) {
+		policy_mgr_err("channels or len is NULL");
+		status = QDF_STATUS_E_FAILURE;
+		return status;
+	}
+
+	if (group_id == POLICY_MGR_PCL_GROUP_ID1_ID2) {
+		weight1 = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		weight2 = WEIGHT_OF_GROUP2_PCL_CHANNELS;
+	} else if (group_id == POLICY_MGR_PCL_GROUP_ID2_ID3) {
+		weight1 = WEIGHT_OF_GROUP2_PCL_CHANNELS;
+		weight2 = WEIGHT_OF_GROUP3_PCL_CHANNELS;
+	} else {
+		weight1 = WEIGHT_OF_GROUP3_PCL_CHANNELS;
+		weight2 = WEIGHT_OF_GROUP4_PCL_CHANNELS;
+	}
+
+	policy_mgr_debug("weight1=%d weight2=%d index=%d ",
+		weight1, weight2, *index);
+
+	while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+		if ((WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[conn_index].chan))
+			&& (pm_conc_connection_list[conn_index].in_use)) {
+			num_5g_channels++;
+			cur_5g_channel =
+				pm_conc_connection_list[conn_index].chan;
+		}
+		conn_index++;
+	}
+
+	conn_index = 0;
+	if (num_5g_channels > 1) {
+		/* This case we are already in SBS so return the channels */
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			channels[num_channels++] =
+				pm_conc_connection_list[conn_index++].chan;
+			if (*index < weight_len)
+				pcl_weight[(*index)++] = weight1;
+		}
+		*len = num_channels;
+		/* fix duplicate issue later */
+		if (add_5g_channels)
+			for (j = 0; j < available_5g_channels_len; j++)
+				remaining_5g_Channels[
+				remaining_channel_index++] =
+				available_5g_channels[j];
+	} else {
+		/* Get list of valid sbs channels for the current
+		 * connected channel
+		 */
+		for (j = 0; j < available_5g_channels_len; j++) {
+			if (WLAN_REG_IS_CHANNEL_VALID_5G_SBS(
+			cur_5g_channel, available_5g_channels[j])) {
+				channels[num_channels++] =
+					available_5g_channels[j];
+			} else {
+				remaining_5g_Channels[
+				remaining_channel_index++] =
+				available_5g_channels[j];
+				continue;
+			}
+			if (*index < weight_len)
+				pcl_weight[(*index)++] = weight1;
+		}
+		*len = num_channels;
+	}
+
+	if (add_5g_channels) {
+		qdf_mem_copy(channels+num_channels, remaining_5g_Channels,
+			remaining_channel_index);
+		*len += remaining_channel_index;
+		for (i = 0; ((i < remaining_channel_index)
+					&& (i < weight_len)); i++)
+			pcl_weight[i] = weight2;
+	}
+
+	return status;
+}
+
+
+/**
+ * policy_mgr_get_connection_channels() - provides the channel(s)
+ * on which current connection(s) is
+ * @channels:	the channel(s) on which current connection(s) is
+ * @len:	Number of channels
+ * @order:	no order OR 2.4 Ghz channel followed by 5 Ghz
+ *	channel OR 5 Ghz channel followed by 2.4 Ghz channel
+ * @skip_dfs_channel: if this flag is true then skip the dfs channel
+ * @pcl_weight: Pointer to the weights of PCL
+ * @weight_len: Max length of the weight list
+ * @index: Index from which the weight list needs to be populated
+ * @group_id: Next available groups for weight assignment
+ *
+ *
+ * This function provides the channel(s) on which current
+ * connection(s) is/are
+ *
+ * Return: QDF_STATUS
+ */
+static
+QDF_STATUS policy_mgr_get_connection_channels(struct wlan_objmgr_psoc *psoc,
+			uint8_t *channels,
+			uint32_t *len, enum policy_mgr_pcl_channel_order order,
+			bool skip_dfs_channel,
+			uint8_t *pcl_weight, uint32_t weight_len,
+			uint32_t *index, enum policy_mgr_pcl_group_id group_id)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint32_t conn_index = 0, num_channels = 0;
+	uint32_t weight1, weight2;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+
+	if ((NULL == channels) || (NULL == len)) {
+		policy_mgr_err("channels or len is NULL");
+		status = QDF_STATUS_E_FAILURE;
+		return status;
+	}
+
+	/* POLICY_MGR_PCL_GROUP_ID1_ID2 indicates that all three weights are
+	 * available for assignment. i.e., WEIGHT_OF_GROUP1_PCL_CHANNELS,
+	 * WEIGHT_OF_GROUP2_PCL_CHANNELS and WEIGHT_OF_GROUP3_PCL_CHANNELS
+	 * are all available. Since in this function only two weights are
+	 * assigned at max, only group1 and group2 weights are considered.
+	 *
+	 * The other possible group id POLICY_MGR_PCL_GROUP_ID2_ID3 indicates
+	 * group1 was assigned the weight WEIGHT_OF_GROUP1_PCL_CHANNELS and
+	 * only weights WEIGHT_OF_GROUP2_PCL_CHANNELS and
+	 * WEIGHT_OF_GROUP3_PCL_CHANNELS are available for further weight
+	 * assignments.
+	 *
+	 * e.g., when order is POLICY_MGR_PCL_ORDER_24G_THEN_5G and group id is
+     * POLICY_MGR_PCL_GROUP_ID2_ID3, WEIGHT_OF_GROUP2_PCL_CHANNELS is
+     * assigned to 2.4GHz channels and the weight
+     * WEIGHT_OF_GROUP3_PCL_CHANNELS is assigned to the 5GHz channels.
+	 */
+	if (group_id == POLICY_MGR_PCL_GROUP_ID1_ID2) {
+		weight1 = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		weight2 = WEIGHT_OF_GROUP2_PCL_CHANNELS;
+	} else {
+		weight1 = WEIGHT_OF_GROUP2_PCL_CHANNELS;
+		weight2 = WEIGHT_OF_GROUP3_PCL_CHANNELS;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (POLICY_MGR_PCL_ORDER_NONE == order) {
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (skip_dfs_channel && wlan_reg_is_dfs_ch(pm_ctx->pdev,
+				    pm_conc_connection_list[conn_index].chan)) {
+				conn_index++;
+			} else if (*index < weight_len) {
+				channels[num_channels++] =
+				pm_conc_connection_list[conn_index++].chan;
+				pcl_weight[(*index)++] = weight1;
+			} else {
+				conn_index++;
+			}
+		}
+		*len = num_channels;
+	} else if (POLICY_MGR_PCL_ORDER_24G_THEN_5G == order) {
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (WLAN_REG_IS_24GHZ_CH(
+				    pm_conc_connection_list[conn_index].chan)
+				&& (*index < weight_len)) {
+				channels[num_channels++] =
+				pm_conc_connection_list[conn_index++].chan;
+				pcl_weight[(*index)++] = weight1;
+			} else {
+				conn_index++;
+			}
+		}
+		conn_index = 0;
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (skip_dfs_channel && wlan_reg_is_dfs_ch(pm_ctx->pdev,
+				    pm_conc_connection_list[conn_index].chan)) {
+				conn_index++;
+			} else if (WLAN_REG_IS_5GHZ_CH(
+				    pm_conc_connection_list[conn_index].chan)
+				&& (*index < weight_len)) {
+				channels[num_channels++] =
+				pm_conc_connection_list[conn_index++].chan;
+				pcl_weight[(*index)++] = weight2;
+			} else {
+				conn_index++;
+			}
+		}
+		*len = num_channels;
+	} else if (POLICY_MGR_PCL_ORDER_5G_THEN_2G == order) {
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (skip_dfs_channel && wlan_reg_is_dfs_ch(pm_ctx->pdev,
+				pm_conc_connection_list[conn_index].chan)) {
+				conn_index++;
+			} else if (WLAN_REG_IS_5GHZ_CH(
+				    pm_conc_connection_list[conn_index].chan)
+				&& (*index < weight_len)) {
+				channels[num_channels++] =
+				pm_conc_connection_list[conn_index++].chan;
+				pcl_weight[(*index)++] = weight1;
+			} else {
+				conn_index++;
+			}
+		}
+		conn_index = 0;
+		while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			if (WLAN_REG_IS_24GHZ_CH(
+				    pm_conc_connection_list[conn_index].chan)
+				&& (*index < weight_len)) {
+				channels[num_channels++] =
+				pm_conc_connection_list[conn_index++].chan;
+				pcl_weight[(*index)++] = weight2;
+
+			} else {
+				conn_index++;
+			}
+		}
+		*len = num_channels;
+	} else {
+		policy_mgr_err("unknown order %d", order);
+		status = QDF_STATUS_E_FAILURE;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return status;
+}
+
+/**
+ * policy_mgr_set_weight_of_dfs_passive_channels_to_zero() - set weight of dfs
+ * and passive channels to 0
+ * @psoc: pointer to soc
+ * @pcl_channels: preferred channel list
+ * @len: length of preferred channel list
+ * @weight_list: preferred channel weight list
+ * @weight_len: length of weight list
+ * This function set the weight of dfs and passive channels to 0
+ *
+ * Return: None
+ */
+void policy_mgr_set_weight_of_dfs_passive_channels_to_zero(
+		struct wlan_objmgr_psoc *psoc, uint8_t *pcl_channels,
+		uint32_t *len, uint8_t *weight_list, uint32_t weight_len)
+{
+	uint8_t i;
+	uint32_t orig_channel_count = 0;
+	bool sta_sap_scc_on_dfs_chan;
+	uint32_t sap_count;
+	enum channel_state channel_state;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	sta_sap_scc_on_dfs_chan =
+		policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc);
+	sap_count = policy_mgr_mode_specific_connection_count(psoc,
+			PM_SAP_MODE, NULL);
+	policy_mgr_debug("sta_sap_scc_on_dfs_chan %u, sap_count %u",
+			 sta_sap_scc_on_dfs_chan, sap_count);
+
+	if (!sta_sap_scc_on_dfs_chan || !sap_count)
+		return;
+
+	if (len)
+		orig_channel_count = QDF_MIN(*len, QDF_MAX_NUM_CHAN);
+	else {
+		policy_mgr_err("invalid number of channel length");
+		return;
+	}
+
+	policy_mgr_debug("Set weight of DFS/passive channels to 0");
+
+	for (i = 0; i < orig_channel_count; i++) {
+		channel_state = reg_get_channel_state(pm_ctx->pdev,
+				pcl_channels[i]);
+		if ((channel_state == CHANNEL_STATE_DISABLE) ||
+				(channel_state == CHANNEL_STATE_INVALID))
+			/* Set weight of inactive channels to 0 */
+			weight_list[i] = 0;
+
+		policy_mgr_debug("chan[%d] - %d, weight[%d] - %d",
+				i, pcl_channels[i], i, weight_list[i]);
+	}
+
+	return;
+}
+
+/**
+ * policy_mgr_get_channel_list() - provides the channel list
+ * suggestion for new connection
+ * @pcl:	The preferred channel list enum
+ * @pcl_channels: PCL channels
+ * @len: length of the PCL
+ * @mode: concurrency mode for which channel list is requested
+ * @pcl_weights: Weights of the PCL
+ * @weight_len: Max length of the weight list
+ *
+ * This function provides the actual channel list based on the
+ * current regulatory domain derived using preferred channel
+ * list enum obtained from one of the pcl_table
+ *
+ * Return: Channel List
+ */
+QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc,
+			enum policy_mgr_pcl_type pcl,
+			uint8_t *pcl_channels, uint32_t *len,
+			enum policy_mgr_con_mode mode,
+			uint8_t *pcl_weights, uint32_t weight_len)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint32_t num_channels = 0;
+	uint32_t sbs_num_channels = 0;
+	uint32_t chan_index = 0, chan_index_24 = 0, chan_index_5 = 0;
+	uint8_t channel_list[QDF_MAX_NUM_CHAN] = {0};
+	uint8_t channel_list_24[QDF_MAX_NUM_CHAN] = {0};
+	uint8_t channel_list_5[QDF_MAX_NUM_CHAN] = {0};
+	uint8_t sbs_channel_list[QDF_MAX_NUM_CHAN] = {0};
+	bool skip_dfs_channel = false;
+	bool is_etsi13_srd_chan_allowed_in_mas_mode = true;
+	uint32_t i = 0, j = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool sta_sap_scc_on_dfs_chan;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+
+	if ((NULL == pcl_channels) || (NULL == len)) {
+		policy_mgr_err("pcl_channels or len is NULL");
+		return status;
+	}
+
+	if (PM_MAX_PCL_TYPE == pcl) {
+		/* msg */
+		policy_mgr_err("pcl is invalid");
+		return status;
+	}
+
+	if (PM_NONE == pcl) {
+		/* msg */
+		policy_mgr_debug("pcl is 0");
+		return QDF_STATUS_SUCCESS;
+	}
+	/* get the channel list for current domain */
+	status = policy_mgr_get_valid_chans(psoc, channel_list, &num_channels);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("Error in getting valid channels");
+		return status;
+	}
+
+	/*
+	 * if you have atleast one STA connection then don't fill DFS channels
+	 * in the preferred channel list
+	 */
+	sta_sap_scc_on_dfs_chan =
+		policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc);
+	policy_mgr_debug("sta_sap_scc_on_dfs_chan %u", sta_sap_scc_on_dfs_chan);
+	if ((mode == PM_SAP_MODE) || (mode == PM_P2P_GO_MODE)) {
+		if ((policy_mgr_mode_specific_connection_count(psoc,
+							       PM_STA_MODE,
+							       NULL) > 0) &&
+		    (!sta_sap_scc_on_dfs_chan)) {
+			policy_mgr_debug("skip DFS ch from pcl for SAP/Go");
+			skip_dfs_channel = true;
+		}
+		is_etsi13_srd_chan_allowed_in_mas_mode =
+			wlan_reg_is_etsi13_srd_chan_allowed_master_mode(pm_ctx->
+									pdev);
+	}
+
+	/* Let's divide the list in 2.4 & 5 Ghz lists */
+	while ((chan_index < QDF_MAX_NUM_CHAN) &&
+		(channel_list[chan_index] <= 11) &&
+		(chan_index_24 < QDF_MAX_NUM_CHAN))
+		channel_list_24[chan_index_24++] = channel_list[chan_index++];
+	if ((chan_index < QDF_MAX_NUM_CHAN) &&
+		(channel_list[chan_index] == 12) &&
+		(chan_index_24 < QDF_MAX_NUM_CHAN)) {
+		channel_list_24[chan_index_24++] = channel_list[chan_index++];
+		if ((chan_index < QDF_MAX_NUM_CHAN) &&
+			(channel_list[chan_index] == 13) &&
+			(chan_index_24 < QDF_MAX_NUM_CHAN)) {
+			channel_list_24[chan_index_24++] =
+				channel_list[chan_index++];
+			if ((chan_index < QDF_MAX_NUM_CHAN) &&
+				(channel_list[chan_index] == 14) &&
+				(chan_index_24 < QDF_MAX_NUM_CHAN))
+				channel_list_24[chan_index_24++] =
+					channel_list[chan_index++];
+		}
+	}
+
+	while ((chan_index < num_channels) &&
+		(chan_index < QDF_MAX_NUM_CHAN) &&
+		(chan_index_5 < QDF_MAX_NUM_CHAN)) {
+		if ((true == skip_dfs_channel) &&
+		    wlan_reg_is_dfs_ch(pm_ctx->pdev,
+				       channel_list[chan_index])) {
+			chan_index++;
+			continue;
+		}
+		if (!is_etsi13_srd_chan_allowed_in_mas_mode &&
+		    wlan_reg_is_etsi13_srd_chan(pm_ctx->pdev,
+						channel_list[chan_index])) {
+			chan_index++;
+			continue;
+		}
+		channel_list_5[chan_index_5++] = channel_list[chan_index++];
+	}
+
+	num_channels = 0;
+	sbs_num_channels = 0;
+	/* In the below switch case, the channel list is populated based on the
+	 * pcl. e.g., if the pcl is PM_SCC_CH_24G, the SCC channel group is
+	 * populated first followed by the 2.4GHz channel group. Along with
+	 * this, the weights are also populated in the same order for each of
+	 * these groups. There are three weight groups:
+	 * WEIGHT_OF_GROUP1_PCL_CHANNELS, WEIGHT_OF_GROUP2_PCL_CHANNELS and
+	 * WEIGHT_OF_GROUP3_PCL_CHANNELS.
+	 *
+	 * e.g., if pcl is PM_SCC_ON_5_SCC_ON_24_24G: scc on 5GHz (group1)
+	 * channels take the weight WEIGHT_OF_GROUP1_PCL_CHANNELS, scc on 2.4GHz
+	 * (group2) channels take the weight WEIGHT_OF_GROUP2_PCL_CHANNELS and
+	 * 2.4GHz (group3) channels take the weight
+	 * WEIGHT_OF_GROUP3_PCL_CHANNELS.
+	 *
+	 * When the weight to be assigned to the group is known along with the
+	 * number of channels, the weights are directly assigned to the
+	 * pcl_weights list. But, the channel list is populated using
+     * policy_mgr_get_connection_channels(), the order of weights to be used
+     * is passed as an argument to the function
+     * policy_mgr_get_connection_channels() using
+     * 'enum policy_mgr_pcl_group_id' which indicates the next available
+     * weights to be used and policy_mgr_get_connection_channels() will take
+     * care of the weight assignments.
+	 *
+     * e.g., 'enum policy_mgr_pcl_group_id' value of
+     * POLICY_MGR_PCL_GROUP_ID2_ID3 indicates that the next available groups
+     * for weight assignment are WEIGHT_OF_GROUP2_PCL_CHANNELS and
+     * WEIGHT_OF_GROUP3_PCL_CHANNELS and that the
+     * weight WEIGHT_OF_GROUP1_PCL_CHANNELS was already allocated.
+     * So, in the same example, when order is
+     * POLICY_MGR_PCL_ORDER_24G_THEN_5G,
+	 * policy_mgr_get_connection_channels() will assign the weight
+	 * WEIGHT_OF_GROUP2_PCL_CHANNELS to 2.4GHz channels and assign the
+	 * weight WEIGHT_OF_GROUP3_PCL_CHANNELS to 5GHz channels.
+	 */
+	switch (pcl) {
+	case PM_24G:
+		chan_index_24 = QDF_MIN(chan_index_24, weight_len);
+		qdf_mem_copy(pcl_channels, channel_list_24,
+			chan_index_24);
+		*len = chan_index_24;
+		for (i = 0; i < *len; i++)
+			pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_5G:
+		chan_index_5 = QDF_MIN(chan_index_5, weight_len);
+		qdf_mem_copy(pcl_channels, channel_list_5,
+			chan_index_5);
+		*len = chan_index_5;
+		for (i = 0; i < *len; i++)
+			pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_CH:
+	case PM_MCC_CH:
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID1_ID2);
+		qdf_mem_copy(pcl_channels, channel_list, num_channels);
+		*len = num_channels;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_CH_24G:
+	case PM_MCC_CH_24G:
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID1_ID2);
+		qdf_mem_copy(pcl_channels, channel_list, num_channels);
+		*len = num_channels;
+		chan_index_24 = QDF_MIN((num_channels + chan_index_24),
+					weight_len) - num_channels;
+		qdf_mem_copy(&pcl_channels[num_channels],
+			channel_list_24, chan_index_24);
+		*len += chan_index_24;
+		for (j = 0; j < chan_index_24; i++, j++)
+			pcl_weights[i] = WEIGHT_OF_GROUP2_PCL_CHANNELS;
+
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_CH_5G:
+	case PM_MCC_CH_5G:
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID1_ID2);
+		qdf_mem_copy(pcl_channels, channel_list,
+			num_channels);
+		*len = num_channels;
+		chan_index_5 = QDF_MIN((num_channels + chan_index_5),
+					weight_len) - num_channels;
+		qdf_mem_copy(&pcl_channels[num_channels],
+			channel_list_5, chan_index_5);
+		*len += chan_index_5;
+		for (j = 0; j < chan_index_5; i++, j++)
+			pcl_weights[i] = WEIGHT_OF_GROUP2_PCL_CHANNELS;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_24G_SCC_CH:
+	case PM_24G_MCC_CH:
+		chan_index_24 = QDF_MIN(chan_index_24, weight_len);
+		qdf_mem_copy(pcl_channels, channel_list_24,
+			chan_index_24);
+		*len = chan_index_24;
+		for (i = 0; i < chan_index_24; i++)
+			pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID2_ID3);
+		qdf_mem_copy(&pcl_channels[chan_index_24],
+			channel_list, num_channels);
+		*len += num_channels;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_5G_SCC_CH:
+	case PM_5G_MCC_CH:
+		chan_index_5 = QDF_MIN(chan_index_5, weight_len);
+		qdf_mem_copy(pcl_channels, channel_list_5,
+			chan_index_5);
+		*len = chan_index_5;
+		for (i = 0; i < chan_index_5; i++)
+			pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID2_ID3);
+		qdf_mem_copy(&pcl_channels[chan_index_5],
+			channel_list, num_channels);
+		*len += num_channels;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_ON_24_SCC_ON_5:
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels,
+			POLICY_MGR_PCL_ORDER_24G_THEN_5G,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID1_ID2);
+		qdf_mem_copy(pcl_channels, channel_list,
+			num_channels);
+		*len = num_channels;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_ON_5_SCC_ON_24:
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels,
+			POLICY_MGR_PCL_ORDER_5G_THEN_2G,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID1_ID2);
+		qdf_mem_copy(pcl_channels, channel_list, num_channels);
+		*len = num_channels;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_ON_24_SCC_ON_5_24G:
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels,
+			POLICY_MGR_PCL_ORDER_24G_THEN_5G,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID1_ID2);
+		qdf_mem_copy(pcl_channels, channel_list, num_channels);
+		*len = num_channels;
+		chan_index_24 = QDF_MIN((num_channels + chan_index_24),
+					weight_len) - num_channels;
+		qdf_mem_copy(&pcl_channels[num_channels],
+			channel_list_24, chan_index_24);
+		*len += chan_index_24;
+		for (j = 0; j < chan_index_24; i++, j++)
+			pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_ON_24_SCC_ON_5_5G:
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels,
+			POLICY_MGR_PCL_ORDER_24G_THEN_5G,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID1_ID2);
+		qdf_mem_copy(pcl_channels, channel_list, num_channels);
+		*len = num_channels;
+		chan_index_5 = QDF_MIN((num_channels + chan_index_5),
+					weight_len) - num_channels;
+		qdf_mem_copy(&pcl_channels[num_channels],
+			channel_list_5, chan_index_5);
+		*len += chan_index_5;
+		for (j = 0; j < chan_index_5; i++, j++)
+			pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_ON_5_SCC_ON_24_24G:
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels,
+			POLICY_MGR_PCL_ORDER_5G_THEN_2G,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID1_ID2);
+		qdf_mem_copy(pcl_channels, channel_list, num_channels);
+		*len = num_channels;
+		chan_index_24 = QDF_MIN((num_channels + chan_index_24),
+					weight_len) - num_channels;
+		qdf_mem_copy(&pcl_channels[num_channels],
+			channel_list_24, chan_index_24);
+		*len += chan_index_24;
+		for (j = 0; j < chan_index_24; i++, j++)
+			pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SCC_ON_5_SCC_ON_24_5G:
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels,
+			POLICY_MGR_PCL_ORDER_5G_THEN_2G,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID1_ID2);
+		qdf_mem_copy(pcl_channels, channel_list, num_channels);
+		*len = num_channels;
+		chan_index_5 = QDF_MIN((num_channels + chan_index_5),
+					weight_len) - num_channels;
+		qdf_mem_copy(&pcl_channels[num_channels],
+			channel_list_5, chan_index_5);
+		*len += chan_index_5;
+		for (j = 0; j < chan_index_5; i++, j++)
+			pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_24G_SCC_CH_SBS_CH:
+		qdf_mem_copy(pcl_channels, channel_list_24,
+			chan_index_24);
+		*len = chan_index_24;
+		for (i = 0; ((i < chan_index_24) && (i < weight_len)); i++)
+			pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID2_ID3);
+		qdf_mem_copy(&pcl_channels[chan_index_24],
+			channel_list, num_channels);
+		*len += num_channels;
+		if (policy_mgr_is_hw_sbs_capable(psoc)) {
+			policy_mgr_get_sbs_channels(
+			sbs_channel_list, &sbs_num_channels, pcl_weights,
+			weight_len, &i, POLICY_MGR_PCL_GROUP_ID3_ID4,
+			channel_list_5, chan_index_5, false);
+			qdf_mem_copy(
+				&pcl_channels[chan_index_24 + num_channels],
+				sbs_channel_list, sbs_num_channels);
+			*len += sbs_num_channels;
+		}
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_24G_SCC_CH_SBS_CH_5G:
+		qdf_mem_copy(pcl_channels, channel_list_24,
+			chan_index_24);
+		*len = chan_index_24;
+		for (i = 0; ((i < chan_index_24) && (i < weight_len)); i++)
+			pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID2_ID3);
+		qdf_mem_copy(&pcl_channels[chan_index_24],
+			channel_list, num_channels);
+		*len += num_channels;
+		if (policy_mgr_is_hw_sbs_capable(psoc)) {
+			policy_mgr_get_sbs_channels(
+			sbs_channel_list, &sbs_num_channels, pcl_weights,
+			weight_len, &i, POLICY_MGR_PCL_GROUP_ID3_ID4,
+			channel_list_5, chan_index_5, true);
+			qdf_mem_copy(
+				&pcl_channels[chan_index_24 + num_channels],
+				sbs_channel_list, sbs_num_channels);
+			*len += sbs_num_channels;
+		} else {
+			qdf_mem_copy(
+				&pcl_channels[chan_index_24 + num_channels],
+				channel_list_5, chan_index_5);
+			*len += chan_index_5;
+			for (i = chan_index_24 + num_channels;
+				((i < *len) && (i < weight_len)); i++)
+				pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS;
+		}
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_24G_SBS_CH_MCC_CH:
+		qdf_mem_copy(pcl_channels, channel_list_24,
+			chan_index_24);
+		*len = chan_index_24;
+		for (i = 0; ((i < chan_index_24) && (i < weight_len)); i++)
+			pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		if (policy_mgr_is_hw_sbs_capable(psoc)) {
+			policy_mgr_get_sbs_channels(
+			sbs_channel_list, &sbs_num_channels, pcl_weights,
+			weight_len, &i, POLICY_MGR_PCL_GROUP_ID2_ID3,
+			channel_list_5, chan_index_5, false);
+			qdf_mem_copy(&pcl_channels[num_channels],
+			sbs_channel_list, sbs_num_channels);
+			*len += sbs_num_channels;
+		}
+		policy_mgr_get_connection_channels(psoc,
+			channel_list, &num_channels, POLICY_MGR_PCL_ORDER_NONE,
+			skip_dfs_channel, pcl_weights, weight_len, &i,
+			POLICY_MGR_PCL_GROUP_ID2_ID3);
+		qdf_mem_copy(&pcl_channels[chan_index_24],
+			channel_list, num_channels);
+		*len += num_channels;
+		status = QDF_STATUS_SUCCESS;
+		break;
+	case PM_SBS_CH_5G:
+		if (policy_mgr_is_hw_sbs_capable(psoc)) {
+			policy_mgr_get_sbs_channels(
+			sbs_channel_list, &sbs_num_channels, pcl_weights,
+			weight_len, &i, POLICY_MGR_PCL_GROUP_ID1_ID2,
+			channel_list_5, chan_index_5, true);
+			qdf_mem_copy(&pcl_channels[num_channels],
+			sbs_channel_list, sbs_num_channels);
+			*len += sbs_num_channels;
+		} else {
+			qdf_mem_copy(pcl_channels, channel_list_5,
+			chan_index_5);
+			*len = chan_index_5;
+			for (i = 0; ((i < *len) && (i < weight_len)); i++)
+				pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS;
+		}
+		status = QDF_STATUS_SUCCESS;
+		break;
+	default:
+		policy_mgr_err("unknown pcl value %d", pcl);
+		break;
+	}
+
+	if ((*len != 0) && (*len != i))
+		policy_mgr_debug("pcl len (%d) and weight list len mismatch (%d)",
+			*len, i);
+
+	/* check the channel avoidance list for beaconing entities */
+	if ((mode == PM_SAP_MODE) || (mode == PM_P2P_GO_MODE))
+		policy_mgr_update_with_safe_channel_list(psoc, pcl_channels,
+							 len, pcl_weights,
+							 weight_len);
+
+	policy_mgr_set_weight_of_dfs_passive_channels_to_zero(psoc,
+			pcl_channels, len, pcl_weights, weight_len);
+	return status;
+}
+
+/**
+ * policy_mgr_disallow_mcc() - Check for mcc
+ *
+ * @channel: channel on which new connection is coming up
+ *
+ * When a new connection is about to come up check if current
+ * concurrency combination including the new connection is
+ * causing MCC
+ *
+ * Return: True/False
+ */
+bool policy_mgr_disallow_mcc(struct wlan_objmgr_psoc *psoc,
+		uint8_t channel)
+{
+	uint32_t index = 0;
+	bool match = false;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return match;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	while (PM_CONC_CONNECTION_LIST_VALID_INDEX(index)) {
+		if (policy_mgr_is_hw_dbs_capable(psoc) == false) {
+			if (pm_conc_connection_list[index].chan !=
+				channel) {
+				match = true;
+				break;
+			}
+		} else if (WLAN_REG_IS_5GHZ_CH
+			(pm_conc_connection_list[index].chan)) {
+			if (pm_conc_connection_list[index].chan != channel) {
+				match = true;
+				break;
+			}
+		}
+		index++;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return match;
+}
+
+/**
+ * policy_mgr_allow_new_home_channel() - Check for allowed number of
+ * home channels
+ * @channel: channel on which new connection is coming up
+ * @num_connections: number of current connections
+ *
+ * When a new connection is about to come up check if current
+ * concurrency combination including the new connection is
+ * allowed or not based on the HW capability
+ *
+ * Return: True/False
+ */
+bool policy_mgr_allow_new_home_channel(struct wlan_objmgr_psoc *psoc,
+			uint8_t channel, uint32_t num_connections)
+{
+	bool status = true;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t mcc_to_scc_switch;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+	mcc_to_scc_switch =
+		policy_mgr_get_mcc_to_scc_switch_mode(psoc);
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (num_connections == 2) {
+	/* No SCC or MCC combination is allowed with / on DFS channel */
+		if ((mcc_to_scc_switch ==
+		QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION)
+		&& wlan_reg_is_dfs_ch(pm_ctx->pdev, channel) &&
+		(wlan_reg_is_dfs_ch(pm_ctx->pdev,
+			pm_conc_connection_list[0].chan) ||
+		wlan_reg_is_dfs_ch(pm_ctx->pdev,
+			pm_conc_connection_list[1].chan))) {
+
+			policy_mgr_err("Existing DFS connection, new 3-port DFS connection is not allowed");
+			status = false;
+
+		} else if (((pm_conc_connection_list[0].chan !=
+				pm_conc_connection_list[1].chan)
+		|| (mcc_to_scc_switch ==
+		QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION)
+		) && (pm_conc_connection_list[0].mac ==
+			pm_conc_connection_list[1].mac)) {
+			if (policy_mgr_is_hw_dbs_capable(psoc) == false) {
+				if ((channel !=
+				     pm_conc_connection_list[0].chan) &&
+				    (channel !=
+				     pm_conc_connection_list[1].chan)) {
+					policy_mgr_err("don't allow 3rd home channel on same MAC");
+					status = false;
+				}
+			} else if (((WLAN_REG_IS_24GHZ_CH(channel)) &&
+				(WLAN_REG_IS_24GHZ_CH
+				(pm_conc_connection_list[0].chan)) &&
+				(WLAN_REG_IS_24GHZ_CH
+				(pm_conc_connection_list[1].chan))) ||
+				   ((WLAN_REG_IS_5GHZ_CH(channel)) &&
+				(WLAN_REG_IS_5GHZ_CH
+				(pm_conc_connection_list[0].chan)) &&
+				(WLAN_REG_IS_5GHZ_CH
+				(pm_conc_connection_list[1].chan)))) {
+					policy_mgr_err("don't allow 3rd home channel on same MAC");
+					status = false;
+			}
+		}
+	} else if ((num_connections == 1)
+		&& (mcc_to_scc_switch ==
+		QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION)
+		&& wlan_reg_is_dfs_ch(pm_ctx->pdev, channel)
+		&& wlan_reg_is_dfs_ch(pm_ctx->pdev,
+			pm_conc_connection_list[0].chan)) {
+
+		policy_mgr_err("Existing DFS connection, new 2-port DFS connection is not allowed");
+		status = false;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return status;
+}
+
+/**
+ * policy_mgr_is_5g_channel_allowed() - check if 5g channel is allowed
+ * @channel: channel number which needs to be validated
+ * @list: list of existing connections.
+ * @mode: mode against which channel needs to be validated
+ *
+ * This API takes the channel as input and compares with existing
+ * connection channels. If existing connection's channel is DFS channel
+ * and provided channel is 5G channel then don't allow concurrency to
+ * happen as MCC with DFS channel is not yet supported
+ *
+ * Return: true if 5G channel is allowed, false if not allowed
+ *
+ */
+bool policy_mgr_is_5g_channel_allowed(struct wlan_objmgr_psoc *psoc,
+				uint8_t channel, uint32_t *list,
+				enum policy_mgr_con_mode mode)
+{
+	uint32_t index = 0, count = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	count = policy_mgr_mode_specific_connection_count(psoc, mode, list);
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	while (index < count) {
+		if (wlan_reg_is_dfs_ch(
+			pm_ctx->pdev,
+			pm_conc_connection_list[list[index]].chan) &&
+		    WLAN_REG_IS_5GHZ_CH(channel) &&
+		    (channel != pm_conc_connection_list[list[index]].chan)) {
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+			policy_mgr_err("don't allow MCC if SAP/GO on DFS channel");
+			return false;
+		}
+		index++;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return true;
+}
+
+/**
+ * policy_mgr_nss_update_cb() - callback from SME confirming nss
+ * update
+ * @hdd_ctx:	HDD Context
+ * @tx_status: tx completion status for updated beacon with new
+ *		nss value
+ * @vdev_id: vdev id for the specific connection
+ * @next_action: next action to happen at policy mgr after
+ *		beacon update
+ * @reason: Reason for nss update
+ * @original_vdev_id: original request hwmode change vdev id
+ *
+ * This function is the callback registered with SME at nss
+ * update request time
+ *
+ * Return: None
+ */
+static void policy_mgr_nss_update_cb(struct wlan_objmgr_psoc *psoc,
+		uint8_t tx_status,
+		uint8_t vdev_id,
+		uint8_t next_action,
+		enum policy_mgr_conn_update_reason reason,
+		uint32_t original_vdev_id)
+{
+	uint32_t conn_index = 0;
+	QDF_STATUS ret;
+
+	if (QDF_STATUS_SUCCESS != tx_status)
+		policy_mgr_err("nss update failed(%d) for vdev %d",
+			tx_status, vdev_id);
+
+	/*
+	 * Check if we are ok to request for HW mode change now
+	 */
+	conn_index = policy_mgr_get_connection_for_vdev_id(psoc, vdev_id);
+	if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) {
+		policy_mgr_err("connection not found for vdev %d", vdev_id);
+		return;
+	}
+
+	policy_mgr_debug("nss update successful for vdev:%d ori %d reason %d",
+			 vdev_id, original_vdev_id, reason);
+	if (PM_NOP != next_action)
+		policy_mgr_next_actions(psoc, original_vdev_id, next_action,
+					reason);
+	else {
+		policy_mgr_debug("No action needed right now");
+		ret = policy_mgr_set_opportunistic_update(psoc);
+		if (!QDF_IS_STATUS_SUCCESS(ret))
+			policy_mgr_err("ERROR: set opportunistic_update event failed");
+	}
+
+	return;
+}
+
+QDF_STATUS policy_mgr_nss_update(struct wlan_objmgr_psoc *psoc,
+		uint8_t  new_nss, uint8_t next_action,
+		enum policy_mgr_band band,
+		enum policy_mgr_conn_update_reason reason,
+		uint32_t original_vdev_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint32_t index, count;
+	uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint32_t conn_index = 0;
+	uint32_t vdev_id;
+	uint32_t original_nss;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint8_t chan;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+
+	count = policy_mgr_mode_specific_connection_count(psoc,
+			PM_P2P_GO_MODE, list);
+	for (index = 0; index < count; index++) {
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		vdev_id = pm_conc_connection_list[list[index]].vdev_id;
+		original_nss =
+		pm_conc_connection_list[list[index]].original_nss;
+		chan = pm_conc_connection_list[list[index]].chan;
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		conn_index = policy_mgr_get_connection_for_vdev_id(
+			psoc, vdev_id);
+		if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) {
+			policy_mgr_err("connection not found for vdev %d",
+				vdev_id);
+			continue;
+		}
+
+		if (original_nss == 2 &&
+		    (band == POLICY_MGR_ANY ||
+		    (band == POLICY_MGR_BAND_24 &&
+		    WLAN_REG_IS_24GHZ_CH(chan)) ||
+		    (band == POLICY_MGR_BAND_5 &&
+		    WLAN_REG_IS_5GHZ_CH(chan)))) {
+			status = pm_ctx->sme_cbacks.sme_nss_update_request(
+					vdev_id, new_nss,
+					policy_mgr_nss_update_cb,
+					next_action, psoc, reason,
+					original_vdev_id);
+			if (!QDF_IS_STATUS_SUCCESS(status)) {
+				policy_mgr_err("sme_nss_update_request() failed for vdev %d",
+				vdev_id);
+			}
+		}
+	}
+
+	count = policy_mgr_mode_specific_connection_count(psoc,
+			PM_SAP_MODE, list);
+	for (index = 0; index < count; index++) {
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		vdev_id = pm_conc_connection_list[list[index]].vdev_id;
+		original_nss =
+		pm_conc_connection_list[list[index]].original_nss;
+		chan = pm_conc_connection_list[list[index]].chan;
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		conn_index = policy_mgr_get_connection_for_vdev_id(
+			psoc, vdev_id);
+		if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) {
+			policy_mgr_err("connection not found for vdev %d",
+				vdev_id);
+			continue;
+		}
+		if (original_nss == 2 &&
+		    (band == POLICY_MGR_ANY ||
+		    (band == POLICY_MGR_BAND_24 &&
+		    WLAN_REG_IS_24GHZ_CH(chan)) ||
+		    (band == POLICY_MGR_BAND_5 &&
+		    WLAN_REG_IS_5GHZ_CH(chan)))) {
+			status = pm_ctx->sme_cbacks.sme_nss_update_request(
+					vdev_id, new_nss,
+					policy_mgr_nss_update_cb,
+					next_action, psoc, reason,
+					original_vdev_id);
+			if (!QDF_IS_STATUS_SUCCESS(status)) {
+				policy_mgr_err("sme_nss_update_request() failed for vdev %d",
+				vdev_id);
+			}
+		}
+	}
+
+	return status;
+}
+
+/**
+ * policy_mgr_complete_action() - initiates actions needed on
+ * current connections once channel has been decided for the new
+ * connection
+ * @new_nss: the new nss value
+ * @next_action: next action to happen at policy mgr after
+ *		beacon update
+ * @reason: Reason for connection update
+ * @session_id: Session id
+ *
+ * This function initiates initiates actions
+ * needed on current connections once channel has been decided
+ * for the new connection. Notifies UMAC & FW as well
+ *
+ * Return: QDF_STATUS enum
+ */
+QDF_STATUS policy_mgr_complete_action(struct wlan_objmgr_psoc *psoc,
+				uint8_t  new_nss, uint8_t next_action,
+				enum policy_mgr_conn_update_reason reason,
+				uint32_t session_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	enum policy_mgr_band downgrade_band;
+
+	if (policy_mgr_is_hw_dbs_capable(psoc) == false) {
+		policy_mgr_err("driver isn't dbs capable, no further action needed");
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+
+	/* policy_mgr_complete_action() is called by policy_mgr_next_actions().
+	 * All other callers of policy_mgr_next_actions() have taken mutex
+	 * protection. So, not taking any lock inside
+	 * policy_mgr_complete_action() during pm_conc_connection_list access.
+	 */
+	if (next_action == PM_DBS1)
+		downgrade_band = POLICY_MGR_BAND_24;
+	else if (next_action == PM_DBS2)
+		downgrade_band = POLICY_MGR_BAND_5;
+	else
+		downgrade_band = POLICY_MGR_ANY;
+
+	status = policy_mgr_nss_update(psoc, new_nss, next_action,
+				       downgrade_band, reason,
+				       session_id);
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		status = policy_mgr_next_actions(psoc, session_id,
+						next_action, reason);
+
+	return status;
+}
+
+enum policy_mgr_con_mode policy_mgr_get_mode_by_vdev_id(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t vdev_id)
+{
+	enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t conn_index;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return mode;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		conn_index++)
+		if ((pm_conc_connection_list[conn_index].vdev_id == vdev_id) &&
+			pm_conc_connection_list[conn_index].in_use){
+				mode = pm_conc_connection_list[conn_index].mode;
+				break;
+		}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return mode;
+}
+
+/**
+ * policy_mgr_init_connection_update() - Initialize connection
+ * update event
+ * @pm_ctx: policy mgr context
+ *
+ * Initializes the concurrent connection update event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_init_connection_update(
+		struct policy_mgr_psoc_priv_obj *pm_ctx)
+{
+	QDF_STATUS qdf_status;
+
+	qdf_status = qdf_event_create(&pm_ctx->connection_update_done_evt);
+
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		policy_mgr_err("init event failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * policy_mgr_get_current_pref_hw_mode_dbs_2x2() - Get the
+ * current preferred hw mode
+ *
+ * Get the preferred hw mode based on the current connection combinations
+ *
+ * Return: No change (PM_NOP), MCC (PM_SINGLE_MAC),
+ *         DBS (PM_DBS), SBS (PM_SBS)
+ */
+enum policy_mgr_conc_next_action
+		policy_mgr_get_current_pref_hw_mode_dbs_2x2(
+		struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t num_connections;
+	uint8_t band1, band2, band3;
+	struct policy_mgr_hw_mode_params hw_mode;
+	QDF_STATUS status;
+
+	status = policy_mgr_get_current_hw_mode(psoc, &hw_mode);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("policy_mgr_get_current_hw_mode failed");
+		return PM_NOP;
+	}
+
+	num_connections = policy_mgr_get_connection_count(psoc);
+
+	policy_mgr_debug("chan[0]:%d chan[1]:%d chan[2]:%d num_connections:%d dbs:%d",
+		pm_conc_connection_list[0].chan,
+		pm_conc_connection_list[1].chan,
+		pm_conc_connection_list[2].chan, num_connections,
+		hw_mode.dbs_cap);
+
+	/* If the band of operation of both the MACs is the same,
+	 * single MAC is preferred, otherwise DBS is preferred.
+	 */
+	switch (num_connections) {
+	case 1:
+		band1 = reg_chan_to_band(pm_conc_connection_list[0].chan);
+		if (band1 == BAND_2G)
+			return PM_DBS;
+		else
+			return PM_NOP;
+	case 2:
+		band1 = reg_chan_to_band(pm_conc_connection_list[0].chan);
+		band2 = reg_chan_to_band(pm_conc_connection_list[1].chan);
+		if ((band1 == BAND_2G) ||
+			(band2 == BAND_2G)) {
+			if (!hw_mode.dbs_cap)
+				return PM_DBS;
+			else
+				return PM_NOP;
+		} else if ((band1 == BAND_5G) &&
+				(band2 == BAND_5G)) {
+			if (WLAN_REG_IS_CHANNEL_VALID_5G_SBS(
+				pm_conc_connection_list[0].chan,
+				pm_conc_connection_list[1].chan)) {
+				if (!hw_mode.sbs_cap)
+					return PM_SBS;
+				else
+					return PM_NOP;
+			} else {
+				if (hw_mode.sbs_cap || hw_mode.dbs_cap)
+					return PM_SINGLE_MAC;
+				else
+					return PM_NOP;
+			}
+		} else
+			return PM_NOP;
+	case 3:
+		band1 = reg_chan_to_band(pm_conc_connection_list[0].chan);
+		band2 = reg_chan_to_band(pm_conc_connection_list[1].chan);
+		band3 = reg_chan_to_band(pm_conc_connection_list[2].chan);
+		if ((band1 == BAND_2G) ||
+			(band2 == BAND_2G) ||
+			(band3 == BAND_2G)) {
+			if (!hw_mode.dbs_cap)
+				return PM_DBS;
+			else
+				return PM_NOP;
+		} else if ((band1 == BAND_5G) &&
+				(band2 == BAND_5G) &&
+					(band3 == BAND_5G)) {
+			if (WLAN_REG_IS_CHANNEL_VALID_5G_SBS(
+				pm_conc_connection_list[0].chan,
+				pm_conc_connection_list[2].chan) &&
+				WLAN_REG_IS_CHANNEL_VALID_5G_SBS(
+				pm_conc_connection_list[1].chan,
+				pm_conc_connection_list[2].chan) &&
+				WLAN_REG_IS_CHANNEL_VALID_5G_SBS(
+				pm_conc_connection_list[0].chan,
+				pm_conc_connection_list[1].chan)) {
+				if (!hw_mode.sbs_cap)
+					return PM_SBS;
+				else
+					return PM_NOP;
+			} else {
+				if (hw_mode.sbs_cap || hw_mode.dbs_cap)
+					return PM_SINGLE_MAC;
+				else
+					return PM_NOP;
+			}
+		} else
+			return PM_NOP;
+	default:
+		policy_mgr_err("unexpected num_connections value %d",
+				num_connections);
+		return PM_NOP;
+	}
+}
+
+/**
+ * policy_mgr_get_current_pref_hw_mode_dbs_1x1() - Get the
+ * current preferred hw mode
+ *
+ * Get the preferred hw mode based on the current connection combinations
+ *
+ * Return: No change (PM_NOP), MCC (PM_SINGLE_MAC_UPGRADE),
+ *         DBS (PM_DBS_DOWNGRADE)
+ */
+enum policy_mgr_conc_next_action
+		policy_mgr_get_current_pref_hw_mode_dbs_1x1(
+		struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t num_connections;
+	uint8_t band1, band2, band3;
+	struct policy_mgr_hw_mode_params hw_mode;
+	QDF_STATUS status;
+	enum policy_mgr_conc_next_action next_action;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return PM_NOP;
+	}
+
+	status = policy_mgr_get_current_hw_mode(psoc, &hw_mode);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("policy_mgr_get_current_hw_mode failed");
+		return PM_NOP;
+	}
+
+	num_connections = policy_mgr_get_connection_count(psoc);
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	policy_mgr_debug("chan[0]:%d chan[1]:%d chan[2]:%d num_connections:%d dbs:%d",
+		pm_conc_connection_list[0].chan,
+		pm_conc_connection_list[1].chan,
+		pm_conc_connection_list[2].chan, num_connections,
+		hw_mode.dbs_cap);
+
+	/* If the band of operation of both the MACs is the same,
+	 * single MAC is preferred, otherwise DBS is preferred.
+	 */
+	switch (num_connections) {
+	case 1:
+		/* The driver would already be in the required hw mode */
+		next_action = PM_NOP;
+		break;
+	case 2:
+		band1 = reg_chan_to_band(pm_conc_connection_list[0].chan);
+		band2 = reg_chan_to_band(pm_conc_connection_list[1].chan);
+		if ((band1 == band2) && (hw_mode.dbs_cap))
+			next_action = PM_SINGLE_MAC_UPGRADE;
+		else if ((band1 != band2) && (!hw_mode.dbs_cap))
+			next_action = PM_DBS_DOWNGRADE;
+		else
+			next_action = PM_NOP;
+
+		break;
+
+	case 3:
+		band1 = reg_chan_to_band(pm_conc_connection_list[0].chan);
+		band2 = reg_chan_to_band(pm_conc_connection_list[1].chan);
+		band3 = reg_chan_to_band(pm_conc_connection_list[2].chan);
+		if (((band1 == band2) && (band2 == band3)) &&
+				(hw_mode.dbs_cap)) {
+			next_action = PM_SINGLE_MAC_UPGRADE;
+		} else if (((band1 != band2) || (band2 != band3) ||
+					(band1 != band3)) &&
+					(!hw_mode.dbs_cap)) {
+			next_action = PM_DBS_DOWNGRADE;
+		} else {
+			next_action = PM_NOP;
+		}
+		break;
+	default:
+		policy_mgr_err("unexpected num_connections value %d",
+				num_connections);
+		next_action = PM_NOP;
+		break;
+	}
+
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return next_action;
+}
+
+enum policy_mgr_conc_next_action
+policy_mgr_get_current_pref_hw_mode_dual_dbs(
+	struct wlan_objmgr_psoc *psoc)
+{
+	enum policy_mgr_conc_next_action next_action;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	enum policy_mgr_conc_next_action preferred_dbs;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return PM_NOP;
+	}
+
+	next_action = policy_mgr_get_current_pref_hw_mode_dbs_1x1(psoc);
+	policy_mgr_info("next_action %d", next_action);
+	if (next_action != PM_DBS_DOWNGRADE)
+		return next_action;
+
+	preferred_dbs = policy_mgr_get_preferred_dbs_action_table(
+				psoc, INVALID_VDEV_ID, 0, 0);
+	if (preferred_dbs == PM_DBS1) {
+		next_action = PM_DBS1_DOWNGRADE;
+	} else if (preferred_dbs == PM_DBS2) {
+		next_action = PM_DBS2_DOWNGRADE;
+	} else {
+		policy_mgr_err("DBS1 and DBS2 hw mode not supported");
+		return PM_NOP;
+	}
+	policy_mgr_info("preferred_dbs %d", next_action);
+	return next_action;
+}
+
+/**
+ * policy_mgr_reset_sap_mandatory_channels() - Reset the SAP mandatory channels
+ *
+ * Resets the SAP mandatory channel list and the length of the list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_reset_sap_mandatory_channels(
+		struct policy_mgr_psoc_priv_obj *pm_ctx)
+{
+	pm_ctx->sap_mandatory_channels_len = 0;
+	qdf_mem_zero(pm_ctx->sap_mandatory_channels,
+		QDF_ARRAY_SIZE(pm_ctx->sap_mandatory_channels));
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void policy_mgr_enable_disable_sap_mandatory_chan_list(
+		struct wlan_objmgr_psoc *psoc, bool val)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	pm_ctx->enable_sap_mandatory_chan_list = val;
+}
+
+void policy_mgr_add_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc,
+		uint8_t chan)
+{
+	int i;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	for (i = 0; i < pm_ctx->sap_mandatory_channels_len; i++) {
+		if (chan == pm_ctx->sap_mandatory_channels[i])
+			return;
+	}
+
+	policy_mgr_debug("chan %hu", chan);
+	pm_ctx->sap_mandatory_channels[pm_ctx->sap_mandatory_channels_len++]
+		= chan;
+}
+
+bool policy_mgr_is_sap_mandatory_chan_list_enabled(
+		struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	return pm_ctx->enable_sap_mandatory_chan_list;
+}
+
+uint32_t policy_mgr_get_sap_mandatory_chan_list_len(
+		struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return 0;
+	}
+
+	return pm_ctx->sap_mandatory_channels_len;
+}
+
+void  policy_mgr_init_sap_mandatory_2g_chan(struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t chan_list[QDF_MAX_NUM_CHAN] = {0};
+	uint32_t len = 0;
+	int i;
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	status = policy_mgr_get_valid_chans(psoc, chan_list, &len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("Error in getting valid channels");
+		return;
+	}
+	pm_ctx->sap_mandatory_channels_len = 0;
+
+	for (i = 0; (i < len) && (i < QDF_MAX_NUM_CHAN); i++) {
+		if (WLAN_REG_IS_24GHZ_CH(chan_list[i])) {
+			policy_mgr_debug("Add chan %hu to mandatory list",
+					chan_list[i]);
+			pm_ctx->sap_mandatory_channels[
+				pm_ctx->sap_mandatory_channels_len++] =
+				chan_list[i];
+		}
+	}
+}
+
+void policy_mgr_remove_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc,
+		uint8_t chan)
+{
+	uint8_t chan_list[QDF_MAX_NUM_CHAN] = {0};
+	uint32_t num_chan = 0;
+	int i;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	if (pm_ctx->sap_mandatory_channels_len >= QDF_MAX_NUM_CHAN) {
+		policy_mgr_err("Invalid channel len %d ",
+				pm_ctx->sap_mandatory_channels_len);
+		return;
+	}
+
+	for (i = 0; i < pm_ctx->sap_mandatory_channels_len; i++) {
+		if (chan == pm_ctx->sap_mandatory_channels[i])
+			continue;
+		chan_list[num_chan++] = pm_ctx->sap_mandatory_channels[i];
+	}
+
+	qdf_mem_zero(pm_ctx->sap_mandatory_channels,
+			pm_ctx->sap_mandatory_channels_len);
+	qdf_mem_copy(pm_ctx->sap_mandatory_channels, chan_list, num_chan);
+	pm_ctx->sap_mandatory_channels_len = num_chan;
+}

+ 3463 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c

@@ -0,0 +1,3463 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_policy_mgr_get_set_utils.c
+ *
+ * WLAN Concurrenct Connection Management APIs
+ *
+ */
+
+/* Include files */
+#include "target_if.h"
+#include "wlan_policy_mgr_api.h"
+#include "wlan_policy_mgr_i.h"
+#include "qdf_types.h"
+#include "qdf_trace.h"
+#include "wlan_objmgr_global_obj.h"
+#include "wlan_objmgr_pdev_obj.h"
+#include "wlan_objmgr_vdev_obj.h"
+
+/* invalid channel id. */
+#define INVALID_CHANNEL_ID 0
+
+QDF_STATUS policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc,
+					      uint8_t *mcc_scc_switch)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*mcc_scc_switch = pm_ctx->cfg.mcc_to_scc_switch;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_sys_pref(struct wlan_objmgr_psoc *psoc,
+					uint8_t *sys_pref)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*sys_pref = pm_ctx->cfg.sys_pref;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_set_sys_pref(struct wlan_objmgr_psoc *psoc,
+				   uint8_t sys_pref)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	pm_ctx->cfg.sys_pref = sys_pref;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_max_conc_cxns(struct wlan_objmgr_psoc *psoc,
+						uint8_t *max_conc_cxns)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*max_conc_cxns = pm_ctx->cfg.max_conc_cxns;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_conc_rule1(struct wlan_objmgr_psoc *psoc,
+						uint8_t *conc_rule1)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*conc_rule1 = pm_ctx->cfg.conc_rule1;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_conc_rule2(struct wlan_objmgr_psoc *psoc,
+						uint8_t *conc_rule2)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*conc_rule2 = pm_ctx->cfg.conc_rule2;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_dbs_selection_plcy(struct wlan_objmgr_psoc *psoc,
+						uint32_t *dbs_selection_plcy)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*dbs_selection_plcy = pm_ctx->cfg.dbs_selection_plcy;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_vdev_priority_list(struct wlan_objmgr_psoc *psoc,
+						uint32_t *vdev_priority_list)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*vdev_priority_list = pm_ctx->cfg.vdev_priority_list;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_chnl_select_plcy(struct wlan_objmgr_psoc *psoc,
+						uint32_t *chnl_select_plcy)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*chnl_select_plcy = pm_ctx->cfg.chnl_select_plcy;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+
+QDF_STATUS policy_mgr_get_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc,
+					   uint8_t *enable_mcc_adaptive_sch)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*enable_mcc_adaptive_sch = pm_ctx->cfg.enable_mcc_adaptive_sch;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_sta_cxn_5g_band(struct wlan_objmgr_psoc *psoc,
+					  uint8_t *enable_sta_cxn_5g_band)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*enable_sta_cxn_5g_band = pm_ctx->cfg.enable_sta_cxn_5g_band;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void policy_mgr_update_new_hw_mode_index(struct wlan_objmgr_psoc *psoc,
+		uint32_t new_hw_mode_index)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+	pm_ctx->new_hw_mode_index = new_hw_mode_index;
+}
+
+void policy_mgr_update_old_hw_mode_index(struct wlan_objmgr_psoc *psoc,
+		uint32_t old_hw_mode_index)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+	pm_ctx->old_hw_mode_index = old_hw_mode_index;
+}
+
+void policy_mgr_update_hw_mode_index(struct wlan_objmgr_psoc *psoc,
+		uint32_t new_hw_mode_index)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+	if (POLICY_MGR_DEFAULT_HW_MODE_INDEX == pm_ctx->new_hw_mode_index) {
+		pm_ctx->new_hw_mode_index = new_hw_mode_index;
+	} else {
+		pm_ctx->old_hw_mode_index = pm_ctx->new_hw_mode_index;
+		pm_ctx->new_hw_mode_index = new_hw_mode_index;
+	}
+	policy_mgr_debug("Updated: old_hw_mode_index:%d new_hw_mode_index:%d",
+		pm_ctx->old_hw_mode_index, pm_ctx->new_hw_mode_index);
+}
+
+/**
+ * policy_mgr_get_num_of_setbits_from_bitmask() - to get num of
+ * setbits from bitmask
+ * @mask: given bitmask
+ *
+ * This helper function should return number of setbits from bitmask
+ *
+ * Return: number of setbits from bitmask
+ */
+static uint32_t policy_mgr_get_num_of_setbits_from_bitmask(uint32_t mask)
+{
+	uint32_t num_of_setbits = 0;
+
+	while (mask) {
+		mask &= (mask - 1);
+		num_of_setbits++;
+	}
+	return num_of_setbits;
+}
+
+/**
+ * policy_mgr_map_wmi_channel_width_to_hw_mode_bw() - returns
+ * bandwidth in terms of hw_mode_bandwidth
+ * @width: bandwidth in terms of wmi_channel_width
+ *
+ * This function returns the bandwidth in terms of hw_mode_bandwidth.
+ *
+ * Return: BW in terms of hw_mode_bandwidth.
+ */
+static enum hw_mode_bandwidth policy_mgr_map_wmi_channel_width_to_hw_mode_bw(
+		wmi_channel_width width)
+{
+	switch (width) {
+	case WMI_CHAN_WIDTH_20:
+		return HW_MODE_20_MHZ;
+	case WMI_CHAN_WIDTH_40:
+		return HW_MODE_40_MHZ;
+	case WMI_CHAN_WIDTH_80:
+		return HW_MODE_80_MHZ;
+	case WMI_CHAN_WIDTH_160:
+		return HW_MODE_160_MHZ;
+	case WMI_CHAN_WIDTH_80P80:
+		return HW_MODE_80_PLUS_80_MHZ;
+	case WMI_CHAN_WIDTH_5:
+		return HW_MODE_5_MHZ;
+	case WMI_CHAN_WIDTH_10:
+		return HW_MODE_10_MHZ;
+	default:
+		return HW_MODE_BW_NONE;
+	}
+
+	return HW_MODE_BW_NONE;
+}
+
+static void policy_mgr_get_hw_mode_params(
+		struct wlan_psoc_host_mac_phy_caps *caps,
+		struct policy_mgr_mac_ss_bw_info *info)
+{
+	if (!caps) {
+		policy_mgr_err("Invalid capabilities");
+		return;
+	}
+
+	info->mac_tx_stream = policy_mgr_get_num_of_setbits_from_bitmask(
+		QDF_MAX(caps->tx_chain_mask_2G,
+		caps->tx_chain_mask_5G));
+	info->mac_rx_stream = policy_mgr_get_num_of_setbits_from_bitmask(
+		QDF_MAX(caps->rx_chain_mask_2G,
+		caps->rx_chain_mask_5G));
+	info->mac_bw = policy_mgr_map_wmi_channel_width_to_hw_mode_bw(
+		QDF_MAX(caps->max_bw_supported_2G,
+		caps->max_bw_supported_5G));
+	info->mac_band_cap = caps->supported_bands;
+}
+
+/**
+ * policy_mgr_set_hw_mode_params() - sets TX-RX stream,
+ * bandwidth and DBS in hw_mode_list
+ * @wma_handle: pointer to wma global structure
+ * @mac0_ss_bw_info: TX-RX streams, BW for MAC0
+ * @mac1_ss_bw_info: TX-RX streams, BW for MAC1
+ * @pos: refers to hw_mode_list array index
+ * @hw_mode_id: hw mode id value used by firmware
+ * @dbs_mode: dbs_mode for the dbs_hw_mode
+ * @sbs_mode: sbs_mode for the sbs_hw_mode
+ *
+ * This function sets TX-RX stream, bandwidth and DBS mode in
+ * hw_mode_list.
+ *
+ * Return: none
+ */
+static void policy_mgr_set_hw_mode_params(struct wlan_objmgr_psoc *psoc,
+			struct policy_mgr_mac_ss_bw_info mac0_ss_bw_info,
+			struct policy_mgr_mac_ss_bw_info mac1_ss_bw_info,
+			uint32_t pos, uint32_t hw_mode_id, uint32_t dbs_mode,
+			uint32_t sbs_mode)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		mac0_ss_bw_info.mac_tx_stream);
+	POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		mac0_ss_bw_info.mac_rx_stream);
+	POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		mac0_ss_bw_info.mac_bw);
+	POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		mac1_ss_bw_info.mac_tx_stream);
+	POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		mac1_ss_bw_info.mac_rx_stream);
+	POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		mac1_ss_bw_info.mac_bw);
+	POLICY_MGR_HW_MODE_DBS_MODE_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		dbs_mode);
+	POLICY_MGR_HW_MODE_AGILE_DFS_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		HW_MODE_AGILE_DFS_NONE);
+	POLICY_MGR_HW_MODE_SBS_MODE_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		sbs_mode);
+	POLICY_MGR_HW_MODE_MAC0_BAND_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		mac0_ss_bw_info.mac_band_cap);
+	POLICY_MGR_HW_MODE_ID_SET(
+		pm_ctx->hw_mode.hw_mode_list[pos],
+		hw_mode_id);
+}
+
+QDF_STATUS policy_mgr_update_hw_mode_list(struct wlan_objmgr_psoc *psoc,
+					  struct target_psoc_info *tgt_hdl)
+{
+	struct wlan_psoc_host_mac_phy_caps *tmp;
+	uint32_t i, hw_config_type, j = 0;
+	uint32_t dbs_mode, sbs_mode;
+	struct policy_mgr_mac_ss_bw_info mac0_ss_bw_info = {0};
+	struct policy_mgr_mac_ss_bw_info mac1_ss_bw_info = {0};
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	struct tgt_info *info;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	info = &tgt_hdl->info;
+	if (!info->service_ext_param.num_hw_modes) {
+		policy_mgr_err("Number of HW modes: %d",
+			       info->service_ext_param.num_hw_modes);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/*
+	 * This list was updated as part of service ready event. Re-populate
+	 * HW mode list from the device capabilities.
+	 */
+	if (pm_ctx->hw_mode.hw_mode_list) {
+		qdf_mem_free(pm_ctx->hw_mode.hw_mode_list);
+		pm_ctx->hw_mode.hw_mode_list = NULL;
+		policy_mgr_debug("DBS list is freed");
+	}
+
+	pm_ctx->num_dbs_hw_modes = info->service_ext_param.num_hw_modes;
+	pm_ctx->hw_mode.hw_mode_list =
+		qdf_mem_malloc(sizeof(*pm_ctx->hw_mode.hw_mode_list) *
+		pm_ctx->num_dbs_hw_modes);
+	if (!pm_ctx->hw_mode.hw_mode_list) {
+		policy_mgr_err("Memory allocation failed for DBS");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	policy_mgr_debug("Updated HW mode list: Num modes:%d",
+		pm_ctx->num_dbs_hw_modes);
+
+	for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) {
+		/* Update for MAC0 */
+		tmp = &info->mac_phy_cap[j++];
+		policy_mgr_get_hw_mode_params(tmp, &mac0_ss_bw_info);
+		hw_config_type = tmp->hw_mode_config_type;
+		dbs_mode = HW_MODE_DBS_NONE;
+		sbs_mode = HW_MODE_SBS_NONE;
+		mac1_ss_bw_info.mac_tx_stream = 0;
+		mac1_ss_bw_info.mac_rx_stream = 0;
+		mac1_ss_bw_info.mac_bw = 0;
+
+		/* SBS and DBS have dual MAC. Upto 2 MACs are considered. */
+		if ((hw_config_type == WMI_HW_MODE_DBS) ||
+			(hw_config_type == WMI_HW_MODE_SBS_PASSIVE) ||
+			(hw_config_type == WMI_HW_MODE_SBS)) {
+			/* Update for MAC1 */
+			tmp = &info->mac_phy_cap[j++];
+			policy_mgr_get_hw_mode_params(tmp, &mac1_ss_bw_info);
+			if (hw_config_type == WMI_HW_MODE_DBS)
+				dbs_mode = HW_MODE_DBS;
+			if ((hw_config_type == WMI_HW_MODE_SBS_PASSIVE) ||
+				(hw_config_type == WMI_HW_MODE_SBS))
+				sbs_mode = HW_MODE_SBS;
+		}
+
+		/* Updating HW mode list */
+		policy_mgr_set_hw_mode_params(psoc, mac0_ss_bw_info,
+			mac1_ss_bw_info, i, tmp->hw_mode_id, dbs_mode,
+			sbs_mode);
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+void policy_mgr_init_dbs_hw_mode(struct wlan_objmgr_psoc *psoc,
+		uint32_t num_dbs_hw_modes,
+		uint32_t *ev_wlan_dbs_hw_mode_list)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	pm_ctx->num_dbs_hw_modes = num_dbs_hw_modes;
+	pm_ctx->hw_mode.hw_mode_list =
+		qdf_mem_malloc(sizeof(*pm_ctx->hw_mode.hw_mode_list) *
+		pm_ctx->num_dbs_hw_modes);
+	if (!pm_ctx->hw_mode.hw_mode_list) {
+		policy_mgr_err("Memory allocation failed for DBS");
+		return;
+	}
+	qdf_mem_copy(pm_ctx->hw_mode.hw_mode_list,
+		ev_wlan_dbs_hw_mode_list,
+		(sizeof(*pm_ctx->hw_mode.hw_mode_list) *
+		pm_ctx->num_dbs_hw_modes));
+}
+
+void policy_mgr_dump_dbs_hw_mode(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t i, param;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) {
+		param = pm_ctx->hw_mode.hw_mode_list[i];
+		policy_mgr_debug("[%d]-MAC0: tx_ss:%d rx_ss:%d bw_idx:%d band_cap:%d",
+				 i,
+				 POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(param),
+				 POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(param),
+				 POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(param),
+				 POLICY_MGR_HW_MODE_MAC0_BAND_GET(param));
+		policy_mgr_debug("[%d]-MAC1: tx_ss:%d rx_ss:%d bw_idx:%d",
+				 i,
+				 POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(param),
+				 POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(param),
+				 POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET(param));
+		policy_mgr_debug("[%d] DBS:%d SBS:%d hw_mode_id:%d", i,
+				 POLICY_MGR_HW_MODE_DBS_MODE_GET(param),
+				 POLICY_MGR_HW_MODE_SBS_MODE_GET(param),
+				 POLICY_MGR_HW_MODE_ID_GET(param));
+	}
+}
+
+void policy_mgr_init_dbs_config(struct wlan_objmgr_psoc *psoc,
+		uint32_t scan_config, uint32_t fw_config)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+	pm_ctx->dual_mac_cfg.cur_scan_config = 0;
+	pm_ctx->dual_mac_cfg.cur_fw_mode_config = 0;
+
+	/* If dual mac features are disabled in the INI, we
+	 * need not proceed further
+	 */
+	if (DISABLE_DBS_CXN_AND_SCAN ==
+			wlan_objmgr_psoc_get_dual_mac_disable(psoc)) {
+		policy_mgr_err("Disabling dual mac capabilities");
+		/* All capabilities are initialized to 0. We can return */
+		goto done;
+	}
+
+	/* Initialize concurrent_scan_config_bits with default FW value */
+	WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_SET(
+		pm_ctx->dual_mac_cfg.cur_scan_config,
+		WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_GET(scan_config));
+	WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_SET(
+		pm_ctx->dual_mac_cfg.cur_scan_config,
+		WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_GET(scan_config));
+	WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(
+		pm_ctx->dual_mac_cfg.cur_scan_config,
+		WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config));
+	WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(
+		pm_ctx->dual_mac_cfg.cur_scan_config,
+		WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config));
+	WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(
+		pm_ctx->dual_mac_cfg.cur_scan_config,
+		WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config));
+
+	/* Initialize fw_mode_config_bits with default FW value */
+	WMI_DBS_FW_MODE_CFG_DBS_SET(
+		pm_ctx->dual_mac_cfg.cur_fw_mode_config,
+		WMI_DBS_FW_MODE_CFG_DBS_GET(fw_config));
+	WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(
+		pm_ctx->dual_mac_cfg.cur_fw_mode_config,
+		WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_config));
+	WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_SET(
+		pm_ctx->dual_mac_cfg.cur_fw_mode_config,
+		WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_GET(fw_config));
+done:
+	/* Initialize the previous scan/fw mode config */
+	pm_ctx->dual_mac_cfg.prev_scan_config =
+		pm_ctx->dual_mac_cfg.cur_scan_config;
+	pm_ctx->dual_mac_cfg.prev_fw_mode_config =
+		pm_ctx->dual_mac_cfg.cur_fw_mode_config;
+
+	policy_mgr_debug("cur_scan_config:%x cur_fw_mode_config:%x",
+		pm_ctx->dual_mac_cfg.cur_scan_config,
+		pm_ctx->dual_mac_cfg.cur_fw_mode_config);
+}
+
+void policy_mgr_update_dbs_scan_config(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	pm_ctx->dual_mac_cfg.prev_scan_config =
+		pm_ctx->dual_mac_cfg.cur_scan_config;
+	pm_ctx->dual_mac_cfg.cur_scan_config =
+		pm_ctx->dual_mac_cfg.req_scan_config;
+}
+
+void policy_mgr_update_dbs_fw_config(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	pm_ctx->dual_mac_cfg.prev_fw_mode_config =
+		pm_ctx->dual_mac_cfg.cur_fw_mode_config;
+	pm_ctx->dual_mac_cfg.cur_fw_mode_config =
+		pm_ctx->dual_mac_cfg.req_fw_mode_config;
+}
+
+void policy_mgr_update_dbs_req_config(struct wlan_objmgr_psoc *psoc,
+		uint32_t scan_config, uint32_t fw_mode_config)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+	pm_ctx->dual_mac_cfg.req_scan_config = scan_config;
+	pm_ctx->dual_mac_cfg.req_fw_mode_config = fw_mode_config;
+}
+
+bool policy_mgr_get_dbs_plus_agile_scan_config(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t scan_config;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	if (policy_mgr_is_dual_mac_disabled_in_ini(psoc))
+		return false;
+
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		/* We take that it is disabled and proceed */
+		return false;
+	}
+	scan_config = pm_ctx->dual_mac_cfg.cur_scan_config;
+
+	return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config);
+}
+
+bool policy_mgr_get_single_mac_scan_with_dfs_config(
+		struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t scan_config;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	if (policy_mgr_is_dual_mac_disabled_in_ini(psoc))
+		return false;
+
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		/* We take that it is disabled and proceed */
+		return false;
+	}
+	scan_config = pm_ctx->dual_mac_cfg.cur_scan_config;
+
+	return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config);
+}
+
+int8_t policy_mgr_get_num_dbs_hw_modes(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return -EINVAL;
+	}
+	return pm_ctx->num_dbs_hw_modes;
+}
+
+bool policy_mgr_is_hw_dbs_capable(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t param, i, found = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	struct wmi_unified *wmi_handle;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	if (!policy_mgr_is_dbs_enable(psoc)) {
+		policy_mgr_debug("DBS is disabled");
+		return false;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		policy_mgr_debug("Invalid WMI handle");
+		return false;
+	}
+
+	policy_mgr_debug("DBS service bit map: %d",
+		wmi_service_enabled(wmi_handle,
+		wmi_service_dual_band_simultaneous_support));
+
+	/* The agreement with FW is that: To know if the target is DBS
+	 * capable, DBS needs to be supported both in the HW mode list
+	 * and in the service ready event
+	 */
+	if (!(wmi_service_enabled(wmi_handle,
+		wmi_service_dual_band_simultaneous_support)))
+		return false;
+
+	for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) {
+		param = pm_ctx->hw_mode.hw_mode_list[i];
+		policy_mgr_debug("HW param: %x", param);
+		if (POLICY_MGR_HW_MODE_DBS_MODE_GET(param)) {
+			policy_mgr_debug("HW (%d) is DBS capable", i);
+			found = 1;
+			break;
+		}
+	}
+
+	if (found)
+		return true;
+
+	return false;
+}
+
+bool policy_mgr_is_hw_sbs_capable(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t param, i, found = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	struct wmi_unified *wmi_handle;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		policy_mgr_debug("Invalid WMI handle");
+		return false;
+	}
+
+	policy_mgr_debug("DBS service bit map: %d",
+		wmi_service_enabled(wmi_handle,
+		wmi_service_dual_band_simultaneous_support));
+
+	/* The agreement with FW is that: To know if the target is SBS
+	 * capable, SBS needs to be supported both in the HW mode list
+	 * and DBS needs to be supported in the service ready event
+	 */
+	if (!(wmi_service_enabled(wmi_handle,
+		wmi_service_dual_band_simultaneous_support)))
+		return false;
+
+	for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) {
+		param = pm_ctx->hw_mode.hw_mode_list[i];
+		policy_mgr_debug("HW param: %x", param);
+		if (POLICY_MGR_HW_MODE_SBS_MODE_GET(param)) {
+			policy_mgr_debug("HW (%d) is SBS capable", i);
+			found = 1;
+			break;
+		}
+	}
+
+	if (found)
+		return true;
+
+	return false;
+}
+
+QDF_STATUS policy_mgr_get_dbs_hw_modes(struct wlan_objmgr_psoc *psoc,
+		bool *one_by_one_dbs, bool *two_by_two_dbs)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t i;
+	int8_t found_one_by_one = -EINVAL, found_two_by_two = -EINVAL;
+	uint32_t conf1_tx_ss, conf1_rx_ss;
+	uint32_t conf2_tx_ss, conf2_rx_ss;
+
+	*one_by_one_dbs = false;
+	*two_by_two_dbs = false;
+
+	if (policy_mgr_is_hw_dbs_capable(psoc) == false) {
+		policy_mgr_err("HW is not DBS capable");
+		/* Caller will understand that DBS is disabled */
+		return QDF_STATUS_SUCCESS;
+
+	}
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* To check 1x1 capability */
+	policy_mgr_get_tx_rx_ss_from_config(HW_MODE_SS_1x1,
+			&conf1_tx_ss, &conf1_rx_ss);
+	/* To check 2x2 capability */
+	policy_mgr_get_tx_rx_ss_from_config(HW_MODE_SS_2x2,
+			&conf2_tx_ss, &conf2_rx_ss);
+
+	for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) {
+		uint32_t t_conf0_tx_ss, t_conf0_rx_ss;
+		uint32_t t_conf1_tx_ss, t_conf1_rx_ss;
+		uint32_t dbs_mode;
+
+		t_conf0_tx_ss = POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		t_conf0_rx_ss = POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		t_conf1_tx_ss = POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		t_conf1_rx_ss = POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+		dbs_mode = POLICY_MGR_HW_MODE_DBS_MODE_GET(
+				pm_ctx->hw_mode.hw_mode_list[i]);
+
+		if (((((t_conf0_tx_ss == conf1_tx_ss) &&
+		    (t_conf0_rx_ss == conf1_rx_ss)) ||
+		    ((t_conf1_tx_ss == conf1_tx_ss) &&
+		    (t_conf1_rx_ss == conf1_rx_ss))) &&
+		    (dbs_mode == HW_MODE_DBS)) &&
+		    (found_one_by_one < 0)) {
+			found_one_by_one = i;
+			policy_mgr_debug("1x1 hw_mode index %d found", i);
+			/* Once an entry is found, need not check for 1x1
+			 * again
+			 */
+			continue;
+		}
+
+		if (((((t_conf0_tx_ss == conf2_tx_ss) &&
+		    (t_conf0_rx_ss == conf2_rx_ss)) ||
+		    ((t_conf1_tx_ss == conf2_tx_ss) &&
+		    (t_conf1_rx_ss == conf2_rx_ss))) &&
+		    (dbs_mode == HW_MODE_DBS)) &&
+		    (found_two_by_two < 0)) {
+			found_two_by_two = i;
+			policy_mgr_debug("2x2 hw_mode index %d found", i);
+			/* Once an entry is found, need not check for 2x2
+			 * again
+			 */
+			continue;
+		}
+	}
+
+	if (found_one_by_one >= 0)
+		*one_by_one_dbs = true;
+	if (found_two_by_two >= 0)
+		*two_by_two_dbs = true;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_current_hw_mode(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_hw_mode_params *hw_mode)
+{
+	QDF_STATUS status;
+	uint32_t old_hw_index = 0, new_hw_index = 0;
+
+	policy_mgr_debug("Get the current hw mode");
+
+	status = policy_mgr_get_old_and_new_hw_index(psoc, &old_hw_index,
+			&new_hw_index);
+	if (QDF_STATUS_SUCCESS != status) {
+		policy_mgr_err("Failed to get HW mode index");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (new_hw_index == POLICY_MGR_DEFAULT_HW_MODE_INDEX) {
+		policy_mgr_err("HW mode is not yet initialized");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = policy_mgr_get_hw_mode_from_idx(psoc, new_hw_index, hw_mode);
+	if (QDF_STATUS_SUCCESS != status) {
+		policy_mgr_err("Failed to get HW mode index");
+		return QDF_STATUS_E_FAILURE;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+bool policy_mgr_is_current_hwmode_dbs(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_hw_mode_params hw_mode;
+
+	if (!policy_mgr_is_hw_dbs_capable(psoc))
+		return false;
+	if (QDF_STATUS_SUCCESS !=
+		policy_mgr_get_current_hw_mode(psoc, &hw_mode))
+		return false;
+	if (hw_mode.dbs_cap)
+		return true;
+	return false;
+}
+
+bool policy_mgr_is_dbs_enable(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) {
+		policy_mgr_debug("DBS is disabled from ini");
+		return false;
+	}
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	policy_mgr_debug("DBS=%d",
+		WMI_DBS_FW_MODE_CFG_DBS_GET(
+			pm_ctx->dual_mac_cfg.cur_fw_mode_config));
+
+	if (WMI_DBS_FW_MODE_CFG_DBS_GET(
+			pm_ctx->dual_mac_cfg.cur_fw_mode_config))
+		return true;
+
+	return false;
+}
+
+bool policy_mgr_is_hw_dbs_2x2_capable(struct wlan_objmgr_psoc *psoc)
+{
+	struct dbs_nss nss_dbs;
+	uint32_t nss;
+
+	nss = policy_mgr_get_hw_dbs_nss(psoc, &nss_dbs);
+	if (nss >= HW_MODE_SS_2x2 && (nss_dbs.mac0_ss == nss_dbs.mac1_ss))
+		return true;
+	else
+		return false;
+}
+
+/*
+ * policy_mgr_is_2x2_1x1_dbs_capable() - check 2x2+1x1 DBS supported or not
+ * @psoc: PSOC object data
+ *
+ * This routine is called to check 2x2 5G + 1x1 2G (DBS1) or
+ * 2x2 2G + 1x1 5G (DBS2) support or not.
+ * Either DBS1 or DBS2 supported
+ *
+ * Return: true/false
+ */
+bool policy_mgr_is_2x2_1x1_dbs_capable(struct wlan_objmgr_psoc *psoc)
+{
+	struct dbs_nss nss_dbs;
+	uint32_t nss;
+
+	nss = policy_mgr_get_hw_dbs_nss(psoc, &nss_dbs);
+	if (nss >= HW_MODE_SS_2x2 && (nss_dbs.mac0_ss > nss_dbs.mac1_ss))
+		return true;
+	else
+		return false;
+}
+
+/*
+ * policy_mgr_is_2x2_5G_1x1_2G_dbs_capable() - check Genoa DBS1 enabled or not
+ * @psoc: PSOC object data
+ *
+ * This routine is called to check support DBS1 or not.
+ * Notes: DBS1: 2x2 5G + 1x1 2G.
+ * This function will call policy_mgr_get_hw_mode_idx_from_dbs_hw_list to match
+ * the HW mode from hw mode list. The parameters will also be matched to
+ * 2x2 5G +2x2 2G HW mode. But firmware will not report 2x2 5G + 2x2 2G alone
+ * with 2x2 5G + 1x1 2G at same time. So, it is safe to find DBS1 with
+ * policy_mgr_get_hw_mode_idx_from_dbs_hw_list.
+ *
+ * Return: true/false
+ */
+bool policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(struct wlan_objmgr_psoc *psoc)
+{
+	return policy_mgr_is_2x2_1x1_dbs_capable(psoc) &&
+		(policy_mgr_get_hw_mode_idx_from_dbs_hw_list(
+					psoc,
+					HW_MODE_SS_2x2,
+					HW_MODE_80_MHZ,
+					HW_MODE_SS_1x1, HW_MODE_40_MHZ,
+					HW_MODE_MAC_BAND_5G,
+					HW_MODE_DBS,
+					HW_MODE_AGILE_DFS_NONE,
+					HW_MODE_SBS_NONE) >= 0);
+}
+
+/*
+ * policy_mgr_is_2x2_2G_1x1_5G_dbs_capable() - check Genoa DBS2 enabled or not
+ * @psoc: PSOC object data
+ *
+ * This routine is called to check support DBS2 or not.
+ * Notes: DBS2: 2x2 2G + 1x1 5G
+ *
+ * Return: true/false
+ */
+bool policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(struct wlan_objmgr_psoc *psoc)
+{
+	return policy_mgr_is_2x2_1x1_dbs_capable(psoc) &&
+		(policy_mgr_get_hw_mode_idx_from_dbs_hw_list(
+					psoc,
+					HW_MODE_SS_2x2,
+					HW_MODE_40_MHZ,
+					HW_MODE_SS_1x1, HW_MODE_40_MHZ,
+					HW_MODE_MAC_BAND_2G,
+					HW_MODE_DBS,
+					HW_MODE_AGILE_DFS_NONE,
+					HW_MODE_SBS_NONE) >= 0);
+}
+
+uint32_t policy_mgr_get_connection_count(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t conn_index, count = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return count;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		conn_index++) {
+		if (pm_conc_connection_list[conn_index].in_use)
+			count++;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return count;
+}
+
+uint32_t policy_mgr_mode_specific_vdev_id(struct wlan_objmgr_psoc *psoc,
+					  enum policy_mgr_con_mode mode)
+{
+	uint32_t conn_index = 0;
+	uint32_t vdev_id = WLAN_INVALID_VDEV_ID;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return vdev_id;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	/*
+	 * Note: This gives you the first vdev id of the mode type in a
+	 * sta+sta or sap+sap or p2p + p2p case
+	 */
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		conn_index++) {
+		if ((pm_conc_connection_list[conn_index].mode == mode) &&
+			pm_conc_connection_list[conn_index].in_use) {
+			vdev_id = pm_conc_connection_list[conn_index].vdev_id;
+			break;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return vdev_id;
+}
+
+uint32_t policy_mgr_mode_specific_connection_count(
+		struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_con_mode mode,
+		uint32_t *list)
+{
+	uint32_t conn_index = 0, count = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return count;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		conn_index++) {
+		if ((pm_conc_connection_list[conn_index].mode == mode) &&
+			pm_conc_connection_list[conn_index].in_use) {
+			if (list != NULL)
+				list[count] = conn_index;
+			 count++;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return count;
+}
+
+QDF_STATUS policy_mgr_check_conn_with_mode_and_vdev_id(
+		struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode,
+		uint32_t vdev_id)
+{
+	QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE;
+	uint32_t conn_index = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return qdf_status;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+		if ((pm_conc_connection_list[conn_index].mode == mode) &&
+		    (pm_conc_connection_list[conn_index].vdev_id == vdev_id)) {
+			qdf_status = QDF_STATUS_SUCCESS;
+			break;
+		}
+		conn_index++;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	return qdf_status;
+}
+
+void policy_mgr_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status,
+		uint32_t scan_config,
+		uint32_t fw_mode_config)
+{
+	policy_mgr_debug("Status:%d for scan_config:%x fw_mode_config:%x",
+			 status, scan_config, fw_mode_config);
+}
+
+void policy_mgr_set_dual_mac_scan_config(struct wlan_objmgr_psoc *psoc,
+		uint8_t dbs_val,
+		uint8_t dbs_plus_agile_scan_val,
+		uint8_t single_mac_scan_with_dbs_val)
+{
+	struct policy_mgr_dual_mac_config cfg;
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	/* Any non-zero positive value is treated as 1 */
+	if (dbs_val != 0)
+		dbs_val = 1;
+	if (dbs_plus_agile_scan_val != 0)
+		dbs_plus_agile_scan_val = 1;
+	if (single_mac_scan_with_dbs_val != 0)
+		single_mac_scan_with_dbs_val = 1;
+
+	status = policy_mgr_get_updated_scan_config(psoc, &cfg.scan_config,
+			dbs_val,
+			dbs_plus_agile_scan_val,
+			single_mac_scan_with_dbs_val);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("policy_mgr_get_updated_scan_config failed %d",
+			status);
+		return;
+	}
+
+	status = policy_mgr_get_updated_fw_mode_config(psoc,
+			&cfg.fw_mode_config,
+			policy_mgr_get_dbs_config(psoc),
+			policy_mgr_get_agile_dfs_config(psoc));
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("policy_mgr_get_updated_fw_mode_config failed %d",
+			status);
+		return;
+	}
+
+	cfg.set_dual_mac_cb = policy_mgr_soc_set_dual_mac_cfg_cb;
+
+	policy_mgr_debug("scan_config:%x fw_mode_config:%x",
+			cfg.scan_config, cfg.fw_mode_config);
+
+	status = pm_ctx->sme_cbacks.sme_soc_set_dual_mac_config(cfg);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("sme_soc_set_dual_mac_config failed %d", status);
+}
+
+void policy_mgr_set_dual_mac_fw_mode_config(struct wlan_objmgr_psoc *psoc,
+			uint8_t dbs, uint8_t dfs)
+{
+	struct policy_mgr_dual_mac_config cfg;
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	/* Any non-zero positive value is treated as 1 */
+	if (dbs != 0)
+		dbs = 1;
+	if (dfs != 0)
+		dfs = 1;
+
+	status = policy_mgr_get_updated_scan_config(psoc, &cfg.scan_config,
+			policy_mgr_get_dbs_scan_config(psoc),
+			policy_mgr_get_dbs_plus_agile_scan_config(psoc),
+			policy_mgr_get_single_mac_scan_with_dfs_config(psoc));
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("policy_mgr_get_updated_scan_config failed %d",
+			status);
+		return;
+	}
+
+	status = policy_mgr_get_updated_fw_mode_config(psoc,
+				&cfg.fw_mode_config, dbs, dfs);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("policy_mgr_get_updated_fw_mode_config failed %d",
+			status);
+		return;
+	}
+
+	cfg.set_dual_mac_cb = policy_mgr_soc_set_dual_mac_cfg_cb;
+
+	policy_mgr_debug("scan_config:%x fw_mode_config:%x",
+			cfg.scan_config, cfg.fw_mode_config);
+
+	status = pm_ctx->sme_cbacks.sme_soc_set_dual_mac_config(cfg);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("sme_soc_set_dual_mac_config failed %d", status);
+}
+
+bool policy_mgr_current_concurrency_is_mcc(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t num_connections = 0;
+	bool is_mcc = false;
+
+	num_connections = policy_mgr_get_connection_count(psoc);
+
+	switch (num_connections) {
+	case 1:
+		break;
+	case 2:
+		if ((pm_conc_connection_list[0].chan !=
+			pm_conc_connection_list[1].chan) &&
+		    (pm_conc_connection_list[0].mac ==
+			pm_conc_connection_list[1].mac)) {
+			is_mcc = true;
+		}
+		break;
+	case 3:
+		if ((pm_conc_connection_list[0].chan !=
+			pm_conc_connection_list[1].chan) ||
+		    (pm_conc_connection_list[0].chan !=
+			pm_conc_connection_list[2].chan) ||
+		    (pm_conc_connection_list[1].chan !=
+			pm_conc_connection_list[2].chan)){
+				is_mcc = true;
+		}
+		break;
+	default:
+		policy_mgr_err("unexpected num_connections value %d",
+			num_connections);
+		break;
+	}
+
+	return is_mcc;
+}
+
+/**
+ * policy_mgr_set_concurrency_mode() - To set concurrency mode
+ * @psoc: PSOC object data
+ * @mode: device mode
+ *
+ * This routine is called to set the concurrency mode
+ *
+ * Return: NONE
+ */
+void policy_mgr_set_concurrency_mode(struct wlan_objmgr_psoc *psoc,
+				     enum QDF_OPMODE mode)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return;
+	}
+
+	switch (mode) {
+	case QDF_STA_MODE:
+	case QDF_P2P_CLIENT_MODE:
+	case QDF_P2P_GO_MODE:
+	case QDF_SAP_MODE:
+	case QDF_IBSS_MODE:
+	case QDF_MONITOR_MODE:
+		pm_ctx->concurrency_mode |= (1 << mode);
+		pm_ctx->no_of_open_sessions[mode]++;
+		break;
+	default:
+		break;
+	}
+
+	policy_mgr_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d",
+		pm_ctx->concurrency_mode, mode,
+		pm_ctx->no_of_open_sessions[mode]);
+}
+
+/**
+ * policy_mgr_clear_concurrency_mode() - To clear concurrency mode
+ * @psoc: PSOC object data
+ * @mode: device mode
+ *
+ * This routine is called to clear the concurrency mode
+ *
+ * Return: NONE
+ */
+void policy_mgr_clear_concurrency_mode(struct wlan_objmgr_psoc *psoc,
+				       enum QDF_OPMODE mode)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return;
+	}
+
+	switch (mode) {
+	case QDF_STA_MODE:
+	case QDF_P2P_CLIENT_MODE:
+	case QDF_P2P_GO_MODE:
+	case QDF_SAP_MODE:
+	case QDF_MONITOR_MODE:
+		pm_ctx->no_of_open_sessions[mode]--;
+		if (!(pm_ctx->no_of_open_sessions[mode]))
+			pm_ctx->concurrency_mode &= (~(1 << mode));
+		break;
+	default:
+		break;
+	}
+
+	policy_mgr_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d",
+		pm_ctx->concurrency_mode, mode,
+		pm_ctx->no_of_open_sessions[mode]);
+}
+
+void policy_mgr_incr_active_session(struct wlan_objmgr_psoc *psoc,
+				enum QDF_OPMODE mode,
+				uint8_t session_id)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	/*
+	 * Need to aquire mutex as entire functionality in this function
+	 * is in critical section
+	 */
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	switch (mode) {
+	case QDF_STA_MODE:
+	case QDF_P2P_CLIENT_MODE:
+	case QDF_P2P_GO_MODE:
+	case QDF_SAP_MODE:
+	case QDF_IBSS_MODE:
+		pm_ctx->no_of_active_sessions[mode]++;
+		break;
+	default:
+		break;
+	}
+
+	if (pm_ctx->dp_cbacks.hdd_v2_flow_pool_map)
+		pm_ctx->dp_cbacks.hdd_v2_flow_pool_map(session_id);
+
+	policy_mgr_debug("No.# of active sessions for mode %d = %d",
+		mode, pm_ctx->no_of_active_sessions[mode]);
+	policy_mgr_incr_connection_count(psoc, session_id);
+	if ((policy_mgr_mode_specific_connection_count(
+		psoc, PM_STA_MODE, NULL) > 0) && (mode != QDF_STA_MODE)) {
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		policy_mgr_set_pcl_for_existing_combo(psoc, PM_STA_MODE);
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	}
+
+	/* Notify tdls */
+	if (pm_ctx->tdls_cbacks.tdls_notify_increment_session)
+		pm_ctx->tdls_cbacks.tdls_notify_increment_session(psoc);
+
+	/*
+	 * Disable LRO/GRO if P2P or IBSS or SAP connection has come up or
+	 * there are more than one STA connections
+	 */
+	if ((policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, NULL) > 1) ||
+	    (policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE, NULL) > 0) ||
+	    (policy_mgr_mode_specific_connection_count(psoc, PM_P2P_CLIENT_MODE, NULL) >
+									0) ||
+	    (policy_mgr_mode_specific_connection_count(psoc, PM_P2P_GO_MODE, NULL) > 0) ||
+	    (policy_mgr_mode_specific_connection_count(psoc, PM_IBSS_MODE, NULL) > 0)) {
+		if (pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency != NULL)
+			pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency(true);
+	};
+
+	/* Enable RPS if SAP interface has come up */
+	if (policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE, NULL)
+		== 1) {
+		if (pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb != NULL)
+			pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb(true);
+	}
+
+	policy_mgr_dump_current_concurrency(psoc);
+
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+}
+
+QDF_STATUS policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc,
+				enum QDF_OPMODE mode,
+				uint8_t session_id)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	QDF_STATUS qdf_status;
+	bool mcc_mode;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("context is NULL");
+		return QDF_STATUS_E_EMPTY;
+	}
+
+	qdf_status = policy_mgr_check_conn_with_mode_and_vdev_id(psoc,
+			policy_mgr_convert_device_mode_to_qdf_type(mode),
+			session_id);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		policy_mgr_debug("No connection with mode:%d vdev_id:%d",
+			policy_mgr_convert_device_mode_to_qdf_type(mode),
+			session_id);
+		return qdf_status;
+	}
+
+	switch (mode) {
+	case QDF_STA_MODE:
+	case QDF_P2P_CLIENT_MODE:
+	case QDF_P2P_GO_MODE:
+	case QDF_SAP_MODE:
+	case QDF_IBSS_MODE:
+		if (pm_ctx->no_of_active_sessions[mode])
+			pm_ctx->no_of_active_sessions[mode]--;
+		break;
+	default:
+		break;
+	}
+
+	if (pm_ctx->dp_cbacks.hdd_v2_flow_pool_unmap)
+		pm_ctx->dp_cbacks.hdd_v2_flow_pool_unmap(session_id);
+
+	policy_mgr_debug("No.# of active sessions for mode %d = %d",
+		mode, pm_ctx->no_of_active_sessions[mode]);
+
+	policy_mgr_decr_connection_count(psoc, session_id);
+
+	/* Notify tdls */
+	if (pm_ctx->tdls_cbacks.tdls_notify_decrement_session)
+		pm_ctx->tdls_cbacks.tdls_notify_decrement_session(psoc);
+	/* Enable LRO/GRO if there no concurrency */
+	if ((policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, NULL) == 1) &&
+	    (policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE, NULL) == 0) &&
+	    (policy_mgr_mode_specific_connection_count(psoc, PM_P2P_CLIENT_MODE, NULL) ==
+									0) &&
+	    (policy_mgr_mode_specific_connection_count(psoc, PM_P2P_GO_MODE, NULL) == 0) &&
+	    (policy_mgr_mode_specific_connection_count(psoc, PM_IBSS_MODE, NULL) == 0)) {
+		if (pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency != NULL)
+			pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency(false);
+	};
+
+	/* Disable RPS if SAP interface has come up */
+	if (policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE, NULL)
+		== 0) {
+		if (pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb != NULL)
+			pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb(false);
+	}
+
+	policy_mgr_dump_current_concurrency(psoc);
+
+	/*
+	 * Check mode of entry being removed. Update mcc_mode only when STA
+	 * or SAP since IPA only cares about these two
+	 */
+	if (mode == QDF_STA_MODE || mode == QDF_SAP_MODE) {
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc);
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+		if (pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb)
+			pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb(mcc_mode);
+	}
+
+	return qdf_status;
+}
+
+QDF_STATUS policy_mgr_incr_connection_count(
+		struct wlan_objmgr_psoc *psoc, uint32_t vdev_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint32_t conn_index;
+	struct policy_mgr_vdev_entry_info conn_table_entry;
+	enum policy_mgr_chain_mode chain_mask = POLICY_MGR_ONE_ONE;
+	uint8_t nss_2g = 0, nss_5g = 0;
+	enum policy_mgr_con_mode mode;
+	uint8_t chan;
+	uint32_t nss = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool update_conn = true;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("context is NULL");
+		return status;
+	}
+
+	conn_index = policy_mgr_get_connection_count(psoc);
+	if (pm_ctx->cfg.max_conc_cxns < conn_index) {
+		policy_mgr_err("exceeded max connection limit %d",
+			pm_ctx->cfg.max_conc_cxns);
+		return status;
+	}
+	if (pm_ctx->wma_cbacks.wma_get_connection_info) {
+		status = pm_ctx->wma_cbacks.wma_get_connection_info(
+				vdev_id, &conn_table_entry);
+		if (QDF_STATUS_SUCCESS != status) {
+			policy_mgr_err("can't find vdev_id %d in connection table",
+			vdev_id);
+			return status;
+		}
+	} else {
+		policy_mgr_err("wma_get_connection_info is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mode = policy_mgr_get_mode(conn_table_entry.type,
+					conn_table_entry.sub_type);
+	chan = wlan_reg_freq_to_chan(pm_ctx->pdev, conn_table_entry.mhz);
+	status = policy_mgr_get_nss_for_vdev(psoc, mode, &nss_2g, &nss_5g);
+	if (QDF_IS_STATUS_SUCCESS(status)) {
+		if ((WLAN_REG_IS_24GHZ_CH(chan) && (nss_2g > 1)) ||
+			(WLAN_REG_IS_5GHZ_CH(chan) && (nss_5g > 1)))
+			chain_mask = POLICY_MGR_TWO_TWO;
+		else
+			chain_mask = POLICY_MGR_ONE_ONE;
+		nss = (WLAN_REG_IS_24GHZ_CH(chan)) ? nss_2g : nss_5g;
+	} else {
+		policy_mgr_err("Error in getting nss");
+	}
+
+	if (mode == PM_STA_MODE || mode == PM_P2P_CLIENT_MODE)
+		update_conn = false;
+
+	/* add the entry */
+	policy_mgr_update_conc_list(psoc, conn_index,
+			mode,
+			chan,
+			policy_mgr_get_bw(conn_table_entry.chan_width),
+			conn_table_entry.mac_id,
+			chain_mask,
+			nss, vdev_id, true, update_conn);
+	policy_mgr_debug("Add at idx:%d vdev %d mac=%d",
+		conn_index, vdev_id,
+		conn_table_entry.mac_id);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_decr_connection_count(struct wlan_objmgr_psoc *psoc,
+					uint32_t vdev_id)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint32_t conn_index = 0, next_conn_index = 0;
+	bool found = false;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+		if (vdev_id == pm_conc_connection_list[conn_index].vdev_id) {
+			/* debug msg */
+			found = true;
+			break;
+		}
+		conn_index++;
+	}
+	if (!found) {
+		policy_mgr_err("can't find vdev_id %d in pm_conc_connection_list",
+			vdev_id);
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		return status;
+	}
+	next_conn_index = conn_index + 1;
+	while (PM_CONC_CONNECTION_LIST_VALID_INDEX(next_conn_index)) {
+		pm_conc_connection_list[conn_index].vdev_id =
+			pm_conc_connection_list[next_conn_index].vdev_id;
+		pm_conc_connection_list[conn_index].mode =
+			pm_conc_connection_list[next_conn_index].mode;
+		pm_conc_connection_list[conn_index].mac =
+			pm_conc_connection_list[next_conn_index].mac;
+		pm_conc_connection_list[conn_index].chan =
+			pm_conc_connection_list[next_conn_index].chan;
+		pm_conc_connection_list[conn_index].bw =
+			pm_conc_connection_list[next_conn_index].bw;
+		pm_conc_connection_list[conn_index].chain_mask =
+			pm_conc_connection_list[next_conn_index].chain_mask;
+		pm_conc_connection_list[conn_index].original_nss =
+			pm_conc_connection_list[next_conn_index].original_nss;
+		pm_conc_connection_list[conn_index].in_use =
+			pm_conc_connection_list[next_conn_index].in_use;
+		conn_index++;
+		next_conn_index++;
+	}
+
+	/* clean up the entry */
+	qdf_mem_zero(&pm_conc_connection_list[next_conn_index - 1],
+		sizeof(*pm_conc_connection_list));
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool policy_mgr_map_concurrency_mode(enum QDF_OPMODE *old_mode,
+				     enum policy_mgr_con_mode *new_mode)
+{
+	bool status = true;
+
+	switch (*old_mode) {
+
+	case QDF_STA_MODE:
+		*new_mode = PM_STA_MODE;
+		break;
+	case QDF_SAP_MODE:
+		*new_mode = PM_SAP_MODE;
+		break;
+	case QDF_P2P_CLIENT_MODE:
+		*new_mode = PM_P2P_CLIENT_MODE;
+		break;
+	case QDF_P2P_GO_MODE:
+		*new_mode = PM_P2P_GO_MODE;
+		break;
+	case QDF_IBSS_MODE:
+		*new_mode = PM_IBSS_MODE;
+		break;
+	default:
+		*new_mode = PM_MAX_NUM_OF_MODE;
+		status = false;
+		break;
+	}
+
+	return status;
+}
+
+bool policy_mgr_is_ibss_conn_exist(struct wlan_objmgr_psoc *psoc,
+				uint8_t *ibss_channel)
+{
+	uint32_t count = 0, index = 0;
+	uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	bool status = false;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+	if (NULL == ibss_channel) {
+		policy_mgr_err("Null pointer error");
+		return false;
+	}
+	count = policy_mgr_mode_specific_connection_count(
+				psoc, PM_IBSS_MODE, list);
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (count == 0) {
+		/* No IBSS connection */
+		status = false;
+	} else if (count == 1) {
+		*ibss_channel = pm_conc_connection_list[list[index]].chan;
+		status = true;
+	} else {
+		*ibss_channel = pm_conc_connection_list[list[index]].chan;
+		policy_mgr_debug("Multiple IBSS connections, picking first one");
+		status = true;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return status;
+}
+
+uint32_t policy_mgr_get_mode_specific_conn_info(struct wlan_objmgr_psoc *psoc,
+				  uint8_t *channel, uint8_t *vdev_id,
+				  enum policy_mgr_con_mode mode)
+{
+
+	uint32_t count = 0, index = 0;
+	uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return count;
+	}
+	if (NULL == channel || NULL == vdev_id) {
+		policy_mgr_err("Null pointer error");
+		return count;
+	}
+
+	count = policy_mgr_mode_specific_connection_count(
+				psoc, mode, list);
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (count == 0) {
+		policy_mgr_debug("No mode:[%d] connection", mode);
+	} else if (count == 1) {
+		*channel = pm_conc_connection_list[list[index]].chan;
+		*vdev_id =
+			pm_conc_connection_list[list[index]].vdev_id;
+	} else {
+		for (index = 0; index < count; index++) {
+			channel[index] =
+			pm_conc_connection_list[list[index]].chan;
+
+			vdev_id[index] =
+			pm_conc_connection_list[list[index]].vdev_id;
+		}
+		policy_mgr_debug("Multiple mode:[%d] connections", mode);
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return count;
+}
+
+bool policy_mgr_max_concurrent_connections_reached(
+		struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t i = 0, j = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (NULL != pm_ctx) {
+		for (i = 0; i < QDF_MAX_NO_OF_MODE; i++)
+			j += pm_ctx->no_of_active_sessions[i];
+		return j >
+			(pm_ctx->cfg.max_conc_cxns - 1);
+	}
+
+	return false;
+}
+
+static bool policy_mgr_is_sub_20_mhz_enabled(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	return pm_ctx->user_cfg.sub_20_mhz_enabled;
+}
+
+/**
+ * policy_mgr_check_privacy_for_new_conn() - Check privacy mode concurrency
+ * @pm_ctx: policy_mgr_psoc_priv_obj policy mgr context
+ *
+ * This routine is called to check vdev security mode allowed in concurrency.
+ * At present, WAPI security mode is not allowed to run concurrency with any
+ * other vdev.
+ *
+ * Return: true - allow
+ */
+static bool policy_mgr_check_privacy_for_new_conn(
+	struct policy_mgr_psoc_priv_obj *pm_ctx)
+{
+	if (!pm_ctx->hdd_cbacks.hdd_wapi_security_sta_exist)
+		return true;
+
+	if (pm_ctx->hdd_cbacks.hdd_wapi_security_sta_exist() &&
+	    (policy_mgr_get_connection_count(pm_ctx->psoc) > 0))
+		return false;
+
+	return true;
+}
+
+bool policy_mgr_is_concurrency_allowed(struct wlan_objmgr_psoc *psoc,
+				       enum policy_mgr_con_mode mode,
+				       uint8_t channel,
+				       enum hw_mode_bandwidth bw)
+{
+	uint32_t num_connections = 0, count = 0, index = 0;
+	bool status = false, match = false;
+	uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool sta_sap_scc_on_dfs_chan;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+	/* find the current connection state from pm_conc_connection_list*/
+	num_connections = policy_mgr_get_connection_count(psoc);
+
+	if (num_connections && policy_mgr_is_sub_20_mhz_enabled(psoc)) {
+		policy_mgr_err("dont allow concurrency if Sub 20 MHz is enabled");
+		status = false;
+		goto done;
+	}
+
+	if (policy_mgr_max_concurrent_connections_reached(psoc)) {
+		policy_mgr_err("Reached max concurrent connections: %d",
+			       pm_ctx->cfg.max_conc_cxns);
+		goto done;
+	}
+
+	if (channel) {
+		/* don't allow 3rd home channel on same MAC */
+		if (!policy_mgr_allow_new_home_channel(psoc,
+			channel, num_connections))
+			goto done;
+
+		/*
+		 * 1) DFS MCC is not yet supported
+		 * 2) If you already have STA connection on 5G channel then
+		 *    don't allow any other persona to make connection on DFS
+		 *    channel because STA 5G + DFS MCC is not allowed.
+		 * 3) If STA is on 2G channel and SAP is coming up on
+		 *    DFS channel then allow concurrency but make sure it is
+		 *    going to DBS and send PCL to firmware indicating that
+		 *    don't allow STA to roam to 5G channels.
+		 */
+		if (!policy_mgr_is_5g_channel_allowed(psoc,
+			channel, list, PM_P2P_GO_MODE))
+			goto done;
+		if (!policy_mgr_is_5g_channel_allowed(psoc,
+			channel, list, PM_SAP_MODE))
+			goto done;
+
+		sta_sap_scc_on_dfs_chan =
+			policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc);
+		policy_mgr_debug("sta_sap_scc_on_dfs_chan %u",
+				 sta_sap_scc_on_dfs_chan);
+
+		if (!sta_sap_scc_on_dfs_chan && ((mode == PM_P2P_GO_MODE) ||
+		    (mode == PM_SAP_MODE))) {
+			if (wlan_reg_is_dfs_ch(pm_ctx->pdev, channel))
+				match = policy_mgr_disallow_mcc(psoc, channel);
+		}
+		if (true == match) {
+			policy_mgr_err("No MCC, SAP/GO about to come up on DFS channel");
+			goto done;
+		}
+	}
+
+	/*
+	 * Check all IBSS+STA concurrencies
+	 *
+	 * don't allow IBSS + STA MCC
+	 * don't allow IBSS + STA SCC if IBSS is on DFS channel
+	 */
+	count = policy_mgr_mode_specific_connection_count(psoc,
+				PM_STA_MODE, list);
+	if ((PM_IBSS_MODE == mode) &&
+		(policy_mgr_mode_specific_connection_count(psoc,
+		PM_IBSS_MODE, list)) && count) {
+		policy_mgr_err("No 2nd IBSS, we already have STA + IBSS");
+		goto done;
+	}
+	if ((PM_IBSS_MODE == mode) &&
+		(wlan_reg_is_dfs_ch(pm_ctx->pdev, channel)) && count) {
+		policy_mgr_err("No IBSS + STA SCC/MCC, IBSS is on DFS channel");
+		goto done;
+	}
+	if (PM_IBSS_MODE == mode) {
+		if (policy_mgr_is_hw_dbs_capable(psoc) == true) {
+			if (num_connections > 1) {
+				policy_mgr_err("No IBSS, we have concurrent connections already");
+				goto done;
+			}
+			qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+			if (PM_STA_MODE != pm_conc_connection_list[0].mode) {
+				policy_mgr_err("No IBSS, we've a non-STA connection");
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				goto done;
+			}
+			/*
+			 * This logic protects STA and IBSS to come up on same
+			 * band. If requirement changes then this condition
+			 * needs to be removed
+			 */
+			if (channel &&
+				(pm_conc_connection_list[0].chan != channel) &&
+				WLAN_REG_IS_SAME_BAND_CHANNELS(
+				pm_conc_connection_list[0].chan, channel)) {
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				policy_mgr_err("No IBSS + STA MCC");
+				goto done;
+			}
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		} else if (num_connections) {
+			policy_mgr_err("No IBSS, we have one connection already");
+			goto done;
+		}
+	}
+
+	if ((PM_STA_MODE == mode) &&
+		(policy_mgr_mode_specific_connection_count(psoc,
+		PM_IBSS_MODE, list)) && count) {
+		policy_mgr_err("No 2nd STA, we already have STA + IBSS");
+		goto done;
+	}
+
+	if ((PM_STA_MODE == mode) &&
+		(policy_mgr_mode_specific_connection_count(psoc,
+		PM_IBSS_MODE, list))) {
+		if (policy_mgr_is_hw_dbs_capable(psoc) == true) {
+			if (num_connections > 1) {
+				policy_mgr_err("No 2nd STA, we already have IBSS concurrency");
+				goto done;
+			}
+			qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+			if (channel &&
+				(wlan_reg_is_dfs_ch(pm_ctx->pdev,
+				pm_conc_connection_list[0].chan))
+				&& (WLAN_REG_IS_5GHZ_CH(channel))) {
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				policy_mgr_err("No IBSS + STA SCC/MCC, IBSS is on DFS channel");
+				goto done;
+			}
+			/*
+			 * This logic protects STA and IBSS to come up on same
+			 * band. If requirement changes then this condition
+			 * needs to be removed
+			 */
+			if ((pm_conc_connection_list[0].chan != channel) &&
+				WLAN_REG_IS_SAME_BAND_CHANNELS(
+				pm_conc_connection_list[0].chan, channel)) {
+				policy_mgr_err("No IBSS + STA MCC");
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				goto done;
+			}
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		} else {
+			policy_mgr_err("No STA, we have IBSS connection already");
+			goto done;
+		}
+	}
+
+	if (!policy_mgr_allow_sap_go_concurrency(psoc, mode, channel,
+						 WLAN_INVALID_VDEV_ID)) {
+		policy_mgr_err("This concurrency combination is not allowed");
+		goto done;
+	}
+
+	/* don't allow two P2P GO on same band */
+	if (channel && (mode == PM_P2P_GO_MODE) && num_connections) {
+		index = 0;
+		count = policy_mgr_mode_specific_connection_count(psoc,
+						PM_P2P_GO_MODE, list);
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		while (index < count) {
+			if (WLAN_REG_IS_SAME_BAND_CHANNELS(channel,
+				pm_conc_connection_list[list[index]].chan)) {
+				policy_mgr_err("Don't allow P2P GO on same band");
+				qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+				goto done;
+			}
+			index++;
+		}
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	}
+
+	if (!policy_mgr_check_privacy_for_new_conn(pm_ctx)) {
+		policy_mgr_err("Don't allow new conn when wapi security conn existing");
+		goto done;
+	}
+
+	status = true;
+
+done:
+	return status;
+}
+
+bool policy_mgr_allow_concurrency(struct wlan_objmgr_psoc *psoc,
+				  enum policy_mgr_con_mode mode,
+				  uint8_t channel, enum hw_mode_bandwidth bw)
+{
+	QDF_STATUS status;
+	struct policy_mgr_pcl_list pcl;
+
+	qdf_mem_zero(&pcl, sizeof(pcl));
+	status = policy_mgr_get_pcl(psoc, mode, pcl.pcl_list, &pcl.pcl_len,
+				    pcl.weight_list,
+				    QDF_ARRAY_SIZE(pcl.weight_list));
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("disallow connection:%d", status);
+		return false;
+	}
+
+	return policy_mgr_is_concurrency_allowed(psoc, mode, channel, bw);
+}
+
+bool  policy_mgr_allow_concurrency_csa(struct wlan_objmgr_psoc *psoc,
+				       enum policy_mgr_con_mode mode,
+				       uint8_t channel,
+				       uint32_t vdev_id)
+{
+	bool allow = false;
+	struct policy_mgr_conc_connection_info info;
+	uint8_t num_cxn_del = 0;
+
+	/*
+	 * Store the connection's parameter and temporarily delete it
+	 * from the concurrency table. This way the allow concurrency
+	 * check can be used as though a new connection is coming up,
+	 * after check, restore the connection to concurrency table.
+	 */
+	policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, vdev_id,
+						      &info, &num_cxn_del);
+	allow = policy_mgr_allow_concurrency(
+				psoc,
+				mode,
+				channel,
+				HW_MODE_20_MHZ);
+	if (!allow)
+		policy_mgr_err("CSA concurrency check failed");
+	/* Restore the connection entry */
+	if (num_cxn_del > 0)
+		policy_mgr_restore_deleted_conn_info(psoc, &info, num_cxn_del);
+
+	return allow;
+}
+
+/**
+ * policy_mgr_get_concurrency_mode() - return concurrency mode
+ * @psoc: PSOC object information
+ *
+ * This routine is used to retrieve concurrency mode
+ *
+ * Return: uint32_t value of concurrency mask
+ */
+uint32_t policy_mgr_get_concurrency_mode(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STA_MASK;
+	}
+
+	policy_mgr_info("concurrency_mode: 0x%x",
+			pm_ctx->concurrency_mode);
+
+	return pm_ctx->concurrency_mode;
+}
+
+/**
+ * policy_mgr_get_channel_from_scan_result() - to get channel from scan result
+ * @psoc: PSOC object information
+ * @roam_profile: pointer to roam profile
+ * @channel: channel to be filled
+ *
+ * This routine gets channel which most likely a candidate to which STA
+ * will make connection.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS policy_mgr_get_channel_from_scan_result(
+		struct wlan_objmgr_psoc *psoc,
+		void *roam_profile, uint8_t *channel)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	void *scan_cache = NULL;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!roam_profile || !channel) {
+		policy_mgr_err("Invalid input parameters");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (pm_ctx->sme_cbacks.sme_get_ap_channel_from_scan) {
+		status = pm_ctx->sme_cbacks.sme_get_ap_channel_from_scan
+			(roam_profile, &scan_cache, channel);
+		if (status != QDF_STATUS_SUCCESS) {
+			policy_mgr_err("Get AP channel failed");
+			return status;
+		}
+	} else {
+		policy_mgr_err("sme_get_ap_channel_from_scan_cache NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (pm_ctx->sme_cbacks.sme_scan_result_purge)
+		status = pm_ctx->sme_cbacks.sme_scan_result_purge(scan_cache);
+	else
+		policy_mgr_err("sme_scan_result_purge NULL");
+
+	return status;
+}
+
+QDF_STATUS policy_mgr_set_user_cfg(struct wlan_objmgr_psoc *psoc,
+				struct policy_mgr_user_cfg *user_cfg)
+{
+
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (NULL == user_cfg) {
+		policy_mgr_err("Invalid User Config");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->user_cfg = *user_cfg;
+	policy_mgr_debug("dbs_selection_plcy 0x%x",
+			 pm_ctx->cfg.dbs_selection_plcy);
+	policy_mgr_debug("vdev_priority_list 0x%x",
+			 pm_ctx->cfg.vdev_priority_list);
+	pm_ctx->cur_conc_system_pref = pm_ctx->cfg.sys_pref;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+uint8_t policy_mgr_search_and_check_for_session_conc(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t session_id,
+		void *roam_profile)
+{
+	uint8_t channel = 0;
+	QDF_STATUS status;
+	enum policy_mgr_con_mode mode;
+	bool ret;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return channel;
+	}
+
+	if (pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev) {
+		mode = pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev(
+			psoc, session_id);
+		if (PM_MAX_NUM_OF_MODE == mode) {
+			policy_mgr_err("Invalid mode");
+			return channel;
+		}
+	} else
+		return channel;
+
+	status = policy_mgr_get_channel_from_scan_result(psoc,
+			roam_profile, &channel);
+	if ((QDF_STATUS_SUCCESS != status) || (channel == 0)) {
+		policy_mgr_err("%s error %d %d",
+			__func__, status, channel);
+		return 0;
+	}
+
+	/* Take care of 160MHz and 80+80Mhz later */
+	ret = policy_mgr_allow_concurrency(psoc, mode, channel, HW_MODE_20_MHZ);
+	if (false == ret) {
+		policy_mgr_err("Connection failed due to conc check fail");
+		return 0;
+	}
+
+	return channel;
+}
+
+/**
+ * policy_mgr_is_two_connection_mcc() - Check if MCC scenario
+ * when there are two connections
+ *
+ * If if MCC scenario when there are two connections
+ *
+ * Return: true or false
+ */
+static bool policy_mgr_is_two_connection_mcc(void)
+{
+	return ((pm_conc_connection_list[0].chan !=
+		 pm_conc_connection_list[1].chan) &&
+		(pm_conc_connection_list[0].mac ==
+		 pm_conc_connection_list[1].mac) &&
+		(pm_conc_connection_list[0].chan <=
+		 WLAN_REG_MAX_24GHZ_CH_NUM) &&
+		(pm_conc_connection_list[1].chan <=
+		 WLAN_REG_MAX_24GHZ_CH_NUM)) ? true : false;
+}
+
+/**
+ * policy_mgr_is_three_connection_mcc() - Check if MCC scenario
+ * when there are three connections
+ *
+ * If if MCC scenario when there are three connections
+ *
+ * Return: true or false
+ */
+static bool policy_mgr_is_three_connection_mcc(void)
+{
+	return (((pm_conc_connection_list[0].chan !=
+		  pm_conc_connection_list[1].chan) ||
+		 (pm_conc_connection_list[0].chan !=
+		  pm_conc_connection_list[2].chan) ||
+		 (pm_conc_connection_list[1].chan !=
+		  pm_conc_connection_list[2].chan)) &&
+		(pm_conc_connection_list[0].chan <=
+		 WLAN_REG_MAX_24GHZ_CH_NUM) &&
+		(pm_conc_connection_list[1].chan <=
+		 WLAN_REG_MAX_24GHZ_CH_NUM) &&
+		(pm_conc_connection_list[2].chan <=
+		 WLAN_REG_MAX_24GHZ_CH_NUM)) ? true : false;
+}
+
+bool policy_mgr_is_mcc_in_24G(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t num_connections = 0;
+	bool is_24G_mcc = false;
+
+	num_connections = policy_mgr_get_connection_count(psoc);
+
+	switch (num_connections) {
+	case 1:
+		break;
+	case 2:
+		if (policy_mgr_is_two_connection_mcc())
+			is_24G_mcc = true;
+		break;
+	case 3:
+		if (policy_mgr_is_three_connection_mcc())
+			is_24G_mcc = true;
+		break;
+	default:
+		policy_mgr_err("unexpected num_connections value %d",
+			num_connections);
+		break;
+	}
+
+	return is_24G_mcc;
+}
+
+bool policy_mgr_check_for_session_conc(struct wlan_objmgr_psoc *psoc,
+				uint8_t session_id, uint8_t channel)
+{
+	enum policy_mgr_con_mode mode;
+	bool ret;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	if (pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev) {
+		mode = pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev(
+			psoc, session_id);
+		if (PM_MAX_NUM_OF_MODE == mode) {
+			policy_mgr_err("Invalid mode");
+			return false;
+		}
+	} else
+		return false;
+
+	if (channel == 0) {
+		policy_mgr_err("Invalid channel number 0");
+		return false;
+	}
+
+	/* Take care of 160MHz and 80+80Mhz later */
+	ret = policy_mgr_allow_concurrency(psoc, mode, channel, HW_MODE_20_MHZ);
+	if (false == ret) {
+		policy_mgr_err("Connection failed due to conc check fail");
+		return 0;
+	}
+
+	return true;
+}
+
+/**
+ * policy_mgr_change_mcc_go_beacon_interval() - Change MCC beacon interval
+ * @psoc: PSOC object information
+ * @vdev_id: vdev id
+ * @dev_mode: device mode
+ *
+ * Updates the beacon parameters of the GO in MCC scenario
+ *
+ * Return: Success or Failure depending on the overall function behavior
+ */
+QDF_STATUS policy_mgr_change_mcc_go_beacon_interval(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t vdev_id, enum QDF_OPMODE dev_mode)
+{
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	policy_mgr_info("UPDATE Beacon Params");
+
+	if (QDF_SAP_MODE == dev_mode) {
+		if (pm_ctx->sme_cbacks.sme_change_mcc_beacon_interval
+		    ) {
+			status = pm_ctx->sme_cbacks.
+				sme_change_mcc_beacon_interval(vdev_id);
+			if (status == QDF_STATUS_E_FAILURE) {
+				policy_mgr_err("Failed to update Beacon Params");
+				return QDF_STATUS_E_FAILURE;
+			}
+		} else {
+			policy_mgr_err("sme_change_mcc_beacon_interval callback is NULL");
+			return QDF_STATUS_E_FAILURE;
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+struct policy_mgr_conc_connection_info *policy_mgr_get_conn_info(uint32_t *len)
+{
+	struct policy_mgr_conc_connection_info *conn_ptr =
+		&pm_conc_connection_list[0];
+	*len = MAX_NUMBER_OF_CONC_CONNECTIONS;
+
+	return conn_ptr;
+}
+
+enum policy_mgr_con_mode policy_mgr_convert_device_mode_to_qdf_type(
+			enum QDF_OPMODE device_mode)
+{
+	enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE;
+	switch (device_mode) {
+	case QDF_STA_MODE:
+		mode = PM_STA_MODE;
+		break;
+	case QDF_P2P_CLIENT_MODE:
+		mode = PM_P2P_CLIENT_MODE;
+		break;
+	case QDF_P2P_GO_MODE:
+		mode = PM_P2P_GO_MODE;
+		break;
+	case QDF_SAP_MODE:
+		mode = PM_SAP_MODE;
+		break;
+	case QDF_IBSS_MODE:
+		mode = PM_IBSS_MODE;
+		break;
+	default:
+		policy_mgr_debug("Unsupported mode (%d)",
+				 device_mode);
+	}
+
+	return mode;
+}
+
+enum QDF_OPMODE policy_mgr_get_qdf_mode_from_pm(
+			enum policy_mgr_con_mode device_mode)
+{
+	enum QDF_OPMODE mode = QDF_MAX_NO_OF_MODE;
+
+	switch (device_mode) {
+	case PM_STA_MODE:
+		mode = QDF_STA_MODE;
+		break;
+	case PM_SAP_MODE:
+		mode = QDF_SAP_MODE;
+		break;
+	case PM_P2P_CLIENT_MODE:
+		mode = QDF_P2P_CLIENT_MODE;
+		break;
+	case PM_P2P_GO_MODE:
+		mode = QDF_P2P_GO_MODE;
+		break;
+	case PM_IBSS_MODE:
+		mode = QDF_IBSS_MODE;
+		break;
+	default:
+		policy_mgr_debug("Unsupported policy mgr mode (%d)",
+				 device_mode);
+	}
+	return mode;
+}
+
+QDF_STATUS policy_mgr_mode_specific_num_open_sessions(
+		struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE mode,
+		uint8_t *num_sessions)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	*num_sessions = pm_ctx->no_of_open_sessions[mode];
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_mode_specific_num_active_sessions(
+		struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE mode,
+		uint8_t *num_sessions)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	*num_sessions = pm_ctx->no_of_active_sessions[mode];
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * policy_mgr_concurrent_open_sessions_running() - Checks for
+ * concurrent open session
+ * @psoc: PSOC object information
+ *
+ * Checks if more than one open session is running for all the allowed modes
+ * in the driver
+ *
+ * Return: True if more than one open session exists, False otherwise
+ */
+bool policy_mgr_concurrent_open_sessions_running(
+	struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t i = 0;
+	uint8_t j = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return false;
+	}
+
+	for (i = 0; i < QDF_MAX_NO_OF_MODE; i++)
+		j += pm_ctx->no_of_open_sessions[i];
+
+	return j > 1;
+}
+
+/**
+ * policy_mgr_concurrent_beaconing_sessions_running() - Checks
+ * for concurrent beaconing entities
+ * @psoc: PSOC object information
+ *
+ * Checks if multiple beaconing sessions are running i.e., if SAP or GO or IBSS
+ * are beaconing together
+ *
+ * Return: True if multiple entities are beaconing together, False otherwise
+ */
+bool policy_mgr_concurrent_beaconing_sessions_running(
+	struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid context");
+		return false;
+	}
+
+	return (pm_ctx->no_of_open_sessions[QDF_SAP_MODE] +
+		pm_ctx->no_of_open_sessions[QDF_P2P_GO_MODE] +
+		pm_ctx->no_of_open_sessions[QDF_IBSS_MODE] > 1) ? true : false;
+}
+
+
+void policy_mgr_clear_concurrent_session_count(struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t i = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (NULL != pm_ctx) {
+		for (i = 0; i < QDF_MAX_NO_OF_MODE; i++)
+			pm_ctx->no_of_active_sessions[i] = 0;
+	}
+}
+
+bool policy_mgr_is_multiple_active_sta_sessions(struct wlan_objmgr_psoc *psoc)
+{
+	return policy_mgr_mode_specific_connection_count(
+		psoc, PM_STA_MODE, NULL) > 1;
+}
+
+/**
+ * policy_mgr_is_sta_active_connection_exists() - Check if a STA
+ * connection is active
+ * @psoc: PSOC object information
+ *
+ * Checks if there is atleast one active STA connection in the driver
+ *
+ * Return: True if an active STA session is present, False otherwise
+ */
+bool policy_mgr_is_sta_active_connection_exists(
+	struct wlan_objmgr_psoc *psoc)
+{
+	return (!policy_mgr_mode_specific_connection_count(
+		psoc, PM_STA_MODE, NULL)) ? false : true;
+}
+
+bool policy_mgr_is_any_nondfs_chnl_present(struct wlan_objmgr_psoc *psoc,
+				uint8_t *channel)
+{
+	bool status = false;
+	uint32_t conn_index = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+			conn_index++) {
+		if (pm_conc_connection_list[conn_index].in_use &&
+		    !wlan_reg_is_dfs_ch(pm_ctx->pdev,
+			pm_conc_connection_list[conn_index].chan)) {
+			*channel = pm_conc_connection_list[conn_index].chan;
+			status = true;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return status;
+}
+
+bool policy_mgr_is_any_dfs_beaconing_session_present(
+		struct wlan_objmgr_psoc *psoc, uint8_t *channel)
+{
+	struct policy_mgr_conc_connection_info *conn_info;
+	bool status = false;
+	uint32_t conn_index = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+			conn_index++) {
+		conn_info = &pm_conc_connection_list[conn_index];
+		if (conn_info->in_use &&
+			wlan_reg_is_dfs_ch(pm_ctx->pdev, conn_info->chan) &&
+		    (PM_SAP_MODE == conn_info->mode ||
+		     PM_P2P_GO_MODE == conn_info->mode)) {
+			*channel = pm_conc_connection_list[conn_index].chan;
+			status = true;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return status;
+}
+
+QDF_STATUS policy_mgr_get_nss_for_vdev(struct wlan_objmgr_psoc *psoc,
+				enum policy_mgr_con_mode mode,
+				uint8_t *nss_2g, uint8_t *nss_5g)
+{
+	enum QDF_OPMODE dev_mode;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	dev_mode = policy_mgr_get_qdf_mode_from_pm(mode);
+	if (dev_mode == QDF_MAX_NO_OF_MODE)
+		return  QDF_STATUS_E_FAILURE;
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (pm_ctx->sme_cbacks.sme_get_nss_for_vdev) {
+		pm_ctx->sme_cbacks.sme_get_nss_for_vdev(
+			dev_mode, nss_2g, nss_5g);
+
+	} else {
+		policy_mgr_err("sme_get_nss_for_vdev callback is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void policy_mgr_dump_connection_status_info(struct wlan_objmgr_psoc *psoc)
+{
+	uint32_t i;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) {
+		policy_mgr_debug("%d: use:%d vdev:%d mode:%d mac:%d chan:%d orig chainmask:%d orig nss:%d bw:%d",
+				i, pm_conc_connection_list[i].in_use,
+				pm_conc_connection_list[i].vdev_id,
+				pm_conc_connection_list[i].mode,
+				pm_conc_connection_list[i].mac,
+				pm_conc_connection_list[i].chan,
+				pm_conc_connection_list[i].chain_mask,
+				pm_conc_connection_list[i].original_nss,
+				pm_conc_connection_list[i].bw);
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+}
+
+bool policy_mgr_is_any_mode_active_on_band_along_with_session(
+						struct wlan_objmgr_psoc *psoc,
+						uint8_t session_id,
+						enum policy_mgr_band band)
+{
+	uint32_t i;
+	bool status = false;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		status = false;
+		goto send_status;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) {
+		switch (band) {
+		case POLICY_MGR_BAND_24:
+			if ((pm_conc_connection_list[i].vdev_id != session_id)
+			&& (pm_conc_connection_list[i].in_use) &&
+			(WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[i].chan))) {
+				status = true;
+				goto release_mutex_and_send_status;
+			}
+			break;
+		case POLICY_MGR_BAND_5:
+			if ((pm_conc_connection_list[i].vdev_id != session_id)
+			&& (pm_conc_connection_list[i].in_use) &&
+			(WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[i].chan))) {
+				status = true;
+				goto release_mutex_and_send_status;
+			}
+			break;
+		default:
+			policy_mgr_err("Invalidband option:%d", band);
+			status = false;
+			goto release_mutex_and_send_status;
+		}
+	}
+release_mutex_and_send_status:
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+send_status:
+	return status;
+}
+
+QDF_STATUS policy_mgr_get_chan_by_session_id(struct wlan_objmgr_psoc *psoc,
+					uint8_t session_id, uint8_t *chan)
+{
+	uint32_t i;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	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].vdev_id == session_id) &&
+		    (pm_conc_connection_list[i].in_use)) {
+			*chan = pm_conc_connection_list[i].chan;
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS policy_mgr_get_mac_id_by_session_id(struct wlan_objmgr_psoc *psoc,
+					uint8_t session_id, uint8_t *mac_id)
+{
+	uint32_t i;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	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].vdev_id == session_id) &&
+		    (pm_conc_connection_list[i].in_use)) {
+			*mac_id = pm_conc_connection_list[i].mac;
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS policy_mgr_get_mcc_session_id_on_mac(struct wlan_objmgr_psoc *psoc,
+					uint8_t mac_id, uint8_t session_id,
+					uint8_t *mcc_session_id)
+{
+	uint32_t i;
+	QDF_STATUS status;
+	uint8_t chan;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = policy_mgr_get_chan_by_session_id(psoc, session_id, &chan);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("Failed to get channel for session id:%d",
+			       session_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	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].mac != mac_id)
+			continue;
+		if (pm_conc_connection_list[i].vdev_id == session_id)
+			continue;
+		/* Inter band or intra band MCC */
+		if ((pm_conc_connection_list[i].chan != chan) &&
+		    (pm_conc_connection_list[i].in_use)) {
+			*mcc_session_id = pm_conc_connection_list[i].vdev_id;
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return QDF_STATUS_E_FAILURE;
+}
+
+uint8_t policy_mgr_get_mcc_operating_channel(struct wlan_objmgr_psoc *psoc,
+					uint8_t session_id)
+{
+	uint8_t mac_id, mcc_session_id;
+	QDF_STATUS status;
+	uint8_t chan;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return INVALID_CHANNEL_ID;
+	}
+
+	status = policy_mgr_get_mac_id_by_session_id(psoc, session_id, &mac_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("failed to get MAC ID");
+		return INVALID_CHANNEL_ID;
+	}
+
+	status = policy_mgr_get_mcc_session_id_on_mac(psoc, mac_id, session_id,
+			&mcc_session_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("failed to get MCC session ID");
+		return INVALID_CHANNEL_ID;
+	}
+
+	status = policy_mgr_get_chan_by_session_id(psoc, mcc_session_id,
+						   &chan);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("Failed to get channel for MCC session ID:%d",
+			       mcc_session_id);
+		return INVALID_CHANNEL_ID;
+	}
+
+	return chan;
+}
+
+void policy_mgr_set_do_hw_mode_change_flag(struct wlan_objmgr_psoc *psoc,
+		bool flag)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	pm_ctx->do_hw_mode_change = flag;
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	policy_mgr_debug("hw_mode_change_channel:%d", flag);
+}
+
+bool policy_mgr_is_hw_mode_change_after_vdev_up(struct wlan_objmgr_psoc *psoc)
+{
+	bool flag;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return INVALID_CHANNEL_ID;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	flag = pm_ctx->do_hw_mode_change;
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return flag;
+}
+
+bool policy_mgr_is_dnsc_set(struct wlan_objmgr_vdev *vdev)
+{
+	bool roffchan;
+
+	if (!vdev) {
+		policy_mgr_err("Invalid parameter");
+		return false;
+	}
+
+	roffchan = wlan_vdev_mlme_cap_get(vdev, WLAN_VDEV_C_RESTRICT_OFFCHAN);
+
+	policy_mgr_debug("Restrict offchannel:%s",
+			 roffchan  ? "set" : "clear");
+
+	return roffchan;
+}
+
+QDF_STATUS policy_mgr_is_chan_ok_for_dnbs(struct wlan_objmgr_psoc *psoc,
+			uint8_t channel, bool *ok)
+{
+	uint32_t cc_count = 0, i;
+	uint8_t operating_channel[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint8_t vdev_id[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	struct wlan_objmgr_vdev *vdev;
+
+	if (!channel || !ok) {
+		policy_mgr_err("Invalid parameter");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	cc_count = policy_mgr_get_mode_specific_conn_info(psoc,
+					&operating_channel[cc_count],
+					&vdev_id[cc_count],
+					PM_SAP_MODE);
+	policy_mgr_debug("Number of SAP modes: %d", cc_count);
+	cc_count = cc_count + policy_mgr_get_mode_specific_conn_info(psoc,
+					&operating_channel[cc_count],
+					&vdev_id[cc_count],
+					PM_P2P_GO_MODE);
+	policy_mgr_debug("Number of beaconing entities (SAP + GO):%d",
+							cc_count);
+	if (!cc_count) {
+		*ok = true;
+		return QDF_STATUS_SUCCESS;
+	}
+
+	for (i = 0; i < cc_count; i++) {
+		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+							vdev_id[i],
+						WLAN_POLICY_MGR_ID);
+		if (!vdev) {
+			policy_mgr_err("vdev for vdev_id:%d is NULL",
+							vdev_id[i]);
+			return QDF_STATUS_E_INVAL;
+		}
+
+	/**
+	 * If channel passed is same as AP/GO operating channel, then
+	 *   return true.
+	 * If channel is different from operating channel but in same band.
+	 *   return false.
+	 * If operating channel in different band (DBS capable).
+	 *   return true.
+	 * If operating channel in different band (not DBS capable).
+	 *   return false.
+	 */
+	/* TODO: To be enhanced for SBS */
+		if (policy_mgr_is_dnsc_set(vdev)) {
+			if (operating_channel[i] == channel) {
+				*ok = true;
+				wlan_objmgr_vdev_release_ref(vdev,
+						WLAN_POLICY_MGR_ID);
+				break;
+			} else if (WLAN_REG_IS_SAME_BAND_CHANNELS(
+				operating_channel[i], channel)) {
+				*ok = false;
+				wlan_objmgr_vdev_release_ref(vdev,
+						WLAN_POLICY_MGR_ID);
+				break;
+			} else if (policy_mgr_is_hw_dbs_capable(psoc)) {
+				*ok = true;
+				wlan_objmgr_vdev_release_ref(vdev,
+						WLAN_POLICY_MGR_ID);
+				break;
+			} else {
+				*ok = false;
+				wlan_objmgr_vdev_release_ref(vdev,
+						WLAN_POLICY_MGR_ID);
+				break;
+			}
+		} else {
+			*ok = true;
+		}
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID);
+	}
+	policy_mgr_debug("chan: %d ok %d", channel, *ok);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+uint32_t policy_mgr_get_hw_dbs_nss(struct wlan_objmgr_psoc *psoc,
+				   struct dbs_nss *nss_dbs)
+{
+	int i, param;
+	uint32_t dbs, tx_chain0, rx_chain0, tx_chain1, rx_chain1;
+	uint32_t min_mac0_rf_chains, min_mac1_rf_chains;
+	uint32_t max_rf_chains, final_max_rf_chains = HW_MODE_SS_0x0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return final_max_rf_chains;
+	}
+
+	for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) {
+		param = pm_ctx->hw_mode.hw_mode_list[i];
+		dbs = POLICY_MGR_HW_MODE_DBS_MODE_GET(param);
+
+		if (dbs) {
+			tx_chain0
+				= POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(param);
+			rx_chain0
+				= POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(param);
+
+			tx_chain1
+				= POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(param);
+			rx_chain1
+				= POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(param);
+
+			min_mac0_rf_chains = QDF_MIN(tx_chain0, rx_chain0);
+			min_mac1_rf_chains = QDF_MIN(tx_chain1, rx_chain1);
+
+			max_rf_chains
+			= QDF_MAX(min_mac0_rf_chains, min_mac1_rf_chains);
+
+			if (final_max_rf_chains < max_rf_chains) {
+				final_max_rf_chains
+					= (max_rf_chains == 2)
+					? HW_MODE_SS_2x2 : HW_MODE_SS_1x1;
+
+				nss_dbs->mac0_ss
+					= (min_mac0_rf_chains == 2)
+					? HW_MODE_SS_2x2 : HW_MODE_SS_1x1;
+
+				nss_dbs->mac1_ss
+					= (min_mac1_rf_chains == 2)
+					? HW_MODE_SS_2x2 : HW_MODE_SS_1x1;
+			}
+		} else {
+			continue;
+		}
+	}
+
+	return final_max_rf_chains;
+}
+
+bool policy_mgr_is_scan_simultaneous_capable(struct wlan_objmgr_psoc *psoc)
+{
+	if ((DISABLE_DBS_CXN_AND_SCAN ==
+	     wlan_objmgr_psoc_get_dual_mac_disable(psoc)) ||
+	    (ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN ==
+	     wlan_objmgr_psoc_get_dual_mac_disable(psoc)) ||
+	    (ENABLE_DBS_CXN_AND_DISABLE_SIMULTANEOUS_SCAN ==
+	     wlan_objmgr_psoc_get_dual_mac_disable(psoc)) ||
+	     !policy_mgr_is_hw_dbs_capable(psoc))
+		return false;
+
+	return true;
+}
+
+void policy_mgr_set_cur_conc_system_pref(struct wlan_objmgr_psoc *psoc,
+		uint8_t conc_system_pref)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	policy_mgr_debug("conc_system_pref %hu", conc_system_pref);
+	pm_ctx->cur_conc_system_pref = conc_system_pref;
+}
+
+uint8_t policy_mgr_get_cur_conc_system_pref(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return PM_THROUGHPUT;
+	}
+
+	policy_mgr_debug("conc_system_pref %hu", pm_ctx->cur_conc_system_pref);
+	return pm_ctx->cur_conc_system_pref;
+}
+
+QDF_STATUS policy_mgr_get_updated_scan_and_fw_mode_config(
+		struct wlan_objmgr_psoc *psoc, uint32_t *scan_config,
+		uint32_t *fw_mode_config, uint32_t dual_mac_disable_ini,
+		uint32_t channel_select_logic_conc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	*scan_config = pm_ctx->dual_mac_cfg.cur_scan_config;
+	*fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config;
+	switch (dual_mac_disable_ini) {
+	case DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN_WITH_ASYNC_SCAN_OFF:
+		policy_mgr_debug("dual_mac_disable_ini:%d async/dbs off",
+			dual_mac_disable_ini);
+		WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_SET(*scan_config, 0);
+		WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_SET(*fw_mode_config, 0);
+		break;
+	case DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN:
+		policy_mgr_debug("dual_mac_disable_ini:%d dbs_cxn off",
+			dual_mac_disable_ini);
+		WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_SET(*fw_mode_config, 0);
+		break;
+	case ENABLE_DBS_CXN_AND_ENABLE_SCAN_WITH_ASYNC_SCAN_OFF:
+		policy_mgr_debug("dual_mac_disable_ini:%d async off",
+			dual_mac_disable_ini);
+		WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_SET(*scan_config, 0);
+		break;
+	case ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN:
+		policy_mgr_debug("%s: dual_mac_disable_ini:%d ", __func__,
+				dual_mac_disable_ini);
+		WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(*scan_config, 0);
+		break;
+	default:
+		break;
+	}
+
+	WMI_DBS_FW_MODE_CFG_DBS_FOR_STA_PLUS_STA_SET(*fw_mode_config,
+		PM_CHANNEL_SELECT_LOGIC_STA_STA_GET(channel_select_logic_conc));
+	WMI_DBS_FW_MODE_CFG_DBS_FOR_STA_PLUS_P2P_SET(*fw_mode_config,
+		PM_CHANNEL_SELECT_LOGIC_STA_P2P_GET(channel_select_logic_conc));
+
+	policy_mgr_debug("*scan_config:%x ", *scan_config);
+	policy_mgr_debug("*fw_mode_config:%x ", *fw_mode_config);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool policy_mgr_is_force_scc(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return 0;
+	}
+
+	return ((pm_ctx->cfg.mcc_to_scc_switch ==
+		QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION) ||
+		(pm_ctx->cfg.mcc_to_scc_switch ==
+		QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) ||
+		(pm_ctx->cfg.mcc_to_scc_switch ==
+		QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION) ||
+		(pm_ctx->cfg.mcc_to_scc_switch ==
+		QDF_MCC_TO_SCC_WITH_PREFERRED_BAND));
+}
+
+bool policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(
+		struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool status = false;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return status;
+	}
+
+	if (policy_mgr_is_force_scc(psoc) &&
+		pm_ctx->user_cfg.is_sta_sap_scc_allowed_on_dfs_chan)
+		status = true;
+
+	return status;
+}
+
+bool policy_mgr_is_sta_connected_2g(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t conn_index;
+	bool ret = false;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return ret;
+	}
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+	     conn_index++) {
+		if (pm_conc_connection_list[conn_index].mode == PM_STA_MODE &&
+		    pm_conc_connection_list[conn_index].chan <= 14 &&
+		    pm_conc_connection_list[conn_index].in_use)
+			ret = true;
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return ret;
+}
+
+void policy_mgr_trim_acs_channel_list(struct wlan_objmgr_psoc *psoc,
+		uint8_t *org_ch_list, uint8_t *org_ch_list_count)
+{
+	uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+	uint32_t index = 0, count, i, ch_list_count;
+	uint8_t band_mask = 0, ch_5g = 0, ch_24g = 0;
+	uint8_t ch_list[QDF_MAX_NUM_CHAN];
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	if (*org_ch_list_count >= QDF_MAX_NUM_CHAN) {
+		policy_mgr_err("org_ch_list_count too big %d",
+			*org_ch_list_count);
+		return;
+	}
+	/*
+	 * if force SCC is enabled and there is a STA connection, trim the
+	 * ACS channel list on the band on which STA connection is present
+	 */
+	count = policy_mgr_mode_specific_connection_count(
+				psoc, PM_STA_MODE, list);
+	if (!(policy_mgr_is_force_scc(psoc) && count))
+		return;
+	while (index < count) {
+		if (WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[list[index]].chan) &&
+			policy_mgr_is_safe_channel(psoc,
+			pm_conc_connection_list[list[index]].chan)) {
+			band_mask |= 1;
+			ch_24g = pm_conc_connection_list[list[index]].chan;
+		}
+		if (WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[list[index]].chan) &&
+			policy_mgr_is_safe_channel(psoc,
+			pm_conc_connection_list[list[index]].chan) &&
+			!wlan_reg_is_dfs_ch(pm_ctx->pdev,
+			pm_conc_connection_list[list[index]].chan) &&
+			!wlan_reg_is_passive_or_disable_ch(pm_ctx->pdev,
+			pm_conc_connection_list[list[index]].chan)) {
+			band_mask |= 2;
+			ch_5g = pm_conc_connection_list[list[index]].chan;
+		}
+		index++;
+	}
+	ch_list_count = 0;
+	if (band_mask == 1) {
+		ch_list[ch_list_count++] = ch_24g;
+		for (i = 0; i < *org_ch_list_count; i++) {
+			if (WLAN_REG_IS_24GHZ_CH(
+				org_ch_list[i]))
+				continue;
+			ch_list[ch_list_count++] =
+				org_ch_list[i];
+		}
+	} else if (band_mask == 2) {
+		if ((reg_get_channel_state(pm_ctx->pdev, ch_5g) ==
+			CHANNEL_STATE_DFS) &&
+		      policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc))
+			ch_list[ch_list_count++] = ch_5g;
+		else if (!(reg_get_channel_state(pm_ctx->pdev, ch_5g) ==
+			CHANNEL_STATE_DFS))
+			ch_list[ch_list_count++] = ch_5g;
+		for (i = 0; i < *org_ch_list_count; i++) {
+			if (WLAN_REG_IS_5GHZ_CH(
+				org_ch_list[i]))
+				continue;
+			ch_list[ch_list_count++] =
+				org_ch_list[i];
+		}
+	} else if (band_mask == 3) {
+		ch_list[ch_list_count++] = ch_24g;
+		ch_list[ch_list_count++] = ch_5g;
+	} else {
+		policy_mgr_debug("unexpected band_mask value %d",
+			band_mask);
+		return;
+	}
+
+	*org_ch_list_count = ch_list_count;
+	for (i = 0; i < *org_ch_list_count; i++)
+		org_ch_list[i] = ch_list[i];
+
+}
+
+uint32_t policy_mgr_get_connection_info(struct wlan_objmgr_psoc *psoc,
+					struct connection_info *info)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t conn_index, count = 0;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return count;
+	}
+
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+	     conn_index++) {
+		if (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) {
+			info[count].vdev_id =
+				pm_conc_connection_list[conn_index].vdev_id;
+			info[count].mac_id =
+				pm_conc_connection_list[conn_index].mac;
+			info[count].channel =
+				pm_conc_connection_list[conn_index].chan;
+			count++;
+		}
+	}
+
+	return count;
+}
+
+bool policy_mgr_allow_sap_go_concurrency(struct wlan_objmgr_psoc *psoc,
+					 enum policy_mgr_con_mode mode,
+					 uint8_t channel,
+					 uint32_t vdev_id)
+{
+	enum policy_mgr_con_mode con_mode;
+	uint8_t con_chan;
+	int id;
+	uint32_t vdev;
+	bool dbs;
+
+	if (mode != PM_SAP_MODE && mode != PM_P2P_GO_MODE)
+		return true;
+	if (policy_mgr_dual_beacon_on_single_mac_mcc_capable(psoc))
+		return true;
+	dbs = policy_mgr_is_hw_dbs_capable(psoc);
+	for (id = 0; id < MAX_NUMBER_OF_CONC_CONNECTIONS; id++) {
+		if (!pm_conc_connection_list[id].in_use)
+			continue;
+		vdev = pm_conc_connection_list[id].vdev_id;
+		if (vdev_id == vdev)
+			continue;
+		con_mode = pm_conc_connection_list[id].mode;
+		if (con_mode != PM_SAP_MODE && con_mode != PM_P2P_GO_MODE)
+			continue;
+		con_chan = pm_conc_connection_list[id].chan;
+		if (policy_mgr_dual_beacon_on_single_mac_scc_capable(psoc) &&
+		    (channel == con_chan)) {
+			policy_mgr_debug("SCC enabled, 2 AP on same channel, allow 2nd AP");
+			return true;
+		}
+		if (!dbs) {
+			policy_mgr_debug("DBS unsupported, mcc and scc unsupported too, don't allow 2nd AP");
+			return false;
+		}
+		if (WLAN_REG_IS_SAME_BAND_CHANNELS(channel, con_chan)) {
+			policy_mgr_debug("DBS supported, 2 SAP on same band, reject 2nd AP");
+			return false;
+		}
+	}
+
+	/* Don't block the second interface */
+	return true;
+}
+
+bool policy_mgr_dual_beacon_on_single_mac_scc_capable(
+		struct wlan_objmgr_psoc *psoc)
+{
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		policy_mgr_debug("Invalid WMI handle");
+		return false;
+	}
+
+	if (wmi_service_enabled(
+			wmi_handle,
+			wmi_service_dual_beacon_on_single_mac_scc_support)) {
+		policy_mgr_debug("Dual beaconing on same channel on single MAC supported");
+		return true;
+	}
+	policy_mgr_debug("Dual beaconing on same channel on single MAC is not supported");
+	return false;
+}
+
+bool policy_mgr_dual_beacon_on_single_mac_mcc_capable(
+		struct wlan_objmgr_psoc *psoc)
+{
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		policy_mgr_debug("Invalid WMI handle");
+		return false;
+	}
+
+	if (wmi_service_enabled(
+			wmi_handle,
+			wmi_service_dual_beacon_on_single_mac_mcc_support)) {
+		policy_mgr_debug("Dual beaconing on different channel on single MAC supported");
+		return true;
+	}
+	policy_mgr_debug("Dual beaconing on different channel on single MAC is not supported");
+	return false;
+}
+
+bool policy_mgr_sta_sap_scc_on_lte_coex_chan(
+	struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+	return pm_ctx->user_cfg.sta_sap_scc_on_lte_coex_chan;
+}
+
+bool policy_mgr_is_valid_for_channel_switch(struct wlan_objmgr_psoc *psoc,
+					    uint8_t channel)
+{
+	uint32_t sta_sap_scc_on_dfs_chan;
+	uint32_t sap_count;
+	enum channel_state state;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	sta_sap_scc_on_dfs_chan =
+			policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc);
+	sap_count = policy_mgr_mode_specific_connection_count(psoc,
+							      PM_SAP_MODE,
+							      NULL);
+	state = reg_get_channel_state(pm_ctx->pdev, channel);
+
+	policy_mgr_debug("sta_sap_scc_on_dfs_chan %u, sap_count %u, channel %u, state %u",
+			 sta_sap_scc_on_dfs_chan, sap_count, channel, state);
+
+	if ((state == CHANNEL_STATE_ENABLE) || (sap_count == 0) ||
+	    ((state == CHANNEL_STATE_DFS) && sta_sap_scc_on_dfs_chan)) {
+		policy_mgr_debug("Valid channel for channel switch");
+		return true;
+	}
+
+	policy_mgr_debug("Invalid channel for channel switch");
+	return false;
+}
+
+bool policy_mgr_is_sta_sap_scc(struct wlan_objmgr_psoc *psoc, uint8_t sap_ch)
+{
+	uint32_t conn_index;
+	bool is_scc = false;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return is_scc;
+	}
+
+	if (!policy_mgr_mode_specific_connection_count(
+		psoc, PM_STA_MODE, NULL)) {
+		policy_mgr_debug("There is no STA+SAP conc");
+		return is_scc;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		conn_index++) {
+		if (pm_conc_connection_list[conn_index].in_use &&
+			(pm_conc_connection_list[conn_index].mode ==
+			PM_STA_MODE) &&
+			(sap_ch == pm_conc_connection_list[conn_index].chan)) {
+			is_scc = true;
+			break;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return is_scc;
+}

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

@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef WLAN_POLICY_MGR_I_H
+#define WLAN_POLICY_MGR_I_H
+
+#include "wlan_policy_mgr_api.h"
+#include "qdf_event.h"
+#include "qdf_mc_timer.h"
+#include "qdf_lock.h"
+#include "qdf_defer.h"
+#include "wlan_reg_services_api.h"
+
+#define DBS_OPPORTUNISTIC_TIME   5
+#ifdef QCA_WIFI_3_0_EMU
+#define CONNECTION_UPDATE_TIMEOUT 3000
+#else
+#define CONNECTION_UPDATE_TIMEOUT 1000
+#endif
+
+#define PM_24_GHZ_CHANNEL_6   (6)
+#define PM_5_GHZ_CHANNEL_36   (36)
+#define CHANNEL_SWITCH_COMPLETE_TIMEOUT   (2000)
+
+/**
+ * Policy Mgr hardware mode list bit-mask definitions.
+ * Bits 4:0, 31:29 are unused.
+ *
+ * The below definitions are added corresponding to WMI DBS HW mode
+ * list to make it independent of firmware changes for WMI definitions.
+ * Currently these definitions have dependency with BIT positions of
+ * the existing WMI macros. Thus, if the BIT positions are changed for
+ * WMI macros, then these macros' BIT definitions are also need to be
+ * changed.
+ */
+#define POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_BITPOS  (28)
+#define POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_BITPOS  (24)
+#define POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_BITPOS  (20)
+#define POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_BITPOS  (16)
+#define POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_BITPOS   (12)
+#define POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_BITPOS   (8)
+#define POLICY_MGR_HW_MODE_DBS_MODE_BITPOS         (7)
+#define POLICY_MGR_HW_MODE_AGILE_DFS_MODE_BITPOS   (6)
+#define POLICY_MGR_HW_MODE_SBS_MODE_BITPOS         (5)
+#define POLICY_MGR_HW_MODE_MAC0_BAND_BITPOS        (3)
+#define POLICY_MGR_HW_MODE_ID_BITPOS               (0)
+
+#define POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_MASK    \
+	(0xf << POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_MASK    \
+	(0xf << POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_MASK    \
+	(0xf << POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_MASK    \
+	(0xf << POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_MASK     \
+	(0xf << POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_MASK     \
+	(0xf << POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_BITPOS)
+#define POLICY_MGR_HW_MODE_DBS_MODE_MASK           \
+	(0x1 << POLICY_MGR_HW_MODE_DBS_MODE_BITPOS)
+#define POLICY_MGR_HW_MODE_AGILE_DFS_MODE_MASK     \
+	(0x1 << POLICY_MGR_HW_MODE_AGILE_DFS_MODE_BITPOS)
+#define POLICY_MGR_HW_MODE_SBS_MODE_MASK           \
+	(0x1 << POLICY_MGR_HW_MODE_SBS_MODE_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC0_BAND_MASK           \
+			(0x3 << POLICY_MGR_HW_MODE_MAC0_BAND_BITPOS)
+#define POLICY_MGR_HW_MODE_ID_MASK           \
+			(0x7 << POLICY_MGR_HW_MODE_ID_BITPOS)
+
+#define POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_SET(hw_mode, value) \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_BITPOS,\
+	4, value)
+#define POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_SET(hw_mode, value) \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_BITPOS,\
+	4, value)
+#define POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_SET(hw_mode, value) \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_BITPOS,\
+	4, value)
+#define POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_SET(hw_mode, value) \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_BITPOS,\
+	4, value)
+#define POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_SET(hw_mode, value)  \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_BITPOS,\
+	4, value)
+#define POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_SET(hw_mode, value)  \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_BITPOS,\
+	4, value)
+#define POLICY_MGR_HW_MODE_DBS_MODE_SET(hw_mode, value)        \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_DBS_MODE_BITPOS,\
+	1, value)
+#define POLICY_MGR_HW_MODE_AGILE_DFS_SET(hw_mode, value)       \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_AGILE_DFS_MODE_BITPOS,\
+	1, value)
+#define POLICY_MGR_HW_MODE_SBS_MODE_SET(hw_mode, value)        \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_SBS_MODE_BITPOS,\
+	1, value)
+#define POLICY_MGR_HW_MODE_MAC0_BAND_SET(hw_mode, value)        \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC0_BAND_BITPOS,\
+	2, value)
+#define POLICY_MGR_HW_MODE_ID_SET(hw_mode, value)        \
+	WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_ID_BITPOS,\
+	3, value)
+
+#define POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(hw_mode)                \
+		(((hw_mode) & POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_MASK) >>    \
+		POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(hw_mode)                \
+		(((hw_mode) & POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_MASK) >>    \
+		POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(hw_mode)                \
+		(((hw_mode) & POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_MASK) >>    \
+		POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(hw_mode)                \
+		(((hw_mode) & POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_MASK) >>    \
+		POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(hw_mode)                 \
+		(((hw_mode) & POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_MASK) >>     \
+		POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET(hw_mode)                 \
+		(((hw_mode) & POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_MASK) >>     \
+		POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_BITPOS)
+#define POLICY_MGR_HW_MODE_DBS_MODE_GET(hw_mode)                       \
+		(((hw_mode) & POLICY_MGR_HW_MODE_DBS_MODE_MASK) >>           \
+		POLICY_MGR_HW_MODE_DBS_MODE_BITPOS)
+#define POLICY_MGR_HW_MODE_AGILE_DFS_GET(hw_mode)                      \
+		(((hw_mode) & POLICY_MGR_HW_MODE_AGILE_DFS_MODE_MASK) >>     \
+		POLICY_MGR_HW_MODE_AGILE_DFS_MODE_BITPOS)
+#define POLICY_MGR_HW_MODE_SBS_MODE_GET(hw_mode)                       \
+		(((hw_mode) & POLICY_MGR_HW_MODE_SBS_MODE_MASK) >>           \
+		POLICY_MGR_HW_MODE_SBS_MODE_BITPOS)
+#define POLICY_MGR_HW_MODE_MAC0_BAND_GET(hw_mode)                       \
+		(((hw_mode) & POLICY_MGR_HW_MODE_MAC0_BAND_MASK) >> \
+		POLICY_MGR_HW_MODE_MAC0_BAND_BITPOS)
+#define POLICY_MGR_HW_MODE_ID_GET(hw_mode)                       \
+		(((hw_mode) & POLICY_MGR_HW_MODE_ID_MASK) >> \
+		POLICY_MGR_HW_MODE_ID_BITPOS)
+
+#define POLICY_MGR_DEFAULT_HW_MODE_INDEX 0xFFFF
+
+#define policy_mgr_alert(params...) \
+	QDF_TRACE_FATAL(QDF_MODULE_ID_POLICY_MGR, params)
+#define policy_mgr_err(params...) \
+	QDF_TRACE_ERROR(QDF_MODULE_ID_POLICY_MGR, params)
+#define policy_mgr_warn(params...) \
+	QDF_TRACE_WARN(QDF_MODULE_ID_POLICY_MGR, params)
+#define policy_mgr_notice(params...) \
+	QDF_TRACE_INFO(QDF_MODULE_ID_POLICY_MGR, params)
+#define policy_mgr_info(params...) \
+	QDF_TRACE_INFO(QDF_MODULE_ID_POLICY_MGR, params)
+#define policy_mgr_debug(params...) \
+	QDF_TRACE_DEBUG(QDF_MODULE_ID_POLICY_MGR, params)
+
+#define policymgr_nofl_alert(params...) \
+	QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_POLICY_MGR, params)
+#define policymgr_nofl_err(params...) \
+	QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_POLICY_MGR, params)
+#define policymgr_nofl_warn(params...) \
+	QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_POLICY_MGR, params)
+#define policymgr_nofl_info(params...) \
+	QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_POLICY_MGR, params)
+#define policymgr_nofl_debug(params...) \
+	QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_POLICY_MGR, params)
+
+#define PM_CONC_CONNECTION_LIST_VALID_INDEX(index) \
+		((MAX_NUMBER_OF_CONC_CONNECTIONS > index) && \
+			(pm_conc_connection_list[index].in_use))
+
+extern struct policy_mgr_conc_connection_info
+	pm_conc_connection_list[MAX_NUMBER_OF_CONC_CONNECTIONS];
+
+extern const enum policy_mgr_pcl_type
+	first_connection_pcl_table[PM_MAX_NUM_OF_MODE]
+			[PM_MAX_CONC_PRIORITY_MODE];
+extern pm_dbs_pcl_second_connection_table_type
+		*second_connection_pcl_dbs_table;
+extern pm_dbs_pcl_third_connection_table_type
+		*third_connection_pcl_dbs_table;
+extern policy_mgr_next_action_two_connection_table_type
+		*next_action_two_connection_table;
+extern policy_mgr_next_action_three_connection_table_type
+		*next_action_three_connection_table;
+extern policy_mgr_next_action_two_connection_table_type
+		*next_action_two_connection_2x2_2g_1x1_5g_table;
+extern policy_mgr_next_action_three_connection_table_type
+		*next_action_three_connection_2x2_2g_1x1_5g_table;
+
+extern enum policy_mgr_conc_next_action
+	(*policy_mgr_get_current_pref_hw_mode_ptr)
+	(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * struct sta_ap_intf_check_work_ctx - sta_ap_intf_check_work
+ * related info
+ * @psoc: pointer to PSOC object information
+ */
+struct sta_ap_intf_check_work_ctx {
+	struct wlan_objmgr_psoc *psoc;
+};
+
+/**
+ * struct policy_mgr_cfg - all the policy manager owned configs
+ * @mcc_to_scc_switch: switch to indicate MCC to SCC config
+ * @sys_pref: system's preference while selecting PCLs
+ * @max_conc_cxns: Max allowed concurrenct active connections
+ * @conc_rule1: concurrency rule1
+ * @conc_rule2: concurrency rule2
+ * @dbs_selection_plcy: DBS selection policy for concurrency
+ * @vdev_priority_list: Priority list for various vdevs
+ * @chnl_select_plcy: Channel selection policy
+ * @enable_mcc_adaptive_sch: Enable/Disable MCC adaptive scheduler
+ * @enable_sta_cxn_5g_band: Enable/Disable STA connection in 5G band
+ */
+struct policy_mgr_cfg {
+	uint8_t mcc_to_scc_switch;
+	uint8_t sys_pref;
+	uint8_t max_conc_cxns;
+	uint8_t conc_rule1;
+	uint8_t conc_rule2;
+	uint8_t enable_mcc_adaptive_sch;
+	uint8_t enable_sta_cxn_5g_band;
+	uint32_t dbs_selection_plcy;
+	uint32_t vdev_priority_list;
+	uint32_t chnl_select_plcy;
+};
+
+/**
+ * struct policy_mgr_psoc_priv_obj - Policy manager private data
+ * @psoc: pointer to PSOC object information
+ * @pdev: pointer to PDEV object information
+ * @connection_update_done_evt: qdf event to synchronize
+ *                            connection activities
+ * @qdf_conc_list_lock: To protect connection table
+ * @dbs_opportunistic_timer: Timer to drop down to Single Mac
+ *                         Mode opportunistically
+ * @sap_restart_chan_switch_cb: Callback for channel switch
+ *                            notification for SAP
+ * @sme_cbacks: callbacks to be registered by SME for
+ *            interaction with Policy Manager
+ * @wma_cbacks: callbacks to be registered by SME for
+ * interaction with Policy Manager
+ * @tdls_cbacks: callbacks to be registered by SME for
+ * interaction with Policy Manager
+ * @cdp_cbacks: callbacks to be registered by SME for
+ * interaction with Policy Manager
+ * @sap_mandatory_channels: The user preferred master list on
+ *                        which SAP can be brought up. This
+ *                        mandatory channel list would be as per
+ *                        OEMs preference & conforming to the
+ *                        regulatory/other considerations
+ * @sap_mandatory_channels_len: Length of the SAP mandatory
+ *                            channel list
+ * @do_hw_mode_change: Flag to check if HW mode change is needed
+ *                   after vdev is up. Especially used after
+ *                   channel switch related vdev restart
+ * @concurrency_mode: active concurrency combination
+ * @no_of_open_sessions: Number of active vdevs
+ * @no_of_active_sessions: Number of active connections
+ * @sta_ap_intf_check_work: delayed sap restart work
+ * @num_dbs_hw_modes: Number of different HW modes supported
+ * @hw_mode: List of HW modes supported
+ * @old_hw_mode_index: Old HW mode from hw_mode table
+ * @new_hw_mode_index: New HW mode from hw_mode table
+ * @dual_mac_cfg: DBS configuration currenctly used by FW for
+ *              scan & connections
+ * @hw_mode_change_in_progress: This is to track if HW mode
+ *                            change is in progress
+ * @enable_mcc_adaptive_scheduler: Enable MCC adaptive scheduler
+ *      value from INI
+ * @unsafe_channel_list: LTE coex channel avoidance list
+ * @unsafe_channel_count: LTE coex channel avoidance list count
+ * @sta_ap_intf_check_work_info: Info related to sta_ap_intf_check_work
+ * @opportunistic_update_done_evt: qdf event to synchronize host
+ *                               & FW HW mode
+ */
+struct policy_mgr_psoc_priv_obj {
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_pdev *pdev;
+	qdf_event_t connection_update_done_evt;
+	qdf_mutex_t qdf_conc_list_lock;
+	qdf_mc_timer_t dbs_opportunistic_timer;
+	struct policy_mgr_hdd_cbacks hdd_cbacks;
+	struct policy_mgr_sme_cbacks sme_cbacks;
+	struct policy_mgr_wma_cbacks wma_cbacks;
+	struct policy_mgr_tdls_cbacks tdls_cbacks;
+	struct policy_mgr_cdp_cbacks cdp_cbacks;
+	struct policy_mgr_dp_cbacks dp_cbacks;
+	bool enable_sap_mandatory_chan_list;
+	uint8_t sap_mandatory_channels[QDF_MAX_NUM_CHAN];
+	uint32_t sap_mandatory_channels_len;
+	bool do_hw_mode_change;
+	uint32_t concurrency_mode;
+	uint8_t no_of_open_sessions[QDF_MAX_NO_OF_MODE];
+	uint8_t no_of_active_sessions[QDF_MAX_NO_OF_MODE];
+	qdf_work_t sta_ap_intf_check_work;
+	uint32_t num_dbs_hw_modes;
+	struct dbs_hw_mode_info hw_mode;
+	uint32_t old_hw_mode_index;
+	uint32_t new_hw_mode_index;
+	struct dual_mac_config dual_mac_cfg;
+	uint32_t hw_mode_change_in_progress;
+	struct policy_mgr_user_cfg user_cfg;
+	uint16_t unsafe_channel_list[QDF_MAX_NUM_CHAN];
+	uint16_t unsafe_channel_count;
+	struct sta_ap_intf_check_work_ctx *sta_ap_intf_check_work_info;
+	uint8_t cur_conc_system_pref;
+	uint8_t sta_sap_scc_on_dfs_chan_allowed;
+	qdf_event_t opportunistic_update_done_evt;
+	qdf_event_t channel_switch_complete_evt;
+	send_mode_change_event_cb mode_change_cb;
+	uint32_t user_config_sap_channel;
+	struct policy_mgr_cfg cfg;
+};
+
+/**
+ * struct policy_mgr_mac_ss_bw_info - hw_mode_list PHY/MAC params for each MAC
+ * @mac_tx_stream: Max TX stream number supported on MAC
+ * @mac_rx_stream: Max RX stream number supported on MAC
+ * @mac_bw: Max bandwidth(wmi_channel_width enum type)
+ * @mac_band_cap: supported Band bit map(WLAN_2G_CAPABILITY = 0x1,
+ *                            WLAN_5G_CAPABILITY = 0x2)
+ */
+struct policy_mgr_mac_ss_bw_info {
+	uint32_t mac_tx_stream;
+	uint32_t mac_rx_stream;
+	uint32_t mac_bw;
+	uint32_t mac_band_cap;
+};
+
+struct policy_mgr_psoc_priv_obj *policy_mgr_get_context(
+		struct wlan_objmgr_psoc *psoc);
+QDF_STATUS policy_mgr_get_updated_scan_config(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t *scan_config,
+		bool dbs_scan,
+		bool dbs_plus_agile_scan,
+		bool single_mac_scan_with_dfs);
+QDF_STATUS policy_mgr_get_updated_fw_mode_config(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t *fw_mode_config,
+		bool dbs,
+		bool agile_dfs);
+bool policy_mgr_is_dual_mac_disabled_in_ini(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_mcc_to_scc_switch_mode() - MCC to SCC
+ * switch mode value in the user config
+ * @psoc: PSOC object information
+ *
+ * MCC to SCC switch mode value in user config
+ *
+ * Return: MCC to SCC switch mode value
+ */
+uint32_t policy_mgr_get_mcc_to_scc_switch_mode(
+	struct wlan_objmgr_psoc *psoc);
+bool policy_mgr_get_dbs_config(struct wlan_objmgr_psoc *psoc);
+bool policy_mgr_get_agile_dfs_config(struct wlan_objmgr_psoc *psoc);
+bool policy_mgr_get_dbs_scan_config(struct wlan_objmgr_psoc *psoc);
+void policy_mgr_get_tx_rx_ss_from_config(enum hw_mode_ss_config mac_ss,
+		uint32_t *tx_ss, uint32_t *rx_ss);
+int8_t policy_mgr_get_matching_hw_mode_index(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t mac0_tx_ss, uint32_t mac0_rx_ss,
+		enum hw_mode_bandwidth mac0_bw,
+		uint32_t mac1_tx_ss, uint32_t mac1_rx_ss,
+		enum hw_mode_bandwidth mac1_bw,
+		enum hw_mode_mac_band_cap mac0_band_cap,
+		enum hw_mode_dbs_capab dbs,
+		enum hw_mode_agile_dfs_capab dfs,
+		enum hw_mode_sbs_capab sbs);
+int8_t policy_mgr_get_hw_mode_idx_from_dbs_hw_list(
+		struct wlan_objmgr_psoc *psoc,
+		enum hw_mode_ss_config mac0_ss,
+		enum hw_mode_bandwidth mac0_bw,
+		enum hw_mode_ss_config mac1_ss,
+		enum hw_mode_bandwidth mac1_bw,
+		enum hw_mode_mac_band_cap mac0_band_cap,
+		enum hw_mode_dbs_capab dbs,
+		enum hw_mode_agile_dfs_capab dfs,
+		enum hw_mode_sbs_capab sbs);
+QDF_STATUS policy_mgr_get_old_and_new_hw_index(
+		struct wlan_objmgr_psoc *psoc,
+		uint32_t *old_hw_mode_index,
+		uint32_t *new_hw_mode_index);
+void policy_mgr_update_conc_list(struct wlan_objmgr_psoc *psoc,
+		uint32_t conn_index,
+		enum policy_mgr_con_mode mode,
+		uint8_t chan,
+		enum hw_mode_bandwidth bw,
+		uint8_t mac,
+		enum policy_mgr_chain_mode chain_mask,
+		uint32_t original_nss,
+		uint32_t vdev_id,
+		bool in_use,
+		bool update_conn);
+void policy_mgr_store_and_del_conn_info(struct wlan_objmgr_psoc *psoc,
+				enum policy_mgr_con_mode mode,
+				bool all_matching_cxn_to_del,
+				struct policy_mgr_conc_connection_info *info,
+				uint8_t *num_cxn_del);
+
+/**
+ * policy_mgr_store_and_del_conn_info_by_vdev_id() - Store and del a
+ * connection info by vdev id
+ * @psoc: PSOC object information
+ * @vdev_id: vdev id whose entry has to be deleted
+ * @info: struture array pointer where the connection info will be saved
+ * @num_cxn_del: number of connection which are going to be deleted
+ *
+ * Saves the connection info corresponding to the provided mode
+ * and deleted that corresponding entry based on vdev from the
+ * connection info structure
+ *
+ * Return: None
+ */
+void policy_mgr_store_and_del_conn_info_by_vdev_id(
+			struct wlan_objmgr_psoc *psoc,
+			uint32_t vdev_id,
+			struct policy_mgr_conc_connection_info *info,
+			uint8_t *num_cxn_del);
+
+void policy_mgr_restore_deleted_conn_info(struct wlan_objmgr_psoc *psoc,
+				struct policy_mgr_conc_connection_info *info,
+				uint8_t num_cxn_del);
+void policy_mgr_update_hw_mode_conn_info(struct wlan_objmgr_psoc *psoc,
+				uint32_t num_vdev_mac_entries,
+				struct policy_mgr_vdev_mac_map *vdev_mac_map,
+				struct policy_mgr_hw_mode_params hw_mode);
+void policy_mgr_pdev_set_hw_mode_cb(uint32_t status,
+				uint32_t cfgd_hw_mode_index,
+				uint32_t num_vdev_mac_entries,
+				struct policy_mgr_vdev_mac_map *vdev_mac_map,
+				uint8_t next_action,
+				enum policy_mgr_conn_update_reason reason,
+				uint32_t session_id, void *context);
+void policy_mgr_dump_current_concurrency(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_pdev_set_pcl() - SET PCL channel list and send to firmware
+ * @psoc: PSOC object information
+ * @mode: Adapter mode
+ *
+ * Return: None
+ */
+void policy_mgr_pdev_set_pcl(struct wlan_objmgr_psoc *psoc,
+			     enum QDF_OPMODE mode);
+void pm_dbs_opportunistic_timer_handler(void *data);
+enum policy_mgr_con_mode policy_mgr_get_mode(uint8_t type,
+		uint8_t subtype);
+enum hw_mode_bandwidth policy_mgr_get_bw(enum phy_ch_width chan_width);
+QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc,
+			enum policy_mgr_pcl_type pcl,
+			uint8_t *pcl_channels, uint32_t *len,
+			enum policy_mgr_con_mode mode,
+			uint8_t *pcl_weights, uint32_t weight_len);
+bool policy_mgr_allow_new_home_channel(struct wlan_objmgr_psoc *psoc,
+			uint8_t channel, uint32_t num_connections);
+bool policy_mgr_is_5g_channel_allowed(struct wlan_objmgr_psoc *psoc,
+				uint8_t channel, uint32_t *list,
+				enum policy_mgr_con_mode mode);
+QDF_STATUS policy_mgr_complete_action(struct wlan_objmgr_psoc *psoc,
+				uint8_t  new_nss, uint8_t next_action,
+				enum policy_mgr_conn_update_reason reason,
+				uint32_t session_id);
+enum policy_mgr_con_mode policy_mgr_get_mode_by_vdev_id(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t vdev_id);
+QDF_STATUS policy_mgr_init_connection_update(
+		struct policy_mgr_psoc_priv_obj *pm_ctx);
+enum policy_mgr_conc_next_action
+		policy_mgr_get_current_pref_hw_mode_dbs_2x2(
+		struct wlan_objmgr_psoc *psoc);
+enum policy_mgr_conc_next_action
+		policy_mgr_get_current_pref_hw_mode_dbs_1x1(
+		struct wlan_objmgr_psoc *psoc);
+
+/**
+ * policy_mgr_get_current_pref_hw_mode_dual_dbs() - Get the
+ * current preferred hw mode
+ *
+ * Get the preferred hw mode based on the current connection combinations
+ *
+ * Return: No change (PM_NOP), (PM_SINGLE_MAC_UPGRADE),
+ *         DBS (PM_DBS1_DOWNGRADE or PM_DBS2_DOWNGRADE)
+ */
+enum policy_mgr_conc_next_action
+		policy_mgr_get_current_pref_hw_mode_dual_dbs(
+		struct wlan_objmgr_psoc *psoc);
+
+QDF_STATUS policy_mgr_reset_sap_mandatory_channels(
+		struct policy_mgr_psoc_priv_obj *pm_ctx);
+
+/**
+ * policy_mgr_get_mode_specific_conn_info() - Get active mode specific
+ * channel and vdev id
+ * @psoc: PSOC object information
+ * @channel: Mode specific channel (list)
+ * @vdev_id: Mode specific vdev id (list)
+ * @mode: Connection Mode
+ *
+ * Get active mode specific channel and vdev id
+ *
+ * Return: number of connection found as per given mode
+ */
+uint32_t policy_mgr_get_mode_specific_conn_info(struct wlan_objmgr_psoc *psoc,
+				  uint8_t *channel, uint8_t *vdev_id,
+				  enum policy_mgr_con_mode mode);
+
+/**
+ * policy_mgr_reg_chan_change_callback() - Callback to be
+ * invoked by regulatory module when valid channel list changes
+ * @psoc: PSOC object information
+ * @pdev: PDEV object information
+ * @chan_list: New channel list
+ * @avoid_freq_ind: LTE coex avoid channel list
+ * @arg: Information passed at registration
+ *
+ * Get updated channel list from regulatory module
+ *
+ * Return: None
+ */
+void policy_mgr_reg_chan_change_callback(struct wlan_objmgr_psoc *psoc,
+		struct wlan_objmgr_pdev *pdev,
+		struct regulatory_channel *chan_list,
+		struct avoid_freq_ind_data *avoid_freq_ind,
+		void *arg);
+
+/**
+ * policy_mgr_nss_update() - update nss for AP vdev
+ * @psoc: PSOC object information
+ * @new_nss: new NSS value
+ * @next_action: Next action after nss update
+ * @band: update AP vdev on the Band.
+ * @reason: action reason
+ * @original_vdev_id: original request hwmode change vdev id
+ *
+ * The function will update AP vdevs on specific band.
+ *  eg. band = POLICY_MGR_ANY will request to update all band (2g and 5g)
+ *
+ * Return: QDF_STATUS_SUCCESS, update requested successfully.
+ */
+QDF_STATUS policy_mgr_nss_update(struct wlan_objmgr_psoc *psoc,
+		uint8_t  new_nss, uint8_t next_action,
+		enum policy_mgr_band band,
+		enum policy_mgr_conn_update_reason reason,
+		uint32_t original_vdev_id);
+
+/**
+ * policy_mgr_is_concurrency_allowed() - Check for allowed
+ * concurrency combination
+ * @psoc: PSOC object information
+ * @mode: new connection mode
+ * @channel: channel on which new connection is coming up
+ * @bw: Bandwidth requested by the connection (optional)
+ *
+ * When a new connection is about to come up check if current
+ * concurrency combination including the new connection is
+ * allowed or not based on the HW capability, but no need to
+ * invoke get_pcl
+ *
+ * Return: True/False
+ */
+bool policy_mgr_is_concurrency_allowed(struct wlan_objmgr_psoc *psoc,
+				       enum policy_mgr_con_mode mode,
+				       uint8_t channel,
+				       enum hw_mode_bandwidth bw);
+#endif

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

@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_policy_mgr_init_deinit.c
+ *
+ * WLAN Concurrenct Connection Management APIs
+ *
+ */
+
+/* Include files */
+
+#include "wlan_policy_mgr_api.h"
+#include "wlan_policy_mgr_tables_1x1_dbs_i.h"
+#include "wlan_policy_mgr_tables_2x2_dbs_i.h"
+#include "wlan_policy_mgr_tables_2x2_5g_1x1_2g.h"
+#include "wlan_policy_mgr_tables_2x2_2g_1x1_5g.h"
+#include "wlan_policy_mgr_i.h"
+#include "qdf_types.h"
+#include "qdf_trace.h"
+#include "wlan_objmgr_global_obj.h"
+
+static QDF_STATUS policy_mgr_psoc_obj_create_cb(struct wlan_objmgr_psoc *psoc,
+		void *data)
+{
+	struct policy_mgr_psoc_priv_obj *policy_mgr_ctx;
+
+	policy_mgr_ctx = qdf_mem_malloc(
+		sizeof(struct policy_mgr_psoc_priv_obj));
+	if (!policy_mgr_ctx) {
+		policy_mgr_err("memory allocation failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	policy_mgr_ctx->psoc = psoc;
+	policy_mgr_ctx->old_hw_mode_index = POLICY_MGR_DEFAULT_HW_MODE_INDEX;
+	policy_mgr_ctx->new_hw_mode_index = POLICY_MGR_DEFAULT_HW_MODE_INDEX;
+
+	wlan_objmgr_psoc_component_obj_attach(psoc,
+			WLAN_UMAC_COMP_POLICY_MGR,
+			policy_mgr_ctx,
+			QDF_STATUS_SUCCESS);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS policy_mgr_psoc_obj_destroy_cb(struct wlan_objmgr_psoc *psoc,
+		void *data)
+{
+	struct policy_mgr_psoc_priv_obj *policy_mgr_ctx;
+
+	policy_mgr_ctx = policy_mgr_get_context(psoc);
+	wlan_objmgr_psoc_component_obj_detach(psoc,
+					WLAN_UMAC_COMP_POLICY_MGR,
+					policy_mgr_ctx);
+	qdf_mem_free(policy_mgr_ctx);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void policy_mgr_psoc_obj_status_cb(struct wlan_objmgr_psoc *psoc,
+		void *data, QDF_STATUS status)
+{
+	return;
+}
+
+static QDF_STATUS policy_mgr_pdev_obj_create_cb(struct wlan_objmgr_pdev *pdev,
+		void *data)
+{
+	struct policy_mgr_psoc_priv_obj *policy_mgr_ctx;
+	struct wlan_objmgr_psoc *psoc;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	policy_mgr_ctx = policy_mgr_get_context(psoc);
+	if (!policy_mgr_ctx) {
+		policy_mgr_err("invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	policy_mgr_ctx->pdev = pdev;
+
+	wlan_reg_register_chan_change_callback(psoc,
+		policy_mgr_reg_chan_change_callback, NULL);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS policy_mgr_pdev_obj_destroy_cb(struct wlan_objmgr_pdev *pdev,
+		void *data)
+{
+	struct policy_mgr_psoc_priv_obj *policy_mgr_ctx;
+	struct wlan_objmgr_psoc *psoc;
+
+	psoc = wlan_pdev_get_psoc(pdev);
+	policy_mgr_ctx = policy_mgr_get_context(psoc);
+	if (!policy_mgr_ctx) {
+		policy_mgr_err("invalid context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	policy_mgr_ctx->pdev = NULL;
+	wlan_reg_unregister_chan_change_callback(psoc,
+		policy_mgr_reg_chan_change_callback);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS policy_mgr_vdev_obj_create_cb(struct wlan_objmgr_vdev *vdev,
+		void *data)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS policy_mgr_vdev_obj_destroy_cb(struct wlan_objmgr_vdev *vdev,
+		void *data)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static void policy_mgr_vdev_obj_status_cb(struct wlan_objmgr_vdev *vdev,
+		void *data, QDF_STATUS status)
+{
+	return;
+}
+
+QDF_STATUS policy_mgr_init(void)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	status = wlan_objmgr_register_psoc_create_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_psoc_obj_create_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register psoc obj create cback");
+		goto err_psoc_create;
+	}
+
+	status = wlan_objmgr_register_psoc_destroy_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_psoc_obj_destroy_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register psoc obj delete cback");
+		goto err_psoc_delete;
+	}
+
+	status = wlan_objmgr_register_psoc_status_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_psoc_obj_status_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register psoc obj status cback");
+		goto err_psoc_status;
+	}
+
+	status = wlan_objmgr_register_pdev_create_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_pdev_obj_create_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register pdev obj create cback");
+		goto err_pdev_create;
+	}
+
+	status = wlan_objmgr_register_pdev_destroy_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_pdev_obj_destroy_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register pdev obj delete cback");
+		goto err_pdev_delete;
+	}
+
+	status = wlan_objmgr_register_vdev_create_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_vdev_obj_create_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register vdev obj create cback");
+		goto err_vdev_create;
+	}
+
+	status = wlan_objmgr_register_vdev_destroy_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_vdev_obj_destroy_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register vdev obj delete cback");
+		goto err_vdev_delete;
+	}
+
+	status = wlan_objmgr_register_vdev_status_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_vdev_obj_status_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("Failed to register vdev obj status cback");
+		goto err_vdev_status;
+	}
+
+	policy_mgr_notice("Callbacks registered with obj mgr");
+
+	return QDF_STATUS_SUCCESS;
+
+err_vdev_status:
+	wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_POLICY_MGR,
+						policy_mgr_vdev_obj_destroy_cb,
+						NULL);
+err_vdev_delete:
+	wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_POLICY_MGR,
+						policy_mgr_vdev_obj_create_cb,
+						NULL);
+err_vdev_create:
+	wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_POLICY_MGR,
+						policy_mgr_pdev_obj_destroy_cb,
+						NULL);
+err_pdev_delete:
+	wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_POLICY_MGR,
+						policy_mgr_pdev_obj_create_cb,
+						NULL);
+err_pdev_create:
+	wlan_objmgr_unregister_psoc_status_handler(WLAN_UMAC_COMP_POLICY_MGR,
+						policy_mgr_psoc_obj_status_cb,
+						NULL);
+err_psoc_status:
+	wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_POLICY_MGR,
+						policy_mgr_psoc_obj_destroy_cb,
+						NULL);
+err_psoc_delete:
+	wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_POLICY_MGR,
+						policy_mgr_psoc_obj_create_cb,
+						NULL);
+err_psoc_create:
+	return status;
+}
+
+QDF_STATUS policy_mgr_deinit(void)
+{
+	QDF_STATUS status;
+
+	status = wlan_objmgr_unregister_psoc_status_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_psoc_obj_status_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to deregister psoc obj status cback");
+
+	status = wlan_objmgr_unregister_psoc_destroy_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_psoc_obj_destroy_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to deregister psoc obj delete cback");
+
+	status = wlan_objmgr_unregister_psoc_create_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_psoc_obj_create_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to deregister psoc obj create cback");
+
+	status = wlan_objmgr_unregister_pdev_destroy_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_pdev_obj_destroy_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to deregister pdev obj delete cback");
+
+	status = wlan_objmgr_unregister_pdev_create_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_pdev_obj_create_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to deregister pdev obj create cback");
+
+	status = wlan_objmgr_unregister_vdev_status_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_vdev_obj_status_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to deregister vdev obj status cback");
+
+	status = wlan_objmgr_unregister_vdev_destroy_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_vdev_obj_destroy_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to deregister vdev obj delete cback");
+
+	status = wlan_objmgr_unregister_vdev_create_handler(
+				WLAN_UMAC_COMP_POLICY_MGR,
+				policy_mgr_vdev_obj_create_cb,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS)
+		policy_mgr_err("Failed to deregister vdev obj create cback");
+
+	policy_mgr_info("deregistered callbacks with obj mgr successfully");
+
+	return status;
+}
+
+QDF_STATUS policy_mgr_psoc_open(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_create(
+		&pm_ctx->qdf_conc_list_lock))) {
+		policy_mgr_err("Failed to init qdf_conc_list_lock");
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_psoc_close(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_destroy(
+		&pm_ctx->qdf_conc_list_lock))) {
+		policy_mgr_err("Failed to destroy qdf_conc_list_lock");
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (pm_ctx->hw_mode.hw_mode_list) {
+		qdf_mem_free(pm_ctx->hw_mode.hw_mode_list);
+		pm_ctx->hw_mode.hw_mode_list = NULL;
+		policy_mgr_info("HW list is freed");
+	}
+
+	if (pm_ctx->sta_ap_intf_check_work_info) {
+		qdf_cancel_work(&pm_ctx->sta_ap_intf_check_work);
+		qdf_mem_free(pm_ctx->sta_ap_intf_check_work_info);
+		pm_ctx->sta_ap_intf_check_work_info = NULL;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_psoc_enable(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	policy_mgr_debug("Initializing the policy manager");
+
+	/* init pm_conc_connection_list */
+	qdf_mem_zero(pm_conc_connection_list, sizeof(pm_conc_connection_list));
+
+	/* init dbs_opportunistic_timer */
+	status = qdf_mc_timer_init(&pm_ctx->dbs_opportunistic_timer,
+				QDF_TIMER_TYPE_SW,
+				pm_dbs_opportunistic_timer_handler,
+				(void *)psoc);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("Failed to init DBS opportunistic timer");
+		return status;
+	}
+
+	/* init connection_update_done_evt */
+	status = policy_mgr_init_connection_update(pm_ctx);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("connection_update_done_evt init failed");
+		return status;
+	}
+
+	status = qdf_event_create(&pm_ctx->opportunistic_update_done_evt);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("opportunistic_update_done_evt init failed");
+		return status;
+	}
+
+	status = qdf_event_create(&pm_ctx->channel_switch_complete_evt);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		policy_mgr_err("channel_switch_complete_evt init failed");
+		return status;
+	}
+	pm_ctx->do_hw_mode_change = false;
+	pm_ctx->hw_mode_change_in_progress = POLICY_MGR_HW_MODE_NOT_IN_PROGRESS;
+	/* reset sap mandatory channels */
+	status = policy_mgr_reset_sap_mandatory_channels(pm_ctx);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("failed to reset mandatory channels");
+		return status;
+	}
+
+	/* init PCL table & function pointers based on HW capability */
+	if (policy_mgr_is_hw_dbs_2x2_capable(psoc))
+		policy_mgr_get_current_pref_hw_mode_ptr =
+		policy_mgr_get_current_pref_hw_mode_dbs_2x2;
+	else if (policy_mgr_is_2x2_1x1_dbs_capable(psoc))
+		policy_mgr_get_current_pref_hw_mode_ptr =
+		policy_mgr_get_current_pref_hw_mode_dual_dbs;
+	else
+		policy_mgr_get_current_pref_hw_mode_ptr =
+		policy_mgr_get_current_pref_hw_mode_dbs_1x1;
+
+	if (policy_mgr_is_hw_dbs_2x2_capable(psoc) ||
+	    policy_mgr_is_2x2_1x1_dbs_capable(psoc))
+		second_connection_pcl_dbs_table =
+		&pm_second_connection_pcl_dbs_2x2_table;
+	else
+		second_connection_pcl_dbs_table =
+		&pm_second_connection_pcl_dbs_1x1_table;
+
+	if (policy_mgr_is_hw_dbs_2x2_capable(psoc) ||
+	    policy_mgr_is_2x2_1x1_dbs_capable(psoc))
+		third_connection_pcl_dbs_table =
+		&pm_third_connection_pcl_dbs_2x2_table;
+	else
+		third_connection_pcl_dbs_table =
+		&pm_third_connection_pcl_dbs_1x1_table;
+
+	if (policy_mgr_is_hw_dbs_2x2_capable(psoc)) {
+		next_action_two_connection_table =
+		&pm_next_action_two_connection_dbs_2x2_table;
+	} else if (policy_mgr_is_2x2_1x1_dbs_capable(psoc)) {
+		next_action_two_connection_table =
+		&pm_next_action_two_connection_dbs_2x2_5g_1x1_2g_table;
+		next_action_two_connection_2x2_2g_1x1_5g_table =
+		&pm_next_action_two_connection_dbs_2x2_2g_1x1_5g_table;
+	} else {
+		next_action_two_connection_table =
+		&pm_next_action_two_connection_dbs_1x1_table;
+	}
+
+	if (policy_mgr_is_hw_dbs_2x2_capable(psoc)) {
+		next_action_three_connection_table =
+		&pm_next_action_three_connection_dbs_2x2_table;
+	} else if (policy_mgr_is_2x2_1x1_dbs_capable(psoc)) {
+		next_action_three_connection_table =
+		&pm_next_action_three_connection_dbs_2x2_5g_1x1_2g_table;
+		next_action_three_connection_2x2_2g_1x1_5g_table =
+		&pm_next_action_three_connection_dbs_2x2_2g_1x1_5g_table;
+	} else {
+		next_action_three_connection_table =
+		&pm_next_action_three_connection_dbs_1x1_table;
+	}
+	policy_mgr_debug("is DBS Capable %d, is SBS Capable %d",
+			 policy_mgr_is_hw_dbs_capable(psoc),
+			 policy_mgr_is_hw_sbs_capable(psoc));
+	policy_mgr_debug("is2x2 %d, is2x2+1x1 %d, is2x2_5g+1x1_2g %d, is2x2_2g+1x1_5g %d",
+			 policy_mgr_is_hw_dbs_2x2_capable(psoc),
+			 policy_mgr_is_2x2_1x1_dbs_capable(psoc),
+			 policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(psoc),
+			 policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(psoc));
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_psoc_disable(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* destroy connection_update_done_evt */
+	if (!QDF_IS_STATUS_SUCCESS(qdf_event_destroy
+		(&pm_ctx->connection_update_done_evt))) {
+		policy_mgr_err("Failed to destroy connection_update_done_evt");
+		status = QDF_STATUS_E_FAILURE;
+		QDF_ASSERT(0);
+	}
+
+	/* destroy opportunistic_update_done_evt */
+	if (!QDF_IS_STATUS_SUCCESS(qdf_event_destroy
+		(&pm_ctx->opportunistic_update_done_evt))) {
+		policy_mgr_err("Failed to destroy opportunistic_update_done_evt");
+		status = QDF_STATUS_E_FAILURE;
+		QDF_ASSERT(0);
+	}
+	/* destroy channel_switch_complete_evt */
+	if (!QDF_IS_STATUS_SUCCESS(qdf_event_destroy
+		(&pm_ctx->channel_switch_complete_evt))) {
+		policy_mgr_err("Failed to destroy channel_switch_complete evt");
+		status = QDF_STATUS_E_FAILURE;
+		QDF_ASSERT(0);
+	}
+
+	/* deallocate dbs_opportunistic_timer */
+	if (QDF_TIMER_STATE_RUNNING ==
+			qdf_mc_timer_get_current_state(
+				&pm_ctx->dbs_opportunistic_timer)) {
+		qdf_mc_timer_stop(&pm_ctx->dbs_opportunistic_timer);
+	}
+
+	if (!QDF_IS_STATUS_SUCCESS(qdf_mc_timer_destroy(
+			&pm_ctx->dbs_opportunistic_timer))) {
+		policy_mgr_err("Cannot deallocate dbs opportunistic timer");
+		status = QDF_STATUS_E_FAILURE;
+		QDF_ASSERT(0);
+	}
+
+	/* reset sap mandatory channels */
+	if (QDF_IS_STATUS_ERROR(
+		policy_mgr_reset_sap_mandatory_channels(pm_ctx))) {
+		policy_mgr_err("failed to reset sap mandatory channels");
+		status = QDF_STATUS_E_FAILURE;
+		QDF_ASSERT(0);
+	}
+
+	/* deinit pm_conc_connection_list */
+	qdf_mem_zero(pm_conc_connection_list, sizeof(pm_conc_connection_list));
+
+	return status;
+}
+
+QDF_STATUS policy_mgr_register_sme_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_sme_cbacks *sme_cbacks)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->sme_cbacks.sme_get_nss_for_vdev =
+		sme_cbacks->sme_get_nss_for_vdev;
+	pm_ctx->sme_cbacks.sme_get_valid_channels =
+		sme_cbacks->sme_get_valid_channels;
+	pm_ctx->sme_cbacks.sme_nss_update_request =
+		sme_cbacks->sme_nss_update_request;
+	pm_ctx->sme_cbacks.sme_pdev_set_hw_mode =
+		sme_cbacks->sme_pdev_set_hw_mode;
+	pm_ctx->sme_cbacks.sme_pdev_set_pcl =
+		sme_cbacks->sme_pdev_set_pcl;
+	pm_ctx->sme_cbacks.sme_soc_set_dual_mac_config =
+		sme_cbacks->sme_soc_set_dual_mac_config;
+	pm_ctx->sme_cbacks.sme_change_mcc_beacon_interval =
+		sme_cbacks->sme_change_mcc_beacon_interval;
+	pm_ctx->sme_cbacks.sme_get_ap_channel_from_scan =
+		sme_cbacks->sme_get_ap_channel_from_scan;
+	pm_ctx->sme_cbacks.sme_scan_result_purge =
+		sme_cbacks->sme_scan_result_purge;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * policy_mgr_register_hdd_cb() - register HDD callbacks
+ * @psoc: PSOC object information
+ * @hdd_cbacks: function pointers from HDD
+ *
+ * API, allows HDD to register callbacks to be invoked by policy
+ * mgr
+ *
+ * Return: SUCCESS,
+ *         Failure (if registration fails)
+ */
+QDF_STATUS policy_mgr_register_hdd_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_hdd_cbacks *hdd_cbacks)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->hdd_cbacks.sap_restart_chan_switch_cb =
+		hdd_cbacks->sap_restart_chan_switch_cb;
+	pm_ctx->hdd_cbacks.wlan_hdd_get_channel_for_sap_restart =
+		hdd_cbacks->wlan_hdd_get_channel_for_sap_restart;
+	pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev =
+		hdd_cbacks->get_mode_for_non_connected_vdev;
+	pm_ctx->hdd_cbacks.hdd_get_device_mode =
+		hdd_cbacks->hdd_get_device_mode;
+	pm_ctx->hdd_cbacks.hdd_wapi_security_sta_exist =
+		hdd_cbacks->hdd_wapi_security_sta_exist;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_deregister_hdd_cb(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->hdd_cbacks.sap_restart_chan_switch_cb = NULL;
+	pm_ctx->hdd_cbacks.wlan_hdd_get_channel_for_sap_restart = NULL;
+	pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev = NULL;
+	pm_ctx->hdd_cbacks.hdd_get_device_mode = NULL;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_register_wma_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_wma_cbacks *wma_cbacks)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->wma_cbacks.wma_get_connection_info =
+		wma_cbacks->wma_get_connection_info;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_register_cdp_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_cdp_cbacks *cdp_cbacks)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->cdp_cbacks.cdp_update_mac_id =
+		cdp_cbacks->cdp_update_mac_id;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_register_dp_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_dp_cbacks *dp_cbacks)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency =
+		dp_cbacks->hdd_disable_rx_ol_in_concurrency;
+	pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb =
+		dp_cbacks->hdd_set_rx_mode_rps_cb;
+	pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb =
+		dp_cbacks->hdd_ipa_set_mcc_mode_cb;
+	pm_ctx->dp_cbacks.hdd_v2_flow_pool_map =
+		dp_cbacks->hdd_v2_flow_pool_map;
+	pm_ctx->dp_cbacks.hdd_v2_flow_pool_unmap =
+		dp_cbacks->hdd_v2_flow_pool_unmap;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_register_tdls_cb(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_tdls_cbacks *tdls_cbacks)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->tdls_cbacks.tdls_notify_increment_session =
+		tdls_cbacks->tdls_notify_increment_session;
+	pm_ctx->tdls_cbacks.tdls_notify_decrement_session =
+		tdls_cbacks->tdls_notify_decrement_session;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_register_mode_change_cb(struct wlan_objmgr_psoc *psoc,
+	send_mode_change_event_cb mode_change_cb)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->mode_change_cb = mode_change_cb;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_deregister_mode_change_cb(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	pm_ctx->mode_change_cb = NULL;
+
+	return QDF_STATUS_SUCCESS;
+}

+ 1763 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c

@@ -0,0 +1,1763 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_policy_mgr_pcl.c
+ *
+ * WLAN Concurrenct Connection Management APIs
+ *
+ */
+
+/* Include files */
+
+#include "wlan_policy_mgr_api.h"
+#include "wlan_policy_mgr_tables_no_dbs_i.h"
+#include "wlan_policy_mgr_i.h"
+#include "qdf_types.h"
+#include "qdf_trace.h"
+#include "wlan_objmgr_global_obj.h"
+#include "wlan_utility.h"
+
+/**
+ * first_connection_pcl_table - table which provides PCL for the
+ * very first connection in the system
+ */
+const enum policy_mgr_pcl_type
+first_connection_pcl_table[PM_MAX_NUM_OF_MODE]
+			[PM_MAX_CONC_PRIORITY_MODE] = {
+	[PM_STA_MODE] = {PM_NONE, PM_NONE, PM_NONE},
+	[PM_SAP_MODE] = {PM_5G,   PM_5G,   PM_5G  },
+	[PM_P2P_CLIENT_MODE] = {PM_5G,   PM_5G,   PM_5G  },
+	[PM_P2P_GO_MODE] = {PM_5G,   PM_5G,   PM_5G  },
+	[PM_IBSS_MODE] = {PM_NONE, PM_NONE, PM_NONE},
+};
+
+pm_dbs_pcl_second_connection_table_type
+		*second_connection_pcl_dbs_table;
+pm_dbs_pcl_third_connection_table_type
+		*third_connection_pcl_dbs_table;
+policy_mgr_next_action_two_connection_table_type
+		*next_action_two_connection_table;
+policy_mgr_next_action_three_connection_table_type
+		*next_action_three_connection_table;
+policy_mgr_next_action_two_connection_table_type
+		*next_action_two_connection_2x2_2g_1x1_5g_table;
+policy_mgr_next_action_three_connection_table_type
+		*next_action_three_connection_2x2_2g_1x1_5g_table;
+
+QDF_STATUS policy_mgr_get_pcl_for_existing_conn(struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_con_mode mode,
+		uint8_t *pcl_ch, uint32_t *len,
+		uint8_t *pcl_weight, uint32_t weight_len,
+		bool all_matching_cxn_to_del)
+{
+	struct policy_mgr_conc_connection_info
+			info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} };
+	uint8_t num_cxn_del = 0;
+
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	policy_mgr_debug("get pcl for existing conn:%d", mode);
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (policy_mgr_mode_specific_connection_count(psoc, mode, NULL) > 0) {
+		/* Check, store and temp delete the mode's parameter */
+		policy_mgr_store_and_del_conn_info(psoc, mode,
+				all_matching_cxn_to_del, info, &num_cxn_del);
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		/* Get the PCL */
+		status = policy_mgr_get_pcl(psoc, mode, pcl_ch, len,
+					pcl_weight, weight_len);
+		policy_mgr_debug("Get PCL to FW for mode:%d", mode);
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		/* Restore the connection info */
+		policy_mgr_restore_deleted_conn_info(psoc, info, num_cxn_del);
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return status;
+}
+
+void policy_mgr_decr_session_set_pcl(struct wlan_objmgr_psoc *psoc,
+						enum QDF_OPMODE mode,
+						uint8_t session_id)
+{
+	QDF_STATUS qdf_status;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	qdf_status = policy_mgr_decr_active_session(psoc, mode, session_id);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		policy_mgr_debug("Invalid active session");
+		return;
+	}
+
+	/*
+	 * After the removal of this connection, we need to check if
+	 * a STA connection still exists. The reason for this is that
+	 * if one or more STA exists, we need to provide the updated
+	 * PCL to the FW for cases like LFR.
+	 *
+	 * Since policy_mgr_get_pcl provides PCL list based on the new
+	 * connection that is going to come up, we will find the
+	 * existing STA entry, save it and delete it temporarily.
+	 * After this we will get PCL as though as new STA connection
+	 * is coming up. This will give the exact PCL that needs to be
+	 * given to the FW. After setting the PCL, we need to restore
+	 * the entry that we have saved before.
+	 */
+	policy_mgr_set_pcl_for_existing_combo(psoc, PM_STA_MODE);
+	/* do we need to change the HW mode */
+	policy_mgr_check_n_start_opportunistic_timer(psoc);
+	return;
+}
+
+void policy_mgr_reg_chan_change_callback(struct wlan_objmgr_psoc *psoc,
+		struct wlan_objmgr_pdev *pdev,
+		struct regulatory_channel *chan_list,
+		struct avoid_freq_ind_data *avoid_freq_ind,
+		void *arg)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	if (!avoid_freq_ind) {
+		policy_mgr_debug("avoid_freq_ind NULL");
+		return;
+	}
+
+	/*
+	 * The ch_list buffer can accomadate a maximum of
+	 * NUM_CHANNELS and hence the ch_cnt should also not
+	 * exceed NUM_CHANNELS.
+	 */
+	pm_ctx->unsafe_channel_count = avoid_freq_ind->chan_list.ch_cnt >=
+			NUM_CHANNELS ?
+			NUM_CHANNELS : avoid_freq_ind->chan_list.ch_cnt;
+	if (pm_ctx->unsafe_channel_count)
+		qdf_mem_copy(pm_ctx->unsafe_channel_list,
+			avoid_freq_ind->chan_list.ch_list,
+			pm_ctx->unsafe_channel_count *
+			sizeof(pm_ctx->unsafe_channel_list[0]));
+	policy_mgr_debug("Channel list update, received %d avoided channels",
+		pm_ctx->unsafe_channel_count);
+}
+
+void policy_mgr_update_with_safe_channel_list(struct wlan_objmgr_psoc *psoc,
+		uint8_t *pcl_channels, uint32_t *len,
+		uint8_t *weight_list, uint32_t weight_len)
+{
+	uint8_t current_channel_list[QDF_MAX_NUM_CHAN];
+	uint8_t org_weight_list[QDF_MAX_NUM_CHAN];
+	uint8_t is_unsafe = 1;
+	uint8_t i, j;
+	uint32_t safe_channel_count = 0, current_channel_count = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return;
+	}
+
+	if (len) {
+		current_channel_count = QDF_MIN(*len, QDF_MAX_NUM_CHAN);
+	} else {
+		policy_mgr_err("invalid number of channel length");
+		return;
+	}
+
+	if (pm_ctx->unsafe_channel_count == 0) {
+		policy_mgr_debug("There are no unsafe channels");
+		return;
+	}
+
+	qdf_mem_copy(current_channel_list, pcl_channels,
+		current_channel_count);
+	qdf_mem_zero(pcl_channels, current_channel_count);
+
+	qdf_mem_copy(org_weight_list, weight_list, QDF_MAX_NUM_CHAN);
+	qdf_mem_zero(weight_list, weight_len);
+
+	for (i = 0; i < current_channel_count; i++) {
+		is_unsafe = 0;
+		for (j = 0; j < pm_ctx->unsafe_channel_count; j++) {
+			if (current_channel_list[i] ==
+				pm_ctx->unsafe_channel_list[j]) {
+				/* Found unsafe channel, update it */
+				is_unsafe = 1;
+				policy_mgr_debug("CH %d is not safe",
+					current_channel_list[i]);
+				break;
+			}
+		}
+		if (!is_unsafe) {
+			pcl_channels[safe_channel_count] =
+				current_channel_list[i];
+			if (safe_channel_count < weight_len)
+				weight_list[safe_channel_count] =
+					org_weight_list[i];
+			safe_channel_count++;
+		}
+	}
+	*len = safe_channel_count;
+
+	return;
+}
+
+static QDF_STATUS policy_mgr_modify_pcl_based_on_enabled_channels(
+					struct policy_mgr_psoc_priv_obj *pm_ctx,
+					uint8_t *pcl_list_org,
+					uint8_t *weight_list_org,
+					uint32_t *pcl_len_org)
+{
+	uint32_t i, pcl_len = 0;
+
+	for (i = 0; i < *pcl_len_org; i++) {
+		if (!wlan_reg_is_passive_or_disable_ch(
+			pm_ctx->pdev, pcl_list_org[i])) {
+			pcl_list_org[pcl_len] = pcl_list_org[i];
+			weight_list_org[pcl_len++] = weight_list_org[i];
+		}
+	}
+	*pcl_len_org = pcl_len;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS policy_mgr_modify_pcl_based_on_dnbs(
+						struct wlan_objmgr_psoc *psoc,
+						uint8_t *pcl_list_org,
+						uint8_t *weight_list_org,
+						uint32_t *pcl_len_org)
+{
+	uint32_t i, pcl_len = 0;
+	uint8_t pcl_list[QDF_MAX_NUM_CHAN];
+	uint8_t weight_list[QDF_MAX_NUM_CHAN];
+	bool ok;
+	int ret;
+
+	for (i = 0; i < *pcl_len_org; i++) {
+		ret = policy_mgr_is_chan_ok_for_dnbs(psoc, pcl_list_org[i],
+						&ok);
+
+		if (QDF_IS_STATUS_ERROR(ret)) {
+			policy_mgr_err("Not able to check DNBS eligibility");
+			return ret;
+		}
+		if (ok) {
+			pcl_list[pcl_len] = pcl_list_org[i];
+			weight_list[pcl_len++] = weight_list_org[i];
+		}
+	}
+
+	qdf_mem_zero(pcl_list_org, QDF_ARRAY_SIZE(pcl_list_org));
+	qdf_mem_zero(weight_list_org, QDF_ARRAY_SIZE(weight_list_org));
+	qdf_mem_copy(pcl_list_org, pcl_list, pcl_len);
+	qdf_mem_copy(weight_list_org, weight_list, pcl_len);
+	*pcl_len_org = pcl_len;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+uint8_t policy_mgr_get_channel(struct wlan_objmgr_psoc *psoc,
+			enum policy_mgr_con_mode mode, uint32_t *vdev_id)
+{
+	uint32_t idx = 0;
+	uint8_t chan;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return 0;
+	}
+
+	if (mode >= PM_MAX_NUM_OF_MODE) {
+		policy_mgr_err("incorrect mode");
+		return 0;
+	}
+
+	for (idx = 0; idx < MAX_NUMBER_OF_CONC_CONNECTIONS; idx++) {
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		if ((pm_conc_connection_list[idx].mode == mode) &&
+				(!vdev_id || (*vdev_id ==
+					pm_conc_connection_list[idx].vdev_id))
+				&& pm_conc_connection_list[idx].in_use) {
+			chan =  pm_conc_connection_list[idx].chan;
+			qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+			return chan;
+		}
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+	}
+
+	return 0;
+}
+
+static QDF_STATUS policy_mgr_modify_sap_pcl_based_on_nol(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t *pcl_list_org,
+		uint8_t *weight_list_org,
+		uint32_t *pcl_len_org)
+{
+	uint32_t i, pcl_len = 0;
+	uint8_t pcl_list[QDF_MAX_NUM_CHAN];
+	uint8_t weight_list[QDF_MAX_NUM_CHAN];
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	for (i = 0; i < *pcl_len_org; i++) {
+		if (!wlan_reg_is_disable_ch(pm_ctx->pdev, pcl_list_org[i])) {
+			pcl_list[pcl_len] = pcl_list_org[i];
+			weight_list[pcl_len++] = weight_list_org[i];
+		}
+	}
+
+	qdf_mem_zero(pcl_list_org, QDF_ARRAY_SIZE(pcl_list_org));
+	qdf_mem_zero(weight_list_org, QDF_ARRAY_SIZE(weight_list_org));
+	qdf_mem_copy(pcl_list_org, pcl_list, pcl_len);
+	qdf_mem_copy(weight_list_org, weight_list, pcl_len);
+	*pcl_len_org = pcl_len;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+policy_mgr_modify_sap_pcl_based_on_srd(struct wlan_objmgr_psoc *psoc,
+				       uint8_t *pcl_list_org,
+				       uint8_t *weight_list_org,
+				       uint32_t *pcl_len_org)
+{
+	uint32_t i, pcl_len = 0;
+	uint8_t pcl_list[QDF_MAX_NUM_CHAN];
+	uint8_t weight_list[QDF_MAX_NUM_CHAN];
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	bool is_etsi13_srd_chan_allowed_in_mas_mode = true;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+	is_etsi13_srd_chan_allowed_in_mas_mode =
+		wlan_reg_is_etsi13_srd_chan_allowed_master_mode(pm_ctx->pdev);
+
+	if (is_etsi13_srd_chan_allowed_in_mas_mode)
+		return QDF_STATUS_SUCCESS;
+
+	for (i = 0; i < *pcl_len_org; i++) {
+		if (wlan_reg_is_etsi13_srd_chan(pm_ctx->pdev,
+						pcl_list_org[i]))
+			continue;
+		pcl_list[pcl_len] = pcl_list_org[i];
+		weight_list[pcl_len++] = weight_list_org[i];
+	}
+
+	qdf_mem_zero(pcl_list_org, QDF_ARRAY_SIZE(pcl_list_org));
+	qdf_mem_zero(weight_list_org, QDF_ARRAY_SIZE(weight_list_org));
+	qdf_mem_copy(pcl_list_org, pcl_list, pcl_len);
+	qdf_mem_copy(weight_list_org, weight_list, pcl_len);
+	*pcl_len_org = pcl_len;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS policy_mgr_pcl_modification_for_sap(
+			struct wlan_objmgr_psoc *psoc,
+			uint8_t *pcl_channels, uint8_t *pcl_weight,
+			uint32_t *len)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint32_t i;
+
+	if (policy_mgr_is_sap_mandatory_channel_set(psoc)) {
+		status = policy_mgr_modify_sap_pcl_based_on_mandatory_channel(
+				psoc, pcl_channels, pcl_weight, len);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			policy_mgr_err("failed to get modified pcl for SAP");
+			return status;
+		}
+		policy_mgr_debug("modified pcl len:%d", *len);
+		for (i = 0; i < *len; i++)
+			policy_mgr_debug("chan:%d weight:%d",
+				pcl_channels[i], pcl_weight[i]);
+	}
+
+	status = policy_mgr_modify_sap_pcl_based_on_nol(
+			psoc, pcl_channels, pcl_weight, len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("failed to get modified pcl for SAP");
+		return status;
+	}
+	policy_mgr_debug("modified pcl len:%d", *len);
+	for (i = 0; i < *len; i++)
+		policy_mgr_debug("chan:%d weight:%d",
+			pcl_channels[i], pcl_weight[i]);
+
+	status = policy_mgr_modify_sap_pcl_based_on_srd
+			(psoc, pcl_channels, pcl_weight, len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("failed to get modified pcl for SAP");
+		return status;
+	}
+	policy_mgr_debug("modified final pcl len:%d", *len);
+	for (i = 0; i < *len; i++)
+		policy_mgr_debug("chan:%d weight:%d",
+				 pcl_channels[i], pcl_weight[i]);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS policy_mgr_pcl_modification_for_p2p_go(
+			struct wlan_objmgr_psoc *psoc,
+			uint8_t *pcl_channels, uint8_t *pcl_weight,
+			uint32_t *len)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	uint32_t i;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("context is NULL");
+		return status;
+	}
+
+	status = policy_mgr_modify_pcl_based_on_enabled_channels(
+			pm_ctx, pcl_channels, pcl_weight, len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("failed to get modified pcl for GO");
+		return status;
+	}
+	policy_mgr_debug("modified pcl len:%d", *len);
+	for (i = 0; i < *len; i++)
+		policy_mgr_debug("chan:%d weight:%d",
+			pcl_channels[i], pcl_weight[i]);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS policy_mgr_mode_specific_modification_on_pcl(
+			struct wlan_objmgr_psoc *psoc,
+			uint8_t *pcl_channels, uint8_t *pcl_weight,
+			uint32_t *len, enum policy_mgr_con_mode mode)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	switch (mode) {
+	case PM_SAP_MODE:
+		status = policy_mgr_pcl_modification_for_sap(
+			psoc, pcl_channels, pcl_weight, len);
+		break;
+	case PM_P2P_GO_MODE:
+		status = policy_mgr_pcl_modification_for_p2p_go(
+			psoc, pcl_channels, pcl_weight, len);
+		break;
+	case PM_STA_MODE:
+	case PM_P2P_CLIENT_MODE:
+	case PM_IBSS_MODE:
+		status = QDF_STATUS_SUCCESS;
+		break;
+	default:
+		policy_mgr_err("unexpected mode %d", mode);
+		break;
+	}
+
+	return status;
+}
+
+QDF_STATUS policy_mgr_get_pcl(struct wlan_objmgr_psoc *psoc,
+			enum policy_mgr_con_mode mode,
+			uint8_t *pcl_channels, uint32_t *len,
+			uint8_t *pcl_weight, uint32_t weight_len)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint32_t num_connections = 0, i;
+	enum policy_mgr_conc_priority_mode first_index = 0;
+	enum policy_mgr_one_connection_mode second_index = 0;
+	enum policy_mgr_two_connection_mode third_index = 0;
+	enum policy_mgr_pcl_type pcl = PM_NONE;
+	enum policy_mgr_conc_priority_mode conc_system_pref = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	enum QDF_OPMODE qdf_mode;
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("context is NULL");
+		return status;
+	}
+
+	if ((mode < 0) || (mode >= PM_MAX_NUM_OF_MODE)) {
+		policy_mgr_err("Invalid connection mode %d received", mode);
+		return status;
+	}
+
+	/* find the current connection state from pm_conc_connection_list*/
+	num_connections = policy_mgr_get_connection_count(psoc);
+	policy_mgr_debug("connections:%d pref:%d requested mode:%d",
+		num_connections, pm_ctx->cur_conc_system_pref, mode);
+
+	switch (pm_ctx->cur_conc_system_pref) {
+	case 0:
+		conc_system_pref = PM_THROUGHPUT;
+		break;
+	case 1:
+		conc_system_pref = PM_POWERSAVE;
+		break;
+	case 2:
+		conc_system_pref = PM_LATENCY;
+		break;
+	default:
+		policy_mgr_err("unknown cur_conc_system_pref value %d",
+			pm_ctx->cur_conc_system_pref);
+		break;
+	}
+
+	switch (num_connections) {
+	case 0:
+		first_index =
+			policy_mgr_get_first_connection_pcl_table_index(psoc);
+		pcl = first_connection_pcl_table[mode][first_index];
+		break;
+	case 1:
+		second_index =
+			policy_mgr_get_second_connection_pcl_table_index(psoc);
+		if (PM_MAX_ONE_CONNECTION_MODE == second_index) {
+			policy_mgr_err("couldn't find index for 2nd connection pcl table");
+			return status;
+		}
+		qdf_mode = policy_mgr_get_qdf_mode_from_pm(mode);
+		if (qdf_mode == QDF_MAX_NO_OF_MODE)
+			return status;
+
+		if (policy_mgr_is_hw_dbs_capable(psoc) == true &&
+		    policy_mgr_is_dbs_allowed_for_concurrency(
+							psoc, qdf_mode)) {
+			pcl = (*second_connection_pcl_dbs_table)
+				[second_index][mode][conc_system_pref];
+		} else {
+			pcl = second_connection_pcl_nodbs_table
+				[second_index][mode][conc_system_pref];
+		}
+
+		break;
+	case 2:
+		third_index =
+			policy_mgr_get_third_connection_pcl_table_index(psoc);
+		if (PM_MAX_TWO_CONNECTION_MODE == third_index) {
+			policy_mgr_err(
+				"couldn't find index for 3rd connection pcl table");
+			return status;
+		}
+		if (policy_mgr_is_hw_dbs_capable(psoc) == true) {
+			pcl = (*third_connection_pcl_dbs_table)
+				[third_index][mode][conc_system_pref];
+		} else {
+			pcl = third_connection_pcl_nodbs_table
+				[third_index][mode][conc_system_pref];
+		}
+		break;
+	default:
+		policy_mgr_err("unexpected num_connections value %d",
+			num_connections);
+		break;
+	}
+
+	policy_mgr_debug("index1:%d index2:%d index3:%d pcl:%d dbs:%d",
+		first_index, second_index, third_index,
+		pcl, policy_mgr_is_hw_dbs_capable(psoc));
+
+	/* once the PCL enum is obtained find out the exact channel list with
+	 * help from sme_get_cfg_valid_channels
+	 */
+	status = policy_mgr_get_channel_list(psoc, pcl, pcl_channels, len, mode,
+					pcl_weight, weight_len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("failed to get channel list:%d", status);
+		return status;
+	}
+
+	policy_mgr_debug("pcl len:%d", *len);
+	for (i = 0; i < *len; i++) {
+		policy_mgr_debug("chan:%d weight:%d",
+				pcl_channels[i], pcl_weight[i]);
+	}
+
+	policy_mgr_mode_specific_modification_on_pcl(
+		psoc, pcl_channels, pcl_weight, len, mode);
+
+	status = policy_mgr_modify_pcl_based_on_dnbs(psoc, pcl_channels,
+						pcl_weight, len);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("failed to get modified pcl based on DNBS");
+		return status;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+enum policy_mgr_conc_priority_mode
+		policy_mgr_get_first_connection_pcl_table_index(
+		struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("context is NULL");
+		return PM_THROUGHPUT;
+	}
+
+	if (pm_ctx->cur_conc_system_pref >= PM_MAX_CONC_PRIORITY_MODE)
+		return PM_THROUGHPUT;
+
+	return pm_ctx->cur_conc_system_pref;
+}
+
+enum policy_mgr_one_connection_mode
+		policy_mgr_get_second_connection_pcl_table_index(
+		struct wlan_objmgr_psoc *psoc)
+{
+	enum policy_mgr_one_connection_mode index = PM_MAX_ONE_CONNECTION_MODE;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return index;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (PM_STA_MODE == pm_conc_connection_list[0].mode) {
+		if (WLAN_REG_IS_24GHZ_CH(pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_24_1x1;
+			else
+				index = PM_STA_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_5_1x1;
+			else
+				index = PM_STA_5_2x2;
+		}
+	} else if (PM_SAP_MODE == pm_conc_connection_list[0].mode) {
+		if (WLAN_REG_IS_24GHZ_CH(pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_SAP_24_1x1;
+			else
+				index = PM_SAP_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_SAP_5_1x1;
+			else
+				index = PM_SAP_5_2x2;
+		}
+	} else if (PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) {
+		if (WLAN_REG_IS_24GHZ_CH(pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_24_1x1;
+			else
+				index = PM_P2P_CLI_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_5_1x1;
+			else
+				index = PM_P2P_CLI_5_2x2;
+		}
+	} else if (PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) {
+		if (WLAN_REG_IS_24GHZ_CH(pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_24_1x1;
+			else
+				index = PM_P2P_GO_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_5_1x1;
+			else
+				index = PM_P2P_GO_5_2x2;
+		}
+	} else if (PM_IBSS_MODE == pm_conc_connection_list[0].mode) {
+		if (WLAN_REG_IS_24GHZ_CH(pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_IBSS_24_1x1;
+			else
+				index = PM_IBSS_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_IBSS_5_1x1;
+			else
+				index = PM_IBSS_5_2x2;
+		}
+	}
+
+	policy_mgr_debug("mode:%d chan:%d chain:%d index:%d",
+		pm_conc_connection_list[0].mode,
+		pm_conc_connection_list[0].chan,
+		pm_conc_connection_list[0].chain_mask, index);
+
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+		policy_mgr_get_third_connection_pcl_table_index_cli_sap(void)
+{
+	enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE;
+	/* SCC */
+	if (pm_conc_connection_list[0].chan ==
+		pm_conc_connection_list[1].chan) {
+		if (WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_SAP_SCC_24_1x1;
+			else
+				index = PM_P2P_CLI_SAP_SCC_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_SAP_SCC_5_1x1;
+			else
+				index = PM_P2P_CLI_SAP_SCC_5_2x2;
+		}
+	/* MCC */
+	} else if (pm_conc_connection_list[0].mac ==
+		pm_conc_connection_list[1].mac) {
+		if ((WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_SAP_MCC_24_1x1;
+			else
+				index = PM_P2P_CLI_SAP_MCC_24_2x2;
+		} else if ((WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_SAP_MCC_5_1x1;
+			else
+				index = PM_P2P_CLI_SAP_MCC_5_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_SAP_MCC_24_5_1x1;
+			else
+				index = PM_P2P_CLI_SAP_MCC_24_5_2x2;
+		}
+	/* SBS or DBS */
+	} else if (pm_conc_connection_list[0].mac !=
+			pm_conc_connection_list[1].mac) {
+		/* SBS */
+		if ((WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[0].chan)) &&
+		    (WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_SAP_SBS_5_1x1;
+		} else {
+		/* DBS */
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_CLI_SAP_DBS_1x1;
+			else
+				index = PM_P2P_CLI_SAP_DBS_2x2;
+		}
+	}
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+		policy_mgr_get_third_connection_pcl_table_index_sta_sap(void)
+{
+	enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE;
+	/* SCC */
+	if (pm_conc_connection_list[0].chan ==
+		pm_conc_connection_list[1].chan) {
+		if (WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_SAP_SCC_24_1x1;
+			else
+				index = PM_STA_SAP_SCC_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_SAP_SCC_5_1x1;
+			else
+				index = PM_STA_SAP_SCC_5_2x2;
+		}
+	/* MCC */
+	} else if (pm_conc_connection_list[0].mac ==
+		pm_conc_connection_list[1].mac) {
+		if ((WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_SAP_MCC_24_1x1;
+			else
+				index = PM_STA_SAP_MCC_24_2x2;
+		} else if ((WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_SAP_MCC_5_1x1;
+			else
+				index = PM_STA_SAP_MCC_5_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_SAP_MCC_24_5_1x1;
+			else
+				index = PM_STA_SAP_MCC_24_5_2x2;
+		}
+	/* SBS or DBS */
+	} else if (pm_conc_connection_list[0].mac !=
+			pm_conc_connection_list[1].mac) {
+		/* SBS */
+		if ((WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[0].chan)) &&
+		    (WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_SAP_SBS_5_1x1;
+		} else {
+		/* DBS */
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_SAP_DBS_1x1;
+			else
+				index = PM_STA_SAP_DBS_2x2;
+		}
+	}
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+		policy_mgr_get_third_connection_pcl_table_index_sap_sap(void)
+{
+	enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE;
+	/* SCC */
+	if (pm_conc_connection_list[0].chan ==
+		pm_conc_connection_list[1].chan) {
+		if (WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_SAP_SAP_SCC_24_1x1;
+			else
+				index = PM_SAP_SAP_SCC_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_SAP_SAP_SCC_5_1x1;
+			else
+				index = PM_SAP_SAP_SCC_5_2x2;
+		}
+	/* MCC */
+	} else if (pm_conc_connection_list[0].mac ==
+		pm_conc_connection_list[1].mac) {
+		if ((WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_SAP_SAP_MCC_24_1x1;
+			else
+				index = PM_SAP_SAP_MCC_24_2x2;
+		} else if ((WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_SAP_SAP_MCC_5_1x1;
+			else
+				index = PM_SAP_SAP_MCC_5_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_SAP_SAP_MCC_24_5_1x1;
+			else
+				index = PM_SAP_SAP_MCC_24_5_2x2;
+		}
+	/* SBS or DBS */
+	} else if (pm_conc_connection_list[0].mac !=
+			pm_conc_connection_list[1].mac) {
+		/* SBS */
+		if ((WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[0].chan)) &&
+		    (WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_SAP_SAP_SBS_5_1x1;
+		} else {
+		/* DBS */
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_SAP_SAP_DBS_1x1;
+			else
+				index = PM_SAP_SAP_DBS_2x2;
+		}
+	}
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+		policy_mgr_get_third_connection_pcl_table_index_sta_go(void)
+{
+	enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE;
+	/* SCC */
+	if (pm_conc_connection_list[0].chan ==
+		pm_conc_connection_list[1].chan) {
+		if (WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_GO_SCC_24_1x1;
+			else
+				index = PM_STA_P2P_GO_SCC_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_GO_SCC_5_1x1;
+			else
+				index = PM_STA_P2P_GO_SCC_5_2x2;
+		}
+	/* MCC */
+	} else if (pm_conc_connection_list[0].mac ==
+		pm_conc_connection_list[1].mac) {
+		if ((WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_GO_MCC_24_1x1;
+			else
+				index = PM_STA_P2P_GO_MCC_24_2x2;
+		} else if ((WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_GO_MCC_5_1x1;
+			else
+				index = PM_STA_P2P_GO_MCC_5_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_GO_MCC_24_5_1x1;
+			else
+				index = PM_STA_P2P_GO_MCC_24_5_2x2;
+		}
+	/* SBS or DBS */
+	} else if (pm_conc_connection_list[0].mac !=
+			pm_conc_connection_list[1].mac) {
+		/* SBS */
+		if ((WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[0].chan)) &&
+		    (WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_GO_SBS_5_1x1;
+		} else {
+		/* DBS */
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_GO_DBS_1x1;
+			else
+				index = PM_STA_P2P_GO_DBS_2x2;
+		}
+	}
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+		policy_mgr_get_third_connection_pcl_table_index_sta_cli(void)
+{
+	enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE;
+	/* SCC */
+	if (pm_conc_connection_list[0].chan ==
+		pm_conc_connection_list[1].chan) {
+		if (WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_CLI_SCC_24_1x1;
+			else
+				index = PM_STA_P2P_CLI_SCC_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_CLI_SCC_5_1x1;
+			else
+				index = PM_STA_P2P_CLI_SCC_5_2x2;
+		}
+	/* MCC */
+	} else if (pm_conc_connection_list[0].mac ==
+		pm_conc_connection_list[1].mac) {
+		if ((WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_CLI_MCC_24_1x1;
+			else
+				index = PM_STA_P2P_CLI_MCC_24_2x2;
+		} else if ((WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_CLI_MCC_5_1x1;
+			else
+				index = PM_STA_P2P_CLI_MCC_5_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_CLI_MCC_24_5_1x1;
+			else
+				index = PM_STA_P2P_CLI_MCC_24_5_2x2;
+		}
+	/* SBS or DBS */
+	} else if (pm_conc_connection_list[0].mac !=
+			pm_conc_connection_list[1].mac) {
+		/* SBS */
+		if ((WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[0].chan)) &&
+		    (WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_CLI_SBS_5_1x1;
+		} else {
+		/* DBS */
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_P2P_CLI_DBS_1x1;
+			else
+				index = PM_STA_P2P_CLI_DBS_2x2;
+		}
+	}
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+		policy_mgr_get_third_connection_pcl_table_index_go_cli(void)
+{
+	enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE;
+	/* SCC */
+	if (pm_conc_connection_list[0].chan ==
+		pm_conc_connection_list[1].chan) {
+		if (WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_P2P_CLI_SCC_24_1x1;
+			else
+				index = PM_P2P_GO_P2P_CLI_SCC_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_P2P_CLI_SCC_5_1x1;
+			else
+				index = PM_P2P_GO_P2P_CLI_SCC_5_2x2;
+		}
+	/* MCC */
+	} else if (pm_conc_connection_list[0].mac ==
+		pm_conc_connection_list[1].mac) {
+		if ((WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_P2P_CLI_MCC_24_1x1;
+			else
+				index = PM_P2P_GO_P2P_CLI_MCC_24_2x2;
+		} else if ((WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_P2P_CLI_MCC_5_1x1;
+			else
+				index = PM_P2P_GO_P2P_CLI_MCC_5_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_P2P_CLI_MCC_24_5_1x1;
+			else
+				index = PM_P2P_GO_P2P_CLI_MCC_24_5_2x2;
+		}
+	/* SBS or DBS */
+	} else if (pm_conc_connection_list[0].mac !=
+			pm_conc_connection_list[1].mac) {
+		/* SBS */
+		if ((WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[0].chan)) &&
+		    (WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_P2P_CLI_SBS_5_1x1;
+		} else {
+		/* DBS */
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_P2P_CLI_DBS_1x1;
+			else
+				index = PM_P2P_GO_P2P_CLI_DBS_2x2;
+		}
+	}
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+		policy_mgr_get_third_connection_pcl_table_index_go_sap(void)
+{
+	enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE;
+	/* SCC */
+	if (pm_conc_connection_list[0].chan ==
+		pm_conc_connection_list[1].chan) {
+		if (WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_SAP_SCC_24_1x1;
+			else
+				index = PM_P2P_GO_SAP_SCC_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_SAP_SCC_5_1x1;
+			else
+				index = PM_P2P_GO_SAP_SCC_5_2x2;
+		}
+	/* MCC */
+	} else if (pm_conc_connection_list[0].mac ==
+		pm_conc_connection_list[1].mac) {
+		if ((WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_SAP_MCC_24_1x1;
+			else
+				index = PM_P2P_GO_SAP_MCC_24_2x2;
+		} else if ((WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_SAP_MCC_5_1x1;
+			else
+				index = PM_P2P_GO_SAP_MCC_5_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_SAP_MCC_24_5_1x1;
+			else
+				index = PM_P2P_GO_SAP_MCC_24_5_2x2;
+		}
+	/* SBS or DBS */
+	} else if (pm_conc_connection_list[0].mac !=
+			pm_conc_connection_list[1].mac) {
+		/* SBS */
+		if ((WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[0].chan)) &&
+		    (WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_SAP_SBS_5_1x1;
+		} else {
+		/* DBS */
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_P2P_GO_SAP_DBS_1x1;
+			else
+				index = PM_P2P_GO_SAP_DBS_2x2;
+		}
+	}
+	return index;
+}
+
+static enum policy_mgr_two_connection_mode
+		policy_mgr_get_third_connection_pcl_table_index_sta_sta(void)
+{
+	enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE;
+	/* SCC */
+	if (pm_conc_connection_list[0].chan ==
+		pm_conc_connection_list[1].chan) {
+		if (WLAN_REG_IS_24GHZ_CH
+			(pm_conc_connection_list[0].chan)) {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_STA_SCC_24_1x1;
+			else
+				index = PM_STA_STA_SCC_24_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+			pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_STA_SCC_5_1x1;
+			else
+				index = PM_STA_STA_SCC_5_2x2;
+		}
+	/* MCC */
+	} else if (pm_conc_connection_list[0].mac ==
+		pm_conc_connection_list[1].mac) {
+		if ((WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_24GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_STA_MCC_24_1x1;
+			else
+				index = PM_STA_STA_MCC_24_2x2;
+		} else if ((WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[0].chan)) &&
+			(WLAN_REG_IS_5GHZ_CH(
+			pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_STA_MCC_5_1x1;
+			else
+				index = PM_STA_STA_MCC_5_2x2;
+		} else {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_STA_MCC_24_5_1x1;
+			else
+				index = PM_STA_STA_MCC_24_5_2x2;
+		}
+	/* SBS or DBS */
+	} else if (pm_conc_connection_list[0].mac !=
+			pm_conc_connection_list[1].mac) {
+		/* SBS */
+		if ((WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[0].chan)) &&
+		    (WLAN_REG_IS_5GHZ_CH(pm_conc_connection_list[1].chan))) {
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_STA_SBS_5_1x1;
+		} else {
+		/* DBS */
+			if (POLICY_MGR_ONE_ONE ==
+				pm_conc_connection_list[0].chain_mask)
+				index = PM_STA_STA_DBS_1x1;
+			else
+				index = PM_STA_STA_DBS_2x2;
+		}
+	}
+	return index;
+}
+
+enum policy_mgr_two_connection_mode
+		policy_mgr_get_third_connection_pcl_table_index(
+		struct wlan_objmgr_psoc *psoc)
+{
+	enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return index;
+	}
+
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (((PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_SAP_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_SAP_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode)))
+		index =
+		policy_mgr_get_third_connection_pcl_table_index_cli_sap();
+	else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_SAP_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_SAP_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_STA_MODE == pm_conc_connection_list[1].mode)))
+		index =
+		policy_mgr_get_third_connection_pcl_table_index_sta_sap();
+	else if ((PM_SAP_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_SAP_MODE == pm_conc_connection_list[1].mode))
+		index =
+		policy_mgr_get_third_connection_pcl_table_index_sap_sap();
+	else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_P2P_GO_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_STA_MODE == pm_conc_connection_list[1].mode)))
+		index =
+		policy_mgr_get_third_connection_pcl_table_index_sta_go();
+	else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_STA_MODE == pm_conc_connection_list[1].mode)))
+		index =
+		policy_mgr_get_third_connection_pcl_table_index_sta_cli();
+	else if (((PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_P2P_GO_MODE == pm_conc_connection_list[1].mode)))
+		index =
+		policy_mgr_get_third_connection_pcl_table_index_go_cli();
+	else if (((PM_SAP_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_P2P_GO_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_SAP_MODE == pm_conc_connection_list[1].mode)))
+		index =
+		policy_mgr_get_third_connection_pcl_table_index_go_sap();
+	else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_STA_MODE == pm_conc_connection_list[1].mode)) ||
+		((PM_STA_MODE == pm_conc_connection_list[0].mode) &&
+		(PM_STA_MODE == pm_conc_connection_list[1].mode)))
+		index =
+		policy_mgr_get_third_connection_pcl_table_index_sta_sta();
+
+	policy_mgr_debug("mode0:%d mode1:%d chan0:%d chan1:%d chain:%d index:%d",
+		pm_conc_connection_list[0].mode,
+		pm_conc_connection_list[1].mode,
+		pm_conc_connection_list[0].chan,
+		pm_conc_connection_list[1].chan,
+		pm_conc_connection_list[0].chain_mask, index);
+
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return index;
+}
+
+uint8_t
+policy_mgr_get_nondfs_preferred_channel(struct wlan_objmgr_psoc *psoc,
+		enum policy_mgr_con_mode mode,
+		bool for_existing_conn)
+{
+	uint8_t pcl_channels[QDF_MAX_NUM_CHAN];
+	uint8_t pcl_weight[QDF_MAX_NUM_CHAN];
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	/*
+	 * in worst case if we can't find any channel at all
+	 * then return 2.4G channel, so atleast we won't fall
+	 * under 5G MCC scenario
+	 */
+	uint8_t channel = PM_24_GHZ_CHANNEL_6;
+	uint32_t i, pcl_len = 0;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return channel;
+	}
+
+	if (true == for_existing_conn) {
+		/*
+		 * First try to see if there is any non-dfs channel already
+		 * present in current connection table. If yes then return
+		 * that channel
+		 */
+		if (true == policy_mgr_is_any_nondfs_chnl_present(
+			psoc, &channel))
+			return channel;
+
+		if (QDF_STATUS_SUCCESS != policy_mgr_get_pcl_for_existing_conn(
+					psoc, mode,
+					&pcl_channels[0], &pcl_len,
+					pcl_weight, QDF_ARRAY_SIZE(pcl_weight),
+					false))
+			return channel;
+	} else {
+		if (QDF_STATUS_SUCCESS != policy_mgr_get_pcl(psoc, mode,
+					&pcl_channels[0], &pcl_len,
+					pcl_weight, QDF_ARRAY_SIZE(pcl_weight)))
+			return channel;
+	}
+
+	for (i = 0; i < pcl_len; i++) {
+		if (wlan_reg_is_dfs_ch(pm_ctx->pdev, pcl_channels[i])) {
+			continue;
+		} else {
+			channel = pcl_channels[i];
+			break;
+		}
+	}
+
+	return channel;
+}
+
+static void policy_mgr_remove_dsrc_channels(uint8_t *chan_list,
+					    uint32_t *num_channels,
+					    struct wlan_objmgr_pdev *pdev)
+{
+	uint32_t num_chan_temp = 0;
+	int i;
+
+	for (i = 0; i < *num_channels; i++) {
+		if (!wlan_reg_is_dsrc_chan(pdev, chan_list[i])) {
+			chan_list[num_chan_temp] = chan_list[i];
+			num_chan_temp++;
+		}
+	}
+
+	*num_channels = num_chan_temp;
+}
+
+QDF_STATUS policy_mgr_get_valid_chans(struct wlan_objmgr_psoc *psoc,
+				uint8_t *chan_list, uint32_t *list_len)
+{
+	QDF_STATUS status;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	*list_len = 0;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!pm_ctx->sme_cbacks.sme_get_valid_channels) {
+		policy_mgr_err("sme_get_valid_chans callback is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	*list_len = QDF_MAX_NUM_CHAN;
+	status = pm_ctx->sme_cbacks.sme_get_valid_channels(
+					chan_list, list_len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("Error in getting valid channels");
+		*list_len = 0;
+		return status;
+	}
+
+	policy_mgr_remove_dsrc_channels(chan_list, list_len, pm_ctx->pdev);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool policy_mgr_list_has_24GHz_channel(uint8_t *channel_list,
+					uint32_t list_len)
+{
+	uint32_t i;
+
+	for (i = 0; i < list_len; i++) {
+		if (WLAN_REG_IS_24GHZ_CH(channel_list[i]))
+			return true;
+	}
+
+	return false;
+}
+
+QDF_STATUS policy_mgr_set_sap_mandatory_channels(struct wlan_objmgr_psoc *psoc,
+					uint8_t *channels, uint32_t len)
+{
+	uint32_t i;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!len) {
+		policy_mgr_err("No mandatory freq/chan configured");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!policy_mgr_list_has_24GHz_channel(channels, len)) {
+		policy_mgr_err("2.4GHz channels missing, this is not expected");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	policy_mgr_debug("mandatory chan length:%d",
+			pm_ctx->sap_mandatory_channels_len);
+
+	for (i = 0; i < len; i++) {
+		pm_ctx->sap_mandatory_channels[i] = channels[i];
+		policy_mgr_debug("chan:%d", pm_ctx->sap_mandatory_channels[i]);
+	}
+
+	pm_ctx->sap_mandatory_channels_len = len;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool policy_mgr_is_sap_mandatory_channel_set(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return false;
+	}
+
+	if (pm_ctx->sap_mandatory_channels_len)
+		return true;
+	else
+		return false;
+}
+
+QDF_STATUS policy_mgr_modify_sap_pcl_based_on_mandatory_channel(
+		struct wlan_objmgr_psoc *psoc,
+		uint8_t *pcl_list_org,
+		uint8_t *weight_list_org,
+		uint32_t *pcl_len_org)
+{
+	uint32_t i, j, pcl_len = 0;
+	bool found;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!pm_ctx->sap_mandatory_channels_len)
+		return QDF_STATUS_SUCCESS;
+
+	if (!policy_mgr_list_has_24GHz_channel(pm_ctx->sap_mandatory_channels,
+			pm_ctx->sap_mandatory_channels_len)) {
+		policy_mgr_err("fav channel list is missing 2.4GHz channels");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	for (i = 0; i < pm_ctx->sap_mandatory_channels_len; i++)
+		policy_mgr_debug("fav chan:%d",
+			pm_ctx->sap_mandatory_channels[i]);
+
+	for (i = 0; i < *pcl_len_org; i++) {
+		found = false;
+		if (i >= QDF_MAX_NUM_CHAN) {
+			policy_mgr_debug("index is exceeding QDF_MAX_NUM_CHAN");
+			break;
+		}
+		for (j = 0; j < pm_ctx->sap_mandatory_channels_len; j++) {
+			if (pcl_list_org[i] ==
+			    pm_ctx->sap_mandatory_channels[j]) {
+				found = true;
+				break;
+			}
+		}
+		if (found && (pcl_len < QDF_MAX_NUM_CHAN)) {
+			pcl_list_org[pcl_len] = pcl_list_org[i];
+			weight_list_org[pcl_len++] = weight_list_org[i];
+		}
+	}
+	*pcl_len_org = pcl_len;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_sap_mandatory_channel(struct wlan_objmgr_psoc *psoc,
+		uint32_t *chan)
+{
+	QDF_STATUS status;
+	struct policy_mgr_pcl_list pcl;
+
+	qdf_mem_zero(&pcl, sizeof(pcl));
+
+	status = policy_mgr_get_pcl_for_existing_conn(psoc, PM_SAP_MODE,
+			pcl.pcl_list, &pcl.pcl_len,
+			pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list),
+			false);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("Unable to get PCL for SAP");
+		return status;
+	}
+
+	/*
+	 * Get inside below loop if no existing SAP connection and hence a new
+	 * SAP connection might be coming up. pcl.pcl_len can be 0 if no common
+	 * channel between PCL & mandatory channel list as well
+	 */
+	if (!pcl.pcl_len && !policy_mgr_mode_specific_connection_count(psoc,
+		PM_SAP_MODE, NULL)) {
+		policy_mgr_debug("policy_mgr_get_pcl_for_existing_conn returned no pcl");
+		status = policy_mgr_get_pcl(psoc, PM_SAP_MODE,
+				pcl.pcl_list, &pcl.pcl_len,
+				pcl.weight_list,
+				QDF_ARRAY_SIZE(pcl.weight_list));
+		if (QDF_IS_STATUS_ERROR(status)) {
+			policy_mgr_err("Unable to get PCL for SAP: policy_mgr_get_pcl");
+			return status;
+		}
+	}
+
+	status = policy_mgr_modify_sap_pcl_based_on_mandatory_channel(
+							psoc, pcl.pcl_list,
+							pcl.weight_list,
+							&pcl.pcl_len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		policy_mgr_err("Unable to modify SAP PCL");
+		return status;
+	}
+
+	if (!pcl.pcl_len) {
+		policy_mgr_err("No common channel between mandatory list & PCL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	*chan = pcl.pcl_list[0];
+	policy_mgr_debug("mandatory channel:%d", *chan);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS policy_mgr_get_valid_chan_weights(struct wlan_objmgr_psoc *psoc,
+		struct policy_mgr_pcl_chan_weights *weight)
+{
+	uint32_t i, j;
+	struct policy_mgr_conc_connection_info
+			info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} };
+	uint8_t num_cxn_del = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_mem_set(weight->weighed_valid_list, QDF_MAX_NUM_CHAN,
+		    WEIGHT_OF_DISALLOWED_CHANNELS);
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	if (policy_mgr_mode_specific_connection_count(
+		psoc, PM_STA_MODE, NULL) > 0) {
+		/*
+		 * Store the STA mode's parameter and temporarily delete it
+		 * from the concurrency table. This way the allow concurrency
+		 * check can be used as though a new connection is coming up,
+		 * allowing to detect the disallowed channels.
+		 */
+		policy_mgr_store_and_del_conn_info(psoc, PM_STA_MODE, false,
+						info, &num_cxn_del);
+		qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+		/*
+		 * There is a small window between releasing the above lock
+		 * and acquiring the same in policy_mgr_allow_concurrency,
+		 * below!
+		 */
+		for (i = 0; i < weight->saved_num_chan; i++) {
+			if (policy_mgr_is_concurrency_allowed
+				(psoc, PM_STA_MODE, weight->saved_chan_list[i],
+				HW_MODE_20_MHZ)) {
+				weight->weighed_valid_list[i] =
+					WEIGHT_OF_NON_PCL_CHANNELS;
+			}
+		}
+		qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+		/* Restore the connection info */
+		policy_mgr_restore_deleted_conn_info(psoc, info, num_cxn_del);
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	for (i = 0; i < weight->saved_num_chan; i++) {
+		for (j = 0; j < weight->pcl_len; j++) {
+			if (weight->saved_chan_list[i] == weight->pcl_list[j]) {
+				weight->weighed_valid_list[i] =
+					weight->weight_list[j];
+				break;
+			}
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+uint8_t policy_mgr_mode_specific_get_channel(
+	struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode)
+{
+	uint32_t conn_index;
+	uint8_t channel = 0;
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("Invalid Context");
+		return channel;
+	}
+	/* provides the channel for the first matching mode type */
+	qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock);
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		conn_index++) {
+		if ((pm_conc_connection_list[conn_index].mode == mode) &&
+			pm_conc_connection_list[conn_index].in_use) {
+			channel = pm_conc_connection_list[conn_index].chan;
+			break;
+		}
+	}
+	qdf_mutex_release(&pm_ctx->qdf_conc_list_lock);
+
+	return channel;
+}
+
+uint8_t policy_mgr_get_alternate_channel_for_sap(
+	struct wlan_objmgr_psoc *psoc)
+{
+	uint8_t pcl_channels[QDF_MAX_NUM_CHAN];
+	uint8_t pcl_weight[QDF_MAX_NUM_CHAN];
+	uint8_t channel = 0;
+	uint32_t pcl_len = 0;
+
+	if (QDF_STATUS_SUCCESS == policy_mgr_get_pcl(psoc, PM_SAP_MODE,
+		&pcl_channels[0], &pcl_len,
+		pcl_weight, QDF_ARRAY_SIZE(pcl_weight))) {
+		channel = pcl_channels[0];
+	}
+
+	return channel;
+}

+ 1173 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_1x1_dbs_i.h

@@ -0,0 +1,1173 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WLAN_POLICY_MGR_TABLES_1X1_DBS_H
+#define __WLAN_POLICY_MGR_TABLES_1X1_DBS_H
+
+#include "wlan_policy_mgr_api.h"
+
+/**
+ * second_connection_pcl_dbs_1x1_table - table which provides PCL
+ * for the 2nd connection, when we have a connection already in
+ * the system (with DBS supported by HW)
+ */
+pm_dbs_pcl_second_connection_table_type
+pm_second_connection_pcl_dbs_1x1_table = {
+	[PM_STA_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {PM_5G,        PM_5G,        PM_5G       } },
+
+	[PM_STA_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {PM_5G,        PM_5G,        PM_5G       } },
+
+	[PM_STA_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_IBSS_MODE] = {PM_24G,        PM_24G,        PM_24G       } },
+
+	[PM_STA_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_IBSS_MODE] = {PM_24G,        PM_24G,        PM_24G       } },
+
+	[PM_P2P_CLI_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH, PM_24G_SCC_CH, PM_24G_SCC_CH},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH, PM_24G_SCC_CH, PM_24G_SCC_CH},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] =	{
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+};
+
+/**
+ * third_connection_pcl_dbs_table - table which provides PCL for
+ * the 3rd connection, when we have two connections already in
+ * the system (with DBS supported by HW)
+ */
+static pm_dbs_pcl_third_connection_table_type
+pm_third_connection_pcl_dbs_1x1_table = {
+	[PM_STA_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G},
+	[PM_SAP_MODE] = {PM_24G,        PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G},
+	[PM_SAP_MODE] = {PM_24G,        PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_24G,        PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_24G,        PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_SCC_ON_5_SCC_ON_24_5G, PM_NONE, PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_SCC_ON_5_SCC_ON_24_5G, PM_NONE, PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_SCC_ON_5_SCC_ON_24_5G, PM_NONE, PM_SCC_ON_5_SCC_ON_24},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+};
+
+/**
+ * next_action_two_connection_table - table which provides next
+ * action while a new connection is coming up, with one
+ * connection already in the system
+ */
+static policy_mgr_next_action_two_connection_table_type
+	pm_next_action_two_connection_dbs_1x1_table = {
+	[PM_STA_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_STA_24_2x2] = {PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_STA_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_STA_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_P2P_CLI_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_P2P_CLI_24_2x2] = {PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_P2P_CLI_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_P2P_CLI_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_P2P_GO_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_P2P_GO_24_2x2] = {PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_P2P_GO_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_P2P_GO_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_SAP_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_SAP_24_2x2] = {PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_SAP_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_SAP_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_IBSS_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_IBSS_24_2x2] = {PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_IBSS_5_1x1] = {PM_DBS,            PM_NOP},
+	[PM_IBSS_5_2x2] = {PM_DBS_DOWNGRADE,  PM_NOP},
+};
+
+/**
+ * next_action_three_connection_table - table which provides next
+ * action while a new connection is coming up, with two
+ * connections already in the system
+ */
+static policy_mgr_next_action_three_connection_table_type
+	pm_next_action_three_connection_dbs_1x1_table = {
+	[PM_STA_SAP_SCC_24_1x1] = {PM_NOP,		PM_DBS},
+	[PM_STA_SAP_SCC_24_2x2] = {PM_NOP,            PM_DBS_DOWNGRADE},
+	[PM_STA_SAP_MCC_24_1x1] = {PM_NOP,            PM_DBS},
+	[PM_STA_SAP_MCC_24_2x2] = {PM_NOP,            PM_DBS_DOWNGRADE},
+	[PM_STA_SAP_SCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_STA_SAP_SCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_STA_SAP_MCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_STA_SAP_MCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_STA_SAP_MCC_24_5_1x1] = {PM_DBS,          PM_DBS},
+	[PM_STA_SAP_MCC_24_5_2x2] = {PM_DBS_DOWNGRADE, PM_DBS_DOWNGRADE},
+	[PM_STA_SAP_DBS_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_P2P_GO_SCC_24_1x1] = {PM_NOP,         PM_DBS},
+	[PM_STA_P2P_GO_SCC_24_2x2] = {PM_NOP,         PM_DBS_DOWNGRADE},
+	[PM_STA_P2P_GO_MCC_24_1x1] = {PM_NOP,         PM_DBS},
+	[PM_STA_P2P_GO_MCC_24_2x2] = {PM_NOP,         PM_DBS_DOWNGRADE},
+	[PM_STA_P2P_GO_SCC_5_1x1] = {PM_DBS,          PM_NOP},
+	[PM_STA_P2P_GO_SCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP},
+	[PM_STA_P2P_GO_MCC_5_1x1] = {PM_DBS,          PM_NOP},
+	[PM_STA_P2P_GO_MCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP},
+	[PM_STA_P2P_GO_MCC_24_5_1x1] = {PM_DBS,       PM_DBS},
+	[PM_STA_P2P_GO_MCC_24_5_2x2] = {
+			PM_DBS_DOWNGRADE,   PM_DBS_DOWNGRADE},
+	[PM_STA_P2P_GO_DBS_1x1] = {PM_NOP,             PM_NOP},
+	[PM_STA_P2P_CLI_SCC_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_STA_P2P_CLI_SCC_24_2x2] = {
+			PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_STA_P2P_CLI_MCC_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_STA_P2P_CLI_MCC_24_2x2] = {
+			PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_STA_P2P_CLI_SCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_STA_P2P_CLI_SCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_STA_P2P_CLI_MCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_STA_P2P_CLI_MCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_STA_P2P_CLI_MCC_24_5_1x1] = {PM_DBS,             PM_DBS},
+	[PM_STA_P2P_CLI_MCC_24_5_2x2] = {
+			PM_DBS_DOWNGRADE,   PM_DBS_DOWNGRADE},
+	[PM_STA_P2P_CLI_DBS_1x1] = {PM_NOP,             PM_NOP},
+	[PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {
+			PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {
+			PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {PM_DBS,             PM_DBS},
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {
+			PM_DBS_DOWNGRADE,   PM_DBS_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_DBS_1x1] = {PM_NOP,             PM_NOP},
+	[PM_P2P_GO_SAP_SCC_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_P2P_GO_SAP_SCC_24_2x2] = {PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_P2P_GO_SAP_MCC_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_P2P_GO_SAP_MCC_24_2x2] = {PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_P2P_GO_SAP_SCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_P2P_GO_SAP_SCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_P2P_GO_SAP_MCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_P2P_GO_SAP_MCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_P2P_GO_SAP_MCC_24_5_1x1] = {PM_DBS,             PM_DBS},
+	[PM_P2P_GO_SAP_MCC_24_5_2x2] = {
+			PM_DBS_DOWNGRADE,   PM_DBS_DOWNGRADE},
+	[PM_P2P_GO_SAP_DBS_1x1] = {PM_NOP,             PM_NOP},
+	[PM_P2P_CLI_SAP_SCC_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_P2P_CLI_SAP_SCC_24_2x2] = {PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_P2P_CLI_SAP_MCC_24_1x1] = {PM_NOP,             PM_DBS},
+	[PM_P2P_CLI_SAP_MCC_24_2x2] = {PM_NOP,             PM_DBS_DOWNGRADE},
+	[PM_P2P_CLI_SAP_SCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_P2P_CLI_SAP_SCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_P2P_CLI_SAP_MCC_5_1x1] = {PM_DBS,             PM_NOP},
+	[PM_P2P_CLI_SAP_MCC_5_2x2] = {PM_DBS_DOWNGRADE,   PM_NOP},
+	[PM_P2P_CLI_SAP_MCC_24_5_1x1] = {PM_DBS,             PM_DBS},
+	[PM_P2P_CLI_SAP_MCC_24_5_2x2] = {PM_DBS_DOWNGRADE, PM_DBS_DOWNGRADE},
+	[PM_P2P_CLI_SAP_DBS_1x1] = {PM_NOP,             PM_NOP},
+
+	[PM_SAP_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS},
+	[PM_SAP_SAP_SCC_5_1x1] = {PM_DBS, PM_NOP},
+
+};
+
+#endif

+ 154 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_2g_1x1_5g.h

@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WLAN_POLICY_MGR_TABLES_2X2_2G_1X1_5G_DBS_H
+#define __WLAN_POLICY_MGR_TABLES_2X2_2G_1X1_5G_DBS_H
+
+#include "wlan_policy_mgr_api.h"
+
+/**
+ * next_action_two_connection_table - table which provides next
+ * action while a new connection is coming up, with one
+ * connection already in the system
+ */
+static policy_mgr_next_action_two_connection_table_type
+	pm_next_action_two_connection_dbs_2x2_2g_1x1_5g_table = {
+	[PM_STA_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_STA_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_STA_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_STA_5_2x2] = {PM_DBS2, PM_NOP},
+	[PM_P2P_CLI_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_P2P_CLI_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_P2P_CLI_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_P2P_CLI_5_2x2] = {PM_DBS2, PM_NOP},
+	[PM_P2P_GO_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_P2P_GO_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_SAP_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_SAP_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_SAP_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_SAP_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_IBSS_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_IBSS_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_IBSS_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_IBSS_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+};
+
+/**
+ * next_action_three_connection_table - table which provides next
+ * action while a new connection is coming up, with two
+ * connections already in the system
+ */
+static policy_mgr_next_action_three_connection_table_type
+	pm_next_action_three_connection_dbs_2x2_2g_1x1_5g_table = {
+	[PM_STA_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_STA_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_STA_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_STA_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_STA_SAP_SCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_STA_SAP_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_STA_SAP_MCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_STA_SAP_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_STA_SAP_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_STA_SAP_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_STA_SAP_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_STA_SAP_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+
+	[PM_STA_P2P_GO_SCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_GO_SCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_GO_MCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_GO_MCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_GO_SCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_STA_P2P_GO_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_STA_P2P_GO_MCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_STA_P2P_GO_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_STA_P2P_GO_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_STA_P2P_GO_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_STA_P2P_GO_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_STA_P2P_GO_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+
+	[PM_STA_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_CLI_SCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_STA_P2P_CLI_SCC_5_2x2] = {PM_DBS2, PM_NOP},
+	[PM_STA_P2P_CLI_MCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_STA_P2P_CLI_MCC_5_2x2] = {PM_DBS2, PM_NOP},
+	[PM_STA_P2P_CLI_MCC_24_5_1x1] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_CLI_MCC_24_5_2x2] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_CLI_DBS_1x1] = {PM_NOP, PM_DBS2},
+	[PM_STA_P2P_CLI_DBS_2x2] = {PM_NOP, PM_DBS2},
+
+	[PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE,
+					    PM_DBS2_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE,
+					    PM_DBS2_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+
+	[PM_P2P_GO_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_P2P_GO_SAP_SCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_P2P_GO_SAP_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_P2P_GO_SAP_MCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_P2P_GO_SAP_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_P2P_GO_SAP_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_P2P_GO_SAP_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_P2P_GO_SAP_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_P2P_GO_SAP_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+
+	[PM_P2P_CLI_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_P2P_CLI_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_P2P_CLI_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_P2P_CLI_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_P2P_CLI_SAP_SCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_P2P_CLI_SAP_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_P2P_CLI_SAP_MCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_P2P_CLI_SAP_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_P2P_CLI_SAP_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_P2P_CLI_SAP_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_P2P_CLI_SAP_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_P2P_CLI_SAP_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+
+	[PM_SAP_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_SAP_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_SAP_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS2},
+	[PM_SAP_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS2},
+	[PM_SAP_SAP_SCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_SAP_SAP_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_SAP_SAP_MCC_5_1x1] = {PM_DBS2, PM_NOP},
+	[PM_SAP_SAP_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP},
+	[PM_SAP_SAP_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_SAP_SAP_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_SAP_SAP_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+	[PM_SAP_SAP_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE},
+};
+
+#endif

+ 154 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_5g_1x1_2g.h

@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WLAN_POLICY_MGR_TABLES_2X2_5G_1X1_2G_DBS_H
+#define __WLAN_POLICY_MGR_TABLES_2X2_5G_1X1_2G_DBS_H
+
+#include "wlan_policy_mgr_api.h"
+
+/**
+ * next_action_two_connection_table - table which provides next
+ * action while a new connection is coming up, with one
+ * connection already in the system
+ */
+static policy_mgr_next_action_two_connection_table_type
+	pm_next_action_two_connection_dbs_2x2_5g_1x1_2g_table = {
+	[PM_STA_24_1x1] = {PM_NOP,		PM_DBS1},
+	[PM_STA_24_2x2] = {PM_NOP,		PM_DBS1},
+	[PM_STA_5_1x1] = {PM_DBS1,		PM_NOP},
+	[PM_STA_5_2x2] = {PM_DBS1,		PM_NOP},
+	[PM_P2P_CLI_24_1x1] = {PM_NOP,	        PM_DBS1},
+	[PM_P2P_CLI_24_2x2] = {PM_NOP,	        PM_DBS1},
+	[PM_P2P_CLI_5_1x1] = {PM_DBS1,		PM_NOP},
+	[PM_P2P_CLI_5_2x2] = {PM_DBS1,		PM_NOP},
+	[PM_P2P_GO_24_1x1] = {PM_NOP,		PM_DBS1},
+	[PM_P2P_GO_24_2x2] = {PM_NOP,		PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_5_1x1] = {PM_DBS1,		PM_NOP},
+	[PM_P2P_GO_5_2x2] = {PM_DBS1,		PM_NOP},
+	[PM_SAP_24_1x1] = {PM_NOP,		PM_DBS1},
+	[PM_SAP_24_2x2] = {PM_NOP,		PM_DBS1_DOWNGRADE},
+	[PM_SAP_5_1x1] = {PM_DBS1,		PM_NOP},
+	[PM_SAP_5_2x2] = {PM_DBS1,		PM_NOP},
+	[PM_IBSS_24_1x1] = {PM_NOP,		PM_DBS1},
+	[PM_IBSS_24_2x2] = {PM_NOP,		PM_DBS1_DOWNGRADE},
+	[PM_IBSS_5_1x1] = {PM_DBS1,		PM_NOP},
+	[PM_IBSS_5_2x2] = {PM_DBS1,		PM_NOP},
+};
+
+/**
+ * next_action_three_connection_table - table which provides next
+ * action while a new connection is coming up, with two
+ * connections already in the system
+ */
+static policy_mgr_next_action_three_connection_table_type
+	pm_next_action_three_connection_dbs_2x2_5g_1x1_2g_table = {
+	[PM_STA_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_STA_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_STA_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_STA_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_STA_SAP_SCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_STA_SAP_SCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_STA_SAP_MCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_STA_SAP_MCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_STA_SAP_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_STA_SAP_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_STA_SAP_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_STA_SAP_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+
+	[PM_STA_P2P_GO_SCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_STA_P2P_GO_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_STA_P2P_GO_MCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_STA_P2P_GO_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_STA_P2P_GO_SCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_STA_P2P_GO_SCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_STA_P2P_GO_MCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_STA_P2P_GO_MCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_STA_P2P_GO_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_STA_P2P_GO_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_STA_P2P_GO_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_STA_P2P_GO_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+
+	[PM_STA_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_STA_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_DBS1},
+	[PM_STA_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_STA_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_DBS1},
+	[PM_STA_P2P_CLI_SCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_STA_P2P_CLI_SCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_STA_P2P_CLI_MCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_STA_P2P_CLI_MCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_STA_P2P_CLI_MCC_24_5_1x1] = {PM_DBS1, PM_DBS1},
+	[PM_STA_P2P_CLI_MCC_24_5_2x2] = {PM_DBS1, PM_DBS1},
+	[PM_STA_P2P_CLI_DBS_1x1] = {PM_DBS1, PM_DBS1},
+	[PM_STA_P2P_CLI_DBS_2x2] = {PM_DBS1, PM_DBS1},
+
+	[PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE,
+					    PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE,
+					    PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+
+	[PM_P2P_GO_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_P2P_GO_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_P2P_GO_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_SAP_SCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_P2P_GO_SAP_SCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_P2P_GO_SAP_MCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_P2P_GO_SAP_MCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_P2P_GO_SAP_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_SAP_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_SAP_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_P2P_GO_SAP_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+
+	[PM_P2P_CLI_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_P2P_CLI_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_P2P_CLI_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_P2P_CLI_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_P2P_CLI_SAP_SCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_P2P_CLI_SAP_SCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_P2P_CLI_SAP_MCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_P2P_CLI_SAP_MCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_P2P_CLI_SAP_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_P2P_CLI_SAP_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_P2P_CLI_SAP_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_P2P_CLI_SAP_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+
+	[PM_SAP_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_SAP_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_SAP_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS1},
+	[PM_SAP_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE},
+	[PM_SAP_SAP_SCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_SAP_SAP_SCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_SAP_SAP_MCC_5_1x1] = {PM_DBS1, PM_NOP},
+	[PM_SAP_SAP_MCC_5_2x2] = {PM_DBS1, PM_NOP},
+	[PM_SAP_SAP_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_SAP_SAP_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_SAP_SAP_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+	[PM_SAP_SAP_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE},
+};
+
+#endif

+ 1394 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_i.h

@@ -0,0 +1,1394 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WLAN_POLICY_MGR_TABLES_2X2_DBS_H
+#define __WLAN_POLICY_MGR_TABLES_2X2_DBS_H
+
+#include "wlan_policy_mgr_api.h"
+
+/**
+ * second_connection_pcl_dbs_2x2_table - table which provides PCL
+ * for the 2nd connection, when we have a connection already in
+ * the system (with DBS supported by HW)
+ * This table consolidates selection for P2PCLI, P2PGO, STA, SAP
+ * into the single set of STA entries for 2.4G and 5G.
+ */
+static pm_dbs_pcl_second_connection_table_type
+pm_second_connection_pcl_dbs_2x2_table = {
+	[PM_STA_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {PM_5G, PM_5G, PM_5G} },
+
+	[PM_STA_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {PM_5G, PM_5G, PM_5G} },
+
+	[PM_STA_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] =	{ PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_IBSS_MODE] = {PM_24G, PM_24G, PM_24G} },
+
+	[PM_STA_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] =	{ PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_IBSS_MODE] = {PM_24G, PM_24G, PM_24G} },
+
+	[PM_P2P_CLI_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] =	{ PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] =	{ PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] =	{ PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] =	{ PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] =	{ PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] =	{ PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_IBSS_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE} },
+
+
+	[PM_IBSS_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] =	{
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] =	{
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] =	{
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] =	{
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+};
+
+/**
+ * third_connection_pcl_dbs_table - table which provides PCL for
+ * the 3rd connection, when we have two connections already in
+ * the system (with DBS supported by HW)
+ */
+static pm_dbs_pcl_third_connection_table_type
+pm_third_connection_pcl_dbs_2x2_table = {
+	[PM_STA_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_DBS_2x2] = {
+	[PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SBS_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH},
+	[PM_SAP_MODE] = {
+		PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_DBS_2x2] = {
+	[PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_SAP_SBS_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH},
+	[PM_SAP_MODE] = {
+		PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_24_1x1] = {
+		[PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE,
+		PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_DBS_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SBS_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = { PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = {
+		PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_DBS_2x2] = {
+	[PM_STA_MODE] = {
+		PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = {
+		PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SBS_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, },
+
+	[PM_STA_P2P_CLI_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_DBS_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SBS_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_DBS_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_DBS_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SBS_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {
+		PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_SAP_MODE] = {
+		PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_SCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_SCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH,
+		PM_24G_SCC_CH_SBS_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, },
+
+	[PM_STA_STA_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_DBS_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_DBS_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24,
+		PM_SCC_ON_5_SCC_ON_24},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_STA_SBS_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH},
+	[PM_SAP_MODE] = {
+		PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+};
+
+/**
+ * next_action_two_connection_table - table which provides next
+ * action while a new connection is coming up, with one
+ * connection already in the system
+ */
+static policy_mgr_next_action_two_connection_table_type
+	pm_next_action_two_connection_dbs_2x2_table = {
+	[PM_STA_24_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_24_2x2] = {PM_NOP,		PM_NOP},
+	[PM_STA_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_STA_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_P2P_CLI_24_1x1] = {PM_NOP,	PM_NOP},
+	[PM_P2P_CLI_24_2x2] = {PM_NOP,	PM_NOP},
+	[PM_P2P_CLI_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_P2P_CLI_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_P2P_GO_24_1x1] = {PM_NOP,		PM_NOP},
+	[PM_P2P_GO_24_2x2] = {PM_NOP,		PM_NOP},
+	[PM_P2P_GO_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_P2P_GO_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_SAP_24_1x1] = {PM_NOP,		PM_NOP},
+	[PM_SAP_24_2x2] = {PM_NOP,		PM_NOP},
+	[PM_SAP_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_SAP_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_IBSS_24_1x1] = {PM_NOP,		PM_NOP},
+	[PM_IBSS_24_2x2] = {PM_NOP,		PM_NOP},
+	[PM_IBSS_5_1x1] = {PM_DBS,		PM_NOP},
+	[PM_IBSS_5_2x2] = {PM_DBS,		PM_NOP},
+};
+
+/**
+ * next_action_three_connection_table - table which provides next
+ * action while a new connection is coming up, with two
+ * connections already in the system
+ */
+static policy_mgr_next_action_three_connection_table_type
+	pm_next_action_three_connection_dbs_2x2_table = {
+	[PM_STA_SAP_SCC_24_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_SAP_SCC_24_2x2] = {PM_NOP,		PM_NOP},
+	[PM_STA_SAP_MCC_24_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_SAP_MCC_24_2x2] = {PM_NOP,		PM_NOP},
+	[PM_STA_SAP_SCC_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_STA_SAP_SCC_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_STA_SAP_MCC_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_STA_SAP_MCC_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_STA_SAP_MCC_24_5_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_SAP_MCC_24_5_2x2] = {PM_NOP,		PM_NOP},
+	[PM_STA_SAP_DBS_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_SAP_DBS_2x2] = {PM_NOP,		PM_NOP},
+	[PM_STA_SAP_SBS_5_1x1] = {PM_DBS_UPGRADE,	PM_NOP},
+
+	[PM_STA_P2P_GO_SCC_24_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_P2P_GO_SCC_24_2x2] = {PM_NOP,		PM_NOP},
+	[PM_STA_P2P_GO_MCC_24_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_P2P_GO_MCC_24_2x2] = {PM_NOP,		PM_NOP},
+	[PM_STA_P2P_GO_SCC_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_STA_P2P_GO_SCC_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_STA_P2P_GO_MCC_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_STA_P2P_GO_MCC_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_STA_P2P_GO_MCC_24_5_1x1] = {PM_NOP,	PM_NOP},
+	[PM_STA_P2P_GO_MCC_24_5_2x2] = {PM_NOP,	PM_NOP},
+	[PM_STA_P2P_GO_DBS_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_P2P_GO_DBS_2x2] = {PM_NOP,		PM_NOP},
+	[PM_STA_P2P_GO_SBS_5_1x1] = {PM_DBS_UPGRADE,	PM_NOP},
+
+	[PM_STA_P2P_CLI_SCC_24_1x1] = {PM_NOP,	PM_NOP},
+	[PM_STA_P2P_CLI_SCC_24_2x2] = {PM_NOP,	PM_NOP},
+	[PM_STA_P2P_CLI_MCC_24_1x1] = {PM_NOP,	PM_NOP},
+	[PM_STA_P2P_CLI_MCC_24_2x2] = {PM_NOP,	PM_NOP},
+	[PM_STA_P2P_CLI_SCC_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_STA_P2P_CLI_SCC_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_STA_P2P_CLI_MCC_5_1x1] = {PM_DBS,		PM_SBS},
+	[PM_STA_P2P_CLI_MCC_5_2x2] = {PM_DBS,		PM_SBS_DOWNGRADE},
+	[PM_STA_P2P_CLI_MCC_24_5_1x1] = {PM_NOP,	PM_NOP},
+	[PM_STA_P2P_CLI_MCC_24_5_2x2] = {PM_NOP,	PM_NOP},
+	[PM_STA_P2P_CLI_DBS_1x1] = {PM_NOP,		PM_NOP},
+	[PM_STA_P2P_CLI_DBS_2x2] = {PM_NOP,		PM_NOP},
+	[PM_STA_P2P_CLI_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP},
+
+	[PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {PM_NOP,	PM_NOP},
+	[PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {PM_NOP,	PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {PM_NOP,	 PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {PM_NOP,	 PM_NOP},
+	[PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {PM_DBS,	  PM_SBS},
+	[PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {PM_DBS,	PM_SBS_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {PM_DBS,	  PM_SBS},
+	[PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {PM_DBS,	PM_SBS_DOWNGRADE},
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {PM_NOP,	PM_NOP},
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {PM_NOP,	PM_NOP},
+	[PM_P2P_GO_P2P_CLI_DBS_1x1] = {PM_NOP,	PM_NOP},
+	[PM_P2P_GO_P2P_CLI_DBS_2x2] = {PM_NOP,	PM_NOP},
+	[PM_P2P_GO_P2P_CLI_SBS_5_1x1] = {PM_DBS_UPGRADE,	PM_NOP},
+
+	[PM_STA_STA_SCC_24_1x1] = {PM_NOP,	PM_NOP},
+	[PM_STA_STA_SCC_24_2x2] = {PM_NOP,	PM_NOP},
+	[PM_STA_STA_MCC_24_1x1] = {PM_NOP,	PM_NOP},
+	[PM_STA_STA_MCC_24_2x2] = {PM_NOP,	PM_NOP},
+	[PM_STA_STA_SCC_5_1x1] = {PM_DBS,	PM_SBS},
+	[PM_STA_STA_SCC_5_2x2] = {PM_DBS,	PM_SBS_DOWNGRADE},
+	[PM_STA_STA_MCC_5_1x1] = {PM_DBS,	PM_SBS},
+	[PM_STA_STA_MCC_5_2x2] = {PM_DBS,	PM_SBS_DOWNGRADE},
+	[PM_STA_STA_MCC_24_5_1x1] = {PM_NOP,	PM_NOP},
+	[PM_STA_STA_MCC_24_5_2x2] = {PM_NOP,	PM_NOP},
+	[PM_STA_STA_DBS_1x1] = {PM_NOP,	PM_NOP},
+	[PM_STA_STA_DBS_2x2] = {PM_NOP,	PM_NOP},
+	[PM_STA_STA_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP},
+
+	[PM_SAP_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS},
+	[PM_SAP_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS},
+	[PM_SAP_SAP_SCC_5_1x1] = {PM_DBS, PM_NOP},
+	[PM_SAP_SAP_SCC_5_2x2] = {PM_DBS, PM_NOP},
+
+};
+
+#endif

+ 900 - 0
components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_no_dbs_i.h

@@ -0,0 +1,900 @@
+/*
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WLAN_POLICY_MGR_TABLES_NO_DBS_H
+#define __WLAN_POLICY_MGR_TABLES_NO_DBS_H
+
+#include "wlan_policy_mgr_api.h"
+
+/**
+ * second_connection_pcl_nodbs_table - table which provides PCL
+ * for the 2nd connection, when we have a connection already in
+ * the system (with DBS not supported by HW)
+ */
+static const enum policy_mgr_pcl_type
+second_connection_pcl_nodbs_table[PM_MAX_ONE_CONNECTION_MODE]
+			[PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE] = {
+	[PM_STA_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_P2P_GO_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_24_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_24_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH,    PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH,    PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH,    PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH,    PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH,    PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH,    PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_24_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_24_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_SAP_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_24_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_24_2x2] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_5_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_IBSS_5_2x2] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+};
+
+/**
+ * third_connection_pcl_nodbs_table - table which provides PCL
+ * for the 3rd connection, when we have two connections already
+ * in the system (with DBS not supported by HW)
+ */
+static const enum policy_mgr_pcl_type
+third_connection_pcl_nodbs_table[PM_MAX_TWO_CONNECTION_MODE]
+			[PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE] = {
+	[PM_STA_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G,        PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_5G,        PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {
+			PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {
+			PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_SCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_GO_DBS_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_2x2] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_STA_P2P_CLI_DBS_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {
+			PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {
+	[PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {
+			PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_P2P_CLI_DBS_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_GO_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+
+	[PM_P2P_CLI_SAP_SCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_SCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_24_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_24_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_SCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_SCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_24_5_1x1] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_MCC_24_5_2x2] = {
+	[PM_STA_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+	[PM_P2P_CLI_SAP_DBS_1x1] = {
+	[PM_STA_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_SAP_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_CLIENT_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_P2P_GO_MODE] = {
+			PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE},
+	[PM_IBSS_MODE] = {
+		PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} },
+
+};
+
+#endif

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

@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "wlan_policy_mgr_ucfg.h"
+#include "wlan_policy_mgr_i.h"
+#include "cfg_ucfg_api.h"
+#include "wlan_policy_mgr_api.h"
+
+static QDF_STATUS policy_mgr_init_cfg(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+	struct policy_mgr_cfg *cfg;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	cfg = &pm_ctx->cfg;
+
+	cfg->mcc_to_scc_switch = cfg_get(psoc, CFG_MCC_TO_SCC_SWITCH);
+	cfg->sys_pref = cfg_get(psoc, CFG_CONC_SYS_PREF);
+	cfg->max_conc_cxns = cfg_get(psoc, CFG_MAX_CONC_CXNS);
+	cfg->conc_rule1 = cfg_get(psoc, CFG_ENABLE_CONC_RULE1);
+	cfg->conc_rule2 = cfg_get(psoc, CFG_ENABLE_CONC_RULE2);
+	cfg->dbs_selection_plcy = cfg_get(psoc, CFG_DBS_SELECTION_PLCY);
+	cfg->vdev_priority_list = cfg_get(psoc, CFG_VDEV_CUSTOM_PRIORITY_LIST);
+	cfg->chnl_select_plcy = cfg_get(psoc, CFG_CHNL_SELECT_LOGIC_CONC);
+	cfg->enable_mcc_adaptive_sch =
+		cfg_get(psoc, CFG_ENABLE_MCC_ADATIVE_SCH_ENABLED_NAME);
+	cfg->enable_sta_cxn_5g_band =
+		cfg_get(psoc, CFG_ENABLE_STA_CONNECTION_IN_5GHZ);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void policy_mgr_deinit_cfg(struct wlan_objmgr_psoc *psoc)
+{
+	struct policy_mgr_psoc_priv_obj *pm_ctx;
+
+	pm_ctx = policy_mgr_get_context(psoc);
+	if (!pm_ctx) {
+		policy_mgr_err("pm_ctx is NULL");
+		return;
+	}
+
+	qdf_mem_zero(&pm_ctx->cfg, sizeof(pm_ctx->cfg));
+}
+
+QDF_STATUS ucfg_policy_mgr_psoc_open(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+
+	status = policy_mgr_init_cfg(psoc);
+	if (status != QDF_STATUS_SUCCESS) {
+		policy_mgr_err("pm_ctx is NULL");
+		return status;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+void ucfg_policy_mgr_psoc_close(struct wlan_objmgr_psoc *psoc)
+{
+	policy_mgr_deinit_cfg(psoc);
+}
+
+QDF_STATUS ucfg_policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc,
+					      uint8_t *mcc_scc_switch)
+{
+	return policy_mgr_get_mcc_scc_switch(psoc, mcc_scc_switch);
+}
+
+QDF_STATUS ucfg_policy_mgr_get_sys_pref(struct wlan_objmgr_psoc *psoc,
+					uint8_t *sys_pref)
+{
+	return policy_mgr_get_sys_pref(psoc, sys_pref);
+}
+
+QDF_STATUS ucfg_policy_mgr_set_sys_pref(struct wlan_objmgr_psoc *psoc,
+					uint8_t sys_pref)
+{
+	return policy_mgr_set_sys_pref(psoc, sys_pref);
+}
+
+QDF_STATUS ucfg_policy_mgr_get_max_conc_cxns(struct wlan_objmgr_psoc *psoc,
+						uint8_t *max_conc_cxns)
+{
+	return policy_mgr_get_max_conc_cxns(psoc, max_conc_cxns);;
+}
+
+QDF_STATUS ucfg_policy_mgr_get_conc_rule1(struct wlan_objmgr_psoc *psoc,
+						uint8_t *conc_rule1)
+{
+	return policy_mgr_get_conc_rule1(psoc, conc_rule1);
+}
+
+QDF_STATUS ucfg_policy_mgr_get_conc_rule2(struct wlan_objmgr_psoc *psoc,
+						uint8_t *conc_rule2)
+{
+	return policy_mgr_get_conc_rule2(psoc, conc_rule2);
+}
+
+QDF_STATUS ucfg_policy_mgr_get_dbs_selection_plcy(struct wlan_objmgr_psoc *psoc,
+						uint32_t *dbs_selection_plcy)
+{
+	return policy_mgr_get_dbs_selection_plcy(psoc, dbs_selection_plcy);
+}
+
+QDF_STATUS ucfg_policy_mgr_get_vdev_priority_list(struct wlan_objmgr_psoc *psoc,
+						uint32_t *vdev_priority_list)
+{
+	return policy_mgr_get_vdev_priority_list(psoc, vdev_priority_list);
+}
+
+QDF_STATUS ucfg_policy_mgr_get_chnl_select_plcy(struct wlan_objmgr_psoc *psoc,
+						uint32_t *chnl_select_plcy)
+{
+	return policy_mgr_get_chnl_select_plcy(psoc, chnl_select_plcy);
+}
+
+
+QDF_STATUS ucfg_policy_mgr_get_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc,
+						uint8_t *mcc_adaptive_sch)
+{
+	return policy_mgr_get_mcc_adaptive_sch(psoc, mcc_adaptive_sch);
+}
+
+QDF_STATUS ucfg_policy_mgr_get_sta_cxn_5g_band(struct wlan_objmgr_psoc *psoc,
+					       uint8_t *enable_sta_cxn_5g_band)
+{
+	return policy_mgr_get_sta_cxn_5g_band(psoc, enable_sta_cxn_5g_band);
+}

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

@@ -181,6 +181,9 @@ QDF_STATUS mlme_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc);
  *
  * Return: pointer to MLME object
  */
-struct wlan_mlme_psoc_obj *mlme_get_psoc_obj(struct wlan_objmgr_psoc *psoc);
+#define mlme_get_psoc_obj(psoc) mlme_get_psoc_obj_fl(psoc, __func__, __LINE__)
+struct wlan_mlme_psoc_obj *mlme_get_psoc_obj_fl(struct wlan_objmgr_psoc *psoc,
+						const char *func,
+						uint32_t line);
 
 #endif

+ 27 - 3
components/mlme/core/src/wlan_mlme_main.c

@@ -28,13 +28,16 @@
 
 #define NUM_OF_SOUNDING_DIMENSIONS     1 /*Nss - 1, (Nss = 2 for 2x2)*/
 
-struct wlan_mlme_psoc_obj *mlme_get_psoc_obj(struct wlan_objmgr_psoc *psoc)
+struct wlan_mlme_psoc_obj *mlme_get_psoc_obj_fl(struct wlan_objmgr_psoc *psoc,
+						const char *func, uint32_t line)
 {
 	struct wlan_mlme_psoc_obj *mlme_obj;
 
 	mlme_obj = (struct wlan_mlme_psoc_obj *)
 		wlan_objmgr_psoc_get_comp_private_obj(psoc,
 						      WLAN_UMAC_COMP_MLME);
+	if (!mlme_obj)
+		mlme_err("mlme obj is null, %s:%d", func, line);
 
 	return mlme_obj;
 }
@@ -585,6 +588,8 @@ static void mlme_init_timeout_cfg(struct wlan_objmgr_psoc *psoc,
 			cfg_get(psoc, CFG_AP_LINK_MONITOR_TIMEOUT);
 	timeouts->ps_data_inactivity_timeout =
 			cfg_get(psoc, CFG_PS_DATA_INACTIVITY_TIMEOUT);
+	timeouts->wmi_wq_watchdog_timeout =
+			cfg_get(psoc, CFG_WMI_WQ_WATCHDOG);
 }
 
 static void mlme_init_ht_cap_in_cfg(struct wlan_objmgr_psoc *psoc,
@@ -850,8 +855,19 @@ static void mlme_init_rates_in_cfg(struct wlan_objmgr_psoc *psoc,
 static void mlme_init_dfs_cfg(struct wlan_objmgr_psoc *psoc,
 			      struct wlan_mlme_dfs_cfg *dfs_cfg)
 {
-	dfs_cfg->dfs_master_capable = cfg_get(psoc,
-					      CFG_ENABLE_DFS_MASTER_CAPABILITY);
+	dfs_cfg->dfs_ignore_cac = cfg_get(psoc, CFG_IGNORE_CAC);
+	dfs_cfg->dfs_master_capable =
+		cfg_get(psoc, CFG_ENABLE_DFS_MASTER_CAPABILITY);
+	dfs_cfg->dfs_disable_channel_switch =
+		cfg_get(psoc, CFG_DISABLE_DFS_CH_SWITCH);
+	dfs_cfg->dfs_filter_offload =
+		cfg_get(psoc, CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD);
+	dfs_cfg->dfs_prefer_non_dfs =
+		cfg_get(psoc, CFG_ENABLE_NON_DFS_CHAN_ON_RADAR);
+	dfs_cfg->dfs_beacon_tx_enhanced =
+		cfg_get(psoc, CFG_DFS_BEACON_TX_ENHANCED);
+	dfs_cfg->sap_tx_leakage_threshold =
+		cfg_get(psoc, CFG_SAP_TX_LEAKAGE_THRESHOLD);
 }
 
 static void mlme_init_feature_flag_in_cfg(
@@ -1687,6 +1703,13 @@ static void mlme_init_wep_cfg(struct wlan_mlme_wep_cfg *wep_params)
 	mlme_init_wep_keys(wep_params);
 }
 
+static void mlme_init_wifi_pos_cfg(struct wlan_objmgr_psoc *psoc,
+				   struct wlan_mlme_wifi_pos_cfg *wifi_pos_cfg)
+{
+	wifi_pos_cfg->fine_time_meas_cap =
+		cfg_get(psoc, CFG_FINE_TIME_MEAS_CAPABILITY);
+}
+
 #ifdef FEATURE_WLAN_ESE
 static void mlme_init_inactivity_intv(struct wlan_objmgr_psoc *psoc,
 				      struct wlan_mlme_wmm_params *wmm_params)
@@ -1844,6 +1867,7 @@ QDF_STATUS mlme_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc)
 	mlme_init_power_cfg(psoc, &mlme_cfg->power);
 	mlme_init_oce_cfg(psoc, &mlme_cfg->oce);
 	mlme_init_wep_cfg(&mlme_cfg->wep_params);
+	mlme_init_wifi_pos_cfg(psoc, &mlme_cfg->wifi_pos_cfg);
 	mlme_init_wps_params_cfg(psoc, &mlme_cfg->wps_params);
 
 	return status;

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

@@ -50,6 +50,7 @@
 #include "cfg_mlme_threshold.h"
 #include "cfg_mlme_feature_flag.h"
 #include "cfg_mlme_wep_params.h"
+#include "cfg_mlme_wifi_pos.h"
 
 /* Please Maintain Alphabetic Order here */
 #define CFG_MLME_ALL \
@@ -80,6 +81,7 @@
 	CFG_TWT_ALL \
 	CFG_VHT_CAPS_ALL \
 	CFG_WEP_PARAMS_ALL \
+	CFG_WIFI_POS_ALL \
 	CFG_WPS_ALL
 
 #endif /* __CFG_MLME_H */

+ 137 - 1
components/mlme/dispatcher/inc/cfg_mlme_dfs.h

@@ -23,6 +23,136 @@
 #ifndef __CFG_MLME_DFS_H
 #define __CFG_MLME_DFS_H
 
+/*
+ * <ini>
+ * gsap_tx_leakage_threshold - sap tx leakage threshold
+ * @Min: 100
+ * @Max: 1000
+ * @Default: 310
+ *
+ * customer can set this value from 100 to 1000 which means
+ * sap tx leakage threshold is -10db to -100db
+ *
+ * Related: none
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_SAP_TX_LEAKAGE_THRESHOLD CFG_INI_UINT( \
+			"gsap_tx_leakage_threshold", \
+			100, \
+			1000, \
+			310, \
+			CFG_VALUE_OR_DEFAULT, \
+			"sap tx leakage threshold")
+
+/*
+ * <ini>
+ * gDfsBeaconTxEnhanced - beacon tx enhanced
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to enhance dfs beacon tx
+ *
+ * Related: none
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_DFS_BEACON_TX_ENHANCED CFG_INI_BOOL( \
+			"gDfsBeaconTxEnhanced", \
+			0, \
+			"beacon tx enhanced")
+
+/*
+ * <ini>
+ * gPreferNonDfsChanOnRadar - During random channel selection prefer non dfs
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * During random channel selection prefer non dfs.
+ *
+ * Related: none
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR CFG_INI_BOOL( \
+			"gPreferNonDfsChanOnRadar", \
+			0, \
+			"channel selection prefer non dfs")
+
+/*
+ * <ini>
+ * dfsPhyerrFilterOffload - Enable dfs phyerror filtering offload in FW
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to to enable dfs phyerror filtering offload to firmware
+ * Enabling it will cause basic phy error to be discarding in firmware.
+ * Related: NA.
+ *
+ * Supported Feature: DFS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD CFG_INI_BOOL( \
+			"dfsPhyerrFilterOffload", \
+			0, \
+			"dfs phyerror filtering offload")
+
+/*
+ * <ini>
+ * gIgnoreCAC - Used to ignore CAC
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to set default CAC
+ *
+ * Related: None
+ *
+ * Supported Feature: DFS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_IGNORE_CAC CFG_INI_BOOL( \
+			"gIgnoreCAC", \
+			0, \
+			"ignore CAC on DFS channel")
+
+/*
+ * <ini>
+ * gDisableDFSChSwitch - Disable channel switch if radar is found
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to disable channel switch if radar is found
+ * on that channel.
+ * Related: NA.
+ *
+ * Supported Feature: DFS
+ *
+ * Usage: Internal
+ *
+ * </ini>
+ */
+#define CFG_DISABLE_DFS_CH_SWITCH CFG_INI_BOOL( \
+			"gDisableDFSChSwitch", \
+			0, \
+			"Disable channel switch on radar")
+
 /*
  * <ini>
  * gEnableDFSMasterCap - Enable DFS master capability
@@ -47,6 +177,12 @@
 			"DFS master mode capability")
 
 #define CFG_DFS_ALL \
-	CFG(CFG_ENABLE_DFS_MASTER_CAPABILITY)
+	CFG(CFG_IGNORE_CAC) \
+	CFG(CFG_DISABLE_DFS_CH_SWITCH) \
+	CFG(CFG_DFS_BEACON_TX_ENHANCED) \
+	CFG(CFG_SAP_TX_LEAKAGE_THRESHOLD) \
+	CFG(CFG_ENABLE_NON_DFS_CHAN_ON_RADAR) \
+	CFG(CFG_ENABLE_DFS_MASTER_CAPABILITY) \
+	CFG(CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD)
 
 #endif /* __CFG_MLME_DFS_H */

+ 27 - 0
components/mlme/dispatcher/inc/cfg_mlme_timeout.h

@@ -285,6 +285,32 @@
 		CFG_VALUE_OR_DEFAULT, \
 		"PS data inactivity timeout")
 
+/*
+ * <ini>
+ * wmi_wq_watchdog - Sets timeout period for wmi watchdog bite.
+ * @Min: 0
+ * @Max: 30
+ * @Default: 20
+ *
+ * This ini is used to set timeout period for wmi watchdog bite. If it is
+ * 0 then wmi watchdog bite is disabled.
+ *
+ * Related: None
+ *
+ * Supported Feature: STA
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_WMI_WQ_WATCHDOG CFG_INI_UINT( \
+		"wmi_wq_watchdog", \
+		0, \
+		30, \
+		20, \
+		CFG_VALUE_OR_DEFAULT, \
+		"timeout period for wmi watchdog bite")
+
 #define CFG_TIMEOUT_ALL \
 	CFG(CFG_JOIN_FAILURE_TIMEOUT) \
 	CFG(CFG_AUTH_FAILURE_TIMEOUT) \
@@ -297,6 +323,7 @@
 	CFG(CFG_HEART_BEAT_THRESHOLD) \
 	CFG(CFG_AP_KEEP_ALIVE_TIMEOUT) \
 	CFG(CFG_AP_LINK_MONITOR_TIMEOUT) \
+	CFG(CFG_WMI_WQ_WATCHDOG) \
 	CFG(CFG_PS_DATA_INACTIVITY_TIMEOUT)
 
 #endif /* __CFG_MLME_TIMEOUT_H */

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

@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2012-2018 The Linux Foundation. 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: This file contains centralized definitions of converged configuration.
+ */
+
+#ifndef __CFG_MLME_WIFI_POS_H
+#define __CFG_MLME_WIFI_POS_H
+
+/*
+ * <ini>
+ * gfine_time_meas_cap - fine timing measurement capability information
+ * @Min: 0x0000
+ * @Max: 0x00BD
+ * @Default: 0x00BD
+ *
+ * fine timing measurement capability information
+ *
+ * <----- fine_time_meas_cap (in bits) ----->
+ * +----------+-----+-----+------+------+-------+-------+-----+-----+
+ * |   8-31   |  7  |  6  |   5  |   4  |   3   |   2   |  1  |  0  |
+ * +----------+-----+-----+------+------+-------+-------+-----+-----+
+ * | reserved | SAP | SAP |P2P-GO|P2P-GO|P2P-CLI|P2P-CLI| STA | STA |
+ * |          |resp |init |resp  |init  |resp   |init   |resp |init |
+ * +----------+-----+-----+------+------+-------+-------+-----+-----+
+ *
+ * resp - responder role; init- initiator role
+ *
+ * CFG_FINE_TIME_MEAS_CAPABILITY_MAX computed based on the table
+ * +-----------------+-----------------+-----------+
+ * |  Device Role    |   Initiator     | Responder |
+ * +-----------------+-----------------+-----------+
+ * |   Station       |       Y         |     N     |
+ * |   P2P-CLI       |       Y         |     Y     |
+ * |   P2P-GO        |       Y         |     Y     |
+ * |   SAP           |       N         |     Y     |
+ * +-----------------+-----------------+-----------+
+ *
+ * Related: None
+ *
+ * Supported Feature: WIFI POS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_FINE_TIME_MEAS_CAPABILITY CFG_INI_UINT( \
+			"gfine_time_meas_cap", \
+			0x0000, \
+			0x00BD, \
+			0x00BD, \
+			CFG_VALUE_OR_DEFAULT, \
+			"fine timing measurement capability")
+
+#define CFG_WIFI_POS_ALL \
+	CFG(CFG_FINE_TIME_MEAS_CAPABILITY)
+
+#endif /* __CFG_MLME_WIFI_POS_H */

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

@@ -573,9 +573,21 @@ struct wlan_mlme_cfg_sap {
 /**
  * struct wlan_mlme_dfs_cfg - DFS Capabilities related config items
  * @dfs_master_capable: Is DFS master mode support enabled
+ * @dfs_disable_channel_switch: disable channel switch on radar detection
+ * @dfs_ignore_cac: Disable cac
+ * @dfs_filter_offload: dfs filter offloaad
+ * @dfs_beacon_tx_enhanced: enhance dfs beacon tx
+ * @dfs_prefer_non_dfs: perefer non dfs channel after radar
+ * @sap_tx_leakage_threshold: sap tx leakage threshold
  */
 struct wlan_mlme_dfs_cfg {
 	bool dfs_master_capable;
+	bool dfs_disable_channel_switch;
+	bool dfs_ignore_cac;
+	bool dfs_filter_offload;
+	bool dfs_beacon_tx_enhanced;
+	bool dfs_prefer_non_dfs;
+	uint32_t sap_tx_leakage_threshold;
 };
 
 /**
@@ -1556,6 +1568,7 @@ struct wlan_mlme_power {
  * @ap_keep_alive_timeout: AP keep alive timeout value
  * @ap_link_monitor_timeout: AP link monitor timeout value
  * @ps_data_inactivity_timeout: PS data inactivity timeout
+ * @wmi_wq_watchdog_timeout: timeout period for wmi watchdog bite
  */
 struct wlan_mlme_timeout {
 	uint32_t join_failure_timeout;
@@ -1570,6 +1583,7 @@ struct wlan_mlme_timeout {
 	uint32_t ap_keep_alive_timeout;
 	uint32_t ap_link_monitor_timeout;
 	uint32_t ps_data_inactivity_timeout;
+	uint32_t wmi_wq_watchdog_timeout;
 };
 
 /**
@@ -1630,6 +1644,14 @@ struct wlan_mlme_wep_cfg {
 	struct mlme_cfg_str wep_default_key_4;
 };
 
+/**
+ * struct wlan_mlme_wifi_pos_cfg - WIFI POS configs
+ * @fine_time_meas_cap: fine timing measurement capability information
+ */
+struct wlan_mlme_wifi_pos_cfg {
+	uint32_t fine_time_meas_cap;
+};
+
 /**
  * struct wlan_mlme_cfg - MLME config items
  * @chainmask_cfg: VHT chainmask related cfg items
@@ -1658,6 +1680,7 @@ struct wlan_mlme_wep_cfg {
  * @acs: ACS related CFG items
  * @feature_flags: Feature flag config items
  * @wep_params:  WEP related config items
+ * @wifi_pos_cfg: WIFI POS config
  * @wmm_params: WMM related CFG & INI Items
  * @wps_params: WPS related CFG itmes
  */
@@ -1690,6 +1713,7 @@ struct wlan_mlme_cfg {
 	struct wlan_mlme_acs acs;
 	struct wlan_mlme_feature_flag feature_flags;
 	struct wlan_mlme_wep_cfg wep_params;
+	struct wlan_mlme_wifi_pos_cfg wifi_pos_cfg;
 	struct wlan_mlme_wmm_params wmm_params;
 	struct wlan_mlme_wps_params wps_params;
 };

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

@@ -702,6 +702,115 @@ QDF_STATUS
 ucfg_mlme_get_dfs_master_capability(struct wlan_objmgr_psoc *psoc,
 				    bool *val);
 
+/*
+ * ucfg_mlme_get_dfs_disable_channel_switch() - Get the dfs channel switch
+ * @psoc: pointer to psoc object
+ * @dfs_disable_channel_switch:  Pointer to the value which will be filled
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_get_dfs_disable_channel_switch(struct wlan_objmgr_psoc *psoc,
+					 bool *dfs_disable_channel_switch);
+
+/*
+ * ucfg_mlme_set_dfs_disable_channel_switch() - Set the dfs channel switch
+ * @psoc: pointer to psoc object
+ * @dfs_disable_channel_switch: Value that needs to be set.
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_set_dfs_disable_channel_switch(struct wlan_objmgr_psoc *psoc,
+					 bool dfs_disable_channel_switch);
+/*
+ * ucfg_mlme_get_dfs_ignore_cac() - GSet the dfs ignore cac
+ * @psoc: pointer to psoc object
+ * @dfs_ignore_cac: Pointer to the value which will be filled for the caller
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_get_dfs_ignore_cac(struct wlan_objmgr_psoc *psoc,
+			     bool *dfs_ignore_cac);
+
+/*
+ * ucfg_mlme_set_dfs_ignore_cac() - Set the dfs ignore cac
+ * @psoc: pointer to psoc object
+ * @dfs_ignore_cac: Value that needs to be set.
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_set_dfs_ignore_cac(struct wlan_objmgr_psoc *psoc,
+			     bool dfs_ignore_cac);
+
+/*
+ * ucfg_mlme_get_sap_tx_leakage_threshold() - Get sap tx leakage threshold
+ * @psoc: pointer to psoc object
+ * @sap_tx_leakage_threshold: Pointer to the value which will be filled
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_get_sap_tx_leakage_threshold(struct wlan_objmgr_psoc *psoc,
+				       uint32_t *sap_tx_leakage_threshold);
+
+/*
+ * ucfg_mlme_set_sap_tx_leakage_threshold() - Set sap tx leakage threshold
+ * @psoc: pointer to psoc object
+ * @sap_tx_leakage_threshold: Value that needs to be set.
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_set_sap_tx_leakage_threshold(struct wlan_objmgr_psoc *psoc,
+				       uint32_t sap_tx_leakage_threshold);
+
+/*
+ * ucfg_mlme_get_dfs_filter_offload() - Get the dfs filter offload
+ * @psoc: pointer to psoc object
+ * @dfs_filter_offload: Pointer to the value which will be filled
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_get_dfs_filter_offload(struct wlan_objmgr_psoc *psoc,
+				 bool *dfs_filter_offload);
+
+/*
+ * ucfg_mlme_set_dfs_filter_offload() - Set the dfs filter offload
+ * @psoc: pointer to psoc object
+ * @dfs_filter_offload: Value that needs to be set.
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_set_dfs_filter_offload(struct wlan_objmgr_psoc *psoc,
+				 bool dfs_filter_offload);
+
+/**
+ * ucfg_mlme_get_fine_time_meas_cap() - Get fine timing measurement capability
+ * @psoc: pointer to psoc object
+ * @fine_time_meas_cap: Pointer to the value which will be filled for the caller
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_get_fine_time_meas_cap(struct wlan_objmgr_psoc *psoc,
+				 uint32_t *fine_time_meas_cap);
+
+/**
+ * ucfg_mlme_set_fine_time_meas_cap() - Set fine timing measurement capability
+ * @psoc: pointer to psoc object
+ * @fine_time_meas_cap:  Value to be set
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_set_fine_time_meas_cap(struct wlan_objmgr_psoc *psoc,
+				 uint32_t fine_time_meas_cap);
+
 /**
  * ucfg_mlme_get_pmkid_modes() - Get PMKID modes
  * @psoc: pointer to psoc object
@@ -1116,6 +1225,28 @@ QDF_STATUS
 ucfg_mlme_set_fast_roam_in_concurrency_enabled(struct wlan_objmgr_psoc *psoc,
 					       bool val);
 
+/**
+ * ucfg_mlme_get_wmi_wq_watchdog_timeout() - Get timeout for wmi watchdog bite
+ * @psoc: pointer to psoc object
+ * @wmi_wq_watchdog_timeout: buffer to hold value
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_get_wmi_wq_watchdog_timeout(struct wlan_objmgr_psoc *psoc,
+				      uint32_t *wmi_wq_watchdog_timeout);
+
+/**
+ * ucfg_mlme_set_wmi_wq_watchdog_timeout() - Set timeout for wmi watchdog bite
+ * @psoc: pointer to psoc object
+ * @wmi_wq_watchdog_timeout: value to be set
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS
+ucfg_mlme_set_wmi_wq_watchdog_timeout(struct wlan_objmgr_psoc *psoc,
+				      uint32_t wmi_wq_watchdog_timeout);
+
 /**
  * ucfg_mlme_get_ps_data_inactivity_timeout() - Get data inactivity timeout
  * @psoc: pointer to psoc object

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

@@ -206,6 +206,186 @@ ucfg_mlme_get_dfs_master_capability(struct wlan_objmgr_psoc *psoc,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS
+ucfg_mlme_get_fine_time_meas_cap(struct wlan_objmgr_psoc *psoc,
+				 uint32_t *fine_time_meas_cap)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		*fine_time_meas_cap =
+			cfg_default(CFG_FINE_TIME_MEAS_CAPABILITY);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*fine_time_meas_cap = mlme_obj->cfg.wifi_pos_cfg.fine_time_meas_cap;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_set_fine_time_meas_cap(struct wlan_objmgr_psoc *psoc,
+				 uint32_t fine_time_meas_cap)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj)
+		return QDF_STATUS_E_INVAL;
+
+	mlme_obj->cfg.wifi_pos_cfg.fine_time_meas_cap = fine_time_meas_cap;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_get_dfs_disable_channel_switch(struct wlan_objmgr_psoc *psoc,
+					 bool *dfs_disable_channel_switch)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		*dfs_disable_channel_switch =
+			cfg_default(CFG_DISABLE_DFS_CH_SWITCH);
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*dfs_disable_channel_switch =
+		mlme_obj->cfg.dfs_cfg.dfs_disable_channel_switch;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_set_dfs_disable_channel_switch(struct wlan_objmgr_psoc *psoc,
+					 bool dfs_disable_channel_switch)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlme_obj->cfg.dfs_cfg.dfs_disable_channel_switch =
+		dfs_disable_channel_switch;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_get_dfs_ignore_cac(struct wlan_objmgr_psoc *psoc,
+			     bool *dfs_ignore_cac)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		*dfs_ignore_cac = cfg_default(CFG_IGNORE_CAC);
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*dfs_ignore_cac = mlme_obj->cfg.dfs_cfg.dfs_ignore_cac;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_set_dfs_ignore_cac(struct wlan_objmgr_psoc *psoc,
+			     bool dfs_ignore_cac)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlme_obj->cfg.dfs_cfg.dfs_ignore_cac = dfs_ignore_cac;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_get_sap_tx_leakage_threshold(struct wlan_objmgr_psoc *psoc,
+				       uint32_t *sap_tx_leakage_threshold)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		*sap_tx_leakage_threshold =
+			cfg_default(CFG_SAP_TX_LEAKAGE_THRESHOLD);
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*sap_tx_leakage_threshold =
+		mlme_obj->cfg.dfs_cfg.sap_tx_leakage_threshold;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_set_sap_tx_leakage_threshold(struct wlan_objmgr_psoc *psoc,
+				       uint32_t sap_tx_leakage_threshold)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlme_obj->cfg.dfs_cfg.sap_tx_leakage_threshold =
+		sap_tx_leakage_threshold;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_get_dfs_filter_offload(struct wlan_objmgr_psoc *psoc,
+				 bool *dfs_filter_offload)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		*dfs_filter_offload =
+			cfg_default(CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD);
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*dfs_filter_offload = mlme_obj->cfg.dfs_cfg.dfs_filter_offload;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_set_dfs_filter_offload(struct wlan_objmgr_psoc *psoc,
+				 bool dfs_filter_offload)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlme_obj->cfg.dfs_cfg.dfs_filter_offload = dfs_filter_offload;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS
 ucfg_mlme_get_pmkid_modes(struct wlan_objmgr_psoc *psoc,
 			  uint32_t *val)
@@ -971,6 +1151,49 @@ ucfg_mlme_get_current_mcs_set(struct wlan_objmgr_psoc *psoc,
 				     len);
 }
 
+QDF_STATUS
+ucfg_mlme_get_wmi_wq_watchdog_timeout(struct wlan_objmgr_psoc *psoc,
+				      uint32_t *wmi_wq_watchdog_timeout)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		*wmi_wq_watchdog_timeout = cfg_default(CFG_WMI_WQ_WATCHDOG);
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*wmi_wq_watchdog_timeout =
+		mlme_obj->cfg.timeouts.wmi_wq_watchdog_timeout;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+ucfg_mlme_set_wmi_wq_watchdog_timeout(struct wlan_objmgr_psoc *psoc,
+				      uint32_t wmi_wq_watchdog_timeout)
+{
+	struct wlan_mlme_psoc_obj *mlme_obj;
+
+	mlme_obj = mlme_get_psoc_obj(psoc);
+	if (!mlme_obj) {
+		mlme_err("mlme obj null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!cfg_in_range(CFG_WMI_WQ_WATCHDOG, wmi_wq_watchdog_timeout)) {
+		mlme_err("wmi watchdog bite timeout is invalid %d",
+			 wmi_wq_watchdog_timeout);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlme_obj->cfg.timeouts.wmi_wq_watchdog_timeout =
+		wmi_wq_watchdog_timeout;
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS
 ucfg_mlme_get_ps_data_inactivity_timeout(struct wlan_objmgr_psoc *psoc,
 					 uint32_t *inactivity_timeout)

+ 1460 - 0
components/p2p/core/src/wlan_p2p_main.c

@@ -0,0 +1,1460 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: This file contains main P2P function definitions
+ */
+
+#include <scheduler_api.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_peer_obj.h>
+#include <wlan_scan_ucfg_api.h>
+#include "wlan_p2p_public_struct.h"
+#include "wlan_p2p_ucfg_api.h"
+#include "wlan_p2p_tgt_api.h"
+#include "wlan_p2p_main.h"
+#include "wlan_p2p_roc.h"
+#include "wlan_p2p_off_chan_tx.h"
+#include "wlan_p2p_cfg.h"
+#include "cfg_ucfg_api.h"
+
+/**
+ * p2p_get_cmd_type_str() - parse cmd to string
+ * @cmd_type: P2P cmd type
+ *
+ * This function parse P2P cmd to string.
+ *
+ * Return: command string
+ */
+static char *p2p_get_cmd_type_str(enum p2p_cmd_type cmd_type)
+{
+	switch (cmd_type) {
+	case P2P_ROC_REQ:
+		return "P2P roc request";
+	case P2P_CANCEL_ROC_REQ:
+		return "P2P cancel roc request";
+	case P2P_MGMT_TX:
+		return "P2P mgmt tx request";
+	case P2P_MGMT_TX_CANCEL:
+		return "P2P cancel mgmt tx request";
+	case P2P_CLEANUP_ROC:
+		return "P2P cleanup roc";
+	case P2P_CLEANUP_TX:
+		return "P2P cleanup tx";
+	case P2P_SET_RANDOM_MAC:
+		return "P2P set random mac";
+	default:
+		return "Invalid P2P command";
+	}
+}
+
+/**
+ * p2p_get_event_type_str() - parase event to string
+ * @event_type: P2P event type
+ *
+ * This function parse P2P event to string.
+ *
+ * Return: event string
+ */
+static char *p2p_get_event_type_str(enum p2p_event_type event_type)
+{
+	switch (event_type) {
+	case P2P_EVENT_SCAN_EVENT:
+		return "P2P scan event";
+	case P2P_EVENT_MGMT_TX_ACK_CNF:
+		return "P2P mgmt tx ack event";
+	case P2P_EVENT_RX_MGMT:
+		return "P2P mgmt rx event";
+	case P2P_EVENT_LO_STOPPED:
+		return "P2P lo stop event";
+	case P2P_EVENT_NOA:
+		return "P2P noa event";
+	case P2P_EVENT_ADD_MAC_RSP:
+		return "P2P add mac filter resp event";
+	default:
+		return "Invalid P2P event";
+	}
+}
+
+/**
+ * p2p_psoc_obj_create_notification() - Function to allocate per P2P
+ * soc private object
+ * @soc: soc context
+ * @data: Pointer to data
+ *
+ * This function gets called from object manager when psoc is being
+ * created and creates p2p soc context.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_psoc_obj_create_notification(
+	struct wlan_objmgr_psoc *soc, void *data)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status;
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = qdf_mem_malloc(sizeof(*p2p_soc_obj));
+	if (!p2p_soc_obj) {
+		p2p_err("Failed to allocate p2p soc private object");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	p2p_soc_obj->soc = soc;
+
+	status = wlan_objmgr_psoc_component_obj_attach(soc,
+				WLAN_UMAC_COMP_P2P, p2p_soc_obj,
+				QDF_STATUS_SUCCESS);
+	if (status != QDF_STATUS_SUCCESS) {
+		qdf_mem_free(p2p_soc_obj);
+		p2p_err("Failed to attach p2p component, %d", status);
+		return status;
+	}
+
+	p2p_debug("p2p soc object create successful, %pK", p2p_soc_obj);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_psoc_obj_destroy_notification() - Free soc private object
+ * @soc: soc context
+ * @data: Pointer to data
+ *
+ * This function gets called from object manager when psoc is being
+ * deleted and delete p2p soc context.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_psoc_obj_destroy_notification(
+	struct wlan_objmgr_psoc *soc, void *data)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status;
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc private object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	p2p_soc_obj->soc = NULL;
+
+	status = wlan_objmgr_psoc_component_obj_detach(soc,
+				WLAN_UMAC_COMP_P2P, p2p_soc_obj);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to detach p2p component, %d", status);
+		return status;
+	}
+
+	p2p_debug("destroy p2p soc object, %pK", p2p_soc_obj);
+
+	qdf_mem_free(p2p_soc_obj);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_vdev_obj_create_notification() - Allocate per p2p vdev object
+ * @vdev: vdev context
+ * @data: Pointer to data
+ *
+ * This function gets called from object manager when vdev is being
+ * created and creates p2p vdev context.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_vdev_obj_create_notification(
+	struct wlan_objmgr_vdev *vdev, void *data)
+{
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	QDF_STATUS status;
+	enum QDF_OPMODE mode;
+
+	if (!vdev) {
+		p2p_err("vdev context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	p2p_debug("vdev mode:%d", mode);
+	if (mode != QDF_P2P_GO_MODE &&
+	    mode != QDF_STA_MODE &&
+	    mode != QDF_P2P_CLIENT_MODE &&
+	    mode != QDF_P2P_DEVICE_MODE) {
+		p2p_debug("won't create p2p vdev private object for mode %d",
+			  mode);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	p2p_vdev_obj =
+		qdf_mem_malloc(sizeof(*p2p_vdev_obj));
+	if (!p2p_vdev_obj) {
+		p2p_err("Failed to allocate p2p vdev object");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	p2p_vdev_obj->vdev = vdev;
+	p2p_vdev_obj->noa_status = true;
+	p2p_vdev_obj->non_p2p_peer_count = 0;
+	p2p_init_random_mac_vdev(p2p_vdev_obj);
+
+	status = wlan_objmgr_vdev_component_obj_attach(vdev,
+				WLAN_UMAC_COMP_P2P, p2p_vdev_obj,
+				QDF_STATUS_SUCCESS);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_deinit_random_mac_vdev(p2p_vdev_obj);
+		qdf_mem_free(p2p_vdev_obj);
+		p2p_err("Failed to attach p2p component to vdev, %d",
+			status);
+		return status;
+	}
+
+	p2p_debug("p2p vdev object create successful, %pK", p2p_vdev_obj);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_vdev_obj_destroy_notification() - Free per P2P vdev object
+ * @vdev: vdev context
+ * @data: Pointer to data
+ *
+ * This function gets called from object manager when vdev is being
+ * deleted and delete p2p vdev context.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_vdev_obj_destroy_notification(
+	struct wlan_objmgr_vdev *vdev, void *data)
+{
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	QDF_STATUS status;
+	enum QDF_OPMODE mode;
+
+	if (!vdev) {
+		p2p_err("vdev context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	p2p_debug("vdev mode:%d", mode);
+	if (mode != QDF_P2P_GO_MODE &&
+	    mode != QDF_STA_MODE &&
+	    mode != QDF_P2P_CLIENT_MODE &&
+	    mode != QDF_P2P_DEVICE_MODE){
+		p2p_debug("no p2p vdev private object for mode %d", mode);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_vdev_obj) {
+		p2p_debug("p2p vdev object is NULL");
+		return QDF_STATUS_SUCCESS;
+	}
+	p2p_deinit_random_mac_vdev(p2p_vdev_obj);
+
+	p2p_vdev_obj->vdev = NULL;
+
+	status = wlan_objmgr_vdev_component_obj_detach(vdev,
+				WLAN_UMAC_COMP_P2P, p2p_vdev_obj);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to detach p2p component, %d", status);
+		return status;
+	}
+
+	p2p_debug("destroy p2p vdev object, p2p vdev obj:%pK, noa info:%pK",
+		p2p_vdev_obj, p2p_vdev_obj->noa_info);
+
+	if (p2p_vdev_obj->noa_info)
+		qdf_mem_free(p2p_vdev_obj->noa_info);
+
+	qdf_mem_free(p2p_vdev_obj);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_peer_obj_create_notification() - manages peer details per vdev
+ * @peer: peer object
+ * @arg: Pointer to private argument - NULL
+ *
+ * This function gets called from object manager when peer is being
+ * created.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_peer_obj_create_notification(
+	struct wlan_objmgr_peer *peer, void *arg)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	enum QDF_OPMODE mode;
+	enum wlan_peer_type peer_type;
+
+	if (!peer) {
+		p2p_err("peer context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev = wlan_peer_get_vdev(peer);
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (mode != QDF_P2P_GO_MODE)
+		return QDF_STATUS_SUCCESS;
+
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+						WLAN_UMAC_COMP_P2P);
+	peer_type = wlan_peer_get_peer_type(peer);
+	if ((peer_type == WLAN_PEER_STA) && p2p_vdev_obj) {
+
+		mode = wlan_vdev_mlme_get_opmode(vdev);
+		if (mode == QDF_P2P_GO_MODE) {
+			p2p_vdev_obj->non_p2p_peer_count++;
+			p2p_debug("Non P2P peer count: %d",
+				  p2p_vdev_obj->non_p2p_peer_count);
+		}
+	}
+	p2p_debug("p2p peer object create successful");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_peer_obj_destroy_notification() - clears peer details per vdev
+ * @peer: peer object
+ * @arg: Pointer to private argument - NULL
+ *
+ * This function gets called from object manager when peer is being
+ * destroyed.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_peer_obj_destroy_notification(
+	struct wlan_objmgr_peer *peer, void *arg)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	struct wlan_objmgr_psoc *psoc;
+	enum QDF_OPMODE mode;
+	enum wlan_peer_type peer_type;
+	uint8_t vdev_id;
+
+	if (!peer) {
+		p2p_err("peer context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev = wlan_peer_get_vdev(peer);
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (mode != QDF_P2P_GO_MODE)
+		return QDF_STATUS_SUCCESS;
+
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+						WLAN_UMAC_COMP_P2P);
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!p2p_vdev_obj || !psoc) {
+		p2p_debug("p2p_vdev_obj:%pK psoc:%pK", p2p_vdev_obj, psoc);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+
+	peer_type = wlan_peer_get_peer_type(peer);
+
+	if ((peer_type == WLAN_PEER_STA) && (mode == QDF_P2P_GO_MODE)) {
+
+		p2p_vdev_obj->non_p2p_peer_count--;
+
+		if (!p2p_vdev_obj->non_p2p_peer_count &&
+		    (p2p_vdev_obj->noa_status == false)) {
+
+			vdev_id = wlan_vdev_get_id(vdev);
+
+			if (ucfg_p2p_set_noa(psoc, vdev_id,
+				 false)	== QDF_STATUS_SUCCESS)
+				p2p_vdev_obj->noa_status = true;
+			else
+				p2p_vdev_obj->noa_status = false;
+
+			p2p_debug("Non p2p peer disconnected from GO,NOA status: %d.",
+				p2p_vdev_obj->noa_status);
+		}
+		p2p_debug("Non P2P peer count: %d",
+			   p2p_vdev_obj->non_p2p_peer_count);
+	}
+	p2p_debug("p2p peer object destroy successful");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_send_noa_to_pe() - send noa information to pe
+ * @noa_info: vdev context
+ *
+ * This function sends noa information to pe since MCL layer need noa
+ * event.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_send_noa_to_pe(struct p2p_noa_info *noa_info)
+{
+	struct p2p_noa_attr *noa_attr;
+	struct scheduler_msg msg = {0};
+	QDF_STATUS status;
+
+	if (!noa_info) {
+		p2p_err("noa info is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	noa_attr = qdf_mem_malloc(sizeof(*noa_attr));
+	if (!noa_attr) {
+		p2p_err("Failed to allocate memory for tSirP2PNoaAttr");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	noa_attr->index = noa_info->index;
+	noa_attr->opps_ps = noa_info->opps_ps;
+	noa_attr->ct_win = noa_info->ct_window;
+	if (!noa_info->num_desc) {
+		p2p_debug("Zero noa descriptors");
+	} else {
+		p2p_debug("%d noa descriptors", noa_info->num_desc);
+
+		noa_attr->noa1_count =
+			noa_info->noa_desc[0].type_count;
+		noa_attr->noa1_duration =
+			noa_info->noa_desc[0].duration;
+		noa_attr->noa1_interval =
+			noa_info->noa_desc[0].interval;
+		noa_attr->noa1_start_time =
+			noa_info->noa_desc[0].start_time;
+		if (noa_info->num_desc > 1) {
+			noa_attr->noa2_count =
+				noa_info->noa_desc[1].type_count;
+			noa_attr->noa2_duration =
+				noa_info->noa_desc[1].duration;
+			noa_attr->noa2_interval =
+				noa_info->noa_desc[1].interval;
+			noa_attr->noa2_start_time =
+				noa_info->noa_desc[1].start_time;
+		}
+	}
+
+	p2p_debug("Sending P2P_NOA_ATTR_IND to pe");
+
+	msg.type = P2P_NOA_ATTR_IND;
+	msg.bodyval = 0;
+	msg.bodyptr = noa_attr;
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_PE,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(noa_attr);
+		p2p_err("post msg fail:%d", status);
+	}
+
+	return status;
+}
+
+/**
+ * process_peer_for_noa() - disable NoA
+ * @vdev: vdev object
+ * @psoc: soc object
+ * @peer: peer object
+ *
+ * This function disables NoA
+ *
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS process_peer_for_noa(struct wlan_objmgr_vdev *vdev,
+				struct wlan_objmgr_psoc *psoc,
+				struct wlan_objmgr_peer *peer)
+{
+	struct p2p_vdev_priv_obj *p2p_vdev_obj = NULL;
+	enum QDF_OPMODE mode;
+	enum wlan_peer_type peer_type;
+	bool disable_noa;
+	uint8_t vdev_id;
+
+	if (!vdev || !psoc || !peer) {
+		p2p_err("vdev:%pK psoc:%pK peer:%pK", vdev, psoc, peer);
+		return QDF_STATUS_E_INVAL;
+	}
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+						WLAN_UMAC_COMP_P2P);
+	if (!p2p_vdev_obj) {
+		p2p_err("p2p_vdev_obj:%pK", p2p_vdev_obj);
+		return QDF_STATUS_E_INVAL;
+	}
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+
+	peer_type = wlan_peer_get_peer_type(peer);
+
+	disable_noa = ((mode == QDF_P2P_GO_MODE)
+			&& p2p_vdev_obj->non_p2p_peer_count
+			&& p2p_vdev_obj->noa_status);
+
+	if (disable_noa && (peer_type == WLAN_PEER_STA)) {
+
+		vdev_id = wlan_vdev_get_id(vdev);
+
+		if (ucfg_p2p_set_noa(psoc, vdev_id,
+				true) == QDF_STATUS_SUCCESS) {
+			p2p_vdev_obj->noa_status = false;
+		} else {
+			p2p_vdev_obj->noa_status = true;
+		}
+		p2p_debug("NoA status: %d", p2p_vdev_obj->noa_status);
+	}
+	p2p_debug("process_peer_for_noa");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_object_init_params() - init parameters for p2p object
+ * @psoc:        pointer to psoc object
+ * @p2p_soc_obj: pointer to p2p psoc object
+ *
+ * This function init parameters for p2p object
+ */
+static QDF_STATUS p2p_object_init_params(
+	struct wlan_objmgr_psoc *psoc,
+	struct p2p_soc_priv_obj *p2p_soc_obj)
+{
+	if (!psoc || !p2p_soc_obj) {
+		p2p_err("invalid param");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj->param.go_keepalive_period =
+			cfg_get(psoc, CFG_GO_KEEP_ALIVE_PERIOD);
+	p2p_soc_obj->param.go_link_monitor_period =
+			cfg_get(psoc, CFG_GO_LINK_MONITOR_PERIOD);
+	p2p_soc_obj->param.p2p_device_addr_admin =
+			cfg_get(psoc, CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED);
+	p2p_soc_obj->param.skip_dfs_channel_p2p_search =
+			cfg_get(psoc, CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#ifdef WLAN_FEATURE_P2P_DEBUG
+/**
+ * wlan_p2p_init_connection_status() - init connection status
+ * @p2p_soc_obj: pointer to p2p psoc object
+ *
+ * This function initial p2p connection status.
+ *
+ * Return: None
+ */
+static void wlan_p2p_init_connection_status(
+		struct p2p_soc_priv_obj *p2p_soc_obj)
+{
+	if (!p2p_soc_obj) {
+		p2p_err("invalid p2p soc obj");
+		return;
+	}
+
+	p2p_soc_obj->connection_status = P2P_NOT_ACTIVE;
+}
+#else
+static void wlan_p2p_init_connection_status(
+		struct p2p_soc_priv_obj *p2p_soc_obj)
+{
+}
+#endif /* WLAN_FEATURE_P2P_DEBUG */
+
+QDF_STATUS p2p_component_init(void)
+{
+	QDF_STATUS status;
+
+	status = wlan_objmgr_register_psoc_create_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_psoc_obj_create_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to register p2p obj create handler");
+		goto err_reg_psoc_create;
+	}
+
+	status = wlan_objmgr_register_psoc_destroy_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_psoc_obj_destroy_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to register p2p obj delete handler");
+		goto err_reg_psoc_delete;
+	}
+
+	status = wlan_objmgr_register_vdev_create_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_vdev_obj_create_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to register p2p vdev create handler");
+		goto err_reg_vdev_create;
+	}
+
+	status = wlan_objmgr_register_vdev_destroy_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_vdev_obj_destroy_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to register p2p vdev delete handler");
+		goto err_reg_vdev_delete;
+	}
+
+	status = wlan_objmgr_register_peer_create_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_peer_obj_create_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to register p2p peer create handler");
+		goto err_reg_peer_create;
+	}
+
+	status = wlan_objmgr_register_peer_destroy_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_peer_obj_destroy_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to register p2p peer destroy handler");
+		goto err_reg_peer_destroy;
+	}
+
+	p2p_debug("Register p2p obj handler successful");
+
+	return QDF_STATUS_SUCCESS;
+err_reg_peer_destroy:
+	wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_P2P,
+			p2p_peer_obj_create_notification, NULL);
+err_reg_peer_create:
+	wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_P2P,
+			p2p_vdev_obj_destroy_notification, NULL);
+err_reg_vdev_delete:
+	wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_P2P,
+			p2p_vdev_obj_create_notification, NULL);
+err_reg_vdev_create:
+	wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_P2P,
+			p2p_psoc_obj_destroy_notification, NULL);
+err_reg_psoc_delete:
+	wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_P2P,
+			p2p_psoc_obj_create_notification, NULL);
+err_reg_psoc_create:
+	return status;
+}
+
+QDF_STATUS p2p_component_deinit(void)
+{
+	QDF_STATUS status;
+	QDF_STATUS ret_status = QDF_STATUS_SUCCESS;
+
+	status = wlan_objmgr_unregister_vdev_create_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_vdev_obj_create_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to unregister p2p vdev create handler, %d",
+			status);
+		ret_status = status;
+	}
+
+	status = wlan_objmgr_unregister_vdev_destroy_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_vdev_obj_destroy_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to unregister p2p vdev delete handler, %d",
+			status);
+		ret_status = status;
+	}
+
+	status = wlan_objmgr_unregister_psoc_create_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_psoc_obj_create_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to unregister p2p obj create handler, %d",
+			status);
+		ret_status = status;
+	}
+
+	status = wlan_objmgr_unregister_psoc_destroy_handler(
+				WLAN_UMAC_COMP_P2P,
+				p2p_psoc_obj_destroy_notification,
+				NULL);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to unregister p2p obj delete handler, %d",
+			status);
+		ret_status = status;
+	}
+
+	p2p_debug("Unregister p2p obj handler complete");
+
+	return ret_status;
+}
+
+QDF_STATUS p2p_psoc_object_open(struct wlan_objmgr_psoc *soc)
+{
+	QDF_STATUS status;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc priviate object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	p2p_object_init_params(soc, p2p_soc_obj);
+	qdf_list_create(&p2p_soc_obj->roc_q, MAX_QUEUE_LENGTH);
+	qdf_list_create(&p2p_soc_obj->tx_q_roc, MAX_QUEUE_LENGTH);
+	qdf_list_create(&p2p_soc_obj->tx_q_ack, MAX_QUEUE_LENGTH);
+
+	status = qdf_event_create(&p2p_soc_obj->cancel_roc_done);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to create cancel roc done event");
+		goto fail_cancel_roc;
+	}
+
+	status = qdf_event_create(&p2p_soc_obj->cleanup_roc_done);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to create cleanup roc done event");
+		goto fail_cleanup_roc;
+	}
+
+	status = qdf_event_create(&p2p_soc_obj->cleanup_tx_done);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to create cleanup roc done event");
+		goto fail_cleanup_tx;
+	}
+
+	qdf_runtime_lock_init(&p2p_soc_obj->roc_runtime_lock);
+	p2p_soc_obj->cur_roc_vdev_id = P2P_INVALID_VDEV_ID;
+	qdf_idr_create(&p2p_soc_obj->p2p_idr);
+
+	p2p_debug("p2p psoc object open successful");
+
+	return QDF_STATUS_SUCCESS;
+
+fail_cleanup_tx:
+	qdf_event_destroy(&p2p_soc_obj->cleanup_roc_done);
+
+fail_cleanup_roc:
+	qdf_event_destroy(&p2p_soc_obj->cancel_roc_done);
+
+fail_cancel_roc:
+	qdf_list_destroy(&p2p_soc_obj->tx_q_ack);
+	qdf_list_destroy(&p2p_soc_obj->tx_q_roc);
+	qdf_list_destroy(&p2p_soc_obj->roc_q);
+
+	return status;
+}
+
+QDF_STATUS p2p_psoc_object_close(struct wlan_objmgr_psoc *soc)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_idr_destroy(&p2p_soc_obj->p2p_idr);
+	qdf_runtime_lock_deinit(&p2p_soc_obj->roc_runtime_lock);
+	qdf_event_destroy(&p2p_soc_obj->cleanup_tx_done);
+	qdf_event_destroy(&p2p_soc_obj->cleanup_roc_done);
+	qdf_event_destroy(&p2p_soc_obj->cancel_roc_done);
+	qdf_list_destroy(&p2p_soc_obj->tx_q_ack);
+	qdf_list_destroy(&p2p_soc_obj->tx_q_roc);
+	qdf_list_destroy(&p2p_soc_obj->roc_q);
+
+	p2p_debug("p2p psoc object close successful");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+static inline void p2p_init_lo_event(struct p2p_start_param *start_param,
+				     struct p2p_start_param *req)
+{
+	start_param->lo_event_cb = req->lo_event_cb;
+	start_param->lo_event_cb_data = req->lo_event_cb_data;
+}
+#else
+static inline void p2p_init_lo_event(struct p2p_start_param *start_param,
+				     struct p2p_start_param *req)
+{
+}
+#endif
+
+QDF_STATUS p2p_psoc_start(struct wlan_objmgr_psoc *soc,
+	struct p2p_start_param *req)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_start_param *start_param;
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	start_param = qdf_mem_malloc(sizeof(*start_param));
+	if (!start_param) {
+		p2p_err("Failed to allocate start params");
+		return QDF_STATUS_E_NOMEM;
+	}
+	start_param->rx_cb = req->rx_cb;
+	start_param->rx_cb_data = req->rx_cb_data;
+	start_param->event_cb = req->event_cb;
+	start_param->event_cb_data = req->event_cb_data;
+	start_param->tx_cnf_cb = req->tx_cnf_cb;
+	start_param->tx_cnf_cb_data = req->tx_cnf_cb_data;
+	p2p_init_lo_event(start_param, req);
+	p2p_soc_obj->start_param = start_param;
+
+	wlan_p2p_init_connection_status(p2p_soc_obj);
+
+	/* register p2p lo stop and noa event */
+	tgt_p2p_register_lo_ev_handler(soc);
+	tgt_p2p_register_noa_ev_handler(soc);
+	tgt_p2p_register_macaddr_rx_filter_evt_handler(soc, true);
+
+	/* register scan request id */
+	p2p_soc_obj->scan_req_id = ucfg_scan_register_requester(
+		soc, P2P_MODULE_NAME, tgt_p2p_scan_event_cb,
+		p2p_soc_obj);
+
+	/* register rx action frame */
+	p2p_mgmt_rx_action_ops(soc, true);
+
+	p2p_debug("p2p psoc start successful, scan request id:%d",
+		p2p_soc_obj->scan_req_id);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_psoc_stop(struct wlan_objmgr_psoc *soc)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_start_param *start_param;
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	start_param = p2p_soc_obj->start_param;
+	p2p_soc_obj->start_param = NULL;
+	if (!start_param) {
+		p2p_err("start parameters is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* unregister rx action frame */
+	p2p_mgmt_rx_action_ops(soc, false);
+
+	/* clean up queue of p2p psoc private object */
+	p2p_cleanup_tx_sync(p2p_soc_obj, NULL);
+	p2p_cleanup_roc_sync(p2p_soc_obj, NULL);
+
+	/* unrgister scan request id*/
+	ucfg_scan_unregister_requester(soc, p2p_soc_obj->scan_req_id);
+
+	/* unregister p2p lo stop and noa event */
+	tgt_p2p_register_macaddr_rx_filter_evt_handler(soc, false);
+	tgt_p2p_unregister_lo_ev_handler(soc);
+	tgt_p2p_unregister_noa_ev_handler(soc);
+
+	start_param->rx_cb = NULL;
+	start_param->rx_cb_data = NULL;
+	start_param->event_cb = NULL;
+	start_param->event_cb_data = NULL;
+	start_param->tx_cnf_cb = NULL;
+	start_param->tx_cnf_cb_data = NULL;
+	qdf_mem_free(start_param);
+
+	p2p_debug("p2p psoc stop successful");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg)
+{
+	QDF_STATUS status;
+
+	p2p_debug("msg type %d, %s", msg->type,
+		p2p_get_cmd_type_str(msg->type));
+
+	if (!(msg->bodyptr)) {
+		p2p_err("Invalid message body");
+		return QDF_STATUS_E_INVAL;
+	}
+	switch (msg->type) {
+	case P2P_ROC_REQ:
+		status = p2p_process_roc_req(
+				(struct p2p_roc_context *)
+				msg->bodyptr);
+		break;
+	case P2P_CANCEL_ROC_REQ:
+		status = p2p_process_cancel_roc_req(
+				(struct cancel_roc_context *)
+				msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
+	case P2P_MGMT_TX:
+		status = p2p_process_mgmt_tx(
+				(struct tx_action_context *)
+				msg->bodyptr);
+		break;
+	case P2P_MGMT_TX_CANCEL:
+		status = p2p_process_mgmt_tx_cancel(
+				(struct cancel_roc_context *)
+				msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
+	case P2P_CLEANUP_ROC:
+		status = p2p_process_cleanup_roc_queue(
+				(struct p2p_cleanup_param *)
+				msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
+	case P2P_CLEANUP_TX:
+		status = p2p_process_cleanup_tx_queue(
+				(struct p2p_cleanup_param *)
+				msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
+	case P2P_SET_RANDOM_MAC:
+		status = p2p_process_set_rand_mac(msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
+
+	default:
+		p2p_err("drop unexpected message received %d",
+			msg->type);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+}
+
+QDF_STATUS p2p_process_evt(struct scheduler_msg *msg)
+{
+	QDF_STATUS status;
+
+	p2p_debug("msg type %d, %s", msg->type,
+		p2p_get_event_type_str(msg->type));
+
+	if (!(msg->bodyptr)) {
+		p2p_err("Invalid message body");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	switch (msg->type) {
+	case P2P_EVENT_MGMT_TX_ACK_CNF:
+		status = p2p_process_mgmt_tx_ack_cnf(
+				(struct p2p_tx_conf_event *)
+				msg->bodyptr);
+		break;
+	case P2P_EVENT_RX_MGMT:
+		status  = p2p_process_rx_mgmt(
+				(struct p2p_rx_mgmt_event *)
+				msg->bodyptr);
+		break;
+	case P2P_EVENT_LO_STOPPED:
+		status = p2p_process_lo_stop(
+				(struct p2p_lo_stop_event *)
+				msg->bodyptr);
+		break;
+	case P2P_EVENT_NOA:
+		status = p2p_process_noa(
+				(struct p2p_noa_event *)
+				msg->bodyptr);
+		break;
+	case P2P_EVENT_ADD_MAC_RSP:
+		status = p2p_process_set_rand_mac_rsp(
+				(struct p2p_mac_filter_rsp *)
+				msg->bodyptr);
+		break;
+	default:
+		p2p_err("Drop unexpected message received %d",
+			msg->type);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	qdf_mem_free(msg->bodyptr);
+	msg->bodyptr = NULL;
+
+	return status;
+}
+
+QDF_STATUS p2p_msg_flush_callback(struct scheduler_msg *msg)
+{
+	struct tx_action_context *tx_action;
+
+	if (!msg || !(msg->bodyptr)) {
+		p2p_err("invalid msg");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_debug("flush msg, type:%d", msg->type);
+	switch (msg->type) {
+	case P2P_MGMT_TX:
+		tx_action = (struct tx_action_context *)msg->bodyptr;
+		qdf_mem_free(tx_action->buf);
+		qdf_mem_free(tx_action);
+		break;
+	default:
+		qdf_mem_free(msg->bodyptr);
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_event_flush_callback(struct scheduler_msg *msg)
+{
+	struct p2p_noa_event *noa_event;
+	struct p2p_rx_mgmt_event *rx_mgmt_event;
+	struct p2p_tx_conf_event *tx_conf_event;
+	struct p2p_lo_stop_event *lo_stop_event;
+
+	if (!msg || !(msg->bodyptr)) {
+		p2p_err("invalid msg");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_debug("flush event, type:%d", msg->type);
+	switch (msg->type) {
+	case P2P_EVENT_NOA:
+		noa_event = (struct p2p_noa_event *)msg->bodyptr;
+		qdf_mem_free(noa_event->noa_info);
+		qdf_mem_free(noa_event);
+		break;
+	case P2P_EVENT_RX_MGMT:
+		rx_mgmt_event = (struct p2p_rx_mgmt_event *)msg->bodyptr;
+		qdf_mem_free(rx_mgmt_event->rx_mgmt);
+		qdf_mem_free(rx_mgmt_event);
+		break;
+	case P2P_EVENT_MGMT_TX_ACK_CNF:
+		tx_conf_event = (struct p2p_tx_conf_event *)msg->bodyptr;
+		qdf_mem_free(tx_conf_event);
+		qdf_nbuf_free(tx_conf_event->nbuf);
+		break;
+	case P2P_EVENT_LO_STOPPED:
+		lo_stop_event = (struct p2p_lo_stop_event *)msg->bodyptr;
+		qdf_mem_free(lo_stop_event->lo_event);
+		qdf_mem_free(lo_stop_event);
+		break;
+	default:
+		qdf_mem_free(msg->bodyptr);
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+QDF_STATUS p2p_process_lo_stop(
+	struct p2p_lo_stop_event *lo_stop_event)
+{
+	struct p2p_lo_event *lo_evt;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_start_param *start_param;
+
+	if (!lo_stop_event) {
+		p2p_err("invalid lo stop event");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	lo_evt = lo_stop_event->lo_event;
+	if (!lo_evt) {
+		p2p_err("invalid lo event");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = lo_stop_event->p2p_soc_obj;
+
+	p2p_debug("vdev_id %d, reason %d",
+		lo_evt->vdev_id, lo_evt->reason_code);
+
+	if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) {
+		p2p_err("Invalid p2p soc object or start parameters");
+		qdf_mem_free(lo_evt);
+		return QDF_STATUS_E_INVAL;
+	}
+	start_param = p2p_soc_obj->start_param;
+	if (start_param->lo_event_cb)
+		start_param->lo_event_cb(
+			start_param->lo_event_cb_data, lo_evt);
+	else
+		p2p_err("Invalid p2p soc obj or hdd lo event callback");
+
+	qdf_mem_free(lo_evt);
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+QDF_STATUS p2p_process_noa(struct p2p_noa_event *noa_event)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct p2p_noa_info *noa_info;
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	enum QDF_OPMODE mode;
+
+	if (!noa_event) {
+		p2p_err("invalid noa event");
+		return QDF_STATUS_E_INVAL;
+	}
+	noa_info = noa_event->noa_info;
+	p2p_soc_obj = noa_event->p2p_soc_obj;
+	psoc = p2p_soc_obj->soc;
+
+	p2p_debug("psoc:%pK, index:%d, opps_ps:%d, ct_window:%d, num_desc:%d, vdev_id:%d",
+		psoc, noa_info->index, noa_info->opps_ps,
+		noa_info->ct_window, noa_info->num_desc,
+		noa_info->vdev_id);
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+			noa_info->vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_err("vdev obj is NULL");
+		qdf_mem_free(noa_event->noa_info);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	p2p_debug("vdev mode:%d", mode);
+	if (mode != QDF_P2P_GO_MODE) {
+		p2p_err("invalid p2p vdev mode:%d", mode);
+		status = QDF_STATUS_E_INVAL;
+		goto fail;
+	}
+
+	/* must send noa to pe since of limitation*/
+	p2p_send_noa_to_pe(noa_info);
+
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+			WLAN_UMAC_COMP_P2P);
+	if (!(p2p_vdev_obj->noa_info)) {
+		p2p_vdev_obj->noa_info =
+			qdf_mem_malloc(sizeof(struct p2p_noa_info));
+		if (!(p2p_vdev_obj->noa_info)) {
+			p2p_err("Failed to allocate p2p noa info");
+			status = QDF_STATUS_E_NOMEM;
+			goto fail;
+		}
+	}
+	qdf_mem_copy(p2p_vdev_obj->noa_info, noa_info,
+		sizeof(struct p2p_noa_info));
+fail:
+	qdf_mem_free(noa_event->noa_info);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return status;
+}
+
+void p2p_peer_authorized(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr)
+{
+	QDF_STATUS status;
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_peer *peer;
+	uint8_t pdev_id;
+
+	if (!vdev) {
+		p2p_err("vdev:%pK", vdev);
+		return;
+	}
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		p2p_err("psoc:%pK", psoc);
+		return;
+	}
+	pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev));
+	peer = wlan_objmgr_get_peer(psoc, pdev_id,  mac_addr, WLAN_P2P_ID);
+	if (!peer) {
+		p2p_debug("peer info not found");
+		return;
+	}
+	status = process_peer_for_noa(vdev, psoc, peer);
+	wlan_objmgr_peer_release_ref(peer, WLAN_P2P_ID);
+
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("status:%u", status);
+		return;
+	}
+	p2p_debug("peer is authorized");
+}
+
+#ifdef WLAN_FEATURE_P2P_DEBUG
+static struct p2p_soc_priv_obj *
+get_p2p_soc_obj_by_vdev(struct wlan_objmgr_vdev *vdev)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct wlan_objmgr_psoc *soc;
+
+	if (!vdev) {
+		p2p_err("vdev context passed is NULL");
+		return NULL;
+	}
+
+	soc = wlan_vdev_get_psoc(vdev);
+	if (!soc) {
+		p2p_err("soc context is NULL");
+		return NULL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj)
+		p2p_err("P2P soc context is NULL");
+
+	return p2p_soc_obj;
+}
+
+QDF_STATUS p2p_status_scan(struct wlan_objmgr_vdev *vdev)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	enum QDF_OPMODE mode;
+
+	p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (mode != QDF_P2P_CLIENT_MODE &&
+	    mode != QDF_P2P_DEVICE_MODE) {
+		p2p_debug("this is not P2P CLIENT or DEVICE, mode:%d",
+			mode);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	p2p_debug("connection status:%d", p2p_soc_obj->connection_status);
+	switch (p2p_soc_obj->connection_status) {
+	case P2P_GO_NEG_COMPLETED:
+	case P2P_GO_NEG_PROCESS:
+		p2p_soc_obj->connection_status =
+				P2P_CLIENT_CONNECTING_STATE_1;
+		p2p_debug("[P2P State] Changing state from Go nego completed to Connection is started");
+		p2p_debug("P2P Scanning is started for 8way Handshake");
+		break;
+	case P2P_CLIENT_DISCONNECTED_STATE:
+		p2p_soc_obj->connection_status =
+				P2P_CLIENT_CONNECTING_STATE_2;
+		p2p_debug("[P2P State] Changing state from Disconnected state to Connection is started");
+		p2p_debug("P2P Scanning is started for 4way Handshake");
+		break;
+	default:
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_status_connect(struct wlan_objmgr_vdev *vdev)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	enum QDF_OPMODE mode;
+
+	p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (mode != QDF_P2P_CLIENT_MODE) {
+		p2p_debug("this is not P2P CLIENT, mode:%d", mode);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	p2p_debug("connection status:%d", p2p_soc_obj->connection_status);
+	switch (p2p_soc_obj->connection_status) {
+	case P2P_CLIENT_CONNECTING_STATE_1:
+		p2p_soc_obj->connection_status =
+				P2P_CLIENT_CONNECTED_STATE_1;
+		p2p_debug("[P2P State] Changing state from Connecting state to Connected State for 8-way Handshake");
+		break;
+	case P2P_CLIENT_DISCONNECTED_STATE:
+		p2p_debug("No scan before 4-way handshake");
+		/*
+		 * Fall thru since no scan before 4-way handshake and
+		 * won't enter state P2P_CLIENT_CONNECTING_STATE_2:
+		 */
+	case P2P_CLIENT_CONNECTING_STATE_2:
+		p2p_soc_obj->connection_status =
+				P2P_CLIENT_COMPLETED_STATE;
+		p2p_debug("[P2P State] Changing state from Connecting state to P2P Client Connection Completed");
+		break;
+	default:
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_status_disconnect(struct wlan_objmgr_vdev *vdev)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	enum QDF_OPMODE mode;
+
+	p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (mode != QDF_P2P_CLIENT_MODE) {
+		p2p_debug("this is not P2P CLIENT, mode:%d", mode);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	p2p_debug("connection status:%d", p2p_soc_obj->connection_status);
+	switch (p2p_soc_obj->connection_status) {
+	case P2P_CLIENT_CONNECTED_STATE_1:
+		p2p_soc_obj->connection_status =
+				P2P_CLIENT_DISCONNECTED_STATE;
+		p2p_debug("[P2P State] 8 way Handshake completed and moved to disconnected state");
+		break;
+	case P2P_CLIENT_COMPLETED_STATE:
+		p2p_soc_obj->connection_status = P2P_NOT_ACTIVE;
+		p2p_debug("[P2P State] P2P Client is removed and moved to inactive state");
+		break;
+	default:
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_status_start_bss(struct wlan_objmgr_vdev *vdev)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	enum QDF_OPMODE mode;
+
+	p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (mode != QDF_P2P_GO_MODE) {
+		p2p_debug("this is not P2P GO, mode:%d", mode);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	p2p_debug("connection status:%d", p2p_soc_obj->connection_status);
+	switch (p2p_soc_obj->connection_status) {
+	case P2P_GO_NEG_COMPLETED:
+		p2p_soc_obj->connection_status =
+				P2P_GO_COMPLETED_STATE;
+		p2p_debug("[P2P State] From Go nego completed to Non-autonomous Group started");
+		break;
+	case P2P_NOT_ACTIVE:
+		p2p_soc_obj->connection_status =
+				P2P_GO_COMPLETED_STATE;
+		p2p_debug("[P2P State] From Inactive to Autonomous Group started");
+		break;
+	default:
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	enum QDF_OPMODE mode;
+
+	p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (mode != QDF_P2P_GO_MODE) {
+		p2p_debug("this is not P2P GO, mode:%d", mode);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	p2p_debug("connection status:%d", p2p_soc_obj->connection_status);
+	if (p2p_soc_obj->connection_status == P2P_GO_COMPLETED_STATE) {
+		p2p_soc_obj->connection_status = P2P_NOT_ACTIVE;
+		p2p_debug("[P2P State] From GO completed to Inactive state GO got removed");
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_FEATURE_P2P_DEBUG */

+ 574 - 0
components/p2p/core/src/wlan_p2p_main.h

@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: Defines main P2P functions & structures
+ */
+
+#ifndef _WLAN_P2P_MAIN_H_
+#define _WLAN_P2P_MAIN_H_
+
+#include <qdf_trace.h>
+#include <qdf_types.h>
+#include <qdf_event.h>
+#include <qdf_list.h>
+#include <qdf_lock.h>
+#include <qdf_idr.h>
+
+#define MAX_QUEUE_LENGTH 20
+#define P2P_NOA_ATTR_IND 0x1090
+#define P2P_MODULE_NAME  "P2P"
+#define P2P_INVALID_VDEV_ID 0xFFFFFFFF
+#define MAX_RANDOM_MAC_ADDRS 4
+
+#define p2p_debug(params ...) \
+	QDF_TRACE_DEBUG(QDF_MODULE_ID_P2P, params)
+#define p2p_info(params ...) \
+	QDF_TRACE_INFO(QDF_MODULE_ID_P2P, params)
+#define p2p_warn(params ...) \
+	QDF_TRACE_WARN(QDF_MODULE_ID_P2P, params)
+#define p2p_err(params ...) \
+	QDF_TRACE_ERROR(QDF_MODULE_ID_P2P, params)
+#define p2p_alert(params ...) \
+	QDF_TRACE_FATAL(QDF_MODULE_ID_P2P, params)
+
+#define p2p_nofl_debug(params ...) \
+	QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_P2P, params)
+#define p2p_nofl_info(params ...) \
+	QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_P2P, params)
+#define p2p_nofl_warn(params ...) \
+	QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_P2P, params)
+#define p2p_nofl_err(params ...) \
+	QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_P2P, params)
+#define p2p_nofl_alert(params ...) \
+	QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_P2P, params)
+
+struct scheduler_msg;
+struct p2p_tx_cnf;
+struct p2p_rx_mgmt_frame;
+struct p2p_lo_event;
+struct p2p_start_param;
+struct p2p_noa_info;
+struct tx_action_context;
+
+/**
+ * enum p2p_cmd_type - P2P request type
+ * @P2P_ROC_REQ:            P2P roc request
+ * @P2P_CANCEL_ROC_REQ:     Cancel P2P roc request
+ * @P2P_MGMT_TX:            P2P tx action frame request
+ * @P2P_MGMT_TX_CANCEL:     Cancel tx action frame request
+ * @P2P_CLEANUP_ROC:        Cleanup roc queue
+ * @P2P_CLEANUP_TX:         Cleanup tx mgmt queue
+ * @P2P_SET_RANDOM_MAC: Set Random MAC addr filter request
+ */
+enum p2p_cmd_type {
+	P2P_ROC_REQ = 0,
+	P2P_CANCEL_ROC_REQ,
+	P2P_MGMT_TX,
+	P2P_MGMT_TX_CANCEL,
+	P2P_CLEANUP_ROC,
+	P2P_CLEANUP_TX,
+	P2P_SET_RANDOM_MAC,
+};
+
+/**
+ * enum p2p_event_type - P2P event type
+ * @P2P_EVENT_SCAN_EVENT:        P2P scan event
+ * @P2P_EVENT_MGMT_TX_ACK_CNF:   P2P mgmt tx confirm frame
+ * @P2P_EVENT_RX_MGMT:           P2P rx mgmt frame
+ * @P2P_EVENT_LO_STOPPED:        P2P listen offload stopped event
+ * @P2P_EVENT_NOA:               P2P noa event
+ * @P2P_EVENT_ADD_MAC_RSP: Set Random MAC addr event
+ */
+enum p2p_event_type {
+	P2P_EVENT_SCAN_EVENT = 0,
+	P2P_EVENT_MGMT_TX_ACK_CNF,
+	P2P_EVENT_RX_MGMT,
+	P2P_EVENT_LO_STOPPED,
+	P2P_EVENT_NOA,
+	P2P_EVENT_ADD_MAC_RSP,
+};
+
+/**
+ * struct p2p_tx_conf_event - p2p tx confirm event
+ * @p2p_soc_obj:        p2p soc private object
+ * @buf:                buffer address
+ * @status:             tx status
+ */
+struct p2p_tx_conf_event {
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	qdf_nbuf_t nbuf;
+	uint32_t status;
+};
+
+/**
+ * struct p2p_rx_mgmt_event - p2p rx mgmt frame event
+ * @p2p_soc_obj:        p2p soc private object
+ * @rx_mgmt:            p2p rx mgmt frame structure
+ */
+struct p2p_rx_mgmt_event {
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_rx_mgmt_frame *rx_mgmt;
+};
+
+/**
+ * struct p2p_lo_stop_event - p2p listen offload stop event
+ * @p2p_soc_obj:        p2p soc private object
+ * @lo_event:           p2p lo stop structure
+ */
+struct p2p_lo_stop_event {
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_lo_event *lo_event;
+};
+
+/**
+ * struct p2p_noa_event - p2p noa event
+ * @p2p_soc_obj:        p2p soc private object
+ * @noa_info:           p2p noa information structure
+ */
+struct p2p_noa_event {
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_noa_info *noa_info;
+};
+
+/**
+ * struct p2p_mac_filter_rsp - p2p set mac filter respone
+ * @p2p_soc_obj: p2p soc private object
+ * @vdev_id: vdev id
+ * @status: successfully(1) or not (0)
+ */
+struct p2p_mac_filter_rsp {
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	uint32_t vdev_id;
+	uint32_t status;
+};
+
+#ifdef WLAN_FEATURE_P2P_DEBUG
+/**
+ * enum p2p_connection_status - p2p connection status
+ * @P2P_NOT_ACTIVE:                P2P not active status
+ * @P2P_GO_NEG_PROCESS:            P2P GO negotiation in process
+ * @P2P_GO_NEG_COMPLETED:          P2P GO negotiation complete
+ * @P2P_CLIENT_CONNECTING_STATE_1: P2P client connecting state 1
+ * @P2P_GO_COMPLETED_STATE:        P2P GO complete state
+ * @P2P_CLIENT_CONNECTED_STATE_1:  P2P client connected state 1
+ * @P2P_CLIENT_DISCONNECTED_STATE: P2P client disconnected state
+ * @P2P_CLIENT_CONNECTING_STATE_2: P2P client connecting state 2
+ * @P2P_CLIENT_COMPLETED_STATE:    P2P client complete state
+ */
+enum p2p_connection_status {
+	P2P_NOT_ACTIVE,
+	P2P_GO_NEG_PROCESS,
+	P2P_GO_NEG_COMPLETED,
+	P2P_CLIENT_CONNECTING_STATE_1,
+	P2P_GO_COMPLETED_STATE,
+	P2P_CLIENT_CONNECTED_STATE_1,
+	P2P_CLIENT_DISCONNECTED_STATE,
+	P2P_CLIENT_CONNECTING_STATE_2,
+	P2P_CLIENT_COMPLETED_STATE
+};
+#endif
+
+/**
+ * struct p2p_param - p2p parameters to be used
+ * @go_keepalive_period:            P2P GO keep alive period
+ * @go_link_monitor_period:         period where link is idle and
+ *                                  where we send NULL frame
+ * @p2p_device_addr_admin:          enable/disable to derive the P2P
+ *                                  MAC address from the primary MAC address
+ * @skip_dfs_channel_p2p_search:    kip DFS Channel in case of P2P Search
+ * @ignore_dynamic_dtim_in_p2p_mode:Ignore Dynamic Dtim in case of P2P options
+ */
+struct p2p_param {
+	uint32_t go_keepalive_period;
+	uint32_t go_link_monitor_period;
+	bool p2p_device_addr_admin;
+	bool skip_dfs_channel_p2p_search;
+	bool ignore_dynamic_dtim_in_p2p_mode;
+};
+
+/**
+ * struct p2p_soc_priv_obj - Per SoC p2p private object
+ * @soc:              Pointer to SoC context
+ * @roc_q:            Queue for pending roc requests
+ * @tx_q_roc:         Queue for tx frames waiting for RoC
+ * @tx_q_ack:         Queue for tx frames waiting for ack
+ * @scan_req_id:      Scan requestor id
+ * @start_param:      Start parameters, include callbacks and user
+ *                    data to HDD
+ * @cancel_roc_done:  Cancel roc done event
+ * @cleanup_roc_done: Cleanup roc done event
+ * @cleanup_tx_done:  Cleanup tx done event
+ * @roc_runtime_lock: Runtime lock for roc request
+ * @p2p_cb: Callbacks to protocol stack
+ * @cur_roc_vdev_id:  Vdev id of current roc
+ * @p2p_idr:          p2p idr
+ * @param:            p2p parameters to be used
+ * @connection_status:Global P2P connection status
+ */
+struct p2p_soc_priv_obj {
+	struct wlan_objmgr_psoc *soc;
+	qdf_list_t roc_q;
+	qdf_list_t tx_q_roc;
+	qdf_list_t tx_q_ack;
+	wlan_scan_requester scan_req_id;
+	struct p2p_start_param *start_param;
+	qdf_event_t cancel_roc_done;
+	qdf_event_t cleanup_roc_done;
+	qdf_event_t cleanup_tx_done;
+	qdf_runtime_lock_t roc_runtime_lock;
+	struct p2p_protocol_callbacks p2p_cb;
+	uint32_t cur_roc_vdev_id;
+	qdf_idr p2p_idr;
+	struct p2p_param param;
+#ifdef WLAN_FEATURE_P2P_DEBUG
+	enum p2p_connection_status connection_status;
+#endif
+};
+
+/**
+ * struct action_frame_cookie - Action frame cookie item in cookie list
+ * @cookie_node: qdf_list_node
+ * @cookie: Cookie value
+ */
+struct action_frame_cookie {
+	qdf_list_node_t cookie_node;
+	uint64_t cookie;
+};
+
+/**
+ * struct action_frame_random_mac - Action Frame random mac addr &
+ * related attrs
+ * @p2p_vdev_obj: p2p vdev private obj ptr
+ * @in_use: Checks whether random mac is in use
+ * @addr: Contains random mac addr
+ * @freq: Channel frequency
+ * @clear_timer: timer to clear random mac filter
+ * @cookie_list: List of cookies tied with random mac
+ */
+struct action_frame_random_mac {
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	bool in_use;
+	uint8_t addr[QDF_MAC_ADDR_SIZE];
+	uint32_t freq;
+	qdf_mc_timer_t clear_timer;
+	qdf_list_t cookie_list;
+};
+
+/**
+ * p2p_request_mgr_callback_t() - callback to process set mac filter result
+ * @result: bool
+ * @context: callback context.
+ *
+ * Return: void
+ */
+typedef void (*p2p_request_mgr_callback_t)(bool result, void *context);
+
+/**
+ * struct random_mac_priv - request private data struct
+ * @result: result of request.
+ */
+struct random_mac_priv {
+	bool result;
+};
+
+/**
+ * struct p2p_set_mac_filter_req - set mac addr filter cmd data structure
+ * @soc: soc object
+ * @vdev_id: vdev id
+ * @mac: mac address to be set
+ * @freq: frequency
+ * @set: set or clear
+ * @cb: callback func to be called when the request completion
+ * @req_cookie: cookie to be used when request completed
+ */
+struct p2p_set_mac_filter_req {
+	struct wlan_objmgr_psoc *soc;
+	uint32_t vdev_id;
+	uint8_t mac[QDF_MAC_ADDR_SIZE];
+	uint32_t freq;
+	bool set;
+	p2p_request_mgr_callback_t cb;
+	void *req_cookie;
+};
+
+/**
+ * struct p2p_vdev_priv_obj - Per vdev p2p private object
+ * @vdev:               Pointer to vdev context
+ * @noa_info:           NoA information
+ * @noa_status:         NoA status i.e. Enabled / Disabled (TRUE/FALSE)
+ * @non_p2p_peer_count: Number of legacy stations connected to this GO
+ * @random_mac_lock:    lock for random_mac list
+ * @random_mac:         active random mac filter lists
+ * @pending_req:        pending set mac filter request.
+ */
+struct p2p_vdev_priv_obj {
+	struct   wlan_objmgr_vdev *vdev;
+	struct   p2p_noa_info *noa_info;
+	bool     noa_status;
+	uint16_t non_p2p_peer_count;
+
+	/* random address management for management action frames */
+	qdf_spinlock_t random_mac_lock;
+	struct action_frame_random_mac random_mac[MAX_RANDOM_MAC_ADDRS];
+	struct p2p_set_mac_filter_req pending_req;
+};
+
+/**
+ * struct p2p_noa_attr - p2p noa attribute
+ * @rsvd1:             reserved bits 1
+ * @opps_ps:           opps ps state of the AP
+ * @ct_win:            ct window in TUs
+ * @index:             identifies instance of NOA su element
+ * @rsvd2:             reserved bits 2
+ * @noa1_count:        interval count of noa1
+ * @noa1_duration:     absent period duration of noa1
+ * @noa1_interval:     absent period interval of noa1
+ * @noa1_start_time:   32 bit tsf time of noa1
+ * @rsvd3:             reserved bits 3
+ * @noa2_count:        interval count of noa2
+ * @noa2_duration:     absent period duration of noa2
+ * @noa2_interval:     absent period interval of noa2
+ * @noa2_start_time:   32 bit tsf time of noa2
+ */
+struct p2p_noa_attr {
+	uint32_t rsvd1:16;
+	uint32_t ct_win:7;
+	uint32_t opps_ps:1;
+	uint32_t index:8;
+	uint32_t rsvd2:24;
+	uint32_t noa1_count:8;
+	uint32_t noa1_duration;
+	uint32_t noa1_interval;
+	uint32_t noa1_start_time;
+	uint32_t rsvd3:24;
+	uint32_t noa2_count:8;
+	uint32_t noa2_duration;
+	uint32_t noa2_interval;
+	uint32_t noa2_start_time;
+};
+
+/**
+ * p2p_component_init() - P2P component initialization
+ *
+ * This function registers psoc/vdev create/delete handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_component_init(void);
+
+/**
+ * p2p_component_deinit() - P2P component de-init
+ *
+ * This function deregisters psoc/vdev create/delete handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_component_deinit(void);
+
+/**
+ * p2p_psoc_object_open() - Open P2P component
+ * @soc: soc context
+ *
+ * This function initialize p2p psoc object
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_psoc_object_open(struct wlan_objmgr_psoc *soc);
+
+/**
+ * p2p_psoc_object_close() - Close P2P component
+ * @soc: soc context
+ *
+ * This function de-init p2p psoc object.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_psoc_object_close(struct wlan_objmgr_psoc *soc);
+
+/**
+ * p2p_psoc_start() - Start P2P component
+ * @soc: soc context
+ * @req: P2P start parameters
+ *
+ * This function sets up layer call back in p2p psoc object
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_psoc_start(struct wlan_objmgr_psoc *soc,
+	struct p2p_start_param *req);
+
+/**
+ * p2p_psoc_stop() - Stop P2P component
+ * @soc: soc context
+ *
+ * This function clears up layer call back in p2p psoc object.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_psoc_stop(struct wlan_objmgr_psoc *soc);
+
+/**
+ * p2p_process_cmd() - Process P2P messages in OS interface queue
+ * @msg: message information
+ *
+ * This function is main handler for P2P messages in OS interface
+ * queue, it gets called by message scheduler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg);
+
+/**
+ * p2p_process_evt() - Process P2P messages in target interface queue
+ * @msg: message information
+ *
+ * This function is main handler for P2P messages in target interface
+ * queue, it gets called by message scheduler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_evt(struct scheduler_msg *msg);
+
+/**
+ * p2p_msg_flush_callback() - Callback used to flush P2P messages
+ * @msg: message information
+ *
+ * This callback will be called when scheduler flush some of P2P messages.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_msg_flush_callback(struct scheduler_msg *msg);
+
+/**
+ * p2p_event_flush_callback() - Callback used to flush P2P events
+ * @msg: event information
+ *
+ * This callback will be called when scheduler flush some of P2P events.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_event_flush_callback(struct scheduler_msg *msg);
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+/**
+ * p2p_process_lo_stop() - Process lo stop event
+ * @lo_stop_event: listen offload stop event information
+ *
+ * This function handles listen offload stop event and deliver this
+ * event to HDD layer by registered callback.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_lo_stop(
+	struct p2p_lo_stop_event *lo_stop_event);
+#else
+static inline QDF_STATUS p2p_process_lo_stop(
+	struct p2p_lo_stop_event *lo_stop_event)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+/**
+ * p2p_process_noa() - Process noa event
+ * @noa_event: noa event information
+ *
+ * This function handles noa event and save noa information in p2p
+ * vdev object.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_noa(struct p2p_noa_event *noa_event);
+
+#ifdef WLAN_FEATURE_P2P_DEBUG
+/**
+ * p2p_status_scan() - Update P2P connection status
+ * @vdev: vdev context
+ *
+ * This function updates P2P connection status when scanning
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_status_scan(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * p2p_status_connect() - Update P2P connection status
+ * @vdev:        vdev context
+ *
+ * This function updates P2P connection status when connecting.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_status_connect(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * p2p_status_disconnect() - Update P2P connection status
+ * @vdev:        vdev context
+ *
+ * This function updates P2P connection status when disconnecting.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_status_disconnect(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * p2p_status_start_bss() - Update P2P connection status
+ * @vdev:        vdev context
+ *
+ * This function updates P2P connection status when starting BSS.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_status_start_bss(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * p2p_status_stop_bss() - Update P2P connection status
+ * @vdev:        vdev context
+ *
+ * This function updates P2P connection status when stopping BSS.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev);
+#else
+static inline QDF_STATUS p2p_status_scan(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS p2p_status_connect(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS p2p_status_disconnect(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS p2p_status_start_bss(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_FEATURE_P2P_DEBUG */
+#endif /* _WLAN_P2P_MAIN_H_ */

+ 2955 - 0
components/p2p/core/src/wlan_p2p_off_chan_tx.c

@@ -0,0 +1,2955 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: This file contains off channel tx API definitions
+ */
+
+#include <wmi_unified_api.h>
+#include <wlan_mgmt_txrx_utils_api.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_peer_obj.h>
+#include <wlan_utility.h>
+#include <scheduler_api.h>
+#include "wlan_p2p_public_struct.h"
+#include "wlan_p2p_tgt_api.h"
+#include "wlan_p2p_ucfg_api.h"
+#include "wlan_p2p_roc.h"
+#include "wlan_p2p_main.h"
+#include "wlan_p2p_off_chan_tx.h"
+#include "wlan_osif_request_manager.h"
+
+/**
+ * p2p_psoc_get_tx_ops() - get p2p tx ops
+ * @psoc:        psoc object
+ *
+ * This function returns p2p tx ops callbacks.
+ *
+ * Return: wlan_lmac_if_p2p_tx_ops
+ */
+static inline struct wlan_lmac_if_p2p_tx_ops *
+p2p_psoc_get_tx_ops(struct wlan_objmgr_psoc *psoc)
+{
+	return &psoc->soc_cb.tx_ops.p2p;
+}
+
+/**
+ * p2p_tx_context_check_valid() - check tx action context
+ * @tx_ctx:         tx context
+ *
+ * This function check if tx action context and parameters are valid.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_tx_context_check_valid(struct tx_action_context *tx_ctx)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	if (!tx_ctx) {
+		p2p_err("null tx action context");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = tx_ctx->p2p_soc_obj;
+	if (!p2p_soc_obj) {
+		p2p_err("null p2p soc private object");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = p2p_soc_obj->soc;
+	if (!psoc) {
+		p2p_err("null p2p soc object");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!tx_ctx->buf) {
+		p2p_err("null tx buffer");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_vdev_check_valid() - check vdev and vdev mode
+ * @tx_ctx:         tx context
+ *
+ * This function check if vdev and vdev mode are valid. It will drop
+ * probe response in sta mode.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_vdev_check_valid(struct tx_action_context *tx_ctx)
+{
+	enum QDF_OPMODE mode;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	p2p_soc_obj = tx_ctx->p2p_soc_obj;
+	psoc = p2p_soc_obj->soc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+			tx_ctx->vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_err("null vdev object");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	p2p_debug("vdev mode:%d", mode);
+
+	/* drop probe response for sta, go, sap */
+	if ((mode == QDF_STA_MODE ||
+		mode == QDF_SAP_MODE ||
+		mode == QDF_P2P_GO_MODE) &&
+		tx_ctx->frame_info.sub_type == P2P_MGMT_PROBE_RSP) {
+		p2p_debug("drop probe response, mode:%d", mode);
+		status = QDF_STATUS_E_FAILURE;
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return status;
+}
+
+/**
+ * p2p_get_p2pie_ptr() - get the pointer to p2p ie
+ * @ie:      source ie
+ * @ie_len:  source ie length
+ *
+ * This function finds out p2p ie by p2p oui and return the pointer.
+ *
+ * Return: pointer to p2p ie
+ */
+static const uint8_t *p2p_get_p2pie_ptr(const uint8_t *ie, uint16_t ie_len)
+{
+	return wlan_get_vendor_ie_ptr_from_oui(P2P_OUI,
+			P2P_OUI_SIZE, ie, ie_len);
+}
+
+/**
+ * p2p_get_p2pie_from_probe_rsp() - get the pointer to p2p ie from
+ * probe response
+ * @tx_ctx:      tx context
+ *
+ * This function finds out p2p ie and return the pointer if it is a
+ * probe response frame.
+ *
+ * Return: pointer to p2p ie
+ */
+static const uint8_t *p2p_get_p2pie_from_probe_rsp(
+	struct tx_action_context *tx_ctx)
+{
+	const uint8_t *ie;
+	const uint8_t *p2p_ie;
+	const uint8_t *tmp_p2p_ie = NULL;
+	uint16_t ie_len;
+
+	if (tx_ctx->buf_len <= PROBE_RSP_IE_OFFSET) {
+		p2p_err("Invalid header len for probe response");
+		return NULL;
+	}
+
+	ie = tx_ctx->buf + PROBE_RSP_IE_OFFSET;
+	ie_len = tx_ctx->buf_len - PROBE_RSP_IE_OFFSET;
+	p2p_ie = p2p_get_p2pie_ptr(ie, ie_len);
+	while ((p2p_ie) &&
+		(P2P_MAX_IE_LENGTH == p2p_ie[1])) {
+		ie_len = tx_ctx->buf_len - (p2p_ie - tx_ctx->buf);
+		if (ie_len > 2) {
+			ie = p2p_ie + P2P_MAX_IE_LENGTH + 2;
+			tmp_p2p_ie = p2p_get_p2pie_ptr(ie, ie_len);
+		}
+
+		if (tmp_p2p_ie) {
+			p2p_ie = tmp_p2p_ie;
+			tmp_p2p_ie = NULL;
+		} else {
+			break;
+		}
+	}
+
+	return p2p_ie;
+}
+
+/**
+ * p2p_get_presence_noa_attr() - get the pointer to noa attr
+ * @pies:      source ie
+ * @length:    source ie length
+ *
+ * This function finds out noa attr by noa eid and return the pointer.
+ *
+ * Return: pointer to noa attr
+ */
+static const uint8_t *p2p_get_presence_noa_attr(const uint8_t *pies, int length)
+{
+	int left = length;
+	const uint8_t *ptr = pies;
+	uint8_t elem_id;
+	uint16_t elem_len;
+
+	p2p_debug("pies:%pK, length:%d", pies, length);
+
+	while (left >= 3) {
+		elem_id = ptr[0];
+		elem_len = ((uint16_t) ptr[1]) | (ptr[2] << 8);
+
+		left -= 3;
+		if (elem_len > left) {
+			p2p_err("****Invalid IEs, elem_len=%d left=%d*****",
+				elem_len, left);
+			return NULL;
+		}
+		if (elem_id == P2P_NOA_ATTR)
+			return ptr;
+
+		left -= elem_len;
+		ptr += (elem_len + 3);
+	}
+
+	return NULL;
+}
+
+/**
+ * p2p_get_noa_attr_stream_in_mult_p2p_ies() - get the pointer to noa
+ * attr from multi p2p ie
+ * @noa_stream:      noa stream
+ * @noa_len:         noa stream length
+ * @overflow_len:    overflow length
+ *
+ * This function finds out noa attr from multi p2p ies.
+ *
+ * Return: noa length
+ */
+static uint8_t p2p_get_noa_attr_stream_in_mult_p2p_ies(uint8_t *noa_stream,
+	uint8_t noa_len, uint8_t overflow_len)
+{
+	uint8_t overflow_p2p_stream[P2P_MAX_NOA_ATTR_LEN];
+
+	p2p_debug("noa_stream:%pK, noa_len:%d, overflow_len:%d",
+		noa_stream, noa_len, overflow_len);
+	if ((noa_len <= (P2P_MAX_NOA_ATTR_LEN + P2P_IE_HEADER_LEN)) &&
+	    (noa_len >= overflow_len) &&
+	    (overflow_len <= P2P_MAX_NOA_ATTR_LEN)) {
+		qdf_mem_copy(overflow_p2p_stream,
+			     noa_stream + noa_len - overflow_len,
+			     overflow_len);
+		noa_stream[noa_len - overflow_len] =
+			P2P_EID_VENDOR;
+		noa_stream[noa_len - overflow_len + 1] =
+			overflow_len + P2P_OUI_SIZE;
+		qdf_mem_copy(noa_stream + noa_len - overflow_len + 2,
+			P2P_OUI, P2P_OUI_SIZE);
+		qdf_mem_copy(noa_stream + noa_len + 2 + P2P_OUI_SIZE -
+			overflow_len, overflow_p2p_stream,
+			overflow_len);
+	}
+
+	return noa_len + P2P_IE_HEADER_LEN;
+}
+
+/**
+ * p2p_get_vdev_noa_info() - get vdev noa information
+ * @tx_ctx:         tx context
+ *
+ * This function gets vdev noa information
+ *
+ * Return: pointer to noa information
+ */
+static struct p2p_noa_info *p2p_get_vdev_noa_info(
+	struct tx_action_context *tx_ctx)
+{
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	enum QDF_OPMODE mode;
+	struct p2p_noa_info *noa_info = NULL;
+
+	p2p_soc_obj = tx_ctx->p2p_soc_obj;
+	psoc = p2p_soc_obj->soc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+			tx_ctx->vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_err("vdev obj is NULL");
+		return NULL;
+	}
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	p2p_debug("vdev mode:%d", mode);
+	if (mode != QDF_P2P_GO_MODE) {
+		p2p_debug("invalid p2p vdev mode:%d", mode);
+		goto fail;
+	}
+
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+			WLAN_UMAC_COMP_P2P);
+
+	if (!p2p_vdev_obj || !(p2p_vdev_obj->noa_info)) {
+		p2p_debug("null noa info");
+		goto fail;
+	}
+
+	noa_info = p2p_vdev_obj->noa_info;
+
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return noa_info;
+}
+
+/**
+ * p2p_get_noa_attr_stream() - get noa stream from p2p vdev object
+ * @tx_ctx:         tx context
+ * @pnoa_stream:    pointer to noa stream
+ *
+ * This function finds out noa stream from p2p vdev object
+ *
+ * Return: noa stream length
+ */
+static uint8_t p2p_get_noa_attr_stream(
+	struct tx_action_context *tx_ctx, uint8_t *pnoa_stream)
+{
+	struct p2p_noa_info *noa_info;
+	struct noa_descriptor *noa_desc_0;
+	struct noa_descriptor *noa_desc_1;
+	uint8_t *pbody = pnoa_stream;
+	uint8_t len = 0;
+
+	noa_info = p2p_get_vdev_noa_info(tx_ctx);
+	if (!noa_info) {
+		p2p_debug("not valid noa information");
+		return 0;
+	}
+
+	noa_desc_0 = &(noa_info->noa_desc[0]);
+	noa_desc_1 = &(noa_info->noa_desc[1]);
+	if ((!(noa_desc_0->duration)) &&
+		(!(noa_desc_1->duration)) &&
+		(!noa_info->opps_ps)) {
+		p2p_debug("opps ps and duration are 0");
+		return 0;
+	}
+
+	pbody[0] = P2P_NOA_ATTR;
+	pbody[3] = noa_info->index;
+	pbody[4] = noa_info->ct_window | (noa_info->opps_ps << 7);
+	len = 5;
+	pbody += len;
+
+	if (noa_desc_0->duration) {
+		*pbody = noa_desc_0->type_count;
+		pbody += 1;
+		len += 1;
+
+		*((uint32_t *) (pbody)) = noa_desc_0->duration;
+		pbody += sizeof(uint32_t);
+		len += 4;
+
+		*((uint32_t *) (pbody)) = noa_desc_0->interval;
+		pbody += sizeof(uint32_t);
+		len += 4;
+
+		*((uint32_t *) (pbody)) = noa_desc_0->start_time;
+		pbody += sizeof(uint32_t);
+		len += 4;
+	}
+
+	if (noa_desc_1->duration) {
+		*pbody = noa_desc_1->type_count;
+		pbody += 1;
+		len += 1;
+
+		*((uint32_t *) (pbody)) = noa_desc_1->duration;
+		pbody += sizeof(uint32_t);
+		len += 4;
+
+		*((uint32_t *) (pbody)) = noa_desc_1->interval;
+		pbody += sizeof(uint32_t);
+		len += 4;
+
+		*((uint32_t *) (pbody)) = noa_desc_1->start_time;
+		pbody += sizeof(uint32_t);
+		len += 4;
+	}
+
+	pbody = pnoa_stream + 1;
+	 /* one byte for Attr and 2 bytes for length */
+	*((uint16_t *) (pbody)) = len - 3;
+
+	return len;
+}
+
+/**
+ * p2p_update_noa_stream() - update noa stream
+ * @tx_ctx:       tx context
+ * @p2p_ie:       pointer to p2p ie
+ * @noa_attr:     pointer to noa attr
+ * @total_len:    pointer to total length of ie
+ *
+ * This function updates noa stream.
+ *
+ * Return: noa stream length
+ */
+static uint16_t p2p_update_noa_stream(struct tx_action_context *tx_ctx,
+	uint8_t *p2p_ie, const uint8_t *noa_attr, uint32_t *total_len,
+	uint8_t *noa_stream)
+{
+	uint16_t noa_len;
+	uint16_t overflow_len;
+	uint8_t orig_len;
+	uint32_t nbytes_copy;
+	uint32_t buf_len = *total_len;
+
+	noa_len = p2p_get_noa_attr_stream(tx_ctx, noa_stream);
+	if (noa_len <= 0) {
+		p2p_debug("do not find out noa attr");
+		return 0;
+	}
+
+	orig_len = p2p_ie[1];
+	if (noa_attr) {
+		noa_len = noa_attr[1] | (noa_attr[2] << 8);
+		orig_len -= (noa_len + 1 + 2);
+		buf_len -= (noa_len + 1 + 2);
+		p2p_ie[1] = orig_len;
+	}
+
+	if ((p2p_ie[1] + noa_len) > P2P_MAX_IE_LENGTH) {
+		overflow_len = p2p_ie[1] + noa_len -
+				P2P_MAX_IE_LENGTH;
+		noa_len = p2p_get_noa_attr_stream_in_mult_p2p_ies(
+				noa_stream, noa_len, overflow_len);
+		p2p_ie[1] = P2P_MAX_IE_LENGTH;
+	} else {
+		/* increment the length of P2P IE */
+		p2p_ie[1] += noa_len;
+	}
+
+	*total_len = buf_len;
+	nbytes_copy = (p2p_ie + orig_len + 2) - tx_ctx->buf;
+
+	p2p_debug("noa_len=%d orig_len=%d p2p_ie=%pK buf_len=%d nbytes copy=%d ",
+		noa_len, orig_len, p2p_ie, buf_len, nbytes_copy);
+
+	return noa_len;
+}
+
+/**
+ * p2p_set_ht_caps() - set ht capability
+ * @tx_ctx:         tx context
+ * @num_bytes:      number bytes
+ *
+ * This function sets ht capability
+ *
+ * Return: None
+ */
+static void p2p_set_ht_caps(struct tx_action_context *tx_ctx,
+	uint32_t num_bytes)
+{
+}
+
+/**
+ * p2p_populate_mac_header() - update sequence number
+ * @tx_ctx:      tx context
+ *
+ * This function updates sequence number of this mgmt frame
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_populate_mac_header(
+	struct tx_action_context *tx_ctx)
+{
+	struct wlan_seq_ctl *seq_ctl;
+	struct wlan_frame_hdr *wh;
+	struct wlan_objmgr_peer *peer;
+	struct wlan_objmgr_psoc *psoc;
+	void *mac_addr;
+	uint16_t seq_num;
+	uint8_t pdev_id;
+	struct wlan_objmgr_vdev *vdev;
+
+	psoc = tx_ctx->p2p_soc_obj->soc;
+
+	wh = (struct wlan_frame_hdr *)tx_ctx->buf;
+	mac_addr = wh->i_addr1;
+	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, tx_ctx->vdev_id,
+						WLAN_P2P_ID);
+	peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_P2P_ID);
+	if (!peer) {
+		mac_addr = wh->i_addr2;
+		peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr,
+					    WLAN_P2P_ID);
+	}
+	if (!peer && tx_ctx->rand_mac_tx) {
+		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+							    tx_ctx->vdev_id,
+							    WLAN_P2P_ID);
+		if (vdev) {
+			mac_addr = wlan_vdev_mlme_get_macaddr(vdev);
+			peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr,
+						    WLAN_P2P_ID);
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+		}
+	}
+	if (!peer) {
+		p2p_err("no valid peer");
+		return QDF_STATUS_E_INVAL;
+	}
+	seq_num = (uint16_t)wlan_peer_mlme_get_next_seq_num(peer);
+	seq_ctl = (struct wlan_seq_ctl *)(tx_ctx->buf +
+			WLAN_SEQ_CTL_OFFSET);
+	seq_ctl->seq_num_lo = (seq_num & WLAN_LOW_SEQ_NUM_MASK);
+	seq_ctl->seq_num_hi = ((seq_num & WLAN_HIGH_SEQ_NUM_MASK) >>
+				WLAN_HIGH_SEQ_NUM_OFFSET);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_P2P_ID);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_get_frame_type_str() - parse frame type to string
+ * @frame_info: frame information
+ *
+ * This function parse frame type to string.
+ *
+ * Return: command string
+ */
+static char *p2p_get_frame_type_str(struct p2p_frame_info *frame_info)
+{
+	if (frame_info->type == P2P_FRAME_NOT_SUPPORT)
+		return "Not support frame";
+
+	if (frame_info->sub_type == P2P_MGMT_NOT_SUPPORT)
+		return "Not support sub frame";
+
+	switch (frame_info->sub_type) {
+	case P2P_MGMT_PROBE_REQ:
+		return "P2P roc request";
+	case P2P_MGMT_PROBE_RSP:
+		return "P2P cancel roc request";
+	case P2P_MGMT_ACTION:
+		break;
+	default:
+		return "Invalid P2P command";
+	}
+
+	if (frame_info->action_type == P2P_ACTION_PRESENCE_REQ)
+		return "P2P action presence request";
+	if (frame_info->action_type == P2P_ACTION_PRESENCE_RSP)
+		return "P2P action presence response";
+
+	switch (frame_info->public_action_type) {
+	case P2P_PUBLIC_ACTION_NEG_REQ:
+		return "GO negotiation request frame";
+	case P2P_PUBLIC_ACTION_NEG_RSP:
+		return "GO negotiation response frame";
+	case P2P_PUBLIC_ACTION_NEG_CNF:
+		return "GO negotiation confirm frame";
+	case P2P_PUBLIC_ACTION_INVIT_REQ:
+		return "P2P invitation request";
+	case P2P_PUBLIC_ACTION_INVIT_RSP:
+		return "P2P invitation response";
+	case P2P_PUBLIC_ACTION_DEV_DIS_REQ:
+		return "Device discoverability request";
+	case P2P_PUBLIC_ACTION_DEV_DIS_RSP:
+		return "Device discoverability response";
+	case P2P_PUBLIC_ACTION_PROV_DIS_REQ:
+		return "Provision discovery request";
+	case P2P_PUBLIC_ACTION_PROV_DIS_RSP:
+		return "Provision discovery response";
+	case P2P_PUBLIC_ACTION_GAS_INIT_REQ:
+		return "GAS init request";
+	case P2P_PUBLIC_ACTION_GAS_INIT_RSP:
+		return "GAS init response";
+	case P2P_PUBLIC_ACTION_GAS_COMB_REQ:
+		return "GAS come back request";
+	case P2P_PUBLIC_ACTION_GAS_COMB_RSP:
+		return "GAS come back response";
+	default:
+		return "Not support action frame";
+	}
+}
+
+/**
+ * p2p_init_frame_info() - init frame information structure
+ * @frame_info:     pointer to frame information
+ *
+ * This function init frame information structure.
+ *
+ * Return: None
+ */
+static void p2p_init_frame_info(struct p2p_frame_info *frame_info)
+{
+	frame_info->type = P2P_FRAME_NOT_SUPPORT;
+	frame_info->sub_type = P2P_MGMT_NOT_SUPPORT;
+	frame_info->public_action_type =
+				P2P_PUBLIC_ACTION_NOT_SUPPORT;
+	frame_info->action_type = P2P_ACTION_NOT_SUPPORT;
+}
+
+/**
+ * p2p_get_frame_info() - get frame information from packet
+ * @data_buf:          data buffer address
+ * @length:            buffer length
+ * @frame_info:        frame information
+ *
+ * This function gets frame information from packet.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_get_frame_info(uint8_t *data_buf, uint32_t length,
+	struct p2p_frame_info *frame_info)
+{
+	uint8_t type;
+	uint8_t sub_type;
+	uint8_t action_type;
+	uint8_t *buf = data_buf;
+
+	p2p_init_frame_info(frame_info);
+
+	if (length < P2P_ACTION_OFFSET + 1) {
+		p2p_err("invalid p2p mgmt hdr len");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	type = P2P_GET_TYPE_FRM_FC(buf[0]);
+	sub_type = P2P_GET_SUBTYPE_FRM_FC(buf[0]);
+	if (type != P2P_FRAME_MGMT) {
+		p2p_err("just support mgmt frame");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	frame_info->type = P2P_FRAME_MGMT;
+	if (sub_type != P2P_MGMT_PROBE_RSP &&
+		sub_type != P2P_MGMT_ACTION) {
+		p2p_err("not support sub type");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (sub_type == P2P_MGMT_PROBE_RSP) {
+		frame_info->sub_type = P2P_MGMT_PROBE_RSP;
+		p2p_debug("Probe Response");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (sub_type == P2P_MGMT_PROBE_REQ) {
+		frame_info->sub_type = P2P_MGMT_PROBE_REQ;
+		p2p_debug("Probe Request");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	frame_info->sub_type = P2P_MGMT_ACTION;
+	buf += P2P_ACTION_OFFSET;
+	if (length > P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET &&
+	    buf[0] == P2P_PUBLIC_ACTION_FRAME &&
+	    buf[1] == P2P_PUBLIC_ACTION_VENDOR_SPECIFIC &&
+	    !qdf_mem_cmp(&buf[2], P2P_OUI, P2P_OUI_SIZE)) {
+		buf = data_buf +
+			P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET;
+		action_type = buf[0];
+		if (action_type > P2P_PUBLIC_ACTION_PROV_DIS_RSP)
+			frame_info->public_action_type =
+				P2P_PUBLIC_ACTION_NOT_SUPPORT;
+		else
+			frame_info->public_action_type = action_type;
+	} else if (length > P2P_ACTION_FRAME_TYPE_OFFSET &&
+		   buf[0] == P2P_ACTION_VENDOR_SPECIFIC_CATEGORY &&
+		   !qdf_mem_cmp(&buf[1], P2P_OUI, P2P_OUI_SIZE)) {
+		buf = data_buf +
+			P2P_ACTION_FRAME_TYPE_OFFSET;
+		action_type = buf[0];
+		if (action_type == P2P_ACTION_PRESENCE_REQ)
+			frame_info->action_type =
+				P2P_ACTION_PRESENCE_REQ;
+		if (action_type == P2P_ACTION_PRESENCE_RSP)
+			frame_info->action_type =
+				P2P_ACTION_PRESENCE_RSP;
+	} else {
+		p2p_debug("this is not vendor specific p2p action frame");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	p2p_debug("%s", p2p_get_frame_type_str(frame_info));
+
+	return QDF_STATUS_SUCCESS;
+}
+
+#ifdef WLAN_FEATURE_P2P_DEBUG
+/**
+ * p2p_tx_update_connection_status() - Update P2P connection status
+ * with tx frame
+ * @p2p_soc_obj:        P2P soc private object
+ * @tx_frame_info:      frame information
+ * @mac_to:              Pointer to dest MAC address
+ *
+ * This function updates P2P connection status with tx frame.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_tx_update_connection_status(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct p2p_frame_info *tx_frame_info,
+	uint8_t *mac_to)
+{
+	if (!p2p_soc_obj || !tx_frame_info || !mac_to) {
+		p2p_err("invalid p2p_soc_obj:%pK or tx_frame_info:%pK or mac_to:%pK",
+			p2p_soc_obj, tx_frame_info, mac_to);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (tx_frame_info->public_action_type !=
+		P2P_PUBLIC_ACTION_NOT_SUPPORT)
+		p2p_info("%s ---> OTA to " QDF_MAC_ADDR_STR,
+			  p2p_get_frame_type_str(tx_frame_info),
+			  QDF_MAC_ADDR_ARRAY(mac_to));
+
+	if ((tx_frame_info->public_action_type ==
+	     P2P_PUBLIC_ACTION_PROV_DIS_REQ) &&
+	    (p2p_soc_obj->connection_status == P2P_NOT_ACTIVE)) {
+		p2p_soc_obj->connection_status = P2P_GO_NEG_PROCESS;
+		p2p_info("[P2P State]Inactive state to GO negotiation progress state");
+	} else if ((tx_frame_info->public_action_type ==
+		    P2P_PUBLIC_ACTION_NEG_CNF) &&
+		   (p2p_soc_obj->connection_status ==
+		    P2P_GO_NEG_PROCESS)) {
+		p2p_soc_obj->connection_status = P2P_GO_NEG_COMPLETED;
+		p2p_info("[P2P State]GO nego progress to GO nego completed state");
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_rx_update_connection_status() - Update P2P connection status
+ * with rx frame
+ * @p2p_soc_obj:        P2P soc private object
+ * @rx_frame_info:      frame information
+ * @mac_from:            Pointer to source MAC address
+ *
+ * This function updates P2P connection status with rx frame.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_rx_update_connection_status(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct p2p_frame_info *rx_frame_info,
+	uint8_t *mac_from)
+{
+	if (!p2p_soc_obj || !rx_frame_info || !mac_from) {
+		p2p_err("invalid p2p_soc_obj:%pK or rx_frame_info:%pK, mac_from:%pK",
+			p2p_soc_obj, rx_frame_info, mac_from);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (rx_frame_info->public_action_type !=
+		P2P_PUBLIC_ACTION_NOT_SUPPORT)
+		p2p_info("%s <--- OTA from " QDF_MAC_ADDR_STR,
+			  p2p_get_frame_type_str(rx_frame_info),
+			  QDF_MAC_ADDR_ARRAY(mac_from));
+
+	if ((rx_frame_info->public_action_type ==
+	     P2P_PUBLIC_ACTION_PROV_DIS_REQ) &&
+	    (p2p_soc_obj->connection_status == P2P_NOT_ACTIVE)) {
+		p2p_soc_obj->connection_status = P2P_GO_NEG_PROCESS;
+		p2p_info("[P2P State]Inactive state to GO negotiation progress state");
+	} else if ((rx_frame_info->public_action_type ==
+		    P2P_PUBLIC_ACTION_NEG_CNF) &&
+		   (p2p_soc_obj->connection_status ==
+		    P2P_GO_NEG_PROCESS)) {
+		p2p_soc_obj->connection_status = P2P_GO_NEG_COMPLETED;
+		p2p_info("[P2P State]GO negotiation progress to GO negotiation completed state");
+	} else if ((rx_frame_info->public_action_type ==
+		    P2P_PUBLIC_ACTION_INVIT_REQ) &&
+		   (p2p_soc_obj->connection_status == P2P_NOT_ACTIVE)) {
+		p2p_soc_obj->connection_status = P2P_GO_NEG_COMPLETED;
+		p2p_info("[P2P State]Inactive state to GO negotiation completed state Autonomous GO formation");
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS p2p_tx_update_connection_status(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct p2p_frame_info *tx_frame_info,
+	uint8_t *mac_to)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS p2p_rx_update_connection_status(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct p2p_frame_info *rx_frame_info,
+	uint8_t *mac_from)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * p2p_packet_alloc() - allocate qdf nbuf
+ * @size:         buffe size
+ * @data:         pointer to qdf nbuf data point
+ * @ppPacket:     pointer to qdf nbuf point
+ *
+ * This function allocates qdf nbuf.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_packet_alloc(uint16_t size, void **data,
+	qdf_nbuf_t *ppPacket)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	qdf_nbuf_t nbuf;
+
+	nbuf = qdf_nbuf_alloc(NULL,
+			roundup(size + P2P_TX_PKT_MIN_HEADROOM, 4),
+			P2P_TX_PKT_MIN_HEADROOM, sizeof(uint32_t),
+			false);
+
+	if (nbuf != NULL) {
+		qdf_nbuf_put_tail(nbuf, size);
+		qdf_nbuf_set_protocol(nbuf, ETH_P_CONTROL);
+		*ppPacket = nbuf;
+		*data = qdf_nbuf_data(nbuf);
+		qdf_mem_set(*data, size, 0);
+		status = QDF_STATUS_SUCCESS;
+	}
+
+	return status;
+}
+
+/**
+ * p2p_send_tx_conf() - send tx confirm
+ * @tx_ctx:        tx context
+ * @status:        tx status
+ *
+ * This function send tx confirm to osif
+ *
+ * Return: QDF_STATUS_SUCCESS - pointer to tx context
+ */
+static QDF_STATUS p2p_send_tx_conf(struct tx_action_context *tx_ctx,
+	bool status)
+{
+	struct p2p_tx_cnf tx_cnf;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_start_param *start_param;
+
+	p2p_soc_obj = tx_ctx->p2p_soc_obj;
+
+	if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) {
+		p2p_err("Invalid p2p soc object or start parameters");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	start_param = p2p_soc_obj->start_param;
+	if (!(start_param->tx_cnf_cb)) {
+		p2p_err("no tx confirm callback");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (tx_ctx->no_ack)
+		tx_cnf.action_cookie = 0;
+	else
+		tx_cnf.action_cookie = (uint64_t)tx_ctx->id;
+
+	tx_cnf.vdev_id = tx_ctx->vdev_id;
+	tx_cnf.buf = tx_ctx->buf;
+	tx_cnf.buf_len = tx_ctx->buf_len;
+	tx_cnf.status = status ? 0 : 1;
+
+	p2p_debug("soc:%pK, vdev_id:%d, action_cookie:%llx, len:%d, status:%d, buf:%pK",
+		p2p_soc_obj->soc, tx_cnf.vdev_id,
+		tx_cnf.action_cookie, tx_cnf.buf_len,
+		tx_cnf.status, tx_cnf.buf);
+
+	p2p_rand_mac_tx_done(p2p_soc_obj->soc, tx_ctx);
+
+	start_param->tx_cnf_cb(start_param->tx_cnf_cb_data, &tx_cnf);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_mgmt_tx() - call mgmt tx api
+ * @tx_ctx:        tx context
+ * @buf_len:       buffer length
+ * @packet:        pointer to qdf nbuf
+ * @frame:         pointer to qdf nbuf data
+ *
+ * This function call mgmt tx api to tx this action frame.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx,
+	uint32_t buf_len, qdf_nbuf_t packet, uint8_t *frame)
+{
+	QDF_STATUS status;
+	mgmt_tx_download_comp_cb tx_comp_cb;
+	mgmt_ota_comp_cb tx_ota_comp_cb;
+	struct wlan_frame_hdr *wh;
+	struct wlan_objmgr_peer *peer;
+	struct wmi_mgmt_params mgmt_param = { 0 };
+	struct wlan_objmgr_psoc *psoc;
+	void *mac_addr;
+	uint8_t pdev_id;
+	struct wlan_objmgr_vdev *vdev;
+
+	psoc = tx_ctx->p2p_soc_obj->soc;
+	mgmt_param.tx_frame = packet;
+	mgmt_param.frm_len = buf_len;
+	mgmt_param.vdev_id = tx_ctx->vdev_id;
+	mgmt_param.pdata = frame;
+	mgmt_param.chanfreq = wlan_chan_to_freq(tx_ctx->chan);
+
+	mgmt_param.qdf_ctx = wlan_psoc_get_qdf_dev(psoc);
+	if (!(mgmt_param.qdf_ctx)) {
+		p2p_err("qdf ctx is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wh = (struct wlan_frame_hdr *)frame;
+	mac_addr = wh->i_addr1;
+	pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, tx_ctx->vdev_id,
+						WLAN_P2P_ID);
+	peer = wlan_objmgr_get_peer(psoc, pdev_id,  mac_addr, WLAN_P2P_ID);
+	if (!peer) {
+		mac_addr = wh->i_addr2;
+		peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr,
+					    WLAN_P2P_ID);
+	}
+	if (!peer && tx_ctx->rand_mac_tx) {
+		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+				psoc, tx_ctx->vdev_id, WLAN_P2P_ID);
+		if (vdev) {
+			mac_addr = wlan_vdev_mlme_get_macaddr(vdev);
+			peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr,
+						    WLAN_P2P_ID);
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+		}
+	}
+
+	if (!peer) {
+		p2p_err("no valid peer");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (tx_ctx->no_ack) {
+		tx_comp_cb = tgt_p2p_mgmt_download_comp_cb;
+		tx_ota_comp_cb = NULL;
+	} else {
+		tx_comp_cb = NULL;
+		tx_ota_comp_cb = tgt_p2p_mgmt_ota_comp_cb;
+	}
+
+	p2p_debug("length:%d, vdev_id:%d, chanfreq:%d, no_ack:%d",
+		mgmt_param.frm_len, mgmt_param.vdev_id,
+		mgmt_param.chanfreq, tx_ctx->no_ack);
+
+	tx_ctx->nbuf = packet;
+
+	status = wlan_mgmt_txrx_mgmt_frame_tx(peer, tx_ctx->p2p_soc_obj,
+			packet, tx_comp_cb, tx_ota_comp_cb,
+			WLAN_UMAC_COMP_P2P, &mgmt_param);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_P2P_ID);
+
+	return status;
+}
+
+/**
+ * p2p_roc_req_for_tx_action() - new a roc request for tx
+ * @tx_ctx:        tx context
+ *
+ * This function new a roc request for tx and call roc api to process
+ * this new roc request.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_roc_req_for_tx_action(
+	struct tx_action_context *tx_ctx)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *roc_ctx;
+	QDF_STATUS status;
+
+	roc_ctx = qdf_mem_malloc(sizeof(struct p2p_roc_context));
+	if (!roc_ctx) {
+		p2p_err("Failed to allocate p2p roc context");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	p2p_soc_obj = tx_ctx->p2p_soc_obj;
+	roc_ctx->p2p_soc_obj = p2p_soc_obj;
+	roc_ctx->vdev_id = tx_ctx->vdev_id;
+	roc_ctx->chan = tx_ctx->chan;
+	roc_ctx->duration = tx_ctx->duration;
+	roc_ctx->roc_state = ROC_STATE_IDLE;
+	roc_ctx->roc_type = OFF_CHANNEL_TX;
+	roc_ctx->tx_ctx = tx_ctx;
+	roc_ctx->id = tx_ctx->id;
+	tx_ctx->roc_cookie = (uintptr_t)roc_ctx;
+
+	p2p_debug("create roc request for off channel tx, tx ctx:%pK, roc ctx:%pK",
+		tx_ctx, roc_ctx);
+
+	status = p2p_process_roc_req(roc_ctx);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("request roc for tx action frrame fail");
+		return status;
+	}
+
+	status = qdf_list_insert_back(&p2p_soc_obj->tx_q_roc,
+		&tx_ctx->node);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to insert off chan tx context to wait roc req queue");
+
+	return status;
+}
+
+/**
+ * p2p_find_tx_ctx() - find tx context by cookie
+ * @p2p_soc_obj:        p2p soc object
+ * @cookie:          cookie to this p2p tx context
+ * @is_roc_q:        it is in waiting for roc queue
+ * @is_ack_q:        it is in waiting for ack queue
+ *
+ * This function finds out tx context by cookie.
+ *
+ * Return: pointer to tx context
+ */
+static struct tx_action_context *p2p_find_tx_ctx(
+	struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie,
+	bool *is_roc_q, bool *is_ack_q)
+{
+	struct tx_action_context *cur_tx_ctx;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+	*is_roc_q = false;
+	*is_ack_q = false;
+
+	p2p_debug("Start to find tx ctx, p2p soc_obj:%pK, cookie:%llx",
+		p2p_soc_obj, cookie);
+
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_roc, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		cur_tx_ctx = qdf_container_of(p_node,
+				struct tx_action_context, node);
+		if ((uintptr_t) cur_tx_ctx == cookie) {
+			*is_roc_q = true;
+			p2p_debug("find tx ctx, cookie:%llx", cookie);
+			return cur_tx_ctx;
+		}
+		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_roc,
+						p_node, &p_node);
+	}
+
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		cur_tx_ctx = qdf_container_of(p_node,
+				struct tx_action_context, node);
+		if ((uintptr_t) cur_tx_ctx == cookie) {
+			*is_ack_q = true;
+			p2p_debug("find tx ctx, cookie:%llx", cookie);
+			return cur_tx_ctx;
+		}
+		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack,
+						p_node, &p_node);
+	}
+
+	return NULL;
+}
+
+/**
+ * p2p_find_tx_ctx_by_roc() - find tx context by roc
+ * @p2p_soc_obj:        p2p soc object
+ * @cookie:          cookie to roc context
+ *
+ * This function finds out tx context by roc context.
+ *
+ * Return: pointer to tx context
+ */
+static struct tx_action_context *p2p_find_tx_ctx_by_roc(
+	struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie)
+{
+	struct tx_action_context *cur_tx_ctx;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	p2p_debug("Start to find tx ctx, p2p soc_obj:%pK, cookie:%llx",
+		p2p_soc_obj, cookie);
+
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_roc, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		cur_tx_ctx = qdf_container_of(p_node,
+					struct tx_action_context, node);
+		if (cur_tx_ctx->roc_cookie == cookie) {
+			p2p_debug("find tx ctx, cookie:%llx", cookie);
+			return cur_tx_ctx;
+		}
+		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_roc,
+						p_node, &p_node);
+	}
+
+	return NULL;
+}
+
+/**
+ * p2p_move_tx_context_to_ack_queue() - move tx context to tx_q_ack
+ * @tx_ctx:        tx context
+ *
+ * This function moves tx context to waiting for ack queue.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_move_tx_context_to_ack_queue(
+	struct tx_action_context *tx_ctx)
+{
+	bool is_roc_q = false;
+	bool is_ack_q = false;
+	struct p2p_soc_priv_obj *p2p_soc_obj = tx_ctx->p2p_soc_obj;
+	struct tx_action_context *cur_tx_ctx;
+	QDF_STATUS status;
+
+	p2p_debug("move tx context to wait for roc queue, %pK", tx_ctx);
+
+	cur_tx_ctx = p2p_find_tx_ctx(p2p_soc_obj, (uintptr_t)tx_ctx,
+					&is_roc_q, &is_ack_q);
+	if (cur_tx_ctx) {
+		if (is_roc_q) {
+			p2p_debug("find in wait for roc queue");
+			status = qdf_list_remove_node(
+				&p2p_soc_obj->tx_q_roc,
+				(qdf_list_node_t *)tx_ctx);
+			if (status != QDF_STATUS_SUCCESS)
+				p2p_err("Failed to remove off chan tx context from wait roc req queue");
+		}
+
+		if (is_ack_q) {
+			p2p_debug("Already in waiting for ack queue");
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+
+	status = qdf_list_insert_back(
+				&p2p_soc_obj->tx_q_ack,
+				&tx_ctx->node);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to insert off chan tx context to wait ack req queue");
+	p2p_debug("insert tx context to wait for ack queue, status:%d",
+		status);
+
+	return status;
+}
+
+/**
+ * p2p_extend_roc_timer() - extend roc timer
+ * @p2p_soc_obj:   p2p soc private object
+ * @frame_info:    pointer to frame information
+ *
+ * This function extends roc timer for some of p2p public action frame.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_extend_roc_timer(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct p2p_frame_info *frame_info)
+{
+	struct p2p_roc_context *curr_roc_ctx;
+	uint32_t extend_time;
+
+	curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj);
+	if (!curr_roc_ctx) {
+		p2p_debug("no running roc request currently");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (!frame_info) {
+		p2p_err("invalid frame information");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	switch (frame_info->public_action_type) {
+	case P2P_PUBLIC_ACTION_NEG_REQ:
+	case P2P_PUBLIC_ACTION_NEG_RSP:
+		extend_time = 2 * P2P_ACTION_FRAME_DEFAULT_WAIT;
+		break;
+	case P2P_PUBLIC_ACTION_INVIT_REQ:
+	case P2P_PUBLIC_ACTION_DEV_DIS_REQ:
+		extend_time = P2P_ACTION_FRAME_DEFAULT_WAIT;
+		break;
+	default:
+		extend_time = 0;
+		break;
+	}
+
+	if (extend_time) {
+		p2p_debug("extend roc timer, duration:%d", extend_time);
+		curr_roc_ctx->duration = extend_time;
+		return p2p_restart_roc_timer(curr_roc_ctx);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_adjust_tx_wait() - adjust tx wait
+ * @tx_ctx:        tx context
+ *
+ * This function adjust wait time of this tx context
+ *
+ * Return: None
+ */
+static void p2p_adjust_tx_wait(struct tx_action_context *tx_ctx)
+{
+	struct p2p_frame_info *frame_info;
+
+	frame_info = &(tx_ctx->frame_info);
+	switch (frame_info->public_action_type) {
+	case P2P_PUBLIC_ACTION_NEG_RSP:
+	case P2P_PUBLIC_ACTION_PROV_DIS_RSP:
+		tx_ctx->duration += P2P_ACTION_FRAME_RSP_WAIT;
+		break;
+	case P2P_PUBLIC_ACTION_NEG_CNF:
+	case P2P_PUBLIC_ACTION_INVIT_RSP:
+		tx_ctx->duration += P2P_ACTION_FRAME_ACK_WAIT;
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * p2p_remove_tx_context() - remove tx ctx from queue
+ * @tx_ctx:        tx context
+ *
+ * This function remove tx context from waiting for roc queue or
+ * waiting for ack queue.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_remove_tx_context(
+	struct tx_action_context *tx_ctx)
+{
+	bool is_roc_q = false;
+	bool is_ack_q = false;
+	struct tx_action_context *cur_tx_ctx;
+	uint64_t cookie = (uintptr_t)tx_ctx;
+	struct p2p_soc_priv_obj *p2p_soc_obj = tx_ctx->p2p_soc_obj;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	p2p_debug("tx context:%pK", tx_ctx);
+
+	cur_tx_ctx = p2p_find_tx_ctx(p2p_soc_obj, cookie, &is_roc_q,
+					&is_ack_q);
+
+	/* for not off channel tx case, won't find from queue */
+	if (!cur_tx_ctx) {
+		p2p_debug("Do not find tx context from queue");
+		goto end;
+	}
+
+	if (is_roc_q) {
+		status = qdf_list_remove_node(
+			&p2p_soc_obj->tx_q_roc,
+			(qdf_list_node_t *)cur_tx_ctx);
+		if (status != QDF_STATUS_SUCCESS)
+			p2p_err("Failed to  tx context from wait roc req queue");
+	}
+
+	if (is_ack_q) {
+		status = qdf_list_remove_node(
+			&p2p_soc_obj->tx_q_ack,
+			(qdf_list_node_t *)cur_tx_ctx);
+		if (status != QDF_STATUS_SUCCESS)
+			p2p_err("Failed to  tx context from wait ack req queue");
+	}
+
+end:
+	if (!tx_ctx->roc_cookie)
+		qdf_idr_remove(&p2p_soc_obj->p2p_idr, tx_ctx->id);
+	qdf_mem_free(tx_ctx->buf);
+	qdf_mem_free(tx_ctx);
+
+	return status;
+}
+
+/**
+ * p2p_tx_timeout() - Callback for tx timeout
+ * @pdata: pointer to tx context
+ *
+ * This function is callback for tx time out.
+ *
+ * Return: None
+ */
+static void p2p_tx_timeout(void *pdata)
+{
+	struct tx_action_context *tx_ctx = pdata;
+
+	p2p_info("pdata:%pK", pdata);
+
+	if (!tx_ctx || !(tx_ctx->p2p_soc_obj)) {
+		p2p_err("invalid tx context or p2p soc object");
+		return;
+	}
+
+	qdf_mc_timer_destroy(&tx_ctx->tx_timer);
+	p2p_send_tx_conf(tx_ctx, false);
+	p2p_remove_tx_context(tx_ctx);
+}
+
+/**
+ * p2p_enable_tx_timer() - enable tx timer
+ * @tx_ctx:         tx context
+ *
+ * This function enable tx timer for action frame required ota tx.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_enable_tx_timer(struct tx_action_context *tx_ctx)
+{
+	QDF_STATUS status;
+
+	p2p_debug("tx context:%pK", tx_ctx);
+
+	status = qdf_mc_timer_init(&tx_ctx->tx_timer,
+			QDF_TIMER_TYPE_SW, p2p_tx_timeout,
+			tx_ctx);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to init tx timer");
+		return status;
+	}
+
+	status = qdf_mc_timer_start(&tx_ctx->tx_timer,
+			P2P_ACTION_FRAME_TX_TIMEOUT);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("tx timer start failed");
+
+	return status;
+}
+
+/**
+ * p2p_disable_tx_timer() - disable tx timer
+ * @tx_ctx:         tx context
+ *
+ * This function disable tx timer for action frame required ota tx.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_disable_tx_timer(struct tx_action_context *tx_ctx)
+{
+	QDF_STATUS status;
+
+	p2p_debug("tx context:%pK", tx_ctx);
+
+	status = qdf_mc_timer_stop(&tx_ctx->tx_timer);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to stop tx timer, status:%d", status);
+
+	status = qdf_mc_timer_destroy(&tx_ctx->tx_timer);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to destroy tx timer, status:%d", status);
+
+	return status;
+}
+
+/**
+ * is_rmf_mgmt_action_frame() - check RMF action frame by category
+ * @action_category: action frame actegory
+ *
+ * This function check the frame is robust mgmt action frame or not
+ *
+ * Return: true - if category is robust mgmt type
+ */
+static bool is_rmf_mgmt_action_frame(uint8_t action_category)
+{
+	switch (action_category) {
+	case ACTION_CATEGORY_SPECTRUM_MGMT:
+	case ACTION_CATEGORY_QOS:
+	case ACTION_CATEGORY_DLS:
+	case ACTION_CATEGORY_BACK:
+	case ACTION_CATEGORY_RRM:
+	case ACTION_FAST_BSS_TRNST:
+	case ACTION_CATEGORY_SA_QUERY:
+	case ACTION_CATEGORY_PROTECTED_DUAL_OF_PUBLIC_ACTION:
+	case ACTION_CATEGORY_WNM:
+	case ACTION_CATEGORY_MESH_ACTION:
+	case ACTION_CATEGORY_MULTIHOP_ACTION:
+	case ACTION_CATEGORY_DMG:
+	case ACTION_CATEGORY_FST:
+	case ACTION_CATEGORY_VENDOR_SPECIFIC_PROTECTED:
+		return true;
+	default:
+		break;
+	}
+	return false;
+}
+
+/**
+ * p2p_populate_rmf_field() - populate unicast rmf frame
+ * @tx_ctx: tx_action_context
+ * @size: input size of frame, and output new size
+ * @ppbuf: input frame ptr, and output new frame
+ * @ppkt: input pkt, output new pkt.
+ *
+ * This function allocates new pkt for rmf frame. The
+ * new frame has extra space for ccmp field.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_populate_rmf_field(struct tx_action_context *tx_ctx,
+	uint32_t *size, uint8_t **ppbuf, qdf_nbuf_t *ppkt)
+{
+	struct wlan_frame_hdr *wh, *rmf_wh;
+	struct action_frm_hdr *action_hdr;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	qdf_nbuf_t pkt = NULL;
+	uint8_t *frame;
+	uint32_t frame_len;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	p2p_soc_obj = tx_ctx->p2p_soc_obj;
+
+	if (tx_ctx->frame_info.sub_type != P2P_MGMT_ACTION ||
+	    !p2p_soc_obj->p2p_cb.is_mgmt_protected)
+		return QDF_STATUS_SUCCESS;
+	if (*size < (sizeof(struct wlan_frame_hdr) +
+	    sizeof(struct action_frm_hdr))) {
+		return QDF_STATUS_E_INVAL;
+	}
+
+	wh = (struct wlan_frame_hdr *)(*ppbuf);
+	action_hdr = (struct action_frm_hdr *)(*ppbuf + sizeof(*wh));
+
+	if (!is_rmf_mgmt_action_frame(action_hdr->action_category)) {
+		p2p_debug("non rmf act frame 0x%x cat %x",
+			  tx_ctx->frame_info.sub_type,
+			  action_hdr->action_category);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	if (!p2p_soc_obj->p2p_cb.is_mgmt_protected(
+		tx_ctx->vdev_id, wh->i_addr1)) {
+		p2p_debug("non rmf connection vdev %d "QDF_MAC_ADDR_STR,
+			  tx_ctx->vdev_id, QDF_MAC_ADDR_ARRAY(wh->i_addr1));
+		return QDF_STATUS_SUCCESS;
+	}
+	if (!qdf_is_macaddr_group((struct qdf_mac_addr *)wh->i_addr1) &&
+	    !qdf_is_macaddr_broadcast((struct qdf_mac_addr *)wh->i_addr1)) {
+
+		frame_len = *size + IEEE80211_CCMP_HEADERLEN +
+			    IEEE80211_CCMP_MICLEN;
+		status = p2p_packet_alloc((uint16_t)frame_len, (void **)&frame,
+			 &pkt);
+		if (status != QDF_STATUS_SUCCESS) {
+			p2p_err("Failed to allocate %d bytes for rmf frame.",
+				frame_len);
+			return QDF_STATUS_E_NOMEM;
+		}
+
+		qdf_mem_copy(frame, wh, sizeof(*wh));
+		qdf_mem_copy(frame + sizeof(*wh) + IEEE80211_CCMP_HEADERLEN,
+			     *ppbuf + sizeof(*wh),
+			     *size - sizeof(*wh));
+		rmf_wh = (struct wlan_frame_hdr *)frame;
+		(rmf_wh)->i_fc[1] |= IEEE80211_FC1_WEP;
+		p2p_debug("set protection 0x%x cat %d "QDF_MAC_ADDR_STR,
+			  tx_ctx->frame_info.sub_type,
+			  action_hdr->action_category,
+			  QDF_MAC_ADDR_ARRAY(wh->i_addr1));
+
+		qdf_nbuf_free(*ppkt);
+		*ppbuf = frame;
+		*ppkt = pkt;
+		*size = frame_len;
+	}
+
+	return status;
+}
+
+/**
+ * p2p_execute_tx_action_frame() - execute tx action frame
+ * @tx_ctx:        tx context
+ *
+ * This function modify p2p ie and tx this action frame.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_execute_tx_action_frame(
+	struct tx_action_context *tx_ctx)
+{
+	uint8_t *frame;
+	qdf_nbuf_t packet;
+	QDF_STATUS status;
+	uint8_t noa_len = 0;
+	uint8_t noa_stream[P2P_NOA_STREAM_ARR_SIZE];
+	uint8_t orig_len = 0;
+	const uint8_t *ie;
+	uint8_t ie_len;
+	uint8_t *p2p_ie = NULL;
+	const uint8_t *presence_noa_attr = NULL;
+	uint32_t nbytes_copy;
+	uint32_t buf_len = tx_ctx->buf_len;
+	struct p2p_frame_info *frame_info;
+
+	frame_info = &(tx_ctx->frame_info);
+	if (frame_info->sub_type == P2P_MGMT_PROBE_RSP) {
+		p2p_ie = (uint8_t *)p2p_get_p2pie_from_probe_rsp(tx_ctx);
+	} else if (frame_info->action_type ==
+			P2P_ACTION_PRESENCE_RSP) {
+		ie = tx_ctx->buf +
+			P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET;
+		ie_len = tx_ctx->buf_len -
+			P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET;
+		p2p_ie = (uint8_t *)p2p_get_p2pie_ptr(ie, ie_len);
+		if (p2p_ie) {
+			/* extract the presence of NoA attribute inside
+			 * P2P IE */
+			ie = p2p_ie + P2P_IE_HEADER_LEN;
+			ie_len = p2p_ie[1];
+			presence_noa_attr = p2p_get_presence_noa_attr(
+						ie, ie_len);
+		}
+	}
+
+	if ((frame_info->sub_type != P2P_MGMT_NOT_SUPPORT) &&
+		p2p_ie) {
+		orig_len = p2p_ie[1];
+		noa_len = p2p_update_noa_stream(tx_ctx, p2p_ie,
+				presence_noa_attr, &buf_len,
+				noa_stream);
+		buf_len += noa_len;
+	}
+
+	if (frame_info->sub_type == P2P_MGMT_PROBE_RSP)
+		p2p_set_ht_caps(tx_ctx, buf_len);
+
+		/* Ok-- try to allocate some memory: */
+	status = p2p_packet_alloc((uint16_t) buf_len, (void **)&frame,
+			&packet);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to allocate %d bytes for a Probe Request.",
+			buf_len);
+		return status;
+	}
+
+	/*
+	 * Add sequence number to action frames
+	 * Frames are handed over in .11 format by supplicant already
+	 */
+	p2p_populate_mac_header(tx_ctx);
+
+	if ((noa_len > 0) && p2p_ie
+		&& (noa_len < (P2P_MAX_NOA_ATTR_LEN +
+				P2P_IE_HEADER_LEN))) {
+		/* Add 2 bytes for length and Arribute field */
+		nbytes_copy = (p2p_ie + orig_len + 2) - tx_ctx->buf;
+		qdf_mem_copy(frame, tx_ctx->buf, nbytes_copy);
+		qdf_mem_copy((frame + nbytes_copy), noa_stream,
+				noa_len);
+		qdf_mem_copy((frame + nbytes_copy + noa_len),
+			tx_ctx->buf + nbytes_copy,
+			buf_len - nbytes_copy - noa_len);
+	} else {
+		qdf_mem_copy(frame, tx_ctx->buf, buf_len);
+	}
+
+	status = p2p_populate_rmf_field(tx_ctx, &buf_len, &frame, &packet);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to populate rmf frame");
+		qdf_nbuf_free(packet);
+		return status;
+	}
+	status = p2p_mgmt_tx(tx_ctx, buf_len, packet, frame);
+	if (status == QDF_STATUS_SUCCESS) {
+		if (tx_ctx->no_ack) {
+			p2p_send_tx_conf(tx_ctx, true);
+			p2p_remove_tx_context(tx_ctx);
+		} else {
+			p2p_enable_tx_timer(tx_ctx);
+			p2p_move_tx_context_to_ack_queue(tx_ctx);
+		}
+	} else {
+		p2p_err("failed to tx mgmt frame");
+		qdf_nbuf_free(packet);
+	}
+
+	return status;
+}
+
+struct tx_action_context *p2p_find_tx_ctx_by_nbuf(
+	struct p2p_soc_priv_obj *p2p_soc_obj, void *nbuf)
+{
+	struct tx_action_context *cur_tx_ctx;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	if (!p2p_soc_obj) {
+		p2p_err("invalid p2p soc object");
+		return NULL;
+	}
+
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		cur_tx_ctx =
+			qdf_container_of(p_node, struct tx_action_context, node);
+		if (cur_tx_ctx->nbuf == nbuf) {
+			p2p_debug("find tx ctx, nbuf:%pK", nbuf);
+			status = qdf_mc_timer_stop(&cur_tx_ctx->tx_timer);
+			if (status != QDF_STATUS_SUCCESS)
+				p2p_err("Failed to stop tx timer, status:%d",
+					status);
+			return cur_tx_ctx;
+		}
+		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack,
+						p_node, &p_node);
+	}
+
+	return NULL;
+}
+
+void p2p_dump_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj)
+{
+	struct tx_action_context *tx_ctx;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	p2p_debug("dump tx queue wait for roc, p2p soc obj:%pK, size:%d",
+		p2p_soc_obj, qdf_list_size(&p2p_soc_obj->tx_q_roc));
+
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_roc, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		tx_ctx = qdf_container_of(p_node,
+				struct tx_action_context, node);
+		p2p_debug("p2p soc object:%pK, tx ctx:%pK, vdev_id:%d, scan_id:%d, roc_cookie:%llx, chan:%d, buf:%pK, len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d",
+			p2p_soc_obj, tx_ctx,
+			tx_ctx->vdev_id, tx_ctx->scan_id,
+			tx_ctx->roc_cookie, tx_ctx->chan,
+			tx_ctx->buf, tx_ctx->buf_len,
+			tx_ctx->off_chan, tx_ctx->no_cck,
+			tx_ctx->no_ack, tx_ctx->duration);
+
+		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_roc,
+						p_node, &p_node);
+	}
+
+	p2p_debug("dump tx queue wait for ack, size:%d",
+		qdf_list_size(&p2p_soc_obj->tx_q_ack));
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		tx_ctx = qdf_container_of(p_node,
+				struct tx_action_context, node);
+		p2p_debug("p2p soc object:%pK, tx_ctx:%pK, vdev_id:%d, scan_id:%d, roc_cookie:%llx, chan:%d, buf:%pK, len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d",
+			p2p_soc_obj, tx_ctx,
+			tx_ctx->vdev_id, tx_ctx->scan_id,
+			tx_ctx->roc_cookie, tx_ctx->chan,
+			tx_ctx->buf, tx_ctx->buf_len,
+			tx_ctx->off_chan, tx_ctx->no_cck,
+			tx_ctx->no_ack, tx_ctx->duration);
+
+		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack,
+						p_node, &p_node);
+	}
+}
+
+QDF_STATUS p2p_ready_to_tx_frame(struct p2p_soc_priv_obj *p2p_soc_obj,
+	uint64_t cookie)
+{
+	struct tx_action_context *cur_tx_ctx;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	cur_tx_ctx = p2p_find_tx_ctx_by_roc(p2p_soc_obj, cookie);
+
+	while (cur_tx_ctx) {
+		p2p_debug("tx_ctx:%pK", cur_tx_ctx);
+		status = p2p_execute_tx_action_frame(cur_tx_ctx);
+		if (status != QDF_STATUS_SUCCESS) {
+			p2p_send_tx_conf(cur_tx_ctx, false);
+			p2p_remove_tx_context(cur_tx_ctx);
+		}
+		cur_tx_ctx = p2p_find_tx_ctx_by_roc(p2p_soc_obj, cookie);
+	}
+
+	return status;
+}
+
+QDF_STATUS p2p_cleanup_tx_sync(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct wlan_objmgr_vdev *vdev)
+{
+	struct scheduler_msg msg = {0};
+	struct p2p_cleanup_param *param;
+	QDF_STATUS status;
+	uint32_t vdev_id;
+
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	p2p_debug("p2p_soc_obj:%pK, vdev:%pK", p2p_soc_obj, vdev);
+	param = qdf_mem_malloc(sizeof(*param));
+	if (!param) {
+		p2p_err("failed to allocate cleanup param");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	param->p2p_soc_obj = p2p_soc_obj;
+	if (vdev)
+		vdev_id = (uint32_t)wlan_vdev_get_id(vdev);
+	else
+		vdev_id = P2P_INVALID_VDEV_ID;
+	param->vdev_id = vdev_id;
+	qdf_event_reset(&p2p_soc_obj->cleanup_tx_done);
+	msg.type = P2P_CLEANUP_TX;
+	msg.bodyptr = param;
+	msg.callback = p2p_process_cmd;
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to post message");
+		qdf_mem_free(param);
+		return status;
+	}
+
+	status = qdf_wait_single_event(
+			&p2p_soc_obj->cleanup_tx_done,
+			P2P_WAIT_CLEANUP_ROC);
+
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("wait for cleanup tx timeout, %d", status);
+
+	return status;
+}
+
+QDF_STATUS p2p_process_cleanup_tx_queue(struct p2p_cleanup_param *param)
+{
+	struct tx_action_context *curr_tx_ctx;
+	qdf_list_node_t *p_node;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	uint32_t vdev_id;
+	QDF_STATUS status, ret;
+
+	if (!param || !(param->p2p_soc_obj)) {
+		p2p_err("Invalid cleanup param");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	p2p_soc_obj = param->p2p_soc_obj;
+	vdev_id = param->vdev_id;
+
+	p2p_debug("clean up tx queue wait for roc, size:%d, vdev_id:%d",
+		  qdf_list_size(&p2p_soc_obj->tx_q_roc), vdev_id);
+
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_roc, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		curr_tx_ctx = qdf_container_of(p_node,
+					struct tx_action_context, node);
+		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_roc,
+					    p_node, &p_node);
+		if ((vdev_id == P2P_INVALID_VDEV_ID) ||
+		    (vdev_id == curr_tx_ctx->vdev_id)) {
+			ret = qdf_list_remove_node(&p2p_soc_obj->tx_q_roc,
+						   &curr_tx_ctx->node);
+			if (ret == QDF_STATUS_SUCCESS) {
+				p2p_send_tx_conf(curr_tx_ctx, false);
+				qdf_mem_free(curr_tx_ctx->buf);
+				qdf_mem_free(curr_tx_ctx);
+			} else
+				p2p_err("remove %pK from roc_q fail",
+					curr_tx_ctx);
+		}
+	}
+
+	p2p_debug("clean up tx queue wait for ack, size:%d",
+		  qdf_list_size(&p2p_soc_obj->tx_q_ack));
+
+	status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		curr_tx_ctx = qdf_container_of(p_node,
+					struct tx_action_context, node);
+		status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack,
+					    p_node, &p_node);
+		if ((vdev_id == P2P_INVALID_VDEV_ID) ||
+		    (vdev_id == curr_tx_ctx->vdev_id)) {
+			ret = qdf_list_remove_node(&p2p_soc_obj->tx_q_ack,
+						   &curr_tx_ctx->node);
+			if (ret == QDF_STATUS_SUCCESS) {
+				p2p_disable_tx_timer(curr_tx_ctx);
+				p2p_send_tx_conf(curr_tx_ctx, false);
+				qdf_mem_free(curr_tx_ctx->buf);
+				qdf_mem_free(curr_tx_ctx);
+			} else
+				p2p_err("remove %pK from roc_q fail",
+					curr_tx_ctx);
+		}
+	}
+
+	qdf_event_set(&p2p_soc_obj->cleanup_tx_done);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+			  uint8_t *random_mac_addr)
+{
+	uint32_t i = 0;
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_debug("vdev is null");
+		return false;
+	}
+
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(
+				vdev, WLAN_UMAC_COMP_P2P);
+	if (!p2p_vdev_obj) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+		p2p_debug("p2p vdev object is NULL");
+		return false;
+	}
+
+	qdf_spin_lock(&p2p_vdev_obj->random_mac_lock);
+	for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) {
+		if ((p2p_vdev_obj->random_mac[i].in_use) &&
+		    (!qdf_mem_cmp(p2p_vdev_obj->random_mac[i].addr,
+				  random_mac_addr, QDF_MAC_ADDR_SIZE))) {
+			qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+			return true;
+		}
+	}
+	qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return false;
+}
+
+/**
+ * find_action_frame_cookie() - Checks for action cookie in cookie list
+ * @cookie_list: List of cookies
+ * @rnd_cookie: Cookie to be searched
+ *
+ * Return: If search is successful return pointer to action_frame_cookie
+ * object in which cookie item is encapsulated.
+ */
+static struct action_frame_cookie *
+find_action_frame_cookie(qdf_list_t *cookie_list, uint64_t rnd_cookie)
+{
+	struct action_frame_cookie *action_cookie;
+
+	qdf_list_for_each(cookie_list, action_cookie, cookie_node) {
+		if (action_cookie->cookie == rnd_cookie)
+			return action_cookie;
+	}
+
+	return NULL;
+}
+
+/**
+ * allocate_action_frame_cookie() - Allocate and add action cookie to
+ * given list
+ * @cookie_list: List of cookies
+ * @rnd_cookie: Cookie to be added
+ *
+ * Return: If allocation and addition is successful return pointer to
+ * action_frame_cookie object in which cookie item is encapsulated.
+ */
+static struct action_frame_cookie *
+allocate_action_frame_cookie(qdf_list_t *cookie_list, uint64_t rnd_cookie)
+{
+	struct action_frame_cookie *action_cookie;
+
+	action_cookie = qdf_mem_malloc(sizeof(*action_cookie));
+	if (!action_cookie)
+		return NULL;
+
+	action_cookie->cookie = rnd_cookie;
+	qdf_list_insert_front(cookie_list, &action_cookie->cookie_node);
+
+	return action_cookie;
+}
+
+/**
+ * delete_action_frame_cookie() - Delete the cookie from given list
+ * @cookie_list: List of cookies
+ * @action_cookie: Cookie to be deleted
+ *
+ * This function deletes the cookie item from given list and corresponding
+ * object in which it is encapsulated.
+ *
+ * Return: None
+ */
+static void
+delete_action_frame_cookie(qdf_list_t *cookie_list,
+			   struct action_frame_cookie *action_cookie)
+{
+	qdf_list_remove_node(cookie_list, &action_cookie->cookie_node);
+	qdf_mem_free(action_cookie);
+}
+
+/**
+ * append_action_frame_cookie() - Append action cookie to given list
+ * @cookie_list: List of cookies
+ * @rnd_cookie: Cookie to be append
+ *
+ * This is a wrapper function which invokes allocate_action_frame_cookie
+ * if the cookie to be added is not duplicate
+ *
+ * Return: true - for successful case
+ *             false - failed.
+ */
+static bool
+append_action_frame_cookie(qdf_list_t *cookie_list, uint64_t rnd_cookie)
+{
+	struct action_frame_cookie *action_cookie;
+
+	/*
+	 * There should be no mac entry with empty cookie list,
+	 * check and ignore if duplicate
+	 */
+	action_cookie = find_action_frame_cookie(cookie_list, rnd_cookie);
+	if (action_cookie)
+		/* random mac address is already programmed */
+		return true;
+
+	/* insert new cookie in cookie list */
+	action_cookie = allocate_action_frame_cookie(cookie_list, rnd_cookie);
+	if (!action_cookie)
+		return false;
+
+	return true;
+}
+
+/**
+ * p2p_add_random_mac() - add or append random mac to given vdev rand mac list
+ * @soc: soc object
+ * @vdev_id: vdev id
+ * @mac: mac addr to be added or append
+ * @freq: frequency
+ * @rnd_cookie: random mac mgmt tx cookie
+ *
+ * This function will add or append the mac addr entry to vdev random mac list.
+ * Once the mac addr filter is not needed, it can be removed by
+ * p2p_del_random_mac.
+ *
+ * Return: QDF_STATUS_E_EXISTS - append to existing list
+ *             QDF_STATUS_SUCCESS - add a new entry.
+ *             other : failed to add the mac address entry.
+ */
+static QDF_STATUS
+p2p_add_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+		   uint8_t *mac, uint32_t freq, uint64_t rnd_cookie)
+{
+	uint32_t i;
+	uint32_t first_unused = MAX_RANDOM_MAC_ADDRS;
+	struct action_frame_cookie *action_cookie;
+	int32_t append_ret;
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	struct wlan_objmgr_vdev *vdev;
+
+	p2p_debug("random_mac:vdev %d mac_addr:%pM rnd_cookie=%llu freq = %u",
+		  vdev_id, mac, rnd_cookie, freq);
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_debug("vdev is null");
+
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(
+				vdev, WLAN_UMAC_COMP_P2P);
+	if (!p2p_vdev_obj) {
+		p2p_debug("random_mac:p2p vdev object is NULL");
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+		return QDF_STATUS_E_INVAL;
+	}
+
+	qdf_spin_lock(&p2p_vdev_obj->random_mac_lock);
+	/*
+	 * Following loop checks whether random mac entry is already
+	 * present, if present get the index of matched entry else
+	 * get the first unused slot to store this new random mac
+	 */
+	for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) {
+		if (!p2p_vdev_obj->random_mac[i].in_use) {
+			if (first_unused == MAX_RANDOM_MAC_ADDRS)
+				first_unused = i;
+			continue;
+		}
+
+		if (!qdf_mem_cmp(p2p_vdev_obj->random_mac[i].addr, mac,
+				 QDF_MAC_ADDR_SIZE))
+			break;
+	}
+
+	if (i != MAX_RANDOM_MAC_ADDRS) {
+		append_ret = append_action_frame_cookie(
+				&p2p_vdev_obj->random_mac[i].cookie_list,
+				rnd_cookie);
+		qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+		p2p_debug("random_mac:append %d vdev %d freq %d %pM rnd_cookie %llu",
+			  append_ret, vdev_id, freq, mac, rnd_cookie);
+		if (!append_ret) {
+			p2p_debug("random_mac:failed to append rnd_cookie");
+			return QDF_STATUS_E_NOMEM;
+		}
+
+		return QDF_STATUS_E_EXISTS;
+	}
+
+	if (first_unused == MAX_RANDOM_MAC_ADDRS) {
+		qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+		p2p_debug("random_mac:Reached the limit of Max random addresses");
+
+		return QDF_STATUS_E_RESOURCES;
+	}
+
+	/* get the first unused buf and store new random mac */
+	i = first_unused;
+
+	action_cookie = allocate_action_frame_cookie(
+				&p2p_vdev_obj->random_mac[i].cookie_list,
+				rnd_cookie);
+	if (!action_cookie) {
+		qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+		p2p_err("random_mac:failed to alloc rnd cookie");
+
+		return QDF_STATUS_E_NOMEM;
+	}
+	qdf_mem_copy(p2p_vdev_obj->random_mac[i].addr, mac, QDF_MAC_ADDR_SIZE);
+	p2p_vdev_obj->random_mac[i].in_use = true;
+	p2p_vdev_obj->random_mac[i].freq = freq;
+	qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+	p2p_debug("random_mac:add vdev %d freq %d %pM rnd_cookie %llu",
+		  vdev_id, freq, mac, rnd_cookie);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+p2p_del_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+		   uint64_t rnd_cookie, uint32_t duration)
+{
+	uint32_t i;
+	struct action_frame_cookie *action_cookie;
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	struct wlan_objmgr_vdev *vdev;
+
+	p2p_debug("random_mac:vdev %d cookie %llu duration %d", vdev_id,
+		  rnd_cookie, duration);
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id,
+						    WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_debug("vdev is null");
+		return QDF_STATUS_E_INVAL;
+	}
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(
+				vdev, WLAN_UMAC_COMP_P2P);
+	if (!p2p_vdev_obj) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+		p2p_debug("p2p vdev object is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	qdf_spin_lock(&p2p_vdev_obj->random_mac_lock);
+	for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) {
+		struct action_frame_random_mac *random_mac;
+
+		random_mac = &p2p_vdev_obj->random_mac[i];
+		if (!random_mac->in_use)
+			continue;
+
+		action_cookie = find_action_frame_cookie(
+				&random_mac->cookie_list, rnd_cookie);
+		if (!action_cookie)
+			continue;
+
+		delete_action_frame_cookie(
+			&random_mac->cookie_list,
+			action_cookie);
+
+		if (qdf_list_empty(&random_mac->cookie_list)) {
+			qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+			if (qdf_mc_timer_get_current_state(
+					&random_mac->clear_timer) ==
+			    QDF_TIMER_STATE_RUNNING)
+				qdf_mc_timer_stop(&random_mac->clear_timer);
+			qdf_mc_timer_start(&random_mac->clear_timer, duration);
+
+			qdf_spin_lock(&p2p_vdev_obj->random_mac_lock);
+			p2p_debug("random_mac:noref on vdev %d addr %pM",
+				  vdev_id, random_mac->addr);
+		}
+		break;
+	}
+	qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void p2p_del_all_rand_mac_vdev(struct wlan_objmgr_vdev *vdev)
+{
+	int32_t i;
+	uint32_t freq;
+	uint8_t addr[QDF_MAC_ADDR_SIZE];
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+
+	if (!vdev)
+		return;
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(
+				vdev, WLAN_UMAC_COMP_P2P);
+	if (!p2p_vdev_obj)
+		return;
+
+	qdf_spin_lock(&p2p_vdev_obj->random_mac_lock);
+	for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) {
+		struct action_frame_cookie *action_cookie;
+		struct action_frame_cookie *action_cookie_next;
+
+		if (!p2p_vdev_obj->random_mac[i].in_use)
+			continue;
+
+		/* empty the list and clear random addr */
+		qdf_list_for_each_del(&p2p_vdev_obj->random_mac[i].cookie_list,
+				      action_cookie, action_cookie_next,
+				      cookie_node) {
+			qdf_list_remove_node(
+				&p2p_vdev_obj->random_mac[i].cookie_list,
+				&action_cookie->cookie_node);
+			qdf_mem_free(action_cookie);
+		}
+
+		p2p_vdev_obj->random_mac[i].in_use = false;
+		freq = p2p_vdev_obj->random_mac[i].freq;
+		qdf_mem_copy(addr, p2p_vdev_obj->random_mac[i].addr,
+			     QDF_MAC_ADDR_SIZE);
+		qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+		qdf_mc_timer_stop(&p2p_vdev_obj->random_mac[i].clear_timer);
+		p2p_clear_mac_filter(wlan_vdev_get_psoc(vdev),
+				     wlan_vdev_get_id(vdev), addr, freq);
+		p2p_debug("random_mac:delall vdev %d freq %d addr %pM",
+			  wlan_vdev_get_id(vdev), freq, addr);
+
+		qdf_spin_lock(&p2p_vdev_obj->random_mac_lock);
+	}
+	qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+}
+
+static void
+p2p_del_rand_mac_vdev_enum_handler(struct wlan_objmgr_psoc *psoc,
+				   void *obj, void *arg)
+{
+	struct wlan_objmgr_vdev *vdev = obj;
+
+	if (!vdev) {
+		p2p_err("random_mac:invalid vdev");
+		return;
+	}
+
+	if (!p2p_is_vdev_support_rand_mac(vdev))
+		return;
+
+	p2p_del_all_rand_mac_vdev(vdev);
+}
+
+void p2p_del_all_rand_mac_soc(struct wlan_objmgr_psoc *soc)
+{
+	if (!soc) {
+		p2p_err("random_mac:soc object is NULL");
+		return;
+	}
+
+	wlan_objmgr_iterate_obj_list(soc, WLAN_VDEV_OP,
+				     p2p_del_rand_mac_vdev_enum_handler,
+				     NULL, 0, WLAN_P2P_ID);
+}
+
+/**
+ * p2p_is_random_mac() - check mac addr is random mac for vdev
+ * @soc: soc object
+ * @vdev_id: vdev id
+ * @mac: mac addr to be added or append
+ *
+ * This function will check the source mac addr same as vdev's mac addr or not.
+ * If not same, then the source mac addr should be random mac addr.
+ *
+ * Return: true if mac is random mac, otherwise false
+ */
+static bool
+p2p_is_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, uint8_t *mac)
+{
+	bool ret = false;
+	struct wlan_objmgr_vdev *vdev;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_debug("random_mac:vdev is null");
+		return false;
+	}
+
+	if (qdf_mem_cmp(wlan_vdev_mlme_get_macaddr(vdev),
+			mac, QDF_MAC_ADDR_SIZE))
+		ret = true;
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return ret;
+}
+
+static void p2p_set_mac_filter_callback(bool result, void *context)
+{
+	struct osif_request *request;
+	struct random_mac_priv *priv;
+
+	p2p_debug("random_mac:set random mac filter result %d", result);
+	request = osif_request_get(context);
+	if (!request) {
+		p2p_err("random_mac:invalid response");
+		return;
+	}
+
+	priv = osif_request_priv(request);
+	priv->result = result;
+
+	osif_request_complete(request);
+	osif_request_put(request);
+}
+
+QDF_STATUS p2p_process_set_rand_mac_rsp(struct p2p_mac_filter_rsp *resp)
+{
+	struct wlan_objmgr_psoc *soc;
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	struct wlan_objmgr_vdev *vdev;
+
+	if (!resp || !resp->p2p_soc_obj || !resp->p2p_soc_obj->soc) {
+		p2p_debug("random_mac:set_filter_req is null");
+		return QDF_STATUS_E_INVAL;
+	}
+	p2p_debug("random_mac:process rsp on vdev %d status %d", resp->vdev_id,
+		  resp->status);
+	soc = resp->p2p_soc_obj->soc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, resp->vdev_id,
+						    WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_debug("random_mac:vdev is null vdev %d", resp->vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(
+				vdev, WLAN_UMAC_COMP_P2P);
+	if (!p2p_vdev_obj) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+		p2p_debug("random_mac:p2p_vdev_obj is null vdev %d",
+			  resp->vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+	if (!p2p_vdev_obj->pending_req.soc) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+		p2p_debug("random_mac:no pending set req for vdev %d",
+			  resp->vdev_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_debug("random_mac:get pending req on vdev %d set %d mac filter %pM freq %d",
+		  p2p_vdev_obj->pending_req.vdev_id,
+		  p2p_vdev_obj->pending_req.set, p2p_vdev_obj->pending_req.mac,
+		  p2p_vdev_obj->pending_req.freq);
+	if (p2p_vdev_obj->pending_req.cb)
+		p2p_vdev_obj->pending_req.cb(
+			!!resp->status, p2p_vdev_obj->pending_req.req_cookie);
+
+	qdf_mem_zero(&p2p_vdev_obj->pending_req,
+		     sizeof(p2p_vdev_obj->pending_req));
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+p2p_process_set_rand_mac(struct p2p_set_mac_filter_req *set_filter_req)
+{
+	struct wlan_objmgr_psoc *soc;
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct p2p_set_mac_filter param;
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	struct wlan_objmgr_vdev *vdev;
+
+	if (!set_filter_req || !set_filter_req->soc) {
+		p2p_debug("random_mac:set_filter_req is null");
+		return QDF_STATUS_E_INVAL;
+	}
+	p2p_debug("random_mac:vdev %d set %d mac filter %pM freq %d",
+		  set_filter_req->vdev_id, set_filter_req->set,
+		  set_filter_req->mac, set_filter_req->freq);
+
+	soc = set_filter_req->soc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+				soc, set_filter_req->vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_debug("random_mac:vdev is null vdev %d",
+			  set_filter_req->vdev_id);
+		goto get_vdev_failed;
+	}
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(
+				vdev, WLAN_UMAC_COMP_P2P);
+	if (!p2p_vdev_obj) {
+		p2p_debug("random_mac:p2p_vdev_obj is null vdev %d",
+			  set_filter_req->vdev_id);
+		goto get_p2p_obj_failed;
+	}
+	if (p2p_vdev_obj->pending_req.soc) {
+		p2p_debug("random_mac:Busy on vdev %d set %d mac filter %pM freq %d",
+			  p2p_vdev_obj->pending_req.vdev_id,
+			  p2p_vdev_obj->pending_req.set,
+			  p2p_vdev_obj->pending_req.mac,
+			  p2p_vdev_obj->pending_req.freq);
+		goto get_p2p_obj_failed;
+	}
+
+	p2p_ops = p2p_psoc_get_tx_ops(soc);
+	if (p2p_ops && p2p_ops->set_mac_addr_rx_filter_cmd) {
+		qdf_mem_zero(&param,  sizeof(param));
+		param.vdev_id = set_filter_req->vdev_id;
+		qdf_mem_copy(param.mac, set_filter_req->mac,
+			     QDF_MAC_ADDR_SIZE);
+		param.freq = set_filter_req->freq;
+		param.set = set_filter_req->set;
+		status = p2p_ops->set_mac_addr_rx_filter_cmd(soc, &param);
+		if (status == QDF_STATUS_SUCCESS && set_filter_req->set)
+			qdf_mem_copy(&p2p_vdev_obj->pending_req,
+				     set_filter_req, sizeof(*set_filter_req));
+		p2p_debug("random_mac:p2p set mac addr rx filter, status:%d",
+			  status);
+	}
+
+get_p2p_obj_failed:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+get_vdev_failed:
+	if (status != QDF_STATUS_SUCCESS &&
+	    set_filter_req->cb)
+		set_filter_req->cb(false, set_filter_req->req_cookie);
+
+	return status;
+}
+
+/**
+ * p2p_set_mac_filter() - send set mac addr filter cmd
+ * @soc: soc
+ * @vdev_id: vdev id
+ * @mac: mac addr
+ * @freq: freq
+ * @set: set or clear
+ * @cb: callback func to be called when the request completed.
+ * @req_cookie: cookie to be returned
+ *
+ * This function send set random mac addr filter command to p2p component
+ * msg core
+ *
+ * Return: QDF_STATUS_SUCCESS - if sent successfully.
+ *         otherwise : failed.
+ */
+static QDF_STATUS
+p2p_set_mac_filter(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+		   uint8_t *mac, uint32_t freq, bool set,
+		   p2p_request_mgr_callback_t cb, void *req_cookie)
+{
+	struct p2p_set_mac_filter_req *set_filter_req;
+	struct scheduler_msg msg = {0};
+	QDF_STATUS status;
+
+	p2p_debug("random_mac:vdev %d freq %d set %d %pM",
+		  vdev_id, freq, set, mac);
+
+	set_filter_req = qdf_mem_malloc(sizeof(*set_filter_req));
+	if (!set_filter_req)
+		return QDF_STATUS_E_NOMEM;
+
+	set_filter_req->soc = soc;
+	set_filter_req->vdev_id = vdev_id;
+	set_filter_req->freq = freq;
+	qdf_mem_copy(set_filter_req->mac, mac, QDF_MAC_ADDR_SIZE);
+	set_filter_req->set = set;
+	set_filter_req->cb = cb;
+	set_filter_req->req_cookie = req_cookie;
+
+	msg.type = P2P_SET_RANDOM_MAC;
+	msg.bodyptr = set_filter_req;
+	msg.callback = p2p_process_cmd;
+	status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+	if (status != QDF_STATUS_SUCCESS)
+		qdf_mem_free(set_filter_req);
+
+	return status;
+}
+
+QDF_STATUS
+p2p_clear_mac_filter(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+		     uint8_t *mac, uint32_t freq)
+{
+	return p2p_set_mac_filter(soc, vdev_id, mac, freq, false, NULL, NULL);
+}
+
+bool
+p2p_is_vdev_support_rand_mac(struct wlan_objmgr_vdev *vdev)
+{
+	enum QDF_OPMODE mode;
+
+	mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (mode == QDF_STA_MODE ||
+	    mode == QDF_P2P_CLIENT_MODE ||
+	    mode == QDF_P2P_DEVICE_MODE)
+		return true;
+	return false;
+}
+
+/**
+ * p2p_is_vdev_support_rand_mac_by_id() - check vdev type support random mac
+ * mgmt tx or not
+ * @soc: soc obj
+ * @vdev_id: vdev id
+ *
+ * Return: true: support random mac mgmt tx
+ *             false: not support random mac mgmt tx.
+ */
+static bool
+p2p_is_vdev_support_rand_mac_by_id(struct wlan_objmgr_psoc *soc,
+				   uint32_t vdev_id)
+{
+	struct wlan_objmgr_vdev *vdev;
+	bool ret = false;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID);
+	if (!vdev)
+		return false;
+	ret = p2p_is_vdev_support_rand_mac(vdev);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return ret;
+}
+
+/**
+ * p2p_set_rand_mac() - set random mac address rx filter
+ * @soc: soc
+ * @vdev_id: vdev id
+ * @mac: mac addr
+ * @freq: freq
+ * @rnd_cookie: cookie to be returned
+ *
+ * This function will post msg to p2p core to set random mac addr rx filter.
+ * It will wait the respone and return the result to caller.
+ *
+ * Return: true: set successfully
+ *             false: failed
+ */
+static bool
+p2p_set_rand_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+		 uint8_t *mac, uint32_t freq, uint64_t rnd_cookie)
+{
+	bool ret = false;
+	int err;
+	QDF_STATUS status;
+	struct osif_request *request;
+	static const struct osif_request_params params = {
+		.priv_size = sizeof(struct random_mac_priv),
+		.timeout_ms = WLAN_WAIT_TIME_SET_RND,
+	};
+	void *req_cookie;
+	struct random_mac_priv *priv;
+
+	request = osif_request_alloc(&params);
+	if (!request) {
+		p2p_err("Request allocation failure");
+		return false;
+	}
+
+	req_cookie = osif_request_cookie(request);
+
+	status = p2p_set_mac_filter(soc, vdev_id, mac, freq, true,
+				    p2p_set_mac_filter_callback, req_cookie);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("random_mac:set mac fitler failure %d", status);
+	} else {
+		err = osif_request_wait_for_response(request);
+		if (err) {
+			p2p_err("random_mac:timeout for set mac fitler %d",
+				err);
+		} else {
+			priv = osif_request_priv(request);
+			ret = priv->result;
+			p2p_debug("random_mac:vdev %d freq %d result %d %pM rnd_cookie %llu",
+				  vdev_id, freq, priv->result, mac, rnd_cookie);
+		}
+	}
+	osif_request_put(request);
+
+	return ret;
+}
+
+/**
+ * p2p_request_random_mac() - request random mac mgmt tx
+ * @soc: soc
+ * @vdev_id: vdev id
+ * @mac: mac addr
+ * @freq: freq
+ * @rnd_cookie: cookie to be returned
+ * @duration: duration of tx timeout
+ *
+ * This function will add/append the random mac addr filter entry to vdev.
+ * If it is new added entry, it will request to set filter in target.
+ *
+ * Return: QDF_STATUS_SUCCESS: request successfully
+ *             other: failed
+ */
+static QDF_STATUS
+p2p_request_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+		       uint8_t *mac, uint32_t freq, uint64_t rnd_cookie,
+		       uint32_t duration)
+{
+	QDF_STATUS status;
+
+	status = p2p_add_random_mac(soc, vdev_id, mac, freq, rnd_cookie);
+	if (status == QDF_STATUS_E_EXISTS)
+		return QDF_STATUS_SUCCESS;
+	else if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	if (!p2p_set_rand_mac(soc, vdev_id, mac, freq, rnd_cookie))
+		status = p2p_del_random_mac(soc, vdev_id, rnd_cookie,
+					    duration);
+
+	return status;
+}
+
+void p2p_rand_mac_tx(struct  tx_action_context *tx_action)
+{
+	struct wlan_objmgr_psoc *soc;
+	QDF_STATUS status;
+
+	if (!tx_action || !tx_action->p2p_soc_obj ||
+	    !tx_action->p2p_soc_obj->soc)
+		return;
+	soc = tx_action->p2p_soc_obj->soc;
+
+	if (!tx_action->no_ack && tx_action->chan &&
+	    tx_action->buf_len > MIN_MAC_HEADER_LEN &&
+	    p2p_is_vdev_support_rand_mac_by_id(soc, tx_action->vdev_id) &&
+	    p2p_is_random_mac(soc, tx_action->vdev_id,
+			      &tx_action->buf[SRC_MAC_ADDR_OFFSET])) {
+		status = p2p_request_random_mac(
+					soc, tx_action->vdev_id,
+					&tx_action->buf[SRC_MAC_ADDR_OFFSET],
+					wlan_chan_to_freq(tx_action->chan),
+					tx_action->id,
+					tx_action->duration);
+		if (status == QDF_STATUS_SUCCESS)
+			tx_action->rand_mac_tx = true;
+		else
+			tx_action->rand_mac_tx = false;
+	}
+}
+
+void
+p2p_rand_mac_tx_done(struct wlan_objmgr_psoc *soc,
+		     struct tx_action_context *tx_ctx)
+{
+	if (!tx_ctx || !tx_ctx->rand_mac_tx || !soc)
+		return;
+
+	p2p_del_random_mac(soc, tx_ctx->vdev_id, tx_ctx->id, tx_ctx->duration);
+}
+
+/**
+ * p2p_mac_clear_timeout() - clear random mac filter timeout
+ * @context: timer context
+ *
+ * This function will clear the mac addr rx filter in target if no
+ * reference to it.
+ *
+ * Return: void
+ */
+static void p2p_mac_clear_timeout(void *context)
+{
+	struct action_frame_random_mac *random_mac = context;
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	uint32_t freq;
+	uint8_t addr[QDF_MAC_ADDR_SIZE];
+	uint32_t vdev_id;
+	bool clear = false;
+
+	if (!random_mac || !random_mac->p2p_vdev_obj) {
+		p2p_err("invalid context for mac_clear timeout");
+		return;
+	}
+	p2p_vdev_obj = random_mac->p2p_vdev_obj;
+	if (!p2p_vdev_obj || !p2p_vdev_obj->vdev)
+		return;
+
+	qdf_spin_lock(&p2p_vdev_obj->random_mac_lock);
+	if (qdf_list_empty(&random_mac->cookie_list)) {
+		random_mac->in_use = false;
+		clear = true;
+	}
+	freq = random_mac->freq;
+	qdf_mem_copy(addr, random_mac->addr, QDF_MAC_ADDR_SIZE);
+	qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock);
+
+	vdev_id = wlan_vdev_get_id(p2p_vdev_obj->vdev);
+	p2p_debug("random_mac:clear timeout vdev %d %pM freq %d clr %d",
+		  vdev_id, addr, freq, clear);
+	if (clear)
+		p2p_clear_mac_filter(wlan_vdev_get_psoc(p2p_vdev_obj->vdev),
+				     vdev_id, addr, freq);
+}
+
+void p2p_init_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj)
+{
+	int32_t i;
+
+	qdf_spinlock_create(&p2p_vdev_obj->random_mac_lock);
+	for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) {
+		qdf_mem_zero(&p2p_vdev_obj->random_mac[i],
+			     sizeof(struct action_frame_random_mac));
+		p2p_vdev_obj->random_mac[i].in_use = false;
+		p2p_vdev_obj->random_mac[i].p2p_vdev_obj = p2p_vdev_obj;
+		qdf_list_create(&p2p_vdev_obj->random_mac[i].cookie_list, 0);
+		qdf_mc_timer_init(&p2p_vdev_obj->random_mac[i].clear_timer,
+				  QDF_TIMER_TYPE_SW, p2p_mac_clear_timeout,
+				  &p2p_vdev_obj->random_mac[i]);
+	}
+}
+
+void p2p_deinit_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj)
+{
+	int32_t i;
+
+	p2p_del_all_rand_mac_vdev(p2p_vdev_obj->vdev);
+	for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) {
+		qdf_mc_timer_destroy(&p2p_vdev_obj->random_mac[i].clear_timer);
+		qdf_list_destroy(&p2p_vdev_obj->random_mac[i].cookie_list);
+	}
+	qdf_spinlock_destroy(&p2p_vdev_obj->random_mac_lock);
+}
+
+QDF_STATUS p2p_process_mgmt_tx(struct tx_action_context *tx_ctx)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *curr_roc_ctx;
+	uint8_t *mac_to;
+	QDF_STATUS status;
+
+	status = p2p_tx_context_check_valid(tx_ctx);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("invalid tx action context");
+		if (tx_ctx) {
+			if (tx_ctx->buf) {
+				p2p_send_tx_conf(tx_ctx, false);
+				qdf_mem_free(tx_ctx->buf);
+			}
+			qdf_mem_free(tx_ctx);
+		}
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = tx_ctx->p2p_soc_obj;
+
+	p2p_debug("soc:%pK, tx_ctx:%pK, vdev_id:%d, scan_id:%d, roc_cookie:%llx, chan:%d, buf:%pK, len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d",
+		p2p_soc_obj->soc, tx_ctx, tx_ctx->vdev_id,
+		tx_ctx->scan_id, tx_ctx->roc_cookie, tx_ctx->chan,
+		tx_ctx->buf, tx_ctx->buf_len, tx_ctx->off_chan,
+		tx_ctx->no_cck, tx_ctx->no_ack, tx_ctx->duration);
+
+	status = p2p_get_frame_info(tx_ctx->buf, tx_ctx->buf_len,
+			&(tx_ctx->frame_info));
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("unsupport frame");
+		status = QDF_STATUS_E_INVAL;
+		goto fail;
+	}
+
+	/* update P2P connection status with tx frame info */
+	mac_to = &(tx_ctx->buf[DST_MAC_ADDR_OFFSET]);
+	p2p_tx_update_connection_status(p2p_soc_obj,
+		&(tx_ctx->frame_info), mac_to);
+
+	status = p2p_vdev_check_valid(tx_ctx);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_debug("invalid vdev or vdev mode");
+		status = QDF_STATUS_E_INVAL;
+		goto fail;
+	}
+
+	/* Do not wait for ack for probe response */
+	if (tx_ctx->frame_info.sub_type == P2P_MGMT_PROBE_RSP &&
+		!(tx_ctx->no_ack)) {
+		p2p_debug("Force set no ack to 1");
+		tx_ctx->no_ack = 1;
+	}
+
+	if (!tx_ctx->off_chan) {
+		status = p2p_execute_tx_action_frame(tx_ctx);
+		if (status != QDF_STATUS_SUCCESS) {
+			p2p_err("execute tx fail");
+			goto fail;
+		} else
+			return QDF_STATUS_SUCCESS;
+	}
+
+	/* For off channel tx case */
+	curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj);
+	if (curr_roc_ctx && (curr_roc_ctx->chan == tx_ctx->chan)) {
+		if ((curr_roc_ctx->roc_state == ROC_STATE_REQUESTED) ||
+		    (curr_roc_ctx->roc_state == ROC_STATE_STARTED)) {
+			tx_ctx->roc_cookie = (uintptr_t)curr_roc_ctx;
+			status = qdf_list_insert_back(
+					&p2p_soc_obj->tx_q_roc,
+					&tx_ctx->node);
+			if (status != QDF_STATUS_SUCCESS) {
+				p2p_err("Failed to insert off chan tx context to wait roc req queue");
+				goto fail;
+			} else
+				return QDF_STATUS_SUCCESS;
+		} else if (curr_roc_ctx->roc_state == ROC_STATE_ON_CHAN) {
+			p2p_adjust_tx_wait(tx_ctx);
+			status = p2p_restart_roc_timer(curr_roc_ctx);
+			curr_roc_ctx->tx_ctx = tx_ctx;
+			if (status != QDF_STATUS_SUCCESS) {
+				p2p_err("restart roc timer fail");
+				goto fail;
+			}
+			status = p2p_execute_tx_action_frame(tx_ctx);
+			if (status != QDF_STATUS_SUCCESS) {
+				p2p_err("execute tx fail");
+				goto fail;
+			} else
+				return QDF_STATUS_SUCCESS;
+		}
+	}
+
+	curr_roc_ctx = p2p_find_roc_by_chan(p2p_soc_obj, tx_ctx->chan);
+	if (curr_roc_ctx && (curr_roc_ctx->roc_state == ROC_STATE_IDLE)) {
+		tx_ctx->roc_cookie = (uintptr_t)curr_roc_ctx;
+		status = qdf_list_insert_back(
+				&p2p_soc_obj->tx_q_roc,
+				&tx_ctx->node);
+		if (status != QDF_STATUS_SUCCESS) {
+			p2p_err("Failed to insert off chan tx context to wait roc req queue");
+			goto fail;
+		} else {
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+
+	status = p2p_roc_req_for_tx_action(tx_ctx);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to request roc before off chan tx");
+		goto fail;
+	}
+
+	return QDF_STATUS_SUCCESS;
+
+fail:
+	p2p_send_tx_conf(tx_ctx, false);
+	qdf_idr_remove(&p2p_soc_obj->p2p_idr, tx_ctx->id);
+	qdf_mem_free(tx_ctx->buf);
+	qdf_mem_free(tx_ctx);
+
+	return status;
+}
+
+QDF_STATUS p2p_process_mgmt_tx_cancel(
+	struct cancel_roc_context *cancel_tx)
+{
+	bool is_roc_q = false;
+	bool is_ack_q = false;
+	struct tx_action_context *cur_tx_ctx;
+	struct p2p_roc_context *cur_roc_ctx;
+	struct cancel_roc_context cancel_roc;
+
+	if (!cancel_tx || !(cancel_tx->cookie)) {
+		p2p_info("invalid cancel info");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	p2p_debug("cookie:0x%llx", cancel_tx->cookie);
+
+	cur_tx_ctx = p2p_find_tx_ctx(cancel_tx->p2p_soc_obj,
+			cancel_tx->cookie, &is_roc_q, &is_ack_q);
+	if (cur_tx_ctx) {
+		if (is_roc_q) {
+			cancel_roc.p2p_soc_obj =
+					cancel_tx->p2p_soc_obj;
+			cancel_roc.cookie =
+					cur_tx_ctx->roc_cookie;
+			return p2p_process_cancel_roc_req(&cancel_roc);
+		}
+		if (is_ack_q) {
+			/*Has tx action frame, waiting for ack*/
+			p2p_debug("Waiting for ack, cookie %llx",
+				cancel_tx->cookie);
+		}
+	} else {
+		p2p_debug("Failed to find tx ctx by cookie, cookie %llx",
+			cancel_tx->cookie);
+
+		cur_roc_ctx = p2p_find_roc_by_tx_ctx(cancel_tx->p2p_soc_obj,
+					cancel_tx->cookie);
+		if (cur_roc_ctx) {
+			p2p_debug("tx ctx:%llx, roc:%pK",
+				cancel_tx->cookie, cur_roc_ctx);
+			cancel_roc.p2p_soc_obj =
+					cancel_tx->p2p_soc_obj;
+			cancel_roc.cookie = (uintptr_t) cur_roc_ctx;
+			return p2p_process_cancel_roc_req(&cancel_roc);
+		}
+
+		p2p_debug("Failed to find roc by tx ctx");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_process_mgmt_tx_ack_cnf(
+	struct p2p_tx_conf_event *tx_cnf_event)
+{
+	struct p2p_tx_cnf tx_cnf;
+	struct tx_action_context *tx_ctx;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_start_param *start_param;
+
+	p2p_soc_obj = tx_cnf_event->p2p_soc_obj;
+
+	if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) {
+		qdf_nbuf_free(tx_cnf_event->nbuf);
+		p2p_err("Invalid p2p soc object or start parameters");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	tx_ctx = p2p_find_tx_ctx_by_nbuf(p2p_soc_obj, tx_cnf_event->nbuf);
+	qdf_nbuf_free(tx_cnf_event->nbuf);
+	if (!tx_ctx) {
+		p2p_err("can't find tx_ctx, tx ack comes late");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	tx_cnf.vdev_id = tx_ctx->vdev_id;
+	tx_cnf.action_cookie = (uint64_t)tx_ctx->id;
+	tx_cnf.buf = tx_ctx->buf;
+	tx_cnf.buf_len = tx_ctx->buf_len;
+	tx_cnf.status = tx_cnf_event->status;
+
+	p2p_debug("soc:%pK, vdev_id:%d, action_cookie:%llx, len:%d, status:%d, buf:%pK",
+		p2p_soc_obj->soc, tx_cnf.vdev_id,
+		tx_cnf.action_cookie, tx_cnf.buf_len,
+		tx_cnf.status, tx_cnf.buf);
+
+	p2p_rand_mac_tx_done(p2p_soc_obj->soc, tx_ctx);
+
+	/* disable tx timer */
+	p2p_disable_tx_timer(tx_ctx);
+
+	start_param = p2p_soc_obj->start_param;
+	if (start_param->tx_cnf_cb)
+		start_param->tx_cnf_cb(start_param->tx_cnf_cb_data,
+					&tx_cnf);
+	else
+		p2p_debug("Got tx conf, but no valid up layer callback");
+
+	p2p_remove_tx_context(tx_ctx);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_process_rx_mgmt(
+	struct p2p_rx_mgmt_event *rx_mgmt_event)
+{
+	struct p2p_rx_mgmt_frame *rx_mgmt;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_start_param *start_param;
+	struct p2p_frame_info frame_info;
+	uint8_t *mac_from;
+
+	p2p_soc_obj = rx_mgmt_event->p2p_soc_obj;
+	rx_mgmt = rx_mgmt_event->rx_mgmt;
+
+	if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) {
+		p2p_err("Invalid psoc object or start parameters");
+		qdf_mem_free(rx_mgmt);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_debug("soc:%pK, frame_len:%d, rx_chan:%d, vdev_id:%d, frm_type:%d, rx_rssi:%d, buf:%pK",
+		p2p_soc_obj->soc, rx_mgmt->frame_len,
+		rx_mgmt->rx_chan, rx_mgmt->vdev_id, rx_mgmt->frm_type,
+		rx_mgmt->rx_rssi, rx_mgmt->buf);
+
+	if (rx_mgmt->frm_type == MGMT_ACTION_VENDOR_SPECIFIC) {
+		p2p_get_frame_info(rx_mgmt->buf, rx_mgmt->frame_len,
+				&frame_info);
+
+		/* update P2P connection status with rx frame info */
+		mac_from = &(rx_mgmt->buf[SRC_MAC_ADDR_OFFSET]);
+		p2p_rx_update_connection_status(p2p_soc_obj,
+						&frame_info, mac_from);
+
+		p2p_debug("action_sub_type %u, action_type %d",
+				frame_info.public_action_type,
+				frame_info.action_type);
+
+		if ((frame_info.public_action_type ==
+			P2P_PUBLIC_ACTION_NOT_SUPPORT) &&
+		   (frame_info.action_type ==
+			P2P_ACTION_NOT_SUPPORT)) {
+			p2p_debug("non-p2p frame, drop it");
+			qdf_mem_free(rx_mgmt);
+			return QDF_STATUS_SUCCESS;
+		} else {
+			p2p_debug("p2p frame, extend roc accordingly");
+			p2p_extend_roc_timer(p2p_soc_obj, &frame_info);
+		}
+	}
+
+	if (rx_mgmt->frm_type == MGMT_ACTION_CATEGORY_VENDOR_SPECIFIC)
+		p2p_get_frame_info(rx_mgmt->buf, rx_mgmt->frame_len,
+				&frame_info);
+
+	start_param = p2p_soc_obj->start_param;
+	if (start_param->rx_cb)
+		start_param->rx_cb(start_param->rx_cb_data, rx_mgmt);
+	else
+		p2p_debug("rx mgmt, but no valid up layer callback");
+
+	qdf_mem_free(rx_mgmt);
+
+	return QDF_STATUS_SUCCESS;
+}

+ 439 - 0
components/p2p/core/src/wlan_p2p_off_chan_tx.h

@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: Defines off channel tx API & structures
+ */
+
+#ifndef _WLAN_P2P_OFF_CHAN_TX_H_
+#define _WLAN_P2P_OFF_CHAN_TX_H_
+
+#include <qdf_types.h>
+#include <qdf_mc_timer.h>
+#include <qdf_list.h>
+
+#define P2P_EID_VENDOR                          0xdd
+#define P2P_ACTION_VENDOR_SPECIFIC_CATEGORY     0x7F
+#define P2P_PUBLIC_ACTION_FRAME                 0x4
+#define P2P_MAC_MGMT_ACTION                     0xD
+#define P2P_PUBLIC_ACTION_VENDOR_SPECIFIC       0x9
+#define P2P_NOA_ATTR                            0xC
+
+#define P2P_MAX_NOA_ATTR_LEN                    31
+#define P2P_IE_HEADER_LEN                       6
+#define P2P_MAX_IE_LENGTH                       255
+#define P2P_ACTION_OFFSET                       24
+#define P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET     30
+#define P2P_ACTION_FRAME_TYPE_OFFSET            29
+#define PROBE_RSP_IE_OFFSET                     36
+
+#define P2P_TX_PKT_MIN_HEADROOM                (64)
+
+#define P2P_OUI                                 "\x50\x6f\x9a\x09"
+#define P2P_OUI_SIZE                            4
+
+#define P2P_ACTION_FRAME_RSP_WAIT               500
+#define P2P_ACTION_FRAME_ACK_WAIT               300
+#define P2P_ACTION_FRAME_TX_TIMEOUT             2000
+
+#define DST_MAC_ADDR_OFFSET  4
+#define SRC_MAC_ADDR_OFFSET  (DST_MAC_ADDR_OFFSET + QDF_MAC_ADDR_SIZE)
+
+#define P2P_NOA_STREAM_ARR_SIZE (P2P_MAX_NOA_ATTR_LEN + (2 * P2P_IE_HEADER_LEN))
+
+#define P2P_GET_TYPE_FRM_FC(__fc__)         (((__fc__) & 0x0F) >> 2)
+#define P2P_GET_SUBTYPE_FRM_FC(__fc__)      (((__fc__) & 0xF0) >> 4)
+
+#define WLAN_WAIT_TIME_SET_RND 100
+
+struct p2p_soc_priv_obj;
+struct cancel_roc_context;
+struct p2p_tx_conf_event;
+struct p2p_rx_mgmt_event;
+
+/**
+ * enum p2p_frame_type - frame type
+ * @P2P_FRAME_MGMT:         mgmt frame
+ * @P2P_FRAME_NOT_SUPPORT:  not support frame type
+ */
+enum p2p_frame_type {
+	P2P_FRAME_MGMT = 0,
+	P2P_FRAME_NOT_SUPPORT,
+};
+
+/**
+ * enum p2p_frame_sub_type - frame sub type
+ * @P2P_MGMT_PROBE_REQ:       probe request frame
+ * @P2P_MGMT_PROBE_RSP:       probe response frame
+ * @P2P_MGMT_ACTION:          action frame
+ * @P2P_MGMT_NOT_SUPPORT:     not support sub frame type
+ */
+enum p2p_frame_sub_type {
+	P2P_MGMT_PROBE_REQ = 4,
+	P2P_MGMT_PROBE_RSP,
+	P2P_MGMT_ACTION = 13,
+	P2P_MGMT_NOT_SUPPORT,
+};
+
+/**
+ * enum p2p_public_action_type - public action frame type
+ * @P2P_PUBLIC_ACTION_NEG_REQ:       go negotiation request frame
+ * @P2P_PUBLIC_ACTION_NEG_RSP:       go negotiation response frame
+ * @P2P_PUBLIC_ACTION_NEG_CNF:       go negotiation confirm frame
+ * @P2P_PUBLIC_ACTION_INVIT_REQ:     p2p invitation request frame
+ * @P2P_PUBLIC_ACTION_INVIT_RSP:     p2p invitation response frame
+ * @P2P_PUBLIC_ACTION_DEV_DIS_REQ:   device discoverability request
+ * @P2P_PUBLIC_ACTION_DEV_DIS_RSP:   device discoverability response
+ * @P2P_PUBLIC_ACTION_PROV_DIS_REQ:  provision discovery request
+ * @P2P_PUBLIC_ACTION_PROV_DIS_RSP:  provision discovery response
+ * @P2P_PUBLIC_ACTION_GAS_INIT_REQ:  gas initial request,
+ * @P2P_PUBLIC_ACTION_GAS_INIT_RSP:  gas initial response
+ * @P2P_PUBLIC_ACTION_GAS_COMB_REQ:  gas comeback request
+ * @P2P_PUBLIC_ACTION_GAS_COMB_RSP:  gas comeback response
+ * @P2P_PUBLIC_ACTION_NOT_SUPPORT:   not support p2p public action frame
+ */
+enum p2p_public_action_type {
+	P2P_PUBLIC_ACTION_NEG_REQ = 0,
+	P2P_PUBLIC_ACTION_NEG_RSP,
+	P2P_PUBLIC_ACTION_NEG_CNF,
+	P2P_PUBLIC_ACTION_INVIT_REQ,
+	P2P_PUBLIC_ACTION_INVIT_RSP,
+	P2P_PUBLIC_ACTION_DEV_DIS_REQ,
+	P2P_PUBLIC_ACTION_DEV_DIS_RSP,
+	P2P_PUBLIC_ACTION_PROV_DIS_REQ,
+	P2P_PUBLIC_ACTION_PROV_DIS_RSP,
+	P2P_PUBLIC_ACTION_GAS_INIT_REQ = 10,
+	P2P_PUBLIC_ACTION_GAS_INIT_RSP,
+	P2P_PUBLIC_ACTION_GAS_COMB_REQ,
+	P2P_PUBLIC_ACTION_GAS_COMB_RSP,
+	P2P_PUBLIC_ACTION_NOT_SUPPORT,
+};
+
+/**
+ * enum p2p_action_type - p2p action frame type
+ * @P2P_ACTION_PRESENCE_REQ:    presence request frame
+ * @P2P_ACTION_PRESENCE_RSP:    presence response frame
+ * @P2P_ACTION_NOT_SUPPORT:     not support action frame type
+ */
+enum p2p_action_type {
+	P2P_ACTION_PRESENCE_REQ = 1,
+	P2P_ACTION_PRESENCE_RSP = 2,
+	P2P_ACTION_NOT_SUPPORT,
+};
+
+struct p2p_frame_info {
+	enum p2p_frame_type type;
+	enum p2p_frame_sub_type sub_type;
+	enum p2p_public_action_type public_action_type;
+	enum p2p_action_type action_type;
+};
+
+/**
+ * struct tx_action_context - tx action frame context
+ * @node:           Node for next element in the list
+ * @p2p_soc_obj:    Pointer to SoC global p2p private object
+ * @vdev_id:        Vdev id on which this request has come
+ * @scan_id:        Scan id given by scan component for this roc req
+ * @roc_cookie:     Cookie for remain on channel request
+ * @id:             Identifier of this tx context
+ * @chan:           Chan for which this tx has been requested
+ * @buf:            tx buffer
+ * @buf_len:        Length of tx buffer
+ * @off_chan:       Is this off channel tx
+ * @no_cck:         Required cck or not
+ * @no_ack:         Required ack or not
+ * @duration:       Duration for the RoC
+ * @tx_timer:       RoC timer
+ * @frame_info:     Frame type information
+ */
+struct tx_action_context {
+	qdf_list_node_t node;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	int vdev_id;
+	int scan_id;
+	uint64_t roc_cookie;
+	int32_t id;
+	uint8_t chan;
+	uint8_t *buf;
+	int buf_len;
+	bool off_chan;
+	bool no_cck;
+	bool no_ack;
+	bool rand_mac_tx;
+	uint32_t duration;
+	qdf_mc_timer_t tx_timer;
+	struct p2p_frame_info frame_info;
+	qdf_nbuf_t nbuf;
+};
+
+/**
+ * p2p_rand_mac_tx_done() - process random mac mgmt tx done
+ * @soc: soc
+ * @tx_ctx: tx context
+ *
+ * This function will remove the random mac addr filter reference.
+ *
+ * Return: void
+ */
+void
+p2p_rand_mac_tx_done(struct wlan_objmgr_psoc *soc,
+		     struct tx_action_context *tx_ctx);
+
+/**
+ * p2p_clear_mac_filter() - send clear mac addr filter cmd
+ * @soc: soc
+ * @vdev_id: vdev id
+ * @mac: mac addr
+ * @freq: freq
+ *
+ * This function send clear random mac addr filter command to p2p component
+ * msg core
+ *
+ * Return: QDF_STATUS_SUCCESS - if sent successfully.
+ *         otherwise: failed.
+ */
+QDF_STATUS
+p2p_clear_mac_filter(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+		     uint8_t *mac, uint32_t freq);
+
+/**
+ * p2p_is_vdev_support_rand_mac() - check vdev type support random mac mgmt
+ *    tx or not
+ * @vdev: vdev object
+ *
+ * Return: true: support random mac mgmt tx
+ *         false: not support random mac mgmt tx.
+ */
+bool
+p2p_is_vdev_support_rand_mac(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * p2p_dump_tx_queue() - dump tx queue
+ * @p2p_soc_obj: p2p soc private object
+ *
+ * This function dumps tx queue and output details about tx context in
+ * queue.
+ *
+ * Return: None
+ */
+void p2p_dump_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj);
+
+/**
+ * p2p_ready_to_tx_frame() - dump tx queue
+ * @p2p_soc_obj: p2p soc private object
+ * @cookie: cookie is pointer to roc
+ *
+ * This function find out the tx context in wait for roc queue and tx
+ * this frame.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_ready_to_tx_frame(struct p2p_soc_priv_obj *p2p_soc_obj,
+	uint64_t cookie);
+
+/**
+ * p2p_cleanup_tx_sync() - Cleanup tx queue
+ * @p2p_soc_obj: p2p psoc private object
+ * @vdev:        vdev object
+ *
+ * This function cleanup tx context in queue until cancellation done.
+ * To avoid deadlock, don't call from scheduler thread.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_cleanup_tx_sync(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct wlan_objmgr_vdev *vdev);
+
+/**
+ * p2p_process_cleanup_tx_queue() - process the message to cleanup tx
+ * @param: pointer to cleanup parameters
+ *
+ * This function cleanup wait for roc queue and wait for ack queue.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_cleanup_tx_queue(
+	struct p2p_cleanup_param *param);
+
+/**
+ * p2p_process_mgmt_tx() - Process mgmt frame tx request
+ * @tx_ctx: tx context
+ *
+ * This function handles mgmt frame tx request. It will call API from
+ * mgmt txrx component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_mgmt_tx(struct tx_action_context *tx_ctx);
+
+/**
+ * p2p_process_mgmt_tx_cancel() - Process cancel mgmt frame tx request
+ * @cancel_tx: cancel tx context
+ *
+ * This function cancel mgmt frame tx request by cookie.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_mgmt_tx_cancel(
+	struct cancel_roc_context *cancel_tx);
+
+/**
+ * p2p_process_mgmt_tx_ack_cnf() - Process tx ack event
+ * @tx_cnf_event: tx confirmation event information
+ *
+ * This function mgmt frame tx confirmation. It will deliver this
+ * event to up layer
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_mgmt_tx_ack_cnf(
+	struct p2p_tx_conf_event *tx_cnf_event);
+
+/**
+ * p2p_process_rx_mgmt() - Process rx mgmt frame event
+ * @rx_mgmt_event: rx mgmt frame event information
+ *
+ * This function mgmt frame rx mgmt frame event. It will deliver this
+ * event to up layer
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_rx_mgmt(
+	struct p2p_rx_mgmt_event *rx_mgmt_event);
+
+/**
+ * p2p_find_tx_ctx_by_nbuf() - find tx context by nbuf
+ * @p2p_soc_obj:        p2p soc object
+ * @nbuf:               pointer to nbuf
+ *
+ * This function finds out tx context by nbuf.
+ *
+ * Return: pointer to tx context
+ */
+struct tx_action_context *p2p_find_tx_ctx_by_nbuf(
+	struct p2p_soc_priv_obj *p2p_soc_obj, void *nbuf);
+
+#define P2P_80211_FRM_SA_OFFSET 10
+
+/**
+ * p2p_del_random_mac() - del mac fitler from given vdev rand mac list
+ * @soc: soc object
+ * @vdev_id: vdev id
+ * @rnd_cookie: random mac mgmt tx cookie
+ * @duration: timeout value to flush the addr in target.
+ *
+ * This function will del the mac addr filter from vdev random mac addr list.
+ * If there is no reference to mac addr, it will set a clear timer to flush it
+ * in target finally.
+ *
+ * Return: QDF_STATUS_SUCCESS - del successfully.
+ *             other : failed to del the mac address entry.
+ */
+QDF_STATUS
+p2p_del_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+		   uint64_t rnd_cookie, uint32_t duration);
+
+/**
+ * p2p_check_random_mac() - check random mac addr or not
+ * @soc: soc context
+ * @vdev_id: vdev id
+ * @random_mac_addr: mac addr to be checked
+ *
+ * This function check the input addr is random mac addr or not for vdev.
+ *
+ * Return: true if addr is random mac address else false.
+ */
+bool p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+			  uint8_t *random_mac_addr);
+
+/**
+ * p2p_process_set_rand_mac() - process the set random mac command
+ * @set_filter_req: request data
+ *
+ * This function will process the set mac addr filter command.
+ *
+ * Return: QDF_STATUS_SUCCESS: if process successfully
+ *             other: failed.
+ */
+QDF_STATUS p2p_process_set_rand_mac(
+		struct p2p_set_mac_filter_req *set_filter_req);
+
+/**
+ * p2p_process_set_rand_mac_rsp() - process the set random mac response
+ * @resp: response date
+ *
+ * This function will process the set mac addr filter event.
+ *
+ * Return: QDF_STATUS_SUCCESS: if process successfully
+ *             other: failed.
+ */
+QDF_STATUS p2p_process_set_rand_mac_rsp(struct p2p_mac_filter_rsp *resp);
+
+/**
+ * p2p_del_all_rand_mac_vdev() - del all random mac filter in vdev
+ * @vdev: vdev object
+ *
+ * This function will del all random mac filter in vdev
+ *
+ * Return: void
+ */
+void p2p_del_all_rand_mac_vdev(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * p2p_del_all_rand_mac_soc() - del all random mac filter in soc
+ * @soc: soc object
+ *
+ * This function will del all random mac filter in all vdev of soc
+ *
+ * Return: void
+ */
+void p2p_del_all_rand_mac_soc(struct wlan_objmgr_psoc *soc);
+
+/**
+ * p2p_rand_mac_tx() - handle random mac mgmt tx
+ * @tx_action: tx action context
+ *
+ * This function will check whether need to set random mac tx filter for a
+ * given mgmt tx request and do the mac addr filter process as needed.
+ *
+ * Return: void
+ */
+void p2p_rand_mac_tx(struct  tx_action_context *tx_action);
+
+/**
+ * p2p_init_random_mac_vdev() - Init random mac data for vdev
+ * @p2p_vdev_obj: p2p vdev private object
+ *
+ * This function will init the per vdev random mac data structure.
+ *
+ * Return: void
+ */
+void p2p_init_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj);
+
+/**
+ * p2p_deinit_random_mac_vdev() - Init random mac data for vdev
+ * @p2p_vdev_obj: p2p vdev private object
+ *
+ * This function will deinit the per vdev random mac data structure.
+ *
+ * Return: void
+ */
+void p2p_deinit_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj);
+
+#endif /* _WLAN_P2P_OFF_CHAN_TX_H_ */

+ 929 - 0
components/p2p/core/src/wlan_p2p_roc.c

@@ -0,0 +1,929 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: This file contains RoC API definitions
+ */
+
+#include <wlan_mgmt_txrx_utils_api.h>
+#include <wlan_scan_public_structs.h>
+#include <wlan_scan_ucfg_api.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_policy_mgr_api.h>
+#include <wlan_utility.h>
+#include "wlan_p2p_public_struct.h"
+#include "wlan_p2p_tgt_api.h"
+#include "wlan_p2p_ucfg_api.h"
+#include "wlan_p2p_roc.h"
+#include "wlan_p2p_main.h"
+#include "wlan_p2p_off_chan_tx.h"
+
+/**
+ * p2p_mgmt_rx_ops() - register or unregister rx callback
+ * @psoc: psoc object
+ * @isregister: register if true, unregister if false
+ *
+ * This function registers or unregisters rx callback to mgmt txrx
+ * component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc,
+	bool isregister)
+{
+	struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info;
+	QDF_STATUS status;
+
+	p2p_debug("psoc:%pK, is register rx:%d", psoc, isregister);
+
+	frm_cb_info.frm_type = MGMT_PROBE_REQ;
+	frm_cb_info.mgmt_rx_cb = tgt_p2p_mgmt_frame_rx_cb;
+
+	if (isregister)
+		status = wlan_mgmt_txrx_register_rx_cb(psoc,
+				WLAN_UMAC_COMP_P2P, &frm_cb_info, 1);
+	else
+		status = wlan_mgmt_txrx_deregister_rx_cb(psoc,
+				WLAN_UMAC_COMP_P2P, &frm_cb_info, 1);
+
+	return status;
+}
+
+/**
+ * p2p_scan_start() - Start scan
+ * @roc_ctx: remain on channel request
+ *
+ * This function trigger a start scan request to scan component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_scan_start(struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	struct scan_start_request *req;
+	struct wlan_objmgr_vdev *vdev;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+			p2p_soc_obj->soc, roc_ctx->vdev_id,
+			WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		p2p_err("failed to alloc scan start request");
+		status = QDF_STATUS_E_NOMEM;
+		goto fail;
+	}
+
+	ucfg_scan_init_default_params(vdev, req);
+	roc_ctx->scan_id = ucfg_scan_get_scan_id(p2p_soc_obj->soc);
+	req->vdev = vdev;
+	req->scan_req.scan_id = roc_ctx->scan_id;
+	req->scan_req.p2p_scan_type = SCAN_P2P_LISTEN;
+	req->scan_req.scan_req_id = p2p_soc_obj->scan_req_id;
+	req->scan_req.chan_list.num_chan = 1;
+	req->scan_req.chan_list.chan[0].freq = wlan_chan_to_freq(roc_ctx->chan);
+	req->scan_req.dwell_time_passive = roc_ctx->duration;
+	req->scan_req.dwell_time_active = 0;
+	req->scan_req.scan_priority = SCAN_PRIORITY_HIGH;
+	req->scan_req.num_bssid = 1;
+	qdf_set_macaddr_broadcast(&req->scan_req.bssid_list[0]);
+
+	status = ucfg_scan_start(req);
+
+	p2p_debug("start scan, scan req id:%d, scan id:%d, status:%d",
+		p2p_soc_obj->scan_req_id, roc_ctx->scan_id, status);
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return status;
+}
+
+/**
+ * p2p_scan_abort() - Abort scan
+ * @roc_ctx: remain on channel request
+ *
+ * This function trigger an abort scan request to scan component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_scan_abort(struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	struct scan_cancel_request *req;
+	struct wlan_objmgr_vdev *vdev;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("abort scan, scan req id:%d, scan id:%d",
+		p2p_soc_obj->scan_req_id, roc_ctx->scan_id);
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+			p2p_soc_obj->soc, roc_ctx->vdev_id,
+			WLAN_P2P_ID);
+	if (!vdev) {
+		p2p_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		p2p_err("failed to alloc scan cancel request");
+		status = QDF_STATUS_E_NOMEM;
+		goto fail;
+	}
+
+	req->vdev = vdev;
+	req->cancel_req.requester = p2p_soc_obj->scan_req_id;
+	req->cancel_req.scan_id = roc_ctx->scan_id;
+	req->cancel_req.vdev_id = roc_ctx->vdev_id;
+	req->cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE;
+
+	qdf_mtrace(QDF_MODULE_ID_P2P, QDF_MODULE_ID_SCAN,
+		   req->cancel_req.req_type,
+		   req->vdev->vdev_objmgr.vdev_id, req->cancel_req.scan_id);
+	status = ucfg_scan_cancel(req);
+
+	p2p_debug("abort scan, scan req id:%d, scan id:%d, status:%d",
+		p2p_soc_obj->scan_req_id, roc_ctx->scan_id, status);
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+
+	return status;
+}
+
+/**
+ * p2p_send_roc_event() - Send roc event
+ * @roc_ctx: remain on channel request
+ * @evt: roc event information
+ *
+ * This function send out roc event to up layer.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_send_roc_event(
+	struct p2p_roc_context *roc_ctx, enum p2p_roc_event evt)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_event p2p_evt;
+	struct p2p_start_param *start_param;
+
+	p2p_soc_obj = roc_ctx->p2p_soc_obj;
+	if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) {
+		p2p_err("Invalid p2p soc object or start parameters");
+		return QDF_STATUS_E_INVAL;
+	}
+	start_param = p2p_soc_obj->start_param;
+	if (!(start_param->event_cb)) {
+		p2p_err("Invalid p2p event callback to up layer");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_evt.vdev_id = roc_ctx->vdev_id;
+	p2p_evt.roc_event = evt;
+	p2p_evt.cookie = (uint64_t)roc_ctx->id;
+	p2p_evt.chan = roc_ctx->chan;
+	p2p_evt.duration = roc_ctx->duration;
+
+	p2p_debug("p2p soc_obj:%pK, roc_ctx:%pK, vdev_id:%d, roc_event:"
+		"%d, cookie:%llx, chan:%d, duration:%d", p2p_soc_obj,
+		roc_ctx, p2p_evt.vdev_id, p2p_evt.roc_event,
+		p2p_evt.cookie, p2p_evt.chan, p2p_evt.duration);
+
+	start_param->event_cb(start_param->event_cb_data, &p2p_evt);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_destroy_roc_ctx() - destroy roc ctx
+ * @roc_ctx:            remain on channel request
+ * @up_layer_event:     if send uplayer event
+ * @in_roc_queue:       if roc context in roc queue
+ *
+ * This function destroy roc context.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_destroy_roc_ctx(struct p2p_roc_context *roc_ctx,
+	bool up_layer_event, bool in_roc_queue)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("p2p_soc_obj:%pK, roc_ctx:%pK, up_layer_event:%d, in_roc_queue:%d",
+		p2p_soc_obj, roc_ctx, up_layer_event, in_roc_queue);
+
+	if (up_layer_event) {
+		if (roc_ctx->roc_state < ROC_STATE_ON_CHAN)
+			p2p_send_roc_event(roc_ctx, ROC_EVENT_READY_ON_CHAN);
+		p2p_send_roc_event(roc_ctx, ROC_EVENT_COMPLETED);
+	}
+
+	if (in_roc_queue) {
+		status = qdf_list_remove_node(&p2p_soc_obj->roc_q,
+				(qdf_list_node_t *)roc_ctx);
+		if (QDF_STATUS_SUCCESS != status)
+			p2p_err("Failed to remove roc req, status %d", status);
+	}
+
+	qdf_idr_remove(&p2p_soc_obj->p2p_idr, roc_ctx->id);
+	qdf_mem_free(roc_ctx);
+
+	return status;
+}
+
+/**
+ * p2p_execute_cancel_roc_req() - Execute cancel roc request
+ * @roc_ctx: remain on channel request
+ *
+ * This function stop roc timer, abort scan and unregister mgmt rx
+ * callbak.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_execute_cancel_roc_req(
+	struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	roc_ctx->roc_state = ROC_STATE_CANCEL_IN_PROG;
+	qdf_event_reset(&p2p_soc_obj->cancel_roc_done);
+	status = qdf_mc_timer_stop(&roc_ctx->roc_timer);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to stop roc timer, roc %pK", roc_ctx);
+
+	status = p2p_scan_abort(roc_ctx);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("Failed to abort scan, status:%d, destroy roc %pK",
+			status, roc_ctx);
+		qdf_mc_timer_destroy(&roc_ctx->roc_timer);
+		p2p_mgmt_rx_ops(p2p_soc_obj->soc, false);
+		p2p_destroy_roc_ctx(roc_ctx, true, true);
+		qdf_event_set(&p2p_soc_obj->cancel_roc_done);
+		return status;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_roc_timeout() - Callback for roc timeout
+ * @pdata: pointer to p2p soc private object
+ *
+ * This function is callback for roc time out.
+ *
+ * Return: None
+ */
+static void p2p_roc_timeout(void *pdata)
+{
+	struct p2p_roc_context *roc_ctx;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%pK", pdata);
+
+	p2p_soc_obj = pdata;
+	if (!p2p_soc_obj) {
+		p2p_err("Invalid p2p soc object");
+		return;
+	}
+
+	roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj);
+	if (!roc_ctx) {
+		p2p_debug("No P2P roc is pending");
+		return;
+	}
+
+	p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	if (roc_ctx->roc_state == ROC_STATE_CANCEL_IN_PROG) {
+		p2p_err("Cancellation already in progress");
+		return;
+	}
+	p2p_execute_cancel_roc_req(roc_ctx);
+}
+
+/**
+ * p2p_execute_roc_req() - Execute roc request
+ * @roc_ctx: remain on channel request
+ *
+ * This function init roc timer, start scan and register mgmt rx
+ * callbak.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_execute_roc_req(struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	uint32_t go_num;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	/* prevent runtime suspend */
+	qdf_runtime_pm_prevent_suspend(&p2p_soc_obj->roc_runtime_lock);
+
+	status = qdf_mc_timer_init(&roc_ctx->roc_timer,
+			QDF_TIMER_TYPE_SW, p2p_roc_timeout,
+			p2p_soc_obj);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to init roc timer, status:%d", status);
+		goto fail;
+	}
+
+	roc_ctx->roc_state = ROC_STATE_REQUESTED;
+	if (roc_ctx->duration < P2P_MAX_ROC_DURATION) {
+		go_num = policy_mgr_mode_specific_connection_count(
+				p2p_soc_obj->soc, PM_P2P_GO_MODE, NULL);
+		p2p_debug("present go number:%d", go_num);
+		if (go_num)
+			roc_ctx->duration *= P2P_ROC_DURATION_MULTI_GO_PRESENT;
+		else
+			roc_ctx->duration *= P2P_ROC_DURATION_MULTI_GO_ABSENT;
+		/* this is to protect too huge value if some customers
+		 * give a higher value from supplicant
+		 */
+		if (roc_ctx->duration > P2P_MAX_ROC_DURATION)
+			roc_ctx->duration = P2P_MAX_ROC_DURATION;
+	}
+	status = p2p_scan_start(roc_ctx);
+	if (status != QDF_STATUS_SUCCESS) {
+		qdf_mc_timer_destroy(&roc_ctx->roc_timer);
+		p2p_err("Failed to start scan, status:%d", status);
+		goto fail;
+	}
+
+fail:
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_destroy_roc_ctx(roc_ctx, true, true);
+		qdf_runtime_pm_allow_suspend(
+			&p2p_soc_obj->roc_runtime_lock);
+		return status;
+	}
+
+	p2p_soc_obj->cur_roc_vdev_id = roc_ctx->vdev_id;
+	status = p2p_mgmt_rx_ops(p2p_soc_obj->soc, true);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to register mgmt rx callback, status:%d",
+			status);
+
+	return status;
+}
+
+/**
+ * p2p_find_roc_ctx() - Find out roc context by cookie
+ * @p2p_soc_obj: p2p psoc private object
+ * @cookie: cookie is the key to find out roc context
+ *
+ * This function find out roc context by cookie from p2p psoc private
+ * object
+ *
+ * Return: Pointer to roc context - success
+ *         NULL                   - failure
+ */
+static struct p2p_roc_context *p2p_find_roc_ctx(
+	struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie)
+{
+	struct p2p_roc_context *curr_roc_ctx;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	p2p_debug("p2p soc obj:%pK, cookie:%llx", p2p_soc_obj, cookie);
+
+	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		curr_roc_ctx = qdf_container_of(p_node,
+					struct p2p_roc_context, node);
+		if ((uintptr_t) curr_roc_ctx == cookie)
+			return curr_roc_ctx;
+		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
+						p_node, &p_node);
+	}
+
+	return NULL;
+}
+
+/**
+ * p2p_process_scan_start_evt() - Process scan start event
+ * @roc_ctx: remain on channel request
+ *
+ * This function process scan start event.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_process_scan_start_evt(
+	struct p2p_roc_context *roc_ctx)
+{
+	roc_ctx->roc_state = ROC_STATE_STARTED;
+	p2p_debug("scan started, roc ctx:%pK, scan id:%d",
+		roc_ctx, roc_ctx->scan_id);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * p2p_process_ready_on_channel_evt() - Process ready on channel event
+ * @roc_ctx: remain on channel request
+ *
+ * This function process ready on channel event. Starts roc timer.
+ * Indicates this event to up layer if this is user request roc. Sends
+ * mgmt frame if this is off channel rx roc.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_process_ready_on_channel_evt(
+	struct p2p_roc_context *roc_ctx)
+{
+	uint64_t cookie;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status;
+
+	p2p_soc_obj = roc_ctx->p2p_soc_obj;
+	roc_ctx->roc_state = ROC_STATE_ON_CHAN;
+
+	p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	status = qdf_mc_timer_start(&roc_ctx->roc_timer,
+		(roc_ctx->duration + P2P_EVENT_PROPAGATE_TIME));
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Remain on Channel timer start failed");
+	if (roc_ctx->roc_type == USER_REQUESTED) {
+		p2p_debug("user required roc, send roc event");
+		status = p2p_send_roc_event(roc_ctx,
+				ROC_EVENT_READY_ON_CHAN);
+	}
+
+	cookie = (uintptr_t)roc_ctx;
+		/* ready to tx frame */
+	p2p_ready_to_tx_frame(p2p_soc_obj, cookie);
+
+	return status;
+}
+
+/**
+ * p2p_process_scan_complete_evt() - Process scan complete event
+ * @roc_ctx: remain on channel request
+ *
+ * This function process scan complete event.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+static QDF_STATUS p2p_process_scan_complete_evt(
+	struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status;
+	qdf_list_node_t *next_node;
+	uint32_t size;
+	struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	/* allow runtime suspend */
+	qdf_runtime_pm_allow_suspend(&p2p_soc_obj->roc_runtime_lock);
+
+	if (QDF_TIMER_STATE_RUNNING ==
+		qdf_mc_timer_get_current_state(&roc_ctx->roc_timer)) {
+		status = qdf_mc_timer_stop(&roc_ctx->roc_timer);
+		if (status != QDF_STATUS_SUCCESS)
+			p2p_err("Failed to stop roc timer");
+	}
+
+	status = qdf_mc_timer_destroy(&roc_ctx->roc_timer);
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to destroy roc timer");
+
+	status = p2p_mgmt_rx_ops(p2p_soc_obj->soc, false);
+	p2p_soc_obj->cur_roc_vdev_id = P2P_INVALID_VDEV_ID;
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("Failed to deregister mgmt rx callback");
+
+	if (roc_ctx->roc_type == USER_REQUESTED)
+		status = p2p_send_roc_event(roc_ctx,
+				ROC_EVENT_COMPLETED);
+
+	p2p_destroy_roc_ctx(roc_ctx, false, true);
+	qdf_event_set(&p2p_soc_obj->cancel_roc_done);
+
+	size = qdf_list_size(&p2p_soc_obj->roc_q);
+	p2p_debug("P2P roc queue size is %d", status);
+	if (size > 0) {
+		status = qdf_list_peek_front(&p2p_soc_obj->roc_q,
+				&next_node);
+		if (QDF_STATUS_SUCCESS != status) {
+			p2p_err("Failed to peek roc req from front, status %d",
+				status);
+			return status;
+		}
+		roc_ctx = qdf_container_of(next_node,
+				struct p2p_roc_context, node);
+		status = p2p_execute_roc_req(roc_ctx);
+	}
+	return status;
+}
+
+QDF_STATUS p2p_mgmt_rx_action_ops(struct wlan_objmgr_psoc *psoc,
+	bool isregister)
+{
+	struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info[2];
+	QDF_STATUS status;
+
+	p2p_debug("psoc:%pK, is register rx:%d", psoc, isregister);
+
+	frm_cb_info[0].frm_type = MGMT_ACTION_VENDOR_SPECIFIC;
+	frm_cb_info[0].mgmt_rx_cb = tgt_p2p_mgmt_frame_rx_cb;
+	frm_cb_info[1].frm_type = MGMT_ACTION_CATEGORY_VENDOR_SPECIFIC;
+	frm_cb_info[1].mgmt_rx_cb = tgt_p2p_mgmt_frame_rx_cb;
+
+	if (isregister)
+		status = wlan_mgmt_txrx_register_rx_cb(psoc,
+				WLAN_UMAC_COMP_P2P, frm_cb_info, 2);
+	else
+		status = wlan_mgmt_txrx_deregister_rx_cb(psoc,
+				WLAN_UMAC_COMP_P2P, frm_cb_info, 2);
+
+	return status;
+}
+
+struct p2p_roc_context *p2p_find_current_roc_ctx(
+	struct p2p_soc_priv_obj *p2p_soc_obj)
+{
+	struct p2p_roc_context *roc_ctx;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		roc_ctx = qdf_container_of(p_node,
+				struct p2p_roc_context, node);
+		if (roc_ctx->roc_state != ROC_STATE_IDLE) {
+			p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id"
+				":%d, scan_id:%d, tx ctx:%pK, chan:"
+				"%d, phy_mode:%d, duration:%d, "
+				"roc_type:%d, roc_state:%d",
+				roc_ctx->p2p_soc_obj, roc_ctx,
+				roc_ctx->vdev_id, roc_ctx->scan_id,
+				roc_ctx->tx_ctx, roc_ctx->chan,
+				roc_ctx->phy_mode, roc_ctx->duration,
+				roc_ctx->roc_type, roc_ctx->roc_state);
+
+			return roc_ctx;
+		}
+		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
+						p_node, &p_node);
+	}
+
+	return NULL;
+}
+
+struct p2p_roc_context *p2p_find_roc_by_tx_ctx(
+	struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie)
+{
+	struct p2p_roc_context *curr_roc_ctx;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	p2p_debug("p2p soc obj:%pK, cookie:%llx", p2p_soc_obj, cookie);
+
+	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		curr_roc_ctx = qdf_container_of(p_node,
+					struct p2p_roc_context, node);
+		if ((uintptr_t) curr_roc_ctx->tx_ctx == cookie)
+			return curr_roc_ctx;
+		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
+						p_node, &p_node);
+	}
+
+	return NULL;
+}
+
+struct p2p_roc_context *p2p_find_roc_by_chan(
+	struct p2p_soc_priv_obj *p2p_soc_obj, uint8_t chan)
+{
+	struct p2p_roc_context *roc_ctx;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		roc_ctx = qdf_container_of(p_node,
+					   struct p2p_roc_context,
+					   node);
+		if (roc_ctx->chan == chan) {
+			p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+				  roc_ctx->p2p_soc_obj, roc_ctx,
+				  roc_ctx->vdev_id, roc_ctx->scan_id,
+				  roc_ctx->tx_ctx, roc_ctx->chan,
+				  roc_ctx->phy_mode, roc_ctx->duration,
+				  roc_ctx->roc_type, roc_ctx->roc_state);
+
+			return roc_ctx;
+		}
+		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
+					    p_node, &p_node);
+	}
+
+	return NULL;
+}
+
+QDF_STATUS p2p_restart_roc_timer(struct p2p_roc_context *roc_ctx)
+{
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	if (QDF_TIMER_STATE_RUNNING ==
+		qdf_mc_timer_get_current_state(&roc_ctx->roc_timer)) {
+		p2p_debug("roc timer is running");
+		status = qdf_mc_timer_stop(&roc_ctx->roc_timer);
+		if (status != QDF_STATUS_SUCCESS) {
+			p2p_err("Failed to stop roc timer");
+			return status;
+		}
+
+		status = qdf_mc_timer_start(&roc_ctx->roc_timer,
+						roc_ctx->duration);
+		if (status != QDF_STATUS_SUCCESS)
+			p2p_err("Remain on Channel timer start failed");
+	}
+
+	return status;
+}
+
+QDF_STATUS p2p_cleanup_roc_sync(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct wlan_objmgr_vdev *vdev)
+{
+	struct scheduler_msg msg = {0};
+	struct p2p_cleanup_param *param;
+	QDF_STATUS status;
+	uint32_t vdev_id;
+
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	p2p_debug("p2p_soc_obj:%pK, vdev:%pK", p2p_soc_obj, vdev);
+	param = qdf_mem_malloc(sizeof(*param));
+	if (!param) {
+		p2p_err("failed to allocate cleanup param");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	param->p2p_soc_obj = p2p_soc_obj;
+	if (vdev)
+		vdev_id = (uint32_t)wlan_vdev_get_id(vdev);
+	else
+		vdev_id = P2P_INVALID_VDEV_ID;
+	param->vdev_id = vdev_id;
+	qdf_event_reset(&p2p_soc_obj->cleanup_roc_done);
+	msg.type = P2P_CLEANUP_ROC;
+	msg.bodyptr = param;
+	msg.callback = p2p_process_cmd;
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (status != QDF_STATUS_SUCCESS) {
+		p2p_err("failed to post message");
+		qdf_mem_free(param);
+		return status;
+	}
+
+	status = qdf_wait_single_event(
+			&p2p_soc_obj->cleanup_roc_done,
+			P2P_WAIT_CLEANUP_ROC);
+
+	if (status != QDF_STATUS_SUCCESS)
+		p2p_err("wait for cleanup roc timeout, %d", status);
+
+	return status;
+}
+
+QDF_STATUS p2p_process_cleanup_roc_queue(
+	struct p2p_cleanup_param *param)
+{
+	uint32_t vdev_id;
+	QDF_STATUS status, ret;
+	struct p2p_roc_context *roc_ctx;
+	qdf_list_node_t *p_node;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	if (!param || !(param->p2p_soc_obj)) {
+		p2p_err("Invalid cleanup param");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	p2p_soc_obj = param->p2p_soc_obj;
+	vdev_id = param->vdev_id;
+
+	p2p_debug("clean up idle roc request, roc queue size:%d, vdev id:%d",
+		  qdf_list_size(&p2p_soc_obj->roc_q), vdev_id);
+	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		roc_ctx = qdf_container_of(p_node,
+				struct p2p_roc_context, node);
+
+		p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+			  roc_ctx->p2p_soc_obj, roc_ctx,
+			  roc_ctx->vdev_id, roc_ctx->scan_id,
+			  roc_ctx->tx_ctx, roc_ctx->chan,
+			  roc_ctx->phy_mode, roc_ctx->duration,
+			  roc_ctx->roc_type, roc_ctx->roc_state);
+		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
+						p_node, &p_node);
+		if ((roc_ctx->roc_state == ROC_STATE_IDLE) &&
+		    ((vdev_id == P2P_INVALID_VDEV_ID) ||
+		     (vdev_id == roc_ctx->vdev_id))) {
+			ret = qdf_list_remove_node(
+					&p2p_soc_obj->roc_q,
+					(qdf_list_node_t *)roc_ctx);
+			if (ret == QDF_STATUS_SUCCESS)
+				qdf_mem_free(roc_ctx);
+			else
+				p2p_err("Failed to remove roc ctx from queue");
+		}
+	}
+
+	p2p_debug("clean up started roc request, roc queue size:%d",
+		  qdf_list_size(&p2p_soc_obj->roc_q));
+	status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		roc_ctx = qdf_container_of(p_node,
+				struct p2p_roc_context, node);
+
+		p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+			  roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+			  roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
+			  roc_ctx->phy_mode, roc_ctx->duration,
+			  roc_ctx->roc_type, roc_ctx->roc_state);
+
+		status = qdf_list_peek_next(&p2p_soc_obj->roc_q,
+						p_node, &p_node);
+		if ((roc_ctx->roc_state != ROC_STATE_IDLE) &&
+		    ((vdev_id == P2P_INVALID_VDEV_ID) ||
+		     (vdev_id == roc_ctx->vdev_id))) {
+			if (roc_ctx->roc_state !=
+			    ROC_STATE_CANCEL_IN_PROG)
+				p2p_execute_cancel_roc_req(roc_ctx);
+
+			ret = qdf_wait_single_event(
+				&p2p_soc_obj->cancel_roc_done,
+				P2P_WAIT_CANCEL_ROC);
+			p2p_debug("RoC cancellation done, return:%d", ret);
+		}
+	}
+
+	qdf_event_set(&p2p_soc_obj->cleanup_roc_done);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS p2p_process_roc_req(struct p2p_roc_context *roc_ctx)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *curr_roc_ctx;
+	QDF_STATUS status;
+	uint32_t size;
+
+	p2p_soc_obj = roc_ctx->p2p_soc_obj;
+
+	p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx_ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d",
+		p2p_soc_obj, roc_ctx, roc_ctx->vdev_id,
+		roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan,
+		roc_ctx->phy_mode, roc_ctx->duration,
+		roc_ctx->roc_type, roc_ctx->roc_state);
+
+	status = qdf_list_insert_back(&p2p_soc_obj->roc_q,
+			&roc_ctx->node);
+	if (QDF_STATUS_SUCCESS != status) {
+		p2p_destroy_roc_ctx(roc_ctx, true, false);
+		p2p_debug("Failed to insert roc req, status %d", status);
+		return status;
+	}
+
+	size = qdf_list_size(&p2p_soc_obj->roc_q);
+	if (size == 1) {
+		status = p2p_execute_roc_req(roc_ctx);
+	} else if (size > 1) {
+		curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj);
+		/*TODO, to handle extend roc */
+	}
+
+	return status;
+}
+
+QDF_STATUS p2p_process_cancel_roc_req(
+	struct cancel_roc_context *cancel_roc_ctx)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *curr_roc_ctx;
+	QDF_STATUS status;
+
+	p2p_soc_obj = cancel_roc_ctx->p2p_soc_obj;
+	curr_roc_ctx = p2p_find_roc_ctx(p2p_soc_obj,
+				cancel_roc_ctx->cookie);
+
+	p2p_debug("p2p soc obj:%pK, cookie:%llx, roc ctx:%pK",
+		p2p_soc_obj, cancel_roc_ctx->cookie, curr_roc_ctx);
+
+	if (!curr_roc_ctx) {
+		p2p_debug("Failed to find roc req by cookie, cookie %llx",
+				cancel_roc_ctx->cookie);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (curr_roc_ctx->roc_state == ROC_STATE_IDLE) {
+		status = p2p_destroy_roc_ctx(curr_roc_ctx, true, true);
+	} else if (curr_roc_ctx->roc_state ==
+				ROC_STATE_CANCEL_IN_PROG) {
+		p2p_debug("Receive cancel roc req when roc req is canceling, cookie %llx",
+			cancel_roc_ctx->cookie);
+		status = QDF_STATUS_SUCCESS;
+	} else {
+		status = p2p_execute_cancel_roc_req(curr_roc_ctx);
+	}
+
+	return status;
+}
+
+void p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev,
+	struct scan_event *event, void *arg)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *curr_roc_ctx;
+
+	p2p_debug("soc:%pK, scan event:%d", arg, event->type);
+
+	p2p_soc_obj = (struct p2p_soc_priv_obj *)arg;
+	if (!p2p_soc_obj) {
+		p2p_err("Invalid P2P context");
+		return;
+	}
+
+	curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj);
+	if (!curr_roc_ctx) {
+		p2p_err("Failed to find valid P2P roc context");
+		return;
+	}
+
+	qdf_mtrace(QDF_MODULE_ID_SCAN, QDF_MODULE_ID_P2P, event->type,
+		   event->vdev_id, event->scan_id);
+	switch (event->type) {
+	case SCAN_EVENT_TYPE_STARTED:
+		p2p_process_scan_start_evt(curr_roc_ctx);
+		break;
+	case SCAN_EVENT_TYPE_FOREIGN_CHANNEL:
+		p2p_process_ready_on_channel_evt(curr_roc_ctx);
+		break;
+	case SCAN_EVENT_TYPE_COMPLETED:
+	case SCAN_EVENT_TYPE_DEQUEUED:
+	case SCAN_EVENT_TYPE_START_FAILED:
+		p2p_process_scan_complete_evt(curr_roc_ctx);
+		break;
+	default:
+		p2p_debug("drop scan event, %d", event->type);
+	}
+}

+ 247 - 0
components/p2p/core/src/wlan_p2p_roc.h

@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: Defines RoC API & structures
+ */
+
+#ifndef _WLAN_P2P_ROC_H_
+#define _WLAN_P2P_ROC_H_
+
+#include <qdf_types.h>
+#include <qdf_mc_timer.h>
+#include <qdf_list.h>
+
+#define P2P_EVENT_PROPAGATE_TIME 10
+#define P2P_WAIT_CANCEL_ROC      1000
+#define P2P_WAIT_CLEANUP_ROC     2000
+#define P2P_MAX_ROC_DURATION     1500
+
+#define P2P_ROC_DURATION_MULTI_GO_PRESENT   6
+#define P2P_ROC_DURATION_MULTI_GO_ABSENT    10
+#define P2P_ACTION_FRAME_DEFAULT_WAIT       200
+
+struct wlan_objmgr_vdev;
+struct scan_event;
+
+/**
+ * enum roc_type - user requested or off channel tx
+ * @USER_REQUESTED:   Requested by supplicant
+ * @OFF_CHANNEL_TX:   Issued internally for off channel tx
+ */
+enum roc_type {
+	USER_REQUESTED,
+	OFF_CHANNEL_TX,
+};
+
+/**
+ * enum roc_state - P2P RoC state
+ * @ROC_STATE_IDLE:           RoC not yet started or completed
+ * @ROC_STATE_REQUESTED:      Sent scan command to scan manager
+ * @ROC_STATE_STARTED:        Got started event from scan manager
+ * @ROC_STATE_ON_CHAN:        Got foreign channel event from SCM
+ * @ROC_STATE_CANCEL_IN_PROG: Requested abort scan to SCM
+ * @ROC_STATE_INVALID:        We should not come to this state
+ */
+enum roc_state {
+	ROC_STATE_IDLE = 0,
+	ROC_STATE_REQUESTED,
+	ROC_STATE_STARTED,
+	ROC_STATE_ON_CHAN,
+	ROC_STATE_CANCEL_IN_PROG,
+	ROC_STATE_INVALID,
+};
+
+/**
+ * struct p2p_roc_context - RoC request context
+ * @node:        Node for next element in the list
+ * @p2p_soc_obj: Pointer to SoC global p2p private object
+ * @vdev_id:     Vdev id on which this request has come
+ * @scan_id:     Scan id given by scan component for this roc req
+ * @tx_ctx:      TX context if this ROC is for tx MGMT
+ * @chan:        Chan for which this RoC has been requested
+ * @phy_mode:    PHY mode
+ * @duration:    Duration for the RoC
+ * @roc_type:    RoC type  User requested or internal
+ * @roc_timer:   RoC timer
+ * @roc_state:   Roc state
+ * @id:          identifier of roc
+ */
+struct p2p_roc_context {
+	qdf_list_node_t node;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	uint32_t vdev_id;
+	uint32_t scan_id;
+	void *tx_ctx;
+	uint8_t chan;
+	uint8_t phy_mode;
+	uint32_t duration;
+	enum roc_type roc_type;
+	qdf_mc_timer_t roc_timer;
+	enum roc_state roc_state;
+	int32_t id;
+};
+
+/**
+ * struct cancel_roc_context - p2p cancel roc context
+ * @p2p_soc_obj:      Pointer to SoC global p2p private object
+ * @cookie:           Cookie which is given by supplicant
+ */
+struct cancel_roc_context {
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	uint64_t cookie;
+};
+
+/**
+ * struct p2p_cleanup_param - p2p cleanup parameters
+ * @p2p_soc_obj:      Pointer to SoC global p2p private object
+ * @vdev_id:          vdev id
+ */
+struct p2p_cleanup_param {
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	uint32_t vdev_id;
+};
+
+/**
+ * p2p_mgmt_rx_action_ops() - register or unregister rx action callback
+ * @psoc: psoc object
+ * @isregister: register if true, unregister if false
+ *
+ * This function registers or unregisters rx action frame callback to
+ * mgmt txrx component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_mgmt_rx_action_ops(struct wlan_objmgr_psoc *psoc,
+	bool isregister);
+
+/**
+ * p2p_find_current_roc_ctx() - Find out roc context in progressing
+ * @p2p_soc_obj: p2p psoc private object
+ *
+ * This function finds out roc context in progressing from p2p psoc
+ * private object
+ *
+ * Return: Pointer to roc context - success
+ *         NULL                   - failure
+ */
+struct p2p_roc_context *p2p_find_current_roc_ctx(
+	struct p2p_soc_priv_obj *p2p_soc_obj);
+
+/**
+ * p2p_find_roc_by_tx_ctx() - Find out roc context by tx context
+ * @p2p_soc_obj: p2p psoc private object
+ * @cookie: cookie is the key to find out roc context
+ *
+ * This function finds out roc context by tx context from p2p psoc
+ * private object
+ *
+ * Return: Pointer to roc context - success
+ *         NULL                   - failure
+ */
+struct p2p_roc_context *p2p_find_roc_by_tx_ctx(
+	struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie);
+
+/**
+ * p2p_find_roc_by_chan() - Find out roc context by channel
+ * @p2p_soc_obj: p2p psoc private object
+ * @chan: channel of the ROC
+ *
+ * This function finds out roc context by channel from p2p psoc
+ * private object
+ *
+ * Return: Pointer to roc context - success
+ *         NULL                   - failure
+ */
+struct p2p_roc_context *p2p_find_roc_by_chan(
+	struct p2p_soc_priv_obj *p2p_soc_obj, uint8_t chan);
+
+/**
+ * p2p_restart_roc_timer() - Restarts roc timer
+ * @roc_ctx: remain on channel context
+ *
+ * This function restarts roc timer with updated duration.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_restart_roc_timer(struct p2p_roc_context *roc_ctx);
+
+/**
+ * p2p_cleanup_roc_sync() - Cleanup roc context in queue
+ * @p2p_soc_obj: p2p psoc private object
+ * @vdev:        vdev object
+ *
+ * This function cleanup roc context in queue, include the roc
+ * context in progressing until cancellation done. To avoid deadlock,
+ * don't call from scheduler thread.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_cleanup_roc_sync(
+	struct p2p_soc_priv_obj *p2p_soc_obj,
+	struct wlan_objmgr_vdev *vdev);
+
+/**
+ * p2p_process_cleanup_roc_queue() - process the message to cleanup roc
+ * @param: pointer to cleanup parameters
+ *
+ * This function process the message to cleanup roc context in queue,
+ * include the roc context in progressing.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_cleanup_roc_queue(
+	struct p2p_cleanup_param *param);
+
+/**
+ * p2p_process_roc_req() - Process roc request
+ * @roc_ctx: roc request context
+ *
+ * This function handles roc request. It will call API from scan/mgmt
+ * txrx component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_roc_req(struct p2p_roc_context *roc_ctx);
+
+/**
+ * p2p_process_cancel_roc_req() - Process cancel roc request
+ * @cancel_roc_ctx: cancel roc request context
+ *
+ * This function cancel roc request by cookie.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS p2p_process_cancel_roc_req(
+	struct cancel_roc_context *cancel_roc_ctx);
+
+/**
+ * p2p_scan_event_cb() - Process scan event
+ * @vdev: vdev associated to this scan event
+ * @event: event information
+ * @arg: registered arguments
+ *
+ * This function handles P2P scan event and deliver P2P event to HDD
+ * layer by registered callback.
+ *
+ * Return: None
+ */
+void p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev,
+	struct scan_event *event, void *arg);
+
+#endif /* _WLAN_P2P_ROC_H_ */

+ 128 - 0
components/p2p/dispatcher/inc/wlan_p2p_cfg.h

@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. 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.
+ */
+
+#if !defined(CONFIG_P2P_H__)
+#define CONFIG_P2P_H__
+
+#include "cfg_define.h"
+#include "cfg_converged.h"
+#include "qdf_types.h"
+
+/*
+ * <ini>
+ * gGoKeepAlivePeriod - P2P GO keep alive period.
+ * @Min: 1
+ * @Max: 65535
+ * @Default: 20
+ *
+ * This is P2P GO keep alive period.
+ *
+ * Related: None.
+ *
+ * Supported Feature: P2P
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_GO_KEEP_ALIVE_PERIOD CFG_INI_UINT( \
+	"gGoKeepAlivePeriod", \
+	1, \
+	65535, \
+	20, \
+	CFG_VALUE_OR_DEFAULT, \
+	"P2P GO keep alive period")
+
+/*
+ * <ini>
+ * gGoLinkMonitorPeriod - period where link is idle and where
+ * we send NULL frame
+ * @Min: 3
+ * @Max: 50
+ * @Default: 10
+ *
+ * This is period where link is idle and where we send NULL frame for P2P GO.
+ *
+ * Related: None.
+ *
+ * Supported Feature: P2P
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_GO_LINK_MONITOR_PERIOD CFG_INI_UINT( \
+	"gGoLinkMonitorPeriod", \
+	3, \
+	50, \
+	10, \
+	CFG_VALUE_OR_DEFAULT, \
+	"period where link is idle and where we send NULL frame")
+
+/*
+ * <ini>
+ * isP2pDeviceAddrAdministrated - Enables to derive the P2P MAC address from
+ * the primary MAC address
+ * @Min: 0
+ * @Max: 1
+ * @Default: 1
+ *
+ * This ini is used to enable/disable to derive the P2P MAC address from the
+ * primary MAC address.
+ *
+ * Related: None.
+ *
+ * Supported Feature: P2P
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED CFG_INI_BOOL( \
+	"isP2pDeviceAddrAdministrated", \
+	1, \
+	"derive the P2P MAC address from the primary MAC address")
+
+/*
+ * <ini>
+ * gSkipDfsChannelInP2pSearch - Skip DFS Channel in case of P2P Search
+ * @Min: 0
+ * @Max: 1
+ * @Default: 1
+ *
+ * This ini is used to disable(skip) dfs channel in p2p search.
+ * Related: None.
+ *
+ * Supported Feature: DFS P2P
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH CFG_INI_BOOL( \
+	"gSkipDfsChannelInP2pSearch", \
+	1, \
+	"skip dfs channel in p2p search")
+
+#define CFG_P2P_ALL \
+	CFG(CFG_GO_KEEP_ALIVE_PERIOD) \
+	CFG(CFG_GO_LINK_MONITOR_PERIOD) \
+	CFG(CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED) \
+	CFG(CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH)
+
+#endif

+ 76 - 0
components/p2p/dispatcher/inc/wlan_p2p_cfg_api.h

@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. 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 p2p configures interface definitions
+ */
+
+#ifndef _WLAN_P2P_CFG_API_H_
+#define _WLAN_P2P_CFG_API_H_
+
+#include <qdf_types.h>
+
+struct wlan_objmgr_psoc;
+
+/**
+ * cfg_p2p_get_go_keepalive_period() - get go keepalive period
+ * @psoc:        pointer to psoc object
+ * @period:      go keepalive period
+ *
+ * This function gets go keepalive period to p2p component
+ */
+QDF_STATUS
+cfg_p2p_get_go_keepalive_period(struct wlan_objmgr_psoc *psoc,
+				uint32_t *period);
+
+/**
+ * cfg_p2p_get_go_link_monitor_period() - get go link monitor period
+ * @psoc:        pointer to psoc object
+ * @period:      go link monitor period
+ *
+ * This function gets go link monitor period to p2p component
+ */
+QDF_STATUS
+cfg_p2p_get_go_link_monitor_period(struct wlan_objmgr_psoc *psoc,
+				   uint32_t *period);
+
+/**
+ * cfg_p2p_get_device_addr_admin() - get enable/disable p2p device
+ * addr administrated
+ * @psoc:        pointer to psoc object
+ * @enable:      enable/disable p2p device addr administrated
+ *
+ * This function gets enable/disable p2p device addr administrated
+ */
+QDF_STATUS
+cfg_p2p_get_device_addr_admin(struct wlan_objmgr_psoc *psoc,
+			      bool *enable);
+
+/**
+ * cfg_p2p_get_skip_dfs_channel_p2p_search() - get skip dfs channel
+ * in p2p search
+ * @psoc:        pointer to psoc object
+ * @enable:      enable/disable skip dfs channel in p2p search
+ *
+ * This function gets enable/disable skip dfs channel in p2p search
+ */
+QDF_STATUS
+cfg_p2p_get_skip_dfs_channel_p2p_search(struct wlan_objmgr_psoc *psoc,
+					bool *enable);
+
+#endif /* _WLAN_P2P_CFG_API_H_ */

+ 272 - 0
components/p2p/dispatcher/inc/wlan_p2p_public_struct.h

@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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 p2p public data structure definations
+ */
+
+#ifndef _WLAN_P2P_PUBLIC_STRUCT_H_
+#define _WLAN_P2P_PUBLIC_STRUCT_H_
+
+#include <qdf_types.h>
+
+#define P2P_MAX_NOA_DESC 4
+
+/**
+ * struct p2p_ps_params - P2P powersave related params
+ * @opp_ps: opportunistic power save
+ * @ctwindow: CT window
+ * @count: count
+ * @duration: duration
+ * @interval: interval
+ * @single_noa_duration: single shot noa duration
+ * @ps_selection: power save selection
+ * @session_id: session id
+ */
+struct p2p_ps_params {
+	uint8_t opp_ps;
+	uint32_t ctwindow;
+	uint8_t count;
+	uint32_t duration;
+	uint32_t interval;
+	uint32_t single_noa_duration;
+	uint8_t ps_selection;
+	uint8_t session_id;
+};
+
+/**
+ * struct p2p_roc_req - P2P roc request
+ * @vdev_id:     Vdev id on which this request has come
+ * @chan:        Chan for which this RoC has been requested
+ * @phy_mode:    PHY mode
+ * @duration:    Duration for the RoC
+ */
+struct p2p_roc_req {
+	uint32_t vdev_id;
+	uint32_t chan;
+	uint32_t phy_mode;
+	uint32_t duration;
+};
+
+/**
+ * enum p2p_roc_event - P2P RoC event
+ * @ROC_EVENT_READY_ON_CHAN:  RoC has started now
+ * @ROC_EVENT_COMPLETED:      RoC has been completed
+ * @ROC_EVENT_INAVLID:        Invalid event
+ */
+enum p2p_roc_event {
+	ROC_EVENT_READY_ON_CHAN = 0,
+	ROC_EVENT_COMPLETED,
+	ROC_EVENT_INAVLID,
+};
+
+/**
+ * struct p2p_event - p2p event
+ * @vdev_id:     Vdev id
+ * @roc_event:   RoC event
+ * @cookie:      Cookie which is given to supplicant for this roc req
+ * @chan:        Chan for which this RoC has been requested
+ * @duration:    Duration for the RoC
+  */
+struct p2p_event {
+	uint32_t vdev_id;
+	enum p2p_roc_event roc_event;
+	uint64_t cookie;
+	uint32_t chan;
+	uint32_t duration;
+};
+
+/**
+ * struct p2p_rx_mgmt_frame - rx mgmt frame structure
+ * @frame_len:   Frame length
+ * @rx_chan:     RX channel
+ * @vdev_id:     Vdev id
+ * @frm_type:    Frame type
+ * @rx_rssi:     RX rssi
+ * @buf:         Buffer address
+ */
+struct p2p_rx_mgmt_frame {
+	uint32_t frame_len;
+	uint32_t rx_chan;
+	uint32_t vdev_id;
+	uint32_t frm_type;
+	uint32_t rx_rssi;
+	uint8_t buf[1];
+};
+
+/**
+ * struct p2p_tx_cnf - tx confirm structure
+ * @vdev_id:        Vdev id
+ * @action_cookie:  TX cookie for this action frame
+ * @buf_len:        Frame length
+ * @status:         TX status
+ * @buf:            Buffer address
+ */
+struct p2p_tx_cnf {
+	uint32_t vdev_id;
+	uint64_t action_cookie;
+	uint32_t buf_len;
+	uint32_t status;
+	uint8_t *buf;
+};
+
+/**
+ * struct p2p_mgmt_tx - p2p mgmt tx structure
+ * @vdev_id:             Vdev id
+ * @chan:                Chan for which this RoC has been requested
+ * @wait:                Duration for the RoC
+ * @len:                 Length of tx buffer
+ * @no_cck:              Required cck or not
+ * @dont_wait_for_ack:   Wait for ack or not
+ * @off_chan:            Off channel tx or not
+ * @buf:                 TX buffer
+ */
+struct p2p_mgmt_tx {
+	uint32_t vdev_id;
+	uint32_t chan;
+	uint32_t wait;
+	uint32_t len;
+	uint32_t no_cck;
+	uint32_t dont_wait_for_ack;
+	uint32_t off_chan;
+	const uint8_t *buf;
+};
+
+/**
+ * struct p2p_set_mac_filter
+ * @vdev_id: Vdev id
+ * @mac: mac addr
+ * @freq: frequency
+ * @set: set or clear
+ */
+struct p2p_set_mac_filter {
+	uint32_t vdev_id;
+	uint8_t mac[QDF_MAC_ADDR_SIZE];
+	uint32_t freq;
+	bool set;
+};
+
+/**
+ * struct p2p_set_mac_filter_evt
+ * @vdev_id: Vdev id
+ * @status: target reported result of set mac addr filter
+ */
+struct p2p_set_mac_filter_evt {
+	uint32_t vdev_id;
+	uint32_t status;
+};
+
+/**
+ * struct p2p_ps_config
+ * @vdev_id:               Vdev id
+ * @opp_ps:                Opportunistic power save
+ * @ct_window:             CT window
+ * @count:                 Count
+ * @duration:              Duration
+ * @interval:              Interval
+ * @single_noa_duration:   Single shot noa duration
+ * @ps_selection:          power save selection
+ */
+struct p2p_ps_config {
+	uint32_t vdev_id;
+	uint32_t opp_ps;
+	uint32_t ct_window;
+	uint32_t count;
+	uint32_t duration;
+	uint32_t interval;
+	uint32_t single_noa_duration;
+	uint32_t ps_selection;
+};
+
+/**
+ * struct p2p_lo_start - p2p listen offload start
+ * @vdev_id:            Vdev id
+ * @ctl_flags:          Control flag
+ * @freq:               P2P listen frequency
+ * @period:             Listen offload period
+ * @interval:           Listen offload interval
+ * @count:              Number listen offload intervals
+ * @dev_types_len:      Device types length
+ * @probe_resp_len:     Probe response template length
+ * @device_types:       Device types
+ * @probe_resp_tmplt:   Probe response template
+ */
+struct p2p_lo_start {
+	uint32_t vdev_id;
+	uint32_t ctl_flags;
+	uint32_t freq;
+	uint32_t period;
+	uint32_t interval;
+	uint32_t count;
+	uint32_t dev_types_len;
+	uint32_t probe_resp_len;
+	uint8_t  *device_types;
+	uint8_t  *probe_resp_tmplt;
+};
+
+/**
+ * struct p2p_lo_event
+ * @vdev_id:        vdev id
+ * @reason_code:    reason code
+ */
+struct p2p_lo_event {
+	uint32_t vdev_id;
+	uint32_t reason_code;
+};
+
+/**
+ * struct noa_descriptor - noa descriptor
+ * @type_count:     255: continuous schedule, 0: reserved
+ * @duration:       Absent period duration in micro seconds
+ * @interval:       Absent period interval in micro seconds
+ * @start_time:     32 bit tsf time when in starts
+ */
+struct noa_descriptor {
+	uint32_t type_count;
+	uint32_t duration;
+	uint32_t interval;
+	uint32_t start_time;
+};
+
+/**
+ * struct p2p_noa_info - p2p noa information
+ * @index:             identifies instance of NOA su element
+ * @opps_ps:           opps ps state of the AP
+ * @ct_window:         ct window in TUs
+ * @vdev_id:           vdev id
+ * @num_descriptors:   number of NOA descriptors
+ * @noa_desc:          noa descriptors
+ */
+struct p2p_noa_info {
+	uint32_t index;
+	uint32_t opps_ps;
+	uint32_t ct_window;
+	uint32_t vdev_id;
+	uint32_t num_desc;
+	struct noa_descriptor noa_desc[P2P_MAX_NOA_DESC];
+};
+
+/**
+ * struct p2p_protocol_callbacks - callback to non-converged driver
+ * @is_mgmt_protected: func to get 11w mgmt protection status
+ */
+struct p2p_protocol_callbacks {
+	bool (*is_mgmt_protected)(uint32_t vdev_id, const uint8_t *peer_addr);
+};
+
+#endif /* _WLAN_P2P_PUBLIC_STRUCT_H_ */

+ 208 - 0
components/p2p/dispatcher/inc/wlan_p2p_tgt_api.h

@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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 p2p south bound interface definitions
+ */
+
+#ifndef _WLAN_P2P_TGT_API_H_
+#define _WLAN_P2P_TGT_API_H_
+
+#include <qdf_types.h>
+#include <qdf_nbuf.h>
+
+struct scan_event;
+struct wlan_objmgr_psoc;
+struct wlan_objmgr_peer;
+struct p2p_noa_info;
+struct p2p_lo_event;
+struct mgmt_rx_event_params;
+enum mgmt_frame_type;
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+
+/**
+ * tgt_p2p_lo_event_cb() - Listen offload stop request
+ * @psoc: soc object
+ * @event_info: lo stop event buffer
+ *
+ * This function gets called from target interface.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_lo_event_cb(struct wlan_objmgr_psoc *psoc,
+			       struct p2p_lo_event *event_info);
+
+/**
+ * tgt_p2p_register_lo_ev_handler() - register lo event
+ * @psoc: soc object
+ *
+ * p2p tgt api to register listen offload event handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_register_lo_ev_handler(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tgt_p2p_unregister_lo_ev_handler() - unregister lo event
+ * @psoc: soc object
+ *
+ * p2p tgt api to unregister listen offload event handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_unregister_lo_ev_handler(
+	struct wlan_objmgr_psoc *psoc);
+#else
+static inline QDF_STATUS tgt_p2p_register_lo_ev_handler(
+	struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS tgt_p2p_unregister_lo_ev_handler(
+	struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * tgt_p2p_register_macaddr_rx_filter_evt_handler() - register add mac rx
+ *    filter status event
+ * @psoc: soc object
+ * @register: register or unregister
+ *
+ * p2p tgt api to register add mac rx filter status event
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_register_macaddr_rx_filter_evt_handler(
+	struct wlan_objmgr_psoc *psoc, bool register);
+
+/**
+ * tgt_p2p_register_noa_ev_handler() - register noa event
+ * @psoc: soc object
+ *
+ * p2p tgt api to register noa event handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_register_noa_ev_handler(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tgt_p2p_unregister_noa_ev_handler() - unregister noa event
+ * @psoc: soc object
+ *
+ * p2p tgt api to unregister noa event handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_unregister_noa_ev_handler(
+	struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tgt_p2p_scan_event_cb() - Callback for scan event
+ * @vdev: vdev object
+ * @event: event information
+ * @arg: registered arguments
+ *
+ * This function gets called from scan component when getting P2P
+ * scan event.
+ *
+ * Return: None
+ */
+void tgt_p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev,
+	struct scan_event *event, void *arg);
+
+/**
+ * tgt_p2p_mgmt_download_comp_cb() - Callback for mgmt frame tx
+ * complete
+ * @context: tx context
+ * @buf: buffer address
+ * @free: need to free or not
+ *
+ * This function gets called from mgmt tx/rx component when mgmt
+ * frame tx complete.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_mgmt_download_comp_cb(void *context,
+	qdf_nbuf_t buf, bool free);
+
+/**
+ * tgt_p2p_mgmt_ota_comp_cb() - Callback for mgmt frame tx ack
+ * @context: tx context
+ * @buf: buffer address
+ * @status: tx status
+ * @tx_compl_params: tx complete parameters
+ *
+ * This function gets called from mgmt tx/rx component when getting
+ * mgmt frame tx ack.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_mgmt_ota_comp_cb(void *context, qdf_nbuf_t buf,
+	uint32_t status, void *tx_compl_params);
+
+/**
+ * tgt_p2p_mgmt_frame_rx_cb() - Callback for rx mgmt frame
+ * @psoc: soc context
+ * @peer: peer context
+ * @buf: rx buffer
+ * @mgmt_rx_params: mgmt rx parameters
+ * @frm_type: frame type
+ *
+ * This function gets called from mgmt tx/rx component when rx mgmt
+ * frame.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc,
+	struct wlan_objmgr_peer *peer, qdf_nbuf_t buf,
+	struct mgmt_rx_event_params *mgmt_rx_params,
+	enum mgmt_frame_type frm_type);
+/**
+ * tgt_p2p_noa_event_cb() - Callback for noa event
+ * @psoc: soc object
+ * @event_info: noa event information
+ *
+ * This function gets called from target interface.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS tgt_p2p_noa_event_cb(struct wlan_objmgr_psoc *psoc,
+		struct p2p_noa_info *event_info);
+
+/**
+ * tgt_p2p_add_mac_addr_status_event_cb() - Callback for set mac addr filter evt
+ * @psoc: soc object
+ * @event_info: event information type of p2p_set_mac_filter_evt
+ *
+ * This function gets called from target interface.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS
+tgt_p2p_add_mac_addr_status_event_cb(
+	struct wlan_objmgr_psoc *psoc,
+	struct p2p_set_mac_filter_evt *event_info);
+
+#endif /* _WLAN_P2P_TGT_API_H_ */

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

@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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 p2p north bound interface definitions
+ */
+
+#ifndef _WLAN_P2P_UCFG_API_H_
+#define _WLAN_P2P_UCFG_API_H_
+
+#include <qdf_types.h>
+
+struct wlan_objmgr_psoc;
+struct p2p_roc_req;
+struct p2p_event;
+struct p2p_rx_mgmt_frame;
+struct p2p_tx_cnf;
+struct p2p_mgmt_tx;
+struct p2p_ps_config;
+struct p2p_lo_start;
+struct p2p_lo_event;
+
+/**
+ * p2p_rx_callback() - Callback for rx mgmt frame
+ * @user_data: user data associated to this rx mgmt frame.
+ * @rx_frame: RX mgmt frame
+ *
+ * This callback will be used to give rx frames to hdd.
+ *
+ * Return: None
+ */
+typedef void (*p2p_rx_callback)(void *user_data,
+	struct p2p_rx_mgmt_frame *rx_frame);
+
+/**
+ * p2p_action_tx_cnf_callback() - Callback for tx confirmation
+ * @user_data: user data associated to this tx confirmation
+ * @tx_cnf: tx confirmation information
+ *
+ * This callback will be used to give tx mgmt frame confirmation to
+ * hdd.
+ *
+ * Return: None
+ */
+typedef void (*p2p_action_tx_cnf_callback)(void *user_data,
+	struct p2p_tx_cnf *tx_cnf);
+
+/**
+ * p2p_lo_event_callback() - Callback for listen offload event
+ * @user_data: user data associated to this lo event
+ * @p2p_lo_event: listen offload event information
+ *
+ * This callback will be used to give listen offload event to hdd.
+ *
+ * Return: None
+ */
+typedef void (*p2p_lo_event_callback)(void *user_data,
+	struct p2p_lo_event *p2p_lo_event);
+
+/**
+ * p2p_event_callback() - Callback for P2P event
+ * @user_data: user data associated to this p2p event
+ * @p2p_event: p2p event information
+ *
+ * This callback will be used to give p2p event to hdd.
+ *
+ * Return: None
+ */
+typedef void (*p2p_event_callback)(void *user_data,
+	struct p2p_event *p2p_event);
+
+/**
+ * struct p2p_start_param - p2p soc start parameters. Below callbacks
+ *                          will be registered by the HDD
+ * @rx_callback:      Function pointer to hdd rx callback. This
+ *                    function will be used to give rx frames to hdd
+ * @rx_cb_data:       RX callback user data
+ * @event_cb:         Founction pointer to hdd p2p event callback.
+ *                    This function will be used to give p2p event
+ *                    to hdd
+ * @event_cb_data:    Pointer to p2p event callback user data
+ * @tx_cnf_cb:        Function pointer to hdd tx confirm callback.
+ *                    This function will be used to give tx confirm
+ *                    to hdd
+ * @tx_cnf_cb_data:   Pointer to p2p tx confirm callback user data
+ * @lo_event_cb:      Founction pointer to p2p listen offload
+ *                    callback. This function will be used to give
+ *                    listen offload stopped event to hdd
+ * @lo_event_cb_data: Pointer to p2p listen offload callback user data
+ */
+struct p2p_start_param {
+	p2p_rx_callback rx_cb;
+	void *rx_cb_data;
+	p2p_event_callback event_cb;
+	void *event_cb_data;
+	p2p_action_tx_cnf_callback tx_cnf_cb;
+	void *tx_cnf_cb_data;
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+	p2p_lo_event_callback lo_event_cb;
+	void *lo_event_cb_data;
+#endif
+};
+
+/**
+ * ucfg_p2p_init() - P2P component initialization
+ *
+ * This function gets called when dispatcher initializing.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_init(void);
+
+/**
+ * ucfg_p2p_deinit() - P2P component de-init
+ *
+ * This function gets called when dispatcher de-init.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_deinit(void);
+
+/**
+ * ucfg_p2p_psoc_open() - Open P2P component
+ * @soc: soc context
+ *
+ * This function gets called when dispatcher opening.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_psoc_open(struct wlan_objmgr_psoc *soc);
+
+/**
+ * ucfg_p2p_psoc_close() - Close P2P component
+ * @soc: soc context
+ *
+ * This function gets called when dispatcher closing.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_psoc_close(struct wlan_objmgr_psoc *soc);
+
+/**
+ * ucfg_p2p_psoc_start() - Start P2P component
+ * @soc: soc context
+ * @req: P2P start parameters
+ *
+ * This function gets called when up layer starting up.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_psoc_start(struct wlan_objmgr_psoc *soc,
+	struct p2p_start_param *req);
+
+/**
+ * ucfg_p2p_psoc_stop() - Stop P2P component
+ * @soc: soc context
+ *
+ * This function gets called when up layer exit.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_psoc_stop(struct wlan_objmgr_psoc *soc);
+
+/**
+ * ucfg_p2p_roc_req() - Roc request
+ * @soc: soc context
+ * @roc_req: Roc request parameters
+ * @cookie: return cookie to caller
+ *
+ * This function delivers roc request to P2P component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_roc_req(struct wlan_objmgr_psoc *soc,
+	struct p2p_roc_req *roc_req, uint64_t *cookie);
+
+/**
+ * ucfg_p2p_roc_cancel_req() - Cancel roc request
+ * @soc: soc context
+ * @cookie: Find out the roc request by cookie
+ *
+ * This function delivers cancel roc request to P2P component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc,
+	uint64_t cookie);
+
+/**
+ * ucfg_p2p_cleanup_roc_by_vdev() - Cleanup roc request by vdev
+ * @vdev: pointer to vdev object
+ *
+ * This function call P2P API to cleanup roc request by vdev
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_cleanup_roc_by_vdev(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_p2p_cleanup_roc_by_poc() - Cleanup roc request by psoc
+ * @psoc: pointer to psoc object
+ *
+ * This function call P2P API to cleanup roc request by psoc
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_cleanup_roc_by_psoc(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_p2p_cleanup_tx_by_vdev() - Cleanup tx request by vdev
+ * @vdev: pointer to vdev object
+ *
+ * This function call P2P API to cleanup tx action frame request by vdev
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_cleanup_tx_by_vdev(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_p2p_cleanup_tx_by_poc() - Cleanup tx request by psoc
+ * @psoc: pointer to psoc object
+ *
+ * This function call P2P API to cleanup tx action frame request by psoc
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_cleanup_tx_by_psoc(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_p2p_mgmt_tx() - Mgmt frame tx request
+ * @soc: soc context
+ * @mgmt_frm: TX mgmt frame parameters
+ * @cookie: Return the cookie to caller
+ *
+ * This function delivers mgmt frame tx request to P2P component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc,
+	struct p2p_mgmt_tx *mgmt_frm, uint64_t *cookie);
+
+/**
+ * ucfg_p2p_mgmt_tx_cancel() - Cancel mgmt frame tx request
+ * @soc: soc context
+ * @vdev: vdev object
+ * @cookie: Find out the mgmt tx request by cookie
+ *
+ * This function delivers cancel mgmt frame tx request request to P2P
+ * component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc,
+	struct wlan_objmgr_vdev *vdev, uint64_t cookie);
+
+/**
+ * ucfg_p2p_set_ps() - P2P set power save
+ * @soc: soc context
+ * @ps_config: power save configure
+ *
+ * This function delivers p2p power save request to P2P component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_set_ps(struct wlan_objmgr_psoc *soc,
+	struct p2p_ps_config *ps_config);
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+/**
+ * ucfg_p2p_lo_start() - Listen offload start request
+ * @soc: soc context
+ * @p2p_lo_start: lo start parameters
+ *
+ * This function delivers listen offload start request to P2P
+ * component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_lo_start(struct wlan_objmgr_psoc *soc,
+	struct p2p_lo_start *p2p_lo_start);
+
+/**
+ * ucfg_p2p_lo_stop() - Listen offload stop request
+ * @soc: soc context
+ * @vdev_id: vdev id
+ *
+ * This function delivers listen offload stop request to P2P component.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_lo_stop(struct wlan_objmgr_psoc *soc,
+	uint32_t vdev_id);
+#endif
+
+/**
+ * p2p_peer_authorized() - Process peer authorized event
+ * @vdev: vdev structure to which peer is associated
+ * @mac_addr: peer mac address
+ *
+ * This function handles disables noa whenever a legacy station
+ * complete 4-way handshake after association.
+ *
+ * Return: void
+ */
+void p2p_peer_authorized(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr);
+
+/**
+ * ucfg_p2p_set_noa() - Disable/Enable NOA
+ * @soc: soc context
+ * @vdev_id: vdev id
+ * @disable_noa: TRUE - Disable NoA, FALSE - Enable NoA
+ *
+ * This function send wmi command to enable / disable NoA.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_set_noa(struct wlan_objmgr_psoc *soc,
+	uint32_t vdev_id, bool disable_noa);
+
+/**
+ * ucfg_p2p_check_random_mac() - check random mac addr or not
+ * @soc: soc context
+ * @vdev_id: vdev id
+ * @random_mac_addr: mac addr to be checked
+ *
+ * This function check the input addr is random mac addr or not for vdev.
+ *
+ * Return: true if addr is random mac address else false.
+ */
+bool ucfg_p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+			       uint8_t *random_mac_addr);
+
+/**
+ * ucfg_p2p_register_callbacks() - register p2p callbacks
+ * @soc: soc context
+ * @cb_obj: p2p_protocol_callbacks struct
+ *
+ * This function registers lim callbacks to p2p components to provide
+ * protocol information.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_register_callbacks(struct wlan_objmgr_psoc *soc,
+	    struct p2p_protocol_callbacks *cb_obj);
+
+/**
+ * ucfg_p2p_status_scan() - Show P2P connection status when scanning
+ * @vdev: vdev context
+ *
+ * This function shows P2P connection status when scanning.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_status_scan(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_p2p_status_connect() - Update P2P connection status
+ * @vdev:        vdev context
+ *
+ * Updates P2P connection status by up layer when connecting.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_status_connect(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_p2p_status_disconnect() - Update P2P connection status
+ * @vdev:        vdev context
+ *
+ * Updates P2P connection status by up layer when disconnecting.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_status_disconnect(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_p2p_status_start_bss() - Update P2P connection status
+ * @vdev:        vdev context
+ *
+ * Updates P2P connection status by up layer when starting bss.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_status_start_bss(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_p2p_status_stop_bss() - Update P2P connection status
+ * @vdev:        vdev context
+ *
+ * Updates P2P connection status by up layer when stopping bss.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS ucfg_p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev);
+
+#endif /* _WLAN_P2P_UCFG_API_H_ */

+ 105 - 0
components/p2p/dispatcher/src/wlan_p2p_cfg.c

@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. 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: This file contains p2p configures interface definitions
+ */
+
+#include <wlan_objmgr_psoc_obj.h>
+#include "wlan_p2p_public_struct.h"
+#include "wlan_p2p_cfg_api.h"
+#include "../../core/src/wlan_p2p_main.h"
+
+static inline struct p2p_soc_priv_obj *
+wlan_psoc_get_p2p_object(struct wlan_objmgr_psoc *psoc)
+{
+	return wlan_objmgr_psoc_get_comp_private_obj(psoc,
+					WLAN_UMAC_COMP_P2P);
+}
+
+QDF_STATUS
+cfg_p2p_get_go_keepalive_period(struct wlan_objmgr_psoc *psoc,
+				uint32_t *period)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	p2p_soc_obj = wlan_psoc_get_p2p_object(psoc);
+	if (!p2p_soc_obj) {
+		*period = 0;
+		p2p_err("p2p psoc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*period = p2p_soc_obj->param.go_keepalive_period;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_p2p_get_go_link_monitor_period(struct wlan_objmgr_psoc *psoc,
+				   uint32_t *period)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	p2p_soc_obj = wlan_psoc_get_p2p_object(psoc);
+	if (!p2p_soc_obj) {
+		*period = 0;
+		p2p_err("p2p psoc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*period = p2p_soc_obj->param.go_link_monitor_period;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_p2p_get_device_addr_admin(struct wlan_objmgr_psoc *psoc,
+			      bool *enable)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	p2p_soc_obj = wlan_psoc_get_p2p_object(psoc);
+	if (!p2p_soc_obj) {
+		*enable = false;
+		p2p_err("p2p psoc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*enable = p2p_soc_obj->param.p2p_device_addr_admin;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_p2p_get_skip_dfs_channel_p2p_search(struct wlan_objmgr_psoc *psoc,
+					bool *enable)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	p2p_soc_obj = wlan_psoc_get_p2p_object(psoc);
+	if (!p2p_soc_obj) {
+		*enable = false;
+		p2p_err("p2p psoc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*enable = p2p_soc_obj->param.skip_dfs_channel_p2p_search;
+
+	return QDF_STATUS_SUCCESS;
+}

+ 432 - 0
components/p2p/dispatcher/src/wlan_p2p_tgt_api.c

@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: This file contains p2p south bound interface definitions
+ */
+
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_mgmt_txrx_utils_api.h>
+#include <scheduler_api.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_peer_obj.h>
+#include "wlan_p2p_tgt_api.h"
+#include "wlan_p2p_public_struct.h"
+#include "../../core/src/wlan_p2p_main.h"
+#include "../../core/src/wlan_p2p_roc.h"
+#include "../../core/src/wlan_p2p_off_chan_tx.h"
+
+#define IEEE80211_FC0_TYPE_MASK              0x0c
+#define P2P_NOISE_FLOOR_DBM_DEFAULT          (-96)
+
+static inline struct wlan_lmac_if_p2p_tx_ops *
+wlan_psoc_get_p2p_tx_ops(struct wlan_objmgr_psoc *psoc)
+{
+	return &(psoc->soc_cb.tx_ops.p2p);
+}
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+QDF_STATUS tgt_p2p_register_lo_ev_handler(
+	struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc);
+	if (p2p_ops && p2p_ops->reg_lo_ev_handler) {
+		status = p2p_ops->reg_lo_ev_handler(psoc, NULL);
+		p2p_debug("register lo event, status:%d", status);
+	}
+
+	return status;
+}
+
+QDF_STATUS tgt_p2p_unregister_lo_ev_handler(
+	struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc);
+	if (p2p_ops && p2p_ops->unreg_lo_ev_handler) {
+		status = p2p_ops->unreg_lo_ev_handler(psoc, NULL);
+		p2p_debug("unregister lo event, status:%d", status);
+	}
+
+	return status;
+}
+
+QDF_STATUS tgt_p2p_lo_event_cb(struct wlan_objmgr_psoc *psoc,
+			       struct p2p_lo_event *event_info)
+{
+	struct p2p_lo_stop_event *lo_stop_event;
+	struct scheduler_msg msg = {0};
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status;
+
+	p2p_debug("soc:%pK, event_info:%pK", psoc, event_info);
+
+	if (!psoc) {
+		p2p_err("psoc context passed is NULL");
+		if (event_info)
+			qdf_mem_free(event_info);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+						WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc object is NULL");
+		if (event_info)
+			qdf_mem_free(event_info);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!event_info) {
+		p2p_err("invalid lo stop event information");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	lo_stop_event = qdf_mem_malloc(sizeof(*lo_stop_event));
+	if (!lo_stop_event) {
+		p2p_err("Failed to allocate p2p lo stop event");
+		qdf_mem_free(event_info);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	lo_stop_event->p2p_soc_obj = p2p_soc_obj;
+	lo_stop_event->lo_event = event_info;
+	msg.type = P2P_EVENT_LO_STOPPED;
+	msg.bodyptr = lo_stop_event;
+	msg.callback = p2p_process_evt;
+	msg.flush_callback = p2p_event_flush_callback;
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_TARGET_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(lo_stop_event->lo_event);
+		qdf_mem_free(lo_stop_event);
+		p2p_err("post msg fail:%d", status);
+	}
+
+	return status;
+}
+#endif /* FEATURE_P2P_LISTEN_OFFLOAD */
+
+QDF_STATUS
+tgt_p2p_add_mac_addr_status_event_cb(struct wlan_objmgr_psoc *psoc,
+				     struct p2p_set_mac_filter_evt *event_info)
+{
+	struct p2p_mac_filter_rsp *mac_filter_rsp;
+	struct scheduler_msg msg = {0};
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status;
+
+	if (!psoc) {
+		p2p_err("random_mac:psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+	if (!event_info) {
+		p2p_err("random_mac:invalid event_info");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(
+				psoc, WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("random_mac:p2p soc object is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mac_filter_rsp = qdf_mem_malloc(sizeof(*mac_filter_rsp));
+	if (!mac_filter_rsp) {
+		p2p_err("random_mac:Failed to allocate mac_filter_rsp");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	mac_filter_rsp->p2p_soc_obj = p2p_soc_obj;
+	mac_filter_rsp->vdev_id = event_info->vdev_id;
+	mac_filter_rsp->status = event_info->status;
+
+	msg.type = P2P_EVENT_ADD_MAC_RSP;
+	msg.bodyptr = mac_filter_rsp;
+	msg.callback = p2p_process_evt;
+	status = scheduler_post_msg(QDF_MODULE_ID_TARGET_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status))
+		qdf_mem_free(mac_filter_rsp);
+
+	return status;
+}
+
+QDF_STATUS tgt_p2p_register_macaddr_rx_filter_evt_handler(
+	struct wlan_objmgr_psoc *psoc, bool reg)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc);
+	if (p2p_ops && p2p_ops->reg_mac_addr_rx_filter_handler) {
+		status = p2p_ops->reg_mac_addr_rx_filter_handler(psoc, reg);
+		p2p_debug("register mac addr rx filter event,  register %d status:%d",
+			  reg, status);
+	}
+
+	return status;
+}
+
+QDF_STATUS tgt_p2p_register_noa_ev_handler(
+	struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc);
+	if (p2p_ops && p2p_ops->reg_noa_ev_handler) {
+		status = p2p_ops->reg_noa_ev_handler(psoc, NULL);
+		p2p_debug("register noa event, status:%d", status);
+	}
+
+	return status;
+}
+
+QDF_STATUS tgt_p2p_unregister_noa_ev_handler(
+	struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc);
+	if (p2p_ops && p2p_ops->unreg_noa_ev_handler) {
+		status = p2p_ops->unreg_noa_ev_handler(psoc, NULL);
+		p2p_debug("unregister noa event, status:%d", status);
+	}
+
+	return status;
+}
+
+void tgt_p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev,
+	struct scan_event *event, void *arg)
+{
+	p2p_scan_event_cb(vdev, event, arg);
+}
+
+QDF_STATUS tgt_p2p_mgmt_download_comp_cb(void *context,
+	qdf_nbuf_t buf, bool free)
+{
+	p2p_debug("conext:%pK, buf:%pK, free:%d", context,
+		qdf_nbuf_data(buf), free);
+
+	qdf_nbuf_free(buf);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tgt_p2p_mgmt_ota_comp_cb(void *context, qdf_nbuf_t buf,
+	uint32_t status, void *tx_compl_params)
+{
+	struct p2p_tx_conf_event *tx_conf_event;
+	struct scheduler_msg msg = {0};
+	QDF_STATUS ret;
+
+	p2p_debug("context:%pK, buf:%pK, status:%d, tx complete params:%pK",
+		context, buf, status, tx_compl_params);
+
+	if (!context) {
+		p2p_err("invalid context");
+		qdf_nbuf_free(buf);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	tx_conf_event = qdf_mem_malloc(sizeof(*tx_conf_event));
+	if (!tx_conf_event) {
+		p2p_err("Failed to allocate tx cnf event");
+		qdf_nbuf_free(buf);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	tx_conf_event->status = status;
+	tx_conf_event->nbuf = buf;
+	tx_conf_event->p2p_soc_obj = (struct p2p_soc_priv_obj *)context;
+	msg.type = P2P_EVENT_MGMT_TX_ACK_CNF;
+	msg.bodyptr = tx_conf_event;
+	msg.callback = p2p_process_evt;
+	msg.flush_callback = p2p_event_flush_callback;
+	ret = scheduler_post_message(QDF_MODULE_ID_P2P,
+				     QDF_MODULE_ID_P2P,
+				     QDF_MODULE_ID_TARGET_IF,
+				     &msg);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		qdf_mem_free(tx_conf_event);
+		qdf_nbuf_free(buf);
+		p2p_err("post msg fail:%d", status);
+	}
+
+	return ret;
+}
+
+QDF_STATUS tgt_p2p_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc,
+	struct wlan_objmgr_peer *peer, qdf_nbuf_t buf,
+	struct mgmt_rx_event_params *mgmt_rx_params,
+	enum mgmt_frame_type frm_type)
+{
+	struct p2p_rx_mgmt_frame *rx_mgmt;
+	struct p2p_rx_mgmt_event *rx_mgmt_event;
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct scheduler_msg msg = {0};
+	struct wlan_objmgr_vdev *vdev;
+	uint32_t vdev_id;
+	uint8_t *pdata;
+	QDF_STATUS status;
+
+	p2p_debug("psoc:%pK, peer:%pK, type:%d", psoc, peer, frm_type);
+
+	if (!mgmt_rx_params) {
+		p2p_err("mgmt rx params is NULL");
+		qdf_nbuf_free(buf);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p ctx is NULL, drop this frame");
+		qdf_nbuf_free(buf);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!peer) {
+		if (p2p_soc_obj->cur_roc_vdev_id == P2P_INVALID_VDEV_ID) {
+			p2p_err("vdev id of current roc invalid");
+			qdf_nbuf_free(buf);
+			return QDF_STATUS_E_FAILURE;
+		} else {
+			vdev_id = p2p_soc_obj->cur_roc_vdev_id;
+		}
+	} else {
+		vdev = wlan_peer_get_vdev(peer);
+		if (!vdev) {
+			p2p_err("vdev is NULL in peer, drop this frame");
+			qdf_nbuf_free(buf);
+			return QDF_STATUS_E_FAILURE;
+		}
+		vdev_id = wlan_vdev_get_id(vdev);
+	}
+
+	rx_mgmt_event = qdf_mem_malloc(sizeof(*rx_mgmt_event));
+	if (!rx_mgmt_event) {
+		p2p_err("Failed to allocate rx mgmt event");
+		qdf_nbuf_free(buf);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	rx_mgmt = qdf_mem_malloc(sizeof(*rx_mgmt) +
+			mgmt_rx_params->buf_len);
+	if (!rx_mgmt) {
+		p2p_err("Failed to allocate rx mgmt frame");
+		qdf_nbuf_free(buf);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	pdata = (uint8_t *)qdf_nbuf_data(buf);
+	rx_mgmt->frame_len = mgmt_rx_params->buf_len;
+	rx_mgmt->rx_chan = mgmt_rx_params->channel;
+	rx_mgmt->vdev_id = vdev_id;
+	rx_mgmt->frm_type = frm_type;
+	rx_mgmt->rx_rssi = mgmt_rx_params->snr +
+				P2P_NOISE_FLOOR_DBM_DEFAULT;
+	rx_mgmt_event->rx_mgmt = rx_mgmt;
+	rx_mgmt_event->p2p_soc_obj = p2p_soc_obj;
+	qdf_mem_copy(rx_mgmt->buf, pdata, mgmt_rx_params->buf_len);
+	msg.type = P2P_EVENT_RX_MGMT;
+	msg.bodyptr = rx_mgmt_event;
+	msg.callback = p2p_process_evt;
+	msg.flush_callback = p2p_event_flush_callback;
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_TARGET_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(rx_mgmt_event->rx_mgmt);
+		qdf_mem_free(rx_mgmt_event);
+		p2p_err("post msg fail:%d", status);
+	}
+	qdf_nbuf_free(buf);
+
+	return status;
+}
+
+QDF_STATUS  tgt_p2p_noa_event_cb(struct wlan_objmgr_psoc *psoc,
+		struct p2p_noa_info *event_info)
+{
+	struct p2p_noa_event *noa_event;
+	struct scheduler_msg msg = {0};
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	QDF_STATUS status;
+
+	p2p_debug("soc:%pK, event_info:%pK", psoc, event_info);
+
+	if (!psoc) {
+		p2p_err("psoc context passed is NULL");
+		if (event_info)
+			qdf_mem_free(event_info);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc object is NULL");
+		if (event_info)
+			qdf_mem_free(event_info);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!event_info) {
+		p2p_err("invalid noa event information");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	noa_event = qdf_mem_malloc(sizeof(*noa_event));
+	if (!noa_event) {
+		p2p_err("Failed to allocate p2p noa event");
+		qdf_mem_free(event_info);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	noa_event->p2p_soc_obj = p2p_soc_obj;
+	noa_event->noa_info = event_info;
+	msg.type = P2P_EVENT_NOA;
+	msg.bodyptr = noa_event;
+	msg.callback = p2p_process_evt;
+	msg.flush_callback = p2p_event_flush_callback;
+	status = scheduler_post_message(QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_TARGET_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(noa_event->noa_info);
+		qdf_mem_free(noa_event);
+		p2p_err("post msg fail:%d", status);
+	}
+
+	return status;
+}

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

@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: This file contains p2p north bound interface definitions
+ */
+
+#include <wmi_unified_api.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <scheduler_api.h>
+#include "wlan_p2p_public_struct.h"
+#include "wlan_p2p_ucfg_api.h"
+#include "../../core/src/wlan_p2p_main.h"
+#include "../../core/src/wlan_p2p_roc.h"
+#include "../../core/src/wlan_p2p_off_chan_tx.h"
+
+static inline struct wlan_lmac_if_p2p_tx_ops *
+ucfg_p2p_psoc_get_tx_ops(struct wlan_objmgr_psoc *psoc)
+{
+	return &(psoc->soc_cb.tx_ops.p2p);
+}
+
+/**
+ * is_p2p_ps_allowed() - If P2P power save is allowed or not
+ * @vdev: vdev object
+ * @id: umac component id
+ *
+ * This function returns TRUE if P2P power-save is allowed
+ * else returns FALSE.
+ *
+ * Return: bool
+ */
+static bool is_p2p_ps_allowed(struct wlan_objmgr_vdev *vdev,
+				enum wlan_umac_comp_id id)
+{
+	struct p2p_vdev_priv_obj *p2p_vdev_obj;
+	uint8_t is_p2pgo = 0;
+
+	if (!vdev) {
+		p2p_err("vdev:%pK", vdev);
+		return true;
+	}
+	p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+						WLAN_UMAC_COMP_P2P);
+
+	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE)
+		is_p2pgo = 1;
+
+	if (!p2p_vdev_obj || !is_p2pgo) {
+		p2p_err("p2p_vdev_obj:%pK is_p2pgo:%u",
+			p2p_vdev_obj, is_p2pgo);
+		return false;
+	}
+	if (p2p_vdev_obj->non_p2p_peer_count &&
+	    p2p_vdev_obj->noa_status == false) {
+		p2p_debug("non_p2p_peer_count: %u, noa_status: %d",
+			p2p_vdev_obj->non_p2p_peer_count,
+			p2p_vdev_obj->noa_status);
+		return false;
+	}
+
+	return true;
+}
+
+QDF_STATUS ucfg_p2p_init(void)
+{
+	return p2p_component_init();
+}
+
+QDF_STATUS ucfg_p2p_deinit(void)
+{
+	return p2p_component_deinit();
+}
+
+QDF_STATUS ucfg_p2p_psoc_open(struct wlan_objmgr_psoc *soc)
+{
+	return p2p_psoc_object_open(soc);
+}
+
+QDF_STATUS ucfg_p2p_psoc_close(struct wlan_objmgr_psoc *soc)
+{
+	return p2p_psoc_object_close(soc);
+}
+
+QDF_STATUS ucfg_p2p_psoc_start(struct wlan_objmgr_psoc *soc,
+	struct p2p_start_param *req)
+{
+	return p2p_psoc_start(soc, req);
+}
+
+QDF_STATUS ucfg_p2p_psoc_stop(struct wlan_objmgr_psoc *soc)
+{
+	return p2p_psoc_stop(soc);
+}
+
+QDF_STATUS ucfg_p2p_roc_req(struct wlan_objmgr_psoc *soc,
+	struct p2p_roc_req *roc_req, uint64_t *cookie)
+{
+	struct scheduler_msg msg = {0};
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct p2p_roc_context *roc_ctx;
+	QDF_STATUS status;
+	int32_t id;
+
+	p2p_debug("soc:%pK, vdev_id:%d, chan:%d, phy_mode:%d, duration:%d",
+		soc, roc_req->vdev_id, roc_req->chan,
+		roc_req->phy_mode, roc_req->duration);
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	roc_ctx = qdf_mem_malloc(sizeof(*roc_ctx));
+	if (!roc_ctx) {
+		p2p_err("failed to allocate p2p roc context");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	status = qdf_idr_alloc(&p2p_soc_obj->p2p_idr, roc_ctx, &id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(roc_ctx);
+		p2p_err("failed to alloc idr, status %d", status);
+		return status;
+	}
+
+	*cookie = (uint64_t)id;
+	roc_ctx->p2p_soc_obj = p2p_soc_obj;
+	roc_ctx->vdev_id = roc_req->vdev_id;
+	roc_ctx->chan = roc_req->chan;
+	roc_ctx->phy_mode = roc_req->phy_mode;
+	roc_ctx->duration = roc_req->duration;
+	roc_ctx->roc_state = ROC_STATE_IDLE;
+	roc_ctx->roc_type = USER_REQUESTED;
+	roc_ctx->id = id;
+	msg.type = P2P_ROC_REQ;
+	msg.bodyptr = roc_ctx;
+	msg.callback = p2p_process_cmd;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(roc_ctx);
+		qdf_idr_remove(&p2p_soc_obj->p2p_idr, id);
+		p2p_err("post msg fail:%d", status);
+	}
+	p2p_debug("cookie = 0x%llx", *cookie);
+
+	return status;
+}
+
+QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc,
+	uint64_t cookie)
+{
+	struct scheduler_msg msg = {0};
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct cancel_roc_context *cancel_roc;
+	void *roc_ctx = NULL;
+	QDF_STATUS status;
+
+	p2p_debug("soc:%pK, cookie:0x%llx", soc, cookie);
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = qdf_idr_find(&p2p_soc_obj->p2p_idr,
+			      cookie, &roc_ctx);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		p2p_err("invalid id");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	cancel_roc = qdf_mem_malloc(sizeof(*cancel_roc));
+	if (!cancel_roc) {
+		p2p_err("failed to allocate cancel p2p roc");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	cancel_roc->p2p_soc_obj = p2p_soc_obj;
+	cancel_roc->cookie = (uintptr_t)roc_ctx;
+	msg.type = P2P_CANCEL_ROC_REQ;
+	msg.bodyptr = cancel_roc;
+	msg.callback = p2p_process_cmd;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF,
+					&msg);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(cancel_roc);
+		p2p_err("post msg fail:%d", status);
+	}
+
+	return status;
+}
+
+QDF_STATUS ucfg_p2p_cleanup_roc_by_vdev(struct wlan_objmgr_vdev *vdev)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct wlan_objmgr_psoc *psoc;
+
+	p2p_debug("vdev:%pK", vdev);
+
+	if (!vdev) {
+		p2p_err("null vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		p2p_err("null psoc");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return p2p_cleanup_roc_sync(p2p_soc_obj, vdev);
+}
+
+QDF_STATUS ucfg_p2p_cleanup_roc_by_psoc(struct wlan_objmgr_psoc *psoc)
+{
+	struct p2p_soc_priv_obj *obj;
+
+	if (!psoc) {
+		p2p_err("null psoc");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_P2P);
+	if (!obj) {
+		p2p_err("null p2p soc obj");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return p2p_cleanup_roc_sync(obj, NULL);
+}
+
+QDF_STATUS ucfg_p2p_cleanup_tx_by_vdev(struct wlan_objmgr_vdev *vdev)
+{
+	struct p2p_soc_priv_obj *obj;
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!vdev) {
+		p2p_err("null vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		p2p_err("null psoc");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_P2P);
+	if (!obj) {
+		p2p_err("null p2p soc obj");
+		return QDF_STATUS_E_FAILURE;
+	}
+	p2p_del_all_rand_mac_vdev(vdev);
+
+	return p2p_cleanup_tx_sync(obj, vdev);
+}
+
+QDF_STATUS ucfg_p2p_cleanup_tx_by_psoc(struct wlan_objmgr_psoc *psoc)
+{
+	struct p2p_soc_priv_obj *obj;
+
+	if (!psoc) {
+		p2p_err("null psoc");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_P2P);
+	if (!obj) {
+		p2p_err("null p2p soc obj");
+		return QDF_STATUS_E_FAILURE;
+	}
+	p2p_del_all_rand_mac_soc(psoc);
+
+	return p2p_cleanup_tx_sync(obj, NULL);
+}
+
+QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc,
+	struct p2p_mgmt_tx *mgmt_frm, uint64_t *cookie)
+{
+	struct scheduler_msg msg = {0};
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct  tx_action_context *tx_action;
+	QDF_STATUS status;
+	int32_t id;
+
+	p2p_debug("soc:%pK, vdev_id:%d, chan:%d, wait:%d, buf_len:%d, cck:%d, no ack:%d, off chan:%d",
+		soc, mgmt_frm->vdev_id, mgmt_frm->chan,
+		mgmt_frm->wait, mgmt_frm->len, mgmt_frm->no_cck,
+		mgmt_frm->dont_wait_for_ack, mgmt_frm->off_chan);
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("P2P soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	tx_action = qdf_mem_malloc(sizeof(*tx_action));
+	if (!tx_action) {
+		p2p_err("Failed to allocate tx action context");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	/* return cookie just for ota ack frames */
+	if (mgmt_frm->dont_wait_for_ack)
+		id = 0;
+	else {
+		status = qdf_idr_alloc(&p2p_soc_obj->p2p_idr,
+				       tx_action, &id);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			qdf_mem_free(tx_action);
+			p2p_err("failed to alloc idr, status :%d", status);
+			return status;
+		}
+	}
+
+	*cookie = (uint64_t)id;
+	tx_action->p2p_soc_obj = p2p_soc_obj;
+	tx_action->vdev_id = mgmt_frm->vdev_id;
+	tx_action->chan = mgmt_frm->chan;
+	tx_action->duration = mgmt_frm->wait;
+	tx_action->buf_len = mgmt_frm->len;
+	tx_action->no_cck = mgmt_frm->no_cck;
+	tx_action->no_ack = mgmt_frm->dont_wait_for_ack;
+	tx_action->off_chan = mgmt_frm->off_chan;
+	tx_action->buf = qdf_mem_malloc(tx_action->buf_len);
+	if (!(tx_action->buf)) {
+		p2p_err("Failed to allocate buffer for action frame");
+		qdf_mem_free(tx_action);
+		return QDF_STATUS_E_NOMEM;
+	}
+	qdf_mem_copy(tx_action->buf, mgmt_frm->buf, tx_action->buf_len);
+	tx_action->nbuf = NULL;
+	tx_action->id = id;
+
+	p2p_rand_mac_tx(tx_action);
+
+	msg.type = P2P_MGMT_TX;
+	msg.bodyptr = tx_action;
+	msg.callback = p2p_process_cmd;
+	msg.flush_callback = p2p_msg_flush_callback;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		if (id)
+			qdf_idr_remove(&p2p_soc_obj->p2p_idr, id);
+		qdf_mem_free(tx_action->buf);
+		qdf_mem_free(tx_action);
+		p2p_err("post msg fail:%d", status);
+	}
+
+	return status;
+}
+
+QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc,
+	struct wlan_objmgr_vdev *vdev, uint64_t cookie)
+{
+	struct scheduler_msg msg = {0};
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+	struct cancel_roc_context *cancel_tx;
+	void *tx_ctx;
+	QDF_STATUS status;
+
+	p2p_debug("soc:%pK, cookie:0x%llx", soc, cookie);
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+			WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc context is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = qdf_idr_find(&p2p_soc_obj->p2p_idr,
+			      (int32_t)cookie, &tx_ctx);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		p2p_debug("invalid id");
+		return QDF_STATUS_E_INVAL;
+	}
+	p2p_del_random_mac(soc, wlan_vdev_get_id(vdev), cookie, 20);
+
+	cancel_tx = qdf_mem_malloc(sizeof(*cancel_tx));
+	if (!cancel_tx) {
+		p2p_err("Failed to allocate cancel p2p roc");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	cancel_tx->p2p_soc_obj = p2p_soc_obj;
+	cancel_tx->cookie = (uintptr_t)tx_ctx;
+	msg.type = P2P_MGMT_TX_CANCEL;
+	msg.bodyptr = cancel_tx;
+	msg.callback = p2p_process_cmd;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_P2P,
+					QDF_MODULE_ID_OS_IF,
+					&msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(cancel_tx);
+		p2p_err("post msg fail: %d", status);
+	}
+
+	return status;
+}
+
+bool ucfg_p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id,
+			       uint8_t *random_mac_addr)
+{
+	return p2p_check_random_mac(soc, vdev_id, random_mac_addr);
+}
+
+QDF_STATUS ucfg_p2p_set_ps(struct wlan_objmgr_psoc *soc,
+	struct p2p_ps_config *ps_config)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	uint16_t obj_id;
+	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);
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	for (obj_id = 0; obj_id < WLAN_UMAC_PSOC_MAX_VDEVS; obj_id++) {
+
+		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, obj_id,
+							WLAN_P2P_ID);
+		if (vdev) {
+			if (is_p2p_ps_allowed(vdev, WLAN_UMAC_COMP_P2P)) {
+				wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+				break;
+			}
+			wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+			p2p_debug("skip p2p set ps vdev %d, NoA is disabled as legacy STA is connected to GO.",
+				  obj_id);
+		}
+	}
+	if (obj_id >= WLAN_UMAC_PSOC_MAX_VDEVS) {
+		p2p_debug("No GO found!");
+		return QDF_STATUS_E_INVAL;
+	}
+	go_ps_config = *ps_config;
+	go_ps_config.vdev_id = obj_id;
+
+	p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc);
+	if (p2p_ops->set_ps) {
+		status = p2p_ops->set_ps(soc, &go_ps_config);
+		p2p_debug("p2p set ps vdev %d, status:%d", obj_id, status);
+	}
+
+	return status;
+}
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+QDF_STATUS ucfg_p2p_lo_start(struct wlan_objmgr_psoc *soc,
+	struct p2p_lo_start *p2p_lo_start)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	p2p_debug("soc:%pK, vdev_id:%d, ctl_flags:%d, freq:%d, period:%d, interval:%d, count:%d, dev_types_len:%d, probe_resp_len:%d, device_types:%pK, probe_resp_tmplt:%pK",
+		soc, p2p_lo_start->vdev_id, p2p_lo_start->ctl_flags,
+		p2p_lo_start->freq, p2p_lo_start->period,
+		p2p_lo_start->interval, p2p_lo_start->count,
+		p2p_lo_start->dev_types_len, p2p_lo_start->probe_resp_len,
+		p2p_lo_start->device_types, p2p_lo_start->probe_resp_tmplt);
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc);
+	if (p2p_ops->lo_start) {
+		status = p2p_ops->lo_start(soc, p2p_lo_start);
+		p2p_debug("p2p lo start, status:%d", status);
+	}
+
+	return status;
+}
+
+QDF_STATUS ucfg_p2p_lo_stop(struct wlan_objmgr_psoc *soc,
+	uint32_t vdev_id)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	p2p_debug("soc:%pK, vdev_id:%d", soc, vdev_id);
+
+	if (!soc) {
+		p2p_err("psoc context passed is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc);
+	if (p2p_ops->lo_stop) {
+		status = p2p_ops->lo_stop(soc, vdev_id);
+		p2p_debug("p2p lo stop, status:%d", status);
+	}
+
+	return status;
+}
+#endif
+
+QDF_STATUS  ucfg_p2p_set_noa(struct wlan_objmgr_psoc *soc,
+	uint32_t vdev_id, bool disable_noa)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_ops;
+	QDF_STATUS status = QDF_STATUS_E_INVAL;
+
+	p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc);
+	if (p2p_ops->set_noa) {
+		status = p2p_ops->set_noa(soc, vdev_id, disable_noa);
+		p2p_debug("p2p set noa, status:%d", status);
+	}
+
+	return status;
+}
+
+QDF_STATUS ucfg_p2p_register_callbacks(struct wlan_objmgr_psoc *soc,
+	    struct p2p_protocol_callbacks *cb_obj)
+{
+	struct p2p_soc_priv_obj *p2p_soc_obj;
+
+	if (!soc || !cb_obj) {
+		p2p_err("psoc %pM cb_obj %pM context passed is NULL", soc,
+			cb_obj);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc,
+		      WLAN_UMAC_COMP_P2P);
+	if (!p2p_soc_obj) {
+		p2p_err("p2p soc private object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	p2p_soc_obj->p2p_cb = *cb_obj;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS ucfg_p2p_status_scan(struct wlan_objmgr_vdev *vdev)
+{
+	if (!vdev) {
+		p2p_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return p2p_status_scan(vdev);
+}
+
+QDF_STATUS ucfg_p2p_status_connect(struct wlan_objmgr_vdev *vdev)
+{
+	if (!vdev) {
+		p2p_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return p2p_status_connect(vdev);
+}
+
+QDF_STATUS ucfg_p2p_status_disconnect(struct wlan_objmgr_vdev *vdev)
+{
+	if (!vdev) {
+		p2p_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return p2p_status_disconnect(vdev);
+}
+
+QDF_STATUS ucfg_p2p_status_start_bss(struct wlan_objmgr_vdev *vdev)
+{
+	if (!vdev) {
+		p2p_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return p2p_status_start_bss(vdev);
+}
+
+QDF_STATUS ucfg_p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev)
+{
+	if (!vdev) {
+		p2p_err("vdev is NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return p2p_status_stop_bss(vdev);
+}

+ 140 - 0
components/target_if/p2p/inc/target_if_p2p.h

@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: offload lmac interface APIs for P2P
+ */
+
+#ifndef _TARGET_IF_P2P_H_
+#define _TARGET_IF_P2P_H_
+
+#include <qdf_types.h>
+
+struct wlan_objmgr_psoc;
+struct p2p_ps_config;
+struct p2p_lo_start;
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+
+/**
+ * target_if_p2p_register_lo_event_handler() - Register lo event handler
+ * @psoc: soc object
+ * @arg: additional argument
+ *
+ * Target interface API to register P2P listen offload event handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS target_if_p2p_register_lo_event_handler(
+	struct wlan_objmgr_psoc *psoc, void *arg);
+
+/**
+ * target_if_p2p_unregister_lo_event_handler() - Unregister lo event handler
+ * @psoc: soc object
+ * @arg: additional argument
+ *
+ * Target interface API to unregister P2P listen offload event handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS target_if_p2p_unregister_lo_event_handler(
+	struct wlan_objmgr_psoc *psoc, void *arg);
+
+/**
+ * target_if_p2p_lo_start() - Start listen offload
+ * @psoc: soc object
+ * @lo_start: lo start information
+ *
+ * Target interface API to start listen offload.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS target_if_p2p_lo_start(struct wlan_objmgr_psoc *psoc,
+				  struct p2p_lo_start *lo_start);
+
+/**
+ * target_if_p2p_lo_stop() - Stop listen offload
+ * @psoc: soc object
+ * @vdev_id: vdev id
+ *
+ * Target interface API to stop listen offload.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS target_if_p2p_lo_stop(struct wlan_objmgr_psoc *psoc,
+				 uint32_t vdev_id);
+#endif
+
+/**
+ * target_if_p2p_register_tx_ops() - Register P2P component TX OPS
+ * @tx_ops: lmac if transmit ops
+ *
+ * Return: None
+ */
+void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops);
+
+/**
+ * target_if_p2p_register_noa_event_handler() - Register noa event handler
+ * @psoc: soc object
+ * @arg: additional argument
+ *
+ * Target interface API to register P2P noa event handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS target_if_p2p_register_noa_event_handler(
+	struct wlan_objmgr_psoc *psoc, void *arg);
+
+/**
+ * target_if_p2p_unregister_noa_event_handler() - Unregister noa event handler
+ * @psoc: soc object
+ * @arg: additional argument
+ *
+ * Target interface API to unregister P2P listen offload event handler.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS target_if_p2p_unregister_noa_event_handler(
+	struct wlan_objmgr_psoc *psoc, void *arg);
+
+/**
+ * target_if_p2p_set_ps() - Set power save
+ * @psoc: soc object
+ * @arg: additional argument
+ *
+ * Target interface API to set power save.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS target_if_p2p_set_ps(struct wlan_objmgr_psoc *psoc,
+				struct p2p_ps_config *ps_config);
+
+/**
+ * target_if_p2p_set_noa() - Disable / Enable NOA
+ * @psoc: soc object
+ * @vdev_id: vdev id
+ * @disable_noa: TRUE - Disable NoA, FALSE - Enable NoA
+ *
+ * Target interface API to Disable / Enable P2P NOA.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS target_if_p2p_set_noa(struct wlan_objmgr_psoc *psoc,
+	uint32_t vdev_id, bool disable_noa);
+
+#endif /* _TARGET_IF_P2P_H_ */

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

@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: offload lmac interface APIs definitions for P2P
+ */
+
+#include <wmi_unified_api.h>
+#include <wlan_p2p_public_struct.h>
+#include "target_if.h"
+#include "target_if_p2p.h"
+#include "init_deinit_lmac.h"
+
+static inline struct wlan_lmac_if_p2p_rx_ops *
+target_if_psoc_get_p2p_rx_ops(struct wlan_objmgr_psoc *psoc)
+{
+	return &(psoc->soc_cb.rx_ops.p2p);
+}
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+static inline void
+target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops)
+{
+	p2p_tx_ops->lo_start = target_if_p2p_lo_start;
+	p2p_tx_ops->lo_stop = target_if_p2p_lo_stop;
+	p2p_tx_ops->reg_lo_ev_handler =
+			target_if_p2p_register_lo_event_handler;
+	p2p_tx_ops->unreg_lo_ev_handler =
+			target_if_p2p_unregister_lo_event_handler;
+}
+
+/**
+ * target_p2p_lo_event_handler() - WMI callback for lo stop event
+ * @scn:       pointer to scn
+ * @event_buf: event buffer
+ * @len:       buffer length
+ *
+ * This function gets called from WMI when triggered wmi event
+ * wmi_p2p_lo_stop_event_id.
+ *
+ * Return: 0 - success
+ * others - failure
+ */
+static int target_p2p_lo_event_handler(ol_scn_t scn, uint8_t *data,
+	uint32_t datalen)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wmi_unified *wmi_handle;
+	struct p2p_lo_event *event_info;
+	struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, datalen);
+
+	if (!scn || !data) {
+		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
+		return -EINVAL;
+	}
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("null psoc");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("null wmi handle");
+		return -EINVAL;
+	}
+
+	event_info = qdf_mem_malloc(sizeof(*event_info));
+	if (!event_info) {
+		target_if_err("Failed to allocate p2p lo event");
+		return -ENOMEM;
+	}
+
+	if (wmi_extract_p2p_lo_stop_ev_param(wmi_handle, data,
+			event_info)) {
+		target_if_err("Failed to extract wmi p2p lo stop event");
+		qdf_mem_free(event_info);
+		return -EINVAL;
+	}
+
+	p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc);
+	if (p2p_rx_ops->lo_ev_handler) {
+		status = p2p_rx_ops->lo_ev_handler(psoc, event_info);
+		target_if_debug("call lo event handler, status:%d",
+			status);
+	} else {
+		qdf_mem_free(event_info);
+		target_if_debug("no valid lo event handler");
+	}
+
+	return qdf_status_to_os_return(status);
+}
+
+QDF_STATUS target_if_p2p_register_lo_event_handler(
+	struct wlan_objmgr_psoc *psoc, void *arg)
+{
+	int status;
+	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	target_if_debug("psoc:%pK, arg:%pK", psoc, arg);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = wmi_unified_register_event(wmi_handle,
+					    wmi_p2p_lo_stop_event_id,
+					    target_p2p_lo_event_handler);
+
+	target_if_debug("wmi register lo event handle, status:%d", status);
+
+	return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS target_if_p2p_unregister_lo_event_handler(
+	struct wlan_objmgr_psoc *psoc, void *arg)
+{
+	int status;
+	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	target_if_debug("psoc:%pK, arg:%pK", psoc, arg);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = wmi_unified_unregister_event(wmi_handle,
+					      wmi_p2p_lo_stop_event_id);
+
+	target_if_debug("wmi unregister lo event handle, status:%d", status);
+
+	return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS target_if_p2p_lo_start(struct wlan_objmgr_psoc *psoc,
+				  struct p2p_lo_start *lo_start)
+{
+	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!lo_start) {
+		target_if_err("lo start parameters is null");
+		return QDF_STATUS_E_INVAL;
+	}
+	target_if_debug("psoc:%pK, vdev_id:%d", psoc, lo_start->vdev_id);
+
+	return wmi_unified_p2p_lo_start_cmd(wmi_handle, lo_start);
+}
+
+QDF_STATUS target_if_p2p_lo_stop(struct wlan_objmgr_psoc *psoc,
+				 uint32_t vdev_id)
+{
+	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	target_if_debug("psoc:%pK, vdev_id:%d", psoc, vdev_id);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return wmi_unified_p2p_lo_stop_cmd(wmi_handle,
+			(uint8_t)vdev_id);
+}
+#else
+static inline void
+target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops)
+{
+}
+#endif /* FEATURE_P2P_LISTEN_OFFLOAD */
+
+/**
+ * target_p2p_noa_event_handler() - WMI callback for noa event
+ * @scn:       pointer to scn
+ * @event_buf: event buffer
+ * @len:       buffer length
+ *
+ * This function gets called from WMI when triggered WMI event
+ * wmi_p2p_noa_event_id.
+ *
+ * Return: 0 - success
+ * others - failure
+ */
+static int target_p2p_noa_event_handler(ol_scn_t scn, uint8_t *data,
+	uint32_t datalen)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wmi_unified *wmi_handle;
+	struct p2p_noa_info *event_info;
+	struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, datalen);
+
+	if (!scn || !data) {
+		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
+		return -EINVAL;
+	}
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("null psoc");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("null wmi handle");
+		return -EINVAL;
+	}
+
+	event_info = qdf_mem_malloc(sizeof(*event_info));
+	if (!event_info) {
+		target_if_err("failed to allocate p2p noa information");
+		return -ENOMEM;
+	}
+
+	if (wmi_extract_p2p_noa_ev_param(wmi_handle, data,
+			event_info)) {
+		target_if_err("failed to extract wmi p2p noa event");
+		qdf_mem_free(event_info);
+		return -EINVAL;
+	}
+
+	p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc);
+	if (p2p_rx_ops->noa_ev_handler) {
+		status = p2p_rx_ops->noa_ev_handler(psoc, event_info);
+		target_if_debug("call noa event handler, status:%d",
+			status);
+	} else {
+		qdf_mem_free(event_info);
+		target_if_debug("no valid noa event handler");
+	}
+
+	return qdf_status_to_os_return(status);
+}
+
+QDF_STATUS target_if_p2p_register_noa_event_handler(
+	struct wlan_objmgr_psoc *psoc, void *arg)
+{
+	int status;
+	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	target_if_debug("psoc:%pK, arg:%pK", psoc, arg);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = wmi_unified_register_event(wmi_handle,
+			wmi_p2p_noa_event_id,
+			target_p2p_noa_event_handler);
+
+	target_if_debug("wmi register noa event handle, status:%d",
+		status);
+
+	return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS target_if_p2p_unregister_noa_event_handler(
+	struct wlan_objmgr_psoc *psoc, void *arg)
+{
+	int status;
+	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	target_if_debug("psoc:%pK, arg:%pK", psoc, arg);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = wmi_unified_unregister_event(wmi_handle,
+			wmi_p2p_noa_event_id);
+
+	target_if_debug("wmi unregister noa event handle, status:%d",
+		status);
+
+	return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS target_if_p2p_set_ps(struct wlan_objmgr_psoc *psoc,
+	struct p2p_ps_config *ps_config)
+{
+	struct p2p_ps_params cmd;
+	QDF_STATUS status;
+	 wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!ps_config) {
+		target_if_err("ps config parameters is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	target_if_debug("psoc:%pK, vdev_id:%d, opp_ps:%d", psoc,
+			ps_config->vdev_id, ps_config->opp_ps);
+
+	cmd.opp_ps = ps_config->opp_ps;
+	cmd.ctwindow = ps_config->ct_window;
+	cmd.count = ps_config->count;
+	cmd.duration = ps_config->duration;
+	cmd.interval = ps_config->interval;
+	cmd.single_noa_duration = ps_config->single_noa_duration;
+	cmd.ps_selection = ps_config->ps_selection;
+	cmd.session_id =  ps_config->vdev_id;
+
+	if (ps_config->opp_ps)
+		status = wmi_unified_set_p2pgo_oppps_req(wmi_handle,
+				   &cmd);
+	else
+		status = wmi_unified_set_p2pgo_noa_req_cmd(wmi_handle,
+				   &cmd);
+
+	if (status != QDF_STATUS_SUCCESS)
+		target_if_err("Failed to send set uapsd param, %d",
+				status);
+
+	return status;
+}
+
+QDF_STATUS target_if_p2p_set_noa(struct wlan_objmgr_psoc *psoc,
+	uint32_t vdev_id, bool disable_noa)
+{
+	struct vdev_set_params param;
+	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	target_if_debug("psoc:%pK, vdev_id:%d disable_noa:%d",
+				psoc, vdev_id, disable_noa);
+	param.if_id = vdev_id;
+	param.param_id = WMI_VDEV_PARAM_DISABLE_NOA_P2P_GO;
+	param.param_value = (uint32_t)disable_noa;
+
+	return wmi_unified_vdev_set_param_send(wmi_handle, &param);
+}
+
+static int target_p2p_mac_rx_filter_event_handler(ol_scn_t scn, uint8_t *data,
+						  uint32_t datalen)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wmi_unified *wmi_handle;
+	struct p2p_set_mac_filter_evt event_info;
+	struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	if (!scn || !data) {
+		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
+		return -EINVAL;
+	}
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("null psoc");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("null wmi handle");
+		return -EINVAL;
+	}
+
+	if (wmi_extract_mac_addr_rx_filter_evt_param(wmi_handle, data,
+						     &event_info)) {
+		target_if_err("failed to extract wmi p2p noa event");
+		return -EINVAL;
+	}
+	target_if_debug("vdev_id %d status %d", event_info.vdev_id,
+			event_info.status);
+	p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc);
+	if (p2p_rx_ops && p2p_rx_ops->add_mac_addr_filter_evt_handler)
+		status = p2p_rx_ops->add_mac_addr_filter_evt_handler(
+					psoc, &event_info);
+	else
+		target_if_debug("no add mac addr filter event handler");
+
+	return qdf_status_to_os_return(status);
+}
+
+static QDF_STATUS target_if_p2p_register_macaddr_rx_filter_evt_handler(
+		struct wlan_objmgr_psoc *psoc, bool reg)
+{
+	int status;
+	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	target_if_debug("psoc:%pK, register %d mac addr rx evt", psoc, reg);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+	if (reg)
+		status = wmi_unified_register_event(
+				wmi_handle,
+				wmi_vdev_add_macaddr_rx_filter_event_id,
+				target_p2p_mac_rx_filter_event_handler);
+	else
+		status = wmi_unified_unregister_event(
+				wmi_handle,
+				wmi_vdev_add_macaddr_rx_filter_event_id);
+
+	return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE;
+}
+
+static QDF_STATUS target_if_p2p_set_mac_addr_rx_filter_cmd(
+	struct wlan_objmgr_psoc *psoc, struct p2p_set_mac_filter *param)
+{
+	wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc);
+
+	if (!wmi_handle) {
+		target_if_err("Invalid wmi handle");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return wmi_send_set_mac_addr_rx_filter_cmd(wmi_handle, param);
+}
+
+void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+	struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops;
+
+	if (!tx_ops) {
+		target_if_err("lmac tx_ops is null");
+		return;
+	}
+
+	p2p_tx_ops = &tx_ops->p2p;
+	p2p_tx_ops->set_ps = target_if_p2p_set_ps;
+	p2p_tx_ops->set_noa = target_if_p2p_set_noa;
+	p2p_tx_ops->reg_noa_ev_handler =
+			target_if_p2p_register_noa_event_handler;
+	p2p_tx_ops->unreg_noa_ev_handler =
+			target_if_p2p_unregister_noa_event_handler;
+	p2p_tx_ops->reg_mac_addr_rx_filter_handler =
+		target_if_p2p_register_macaddr_rx_filter_evt_handler;
+	p2p_tx_ops->set_mac_addr_rx_filter_cmd =
+		target_if_p2p_set_mac_addr_rx_filter_cmd;
+	/* register P2P listen offload callbacks */
+	target_if_p2p_lo_register_tx_ops(p2p_tx_ops);
+}

+ 116 - 0
components/target_if/tdls/inc/target_if_tdls.h

@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. 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: offload lmac interface APIs for tdls
+ *
+ */
+
+#ifndef __TARGET_IF_TDLS_H__
+#define __TARGET_IF_TDLS_H__
+
+struct tdls_info;
+struct wlan_objmgr_psoc;
+struct tdls_peer_update_state;
+struct tdls_channel_switch_params;
+struct sta_uapsd_trig_params;
+
+/**
+ * target_if_tdls_update_fw_state() - lmac handler to update tdls fw state
+ * @psoc: psoc object
+ * @param: tdls state parameter
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_tdls_update_fw_state(struct wlan_objmgr_psoc *psoc,
+			       struct tdls_info *param);
+
+/**
+ * target_if_tdls_update_peer_state() - lmac handler to update tdls peer state
+ * @psoc: psoc object
+ * @peer_params: tdls peer state params
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_tdls_update_peer_state(struct wlan_objmgr_psoc *psoc,
+				 struct tdls_peer_update_state *peer_params);
+
+/**
+ * target_if_tdls_set_offchan_mode() - lmac handler to set tdls off channel mode
+ * @psoc: psoc object
+ * @params: tdls channel swithc params
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc,
+				struct tdls_channel_switch_params *params);
+
+/**
+ * target_if_tdls_set_uapsd() - lmac handler to set uapsd auto trigger cmd
+ * @psoc: psoc object
+ * @params: upasd parameters
+ *
+ * This function sets the trigger
+ * uapsd params such as service interval, delay interval
+ * and suspend interval which will be used by the firmware
+ * to send trigger frames periodically when there is no
+ * traffic on the transmit side.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_tdls_set_uapsd(struct wlan_objmgr_psoc *psoc,
+			 struct sta_uapsd_trig_params *params);
+
+/**
+ * target_if_tdls_register_event_handler() - lmac handler to register tdls event
+ * handler
+ * @psoc : psoc object
+ * @arg: argument passed to lmac
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_tdls_register_event_handler(struct wlan_objmgr_psoc *psoc,
+				      void *arg);
+
+/**
+ * target_if_tdls_unregister_event_handler() - lmac handler to unregister tdls
+ * event handler
+ * @psoc : psoc object
+ * @arg: argument passed to lmac
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_tdls_unregister_event_handler(struct wlan_objmgr_psoc *psoc,
+					void *arg);
+
+/**
+ * target_if_tdls_register_tx_ops() - lmac handler to register tdls tx ops
+ * callback functions
+ * @tx_ops: wlan_lmac_if_tx_ops object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_tdls_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops);
+#endif

+ 214 - 0
components/target_if/tdls/src/target_if_tdls.c

@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: offload lmac interface APIs for tdls
+ *
+ */
+
+#include <qdf_mem.h>
+#include <target_if.h>
+#include <qdf_status.h>
+#include <wmi_unified_api.h>
+#include <wmi_unified_priv.h>
+#include <wmi_unified_param.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_tdls_tgt_api.h>
+#include <target_if_tdls.h>
+#include <cdp_txrx_peer_ops.h>
+#include <wlan_utility.h>
+
+static inline struct wlan_lmac_if_tdls_rx_ops *
+target_if_tdls_get_rx_ops(struct wlan_objmgr_psoc *psoc)
+{
+	return &psoc->soc_cb.rx_ops.tdls_rx_ops;
+}
+
+static int
+target_if_tdls_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wmi_unified *wmi_handle;
+	struct wlan_lmac_if_tdls_rx_ops *tdls_rx_ops;
+	struct tdls_event_info info;
+	QDF_STATUS status;
+
+	if (!scn || !data) {
+		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
+		return -EINVAL;
+	}
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("null psoc");
+		return -EINVAL;
+	}
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+
+	if (!wmi_handle) {
+		target_if_err("null wmi_handle");
+		return -EINVAL;
+	}
+
+	if (wmi_extract_vdev_tdls_ev_param(wmi_handle, data, &info)) {
+		target_if_err("Failed to extract wmi tdls event");
+		return -EINVAL;
+	}
+
+	tdls_rx_ops = target_if_tdls_get_rx_ops(psoc);
+	if (tdls_rx_ops && tdls_rx_ops->tdls_ev_handler) {
+		status = tdls_rx_ops->tdls_ev_handler(psoc, &info);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			target_if_err("fail to handle tdls event");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+QDF_STATUS
+target_if_tdls_update_fw_state(struct wlan_objmgr_psoc *psoc,
+			       struct tdls_info *param)
+{
+	QDF_STATUS status;
+	uint8_t tdls_state;
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("Invalid WMI handle");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (TDLS_SUPPORT_EXP_TRIG_ONLY == param->tdls_state)
+		tdls_state = WMI_TDLS_ENABLE_PASSIVE;
+	else if (TDLS_SUPPORT_IMP_MODE == param->tdls_state ||
+		 TDLS_SUPPORT_EXT_CONTROL == param->tdls_state)
+		tdls_state = WMI_TDLS_ENABLE_CONNECTION_TRACKER_IN_HOST;
+	else
+		tdls_state = WMI_TDLS_DISABLE;
+
+	status = wmi_unified_update_fw_tdls_state_cmd(wmi_handle,
+						      param, tdls_state);
+
+	target_if_debug("vdev_id %d", param->vdev_id);
+	return status;
+}
+
+QDF_STATUS
+target_if_tdls_update_peer_state(struct wlan_objmgr_psoc *psoc,
+				 struct tdls_peer_update_state *peer_params)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+target_if_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc,
+				struct tdls_channel_switch_params *params)
+{
+	QDF_STATUS status;
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("Invalid WMI handle");
+		return QDF_STATUS_E_FAILURE;
+	}
+	status = wmi_unified_set_tdls_offchan_mode_cmd(wmi_handle,
+						       params);
+
+	return status;
+}
+
+QDF_STATUS
+target_if_tdls_set_uapsd(struct wlan_objmgr_psoc *psoc,
+			 struct sta_uapsd_trig_params *params)
+{
+	QDF_STATUS ret;
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("Invalid WMI handle");
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (!wmi_service_enabled(wmi_handle,
+				    wmi_sta_uapsd_basic_auto_trig) ||
+	    !wmi_service_enabled(wmi_handle,
+				    wmi_sta_uapsd_var_auto_trig)) {
+		target_if_debug("Trigger uapsd is not supported vdev id %d",
+				params->vdevid);
+		return QDF_STATUS_SUCCESS;
+	}
+	ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wmi_handle,
+						      params);
+
+	if (QDF_IS_STATUS_ERROR(ret))
+		target_if_err("Failed to send set uapsd param ret = %d", ret);
+
+	return ret;
+}
+
+QDF_STATUS
+target_if_tdls_register_event_handler(struct wlan_objmgr_psoc *psoc,
+				      void *arg)
+{
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("null wmi_handle");
+		return QDF_STATUS_E_INVAL;
+	}
+	return wmi_unified_register_event(wmi_handle,
+					  wmi_tdls_peer_event_id,
+					  target_if_tdls_event_handler);
+}
+
+QDF_STATUS
+target_if_tdls_unregister_event_handler(struct wlan_objmgr_psoc *psoc,
+					void *arg)
+{
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("null wmi_handle");
+		return QDF_STATUS_E_INVAL;
+	}
+	return wmi_unified_unregister_event(wmi_handle,
+					    wmi_tdls_peer_event_id);
+}
+
+QDF_STATUS
+target_if_tdls_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+	struct wlan_lmac_if_tdls_tx_ops *tdls_txops;
+
+	tdls_txops = &tx_ops->tdls_tx_ops;
+
+	tdls_txops->update_fw_state = target_if_tdls_update_fw_state;
+	tdls_txops->update_peer_state = target_if_tdls_update_peer_state;
+	tdls_txops->set_offchan_mode = target_if_tdls_set_offchan_mode;
+	tdls_txops->tdls_reg_ev_handler = target_if_tdls_register_event_handler;
+	tdls_txops->tdls_unreg_ev_handler =
+		target_if_tdls_unregister_event_handler;
+	tdls_txops->tdls_set_uapsd = target_if_tdls_set_uapsd;
+
+	return QDF_STATUS_SUCCESS;
+}

+ 2431 - 0
components/tdls/core/src/wlan_tdls_cmds_process.c

@@ -0,0 +1,2431 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_cmds_process.c
+ *
+ * TDLS north bound commands implementation
+ */
+#include <wlan_reg_services_api.h>
+#include <wlan_serialization_api.h>
+#include "wlan_tdls_main.h"
+#include "wlan_tdls_peer.h"
+#include "wlan_tdls_ct.h"
+#include "wlan_tdls_mgmt.h"
+#include "wlan_tdls_cmds_process.h"
+#include "wlan_tdls_tgt_api.h"
+#include "wlan_policy_mgr_api.h"
+
+static uint16_t tdls_get_connected_peer(struct tdls_soc_priv_obj *soc_obj)
+{
+	return soc_obj->connected_peer_count;
+}
+
+/**
+ * tdls_decrement_peer_count() - decrement connected TDLS peer counter
+ * @soc_obj: TDLS soc object
+ *
+ * Used in scheduler thread context, no lock needed.
+ *
+ * Return: None.
+ */
+void tdls_decrement_peer_count(struct tdls_soc_priv_obj *soc_obj)
+{
+	if (soc_obj->connected_peer_count)
+		soc_obj->connected_peer_count--;
+
+	tdls_debug("Connected peer count %d", soc_obj->connected_peer_count);
+}
+
+/**
+ * tdls_increment_peer_count() - increment connected TDLS peer counter
+ * @soc_obj: TDLS soc object
+ *
+ * Used in scheduler thread context, no lock needed.
+ *
+ * Return: None.
+ */
+static void tdls_increment_peer_count(struct tdls_soc_priv_obj *soc_obj)
+{
+	soc_obj->connected_peer_count++;
+	tdls_debug("Connected peer count %d", soc_obj->connected_peer_count);
+}
+
+/**
+ * tdls_validate_current_mode() - check current TDL mode
+ * @soc_obj: TDLS soc object
+ *
+ * Return: QDF_STATUS_SUCCESS if TDLS enabled, other for disabled
+ */
+static QDF_STATUS tdls_validate_current_mode(struct tdls_soc_priv_obj *soc_obj)
+{
+	if (soc_obj->tdls_current_mode == TDLS_SUPPORT_DISABLED ||
+	    soc_obj->tdls_current_mode == TDLS_SUPPORT_SUSPENDED) {
+		tdls_err("TDLS mode disabled OR not enabled, current mode %d",
+			 soc_obj->tdls_current_mode);
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+static char *tdls_get_ser_cmd_str(enum  wlan_serialization_cmd_type type)
+{
+	switch (type) {
+	case WLAN_SER_CMD_TDLS_ADD_PEER:
+		return "TDLS_ADD_PEER_CMD";
+	case WLAN_SER_CMD_TDLS_DEL_PEER:
+		return "TDLS_DEL_PEER_CMD";
+	case WLAN_SER_CMD_TDLS_SEND_MGMT:
+		return "TDLS_SEND_MGMT_CMD";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+void
+tdls_release_serialization_command(struct wlan_objmgr_vdev *vdev,
+				   enum wlan_serialization_cmd_type type)
+{
+	struct wlan_serialization_queued_cmd_info cmd = {0};
+
+	cmd.cmd_type = type;
+	cmd.cmd_id = 0;
+	cmd.vdev = vdev;
+
+	tdls_debug("release %s", tdls_get_ser_cmd_str(type));
+	/* Inform serialization for command completion */
+	wlan_serialization_remove_cmd(&cmd);
+}
+
+/**
+ * tdls_pe_add_peer() - send TDLS add peer request to PE
+ * @req: TDL add peer request
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+static QDF_STATUS tdls_pe_add_peer(struct tdls_add_peer_request *req)
+{
+	struct tdls_add_sta_req *addstareq;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_peer *peer;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct scheduler_msg msg = {0,};
+	QDF_STATUS status;
+
+	addstareq = qdf_mem_malloc(sizeof(*addstareq));
+	if (!addstareq) {
+		tdls_err("allocate failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+	vdev = req->vdev;
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (!soc_obj) {
+		tdls_err("NULL tdls soc object");
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	addstareq->tdls_oper = TDLS_OPER_ADD;
+	addstareq->transaction_id = 0;
+
+	addstareq->session_id = wlan_vdev_get_id(vdev);
+	peer = wlan_vdev_get_bsspeer(vdev);
+	if (!peer) {
+		tdls_err("bss peer is NULL");
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+	status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get bss peer");
+		goto error;
+	}
+	wlan_peer_obj_lock(peer);
+	qdf_mem_copy(addstareq->bssid.bytes,
+		     wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
+	wlan_peer_obj_unlock(peer);
+	wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID);
+	qdf_mem_copy(addstareq->peermac.bytes, req->add_peer_req.peer_addr,
+		     QDF_MAC_ADDR_SIZE);
+
+	tdls_debug("for " QDF_MAC_ADDR_STR,
+		   QDF_MAC_ADDR_ARRAY(addstareq->peermac.bytes));
+	msg.type = soc_obj->tdls_add_sta_req;
+	msg.bodyptr = addstareq;
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_PE,
+					QDF_MODULE_ID_PE, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("fail to post pe msg to add peer");
+		goto error;
+	}
+	return status;
+error:
+	qdf_mem_free(addstareq);
+	return status;
+}
+
+/**
+ * tdls_pe_del_peer() - send TDLS delete peer request to PE
+ * @req: TDLS delete peer request
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+QDF_STATUS tdls_pe_del_peer(struct tdls_del_peer_request *req)
+{
+	struct tdls_del_sta_req *delstareq;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_peer *peer;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct scheduler_msg msg = {0,};
+	QDF_STATUS status;
+
+	delstareq = qdf_mem_malloc(sizeof(*delstareq));
+	if (!delstareq) {
+		tdls_err("allocate failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+	vdev = req->vdev;
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (!soc_obj) {
+		tdls_err("NULL tdls soc object");
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	delstareq->transaction_id = 0;
+
+	delstareq->session_id = wlan_vdev_get_id(vdev);
+	peer = wlan_vdev_get_bsspeer(vdev);
+	if (!peer) {
+		tdls_err("bss peer is NULL");
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+	status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get bss peer");
+		goto error;
+	}
+	wlan_peer_obj_lock(peer);
+	qdf_mem_copy(delstareq->bssid.bytes,
+		     wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
+	wlan_peer_obj_unlock(peer);
+	wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID);
+	qdf_mem_copy(delstareq->peermac.bytes, req->del_peer_req.peer_addr,
+		     QDF_MAC_ADDR_SIZE);
+
+	tdls_debug("for " QDF_MAC_ADDR_STR,
+		   QDF_MAC_ADDR_ARRAY(delstareq->peermac.bytes));
+	msg.type = soc_obj->tdls_del_sta_req;
+	msg.bodyptr = delstareq;
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_PE,
+					QDF_MODULE_ID_PE, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("fail to post pe msg to del peer");
+		goto error;
+	}
+	return status;
+error:
+	qdf_mem_free(delstareq);
+	return status;
+}
+
+/**
+ * tdls_pe_update_peer() - send TDLS update peer request to PE
+ * @req: TDLS update peer request
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+static QDF_STATUS tdls_pe_update_peer(struct tdls_update_peer_request *req)
+{
+	struct tdls_add_sta_req *addstareq;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_peer *peer;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct scheduler_msg msg = {0,};
+	struct tdls_update_peer_params *update_peer;
+	QDF_STATUS status;
+
+	addstareq = qdf_mem_malloc(sizeof(*addstareq));
+	if (!addstareq) {
+		tdls_err("allocate failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+	vdev = req->vdev;
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (!soc_obj) {
+		tdls_err("NULL tdls soc object");
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+	update_peer = &req->update_peer_req;
+
+	addstareq->tdls_oper = TDLS_OPER_UPDATE;
+	addstareq->transaction_id = 0;
+
+	addstareq->session_id = wlan_vdev_get_id(vdev);
+	peer = wlan_vdev_get_bsspeer(vdev);
+	if (!peer) {
+		tdls_err("bss peer is NULL");
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+	status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get bss peer");
+		goto error;
+	}
+	wlan_peer_obj_lock(peer);
+	qdf_mem_copy(addstareq->bssid.bytes,
+		     wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
+	wlan_peer_obj_unlock(peer);
+	wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID);
+	qdf_mem_copy(addstareq->peermac.bytes, update_peer->peer_addr,
+		     QDF_MAC_ADDR_SIZE);
+	addstareq->capability = update_peer->capability;
+	addstareq->uapsd_queues = update_peer->uapsd_queues;
+	addstareq->max_sp = update_peer->max_sp;
+
+	qdf_mem_copy(addstareq->extn_capability,
+		     update_peer->extn_capability, WLAN_MAC_MAX_EXTN_CAP);
+	addstareq->htcap_present = update_peer->htcap_present;
+	qdf_mem_copy(&addstareq->ht_cap,
+		     &update_peer->ht_cap,
+		     sizeof(update_peer->ht_cap));
+	addstareq->vhtcap_present = update_peer->vhtcap_present;
+	qdf_mem_copy(&addstareq->vht_cap,
+		     &update_peer->vht_cap,
+		     sizeof(update_peer->vht_cap));
+	addstareq->supported_rates_length = update_peer->supported_rates_len;
+	qdf_mem_copy(&addstareq->supported_rates,
+		     update_peer->supported_rates,
+		     update_peer->supported_rates_len);
+	tdls_debug("for " QDF_MAC_ADDR_STR,
+		   QDF_MAC_ADDR_ARRAY(addstareq->peermac.bytes));
+
+	msg.type = soc_obj->tdls_add_sta_req;
+	msg.bodyptr = addstareq;
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_PE,
+					QDF_MODULE_ID_PE, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("fail to post pe msg to update peer");
+		goto error;
+	}
+	return status;
+error:
+	qdf_mem_free(addstareq);
+	return status;
+}
+
+static QDF_STATUS
+tdls_internal_add_peer_rsp(struct tdls_add_peer_request *req,
+			   QDF_STATUS status)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_osif_indication ind;
+	QDF_STATUS ret;
+
+	if (!req || !req->vdev) {
+		tdls_err("req: %pK", req);
+		return QDF_STATUS_E_INVAL;
+	}
+	vdev = req->vdev;
+	ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_SB_ID);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		tdls_err("can't get vdev object");
+		return ret;
+	}
+
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (soc_obj && soc_obj->tdls_event_cb) {
+		ind.vdev = vdev;
+		ind.status = status;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_ADD_PEER, &ind);
+	}
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+tdls_internal_update_peer_rsp(struct tdls_update_peer_request *req,
+			      QDF_STATUS status)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_osif_indication ind;
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS ret;
+
+	if (!req || !req->vdev) {
+		tdls_err("req: %pK", req);
+		return QDF_STATUS_E_INVAL;
+	}
+	vdev = req->vdev;
+	ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_SB_ID);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		tdls_err("can't get vdev object");
+		return ret;
+	}
+
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (soc_obj && soc_obj->tdls_event_cb) {
+		ind.vdev = vdev;
+		ind.status = status;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_ADD_PEER, &ind);
+	}
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS tdls_internal_del_peer_rsp(struct tdls_oper_request *req)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_osif_indication ind;
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+
+	if (!req || !req->vdev) {
+		tdls_err("req: %pK", req);
+		return QDF_STATUS_E_INVAL;
+	}
+	vdev = req->vdev;
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get vdev object");
+		return status;
+	}
+
+	soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev);
+	if (soc_obj && soc_obj->tdls_event_cb) {
+		ind.vdev = req->vdev;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_DEL_PEER, &ind);
+	}
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS tdls_activate_add_peer(struct tdls_add_peer_request *req)
+{
+	QDF_STATUS status;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct tdls_peer *peer;
+	uint16_t curr_tdls_peers;
+	const uint8_t *mac;
+	struct tdls_osif_indication ind;
+
+	if (!req->vdev) {
+		tdls_err("vdev null when add tdls peer");
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	mac = req->add_peer_req.peer_addr;
+	soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev);
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(req->vdev);
+
+	if (!soc_obj || !vdev_obj) {
+		tdls_err("soc_obj: %pK, vdev_obj: %pK", soc_obj, vdev_obj);
+		return QDF_STATUS_E_INVAL;
+	}
+	status = tdls_validate_current_mode(soc_obj);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto addrsp;
+
+	peer = tdls_get_peer(vdev_obj, mac);
+	if (!peer) {
+		tdls_err("peer: " QDF_MAC_ADDR_STR " not exist. invalid",
+			 QDF_MAC_ADDR_ARRAY(mac));
+		status = QDF_STATUS_E_INVAL;
+		goto addrsp;
+	}
+
+	/* in add station, we accept existing valid sta_id if there is */
+	if ((peer->link_status > TDLS_LINK_CONNECTING) ||
+	    (TDLS_STA_INDEX_CHECK((peer->sta_id)))) {
+		tdls_notice("link_status %d sta_id %d add peer ignored",
+			    peer->link_status, peer->sta_id);
+		status = QDF_STATUS_SUCCESS;
+		goto addrsp;
+	}
+
+	/* when others are on-going, we want to change link_status to idle */
+	if (tdls_is_progress(vdev_obj, mac, true)) {
+		tdls_notice(QDF_MAC_ADDR_STR " TDLS setuping. Req declined.",
+			    QDF_MAC_ADDR_ARRAY(mac));
+		status = QDF_STATUS_E_PERM;
+		goto setlink;
+	}
+
+	/* first to check if we reached to maximum supported TDLS peer. */
+	curr_tdls_peers = tdls_get_connected_peer(soc_obj);
+	if (soc_obj->max_num_tdls_sta <= curr_tdls_peers) {
+		tdls_err(QDF_MAC_ADDR_STR
+			 " Request declined. Current %d, Max allowed %d.",
+			 QDF_MAC_ADDR_ARRAY(mac), curr_tdls_peers,
+			 soc_obj->max_num_tdls_sta);
+		status = QDF_STATUS_E_PERM;
+		goto setlink;
+	}
+
+	tdls_set_peer_link_status(peer,
+				  TDLS_LINK_CONNECTING, TDLS_LINK_SUCCESS);
+
+	status = tdls_pe_add_peer(req);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto setlink;
+
+	return QDF_STATUS_SUCCESS;
+
+setlink:
+	tdls_set_link_status(vdev_obj, mac, TDLS_LINK_IDLE,
+			     TDLS_LINK_UNSPECIFIED);
+addrsp:
+	if (soc_obj->tdls_event_cb) {
+		ind.status = status;
+		ind.vdev = req->vdev;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_ADD_PEER, &ind);
+	}
+
+	return QDF_STATUS_E_PERM;
+}
+
+static QDF_STATUS
+tdls_add_peer_serialize_callback(struct wlan_serialization_command *cmd,
+				 enum wlan_serialization_cb_reason reason)
+{
+	struct tdls_add_peer_request *req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!cmd || !cmd->umac_cmd) {
+		tdls_err("cmd: %pK, reason: %d", cmd, reason);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	req = cmd->umac_cmd;
+	tdls_debug("reason: %d, req %pK", reason, req);
+
+	switch (reason) {
+	case WLAN_SER_CB_ACTIVATE_CMD:
+		/* command moved to active list
+		 */
+		status = tdls_activate_add_peer(req);
+		break;
+
+	case WLAN_SER_CB_CANCEL_CMD:
+		/* command removed from pending list.
+		 * notify os interface the status
+		 */
+		status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE);
+		break;
+
+	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
+		/* active command time out. */
+		status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE);
+		break;
+
+	case WLAN_SER_CB_RELEASE_MEM_CMD:
+		/* command successfully completed.
+		 * release memory & vdev reference count
+		 */
+		wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(req);
+		break;
+
+	default:
+		/* Do nothing but logging */
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+}
+
+void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc,
+				  uint8_t action_code)
+{
+	if (!tdls_soc)
+		return;
+
+	if (TDLS_TEARDOWN != action_code ||
+	    !tdls_soc->tdls_nss_switch_in_progress)
+		return;
+
+	if (tdls_soc->tdls_teardown_peers_cnt != 0)
+		tdls_soc->tdls_teardown_peers_cnt--;
+	if (tdls_soc->tdls_teardown_peers_cnt == 0) {
+		if (tdls_soc->tdls_nss_transition_mode ==
+		    TDLS_NSS_TRANSITION_S_1x1_to_2x2) {
+			/* TDLS NSS switch is fully completed, so
+			 * reset the flags.
+			 */
+			tdls_notice("TDLS NSS switch is fully completed");
+			tdls_soc->tdls_nss_switch_in_progress = false;
+			tdls_soc->tdls_nss_teardown_complete = false;
+		} else {
+			/* TDLS NSS switch is not yet completed, but
+			 * tdls teardown is completed for all the
+			 * peers.
+			 */
+			tdls_notice("teardown done & NSS switch in progress");
+			tdls_soc->tdls_nss_teardown_complete = true;
+		}
+		tdls_soc->tdls_nss_transition_mode =
+			TDLS_NSS_TRANSITION_S_UNKNOWN;
+	}
+
+}
+
+/**
+ * tdls_set_cap() - set TDLS capability type
+ * @tdls_vdev: tdls vdev object
+ * @mac: peer mac address
+ * @cap: TDLS capability type
+ *
+ * Return: 0 if successful or negative errno otherwise
+ */
+int tdls_set_cap(struct tdls_vdev_priv_obj *tdls_vdev, const uint8_t *mac,
+			  enum tdls_peer_capab cap)
+{
+	struct tdls_peer *curr_peer;
+
+	curr_peer = tdls_get_peer(tdls_vdev, mac);
+	if (curr_peer == NULL) {
+		tdls_err("curr_peer is NULL");
+		return -EINVAL;
+	}
+
+	curr_peer->tdls_support = cap;
+	return 0;
+}
+
+static int tdls_validate_setup_frames(struct tdls_soc_priv_obj *tdls_soc,
+				struct tdls_validate_action_req *tdls_validate)
+{
+	/* supplicant still sends tdls_mgmt(SETUP_REQ)
+	 * even after we return error code at
+	 * 'add_station()'. Hence we have this check
+	 * again in addition to add_station().	Anyway,
+	 * there is no harm to double-check.
+	 */
+	if (TDLS_SETUP_REQUEST == tdls_validate->action_code) {
+		tdls_err(QDF_MAC_ADDR_STR " TDLS Max peer already connected. action (%d) declined. Num of peers (%d), Max allowed (%d).",
+			 QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+			 tdls_validate->action_code,
+			 tdls_soc->connected_peer_count,
+			 tdls_soc->max_num_tdls_sta);
+		return -EINVAL;
+	}
+	/* maximum reached. tweak to send
+	 * error code to peer and return error
+	 * code to supplicant
+	 */
+	tdls_validate->status_code = QDF_STATUS_E_RESOURCES;
+	tdls_err(QDF_MAC_ADDR_STR " TDLS Max peer already connected, send response status (%d). Num of peers (%d), Max allowed (%d).",
+		 QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+		 tdls_validate->action_code,
+		 tdls_soc->connected_peer_count,
+		 tdls_soc->max_num_tdls_sta);
+
+	tdls_validate->max_sta_failed = -EPERM;
+	return 0;
+}
+
+int tdls_validate_mgmt_request(struct tdls_action_frame_request *tdls_mgmt_req)
+{
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc;
+	struct tdls_peer *curr_peer;
+	struct tdls_peer *temp_peer;
+	QDF_STATUS status;
+	uint8_t vdev_id;
+
+	struct tdls_validate_action_req *tdls_validate =
+		tdls_mgmt_req->chk_frame;
+
+	if (!tdls_validate || !tdls_validate->vdev)
+		return -EINVAL;
+
+	if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(tdls_validate->vdev,
+							&tdls_vdev,
+							&tdls_soc))
+		return -ENOTSUPP;
+
+	/*
+	 * STA or P2P client should be connected and authenticated before
+	 *  sending any TDLS frames
+	 */
+	if (!tdls_is_vdev_connected(tdls_validate->vdev) ||
+	    !tdls_is_vdev_authenticated(tdls_validate->vdev)) {
+		tdls_err("STA is not connected or not authenticated.");
+		return -EAGAIN;
+	}
+
+	/* other than teardown frame, mgmt frames are not sent if disabled */
+	if (TDLS_TEARDOWN != tdls_validate->action_code) {
+		if (!tdls_check_is_tdls_allowed(tdls_validate->vdev)) {
+			tdls_err("TDLS not allowed, reject MGMT, action = %d",
+				tdls_validate->action_code);
+			return -EPERM;
+		}
+		/* if tdls_mode is disabled, then decline the peer's request */
+		if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode ||
+		    TDLS_SUPPORT_SUSPENDED == tdls_soc->tdls_current_mode) {
+			tdls_notice(QDF_MAC_ADDR_STR
+				" TDLS mode is disabled. action %d declined.",
+				QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+				tdls_validate->action_code);
+			return -ENOTSUPP;
+		}
+		if (tdls_soc->tdls_nss_switch_in_progress) {
+			tdls_err("nss switch in progress, action %d declined "
+				QDF_MAC_ADDR_STR,
+				tdls_validate->action_code,
+				QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac));
+			return -EAGAIN;
+		}
+	}
+
+	if (TDLS_IS_SETUP_ACTION(tdls_validate->action_code)) {
+		if (NULL != tdls_is_progress(tdls_vdev,
+			tdls_validate->peer_mac, true)) {
+			tdls_err("setup is ongoing. action %d declined for "
+				 QDF_MAC_ADDR_STR,
+				 tdls_validate->action_code,
+				 QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac));
+			return -EPERM;
+		}
+	}
+
+	/*  call hdd_wmm_is_acm_allowed() */
+	vdev_id = wlan_vdev_get_id(tdls_validate->vdev);
+	if (!tdls_soc->tdls_wmm_cb(vdev_id)) {
+		tdls_debug("admission ctrl set to VI, send the frame with least AC (BK) for action %d",
+			   tdls_validate->action_code);
+		tdls_mgmt_req->use_default_ac = false;
+	} else {
+		tdls_mgmt_req->use_default_ac = true;
+	}
+
+	if (TDLS_SETUP_REQUEST == tdls_validate->action_code ||
+	    TDLS_SETUP_RESPONSE == tdls_validate->action_code) {
+		if (tdls_soc->max_num_tdls_sta <=
+			tdls_soc->connected_peer_count) {
+			status = tdls_validate_setup_frames(tdls_soc,
+							    tdls_validate);
+			if (QDF_STATUS_SUCCESS != status)
+				return status;
+			/* fall through to send setup resp
+			 * with failure status code
+			 */
+		} else {
+			curr_peer =
+				tdls_find_peer(tdls_vdev,
+					       tdls_validate->peer_mac);
+			if (curr_peer) {
+				if (TDLS_IS_LINK_CONNECTED(curr_peer)) {
+					tdls_err(QDF_MAC_ADDR_STR " already connected action %d declined.",
+						QDF_MAC_ADDR_ARRAY(
+						tdls_validate->peer_mac),
+						tdls_validate->action_code);
+
+					return -EPERM;
+				}
+			}
+		}
+	}
+
+	tdls_notice("tdls_mgmt" QDF_MAC_ADDR_STR " action %d, dialog_token %d status %d, len = %zu",
+		   QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+		   tdls_validate->action_code, tdls_validate->dialog_token,
+		   tdls_validate->status_code, tdls_validate->len);
+
+	/*Except teardown responder will not be used so just make 0 */
+	tdls_validate->responder = 0;
+	if (TDLS_TEARDOWN == tdls_validate->action_code) {
+		temp_peer = tdls_find_peer(tdls_vdev, tdls_validate->peer_mac);
+		if (!temp_peer) {
+			tdls_err(QDF_MAC_ADDR_STR " peer doesn't exist",
+				     QDF_MAC_ADDR_ARRAY(
+				     tdls_validate->peer_mac));
+			return -EPERM;
+		}
+
+		if (TDLS_IS_LINK_CONNECTED(temp_peer))
+			tdls_validate->responder = temp_peer->is_responder;
+		else {
+			tdls_err(QDF_MAC_ADDR_STR " peer doesn't exist or not connected %d dialog_token %d status %d, tdls_validate->len = %zu",
+				 QDF_MAC_ADDR_ARRAY(tdls_validate->peer_mac),
+				 temp_peer->link_status,
+				 tdls_validate->dialog_token,
+				 tdls_validate->status_code,
+				 tdls_validate->len);
+			return -EPERM;
+		}
+	}
+
+	/* For explicit trigger of DIS_REQ come out of BMPS for
+	 * successfully receiving DIS_RSP from peer.
+	 */
+	if ((TDLS_SETUP_RESPONSE == tdls_validate->action_code) ||
+	    (TDLS_SETUP_CONFIRM == tdls_validate->action_code) ||
+	    (TDLS_DISCOVERY_RESPONSE == tdls_validate->action_code) ||
+	    (TDLS_DISCOVERY_REQUEST == tdls_validate->action_code)) {
+		/* Fw will take care if PS offload is enabled. */
+		if (TDLS_DISCOVERY_REQUEST != tdls_validate->action_code)
+			tdls_set_cap(tdls_vdev, tdls_validate->peer_mac,
+					      TDLS_CAP_SUPPORTED);
+	}
+	return 0;
+}
+
+QDF_STATUS tdls_process_add_peer(struct tdls_add_peer_request *req)
+{
+	struct wlan_serialization_command cmd = {0,};
+	enum wlan_serialization_status ser_cmd_status;
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!req || !req->vdev) {
+		tdls_err("req: %pK", req);
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+	vdev = req->vdev;
+	cmd.cmd_type = WLAN_SER_CMD_TDLS_ADD_PEER;
+	cmd.cmd_id = 0;
+	cmd.cmd_cb = (wlan_serialization_cmd_callback)
+		tdls_add_peer_serialize_callback;
+	cmd.umac_cmd = req;
+	cmd.source = WLAN_UMAC_COMP_TDLS;
+	cmd.is_high_priority = false;
+	cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT;
+	cmd.vdev = vdev;
+	cmd.is_blocking = true;
+
+	ser_cmd_status = wlan_serialization_request(&cmd);
+	tdls_debug("req: 0x%pK wlan_serialization_request status:%d", req,
+		   ser_cmd_status);
+
+	switch (ser_cmd_status) {
+	case WLAN_SER_CMD_PENDING:
+		/* command moved to pending list. Do nothing */
+		break;
+	case WLAN_SER_CMD_ACTIVE:
+		/* command moved to active list. Do nothing */
+		break;
+	case WLAN_SER_CMD_DENIED_LIST_FULL:
+	case WLAN_SER_CMD_DENIED_RULES_FAILED:
+	case WLAN_SER_CMD_DENIED_UNSPECIFIED:
+		/* notify os interface about internal error*/
+		status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+		/* cmd can't be serviced.
+		 * release tdls_add_peer_request memory
+		 */
+		qdf_mem_free(req);
+		break;
+	default:
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	return status;
+error:
+	status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE);
+	qdf_mem_free(req);
+	return status;
+}
+
+static QDF_STATUS
+tdls_activate_update_peer(struct tdls_update_peer_request *req)
+{
+	QDF_STATUS status;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_peer *curr_peer;
+	uint16_t curr_tdls_peers;
+	const uint8_t *mac;
+	struct tdls_update_peer_params *update_peer;
+	struct tdls_osif_indication ind;
+
+	if (!req->vdev) {
+		tdls_err("vdev object NULL when add TDLS peer");
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	mac = req->update_peer_req.peer_addr;
+	vdev = req->vdev;
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+	if (!soc_obj || !vdev_obj) {
+		tdls_err("soc_obj: %pK, vdev_obj: %pK", soc_obj, vdev_obj);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = tdls_validate_current_mode(soc_obj);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto updatersp;
+
+	curr_peer = tdls_get_peer(vdev_obj, mac);
+	if (!curr_peer) {
+		tdls_err(QDF_MAC_ADDR_STR " not exist. return invalid",
+			 QDF_MAC_ADDR_ARRAY(mac));
+		status = QDF_STATUS_E_INVAL;
+		goto updatersp;
+	}
+
+	/* in change station, we accept only when sta_id is valid */
+	if (curr_peer->link_status > TDLS_LINK_CONNECTING ||
+	    !(TDLS_STA_INDEX_CHECK(curr_peer->sta_id))) {
+		tdls_err(QDF_MAC_ADDR_STR " link %d. sta %d. update peer %s",
+			 QDF_MAC_ADDR_ARRAY(mac), curr_peer->link_status,
+			 curr_peer->sta_id,
+			 (TDLS_STA_INDEX_CHECK(curr_peer->sta_id)) ? "ignored"
+			 : "declined");
+		status = (TDLS_STA_INDEX_CHECK(curr_peer->sta_id)) ?
+			QDF_STATUS_SUCCESS : QDF_STATUS_E_PERM;
+		goto updatersp;
+	}
+
+	/* when others are on-going, we want to change link_status to idle */
+	if (tdls_is_progress(vdev_obj, mac, true)) {
+		tdls_notice(QDF_MAC_ADDR_STR " TDLS setuping. Req declined.",
+			    QDF_MAC_ADDR_ARRAY(mac));
+		status = QDF_STATUS_E_PERM;
+		goto setlink;
+	}
+
+	curr_tdls_peers = tdls_get_connected_peer(soc_obj);
+	if (soc_obj->max_num_tdls_sta <= curr_tdls_peers) {
+		tdls_err(QDF_MAC_ADDR_STR
+			 " Request declined. Current: %d, Max allowed: %d.",
+			 QDF_MAC_ADDR_ARRAY(mac), curr_tdls_peers,
+			 soc_obj->max_num_tdls_sta);
+		status = QDF_STATUS_E_PERM;
+		goto setlink;
+	}
+	update_peer = &req->update_peer_req;
+
+	if (update_peer->htcap_present)
+		curr_peer->spatial_streams = update_peer->ht_cap.mcsset[1];
+
+	tdls_set_peer_caps(vdev_obj, mac, &req->update_peer_req);
+	status = tdls_pe_update_peer(req);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto setlink;
+
+	return QDF_STATUS_SUCCESS;
+
+setlink:
+	tdls_set_link_status(vdev_obj, mac, TDLS_LINK_IDLE,
+			     TDLS_LINK_UNSPECIFIED);
+updatersp:
+	if (soc_obj->tdls_event_cb) {
+		ind.status = status;
+		ind.vdev = vdev;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_ADD_PEER, &ind);
+	}
+
+	return QDF_STATUS_E_PERM;
+}
+
+static QDF_STATUS
+tdls_update_peer_serialize_callback(struct wlan_serialization_command *cmd,
+				    enum wlan_serialization_cb_reason reason)
+{
+	struct tdls_update_peer_request *req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!cmd || !cmd->umac_cmd) {
+		tdls_err("cmd: %pK, reason: %d", cmd, reason);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	req = cmd->umac_cmd;
+	tdls_debug("reason: %d, req %pK", reason, req);
+
+	switch (reason) {
+	case WLAN_SER_CB_ACTIVATE_CMD:
+		/* command moved to active list
+		 */
+		status = tdls_activate_update_peer(req);
+		break;
+
+	case WLAN_SER_CB_CANCEL_CMD:
+		/* command removed from pending list.
+		 * notify os interface the status
+		 */
+		status = tdls_internal_update_peer_rsp(req,
+						       QDF_STATUS_E_FAILURE);
+		break;
+
+	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
+		/* active command time out. */
+		status = tdls_internal_update_peer_rsp(req,
+						       QDF_STATUS_E_FAILURE);
+		break;
+
+	case WLAN_SER_CB_RELEASE_MEM_CMD:
+		/* command successfully completed.
+		 * release memory & release reference count
+		 */
+		wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(req);
+		break;
+
+	default:
+		/* Do nothing but logging */
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+}
+
+QDF_STATUS tdls_process_update_peer(struct tdls_update_peer_request *req)
+{
+	struct wlan_serialization_command cmd = {0,};
+	enum wlan_serialization_status ser_cmd_status;
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!req || !req->vdev) {
+		tdls_err("req: %pK", req);
+		status = QDF_STATUS_E_FAILURE;
+		goto error;
+	}
+
+	vdev = req->vdev;
+	cmd.cmd_type = WLAN_SER_CMD_TDLS_ADD_PEER;
+	cmd.cmd_id = 0;
+	cmd.cmd_cb = (wlan_serialization_cmd_callback)
+		tdls_update_peer_serialize_callback;
+	cmd.umac_cmd = req;
+	cmd.source = WLAN_UMAC_COMP_TDLS;
+	cmd.is_high_priority = false;
+	cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT;
+	cmd.vdev = req->vdev;
+	cmd.is_blocking = true;
+
+	ser_cmd_status = wlan_serialization_request(&cmd);
+	tdls_debug("req: 0x%pK wlan_serialization_request status:%d", req,
+		   ser_cmd_status);
+
+	switch (ser_cmd_status) {
+	case WLAN_SER_CMD_PENDING:
+		/* command moved to pending list. Do nothing */
+		break;
+	case WLAN_SER_CMD_ACTIVE:
+		/* command moved to active list. Do nothing */
+		break;
+	case WLAN_SER_CMD_DENIED_LIST_FULL:
+	case WLAN_SER_CMD_DENIED_RULES_FAILED:
+	case WLAN_SER_CMD_DENIED_UNSPECIFIED:
+		/* notify os interface about internal error*/
+		status = tdls_internal_update_peer_rsp(req,
+						       QDF_STATUS_E_FAILURE);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+		/* cmd can't be serviced.
+		 * release tdls_add_peer_request memory
+		 */
+		qdf_mem_free(req);
+		break;
+	default:
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+error:
+	status = tdls_internal_update_peer_rsp(req, QDF_STATUS_E_FAILURE);
+	qdf_mem_free(req);
+	return status;
+}
+
+static QDF_STATUS tdls_activate_del_peer(struct tdls_oper_request *req)
+{
+	struct tdls_del_peer_request request = {0,};
+
+	request.vdev = req->vdev;
+	request.del_peer_req.peer_addr = req->peer_addr;
+
+	return tdls_pe_del_peer(&request);
+}
+
+static QDF_STATUS
+tdls_del_peer_serialize_callback(struct wlan_serialization_command *cmd,
+				 enum wlan_serialization_cb_reason reason)
+{
+	struct tdls_oper_request *req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!cmd || !cmd->umac_cmd) {
+		tdls_err("cmd: %pK, reason: %d", cmd, reason);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	req = cmd->umac_cmd;
+	tdls_debug("reason: %d, req %pK", reason, req);
+
+	switch (reason) {
+	case WLAN_SER_CB_ACTIVATE_CMD:
+		/* command moved to active list
+		 */
+		status = tdls_activate_del_peer(req);
+		break;
+
+	case WLAN_SER_CB_CANCEL_CMD:
+		/* command removed from pending list.
+		 * notify os interface the status
+		 */
+		status = tdls_internal_del_peer_rsp(req);
+		break;
+
+	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
+		/* active command time out. */
+		status = tdls_internal_del_peer_rsp(req);
+		break;
+
+	case WLAN_SER_CB_RELEASE_MEM_CMD:
+		/* command successfully completed.
+		 * release memory & vdev reference count
+		 */
+		wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(req);
+		break;
+
+	default:
+		/* Do nothing but logging */
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+}
+
+QDF_STATUS tdls_process_del_peer(struct tdls_oper_request *req)
+{
+	struct wlan_serialization_command cmd = {0,};
+	enum wlan_serialization_status ser_cmd_status;
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct tdls_soc_priv_obj *soc_obj;
+	uint8_t *mac;
+	struct tdls_peer *peer;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!req || !req->vdev) {
+		tdls_err("req: %pK", req);
+		status = QDF_STATUS_E_INVAL;
+		goto free_req;
+	}
+
+	vdev = req->vdev;
+
+	/* vdev reference cnt is acquired in ucfg_tdls_oper */
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+
+	if (!vdev_obj || !soc_obj) {
+		tdls_err("tdls vdev_obj: %pK soc_obj: %pK", vdev_obj, soc_obj);
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto error;
+	}
+
+	mac = req->peer_addr;
+	peer = tdls_find_peer(vdev_obj, mac);
+	if (!peer) {
+		tdls_err(QDF_MAC_ADDR_STR
+			 " not found, ignore NL80211_TDLS_ENABLE_LINK",
+			 QDF_MAC_ADDR_ARRAY(mac));
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	if (soc_obj->tdls_dp_vdev_update)
+		soc_obj->tdls_dp_vdev_update(&soc_obj->soc,
+					peer->sta_id,
+					soc_obj->tdls_update_dp_vdev_flags,
+					false);
+
+	cmd.cmd_type = WLAN_SER_CMD_TDLS_DEL_PEER;
+	cmd.cmd_id = 0;
+	cmd.cmd_cb = (wlan_serialization_cmd_callback)
+		tdls_del_peer_serialize_callback;
+	cmd.umac_cmd = req;
+	cmd.source = WLAN_UMAC_COMP_TDLS;
+	cmd.is_high_priority = false;
+	cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT;
+	cmd.vdev = vdev;
+	cmd.is_blocking = true;
+
+	ser_cmd_status = wlan_serialization_request(&cmd);
+	tdls_debug("req: 0x%pK wlan_serialization_request status:%d", req,
+		   ser_cmd_status);
+
+	switch (ser_cmd_status) {
+	case WLAN_SER_CMD_PENDING:
+		/* command moved to pending list. Do nothing */
+		break;
+	case WLAN_SER_CMD_ACTIVE:
+		/* command moved to active list. Do nothing */
+		break;
+	case WLAN_SER_CMD_DENIED_LIST_FULL:
+	case WLAN_SER_CMD_DENIED_RULES_FAILED:
+	case WLAN_SER_CMD_DENIED_UNSPECIFIED:
+		/* notify os interface about internal error*/
+		status = tdls_internal_del_peer_rsp(req);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+		/* cmd can't be serviced.
+		 * release tdls_add_peer_request memory
+		 */
+		qdf_mem_free(req);
+		break;
+	default:
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+error:
+	status = tdls_internal_del_peer_rsp(req);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+free_req:
+	qdf_mem_free(req);
+	return status;
+}
+
+/**
+ * tdls_process_add_peer_rsp() - handle response for update TDLS peer
+ * @rsp: TDLS add peer response
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+static QDF_STATUS tdls_update_peer_rsp(struct tdls_add_sta_rsp *rsp)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct tdls_soc_priv_obj *soc_obj;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct tdls_osif_indication ind;
+
+	psoc = rsp->psoc;
+	if (!psoc) {
+		tdls_err("psoc is NULL");
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_FAILURE;
+	}
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id,
+						    WLAN_TDLS_SB_ID);
+	if (!vdev) {
+		tdls_err("invalid vdev: %d", rsp->session_id);
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_ADD_PEER);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+error:
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (soc_obj && soc_obj->tdls_event_cb) {
+		ind.status = rsp->status_code;
+		ind.vdev = vdev;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_ADD_PEER, &ind);
+	}
+	qdf_mem_free(rsp);
+
+	return status;
+}
+
+/**
+ * tdls_process_send_mgmt_rsp() - handle response for send mgmt
+ * @rsp: TDLS send mgmt response
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+QDF_STATUS tdls_process_send_mgmt_rsp(struct tdls_send_mgmt_rsp *rsp)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct tdls_osif_indication ind;
+
+	psoc = rsp->psoc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id,
+						    WLAN_TDLS_SB_ID);
+	if (!vdev) {
+		tdls_err("invalid vdev");
+		status =  QDF_STATUS_E_INVAL;
+		qdf_mem_free(rsp);
+		return status;
+	}
+	tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc);
+	tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
+	if (!tdls_soc || !tdls_vdev) {
+		tdls_err("soc object:%pK, vdev object:%pK", tdls_soc, tdls_vdev);
+		status = QDF_STATUS_E_FAILURE;
+	}
+
+	tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_SEND_MGMT);
+
+	if (legacy_result_success == rsp->status_code)
+		goto free_rsp;
+	tdls_err("send mgmt failed. status code(=%d)", rsp->status_code);
+	status = QDF_STATUS_E_FAILURE;
+
+	if (tdls_soc && tdls_soc->tdls_event_cb) {
+		ind.vdev = vdev;
+		ind.status = status;
+		tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
+				       TDLS_EVENT_MGMT_TX_ACK_CNF, &ind);
+	}
+
+free_rsp:
+	qdf_mem_free(rsp);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+	return status;
+}
+
+/**
+ * tdls_send_mgmt_tx_completion() - process tx completion
+ * @tx_complete: TDLS mgmt completion info
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+QDF_STATUS tdls_send_mgmt_tx_completion(
+			struct tdls_mgmt_tx_completion_ind *tx_complete)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct tdls_osif_indication ind;
+
+	psoc = tx_complete->psoc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+						    tx_complete->session_id,
+						    WLAN_TDLS_SB_ID);
+
+	if (!vdev) {
+		tdls_err("invalid vdev");
+		status =  QDF_STATUS_E_INVAL;
+		goto free_tx_complete;
+	}
+
+	tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc);
+	tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
+
+	if (!tdls_soc || !tdls_vdev) {
+		tdls_err("soc object:%pK, vdev object:%pK", tdls_soc, tdls_vdev);
+		status = QDF_STATUS_E_FAILURE;
+	}
+
+	if (tdls_soc && tdls_soc->tdls_event_cb) {
+		ind.vdev = vdev;
+		ind.status = tx_complete->tx_complete_status;
+		tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
+			       TDLS_EVENT_MGMT_TX_ACK_CNF, &ind);
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+free_tx_complete:
+	qdf_mem_free(tx_complete);
+	return status;
+}
+
+/**
+ * tdls_add_peer_rsp() - handle response for add TDLS peer
+ * @rsp: TDLS add peer response
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+static QDF_STATUS tdls_add_peer_rsp(struct tdls_add_sta_rsp *rsp)
+{
+	uint8_t sta_idx;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct tdls_soc_priv_obj *soc_obj = NULL;
+	struct tdls_conn_info *conn_rec;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct tdls_osif_indication ind;
+
+	psoc = rsp->psoc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id,
+						    WLAN_TDLS_SB_ID);
+	if (!vdev) {
+		tdls_err("invalid vdev: %d", rsp->session_id);
+		status =  QDF_STATUS_E_INVAL;
+		goto error;
+	}
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+	if (!soc_obj || !vdev_obj) {
+		tdls_err("soc object:%pK, vdev object:%pK", soc_obj, vdev_obj);
+		status = QDF_STATUS_E_FAILURE;
+		goto cmddone;
+	}
+	if (rsp->status_code) {
+		tdls_err("add sta failed. status code(=%d)", rsp->status_code);
+		status = QDF_STATUS_E_FAILURE;
+	} else {
+		conn_rec = soc_obj->tdls_conn_info;
+		for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta;
+		     sta_idx++) {
+			if (INVALID_TDLS_PEER_ID == conn_rec[sta_idx].sta_id) {
+				conn_rec[sta_idx].session_id = rsp->session_id;
+				conn_rec[sta_idx].sta_id = rsp->sta_id;
+				qdf_copy_macaddr(&conn_rec[sta_idx].peer_mac,
+						 &rsp->peermac);
+				tdls_warn("TDLS: STA IDX at %d is %d of mac "
+					  QDF_MAC_ADDR_STR, sta_idx,
+					  rsp->sta_id, QDF_MAC_ADDR_ARRAY
+					  (rsp->peermac.bytes));
+				break;
+			}
+		}
+
+		if (sta_idx < soc_obj->max_num_tdls_sta) {
+			status = tdls_set_sta_id(vdev_obj, rsp->peermac.bytes,
+						 rsp->sta_id);
+			if (QDF_IS_STATUS_ERROR(status)) {
+				tdls_err("set staid failed");
+				status = QDF_STATUS_E_FAILURE;
+			}
+		} else {
+			status = QDF_STATUS_E_FAILURE;
+		}
+	}
+
+cmddone:
+	tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_ADD_PEER);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+error:
+	if (soc_obj && soc_obj->tdls_event_cb) {
+		ind.vdev = vdev;
+		ind.status = rsp->status_code;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_ADD_PEER, &ind);
+	}
+	qdf_mem_free(rsp);
+
+	return status;
+}
+
+QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp)
+{
+	tdls_debug("peer oper %d", rsp->tdls_oper);
+
+	if (rsp->tdls_oper == TDLS_OPER_ADD)
+		return tdls_add_peer_rsp(rsp);
+	else if (rsp->tdls_oper == TDLS_OPER_UPDATE)
+		return tdls_update_peer_rsp(rsp);
+
+	return QDF_STATUS_E_INVAL;
+}
+
+QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp)
+{
+	uint8_t sta_idx, id;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	struct wlan_objmgr_vdev *vdev;
+	struct wlan_objmgr_psoc *psoc;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct tdls_soc_priv_obj *soc_obj = NULL;
+	struct tdls_conn_info *conn_rec;
+	struct tdls_peer *curr_peer = NULL;
+	const uint8_t *macaddr;
+	struct tdls_osif_indication ind;
+
+	tdls_debug("del peer rsp: vdev %d  peer " QDF_MAC_ADDR_STR,
+		   rsp->session_id, QDF_MAC_ADDR_ARRAY(rsp->peermac.bytes));
+	psoc = rsp->psoc;
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id,
+						    WLAN_TDLS_SB_ID);
+	if (!vdev) {
+		tdls_err("invalid vdev: %d", rsp->session_id);
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+	if (!soc_obj || !vdev_obj) {
+		tdls_err("soc object:%pK, vdev object:%pK", soc_obj, vdev_obj);
+		status = QDF_STATUS_E_FAILURE;
+		goto cmddone;
+	}
+
+	conn_rec = soc_obj->tdls_conn_info;
+	for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta; sta_idx++) {
+		if (conn_rec[sta_idx].session_id != rsp->session_id ||
+		    conn_rec[sta_idx].sta_id != rsp->sta_id)
+			continue;
+
+		macaddr = rsp->peermac.bytes;
+		tdls_warn("TDLS: del STA IDX = %x", rsp->sta_id);
+		curr_peer = tdls_find_peer(vdev_obj, macaddr);
+		if (curr_peer) {
+			tdls_debug(QDF_MAC_ADDR_STR " status is %d",
+				   QDF_MAC_ADDR_ARRAY(macaddr),
+				   curr_peer->link_status);
+
+			id = wlan_vdev_get_id(vdev);
+
+			if (TDLS_IS_LINK_CONNECTED(curr_peer)) {
+				soc_obj->tdls_dereg_peer(
+					soc_obj->tdls_peer_context,
+					id, curr_peer->sta_id);
+				tdls_decrement_peer_count(soc_obj);
+			} else if (TDLS_LINK_CONNECTING ==
+				   curr_peer->link_status) {
+				soc_obj->tdls_dereg_peer(
+					soc_obj->tdls_peer_context,
+					id, curr_peer->sta_id);
+			}
+		}
+		tdls_reset_peer(vdev_obj, macaddr);
+		conn_rec[sta_idx].sta_id = INVALID_TDLS_PEER_ID;
+		conn_rec[sta_idx].session_id = 0xff;
+		qdf_mem_zero(&conn_rec[sta_idx].peer_mac,
+			     QDF_MAC_ADDR_SIZE);
+
+		status = QDF_STATUS_SUCCESS;
+		break;
+	}
+	macaddr = rsp->peermac.bytes;
+	if (!curr_peer) {
+		curr_peer = tdls_find_peer(vdev_obj, macaddr);
+
+		if (curr_peer)
+			tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE,
+						  (curr_peer->link_status ==
+						   TDLS_LINK_TEARING) ?
+						  TDLS_LINK_UNSPECIFIED :
+						  TDLS_LINK_DROPPED_BY_REMOTE);
+	}
+
+cmddone:
+	tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_DEL_PEER);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+error:
+
+	if (soc_obj && soc_obj->tdls_event_cb) {
+		ind.vdev = vdev;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_DEL_PEER, &ind);
+	}
+	qdf_mem_free(rsp);
+
+	return status;
+}
+
+static QDF_STATUS
+tdls_wma_update_peer_state(struct tdls_soc_priv_obj *soc_obj,
+			   struct tdls_peer_update_state *peer_state)
+{
+	struct scheduler_msg msg = {0,};
+	QDF_STATUS status;
+
+	tdls_debug("update TDLS peer " QDF_MAC_ADDR_STR " vdev %d, state %d",
+		   QDF_MAC_ADDR_ARRAY(peer_state->peer_macaddr),
+		   peer_state->vdev_id, peer_state->peer_state);
+	msg.type = soc_obj->tdls_update_peer_state;
+	msg.reserved = 0;
+	msg.bodyptr = peer_state;
+
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_WMA,
+					QDF_MODULE_ID_WMA, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("scheduler_post_msg failed");
+		status = QDF_STATUS_E_FAILURE;
+	}
+
+	return status;
+}
+
+static QDF_STATUS
+tdls_update_uapsd(struct wlan_objmgr_psoc *psoc, struct wlan_objmgr_vdev *vdev,
+		  uint8_t sta_id, uint32_t srvc_int, uint32_t sus_int,
+		  uint8_t dir, uint8_t psb, uint32_t delay_interval)
+{
+	uint8_t i;
+	static const uint8_t ac[AC_PRIORITY_NUM] = {UAPSD_AC_VO, UAPSD_AC_VI,
+						    UAPSD_AC_BK, UAPSD_AC_BE};
+	static const uint8_t tid[AC_PRIORITY_NUM] = {7, 5, 2, 3};
+	uint32_t vdev_id;
+
+	struct sta_uapsd_params tdls_uapsd_params;
+	struct sta_uapsd_trig_params tdls_trig_params;
+	struct wlan_objmgr_peer *bsspeer;
+	uint8_t macaddr[QDF_MAC_ADDR_SIZE];
+	QDF_STATUS status;
+
+	if (!psb) {
+		tdls_debug("No need to configure auto trigger:psb is 0");
+		return QDF_STATUS_SUCCESS;
+	}
+	vdev_id = wlan_vdev_get_id(vdev);
+	bsspeer = wlan_vdev_get_bsspeer(vdev);
+	if (!bsspeer) {
+		tdls_err("bss peer is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	wlan_vdev_obj_lock(vdev);
+	qdf_mem_copy(macaddr,
+		     wlan_peer_get_macaddr(bsspeer), QDF_MAC_ADDR_SIZE);
+	wlan_vdev_obj_unlock(vdev);
+
+	tdls_debug("TDLS uapsd id %d, srvc %d, sus %d, dir %d psb %d delay %d",
+		   sta_id, srvc_int, sus_int, dir, psb, delay_interval);
+	for (i = 0; i < AC_PRIORITY_NUM; i++) {
+		tdls_uapsd_params.wmm_ac = ac[i];
+		tdls_uapsd_params.user_priority = tid[i];
+		tdls_uapsd_params.service_interval = srvc_int;
+		tdls_uapsd_params.delay_interval = delay_interval;
+		tdls_uapsd_params.suspend_interval = sus_int;
+
+		tdls_trig_params.vdevid = vdev_id;
+		tdls_trig_params.num_ac = 1;
+		tdls_trig_params.auto_triggerparam = &tdls_uapsd_params;
+
+		qdf_mem_copy(tdls_trig_params.peer_addr,
+			     macaddr, QDF_MAC_ADDR_SIZE);
+		status = tgt_tdls_set_uapsd(psoc, &tdls_trig_params);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			tdls_err("Failed to set uapsd for vdev %d, status %d",
+				 vdev_id, status);
+		}
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_process_enable_link(struct tdls_oper_request *req)
+{
+	struct tdls_peer *peer;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct wlan_objmgr_vdev *vdev;
+	uint8_t *mac;
+	struct tdls_peer_update_state *peer_update_param;
+	QDF_STATUS status;
+	uint32_t feature;
+	uint8_t id;
+
+	vdev = req->vdev;
+	if (!vdev) {
+		tdls_err("NULL vdev object");
+		qdf_mem_free(req);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	/* vdev reference cnt is acquired in ucfg_tdls_oper */
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+
+	if (!vdev_obj || !soc_obj) {
+		tdls_err("tdls vdev_obj: %pK soc_obj: %pK", vdev_obj, soc_obj);
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto error;
+	}
+
+	mac = req->peer_addr;
+	peer = tdls_find_peer(vdev_obj, mac);
+	if (!peer) {
+		tdls_err(QDF_MAC_ADDR_STR
+			 " not found, ignore NL80211_TDLS_ENABLE_LINK",
+			 QDF_MAC_ADDR_ARRAY(mac));
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	tdls_debug("enable link for peer " QDF_MAC_ADDR_STR " link state %d",
+		   QDF_MAC_ADDR_ARRAY(mac), peer->link_status);
+	if (!TDLS_STA_INDEX_CHECK(peer->sta_id)) {
+		tdls_err("invalid sta idx %u for " QDF_MAC_ADDR_STR,
+			 peer->sta_id, QDF_MAC_ADDR_ARRAY(mac));
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	peer->tdls_support = TDLS_CAP_SUPPORTED;
+	if (TDLS_LINK_CONNECTED != peer->link_status)
+		tdls_set_peer_link_status(peer, TDLS_LINK_CONNECTED,
+					  TDLS_LINK_SUCCESS);
+
+	id = wlan_vdev_get_id(vdev);
+	status = soc_obj->tdls_reg_peer(soc_obj->tdls_peer_context,
+					id, mac, peer->sta_id,
+					peer->qos);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("TDLS register peer fail, status %d", status);
+		goto error;
+	}
+
+	peer_update_param = qdf_mem_malloc(sizeof(*peer_update_param));
+	if (!peer_update_param) {
+		tdls_err("memory allocation failed");
+		status = QDF_STATUS_E_NOMEM;
+		goto error;
+	}
+
+	tdls_extract_peer_state_param(peer_update_param, peer);
+
+	status = tdls_wma_update_peer_state(soc_obj, peer_update_param);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(peer_update_param);
+		status = QDF_STATUS_E_PERM;
+		goto error;
+	}
+
+	tdls_increment_peer_count(soc_obj);
+	feature = soc_obj->tdls_configs.tdls_feature_flags;
+
+	if (soc_obj->tdls_dp_vdev_update)
+		soc_obj->tdls_dp_vdev_update(&soc_obj->soc,
+					peer->sta_id,
+					soc_obj->tdls_update_dp_vdev_flags,
+					((peer->link_status ==
+					TDLS_LINK_CONNECTED) ? true : false));
+
+	tdls_debug("TDLS buffer sta: %d, uapsd_mask %d",
+		   TDLS_IS_BUFFER_STA_ENABLED(feature),
+		   soc_obj->tdls_configs.tdls_uapsd_mask);
+
+	if (TDLS_IS_BUFFER_STA_ENABLED(feature) ||
+	    soc_obj->tdls_configs.tdls_uapsd_mask)
+		tdls_update_uapsd(soc_obj->soc,
+				  vdev, peer->sta_id, 0, 0, BI_DIR, 1,
+				  soc_obj->tdls_configs.delayed_trig_framint);
+error:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+	qdf_mem_free(req);
+
+	return status;
+}
+
+/**
+ * tdls_config_force_peer() - configure an externally controllable TDLS peer
+ * @req: TDLS operation request
+ *
+ * This is not the tdls_process_cmd function. No need to acquire the reference
+ * count, release reference count  and free the request, the caller handle it
+ * correctly.
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other values if failed
+ */
+static QDF_STATUS tdls_config_force_peer(
+	struct tdls_oper_config_force_peer_request *req)
+{
+	struct tdls_peer *peer;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_objmgr_vdev *vdev;
+	const uint8_t *macaddr;
+	uint32_t feature;
+	QDF_STATUS status;
+	struct tdls_peer_update_state *peer_update_param;
+
+	macaddr = req->peer_addr;
+	tdls_debug("NL80211_TDLS_SETUP for " QDF_MAC_ADDR_STR,
+		   QDF_MAC_ADDR_ARRAY(macaddr));
+
+	vdev = req->vdev;
+	pdev = wlan_vdev_get_pdev(vdev);
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (!pdev || !vdev_obj || !soc_obj) {
+		tdls_err("pdev: %pK, vdev_obj: %pK, soc_obj: %pK",
+			 pdev, vdev_obj, soc_obj);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	feature = soc_obj->tdls_configs.tdls_feature_flags;
+	if (!TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature) ||
+	    !TDLS_IS_IMPLICIT_TRIG_ENABLED(feature)) {
+		tdls_err("TDLS ext ctrl or Imp Trig not enabled, %x", feature);
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+
+	peer_update_param = qdf_mem_malloc(sizeof(*peer_update_param));
+	if (!peer_update_param) {
+		tdls_err("memory allocation failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	peer = tdls_get_peer(vdev_obj, macaddr);
+	if (!peer) {
+		tdls_err("peer " QDF_MAC_ADDR_STR " does not exist",
+			 QDF_MAC_ADDR_ARRAY(macaddr));
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto error;
+	}
+	status = tdls_set_force_peer(vdev_obj, macaddr, true);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("set force peer failed");
+		goto error;
+	}
+
+	/* Update the peer mac to firmware, so firmware could update the
+	 * connection table
+	 */
+	peer_update_param->vdev_id = wlan_vdev_get_id(vdev);
+	qdf_mem_copy(peer_update_param->peer_macaddr,
+		     macaddr, QDF_MAC_ADDR_SIZE);
+	peer_update_param->peer_state = TDLS_PEER_ADD_MAC_ADDR;
+
+	status = tdls_wma_update_peer_state(soc_obj, peer_update_param);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("update peer state failed");
+		goto error;
+	}
+
+	soc_obj->tdls_external_peer_count++;
+
+	/* Validate if off channel is DFS channel */
+	if (wlan_reg_is_dfs_ch(pdev, req->chan)) {
+		tdls_err("Resetting TDLS off-channel from %d to %d",
+			 req->chan, WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF);
+		req->chan = WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF;
+	}
+	tdls_set_extctrl_param(peer, req->chan, req->max_latency, req->op_class,
+			       req->min_bandwidth);
+
+	tdls_set_callback(peer, req->callback);
+
+	tdls_set_ct_mode(soc_obj->soc);
+	if (soc_obj->enable_tdls_connection_tracker)
+		tdls_implicit_enable(vdev_obj);
+
+	return status;
+error:
+	qdf_mem_free(peer_update_param);
+	return status;
+}
+
+/**
+ * tdls_process_setup_peer() - process configure an externally
+ *                                    controllable TDLS peer
+ * @req: TDLS operation request
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other values if failed
+ */
+QDF_STATUS tdls_process_setup_peer(struct tdls_oper_request *req)
+{
+	struct tdls_oper_config_force_peer_request peer_req;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status;
+
+	tdls_debug("Configure external TDLS peer " QDF_MAC_ADDR_STR,
+		   QDF_MAC_ADDR_ARRAY(req->peer_addr));
+
+	/* reference cnt is acquired in ucfg_tdls_oper */
+	vdev = req->vdev;
+	if (!vdev) {
+		tdls_err("NULL vdev object");
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto freereq;
+	}
+
+	qdf_mem_zero(&peer_req, sizeof(peer_req));
+	peer_req.vdev = vdev;
+	qdf_mem_copy(peer_req.peer_addr, req->peer_addr, QDF_MAC_ADDR_SIZE);
+
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (!soc_obj) {
+		tdls_err("NULL soc object");
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	peer_req.chan = soc_obj->tdls_configs.tdls_pre_off_chan_num;
+
+	status = tdls_config_force_peer(&peer_req);
+error:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+freereq:
+	qdf_mem_free(req);
+
+	return status;
+}
+
+QDF_STATUS tdls_process_remove_force_peer(struct tdls_oper_request *req)
+{
+	struct tdls_peer *peer;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct wlan_objmgr_vdev *vdev;
+	const uint8_t *macaddr;
+	uint32_t feature;
+	QDF_STATUS status;
+	struct tdls_peer_update_state *peer_update_param;
+	struct tdls_osif_indication ind;
+
+	macaddr = req->peer_addr;
+	tdls_debug("NL80211_TDLS_TEARDOWN for " QDF_MAC_ADDR_STR,
+		   QDF_MAC_ADDR_ARRAY(macaddr));
+
+	vdev = req->vdev;
+	if (!vdev) {
+		tdls_err("NULL vdev object");
+		qdf_mem_free(req);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	/* reference cnt is acquired in ucfg_tdls_oper */
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(req->vdev);
+	soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev);
+	if (!soc_obj || !vdev_obj) {
+		tdls_err("soc_obj: %pK, vdev_obj: %pK", soc_obj, vdev_obj);
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	feature = soc_obj->tdls_configs.tdls_feature_flags;
+	if (!TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature) ||
+	    !TDLS_IS_IMPLICIT_TRIG_ENABLED(feature)) {
+		tdls_err("TDLS ext ctrl or Imp Trig not enabled, %x", feature);
+		status = QDF_STATUS_E_NOSUPPORT;
+		goto error;
+	}
+
+	peer = tdls_find_peer(vdev_obj, macaddr);
+	if (!peer) {
+		tdls_err("peer matching " QDF_MAC_ADDR_STR " not found",
+			 QDF_MAC_ADDR_ARRAY(macaddr));
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto error;
+	}
+
+	tdls_set_peer_link_status(peer, TDLS_LINK_TEARING,
+				  TDLS_LINK_UNSPECIFIED);
+
+	if (soc_obj->tdls_dp_vdev_update)
+		soc_obj->tdls_dp_vdev_update(&soc_obj->soc,
+				peer->sta_id,
+				soc_obj->tdls_update_dp_vdev_flags,
+				false);
+
+	if (soc_obj->tdls_event_cb) {
+		qdf_mem_copy(ind.peer_mac, macaddr, QDF_MAC_ADDR_SIZE);
+		ind.vdev = vdev;
+		ind.reason = TDLS_TEARDOWN_PEER_UNSPEC_REASON;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_TEARDOWN_REQ, &ind);
+	}
+
+	status = tdls_set_force_peer(vdev_obj, macaddr, false);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("set force peer failed");
+		status = QDF_STATUS_E_INVAL;
+		goto error;
+	}
+
+	if (soc_obj->tdls_external_peer_count)
+		soc_obj->tdls_external_peer_count--;
+
+	tdls_set_callback(peer, NULL);
+	peer_update_param = qdf_mem_malloc(sizeof(*peer_update_param));
+	if (!peer_update_param) {
+		tdls_err("memory allocation failed");
+		status = QDF_STATUS_E_NOMEM;
+		goto error;
+	}
+
+	peer_update_param->vdev_id = wlan_vdev_get_id(vdev);
+	qdf_mem_copy(peer_update_param->peer_macaddr,
+		     macaddr, QDF_MAC_ADDR_SIZE);
+	peer_update_param->peer_state = TDLS_PEER_REMOVE_MAC_ADDR;
+	status = tdls_wma_update_peer_state(soc_obj, peer_update_param);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(peer_update_param);
+		goto error;
+	}
+	tdls_set_ct_mode(soc_obj->soc);
+	if (!soc_obj->enable_tdls_connection_tracker)
+		tdls_implicit_disable(vdev_obj);
+
+error:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+	qdf_mem_free(req);
+
+	return status;
+}
+
+static const char *tdls_evt_to_str(enum tdls_event_msg_type type)
+{
+	switch (type) {
+	case TDLS_SHOULD_DISCOVER:
+		return "SHOULD_DISCOVER";
+	case TDLS_SHOULD_TEARDOWN:
+		return "SHOULD_TEARDOWN";
+	case TDLS_PEER_DISCONNECTED:
+		return "SHOULD_PEER_DISCONNECTED";
+	case TDLS_CONNECTION_TRACKER_NOTIFY:
+		return "CONNECTION_TRACKER_NOTIFICATION";
+	default:
+		return "INVALID_TYPE";
+	}
+}
+
+QDF_STATUS tdls_process_should_discover(struct wlan_objmgr_vdev *vdev,
+					struct tdls_event_info *evt)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct tdls_peer *curr_peer;
+	uint32_t feature;
+	uint16_t type;
+
+	/*TODO ignore this if any concurrency detected*/
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+	type = evt->message_type;
+
+	tdls_debug("TDLS %s: " QDF_MAC_ADDR_STR "reason %d",
+		   tdls_evt_to_str(type),
+		   QDF_MAC_ADDR_ARRAY(evt->peermac.bytes),
+		   evt->peer_reason);
+	if (!soc_obj || !vdev_obj) {
+		tdls_err("soc_obj: %pK, vdev_obj: %pK, ignore %s",
+			 soc_obj, vdev_obj, tdls_evt_to_str(type));
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	if (soc_obj->tdls_nss_switch_in_progress) {
+		tdls_err("TDLS antenna switching, ignore %s",
+			 tdls_evt_to_str(type));
+		return QDF_STATUS_SUCCESS;
+	}
+
+	curr_peer = tdls_get_peer(vdev_obj, evt->peermac.bytes);
+	if (!curr_peer) {
+		tdls_notice("curr_peer is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	if (TDLS_LINK_CONNECTED == curr_peer->link_status) {
+		tdls_err("TDLS link status is connected, ignore");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	feature = soc_obj->tdls_configs.tdls_feature_flags;
+	if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature) &&
+	    !curr_peer->is_forced_peer) {
+		tdls_debug("curr_peer is not forced, ignore %s",
+			   tdls_evt_to_str(type));
+		return QDF_STATUS_SUCCESS;
+	}
+
+	tdls_debug("initiate TDLS setup on %s, ext: %d, force: %d, reason: %d",
+		   tdls_evt_to_str(type),
+		   TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature),
+		   curr_peer->is_forced_peer, evt->peer_reason);
+	vdev_obj->curr_candidate = curr_peer;
+	tdls_implicit_send_discovery_request(vdev_obj);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_process_should_teardown(struct wlan_objmgr_vdev *vdev,
+					struct tdls_event_info *evt)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct tdls_peer *curr_peer;
+	uint32_t reason;
+	uint16_t type;
+
+	type = evt->message_type;
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+
+	tdls_debug("TDLS %s: " QDF_MAC_ADDR_STR "reason %d",
+		   tdls_evt_to_str(type),
+		   QDF_MAC_ADDR_ARRAY(evt->peermac.bytes), evt->peer_reason);
+
+	if (!soc_obj || !vdev_obj) {
+		tdls_err("soc_obj: %pK, vdev_obj: %pK, ignore %s",
+			 soc_obj, vdev_obj, tdls_evt_to_str(type));
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	curr_peer = tdls_find_peer(vdev_obj, evt->peermac.bytes);
+	if (!curr_peer) {
+		tdls_notice("curr_peer is null");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	reason = evt->peer_reason;
+	if (TDLS_LINK_CONNECTED == curr_peer->link_status) {
+		tdls_err("%s reason: %d for" QDF_MAC_ADDR_STR,
+			 tdls_evt_to_str(type), evt->peer_reason,
+			 QDF_MAC_ADDR_ARRAY(evt->peermac.bytes));
+		if (reason == TDLS_TEARDOWN_RSSI ||
+		    reason == TDLS_DISCONNECTED_PEER_DELETE ||
+		    reason == TDLS_TEARDOWN_PTR_TIMEOUT ||
+		    reason == TDLS_TEARDOWN_NO_RSP)
+			reason = TDLS_TEARDOWN_PEER_UNREACHABLE;
+		else
+			reason = TDLS_TEARDOWN_PEER_UNSPEC_REASON;
+
+		tdls_indicate_teardown(vdev_obj, curr_peer, reason);
+	} else {
+		tdls_err("TDLS link is not connected, ignore %s",
+			 tdls_evt_to_str(type));
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_process_connection_tracker_notify(struct wlan_objmgr_vdev *vdev,
+						  struct tdls_event_info *evt)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	uint16_t type;
+
+	type = evt->message_type;
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+
+	if (!soc_obj || !vdev_obj) {
+		tdls_err("soc_obj: %pK, vdev_obj: %pK, ignore %s",
+			 soc_obj, vdev_obj, tdls_evt_to_str(type));
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	/*TODO connection tracker update*/
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * tdls_process_set_responder() - Set/clear TDLS peer's responder role
+ * @set_req: set responder request
+ *
+ * Return: 0 for success or -EINVAL otherwise
+ */
+static
+int tdls_process_set_responder(struct tdls_set_responder_req *set_req)
+{
+	struct tdls_peer *curr_peer;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+
+	tdls_vdev = wlan_vdev_get_tdls_vdev_obj(set_req->vdev);
+	if (!tdls_vdev) {
+		tdls_err("tdls vdev obj is NULL");
+		return -EINVAL;
+	}
+	curr_peer = tdls_get_peer(tdls_vdev, set_req->peer_mac);
+	if (curr_peer == NULL) {
+		tdls_err("curr_peer is NULL");
+		return -EINVAL;
+	}
+
+	curr_peer->is_responder = set_req->responder;
+	return 0;
+}
+
+
+/**
+ * tdls_set_responder() - Set/clear TDLS peer's responder role
+ * @set_req: set responder request
+ *
+ * Return: 0 for success or -EINVAL otherwise
+ */
+int tdls_set_responder(struct tdls_set_responder_req *set_req)
+{
+	QDF_STATUS status;
+
+	if (!set_req || !set_req->vdev) {
+		tdls_err("Invalid input params %pK", set_req);
+		return -EINVAL;
+	}
+
+	status = wlan_objmgr_vdev_try_get_ref(set_req->vdev, WLAN_TDLS_NB_ID);
+	if (QDF_STATUS_SUCCESS != status) {
+		tdls_err("vdev object is deleted");
+		return -EINVAL;
+	}
+
+	status = tdls_process_set_responder(set_req);
+
+	wlan_objmgr_vdev_release_ref(set_req->vdev, WLAN_TDLS_NB_ID);
+	qdf_mem_free(set_req);
+	return status;
+}
+
+static int tdls_teardown_links(struct tdls_soc_priv_obj *soc_obj, uint32_t mode)
+{
+	uint8_t staidx;
+	struct tdls_peer *curr_peer;
+	struct tdls_conn_info *conn_rec;
+	int ret = 0;
+
+	conn_rec = soc_obj->tdls_conn_info;
+	for (staidx = 0; staidx < soc_obj->max_num_tdls_sta; staidx++) {
+		if (conn_rec[staidx].sta_id == INVALID_TDLS_PEER_ID)
+			continue;
+
+		curr_peer = tdls_find_all_peer(soc_obj,
+					       conn_rec[staidx].peer_mac.bytes);
+		if (!curr_peer)
+			continue;
+
+		/* if supported only 1x1, skip it */
+		if (curr_peer->spatial_streams == HW_MODE_SS_1x1)
+			continue;
+
+		tdls_debug("Indicate TDLS teardown (staId %d)",
+			   curr_peer->sta_id);
+		tdls_indicate_teardown(curr_peer->vdev_priv, curr_peer,
+				       TDLS_TEARDOWN_PEER_UNSPEC_REASON);
+
+		soc_obj->tdls_teardown_peers_cnt++;
+	}
+
+	if (soc_obj->tdls_teardown_peers_cnt >= 1) {
+		soc_obj->tdls_nss_switch_in_progress = true;
+		tdls_debug("TDLS peers to be torn down = %d",
+			   soc_obj->tdls_teardown_peers_cnt);
+
+		/* set the antenna switch transition mode */
+		if (mode == HW_MODE_SS_1x1) {
+			soc_obj->tdls_nss_transition_mode =
+				TDLS_NSS_TRANSITION_S_2x2_to_1x1;
+			ret = -EAGAIN;
+		} else {
+			soc_obj->tdls_nss_transition_mode =
+				TDLS_NSS_TRANSITION_S_1x1_to_2x2;
+			ret = 0;
+		}
+		tdls_debug("TDLS teardown for antenna switch operation starts");
+	}
+
+	return ret;
+}
+
+QDF_STATUS tdls_process_antenna_switch(struct tdls_antenna_switch_request *req)
+{
+	QDF_STATUS status;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct wlan_objmgr_vdev *vdev = NULL;
+	uint32_t vdev_nss;
+	int ant_switch_state = 0;
+	uint32_t vdev_id;
+	enum QDF_OPMODE opmode;
+	uint8_t channel;
+	struct tdls_osif_indication ind;
+
+	if (!req) {
+		tdls_err("null req");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	vdev = req->vdev;
+	if (!vdev) {
+		tdls_err("null vdev");
+		qdf_mem_free(req);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = tdls_get_vdev_objects(vdev, &vdev_obj, &soc_obj);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get vdev_obj & soc_obj");
+		goto get_obj_err;
+	}
+
+	if (soc_obj->connected_peer_count == 0)
+		goto ant_sw_done;
+
+	if (soc_obj->tdls_nss_switch_in_progress) {
+		if (!soc_obj->tdls_nss_teardown_complete) {
+			tdls_err("TDLS antenna switch is in progress");
+			goto ant_sw_in_progress;
+		} else {
+			goto ant_sw_done;
+		}
+	}
+
+	vdev_id = wlan_vdev_get_id(vdev);
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
+	channel = policy_mgr_get_channel(soc_obj->soc,
+			policy_mgr_convert_device_mode_to_qdf_type(opmode),
+			&vdev_id);
+
+	/* Check supported nss for TDLS, if is 1x1, no need to teardown links */
+	if (WLAN_REG_IS_24GHZ_CH(channel))
+		vdev_nss = soc_obj->tdls_configs.tdls_vdev_nss_2g;
+	else
+		vdev_nss = soc_obj->tdls_configs.tdls_vdev_nss_5g;
+
+	if (vdev_nss == HW_MODE_SS_1x1) {
+		tdls_debug("Supported NSS is 1x1, no need to teardown TDLS links");
+		goto ant_sw_done;
+	}
+
+	if (tdls_teardown_links(soc_obj, req->mode) == 0)
+		goto ant_sw_done;
+
+ant_sw_in_progress:
+	ant_switch_state = -EAGAIN;
+ant_sw_done:
+	if (soc_obj->tdls_event_cb) {
+		ind.vdev = vdev;
+		ind.status = ant_switch_state;
+		soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data,
+				       TDLS_EVENT_ANTENNA_SWITCH, &ind);
+	}
+
+	if (soc_obj->tdls_nss_switch_in_progress &&
+	    soc_obj->tdls_nss_teardown_complete) {
+		soc_obj->tdls_nss_switch_in_progress = false;
+		soc_obj->tdls_nss_teardown_complete = false;
+	}
+	tdls_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d",
+		   soc_obj->tdls_nss_switch_in_progress,
+		   soc_obj->tdls_nss_teardown_complete);
+
+get_obj_err:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+	qdf_mem_free(req);
+
+	return status;
+}
+
+QDF_STATUS tdls_antenna_switch_flush_callback(struct scheduler_msg *msg)
+{
+	struct tdls_antenna_switch_request *req;
+
+	if (!msg || !msg->bodyptr) {
+		tdls_err("msg: 0x%pK", msg);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	req = msg->bodyptr;
+	wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
+	qdf_mem_free(req);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void wlan_tdls_offchan_parms_callback(struct wlan_objmgr_vdev *vdev)
+{
+	if (!vdev) {
+		tdls_err("vdev is NULL");
+		return;
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+}
+
+int tdls_process_set_offchannel(struct tdls_set_offchannel *req)
+{
+	int status;
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+
+	if (tdls_get_vdev_objects(req->vdev, &tdls_vdev_obj, &tdls_soc_obj) !=
+		QDF_STATUS_SUCCESS) {
+		status = -ENOTSUPP;
+		goto free;
+	}
+
+	tdls_debug("TDLS offchannel to be configured %d", req->offchannel);
+
+	if (req->offchannel)
+		status = tdls_set_tdls_offchannel(tdls_soc_obj,
+						  req->offchannel);
+	else
+		status = -ENOTSUPP;
+
+free:
+
+	if (req->callback)
+		req->callback(req->vdev);
+	qdf_mem_free(req);
+
+	return status;
+}
+
+int tdls_process_set_offchan_mode(struct tdls_set_offchanmode *req)
+{
+	int status;
+
+	tdls_debug("TDLS offchan mode to be configured %d", req->offchan_mode);
+	status = tdls_set_tdls_offchannelmode(req->vdev, req->offchan_mode);
+
+	if (req->callback)
+		req->callback(req->vdev);
+	qdf_mem_free(req);
+
+	return status;
+}
+
+int tdls_process_set_secoffchanneloffset(
+		struct tdls_set_secoffchanneloffset *req)
+{
+	int status;
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+
+	if (tdls_get_vdev_objects(req->vdev, &tdls_vdev_obj, &tdls_soc_obj) !=
+		QDF_STATUS_SUCCESS) {
+		status = -ENOTSUPP;
+		goto free;
+	}
+
+	tdls_debug("TDLS offchannel offset to be configured %d",
+		   req->offchan_offset);
+	status = tdls_set_tdls_secoffchanneloffset(tdls_soc_obj,
+						   req->offchan_offset);
+
+free:
+
+	if (req->callback)
+		req->callback(req->vdev);
+	qdf_mem_free(req);
+
+	return status;
+}

+ 420 - 0
components/tdls/core/src/wlan_tdls_cmds_process.h

@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_cmds_process.h
+ *
+ * TDLS north bound commands include file
+ */
+
+#ifndef _WLAN_TDLS_CMDS_PROCESS_H_
+#define _WLAN_TDLS_CMDS_PROCESS_H_
+
+#define TDLS_IS_SETUP_ACTION(action) \
+	((TDLS_SETUP_REQUEST <= action) && \
+	(TDLS_SETUP_CONFIRM >= action))
+
+/**
+ * enum legacy_result_code - defined to comply with tSirResultCodes, need refine
+ *                           when mlme converged.
+ * @legacy_result_success: success
+ * @legacy_result_max: max result value
+ */
+enum legacy_result_code {
+	legacy_result_success,
+	legacy_result_max = 0x7FFFFFFF
+};
+
+/**
+ * struct tdls_send_mgmt_rsp - TDLS Response struct PE --> TDLS module
+ *                           same as struct tSirSmeRsp
+ * @message_type: message type eWNI_SME_TDLS_SEND_MGMT_RSP
+ * @length: message length
+ * @session_id: session id
+ * @transaction_id: transaction id
+ * @status_code: status code as tSirResultCodes
+ * @psoc: soc object
+ */
+struct tdls_send_mgmt_rsp {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t session_id;
+	uint16_t transaction_id;
+	enum legacy_result_code status_code;
+	struct wlan_objmgr_psoc *psoc;
+};
+
+/**
+ * struct tdls_mgmt_tx_completion_ind - TDLS TX completion PE --> TDLS module
+ *                           same as struct sSirMgmtTxCompletionInd
+ * @message_type: message type eWNI_SME_MGMT_FRM_TX_COMPLETION_IND
+ * @length: message length
+ * @session_id: session id
+ * @tx_complete_status: tx complete status
+ * @psoc: soc object
+ */
+struct tdls_mgmt_tx_completion_ind {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t session_id;      /* Session ID */
+	uint32_t tx_complete_status;
+	struct wlan_objmgr_psoc *psoc;
+};
+
+/**
+ * struct tdls_add_sta_req - TDLS request struct TDLS module --> PE
+ *                           same as struct tSirTdlsAddStaReq;
+ * @message_type: eWNI_SME_TDLS_ADD_STA_REQ
+ * @length: message length
+ * @session_id: session id
+ * @transaction_id: transaction id for cmd
+ * @bssid: bssid
+ * @tdls_oper: add peer type
+ * @peermac: MAC address for TDLS peer
+ * @capability: mac capability as sSirMacCapabilityInfo
+ * @extn_capability: extent capability
+ * @supported_rates_length: rates length
+ * @supported_rates: supported rates
+ * @htcap_present: ht capability present
+ * @ht_cap: ht capability
+ * @vhtcap_present: vht capability present
+ * @vht_cap: vht capability
+ * @uapsd_queues: uapsd queue as sSirMacQosInfoStation
+ * @max_sp: maximum service period
+ */
+struct tdls_add_sta_req {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t session_id;
+	uint16_t transaction_id;
+	struct qdf_mac_addr bssid;
+	enum tdls_add_oper tdls_oper;
+	struct qdf_mac_addr peermac;
+	uint16_t capability;
+	uint8_t extn_capability[WLAN_MAC_MAX_EXTN_CAP];
+	uint8_t supported_rates_length;
+	uint8_t supported_rates[WLAN_MAC_MAX_SUPP_RATES];
+	uint8_t htcap_present;
+	struct htcap_cmn_ie ht_cap;
+	uint8_t vhtcap_present;
+	struct vhtcap vht_cap;
+	uint8_t uapsd_queues;
+	uint8_t max_sp;
+};
+
+/**
+ * struct tdls_add_sta_rsp - TDLS Response struct PE --> TDLS module
+ *                           same as struct sSirTdlsAddStaRsp
+ * @message_type: message type eWNI_SME_TDLS_ADD_STA_RSP
+ * @length: message length
+ * @status_code: status code as tSirResultCodes
+ * @peermac: MAC address of the TDLS peer
+ * @session_id: session id
+ * @sta_id: sta id
+ * @sta_type: sta type
+ * @tdls_oper: add peer type
+ * @psoc: soc object
+ */
+struct tdls_add_sta_rsp {
+	uint16_t message_type;
+	uint16_t length;
+	QDF_STATUS status_code;
+	struct qdf_mac_addr peermac;
+	uint8_t session_id;
+	uint16_t sta_id;
+	uint16_t sta_type;
+	enum tdls_add_oper tdls_oper;
+	struct wlan_objmgr_psoc *psoc;
+};
+
+/**
+ * struct tdls_del_sta_req - TDLS Request struct TDLS module --> PE
+ *                           same as sSirTdlsDelStaReq
+ * @message_type: message type eWNI_SME_TDLS_DEL_STA_REQ
+ * @length: message length
+ * @session_id: session id
+ * @transaction_id: transaction id for cmd
+ * @bssid: bssid
+ * @peermac: MAC address of the TDLS peer
+ */
+struct tdls_del_sta_req {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t session_id;
+	uint16_t transaction_id;
+	struct qdf_mac_addr bssid;
+	struct qdf_mac_addr peermac;
+};
+
+/**
+ * struct tdls_del_sta_rsp - TDLS Response struct PE --> TDLS module
+ *                           same as sSirTdlsDelStaRsp
+ * @message_type: message type eWNI_SME_TDLS_DEL_STA_RSP
+ * @length: message length
+ * @session_id: session id
+ * @status_code: status code as tSirResultCodes
+ * @peermac: MAC address of the TDLS peer
+ * @sta_id: sta id
+ * @psoc: soc object
+ */
+struct tdls_del_sta_rsp {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t session_id;
+	QDF_STATUS status_code;
+	struct qdf_mac_addr peermac;
+	uint16_t sta_id;
+	struct wlan_objmgr_psoc *psoc;
+};
+
+/**
+ * tdls_process_add_peer() - add TDLS peer
+ * @req: TDLS add peer request
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other value if failed
+ */
+QDF_STATUS tdls_process_add_peer(struct tdls_add_peer_request *req);
+
+/**
+ * tdls_process_del_peer() - del TDLS peer
+ * @req: TDLS del peer request
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other value if failed
+ */
+QDF_STATUS tdls_process_del_peer(struct tdls_oper_request *req);
+
+/**
+ * tdls_process_enable_link() - enable TDLS link
+ * @req: TDLS enable link request
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other value if failed
+ */
+QDF_STATUS tdls_process_enable_link(struct tdls_oper_request *req);
+
+/**
+ * tdls_process_setup_peer() - process configure an externally
+ *                                    controllable TDLS peer
+ * @req: TDLS configure force peer request
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other values if failed
+ */
+QDF_STATUS tdls_process_setup_peer(struct tdls_oper_request *req);
+
+/**
+ * tdls_process_remove_force_peer() - process remove an externally controllable
+ *                                    TDLS peer
+ * @req: TDLS operation request
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other values if failed
+ */
+QDF_STATUS tdls_process_remove_force_peer(struct tdls_oper_request *req);
+
+/**
+ * tdls_process_update_peer() - update TDLS peer
+ * @req: TDLS update peer request
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other value if failed
+ */
+QDF_STATUS tdls_process_update_peer(struct tdls_update_peer_request *req);
+
+/**
+ * tdls_process_antenna_switch() - handle TDLS antenna switch
+ * @req: TDLS antenna switch request
+ *
+ * Rely on callback to indicate the antenna switch state to caller.
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other value if failed.
+ */
+QDF_STATUS tdls_process_antenna_switch(struct tdls_antenna_switch_request *req);
+
+/**
+ * tdls_antenna_switch_flush_callback() - flush TDLS antenna switch request
+ * @msg: scheduler message contains tdls antenna switch event
+ *
+ * This function call is invoked when scheduler thread is going down
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_antenna_switch_flush_callback(struct scheduler_msg *msg);
+
+/**
+ * tdls_pe_del_peer() - send TDLS delete peer request to PE
+ * @req: TDLS delete peer request
+ *
+ * Return: QDF status
+ */
+QDF_STATUS tdls_pe_del_peer(struct tdls_del_peer_request *req);
+
+/**
+ * tdls_process_add_peer_rsp() - handle response for add or update TDLS peer
+ * @rsp: TDLS add peer response
+ *
+ * Return: QDF status
+ */
+QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp);
+
+/**
+ * tdls_reset_nss() - reset tdls nss parameters
+ * @tdls_soc: TDLS soc object
+ * @action_code: action code
+ *
+ * Return: None
+ */
+void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc,
+				  uint8_t action_code);
+
+/**
+ * tdls_release_serialization_command() - TDLS wrapper to
+ * relases serialization command.
+ * @vdev: Object manager vdev
+ * @type: command to release.
+ *
+ * Return: None
+ */
+
+void
+tdls_release_serialization_command(struct wlan_objmgr_vdev *vdev,
+				   enum wlan_serialization_cmd_type type);
+
+/**
+ * tdls_set_cap() - set TDLS capability type
+ * @tdls_vdev: tdls vdev object
+ * @mac: peer mac address
+ * @cap: TDLS capability type
+ *
+ * Return: 0 if successful or negative errno otherwise
+ */
+int tdls_set_cap(struct tdls_vdev_priv_obj *tdls_vdev, const uint8_t *mac,
+			  enum tdls_peer_capab cap);
+
+/**
+ * tdls_process_send_mgmt_rsp() - handle response for send mgmt
+ * @rsp: TDLS send mgmt response
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+QDF_STATUS tdls_process_send_mgmt_rsp(struct tdls_send_mgmt_rsp *rsp);
+
+/**
+ * tdls_send_mgmt_tx_completion() - process tx completion
+ * @tx_complete: TDLS mgmt completion info
+ *
+ * Return: QDF_STATUS_SUCCESS for success; other values if failed
+ */
+QDF_STATUS tdls_send_mgmt_tx_completion(
+			struct tdls_mgmt_tx_completion_ind *tx_complete);
+
+/**
+ * tdls_process_add_peer_rsp() - handle response for delete TDLS peer
+ * @rsp: TDLS delete peer response
+ *
+ * Return: QDF status
+ */
+QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp);
+
+/**
+ * tdls_process_should_discover() - handle tdls should_discover event
+ * @vdev: vdev object
+ * @evt: event info
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_process_should_discover(struct wlan_objmgr_vdev *vdev,
+					struct tdls_event_info *evt);
+
+/**
+ * tdls_process_should_teardown() - handle tdls should_teardown event
+ * @vdev: vdev object
+ * @evt: event info
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_process_should_teardown(struct wlan_objmgr_vdev *vdev,
+					struct tdls_event_info *evt);
+
+/**
+ * tdls_process_connection_tracker_notify() -handle tdls connect tracker notify
+ * @vdev: vdev object
+ * @evt: event info
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_process_connection_tracker_notify(struct wlan_objmgr_vdev *vdev,
+						  struct tdls_event_info *evt);
+
+/**
+ * tdls_validate_mgmt_request() -validate mgmt request
+ * @tdls_validate: action frame request
+ *
+ * Return: 0 for success or -EINVAL otherwise
+ */
+int tdls_validate_mgmt_request(struct tdls_action_frame_request *tdls_mgmt_req);
+
+/**
+ * tdls_set_responder() - Set/clear TDLS peer's responder role
+ * @set_req: set responder request
+ *
+ * Return: 0 for success or -EINVAL otherwise
+ */
+int tdls_set_responder(struct tdls_set_responder_req *set_req);
+
+/**
+ * tdls_decrement_peer_count() - decrement connected TDLS peer counter
+ * @soc_obj: TDLS soc object
+ *
+ * Used in scheduler thread context, no lock needed.
+ *
+ * Return: None.
+ */
+void tdls_decrement_peer_count(struct tdls_soc_priv_obj *soc_obj);
+
+/**
+ * wlan_tdls_offchan_parms_callback() - Callback to release ref count
+ * @vdev: vdev object
+ *
+ * Return: none
+ */
+void wlan_tdls_offchan_parms_callback(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * tdls_process_set_offchannel() - Handle set offchannel request for TDLS
+ * @req: TDLS set offchannel request
+ *
+ * Return: int status
+ */
+int tdls_process_set_offchannel(struct tdls_set_offchannel *req);
+
+/**
+ * tdls_process_set_offchan_mode() - Handle set offchan mode request for TDLS
+ * @req: TDLS set offchannel mode request
+ *
+ * Return: int status
+ */
+int tdls_process_set_offchan_mode(struct tdls_set_offchanmode *req);
+
+/**
+ * tdls_process_set_secoffchanneloffset() - Handle set sec offchannel
+ * offset request for TDLS
+ * @req: TDLS set secoffchannel offchannel request
+ *
+ * Return: int status
+ */
+int tdls_process_set_secoffchanneloffset(
+		struct tdls_set_secoffchanneloffset *req);
+
+#endif

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

@@ -0,0 +1,1319 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_ct.c
+ *
+ * TDLS connection tracker function definitions
+ */
+
+#include "wlan_tdls_main.h"
+#include "wlan_tdls_peer.h"
+#include "wlan_tdls_ct.h"
+#include "wlan_tdls_cmds_process.h"
+
+bool tdls_is_vdev_connected(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_peer *peer;
+	enum wlan_peer_state peer_state;
+
+	peer = wlan_vdev_get_bsspeer(vdev);
+
+	if (!peer) {
+		tdls_err("peer is null");
+		return false;
+	}
+
+	peer_state = wlan_peer_mlme_get_state(peer);
+
+	if (peer_state != WLAN_ASSOC_STATE) {
+		tdls_err("peer state: %d", peer_state);
+		return false;
+	}
+
+	return true;
+}
+
+bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_peer *peer;
+	bool is_authenticated = false;
+
+	peer = wlan_vdev_get_bsspeer(vdev);
+
+	if (!peer) {
+		tdls_err("peer is null");
+		return false;
+	}
+
+	is_authenticated = wlan_peer_mlme_get_auth_state(peer);
+
+	return is_authenticated;
+}
+
+/**
+ * tdls_peer_reset_discovery_processed() - reset discovery status
+ * @tdls_vdev: TDLS vdev object
+ *
+ * This function resets discovery processing bit for all TDLS peers
+ *
+ * Caller has to take the lock before calling this function
+ *
+ * Return: 0
+ */
+static int32_t tdls_peer_reset_discovery_processed(
+					struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	int i;
+	qdf_list_t *head;
+	qdf_list_node_t *p_node;
+	struct tdls_peer *peer;
+	QDF_STATUS status;
+
+	tdls_vdev->discovery_peer_cnt = 0;
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &tdls_vdev->peer_list[i];
+		status = qdf_list_peek_front(head, &p_node);
+		while (QDF_IS_STATUS_SUCCESS(status)) {
+			peer = qdf_container_of(p_node, struct tdls_peer, node);
+			peer->discovery_processed = 0;
+			status = qdf_list_peek_next(head, p_node, &p_node);
+		}
+	}
+
+	return 0;
+}
+
+void tdls_discovery_timeout_peer_cb(void *user_data)
+{
+	int i;
+	qdf_list_t *head;
+	qdf_list_node_t *p_node;
+	struct tdls_peer *peer;
+	QDF_STATUS status;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+
+	if (!user_data) {
+		tdls_err("discovery time out data is null");
+		return;
+	}
+
+	tdls_vdev = (struct tdls_vdev_priv_obj *) user_data;
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &tdls_vdev->peer_list[i];
+		status = qdf_list_peek_front(head, &p_node);
+		while (QDF_IS_STATUS_SUCCESS(status)) {
+			peer = qdf_container_of(p_node, struct tdls_peer,
+						node);
+			if (TDLS_LINK_DISCOVERING != peer->link_status) {
+				status = qdf_list_peek_next(head, p_node,
+							    &p_node);
+				continue;
+			}
+			tdls_debug(QDF_MAC_ADDR_STR " to idle state",
+				   QDF_MAC_ADDR_ARRAY(peer->peer_mac.bytes));
+			tdls_set_peer_link_status(peer,
+						  TDLS_LINK_IDLE,
+						  TDLS_LINK_NOT_SUPPORTED);
+		}
+	}
+	tdls_vdev->discovery_sent_cnt = 0;
+
+	/* add tdls power save prohibited */
+
+	return;
+}
+
+/**
+ * tdls_reset_tx_rx() - reset tx/rx counters for all tdls peers
+ * @tdls_vdev: TDLS vdev object
+ *
+ * Caller has to take the TDLS lock before calling this function
+ *
+ * Return: Void
+ */
+static void tdls_reset_tx_rx(struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	int i;
+	qdf_list_t *head;
+	qdf_list_node_t *p_node;
+	struct tdls_peer *peer;
+	QDF_STATUS status;
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &tdls_vdev->peer_list[i];
+		status = qdf_list_peek_front(head, &p_node);
+		while (QDF_IS_STATUS_SUCCESS(status)) {
+			peer = qdf_container_of(p_node, struct tdls_peer, node);
+			peer->tx_pkt = 0;
+			peer->rx_pkt = 0;
+			status = qdf_list_peek_next(head, p_node, &p_node);
+		}
+	}
+	return;
+}
+
+void tdls_implicit_disable(struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	tdls_debug("Disable Implicit TDLS");
+	tdls_timers_stop(tdls_vdev);
+}
+
+/**
+ * tdls_implicit_enable() - enable implicit tdls triggering
+ * @tdls_vdev: TDLS vdev
+ *
+ * Return: Void
+ */
+void tdls_implicit_enable(struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	tdls_debug("Enable Implicit TDLS");
+	if (!tdls_vdev)
+		return;
+
+	tdls_peer_reset_discovery_processed(tdls_vdev);
+	tdls_reset_tx_rx(tdls_vdev);
+	/* TODO check whether tdls power save prohibited */
+
+	/* Restart the connection tracker timer */
+	tdls_timer_restart(tdls_vdev->vdev, &tdls_vdev->peer_update_timer,
+			   tdls_vdev->threshold_config.tx_period_t);
+}
+
+/**
+ * tdls_ct_sampling_tx_rx() - collect tx/rx traffic sample
+ * @tdls_vdev_obj: tdls vdev object
+ * @tdls_soc_obj: tdls soc object
+ *
+ * Function to update data traffic information in tdls connection
+ * tracker data structure for connection tracker operation
+ *
+ * Return: None
+ */
+static void tdls_ct_sampling_tx_rx(struct tdls_vdev_priv_obj *tdls_vdev,
+				   struct tdls_soc_priv_obj *tdls_soc)
+{
+	struct tdls_peer *curr_peer;
+	uint8_t mac[QDF_MAC_ADDR_SIZE];
+	uint8_t mac_cnt;
+	uint8_t mac_entries;
+	struct tdls_conn_tracker_mac_table mac_table[WLAN_TDLS_CT_TABLE_SIZE];
+
+	qdf_spin_lock_bh(&tdls_soc->tdls_ct_spinlock);
+
+	if (0 == tdls_vdev->valid_mac_entries) {
+		qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock);
+		return;
+	}
+
+	mac_entries = QDF_MIN(tdls_vdev->valid_mac_entries,
+			      WLAN_TDLS_CT_TABLE_SIZE);
+
+	qdf_mem_copy(mac_table, tdls_vdev->ct_peer_table,
+	       (sizeof(struct tdls_conn_tracker_mac_table)) * mac_entries);
+
+	qdf_mem_set(tdls_vdev->ct_peer_table, 0,
+	       (sizeof(struct tdls_conn_tracker_mac_table)) * mac_entries);
+
+	tdls_vdev->valid_mac_entries = 0;
+
+	qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock);
+
+	for (mac_cnt = 0; mac_cnt < mac_entries; mac_cnt++) {
+		qdf_mem_copy(mac, mac_table[mac_cnt].mac_address.bytes,
+		       QDF_MAC_ADDR_SIZE);
+		curr_peer = tdls_get_peer(tdls_vdev, mac);
+		if (NULL != curr_peer) {
+			curr_peer->tx_pkt =
+			mac_table[mac_cnt].tx_packet_cnt;
+			curr_peer->rx_pkt =
+			mac_table[mac_cnt].rx_packet_cnt;
+		}
+	}
+}
+
+void tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
+				 struct qdf_mac_addr *mac_addr)
+{
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	uint8_t mac_cnt;
+	uint8_t valid_mac_entries;
+	struct tdls_conn_tracker_mac_table *mac_table;
+
+	if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
+						   &tdls_soc_obj))
+		return;
+
+	if (!tdls_soc_obj->enable_tdls_connection_tracker)
+		return;
+
+	if (qdf_is_macaddr_group(mac_addr))
+		return;
+
+	if (qdf_mem_cmp(vdev->vdev_mlme.macaddr, mac_addr,
+		QDF_MAC_ADDR_SIZE) == 0)
+		return;
+
+	qdf_spin_lock_bh(&tdls_soc_obj->tdls_ct_spinlock);
+	valid_mac_entries = tdls_vdev_obj->valid_mac_entries;
+	mac_table = tdls_vdev_obj->ct_peer_table;
+
+	for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
+		if (qdf_mem_cmp(mac_table[mac_cnt].mac_address.bytes,
+		    mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
+			mac_table[mac_cnt].rx_packet_cnt++;
+			goto rx_cnt_return;
+		}
+	}
+
+	/* If we have more than 8 peers within 30 mins. we will
+	 *  stop tracking till the old entries are removed
+	 */
+	if (mac_cnt < WLAN_TDLS_CT_TABLE_SIZE) {
+		qdf_mem_copy(mac_table[mac_cnt].mac_address.bytes,
+		       mac_addr, QDF_MAC_ADDR_SIZE);
+		tdls_vdev_obj->valid_mac_entries = mac_cnt+1;
+		mac_table[mac_cnt].rx_packet_cnt = 1;
+	}
+
+rx_cnt_return:
+	qdf_spin_unlock_bh(&tdls_soc_obj->tdls_ct_spinlock);
+	return;
+}
+
+void tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
+			    struct qdf_mac_addr *mac_addr)
+{
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	uint8_t mac_cnt;
+	uint8_t valid_mac_entries;
+	struct tdls_conn_tracker_mac_table *mac_table;
+
+	if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
+						   &tdls_soc_obj))
+		return;
+
+	if (!tdls_soc_obj->enable_tdls_connection_tracker)
+		return;
+
+	if (qdf_is_macaddr_group(mac_addr))
+		return;
+
+	if (qdf_mem_cmp(vdev->vdev_mlme.macaddr, mac_addr,
+		QDF_MAC_ADDR_SIZE) == 0)
+		return;
+
+	qdf_spin_lock_bh(&tdls_soc_obj->tdls_ct_spinlock);
+	mac_table = tdls_vdev_obj->ct_peer_table;
+
+	valid_mac_entries = tdls_vdev_obj->valid_mac_entries;
+
+	for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
+		if (qdf_mem_cmp(mac_table[mac_cnt].mac_address.bytes,
+		    mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
+			mac_table[mac_cnt].tx_packet_cnt++;
+			goto tx_cnt_return;
+		}
+	}
+
+	/* If we have more than 8 peers within 30 mins. we will
+	 *  stop tracking till the old entries are removed
+	 */
+	if (mac_cnt < WLAN_TDLS_CT_TABLE_SIZE) {
+		qdf_mem_copy(mac_table[mac_cnt].mac_address.bytes,
+			mac_addr, QDF_MAC_ADDR_SIZE);
+		mac_table[mac_cnt].tx_packet_cnt = 1;
+		tdls_vdev_obj->valid_mac_entries++;
+	}
+
+tx_cnt_return:
+	qdf_spin_unlock_bh(&tdls_soc_obj->tdls_ct_spinlock);
+	return;
+}
+
+void tdls_implicit_send_discovery_request(
+				struct tdls_vdev_priv_obj *tdls_vdev_obj)
+{
+	struct tdls_peer *curr_peer;
+	struct tdls_peer *temp_peer;
+	struct tdls_soc_priv_obj *tdls_psoc;
+	struct tdls_osif_indication tdls_ind;
+
+	if (NULL == tdls_vdev_obj) {
+		tdls_notice("tdls_vdev_obj is NULL");
+		return;
+	}
+
+	tdls_psoc = wlan_vdev_get_tdls_soc_obj(tdls_vdev_obj->vdev);
+
+	if (NULL == tdls_psoc) {
+		tdls_notice("tdls_psoc_obj is NULL");
+		return;
+	}
+
+	curr_peer = tdls_vdev_obj->curr_candidate;
+
+	if (NULL == curr_peer) {
+		tdls_err("curr_peer is NULL");
+		return;
+	}
+
+	/* This function is called in mutex_lock */
+	temp_peer = tdls_is_progress(tdls_vdev_obj, NULL, 0);
+	if (NULL != temp_peer) {
+		tdls_notice(QDF_MAC_ADDR_STR " ongoing. pre_setup ignored",
+			    QDF_MAC_ADDR_ARRAY(temp_peer->peer_mac.bytes));
+		goto done;
+	}
+
+	if (TDLS_CAP_UNKNOWN != curr_peer->tdls_support)
+		tdls_set_peer_link_status(curr_peer,
+					  TDLS_LINK_DISCOVERING,
+					  TDLS_LINK_SUCCESS);
+
+	qdf_mem_copy(tdls_ind.peer_mac, curr_peer->peer_mac.bytes,
+			QDF_MAC_ADDR_SIZE);
+
+	tdls_ind.vdev = tdls_vdev_obj->vdev;
+
+	tdls_debug("Implicit TDLS, Send Discovery request event");
+
+	tdls_psoc->tdls_event_cb(tdls_psoc->tdls_evt_cb_data,
+				 TDLS_EVENT_DISCOVERY_REQ, &tdls_ind);
+
+	tdls_vdev_obj->discovery_sent_cnt++;
+
+	tdls_timer_restart(tdls_vdev_obj->vdev,
+				&tdls_vdev_obj->peer_discovery_timer,
+				tdls_vdev_obj->threshold_config.tx_period_t -
+				TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE);
+
+	tdls_debug("discovery count %u timeout %u msec",
+		 tdls_vdev_obj->discovery_sent_cnt,
+		 tdls_vdev_obj->threshold_config.tx_period_t -
+		 TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE);
+done:
+	tdls_vdev_obj->curr_candidate = NULL;
+	tdls_vdev_obj->magic = 0;
+	return;
+}
+
+int tdls_recv_discovery_resp(struct tdls_vdev_priv_obj *tdls_vdev,
+				   const uint8_t *mac)
+{
+	struct tdls_peer *curr_peer;
+	struct tdls_soc_priv_obj *tdls_soc;
+	struct tdls_osif_indication indication;
+	struct tdls_config_params *tdls_cfg;
+	int status = 0;
+
+	if (!tdls_vdev)
+		return -EINVAL;
+
+	tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev);
+	if (NULL == tdls_soc) {
+		tdls_err("tdls soc is NULL");
+		return -EINVAL;
+	}
+
+	curr_peer = tdls_get_peer(tdls_vdev, mac);
+	if (NULL == curr_peer) {
+		tdls_err("curr_peer is NULL");
+		return -EINVAL;
+	}
+
+	if (tdls_vdev->discovery_sent_cnt)
+		tdls_vdev->discovery_sent_cnt--;
+
+	if (0 == tdls_vdev->discovery_sent_cnt)
+		qdf_mc_timer_stop(&tdls_vdev->peer_discovery_timer);
+
+	tdls_debug("Discovery(%u) Response from " QDF_MAC_ADDR_STR
+		   " link_status %d", tdls_vdev->discovery_sent_cnt,
+		   QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
+		   curr_peer->link_status);
+
+	tdls_cfg = &tdls_vdev->threshold_config;
+	if (TDLS_LINK_DISCOVERING == curr_peer->link_status) {
+		/* Since we are here, it means Throughput threshold is
+		 * already met. Make sure RSSI threshold is also met
+		 * before setting up TDLS link.
+		 */
+		if ((int32_t) curr_peer->rssi >
+		    (int32_t) tdls_cfg->rssi_trigger_threshold) {
+			tdls_set_peer_link_status(curr_peer,
+						TDLS_LINK_DISCOVERED,
+						TDLS_LINK_SUCCESS);
+			tdls_debug("Rssi Threshold met: " QDF_MAC_ADDR_STR
+				" rssi = %d threshold= %d",
+				QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
+				curr_peer->rssi,
+				tdls_cfg->rssi_trigger_threshold);
+
+			qdf_mem_copy(indication.peer_mac, mac,
+					QDF_MAC_ADDR_SIZE);
+
+			indication.vdev = tdls_vdev->vdev;
+
+			tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
+						TDLS_EVENT_SETUP_REQ,
+						&indication);
+		} else {
+			tdls_debug("Rssi Threshold not met: " QDF_MAC_ADDR_STR
+				" rssi = %d threshold = %d ",
+				QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
+				curr_peer->rssi,
+				tdls_cfg->rssi_trigger_threshold);
+
+			tdls_set_peer_link_status(curr_peer,
+						TDLS_LINK_IDLE,
+						TDLS_LINK_UNSPECIFIED);
+
+			/* if RSSI threshold is not met then allow
+			 * further discovery attempts by decrementing
+			 * count for the last attempt
+			 */
+			if (curr_peer->discovery_attempt)
+				curr_peer->discovery_attempt--;
+		}
+	}
+
+	curr_peer->tdls_support = TDLS_CAP_SUPPORTED;
+
+	return status;
+}
+
+void tdls_indicate_teardown(struct tdls_vdev_priv_obj *tdls_vdev,
+			    struct tdls_peer *curr_peer,
+			    uint16_t reason)
+{
+	struct tdls_soc_priv_obj *tdls_soc;
+	struct tdls_osif_indication indication;
+
+	if (!tdls_vdev || !curr_peer) {
+		tdls_err("tdls_vdev: %pK, curr_peer: %pK",
+			 tdls_vdev, curr_peer);
+		return;
+	}
+
+	tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev);
+	if (!tdls_soc) {
+		tdls_err("tdls_soc: %pK", tdls_soc);
+		return;
+	}
+
+	if (TDLS_LINK_CONNECTED != curr_peer->link_status)
+		return;
+
+	tdls_set_peer_link_status(curr_peer,
+				  TDLS_LINK_TEARING,
+				  TDLS_LINK_UNSPECIFIED);
+	tdls_notice("Teardown reason %d", reason);
+
+	if (tdls_soc->tdls_dp_vdev_update)
+		tdls_soc->tdls_dp_vdev_update(&tdls_soc->soc,
+				curr_peer->sta_id,
+				tdls_soc->tdls_update_dp_vdev_flags,
+				false);
+
+	indication.reason = reason;
+	indication.vdev = tdls_vdev->vdev;
+	qdf_mem_copy(indication.peer_mac, curr_peer->peer_mac.bytes,
+			QDF_MAC_ADDR_SIZE);
+
+	if (tdls_soc->tdls_event_cb)
+		tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
+				     TDLS_EVENT_TEARDOWN_REQ, &indication);
+}
+
+/**
+ * tdls_get_conn_info() - get the tdls connection information.
+ * @tdls_soc: tdls soc object
+ * @idx: sta id
+ *
+ * Function to check tdls sta index
+ *
+ * Return: tdls connection information
+ */
+static struct tdls_conn_info *
+tdls_get_conn_info(struct tdls_soc_priv_obj *tdls_soc, uint8_t idx)
+{
+	uint8_t sta_idx;
+
+	/* check if there is available index for this new TDLS STA */
+	for (sta_idx = 0; sta_idx < WLAN_TDLS_STA_MAX_NUM; sta_idx++) {
+		if (idx == tdls_soc->tdls_conn_info[sta_idx].sta_id) {
+			tdls_debug("tdls peer with sta_idx %u exists", idx);
+			return &tdls_soc->tdls_conn_info[sta_idx];
+		}
+	}
+
+	tdls_err("tdls peer with staIdx %u not exists", idx);
+	return NULL;
+}
+
+static void
+tdls_ct_process_idle_handler(
+			struct tdls_ct_idle_peer_data *tdls_idle_peer_data)
+{
+	struct tdls_conn_info *tdls_info;
+	struct tdls_peer *curr_peer;
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+
+	vdev = tdls_idle_peer_data->vdev;
+	tdls_info = tdls_idle_peer_data->tdls_info;
+
+	if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
+						   &tdls_soc_obj))
+		return;
+
+	if (INVALID_TDLS_PEER_ID == tdls_info->sta_id) {
+		tdls_err("peer (staidx %u) doesn't exists", tdls_info->sta_id);
+		return;
+	}
+
+	curr_peer = tdls_find_peer(tdls_vdev_obj,
+		(u8 *) &tdls_info->peer_mac.bytes[0]);
+
+	if (NULL == curr_peer) {
+		tdls_err("Invalid tdls idle timer expired");
+		return;
+	}
+
+	tdls_debug(QDF_MAC_ADDR_STR
+		" tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d",
+		QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
+		curr_peer->tx_pkt,
+		curr_peer->rx_pkt,
+		tdls_vdev_obj->threshold_config.idle_packet_n);
+
+	/* Check tx/rx statistics on this tdls link for recent activities and
+	 * then decide whether to tear down the link or keep it.
+	 */
+	if ((curr_peer->tx_pkt >=
+	     tdls_vdev_obj->threshold_config.idle_packet_n) ||
+	    (curr_peer->rx_pkt >=
+	     tdls_vdev_obj->threshold_config.idle_packet_n)) {
+		/* this tdls link got back to normal, so keep it */
+		tdls_debug("tdls link to " QDF_MAC_ADDR_STR
+			 " back to normal, will stay",
+			  QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes));
+	} else {
+		/* this tdls link needs to get torn down */
+		tdls_notice("trigger tdls link to "QDF_MAC_ADDR_STR" down",
+			    QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes));
+		tdls_indicate_teardown(tdls_vdev_obj,
+					curr_peer,
+					TDLS_TEARDOWN_PEER_UNSPEC_REASON);
+	}
+
+	return;
+}
+
+void tdls_ct_idle_handler(void *user_data)
+{
+	struct tdls_ct_idle_peer_data *tdls_idle_peer_data;
+	struct wlan_objmgr_vdev *vdev;
+
+	tdls_idle_peer_data = (struct tdls_ct_idle_peer_data *) user_data;
+
+	if (NULL == tdls_idle_peer_data ||
+	    NULL == tdls_idle_peer_data->vdev ||
+	    NULL == tdls_idle_peer_data->tdls_info)
+		return;
+
+	vdev = tdls_idle_peer_data->vdev;
+	if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(vdev,
+							WLAN_TDLS_NB_ID))
+		return;
+
+	tdls_ct_process_idle_handler(tdls_idle_peer_data);
+	wlan_objmgr_vdev_release_ref(vdev,
+				     WLAN_TDLS_NB_ID);
+}
+
+/**
+ * tdls_ct_process_idle_and_discovery() - process the traffic data
+ * @curr_peer: tdls peer needs to be examined
+ * @tdls_vdev_obj: tdls vdev object
+ * @tdls_soc_obj: tdls soc object
+ *
+ * Function to check the peer traffic data in idle link and  tdls
+ * discovering link
+ *
+ * Return: None
+ */
+static void
+tdls_ct_process_idle_and_discovery(struct tdls_peer *curr_peer,
+				struct tdls_vdev_priv_obj *tdls_vdev_obj,
+				struct tdls_soc_priv_obj *tdls_soc_obj)
+{
+	uint16_t valid_peers;
+
+	valid_peers = tdls_soc_obj->connected_peer_count;
+
+	if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
+	     tdls_vdev_obj->threshold_config.tx_packet_n) {
+		if (WLAN_TDLS_STA_MAX_NUM > valid_peers) {
+			tdls_notice("Tput trigger TDLS pre-setup");
+			tdls_vdev_obj->curr_candidate = curr_peer;
+			tdls_implicit_send_discovery_request(tdls_vdev_obj);
+		} else {
+			tdls_notice("Maximum peers connected already! %d",
+				 valid_peers);
+		}
+	}
+}
+
+/**
+ * tdls_ct_process_connected_link() - process the traffic
+ * @curr_peer: tdls peer needs to be examined
+ * @tdls_vdev_obj: tdls vdev
+ * @tdls_soc_obj: tdls soc context
+ *
+ * Function to check the peer traffic data in active STA
+ * session
+ *
+ * Return: None
+ */
+static void tdls_ct_process_connected_link(
+				struct tdls_peer *curr_peer,
+				struct tdls_vdev_priv_obj *tdls_vdev,
+				struct tdls_soc_priv_obj *tdls_soc)
+{
+
+	if ((int32_t)curr_peer->rssi <
+	    (int32_t)tdls_vdev->threshold_config.rssi_teardown_threshold) {
+		tdls_warn("Tear down - low RSSI: " QDF_MAC_ADDR_STR "!",
+			 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes));
+		tdls_indicate_teardown(tdls_vdev,
+					curr_peer,
+					TDLS_TEARDOWN_PEER_UNSPEC_REASON);
+		return;
+	}
+
+	/* Only teardown based on non zero idle packet threshold, to address
+	 * a use case where this threshold does not get consider for TEAR DOWN
+	 */
+	if ((0 != tdls_vdev->threshold_config.idle_packet_n) &&
+	    ((curr_peer->tx_pkt <
+	      tdls_vdev->threshold_config.idle_packet_n) &&
+	     (curr_peer->rx_pkt <
+	      tdls_vdev->threshold_config.idle_packet_n))) {
+		if (!curr_peer->is_peer_idle_timer_initialised) {
+			uint8_t sta_id = (uint8_t)curr_peer->sta_id;
+			struct tdls_conn_info *tdls_info;
+			tdls_info = tdls_get_conn_info(tdls_soc, sta_id);
+			tdls_soc->tdls_idle_peer_data.tdls_info = tdls_info;
+			tdls_soc->tdls_idle_peer_data.vdev = tdls_vdev->vdev;
+			qdf_mc_timer_init(&curr_peer->peer_idle_timer,
+					  QDF_TIMER_TYPE_SW,
+					  tdls_ct_idle_handler,
+					  &tdls_soc->tdls_idle_peer_data);
+			curr_peer->is_peer_idle_timer_initialised = true;
+		}
+		if (QDF_TIMER_STATE_RUNNING !=
+		    curr_peer->peer_idle_timer.state) {
+			tdls_warn("Tx/Rx Idle timer start: "
+				QDF_MAC_ADDR_STR "!",
+				QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes));
+			tdls_timer_restart(tdls_vdev->vdev,
+				&curr_peer->peer_idle_timer,
+				tdls_vdev->threshold_config.idle_timeout_t);
+		}
+	} else if (QDF_TIMER_STATE_RUNNING ==
+		   curr_peer->peer_idle_timer.state) {
+		tdls_warn("Tx/Rx Idle timer stop: " QDF_MAC_ADDR_STR "!",
+			 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes));
+		qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
+	}
+}
+
+/**
+ * tdls_ct_process_cap_supported() - process TDLS supported peer.
+ * @curr_peer: tdls peer needs to be examined
+ * @tdls_vdev_obj: tdls vdev context
+ * @tdls_soc_obj: tdls soc context
+ *
+ * Function to check the peer traffic data  for tdls supported peer
+ *
+ * Return: None
+ */
+static void tdls_ct_process_cap_supported(struct tdls_peer *curr_peer,
+					struct tdls_vdev_priv_obj *tdls_vdev,
+					struct tdls_soc_priv_obj *tdls_soc_obj)
+{
+	tdls_debug("tx %d rx %d thr.pkt %d/idle %d rssi %d thr.trig %d/tear %d",
+		 curr_peer->tx_pkt, curr_peer->rx_pkt,
+		 tdls_vdev->threshold_config.tx_packet_n,
+		 tdls_vdev->threshold_config.idle_packet_n,
+		 curr_peer->rssi,
+		 tdls_vdev->threshold_config.rssi_trigger_threshold,
+		 tdls_vdev->threshold_config.rssi_teardown_threshold);
+
+	switch (curr_peer->link_status) {
+	case TDLS_LINK_IDLE:
+	case TDLS_LINK_DISCOVERING:
+		if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(
+			tdls_soc_obj->tdls_configs.tdls_feature_flags) &&
+			(!curr_peer->is_forced_peer))
+			break;
+		tdls_ct_process_idle_and_discovery(curr_peer, tdls_vdev,
+						   tdls_soc_obj);
+		break;
+	case TDLS_LINK_CONNECTED:
+		tdls_ct_process_connected_link(curr_peer, tdls_vdev,
+					       tdls_soc_obj);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * tdls_ct_process_cap_unknown() - process unknown peer
+ * @curr_peer: tdls peer needs to be examined
+ * @tdls_vdev_obj: tdls vdev object
+ * @tdls_soc_obj: tdls soc object
+ *
+ * Function check the peer traffic data , when tdls capability is unknown
+ *
+ * Return: None
+ */
+static void tdls_ct_process_cap_unknown(struct tdls_peer *curr_peer,
+					struct tdls_vdev_priv_obj *tdls_vdev,
+					struct tdls_soc_priv_obj *tdlsa_soc)
+{
+	if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(
+			tdlsa_soc->tdls_configs.tdls_feature_flags) &&
+			(!curr_peer->is_forced_peer))
+			return;
+
+	tdls_debug("threshold tx pkt = %d peer tx_pkt = %d & rx_pkt = %d ",
+		tdls_vdev->threshold_config.tx_packet_n, curr_peer->tx_pkt,
+		curr_peer->rx_pkt);
+
+	if (!TDLS_IS_LINK_CONNECTED(curr_peer) &&
+	    ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
+	    tdls_vdev->threshold_config.tx_packet_n)) {
+		/* Ignore discovery attempt if External Control is enabled, that
+		 * is, peer is forced. In that case, continue discovery attempt
+		 * regardless attempt count
+		 */
+		tdls_debug("TDLS UNKNOWN pre discover ");
+		if (curr_peer->is_forced_peer ||
+			curr_peer->discovery_attempt++ <
+		    tdls_vdev->threshold_config.discovery_tries_n) {
+			tdls_debug("TDLS UNKNOWN discover ");
+			tdls_vdev->curr_candidate = curr_peer;
+			tdls_implicit_send_discovery_request(tdls_vdev);
+		} else {
+			curr_peer->tdls_support = TDLS_CAP_NOT_SUPPORTED;
+			tdls_set_peer_link_status(
+				    curr_peer,
+				    TDLS_LINK_IDLE,
+				    TDLS_LINK_NOT_SUPPORTED);
+		}
+	}
+}
+
+/**
+ * tdls_ct_process_peers() - process the peer
+ * @curr_peer: tdls peer needs to be examined
+ * @tdls_vdev_obj: tdls vdev object
+ * @tdls_soc_obj: tdls soc object
+ *
+ * This function check the peer capability and process the metadata from
+ * the peer
+ *
+ * Return: None
+ */
+static void tdls_ct_process_peers(struct tdls_peer *curr_peer,
+				  struct tdls_vdev_priv_obj *tdls_vdev_obj,
+				  struct tdls_soc_priv_obj *tdls_soc_obj)
+{
+	tdls_debug(QDF_MAC_ADDR_STR " link_status %d tdls_support %d",
+		 QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
+		 curr_peer->link_status, curr_peer->tdls_support);
+
+	switch (curr_peer->tdls_support) {
+	case TDLS_CAP_SUPPORTED:
+		tdls_ct_process_cap_supported(curr_peer, tdls_vdev_obj,
+						       tdls_soc_obj);
+		break;
+
+	case TDLS_CAP_UNKNOWN:
+		tdls_ct_process_cap_unknown(curr_peer, tdls_vdev_obj,
+						     tdls_soc_obj);
+		break;
+	default:
+		break;
+	}
+
+}
+
+static void tdls_ct_process_handler(struct wlan_objmgr_vdev *vdev)
+{
+	int i;
+	qdf_list_t *head;
+	qdf_list_node_t *list_node;
+	struct tdls_peer *curr_peer;
+	QDF_STATUS status;
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+
+	if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
+						   &tdls_soc_obj))
+		return;
+
+	/* If any concurrency is detected */
+	if (!tdls_soc_obj->enable_tdls_connection_tracker) {
+		tdls_notice("Connection tracker is disabled");
+		return;
+	}
+
+	/* Update tx rx traffic sample in tdls data structures */
+	tdls_ct_sampling_tx_rx(tdls_vdev_obj, tdls_soc_obj);
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &tdls_vdev_obj->peer_list[i];
+		status = qdf_list_peek_front(head, &list_node);
+		while (QDF_IS_STATUS_SUCCESS(status)) {
+			curr_peer = qdf_container_of(list_node,
+						struct tdls_peer, node);
+			tdls_ct_process_peers(curr_peer, tdls_vdev_obj,
+					      tdls_soc_obj);
+			curr_peer->tx_pkt = 0;
+			curr_peer->rx_pkt = 0;
+			status = qdf_list_peek_next(head,
+						    list_node, &list_node);
+		}
+	}
+
+	tdls_timer_restart(tdls_vdev_obj->vdev,
+			   &tdls_vdev_obj->peer_update_timer,
+			   tdls_vdev_obj->threshold_config.tx_period_t);
+
+}
+
+void tdls_ct_handler(void *user_data)
+{
+	struct wlan_objmgr_vdev *vdev;
+
+	if (!user_data)
+		return;
+
+	vdev = (struct wlan_objmgr_vdev *)user_data;
+
+	if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(vdev,
+							WLAN_TDLS_NB_ID))
+		return;
+
+	tdls_ct_process_handler(vdev);
+
+	wlan_objmgr_vdev_release_ref(vdev,
+				     WLAN_TDLS_NB_ID);
+}
+
+int tdls_set_tdls_offchannel(struct tdls_soc_priv_obj *tdls_soc,
+			     int offchannel)
+{
+	uint32_t tdls_feature_flags;
+
+	tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags;
+
+	if (TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) &&
+	   (TDLS_SUPPORT_EXP_TRIG_ONLY == tdls_soc->tdls_current_mode ||
+	    TDLS_SUPPORT_IMP_MODE == tdls_soc->tdls_current_mode ||
+	    TDLS_SUPPORT_EXT_CONTROL == tdls_soc->tdls_current_mode)) {
+		if (offchannel < TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN ||
+			offchannel > TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX) {
+			tdls_err("Invalid tdls off channel %u", offchannel);
+			return -EINVAL;
+			}
+	} else {
+		tdls_err("Either TDLS or TDLS Off-channel is not enabled");
+		return -ENOTSUPP;
+	}
+	tdls_notice("change tdls off channel from %d to %d",
+		   tdls_soc->tdls_off_channel, offchannel);
+	tdls_soc->tdls_off_channel = offchannel;
+	return 0;
+}
+
+int tdls_set_tdls_secoffchanneloffset(struct tdls_soc_priv_obj *tdls_soc,
+				int offchanoffset)
+{
+	uint32_t tdls_feature_flags;
+
+	tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags;
+
+	if (!TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) ||
+	    TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) {
+		tdls_err("Either TDLS or TDLS Off-channel is not enabled");
+		return  -ENOTSUPP;
+	}
+
+	tdls_soc->tdls_channel_offset = BW_INVALID;
+
+	switch (offchanoffset) {
+	case TDLS_SEC_OFFCHAN_OFFSET_0:
+		tdls_soc->tdls_channel_offset = BW20;
+		break;
+	case TDLS_SEC_OFFCHAN_OFFSET_40PLUS:
+		tdls_soc->tdls_channel_offset = BW40_LOW_PRIMARY;
+		break;
+	case TDLS_SEC_OFFCHAN_OFFSET_40MINUS:
+		tdls_soc->tdls_channel_offset = BW40_LOW_PRIMARY;
+		break;
+	case TDLS_SEC_OFFCHAN_OFFSET_80:
+		tdls_soc->tdls_channel_offset = BW80;
+		break;
+	case TDLS_SEC_OFFCHAN_OFFSET_160:
+		tdls_soc->tdls_channel_offset = BWALL;
+		break;
+	default:
+		tdls_err("Invalid tdls secondary off channel offset %d",
+			offchanoffset);
+		return -EINVAL;
+	} /* end switch */
+
+	tdls_notice("change tdls secondary off channel offset to 0x%x",
+		    tdls_soc->tdls_channel_offset);
+	return 0;
+}
+
+int tdls_set_tdls_offchannelmode(struct wlan_objmgr_vdev *vdev,
+				 int offchanmode)
+{
+	struct tdls_peer *conn_peer = NULL;
+	struct tdls_channel_switch_params chan_switch_params;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+	int ret_value = 0;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc;
+	uint32_t tdls_feature_flags;
+
+
+	status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc);
+
+	if (status != QDF_STATUS_SUCCESS)
+		return -EINVAL;
+
+
+	if (offchanmode < ENABLE_CHANSWITCH ||
+			offchanmode > DISABLE_CHANSWITCH) {
+		tdls_err("Invalid tdls off channel mode %d", offchanmode);
+		return -EINVAL;
+	}
+
+	if (!tdls_is_vdev_connected(vdev)) {
+		tdls_err("tdls off channel req in not associated state %d",
+			offchanmode);
+		return -EPERM;
+	}
+
+	tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags;
+	if (!TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) ||
+	    TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) {
+		tdls_err("Either TDLS or TDLS Off-channel is not enabled");
+		return  -ENOTSUPP;
+	}
+
+	conn_peer = tdls_find_first_connected_peer(tdls_vdev);
+	if (NULL == conn_peer) {
+		tdls_err("No TDLS Connected Peer");
+		return -EPERM;
+	}
+
+	tdls_notice("TDLS Channel Switch in swmode=%d tdls_off_channel %d offchanoffset %d",
+		   offchanmode, tdls_soc->tdls_off_channel,
+		   tdls_soc->tdls_channel_offset);
+
+	switch (offchanmode) {
+	case ENABLE_CHANSWITCH:
+		if (tdls_soc->tdls_off_channel &&
+			tdls_soc->tdls_channel_offset != BW_INVALID) {
+			chan_switch_params.tdls_off_ch =
+				tdls_soc->tdls_off_channel;
+			chan_switch_params.tdls_off_ch_bw_offset =
+				tdls_soc->tdls_channel_offset;
+			chan_switch_params.oper_class =
+			   tdls_find_opclass(tdls_soc->soc,
+				chan_switch_params.tdls_off_ch,
+				chan_switch_params.tdls_off_ch_bw_offset);
+		} else {
+			tdls_err("TDLS off-channel parameters are not set yet!!!");
+			return -EINVAL;
+
+		}
+		break;
+	case DISABLE_CHANSWITCH:
+		chan_switch_params.tdls_off_ch = 0;
+		chan_switch_params.tdls_off_ch_bw_offset = 0;
+		chan_switch_params.oper_class = 0;
+		break;
+	default:
+		tdls_err("Incorrect Parameters mode: %d tdls_off_channel: %d offchanoffset: %d",
+			offchanmode, tdls_soc->tdls_off_channel,
+			tdls_soc->tdls_channel_offset);
+		return -EINVAL;
+	} /* end switch */
+
+	chan_switch_params.vdev_id = tdls_vdev->session_id;
+	chan_switch_params.tdls_sw_mode = offchanmode;
+	chan_switch_params.is_responder =
+		conn_peer->is_responder;
+	qdf_mem_copy(&chan_switch_params.peer_mac_addr,
+		     &conn_peer->peer_mac.bytes,
+		     QDF_MAC_ADDR_SIZE);
+	tdls_notice("Peer " QDF_MAC_ADDR_STR " vdevId: %d, off channel: %d, offset: %d, mode: %d, is_responder: %d",
+		 QDF_MAC_ADDR_ARRAY(chan_switch_params.peer_mac_addr),
+		 chan_switch_params.vdev_id,
+		 chan_switch_params.tdls_off_ch,
+		 chan_switch_params.tdls_off_ch_bw_offset,
+		 chan_switch_params.tdls_sw_mode,
+		 chan_switch_params.is_responder);
+
+	status = tdls_set_offchan_mode(tdls_soc->soc,
+				       &chan_switch_params);
+
+	if (status != QDF_STATUS_SUCCESS) {
+		tdls_err("Failed to send channel switch request to wmi");
+		return -EINVAL;
+	}
+
+	tdls_soc->tdls_fw_off_chan_mode = offchanmode;
+
+	if (ENABLE_CHANSWITCH == offchanmode) {
+		conn_peer = tdls_find_first_connected_peer(tdls_vdev);
+		if (NULL == conn_peer) {
+			tdls_err("No TDLS Connected Peer");
+			return -EPERM;
+		}
+		conn_peer->pref_off_chan_num =
+			chan_switch_params.tdls_off_ch;
+		conn_peer->op_class_for_pref_off_chan =
+			chan_switch_params.oper_class;
+	}
+
+	return ret_value;
+}
+
+static QDF_STATUS tdls_delete_all_tdls_peers_flush_cb(struct scheduler_msg *msg)
+{
+	if (msg && msg->bodyptr) {
+		qdf_mem_free(msg->bodyptr);
+		msg->bodyptr = NULL;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+/**
+ * tdls_delete_all_tdls_peers(): send request to delete tdls peers
+ * @vdev: vdev object
+ * @tdls_soc: tdls soc object
+ *
+ * This function sends request to lim to delete tdls peers
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_delete_all_tdls_peers(struct wlan_objmgr_vdev *vdev,
+					  struct tdls_soc_priv_obj *tdls_soc)
+{
+	struct wlan_objmgr_peer *peer;
+	struct tdls_del_all_tdls_peers *del_msg;
+	struct scheduler_msg msg = {0};
+	QDF_STATUS status;
+
+
+	del_msg = qdf_mem_malloc(sizeof(*del_msg));
+	if (NULL == del_msg) {
+		tdls_err("memory alloc failed");
+		return QDF_STATUS_E_FAILURE;
+	}
+	qdf_mem_zero(del_msg, sizeof(*del_msg));
+
+	peer = wlan_vdev_get_bsspeer(vdev);
+	if (QDF_STATUS_SUCCESS != wlan_objmgr_peer_try_get_ref(peer,
+							WLAN_TDLS_SB_ID)) {
+		qdf_mem_free(del_msg);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	qdf_mem_copy(del_msg->bssid.bytes,
+		     wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
+
+	del_msg->msg_type = tdls_soc->tdls_del_all_peers;
+	del_msg->msg_len = (uint16_t) sizeof(*del_msg);
+
+	/* Send the request to PE. */
+	qdf_mem_zero(&msg, sizeof(msg));
+
+	tdls_debug("sending delete all peers req to PE ");
+
+	msg.type = del_msg->msg_type;
+	msg.bodyptr = del_msg;
+	msg.flush_callback = tdls_delete_all_tdls_peers_flush_cb;
+
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_PE,
+					QDF_MODULE_ID_PE, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("post delete all peer req failed, status %d", status);
+		qdf_mem_free(del_msg);
+	}
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID);
+	return status;
+}
+
+void tdls_disable_offchan_and_teardown_links(
+				struct wlan_objmgr_vdev *vdev)
+{
+	uint16_t connected_tdls_peers = 0;
+	uint8_t staidx;
+	struct tdls_peer *curr_peer = NULL;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc;
+	QDF_STATUS status;
+	uint8_t vdev_id;
+	bool tdls_in_progress = false;
+
+	status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc);
+	if (QDF_STATUS_SUCCESS != status) {
+		tdls_err("tdls objects are NULL ");
+		return;
+	}
+
+	if (TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) {
+		tdls_notice("TDLS mode %d is disabled OR not suspended now",
+			   tdls_soc->tdls_current_mode);
+		return;
+	}
+
+	connected_tdls_peers = tdls_soc->connected_peer_count;
+	if (tdls_is_progress(tdls_vdev, NULL, 0))
+		tdls_in_progress = true;
+
+	if (!(connected_tdls_peers || tdls_in_progress)) {
+		tdls_notice("No TDLS connected/progress peers to delete");
+		vdev_id = vdev->vdev_objmgr.vdev_id;
+		if (tdls_soc->set_state_info.set_state_cnt > 0) {
+			tdls_debug("Disable the tdls in FW as second interface is coming up");
+			tdls_send_update_to_fw(tdls_vdev, tdls_soc, true,
+					       true, false, vdev_id);
+		}
+		return;
+	}
+
+	/* TDLS is not supported in case of concurrency.
+	 * Disable TDLS Offchannel in FW to avoid more
+	 * than two concurrent channels and generate TDLS
+	 * teardown indication to supplicant.
+	 * Below function Finds the first connected peer and
+	 * disables TDLS offchannel for that peer.
+	 * FW enables TDLS offchannel only when there is
+	 * one TDLS peer. When there are more than one TDLS peer,
+	 * there will not be TDLS offchannel in FW.
+	 * So to avoid sending multiple request to FW, for now,
+	 * just invoke offchannel mode functions only once
+	 */
+	tdls_set_tdls_offchannel(tdls_soc,
+				tdls_soc->tdls_configs.tdls_pre_off_chan_num);
+	tdls_set_tdls_secoffchanneloffset(tdls_soc,
+			TDLS_SEC_OFFCHAN_OFFSET_40PLUS);
+	tdls_set_tdls_offchannelmode(vdev, DISABLE_CHANSWITCH);
+
+	/* Send Msg to PE for deleting all the TDLS peers */
+	tdls_delete_all_tdls_peers(vdev, tdls_soc);
+
+	for (staidx = 0; staidx < tdls_soc->max_num_tdls_sta;
+							staidx++) {
+		if (tdls_soc->tdls_conn_info[staidx].sta_id
+						== INVALID_TDLS_PEER_ID)
+			continue;
+
+		curr_peer = tdls_find_all_peer(tdls_soc,
+			tdls_soc->tdls_conn_info[staidx].peer_mac.bytes);
+		if (!curr_peer)
+			continue;
+
+		tdls_notice("indicate TDLS teardown (staId %d)",
+			   curr_peer->sta_id);
+
+		/* Indicate teardown to supplicant */
+		tdls_indicate_teardown(tdls_vdev,
+				       curr_peer,
+				       TDLS_TEARDOWN_PEER_UNSPEC_REASON);
+
+		/*
+		 * Del Sta happened already as part of tdls_delete_all_tdls_peers
+		 * Hence clear tdls vdev data structure.
+		 */
+		tdls_reset_peer(tdls_vdev, curr_peer->peer_mac.bytes);
+
+		if (tdls_soc->tdls_dereg_peer)
+			tdls_soc->tdls_dereg_peer(
+					tdls_soc->tdls_peer_context,
+					wlan_vdev_get_id(vdev),
+					curr_peer->sta_id);
+		tdls_decrement_peer_count(tdls_soc);
+		tdls_soc->tdls_conn_info[staidx].sta_id = INVALID_TDLS_PEER_ID;
+		tdls_soc->tdls_conn_info[staidx].session_id = 255;
+
+		qdf_mem_zero(&tdls_soc->tdls_conn_info[staidx].peer_mac,
+			     sizeof(struct qdf_mac_addr));
+	}
+}
+
+void tdls_teardown_connections(struct wlan_objmgr_vdev *vdev)
+{
+	struct tdls_osif_indication indication;
+	struct tdls_soc_priv_obj *tdls_soc;
+	struct wlan_objmgr_vdev *tdls_vdev_obj;
+
+	if (!vdev) {
+		QDF_ASSERT(0);
+		return;
+	}
+
+	tdls_soc = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (!tdls_soc)
+		return;
+
+	/* Get the tdls specific vdev and clear the links */
+	tdls_vdev_obj = tdls_get_vdev(tdls_soc->soc, WLAN_TDLS_SB_ID);
+	if (tdls_vdev_obj) {
+		tdls_disable_offchan_and_teardown_links(tdls_vdev_obj);
+		wlan_objmgr_vdev_release_ref(tdls_vdev_obj, WLAN_TDLS_SB_ID);
+	}
+
+	indication.vdev = vdev;
+
+	if (tdls_soc->tdls_event_cb)
+		tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data,
+				     TDLS_EVENT_TEARDOWN_LINKS_DONE,
+				     &indication);
+}

+ 247 - 0
components/tdls/core/src/wlan_tdls_ct.h

@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_ct.h
+ *
+ * TDLS connection tracker declarations
+ */
+
+#ifndef _WLAN_TDLS_CT_H_
+#define _WLAN_TDLS_CT_H_
+
+ /*
+  * Before UpdateTimer expires, we want to timeout discovery response
+  * should not be more than 2000.
+  */
+#define TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE     1000
+
+#define TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN      1
+#define TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX      165
+#define TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT  36
+
+/**
+ * tdls_is_vdev_connected() - check the vdev is connected to ap
+ * @vdev: vdev object manager
+ *
+ * This function will check the vdev connection status and return
+ * true or false
+ *
+ * Return: true - Connected, false - Not connected
+ */
+bool tdls_is_vdev_connected(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * tdls_implicit_enable() - enable implicit tdls triggering
+ * @tdls_vdev: TDLS vdev
+ *
+ * Return: Void
+ */
+void tdls_implicit_enable(struct tdls_vdev_priv_obj *tdls_vdev);
+
+/**
+ * tdls_update_rx_pkt_cnt() - Update rx packet count
+ * @vdev: vdev object manager
+ * @mac_addr: mac address of the data
+ *
+ * Increase the rx packet count, if the sender is not bssid and the packet is
+ * not broadcast and multicast packet
+ *
+ * This sampling information will be used in TDLS connection tracker
+ *
+ * This function expected to be called in an atomic context so blocking APIs
+ * not allowed
+ *
+ * Return: None
+ */
+void tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
+				     struct qdf_mac_addr *mac_addr);
+
+/**
+ * tdls_update_tx_pkt_cnt() - update tx packet
+ * @vdev: vdev object
+ * @mac_addr: mac address of the data
+ *
+ * Increase the tx packet count, if the sender is not bssid and the packet is
+ * not broadcast and multicast packet
+ *
+ * This sampling information will be used in TDLS connection tracker
+ *
+ * This function expected to be called in an atomic context so blocking APIs
+ * not allowed
+ *
+ * Return: None
+ */
+void tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
+				     struct qdf_mac_addr *mac_addr);
+
+/**
+ * wlan_hdd_tdls_implicit_send_discovery_request() - send discovery request
+ * @tdls_vdev_obj: tdls vdev object
+ *
+ * Return: None
+ */
+void tdls_implicit_send_discovery_request(
+				struct tdls_vdev_priv_obj *tdls_vdev_obj);
+
+/**
+ * tdls_recv_discovery_resp() - handling of tdls discovery response
+ * @soc: object manager
+ * @mac: mac address of peer from which the response was received
+ *
+ * Return: 0 for success or negative errno otherwise
+ */
+int tdls_recv_discovery_resp(struct tdls_vdev_priv_obj *tdls_vdev,
+				   const uint8_t *mac);
+
+/**
+ * tdls_indicate_teardown() - indicate teardown to upper layer
+ * @tdls_vdev: tdls vdev object
+ * @curr_peer: teardown peer
+ * @reason: teardown reason
+ *
+ * Return: Void
+ */
+void tdls_indicate_teardown(struct tdls_vdev_priv_obj *tdls_vdev,
+				struct tdls_peer *curr_peer,
+				uint16_t reason);
+
+/**
+ * tdls_ct_handler() - TDLS connection tracker handler
+ * @user_data: user data from timer
+ *
+ * tdls connection tracker timer starts, when the STA connected to AP
+ * and it's scan the traffic between two STA peers and make TDLS
+ * connection and teardown, based on the traffic threshold
+ *
+ * Return: None
+ */
+void tdls_ct_handler(void *user_data);
+
+/**
+ * tdls_ct_idle_handler() - Check tdls idle traffic
+ * @user_data: data from tdls idle timer
+ *
+ * Function to check the tdls idle traffic and make a decision about
+ * tdls teardown
+ *
+ * Return: None
+ */
+void tdls_ct_idle_handler(void *user_data);
+
+/**
+ * tdls_discovery_timeout_peer_cb() - tdls discovery timeout callback
+ * @userData: tdls vdev
+ *
+ * Return: None
+ */
+void tdls_discovery_timeout_peer_cb(void *user_data);
+
+/**
+ * tdls_implicit_disable() - disable implicit tdls triggering
+ * @pHddTdlsCtx: TDLS context
+ *
+ * Return: Void
+ */
+void tdls_implicit_disable(struct tdls_vdev_priv_obj *tdls_vdev);
+
+/**
+ * tdls_is_vdev_connected() -check the vdev connection
+ * @vdev: vdev oobject
+ *
+ * Return: true or false
+ */
+bool tdls_is_vdev_connected(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * tdls_is_vdev_authenticated() -check the vdev authentication state
+ * @vdev: vdev oobject
+ *
+ * Return: true or false
+ */
+bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * tdls_teardown_connections() -teardown and delete all the tdls peers
+ * @vdev: vdev oobject
+ *
+ * Return: true or false
+ */
+void tdls_teardown_connections(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * tdls_disable_offchan_and_teardown_links - Disable offchannel
+ * and teardown TDLS links
+ * @tdls_soc : tdls soc object
+ *
+ * Return: None
+ */
+void tdls_disable_offchan_and_teardown_links(
+				struct wlan_objmgr_vdev *vdev);
+
+/**
+ * tdls_delete_all_tdls_peers(): send request to delete tdls peers
+ * @vdev: vdev object
+ * @tdls_soc: tdls soc object
+ *
+ * This function sends request to lim to delete tdls peers
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_delete_all_tdls_peers(struct wlan_objmgr_vdev *vdev,
+					  struct tdls_soc_priv_obj *tdls_soc);
+
+/**
+ * tdls_set_tdls_offchannel() - set tdls off-channel number
+ * @tdls_soc: tdls soc object
+ * @offchannel: tdls off-channel number
+ *
+ * This function sets tdls off-channel number
+ *
+ * Return: 0 on success; negative errno otherwise
+ */
+int tdls_set_tdls_offchannel(struct tdls_soc_priv_obj *tdls_soc,
+			     int offchannel);
+
+/**
+ * tdls_set_tdls_offchannelmode() - set tdls off-channel mode
+ * @adapter: Pointer to the HDD adapter
+ * @offchanmode: tdls off-channel mode
+ *
+ * This function sets tdls off-channel mode
+ *
+ * Return: 0 on success; negative errno otherwise
+ */
+
+int tdls_set_tdls_offchannelmode(struct wlan_objmgr_vdev *vdev,
+				 int offchanmode);
+
+/**
+ * tdls_set_tdls_secoffchanneloffset() - set secondary tdls off-channel offset
+ * @tdls_soc: tdls soc object
+ * @offchanoffset: tdls off-channel offset
+ *
+ * This function sets secondary tdls off-channel offset
+ *
+ * Return: 0 on success; negative errno otherwise
+ */
+
+int tdls_set_tdls_secoffchanneloffset(struct tdls_soc_priv_obj *tdls_soc,
+				      int offchanoffset);
+
+#endif

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

@@ -0,0 +1,1667 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_main.c
+ *
+ * TDLS core function definitions
+ */
+
+#include "wlan_tdls_main.h"
+#include "wlan_tdls_cmds_process.h"
+#include "wlan_tdls_peer.h"
+#include "wlan_tdls_ct.h"
+#include "wlan_tdls_mgmt.h"
+#include "wlan_tdls_tgt_api.h"
+#include "wlan_policy_mgr_public_struct.h"
+#include "wlan_policy_mgr_api.h"
+#include "wlan_scan_ucfg_api.h"
+
+
+/* Global tdls soc pvt object
+ * this is useful for some functions which does not receive either vdev or psoc
+ * objects.
+ */
+static struct tdls_soc_priv_obj *tdls_soc_global;
+
+QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc,
+					     void *arg_list)
+{
+	QDF_STATUS status;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+
+	tdls_soc_obj = qdf_mem_malloc(sizeof(*tdls_soc_obj));
+	if (!tdls_soc_obj) {
+		tdls_err("Failed to allocate memory for tdls object");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	tdls_soc_obj->soc = psoc;
+
+	status = wlan_objmgr_psoc_component_obj_attach(psoc,
+						       WLAN_UMAC_COMP_TDLS,
+						       (void *)tdls_soc_obj,
+						       QDF_STATUS_SUCCESS);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("Failed to attach psoc tdls component");
+		qdf_mem_free(tdls_soc_obj);
+		return status;
+	}
+
+	tdls_soc_global = tdls_soc_obj;
+	tdls_notice("TDLS obj attach to psoc successfully");
+
+	return status;
+}
+
+QDF_STATUS tdls_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc,
+					      void *arg_list)
+{
+	QDF_STATUS status;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+
+	tdls_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+						WLAN_UMAC_COMP_TDLS);
+	if (!tdls_soc_obj) {
+		tdls_err("Failed to get tdls obj in psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = wlan_objmgr_psoc_component_obj_detach(psoc,
+						       WLAN_UMAC_COMP_TDLS,
+						       tdls_soc_obj);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		tdls_err("Failed to detach psoc tdls component");
+	qdf_mem_free(tdls_soc_obj);
+
+	return status;
+}
+
+static QDF_STATUS tdls_vdev_init(struct tdls_vdev_priv_obj *vdev_obj)
+{
+	uint8_t i;
+	struct tdls_config_params *config;
+	struct tdls_user_config *user_config;
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
+	if (!soc_obj) {
+		tdls_err("tdls soc obj NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	config = &vdev_obj->threshold_config;
+	user_config = &soc_obj->tdls_configs;
+	config->tx_period_t = user_config->tdls_tx_states_period;
+	config->tx_packet_n = user_config->tdls_tx_pkt_threshold;
+	config->discovery_tries_n = user_config->tdls_max_discovery_attempt;
+	config->idle_timeout_t = user_config->tdls_idle_timeout;
+	config->idle_packet_n = user_config->tdls_idle_pkt_threshold;
+	config->rssi_trigger_threshold =
+		user_config->tdls_rssi_trigger_threshold;
+	config->rssi_teardown_threshold =
+		user_config->tdls_rssi_teardown_threshold;
+	config->rssi_delta = user_config->tdls_rssi_delta;
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		qdf_list_create(&vdev_obj->peer_list[i],
+				WLAN_TDLS_PEER_SUB_LIST_SIZE);
+	}
+	qdf_mc_timer_init(&vdev_obj->peer_update_timer, QDF_TIMER_TYPE_SW,
+			  tdls_ct_handler, vdev_obj->vdev);
+	qdf_mc_timer_init(&vdev_obj->peer_discovery_timer, QDF_TIMER_TYPE_SW,
+			  tdls_discovery_timeout_peer_cb, vdev_obj);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static void tdls_vdev_deinit(struct tdls_vdev_priv_obj *vdev_obj)
+{
+	qdf_mc_timer_stop(&vdev_obj->peer_update_timer);
+	qdf_mc_timer_stop(&vdev_obj->peer_discovery_timer);
+
+	qdf_mc_timer_destroy(&vdev_obj->peer_update_timer);
+	qdf_mc_timer_destroy(&vdev_obj->peer_discovery_timer);
+
+	tdls_peer_idle_timers_destroy(vdev_obj);
+	tdls_free_peer_list(vdev_obj);
+}
+
+QDF_STATUS tdls_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev,
+					     void *arg)
+{
+	QDF_STATUS status;
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct wlan_objmgr_pdev *pdev;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	uint32_t tdls_feature_flags;
+
+	tdls_debug("tdls vdev mode %d", wlan_vdev_mlme_get_opmode(vdev));
+	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE &&
+	    wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE)
+		return QDF_STATUS_SUCCESS;
+
+	tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (!tdls_soc_obj) {
+		tdls_err("get soc by vdev failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags;
+	if (!TDLS_IS_ENABLED(tdls_feature_flags)) {
+		tdls_debug("disabled in ini");
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+
+	/* TODO: Add concurrency check */
+
+	tdls_vdev_obj = qdf_mem_malloc(sizeof(*tdls_vdev_obj));
+	if (!tdls_vdev_obj) {
+		tdls_err("Failed to allocate memory for tdls vdev object");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	status = wlan_objmgr_vdev_component_obj_attach(vdev,
+						       WLAN_UMAC_COMP_TDLS,
+						       (void *)tdls_vdev_obj,
+						       QDF_STATUS_SUCCESS);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("Failed to attach vdev tdls component");
+		goto err;
+	}
+	tdls_vdev_obj->vdev = vdev;
+	status = tdls_vdev_init(tdls_vdev_obj);
+	if (QDF_IS_STATUS_ERROR(status))
+		goto err;
+
+	pdev = wlan_vdev_get_pdev(vdev);
+
+	status = ucfg_scan_register_event_handler(pdev,
+				tdls_scan_complete_event_handler,
+				tdls_soc_obj);
+
+	if (QDF_STATUS_SUCCESS != status) {
+		tdls_err("scan event register failed ");
+		tdls_vdev_deinit(tdls_vdev_obj);
+		goto err;
+	}
+
+	tdls_debug("tdls object attach to vdev successfully");
+	return status;
+err:
+	qdf_mem_free(tdls_vdev_obj);
+	return status;
+}
+
+QDF_STATUS tdls_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev,
+					      void *arg)
+{
+	QDF_STATUS status;
+	void *tdls_vdev_obj;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	uint32_t tdls_feature_flags;
+
+	tdls_debug("tdls vdev mode %d", wlan_vdev_mlme_get_opmode(vdev));
+	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE &&
+	    wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE)
+		return QDF_STATUS_SUCCESS;
+
+	tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (!tdls_soc_obj) {
+		tdls_err("get soc by vdev failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags;
+	if (!TDLS_IS_ENABLED(tdls_feature_flags)) {
+		tdls_debug("disabled in ini");
+		return QDF_STATUS_E_NOSUPPORT;
+	}
+
+	tdls_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+							WLAN_UMAC_COMP_TDLS);
+	if (!tdls_vdev_obj) {
+		tdls_err("Failed to get tdls vdev object");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = wlan_objmgr_vdev_component_obj_detach(vdev,
+						       WLAN_UMAC_COMP_TDLS,
+						       tdls_vdev_obj);
+	if (QDF_IS_STATUS_ERROR(status))
+		tdls_err("Failed to detach vdev tdls component");
+
+	tdls_vdev_deinit(tdls_vdev_obj);
+	qdf_mem_free(tdls_vdev_obj);
+
+	return status;
+}
+
+/**
+ * __tdls_get_all_peers_from_list() - get all the tdls peers from the list
+ * @get_tdls_peers: get_tdls_peers object
+ *
+ * Return: int
+ */
+static int __tdls_get_all_peers_from_list(
+			struct tdls_get_all_peers *get_tdls_peers)
+{
+	int i;
+	int len, init_len;
+	qdf_list_t *head;
+	qdf_list_node_t *p_node;
+	struct tdls_peer *curr_peer;
+	char *buf;
+	int buf_len;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	QDF_STATUS status;
+
+	tdls_notice("Enter ");
+
+	buf = get_tdls_peers->buf;
+	buf_len = get_tdls_peers->buf_len;
+
+	if (!tdls_is_vdev_connected(get_tdls_peers->vdev)) {
+		len = qdf_scnprintf(buf, buf_len,
+				"\nSTA is not associated\n");
+		return len;
+	}
+
+	tdls_vdev = wlan_vdev_get_tdls_vdev_obj(get_tdls_peers->vdev);
+
+	if (!tdls_vdev) {
+		len = qdf_scnprintf(buf, buf_len, "TDLS not enabled\n");
+		return len;
+	}
+
+	init_len = buf_len;
+	len = qdf_scnprintf(buf, buf_len,
+			"\n%-18s%-3s%-4s%-3s%-5s\n",
+			"MAC", "Id", "cap", "up", "RSSI");
+	buf += len;
+	buf_len -= len;
+	len = qdf_scnprintf(buf, buf_len,
+			    "---------------------------------\n");
+	buf += len;
+	buf_len -= len;
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &tdls_vdev->peer_list[i];
+		status = qdf_list_peek_front(head, &p_node);
+		while (QDF_IS_STATUS_SUCCESS(status)) {
+			curr_peer = qdf_container_of(p_node,
+						     struct tdls_peer, node);
+			if (buf_len < 32 + 1)
+				break;
+			len = qdf_scnprintf(buf, buf_len,
+				QDF_MAC_ADDR_STR "%3d%4s%3s%5d\n",
+				QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes),
+				curr_peer->sta_id,
+				(curr_peer->tdls_support ==
+				 TDLS_CAP_SUPPORTED) ? "Y" : "N",
+				TDLS_IS_LINK_CONNECTED(curr_peer) ? "Y" :
+				"N", curr_peer->rssi);
+			buf += len;
+			buf_len -= len;
+			status = qdf_list_peek_next(head, p_node, &p_node);
+		}
+	}
+
+	tdls_notice("Exit ");
+	return init_len - buf_len;
+}
+
+/**
+ * tdls_get_all_peers_from_list() - get all the tdls peers from the list
+ * @get_tdls_peers: get_tdls_peers object
+ *
+ * Return: None
+ */
+static void tdls_get_all_peers_from_list(
+			struct tdls_get_all_peers *get_tdls_peers)
+{
+	int32_t len;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	struct tdls_osif_indication indication;
+
+	if (!get_tdls_peers->vdev) {
+		qdf_mem_free(get_tdls_peers);
+		return;
+	}
+	len = __tdls_get_all_peers_from_list(get_tdls_peers);
+
+	indication.status = len;
+	indication.vdev = get_tdls_peers->vdev;
+
+	tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(get_tdls_peers->vdev);
+	if (tdls_soc_obj && tdls_soc_obj->tdls_event_cb)
+		tdls_soc_obj->tdls_event_cb(tdls_soc_obj->tdls_evt_cb_data,
+			TDLS_EVENT_USER_CMD, &indication);
+
+	qdf_mem_free(get_tdls_peers);
+}
+
+/**
+ * tdls_process_reset_all_peers() - Reset all tdls peers
+ * @delete_all_peers_ind: Delete all peers indication
+ *
+ * This function is called to reset all tdls peers and
+ * notify upper layers of teardown inidcation
+ *
+ * Return: QDF_STATUS
+ */
+
+static QDF_STATUS tdls_process_reset_all_peers(struct wlan_objmgr_vdev *vdev)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint8_t staidx;
+	struct tdls_peer *curr_peer = NULL;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc;
+	uint8_t reset_session_id;
+
+	status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc);
+	if (QDF_STATUS_SUCCESS != status) {
+		tdls_err("tdls objects are NULL ");
+		return status;
+	}
+
+	if (!tdls_soc->connected_peer_count) {
+		tdls_debug("No tdls connected peers");
+		return status;
+	}
+
+	reset_session_id = tdls_vdev->session_id;
+	for (staidx = 0; staidx < tdls_soc->max_num_tdls_sta;
+							staidx++) {
+		if (tdls_soc->tdls_conn_info[staidx].sta_id
+						== INVALID_TDLS_PEER_ID)
+			continue;
+		if (tdls_soc->tdls_conn_info[staidx].session_id !=
+		    reset_session_id)
+			continue;
+
+		curr_peer =
+		tdls_find_all_peer(tdls_soc,
+				   tdls_soc->tdls_conn_info[staidx].
+				   peer_mac.bytes);
+		if (!curr_peer)
+			continue;
+
+		tdls_notice("indicate TDLS teardown (staId %d)",
+			    curr_peer->sta_id);
+
+		/* Indicate teardown to supplicant */
+		tdls_indicate_teardown(tdls_vdev,
+				       curr_peer,
+				       TDLS_TEARDOWN_PEER_UNSPEC_REASON);
+
+		tdls_reset_peer(tdls_vdev, curr_peer->peer_mac.bytes);
+
+		if (tdls_soc->tdls_dereg_peer)
+			tdls_soc->tdls_dereg_peer(
+					tdls_soc->tdls_peer_context,
+					wlan_vdev_get_id(vdev),
+					curr_peer->sta_id);
+		tdls_decrement_peer_count(tdls_soc);
+		tdls_soc->tdls_conn_info[staidx].sta_id = INVALID_TDLS_PEER_ID;
+		tdls_soc->tdls_conn_info[staidx].session_id = 255;
+
+		qdf_mem_zero(&tdls_soc->tdls_conn_info[staidx].peer_mac,
+			     sizeof(struct qdf_mac_addr));
+	}
+	return status;
+}
+
+/**
+ * tdls_reset_all_peers() - Reset all tdls peers
+ * @delete_all_peers_ind: Delete all peers indication
+ *
+ * This function is called to reset all tdls peers and
+ * notify upper layers of teardown inidcation
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS tdls_reset_all_peers(
+		struct tdls_delete_all_peers_params *delete_all_peers_ind)
+{
+	QDF_STATUS status;
+
+	if (!delete_all_peers_ind || !delete_all_peers_ind->vdev) {
+		tdls_err("invalid param");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = tdls_process_reset_all_peers(delete_all_peers_ind->vdev);
+
+	wlan_objmgr_vdev_release_ref(delete_all_peers_ind->vdev,
+				     WLAN_TDLS_SB_ID);
+	qdf_mem_free(delete_all_peers_ind);
+
+	return status;
+}
+
+QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!msg || !msg->bodyptr) {
+		tdls_err("msg: 0x%pK", msg);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	tdls_debug("TDLS process command: %d", msg->type);
+
+	switch (msg->type) {
+	case TDLS_CMD_TX_ACTION:
+		tdls_process_mgmt_req(msg->bodyptr);
+		break;
+	case TDLS_CMD_ADD_STA:
+		tdls_process_add_peer(msg->bodyptr);
+		break;
+	case TDLS_CMD_CHANGE_STA:
+		tdls_process_update_peer(msg->bodyptr);
+		break;
+	case TDLS_CMD_ENABLE_LINK:
+		tdls_process_enable_link(msg->bodyptr);
+		break;
+	case TDLS_CMD_DISABLE_LINK:
+		tdls_process_del_peer(msg->bodyptr);
+		break;
+	case TDLS_CMD_CONFIG_FORCE_PEER:
+		tdls_process_setup_peer(msg->bodyptr);
+		break;
+	case TDLS_CMD_REMOVE_FORCE_PEER:
+		tdls_process_remove_force_peer(msg->bodyptr);
+		break;
+	case TDLS_CMD_STATS_UPDATE:
+		break;
+	case TDLS_CMD_CONFIG_UPDATE:
+		break;
+	case TDLS_CMD_SET_RESPONDER:
+		tdls_set_responder(msg->bodyptr);
+		break;
+	case TDLS_CMD_SCAN_DONE:
+		tdls_scan_done_callback(msg->bodyptr);
+		break;
+	case TDLS_NOTIFY_STA_CONNECTION:
+		tdls_notify_sta_connect(msg->bodyptr);
+		break;
+	case TDLS_NOTIFY_STA_DISCONNECTION:
+		tdls_notify_sta_disconnect(msg->bodyptr);
+		break;
+	case TDLS_CMD_SET_TDLS_MODE:
+		tdls_set_operation_mode(msg->bodyptr);
+		break;
+	case TDLS_CMD_SESSION_INCREMENT:
+	case TDLS_CMD_SESSION_DECREMENT:
+		tdls_process_policy_mgr_notification(msg->bodyptr);
+		break;
+	case TDLS_CMD_TEARDOWN_LINKS:
+		tdls_teardown_connections(msg->bodyptr);
+		break;
+	case TDLS_NOTIFY_RESET_ADAPTERS:
+		tdls_notify_reset_adapter(msg->bodyptr);
+		break;
+	case TDLS_CMD_ANTENNA_SWITCH:
+		tdls_process_antenna_switch(msg->bodyptr);
+		break;
+	case TDLS_CMD_GET_ALL_PEERS:
+		tdls_get_all_peers_from_list(msg->bodyptr);
+		break;
+	case TDLS_CMD_SET_OFFCHANNEL:
+		tdls_process_set_offchannel(msg->bodyptr);
+		break;
+	case TDLS_CMD_SET_OFFCHANMODE:
+		tdls_process_set_offchan_mode(msg->bodyptr);
+		break;
+	case TDLS_CMD_SET_SECOFFCHANOFFSET:
+		tdls_process_set_secoffchanneloffset(msg->bodyptr);
+		break;
+	case TDLS_DELETE_ALL_PEERS_INDICATION:
+		tdls_reset_all_peers(msg->bodyptr);
+		break;
+	default:
+		break;
+	}
+
+	return status;
+}
+
+QDF_STATUS tdls_process_evt(struct scheduler_msg *msg)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_event_notify *notify;
+	struct tdls_event_info *event;
+
+	if (!msg || !msg->bodyptr) {
+		tdls_err("msg is not valid: %pK", msg);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	notify = msg->bodyptr;
+	vdev = notify->vdev;
+	if (!vdev) {
+		tdls_err("NULL vdev object");
+		qdf_mem_free(notify);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	event = &notify->event;
+
+	tdls_debug("evt type: %d", event->message_type);
+	switch (event->message_type) {
+	case TDLS_SHOULD_DISCOVER:
+		tdls_process_should_discover(vdev, event);
+		break;
+	case TDLS_SHOULD_TEARDOWN:
+	case TDLS_PEER_DISCONNECTED:
+		tdls_process_should_teardown(vdev, event);
+		break;
+	case TDLS_CONNECTION_TRACKER_NOTIFY:
+		tdls_process_connection_tracker_notify(vdev, event);
+		break;
+	default:
+		break;
+	}
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+	qdf_mem_free(notify);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void tdls_timer_restart(struct wlan_objmgr_vdev *vdev,
+				 qdf_mc_timer_t *timer,
+				 uint32_t expiration_time)
+{
+	qdf_mc_timer_start(timer, expiration_time);
+}
+
+/**
+ * wlan_hdd_tdls_monitor_timers_stop() - stop all monitoring timers
+ * @hdd_tdls_ctx: TDLS context
+ *
+ * Return: none
+ */
+static void tdls_monitor_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	qdf_mc_timer_stop(&tdls_vdev->peer_discovery_timer);
+}
+
+/**
+ * tdls_peer_idle_timers_stop() - stop peer idle timers
+ * @tdls_vdev: TDLS vdev object
+ *
+ * Loop through the idle peer list and stop their timers
+ *
+ * Return: None
+ */
+static void tdls_peer_idle_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	int i;
+	qdf_list_t *head;
+	qdf_list_node_t *p_node;
+	struct tdls_peer *curr_peer;
+	QDF_STATUS status;
+
+	tdls_vdev->discovery_peer_cnt = 0;
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &tdls_vdev->peer_list[i];
+		status = qdf_list_peek_front(head, &p_node);
+		while (QDF_IS_STATUS_SUCCESS(status)) {
+			curr_peer = qdf_container_of(p_node, struct tdls_peer,
+						     node);
+			if (curr_peer->is_peer_idle_timer_initialised)
+				qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
+			status = qdf_list_peek_next(head, p_node, &p_node);
+		}
+	}
+
+}
+
+/**
+ * wlan_hdd_tdls_ct_timers_stop() - stop tdls connection tracker timers
+ * @tdls_vdev: TDLS vdev
+ *
+ * Return: None
+ */
+static void tdls_ct_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	qdf_mc_timer_stop(&tdls_vdev->peer_update_timer);
+	tdls_peer_idle_timers_stop(tdls_vdev);
+}
+
+/**
+ * wlan_hdd_tdls_timers_stop() - stop all the tdls timers running
+ * @tdls_vdev: TDLS vdev
+ *
+ * Return: none
+ */
+void tdls_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	tdls_monitor_timers_stop(tdls_vdev);
+	tdls_ct_timers_stop(tdls_vdev);
+}
+
+QDF_STATUS tdls_get_vdev_objects(struct wlan_objmgr_vdev *vdev,
+				   struct tdls_vdev_priv_obj **tdls_vdev_obj,
+				   struct tdls_soc_priv_obj **tdls_soc_obj)
+{
+	enum QDF_OPMODE device_mode;
+
+	if (NULL == vdev)
+		return QDF_STATUS_E_FAILURE;
+
+	*tdls_vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev);
+	if (NULL == (*tdls_vdev_obj))
+		return QDF_STATUS_E_FAILURE;
+
+	*tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (NULL == (*tdls_soc_obj))
+		return QDF_STATUS_E_FAILURE;
+
+	device_mode = wlan_vdev_mlme_get_opmode(vdev);
+
+	if (device_mode != QDF_STA_MODE &&
+	    device_mode != QDF_P2P_CLIENT_MODE)
+		return QDF_STATUS_E_FAILURE;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * tdls_state_param_setting_dump() - print tdls state & parameters to send to fw
+ * @info: tdls setting to be sent to fw
+ *
+ * Return: void
+ */
+static void tdls_state_param_setting_dump(struct tdls_info *info)
+{
+	if (!info)
+		return;
+
+	tdls_debug("Setting tdls state and param in fw: vdev_id: %d, tdls_state: %d, notification_interval_ms: %d, tx_discovery_threshold: %d, tx_teardown_threshold: %d, rssi_teardown_threshold: %d, rssi_delta: %d, tdls_options: 0x%x, peer_traffic_ind_window: %d, peer_traffic_response_timeout: %d, puapsd_mask: 0x%x, puapsd_inactivity_time: %d, puapsd_rx_frame_threshold: %d, teardown_notification_ms: %d, tdls_peer_kickout_threshold: %d",
+		   info->vdev_id,
+		   info->tdls_state,
+		   info->notification_interval_ms,
+		   info->tx_discovery_threshold,
+		   info->tx_teardown_threshold,
+		   info->rssi_teardown_threshold,
+		   info->rssi_delta,
+		   info->tdls_options,
+		   info->peer_traffic_ind_window,
+		   info->peer_traffic_response_timeout,
+		   info->puapsd_mask,
+		   info->puapsd_inactivity_time,
+		   info->puapsd_rx_frame_threshold,
+		   info->teardown_notification_ms,
+		   info->tdls_peer_kickout_threshold);
+
+}
+
+QDF_STATUS tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc,
+				     struct tdls_channel_switch_params *param)
+{
+	QDF_STATUS status;
+
+	/*  wmi_unified_set_tdls_offchan_mode_cmd() will be called directly */
+	status = tgt_tdls_set_offchan_mode(psoc, param);
+
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		status = QDF_STATUS_E_FAILURE;
+
+	return status;
+}
+
+/**
+ * tdls_update_fw_tdls_state() - update tdls status info
+ * @tdls_soc_obj: TDLS soc object
+ * @tdls_info_to_fw: TDLS state info to update in f/w.
+ *
+ * send message to WMA to set TDLS state in f/w
+ *
+ * Return: QDF_STATUS.
+ */
+static
+QDF_STATUS tdls_update_fw_tdls_state(struct tdls_soc_priv_obj *tdls_soc_obj,
+				     struct tdls_info *tdls_info_to_fw)
+{
+	QDF_STATUS status;
+
+	/*  wmi_unified_update_fw_tdls_state_cmd() will be called directly */
+	status = tgt_tdls_set_fw_state(tdls_soc_obj->soc, tdls_info_to_fw);
+
+	if (!QDF_IS_STATUS_SUCCESS(status))
+		status = QDF_STATUS_E_FAILURE;
+
+	return status;
+}
+
+bool tdls_check_is_tdls_allowed(struct wlan_objmgr_vdev *vdev)
+{
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	bool state = false;
+
+	if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(vdev,
+							       WLAN_TDLS_NB_ID))
+		return state;
+
+	if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj,
+						   &tdls_soc_obj)) {
+		wlan_objmgr_vdev_release_ref(vdev,
+					     WLAN_TDLS_NB_ID);
+		return state;
+	}
+
+	if (policy_mgr_get_connection_count(tdls_soc_obj->soc) == 1)
+		state = true;
+	else
+		tdls_warn("Concurrent sessions are running or TDLS disabled");
+	/* If any concurrency is detected */
+	/* print session information */
+	wlan_objmgr_vdev_release_ref(vdev,
+				     WLAN_TDLS_NB_ID);
+	return state;
+}
+
+/**
+ * cds_set_tdls_ct_mode() - Set the tdls connection tracker mode
+ * @hdd_ctx: hdd context
+ *
+ * This routine is called to set the tdls connection tracker operation status
+ *
+ * Return: NONE
+ */
+void tdls_set_ct_mode(struct wlan_objmgr_psoc *psoc)
+{
+	bool state = false;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+
+	tdls_soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (NULL == tdls_soc_obj)
+		return;
+
+	/* If any concurrency is detected, skip tdls pkt tracker */
+	if (policy_mgr_get_connection_count(psoc) > 1) {
+		state = false;
+		goto set_state;
+	}
+
+	if (TDLS_SUPPORT_DISABLED == tdls_soc_obj->tdls_current_mode ||
+	    TDLS_SUPPORT_SUSPENDED == tdls_soc_obj->tdls_current_mode ||
+	    !TDLS_IS_IMPLICIT_TRIG_ENABLED(
+			tdls_soc_obj->tdls_configs.tdls_feature_flags)) {
+		state = false;
+		goto set_state;
+	} else if (policy_mgr_mode_specific_connection_count(psoc,
+							     PM_STA_MODE,
+							     NULL) == 1) {
+		state = true;
+	} else if (policy_mgr_mode_specific_connection_count(psoc,
+							     PM_P2P_CLIENT_MODE,
+							     NULL) == 1){
+		state = true;
+	} else {
+		state = false;
+		goto set_state;
+	}
+
+	/* In case of TDLS external control, peer should be added
+	 * by the user space to start connection tracker.
+	 */
+	if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(
+			tdls_soc_obj->tdls_configs.tdls_feature_flags)) {
+		if (tdls_soc_obj->tdls_external_peer_count)
+			state = true;
+		else
+			state = false;
+	}
+
+set_state:
+	tdls_soc_obj->enable_tdls_connection_tracker = state;
+
+	tdls_debug("enable_tdls_connection_tracker %d",
+		 tdls_soc_obj->enable_tdls_connection_tracker);
+}
+
+QDF_STATUS
+tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc)
+{
+	if (!psoc) {
+		tdls_err("psoc: %pK", psoc);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	tdls_debug("enter ");
+	tdls_set_ct_mode(psoc);
+	tdls_debug("exit ");
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * tdls_get_vdev() - Get tdls specific vdev object manager
+ * @psoc: wlan psoc object manager
+ * @dbg_id: debug id
+ *
+ * If TDLS possible, return the corresponding vdev
+ * to enable TDLS in the system.
+ *
+ * Return: vdev manager pointer or NULL.
+ */
+struct wlan_objmgr_vdev *tdls_get_vdev(struct wlan_objmgr_psoc *psoc,
+					  wlan_objmgr_ref_dbgid dbg_id)
+{
+	uint32_t vdev_id;
+
+	if (policy_mgr_get_connection_count(psoc) > 1)
+		return NULL;
+
+	vdev_id = policy_mgr_mode_specific_vdev_id(psoc, PM_STA_MODE);
+
+	if (WLAN_INVALID_VDEV_ID != vdev_id)
+		return wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+							    vdev_id,
+							    dbg_id);
+
+	vdev_id = policy_mgr_mode_specific_vdev_id(psoc, PM_P2P_CLIENT_MODE);
+
+	if (WLAN_INVALID_VDEV_ID != vdev_id)
+		return wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+							    vdev_id,
+							    dbg_id);
+
+	return NULL;
+}
+
+static QDF_STATUS tdls_post_msg_flush_cb(struct scheduler_msg *msg)
+{
+	void *ptr = msg->bodyptr;
+	struct wlan_objmgr_vdev *vdev = NULL;
+
+	switch (msg->type) {
+	case TDLS_NOTIFY_STA_DISCONNECTION:
+		vdev = ((struct tdls_sta_notify_params *)ptr)->vdev;
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(ptr);
+		break;
+
+	case TDLS_DELETE_ALL_PEERS_INDICATION:
+		vdev = ((struct tdls_delete_all_peers_params *)ptr)->vdev;
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+		qdf_mem_free(ptr);
+		break;
+
+	case TDLS_CMD_SCAN_DONE:
+	case TDLS_CMD_SESSION_INCREMENT:
+	case TDLS_CMD_SESSION_DECREMENT:
+		break;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * tdls_process_session_update() - update session count information
+ * @psoc: soc object
+ * @notification: TDLS os if notification
+ *
+ * update the session information in connection tracker
+ *
+ * Return: None
+ */
+static void tdls_process_session_update(struct wlan_objmgr_psoc *psoc,
+				 enum tdls_command_type cmd_type)
+{
+	struct scheduler_msg msg = {0};
+	QDF_STATUS status;
+
+	msg.bodyptr = psoc;
+	msg.callback = tdls_process_cmd;
+	msg.flush_callback = tdls_post_msg_flush_cb;
+	msg.type = (uint16_t)cmd_type;
+
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status))
+		tdls_alert("message post failed ");
+}
+
+void tdls_notify_increment_session(struct wlan_objmgr_psoc *psoc)
+{
+	tdls_process_session_update(psoc, TDLS_CMD_SESSION_INCREMENT);
+}
+
+void tdls_notify_decrement_session(struct wlan_objmgr_psoc *psoc)
+{
+	tdls_process_session_update(psoc, TDLS_CMD_SESSION_DECREMENT);
+}
+
+void tdls_send_update_to_fw(struct tdls_vdev_priv_obj *tdls_vdev_obj,
+			    struct tdls_soc_priv_obj *tdls_soc_obj,
+			    bool tdls_prohibited,
+			    bool tdls_chan_swit_prohibited,
+			    bool sta_connect_event,
+			    uint8_t session_id)
+{
+	struct tdls_info *tdls_info_to_fw;
+	struct tdls_config_params *threshold_params;
+	uint32_t tdls_feature_flags;
+	QDF_STATUS status;
+
+	tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags;
+	if (!TDLS_IS_ENABLED(tdls_feature_flags)) {
+		tdls_debug("TDLS mode is not enabled");
+		return;
+	}
+
+	if (tdls_soc_obj->set_state_info.set_state_cnt == 0 &&
+	    !sta_connect_event) {
+		return;
+	}
+
+	/* If AP or caller indicated TDLS Prohibited then disable tdls mode */
+	if (sta_connect_event) {
+		if (tdls_prohibited) {
+			tdls_soc_obj->tdls_current_mode =
+					TDLS_SUPPORT_DISABLED;
+		} else {
+			tdls_debug("TDLS feature flags from ini %d ",
+				tdls_feature_flags);
+			if (!TDLS_IS_IMPLICIT_TRIG_ENABLED(tdls_feature_flags))
+				tdls_soc_obj->tdls_current_mode =
+					TDLS_SUPPORT_EXP_TRIG_ONLY;
+			else if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(
+				tdls_feature_flags))
+				tdls_soc_obj->tdls_current_mode =
+					TDLS_SUPPORT_EXT_CONTROL;
+			else
+				tdls_soc_obj->tdls_current_mode =
+					TDLS_SUPPORT_IMP_MODE;
+		}
+	} else {
+		tdls_soc_obj->tdls_current_mode =
+				TDLS_SUPPORT_DISABLED;
+	}
+
+	tdls_info_to_fw = qdf_mem_malloc(sizeof(struct tdls_info));
+
+	if (!tdls_info_to_fw) {
+		tdls_err("memory allocation failed for tdlsParams");
+		QDF_ASSERT(0);
+		return;
+	}
+
+	threshold_params = &tdls_vdev_obj->threshold_config;
+
+	tdls_info_to_fw->notification_interval_ms =
+		threshold_params->tx_period_t;
+	tdls_info_to_fw->tx_discovery_threshold =
+		threshold_params->tx_packet_n;
+	tdls_info_to_fw->tx_teardown_threshold =
+		threshold_params->idle_packet_n;
+	tdls_info_to_fw->rssi_teardown_threshold =
+		threshold_params->rssi_teardown_threshold;
+	tdls_info_to_fw->rssi_delta = threshold_params->rssi_delta;
+
+	if (tdls_soc_obj->set_state_info.set_state_cnt == 1 &&
+	    sta_connect_event) {
+		tdls_warn("Concurrency not allowed in TDLS! set state cnt %d",
+			tdls_soc_obj->set_state_info.set_state_cnt);
+		/* disable off channel and teardown links */
+		/* Go through the peer list and delete them */
+		tdls_disable_offchan_and_teardown_links(tdls_vdev_obj->vdev);
+		tdls_soc_obj->tdls_current_mode = TDLS_SUPPORT_DISABLED;
+		tdls_info_to_fw->vdev_id = tdls_soc_obj->set_state_info.vdev_id;
+	} else {
+		tdls_info_to_fw->vdev_id = session_id;
+	}
+
+	/* record the session id in vdev context */
+	tdls_vdev_obj->session_id = session_id;
+	tdls_info_to_fw->tdls_state = tdls_soc_obj->tdls_current_mode;
+	tdls_info_to_fw->tdls_options = 0;
+
+	/* Do not enable TDLS offchannel, if AP prohibited TDLS
+	 * channel switch
+	 */
+	if (TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) &&
+		(!tdls_chan_swit_prohibited))
+		tdls_info_to_fw->tdls_options = ENA_TDLS_OFFCHAN;
+
+	if (TDLS_IS_BUFFER_STA_ENABLED(tdls_feature_flags))
+		tdls_info_to_fw->tdls_options |= ENA_TDLS_BUFFER_STA;
+	if (TDLS_IS_SLEEP_STA_ENABLED(tdls_feature_flags))
+		tdls_info_to_fw->tdls_options |=  ENA_TDLS_SLEEP_STA;
+
+
+	tdls_info_to_fw->peer_traffic_ind_window =
+		tdls_soc_obj->tdls_configs.tdls_uapsd_pti_window;
+	tdls_info_to_fw->peer_traffic_response_timeout =
+		tdls_soc_obj->tdls_configs.tdls_uapsd_ptr_timeout;
+	tdls_info_to_fw->puapsd_mask =
+		tdls_soc_obj->tdls_configs.tdls_uapsd_mask;
+	tdls_info_to_fw->puapsd_inactivity_time =
+		tdls_soc_obj->tdls_configs.tdls_uapsd_inactivity_time;
+	tdls_info_to_fw->puapsd_rx_frame_threshold =
+		tdls_soc_obj->tdls_configs.tdls_rx_pkt_threshold;
+	tdls_info_to_fw->teardown_notification_ms =
+		tdls_soc_obj->tdls_configs.tdls_idle_timeout;
+	tdls_info_to_fw->tdls_peer_kickout_threshold =
+		tdls_soc_obj->tdls_configs.tdls_peer_kickout_threshold;
+
+	tdls_state_param_setting_dump(tdls_info_to_fw);
+
+	status = tdls_update_fw_tdls_state(tdls_soc_obj, tdls_info_to_fw);
+	if (QDF_STATUS_SUCCESS != status)
+		goto done;
+
+	if (sta_connect_event) {
+		tdls_soc_obj->set_state_info.set_state_cnt++;
+		tdls_soc_obj->set_state_info.vdev_id = session_id;
+	} else {
+		tdls_soc_obj->set_state_info.set_state_cnt--;
+	}
+
+	tdls_debug("TDLS Set state cnt %d",
+		tdls_soc_obj->set_state_info.set_state_cnt);
+done:
+	qdf_mem_free(tdls_info_to_fw);
+	return;
+}
+
+static QDF_STATUS
+tdls_process_sta_connect(struct tdls_sta_notify_params *notify)
+{
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+
+	if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(notify->vdev,
+							&tdls_vdev_obj,
+							&tdls_soc_obj))
+		return QDF_STATUS_E_INVAL;
+
+
+	tdls_debug("Check and update TDLS state");
+
+	if (policy_mgr_get_connection_count(tdls_soc_obj->soc) > 1) {
+		tdls_debug("Concurrent sessions exist, TDLS can't be enabled");
+		return QDF_STATUS_SUCCESS;
+	}
+
+	/* Association event */
+	if (!tdls_soc_obj->tdls_disable_in_progress) {
+		tdls_send_update_to_fw(tdls_vdev_obj,
+				   tdls_soc_obj,
+				   notify->tdls_prohibited,
+				   notify->tdls_chan_swit_prohibited,
+				   true,
+				   notify->session_id);
+	}
+
+	/* check and set the connection tracker */
+	tdls_set_ct_mode(tdls_soc_obj->soc);
+	if (tdls_soc_obj->enable_tdls_connection_tracker)
+		tdls_implicit_enable(tdls_vdev_obj);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify)
+{
+	QDF_STATUS status;
+
+	if (!notify || !notify->vdev) {
+		tdls_err("invalid param");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = tdls_process_sta_connect(notify);
+
+	wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID);
+	qdf_mem_free(notify);
+
+	return status;
+}
+
+static QDF_STATUS
+tdls_process_sta_disconnect(struct tdls_sta_notify_params *notify)
+{
+	struct tdls_vdev_priv_obj *tdls_vdev_obj;
+	struct tdls_vdev_priv_obj *curr_tdls_vdev;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	struct tdls_soc_priv_obj *curr_tdls_soc;
+	struct wlan_objmgr_vdev *temp_vdev = NULL;
+
+
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(notify->vdev,
+							&tdls_vdev_obj,
+							&tdls_soc_obj))
+		return QDF_STATUS_E_INVAL;
+
+	/* if the disconnect comes from user space, we have to delete all the
+	 * tdls peers before sending the set state cmd.
+	 */
+	if (notify->user_disconnect)
+		return tdls_delete_all_tdls_peers(notify->vdev, tdls_soc_obj);
+
+	tdls_debug("Check and update TDLS state");
+
+	curr_tdls_vdev = tdls_vdev_obj;
+	curr_tdls_soc = tdls_soc_obj;
+
+	/* Disassociation event */
+	if (!tdls_soc_obj->tdls_disable_in_progress)
+		tdls_send_update_to_fw(tdls_vdev_obj, tdls_soc_obj, false,
+				       false, false, notify->session_id);
+
+	/* If concurrency is not marked, then we have to
+	 * check, whether TDLS could be enabled in the
+	 * system after this disassoc event.
+	 */
+	if (!notify->lfr_roam && !tdls_soc_obj->tdls_disable_in_progress) {
+		temp_vdev = tdls_get_vdev(tdls_soc_obj->soc, WLAN_TDLS_NB_ID);
+		if (NULL != temp_vdev) {
+			status = tdls_get_vdev_objects(temp_vdev,
+						       &tdls_vdev_obj,
+						       &tdls_soc_obj);
+			if (QDF_STATUS_SUCCESS == status) {
+				tdls_send_update_to_fw(tdls_vdev_obj,
+						       tdls_soc_obj,
+						       false,
+						       false,
+						       true,
+						       notify->session_id);
+				curr_tdls_vdev = tdls_vdev_obj;
+				curr_tdls_soc = tdls_soc_obj;
+			}
+		}
+	}
+
+	/* Check and set the connection tracker and implicit timers */
+	tdls_set_ct_mode(curr_tdls_soc->soc);
+	if (curr_tdls_soc->enable_tdls_connection_tracker)
+		tdls_implicit_enable(curr_tdls_vdev);
+	else
+		tdls_implicit_disable(curr_tdls_vdev);
+
+	/* release the vdev ref , if temp vdev was acquired */
+	if (temp_vdev)
+		wlan_objmgr_vdev_release_ref(temp_vdev,
+					     WLAN_TDLS_NB_ID);
+
+	return status;
+}
+
+QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify)
+{
+	QDF_STATUS status;
+
+	if (!notify || !notify->vdev) {
+		tdls_err("invalid param");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	status = tdls_process_sta_disconnect(notify);
+
+	wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID);
+	qdf_mem_free(notify);
+
+	return status;
+}
+
+static void tdls_process_reset_adapter(struct wlan_objmgr_vdev *vdev)
+{
+	struct tdls_vdev_priv_obj *tdls_vdev;
+
+	tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
+	if (!tdls_vdev)
+		return;
+	tdls_timers_stop(tdls_vdev);
+}
+
+void tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev)
+{
+	if (!vdev) {
+		QDF_ASSERT(0);
+		return;
+	}
+
+	if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(vdev,
+						WLAN_TDLS_NB_ID))
+		return;
+
+	tdls_process_reset_adapter(vdev);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+}
+
+QDF_STATUS tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_sta_notify_params *notify;
+	QDF_STATUS status;
+	struct wlan_objmgr_vdev *vdev;
+
+	notify = qdf_mem_malloc(sizeof(*notify));
+	if (!notify) {
+		tdls_err("memory allocation failed !!!");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+						    vdev_id,
+						    WLAN_TDLS_NB_ID);
+
+	if (!vdev) {
+		tdls_err("vdev not exist for the vdev id %d",
+			 vdev_id);
+		qdf_mem_free(notify);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	notify->lfr_roam = true;
+	notify->tdls_chan_swit_prohibited = false;
+	notify->tdls_prohibited = false;
+	notify->session_id = vdev_id;
+	notify->vdev = vdev;
+	notify->user_disconnect = false;
+
+	msg.bodyptr = notify;
+	msg.callback = tdls_process_cmd;
+	msg.flush_callback = tdls_post_msg_flush_cb;
+	msg.type = TDLS_NOTIFY_STA_DISCONNECTION;
+
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(notify);
+		tdls_alert("message post failed ");
+
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc,
+					    uint8_t vdev_id)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_delete_all_peers_params *indication;
+	QDF_STATUS status;
+	struct wlan_objmgr_vdev *vdev;
+
+	indication = qdf_mem_malloc(sizeof(*indication));
+	if (!indication) {
+		tdls_err("memory allocation failed !!!");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+						    vdev_id,
+						    WLAN_TDLS_SB_ID);
+
+	if (!vdev) {
+		tdls_err("vdev not exist for the session id %d",
+			 vdev_id);
+		qdf_mem_free(indication);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	indication->vdev = vdev;
+
+	msg.bodyptr = indication;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_DELETE_ALL_PEERS_INDICATION;
+	msg.flush_callback = tdls_post_msg_flush_cb;
+
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+		qdf_mem_free(indication);
+		tdls_alert("message post failed ");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * tdls_set_mode_in_vdev() - set TDLS mode
+ * @tdls_vdev: tdls vdev object
+ * @tdls_soc: tdls soc object
+ * @tdls_mode: TDLS mode
+ * @source: TDLS disable source enum values
+ *
+ * Return: Void
+ */
+static void tdls_set_mode_in_vdev(struct tdls_vdev_priv_obj *tdls_vdev,
+				  struct tdls_soc_priv_obj *tdls_soc,
+				  enum tdls_feature_mode tdls_mode,
+				  enum tdls_disable_sources source)
+{
+	if (!tdls_vdev)
+		return;
+	tdls_debug("enter tdls mode is %d", tdls_mode);
+
+	if (TDLS_SUPPORT_IMP_MODE == tdls_mode ||
+	    TDLS_SUPPORT_EXT_CONTROL == tdls_mode) {
+		clear_bit((unsigned long)source,
+			  &tdls_soc->tdls_source_bitmap);
+		/*
+		 * Check if any TDLS source bit is set and if
+		 * bitmap is not zero then we should not
+		 * enable TDLS
+		 */
+		if (tdls_soc->tdls_source_bitmap) {
+			tdls_notice("Don't enable TDLS, source bitmap: %lu",
+				tdls_soc->tdls_source_bitmap);
+			return;
+		}
+		tdls_implicit_enable(tdls_vdev);
+		/* tdls implicit mode is enabled, so
+		 * enable the connection tracker
+		 */
+		tdls_soc->enable_tdls_connection_tracker =
+			true;
+	} else if (TDLS_SUPPORT_DISABLED == tdls_mode) {
+		set_bit((unsigned long)source,
+			&tdls_soc->tdls_source_bitmap);
+		tdls_implicit_disable(tdls_vdev);
+		/* If tdls implicit mode is disabled, then
+		 * stop the connection tracker.
+		 */
+		tdls_soc->enable_tdls_connection_tracker =
+			false;
+	} else if (TDLS_SUPPORT_EXP_TRIG_ONLY ==
+		   tdls_mode) {
+		clear_bit((unsigned long)source,
+			  &tdls_soc->tdls_source_bitmap);
+		tdls_implicit_disable(tdls_vdev);
+		/* If tdls implicit mode is disabled, then
+		 * stop the connection tracker.
+		 */
+		tdls_soc->enable_tdls_connection_tracker =
+			false;
+
+		/*
+		 * Check if any TDLS source bit is set and if
+		 * bitmap is not zero then we should not
+		 * enable TDLS
+		 */
+		if (tdls_soc->tdls_source_bitmap)
+			return;
+	}
+	tdls_debug("exit ");
+
+}
+
+/**
+ * tdls_set_current_mode() - set TDLS mode
+ * @tdls_soc: tdls soc object
+ * @tdls_mode: TDLS mode
+ * @update_last: indicate to record the last tdls mode
+ * @source: TDLS disable source enum values
+ *
+ * Return: Void
+ */
+static void tdls_set_current_mode(struct tdls_soc_priv_obj *tdls_soc,
+				   enum tdls_feature_mode tdls_mode,
+				   bool update_last,
+				   enum tdls_disable_sources source)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+
+	if (!tdls_soc)
+		return;
+
+	tdls_debug("mode %d", (int)tdls_mode);
+
+	if (update_last)
+		tdls_soc->tdls_last_mode = tdls_mode;
+
+	if (tdls_soc->tdls_current_mode == tdls_mode) {
+		tdls_debug("already in mode %d", tdls_mode);
+
+		switch (tdls_mode) {
+		/* TDLS is already enabled hence clear source mask, return */
+		case TDLS_SUPPORT_IMP_MODE:
+		case TDLS_SUPPORT_EXP_TRIG_ONLY:
+		case TDLS_SUPPORT_EXT_CONTROL:
+			clear_bit((unsigned long)source,
+				  &tdls_soc->tdls_source_bitmap);
+			tdls_debug("clear source mask:%d", source);
+			return;
+		/* TDLS is already disabled hence set source mask, return */
+		case TDLS_SUPPORT_DISABLED:
+			set_bit((unsigned long)source,
+				&tdls_soc->tdls_source_bitmap);
+			tdls_debug("set source mask:%d", source);
+			return;
+		default:
+			return;
+		}
+	}
+
+	/* get sta vdev */
+	vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(tdls_soc->soc,
+							QDF_STA_MODE,
+							WLAN_TDLS_NB_ID);
+	if (NULL != vdev) {
+		tdls_debug("set mode in tdls vdev ");
+		tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
+		if (!tdls_vdev)
+			tdls_set_mode_in_vdev(tdls_vdev, tdls_soc,
+					      tdls_mode, source);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+	}
+
+	/* get p2p client vdev */
+	vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(tdls_soc->soc,
+							QDF_P2P_CLIENT_MODE,
+							WLAN_TDLS_NB_ID);
+	if (NULL != vdev) {
+		tdls_debug("set mode in tdls vdev ");
+		tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
+		if (!tdls_vdev)
+			tdls_set_mode_in_vdev(tdls_vdev, tdls_soc,
+					      tdls_mode, source);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+	}
+
+	if (!update_last)
+		tdls_soc->tdls_last_mode = tdls_soc->tdls_current_mode;
+
+	tdls_soc->tdls_current_mode = tdls_mode;
+
+}
+
+QDF_STATUS tdls_set_operation_mode(struct tdls_set_mode_params *tdls_set_mode)
+{
+	struct tdls_soc_priv_obj *tdls_soc;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	QDF_STATUS status;
+
+	if (!tdls_set_mode || !tdls_set_mode->vdev)
+		return QDF_STATUS_E_INVAL;
+
+	status = tdls_get_vdev_objects(tdls_set_mode->vdev,
+				       &tdls_vdev, &tdls_soc);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		goto release_mode_ref;
+
+	tdls_set_current_mode(tdls_soc,
+			      tdls_set_mode->tdls_mode,
+			      tdls_set_mode->update_last,
+			      tdls_set_mode->source);
+
+release_mode_ref:
+	wlan_objmgr_vdev_release_ref(tdls_set_mode->vdev, WLAN_TDLS_NB_ID);
+	qdf_mem_free(tdls_set_mode);
+	return status;
+}
+
+/**
+ * wlan_hdd_tdls_scan_done_callback() - callback for tdls scan done event
+ * @pAdapter: HDD adapter
+ *
+ * Return: Void
+ */
+void tdls_scan_done_callback(struct tdls_soc_priv_obj *tdls_soc)
+{
+	if (!tdls_soc)
+		return;
+
+	if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode) {
+		tdls_debug("TDLS mode is disabled OR not enabled");
+		return;
+	}
+
+	/* if tdls was enabled before scan, re-enable tdls mode */
+	if (TDLS_SUPPORT_IMP_MODE == tdls_soc->tdls_last_mode ||
+	    TDLS_SUPPORT_EXT_CONTROL == tdls_soc->tdls_last_mode ||
+	    TDLS_SUPPORT_EXP_TRIG_ONLY == tdls_soc->tdls_last_mode) {
+		tdls_debug("revert tdls mode %d",
+			   tdls_soc->tdls_last_mode);
+
+		tdls_set_current_mode(tdls_soc, tdls_soc->tdls_last_mode,
+				      false,
+				      TDLS_SET_MODE_SOURCE_SCAN);
+	}
+}
+
+/**
+ * tdls_post_scan_done_msg() - post scan done message to tdls cmd queue
+ * @tdls_soc: tdls soc object
+ *
+ * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_NULL_VALUE
+ */
+static QDF_STATUS tdls_post_scan_done_msg(struct tdls_soc_priv_obj *tdls_soc)
+{
+	struct scheduler_msg msg = {0, };
+
+	if (!tdls_soc) {
+		tdls_err("tdls_soc: %pK ", tdls_soc);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	msg.bodyptr = tdls_soc;
+	msg.callback = tdls_process_cmd;
+	msg.flush_callback = tdls_post_msg_flush_cb;
+	msg.type = TDLS_CMD_SCAN_DONE;
+
+	return scheduler_post_message(QDF_MODULE_ID_TDLS,
+				      QDF_MODULE_ID_TDLS,
+				      QDF_MODULE_ID_OS_IF, &msg);
+}
+
+void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev,
+			struct scan_event *event,
+			void *arg)
+{
+	enum QDF_OPMODE device_mode;
+	struct tdls_soc_priv_obj *tdls_soc;
+
+	if (!vdev || !event || !arg)
+		return;
+
+	if (SCAN_EVENT_TYPE_COMPLETED != event->type)
+		return;
+
+	device_mode = wlan_vdev_mlme_get_opmode(vdev);
+
+	if (device_mode != QDF_STA_MODE &&
+	    device_mode != QDF_P2P_CLIENT_MODE)
+		return;
+	tdls_soc = (struct tdls_soc_priv_obj *) arg;
+	tdls_post_scan_done_msg(tdls_soc);
+}
+
+QDF_STATUS tdls_scan_callback(struct tdls_soc_priv_obj *tdls_soc)
+{
+	struct tdls_peer *curr_peer;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	struct wlan_objmgr_vdev *vdev;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	/* if tdls is not enabled, then continue scan */
+	if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode)
+		return status;
+
+	/* Get the vdev based on vdev operating mode*/
+	vdev = tdls_get_vdev(tdls_soc->soc, WLAN_TDLS_NB_ID);
+	if (!vdev)
+		return status;
+
+	tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev);
+	if (!tdls_vdev)
+		goto  return_success;
+
+	curr_peer = tdls_is_progress(tdls_vdev, NULL, 0);
+	if (NULL != curr_peer) {
+		if (tdls_soc->scan_reject_count++ >= TDLS_SCAN_REJECT_MAX) {
+			tdls_notice(QDF_MAC_ADDR_STR
+				    ". scan rejected %d. force it to idle",
+				    QDF_MAC_ADDR_ARRAY(
+						curr_peer->peer_mac.bytes),
+				    tdls_soc->scan_reject_count);
+			tdls_soc->scan_reject_count = 0;
+
+			tdls_set_peer_link_status(curr_peer,
+						  TDLS_LINK_IDLE,
+						  TDLS_LINK_UNSPECIFIED);
+			status = QDF_STATUS_SUCCESS;
+		} else {
+			tdls_warn("tdls in progress. scan rejected %d",
+				  tdls_soc->scan_reject_count);
+			status = QDF_STATUS_E_BUSY;
+		}
+	}
+return_success:
+	wlan_objmgr_vdev_release_ref(vdev,
+				     WLAN_TDLS_NB_ID);
+	return status;
+}
+
+void tdls_scan_serialization_comp_info_cb(struct wlan_objmgr_vdev *vdev,
+		union wlan_serialization_rules_info *comp_info)
+{
+	struct tdls_soc_priv_obj *tdls_soc;
+	QDF_STATUS status;
+	if (!comp_info)
+		return;
+
+	tdls_soc = tdls_soc_global;
+	comp_info->scan_info.is_tdls_in_progress = false;
+	status = tdls_scan_callback(tdls_soc);
+	if (QDF_STATUS_E_BUSY == status)
+		comp_info->scan_info.is_tdls_in_progress = true;
+}
+
+

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

@@ -0,0 +1,741 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_main.h
+ *
+ * TDLS core function declaration
+ */
+
+#if !defined(_WLAN_TDLS_MAIN_H_)
+#define _WLAN_TDLS_MAIN_H_
+
+#include <qdf_trace.h>
+#include <qdf_list.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_peer_obj.h>
+#include <wlan_tdls_public_structs.h>
+#include <scheduler_api.h>
+#include "wlan_serialization_api.h"
+
+/* Bit mask flag for tdls_option to FW */
+#define ENA_TDLS_OFFCHAN      (1 << 0)  /* TDLS Off Channel support */
+#define ENA_TDLS_BUFFER_STA   (1 << 1)  /* TDLS Buffer STA support */
+#define ENA_TDLS_SLEEP_STA    (1 << 2)  /* TDLS Sleep STA support */
+
+#define BW_20_OFFSET_BIT   0
+#define BW_40_OFFSET_BIT   1
+#define BW_80_OFFSET_BIT   2
+#define BW_160_OFFSET_BIT  3
+
+#define TDLS_SEC_OFFCHAN_OFFSET_0        0
+#define TDLS_SEC_OFFCHAN_OFFSET_40PLUS   40
+#define TDLS_SEC_OFFCHAN_OFFSET_40MINUS  (-40)
+#define TDLS_SEC_OFFCHAN_OFFSET_80       80
+#define TDLS_SEC_OFFCHAN_OFFSET_160      160
+/*
+ * Before UpdateTimer expires, we want to timeout discovery response
+ * should not be more than 2000.
+ */
+#define TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE     1000
+#define TDLS_SCAN_REJECT_MAX            5
+
+#define tdls_debug(params...) \
+	QDF_TRACE_DEBUG(QDF_MODULE_ID_TDLS, params)
+#define tdls_notice(params...) \
+	QDF_TRACE_INFO(QDF_MODULE_ID_TDLS, params)
+#define tdls_warn(params...) \
+	QDF_TRACE_WARN(QDF_MODULE_ID_TDLS, params)
+#define tdls_err(params...) \
+	QDF_TRACE_ERROR(QDF_MODULE_ID_TDLS, params)
+#define tdls_alert(params...) \
+	QDF_TRACE_FATAL(QDF_MODULE_ID_TDLS, params)
+
+#define tdls_nofl_debug(params...) \
+	QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_TDLS, params)
+#define tdls_nofl_notice(params...) \
+	QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_TDLS, params)
+#define tdls_nofl_warn(params...) \
+	QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_TDLS, params)
+#define tdls_nofl_err(params...) \
+	QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_TDLS, params)
+#define tdls_nofl_alert(params...) \
+	QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_TDLS, params)
+
+#define TDLS_IS_LINK_CONNECTED(peer)  \
+	((TDLS_LINK_CONNECTED == (peer)->link_status) || \
+	 (TDLS_LINK_TEARING == (peer)->link_status))
+
+#define SET_BIT(value, mask) ((value) |= (1 << (mask)))
+#define CLEAR_BIT(value, mask) ((value) &= ~(1 << (mask)))
+#define CHECK_BIT(value, mask) ((value) & (1 << (mask)))
+/**
+ * struct tdls_conn_info - TDLS connection record
+ * @session_id: session id
+ * @sta_id: sta id
+ * @peer_mac: peer address
+ */
+struct tdls_conn_info {
+	uint8_t session_id;
+	uint8_t sta_id;
+	struct qdf_mac_addr peer_mac;
+};
+
+/**
+ * enum tdls_nss_transition_state - TDLS NSS transition states
+ * @TDLS_NSS_TRANSITION_UNKNOWN: default state
+ * @TDLS_NSS_TRANSITION_2x2_to_1x1: transition from 2x2 to 1x1 stream
+ * @TDLS_NSS_TRANSITION_1x1_to_2x2: transition from 1x1 to 2x2 stream
+ */
+enum tdls_nss_transition_state {
+	TDLS_NSS_TRANSITION_S_UNKNOWN = 0,
+	TDLS_NSS_TRANSITION_S_2x2_to_1x1,
+	TDLS_NSS_TRANSITION_S_1x1_to_2x2,
+};
+
+/**
+ * struct tdls_conn_tracker_mac_table - connection tracker peer table
+ * @mac_address: peer mac address
+ * @tx_packet_cnt: number of tx pkts
+ * @rx_packet_cnt: number of rx pkts
+ * @peer_timestamp_ms: time stamp of latest peer traffic
+ */
+struct tdls_conn_tracker_mac_table {
+	struct qdf_mac_addr mac_address;
+	uint32_t tx_packet_cnt;
+	uint32_t rx_packet_cnt;
+	uint32_t peer_timestamp_ms;
+};
+
+/**
+ * struct tdls_ct_idle_peer_data - connection tracker idle peer info
+ * @vdev: vdev object
+ * @tdls_info: tdls connection info
+ */
+struct tdls_ct_idle_peer_data {
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_conn_info *tdls_info;
+};
+
+/**
+ * struct tdls_set_state_db - to record set tdls state command, we need to
+ * set correct tdls state to firmware:
+ * 1. enable tdls in firmware before tdls connection;
+ * 2. disable tdls if concurrency happen, before disable tdls, all active peer
+ * should be deleted in firmware.
+ *
+ * @set_state_cnt: tdls set state count
+ * @vdev_id: vdev id of last set state command
+ */
+struct tdls_set_state_info {
+	uint8_t set_state_cnt;
+	uint8_t vdev_id;
+};
+
+/**
+ * struct tdls_psoc_priv_ctx - tdls context
+ * @soc: objmgr psoc
+ * @tdls_current_mode: current tdls mode
+ * @tdls_last_mode: last tdls mode
+ * @scan_reject_count: number of times scan rejected due to TDLS
+ * @tdls_source_bitmap: bit map to set/reset TDLS by different sources
+ * @tdls_conn_info: this tdls_conn_info can be removed and we can use peer type
+ *                of peer object to get the active tdls peers
+ * @tdls_configs: tdls user configure
+ * @max_num_tdls_sta: maximum TDLS station number allowed upon runtime condition
+ * @connected_peer_count: tdls peer connected count
+ * @tdls_off_channel: tdls off channel number
+ * @tdls_channel_offset: tdls channel offset
+ * @tdls_fw_off_chan_mode: tdls fw off channel mode
+ * @enable_tdls_connection_tracker: enable tdls connection tracker
+ * @tdls_external_peer_count: external tdls peer count
+ * @tdls_nss_switch_in_progress: tdls antenna switch in progress
+ * @tdls_nss_teardown_complete: tdls tear down complete
+ * @tdls_nss_transition_mode: tdls nss transition mode
+ * @tdls_teardown_peers_cnt: tdls tear down peer count
+ * @set_state_info: set tdls state info
+ * @tdls_event_cb: tdls event callback
+ * @tdls_evt_cb_data: tdls event user data
+ * @tdls_peer_context: userdata for register/deregister TDLS peer
+ * @tdls_reg_peer: register tdls peer with datapath
+ * @tdls_dereg_peer: deregister tdls peer from datapath
+ * @tx_q_ack: queue for tx frames waiting for ack
+ * @tdls_con_cap: tdls concurrency support
+ * @tdls_send_mgmt_req: store eWNI_SME_TDLS_SEND_MGMT_REQ value
+ * @tdls_add_sta_req: store eWNI_SME_TDLS_ADD_STA_REQ value
+ * @tdls_del_sta_req: store eWNI_SME_TDLS_DEL_STA_REQ value
+ * @tdls_update_peer_state: store WMA_UPDATE_TDLS_PEER_STATE value
+ * @tdls_del_all_peers:store eWNI_SME_DEL_ALL_TDLS_PEERS
+ * @tdls_update_dp_vdev_flags store CDP_UPDATE_TDLS_FLAGS
+ * @tdls_idle_peer_data: provide information about idle peer
+ * @tdls_ct_spinlock: connection tracker spin lock
+ */
+struct tdls_soc_priv_obj {
+	struct wlan_objmgr_psoc *soc;
+	enum tdls_feature_mode tdls_current_mode;
+	enum tdls_feature_mode tdls_last_mode;
+	int scan_reject_count;
+	unsigned long tdls_source_bitmap;
+	struct tdls_conn_info tdls_conn_info[WLAN_TDLS_STA_MAX_NUM];
+	struct tdls_user_config tdls_configs;
+	uint16_t max_num_tdls_sta;
+	uint16_t connected_peer_count;
+	uint8_t tdls_off_channel;
+	uint16_t tdls_channel_offset;
+	int32_t tdls_fw_off_chan_mode;
+	bool enable_tdls_connection_tracker;
+	uint8_t tdls_external_peer_count;
+	bool tdls_nss_switch_in_progress;
+	bool tdls_nss_teardown_complete;
+	bool tdls_disable_in_progress;
+	enum tdls_nss_transition_state tdls_nss_transition_mode;
+	int32_t tdls_teardown_peers_cnt;
+	struct tdls_set_state_info set_state_info;
+	tdls_rx_callback tdls_rx_cb;
+	void *tdls_rx_cb_data;
+	tdls_wmm_check tdls_wmm_cb;
+	void *tdls_wmm_cb_data;
+	tdls_evt_callback tdls_event_cb;
+	void *tdls_evt_cb_data;
+	void *tdls_peer_context;
+	tdls_register_peer_callback tdls_reg_peer;
+	tdls_deregister_peer_callback tdls_dereg_peer;
+	tdls_dp_vdev_update_flags_callback tdls_dp_vdev_update;
+	qdf_list_t tx_q_ack;
+	enum tdls_conc_cap tdls_con_cap;
+	uint16_t tdls_send_mgmt_req;
+	uint16_t tdls_add_sta_req;
+	uint16_t tdls_del_sta_req;
+	uint16_t tdls_update_peer_state;
+	uint16_t tdls_del_all_peers;
+	uint32_t tdls_update_dp_vdev_flags;
+	struct tdls_ct_idle_peer_data tdls_idle_peer_data;
+	qdf_spinlock_t tdls_ct_spinlock;
+};
+
+/**
+ * struct tdls_vdev_priv_obj - tdls private vdev object
+ * @vdev: vdev objmgr object
+ * @peer_list: tdls peer list on this vdev
+ * @peer_update_timer: connection tracker timer
+ * @peer_dicovery_timer: peer discovery timer
+ * @threshold_config: threshold config
+ * @discovery_peer_cnt: discovery peer count
+ * @discovery_sent_cnt: discovery sent count
+ * @ap_rssi: ap rssi
+ * @curr_candidate: current candidate
+ * @ct_peer_table: linear mac address table for counting the packets
+ * @valid_mac_entries: number of valid mac entry in @ct_peer_mac_table
+ * @magic: magic
+ * @tx_queue: tx frame queue
+ */
+struct tdls_vdev_priv_obj {
+	struct wlan_objmgr_vdev *vdev;
+	qdf_list_t peer_list[WLAN_TDLS_PEER_LIST_SIZE];
+	qdf_mc_timer_t peer_update_timer;
+	qdf_mc_timer_t peer_discovery_timer;
+	struct tdls_config_params threshold_config;
+	int32_t discovery_peer_cnt;
+	uint32_t discovery_sent_cnt;
+	int8_t ap_rssi;
+	struct tdls_peer *curr_candidate;
+	struct tdls_conn_tracker_mac_table
+			ct_peer_table[WLAN_TDLS_CT_TABLE_SIZE];
+	uint8_t valid_mac_entries;
+	uint32_t magic;
+	uint8_t session_id;
+	qdf_list_t tx_queue;
+};
+
+/**
+ * struct tdls_peer_mlme_info - tdls peer mlme info
+ **/
+struct tdls_peer_mlme_info {
+};
+
+/**
+ * struct tdls_peer - tdls peer data
+ * @node: node
+ * @vdev_priv: tdls vdev priv obj
+ * @peer_mac: peer mac address
+ * @sta_id: station identifier
+ * @rssi: rssi
+ * @tdls_support: tdls support
+ * @link_status: tdls link status
+ * @is_responder: is responder
+ * @discovery_processed: dicovery processed
+ * @discovery_attempt: discovery attempt
+ * @tx_pkt: tx packet
+ * @rx_pkt: rx packet
+ * @uapsd_queues: uapsd queues
+ * @max_sp: max sp
+ * @buf_sta_capable: is buffer sta
+ * @off_channel_capable: is offchannel supported flag
+ * @supported_channels_len: supported channels length
+ * @supported_channels: supported channels
+ * @supported_oper_classes_len: supported operation classes length
+ * @supported_oper_classes: supported operation classes
+ * @is_forced_peer: is forced peer
+ * @op_class_for_pref_off_chan: op class for preferred off channel
+ * @pref_off_chan_num: preferred off channel number
+ * @op_class_for_pref_off_chan_is_set: op class for preferred off channel set
+ * @peer_idle_timer: time to check idle traffic in tdls peers
+ * @is_peer_idle_timer_initialised: Flag to check idle timer init
+ * @spatial_streams: Number of TX/RX spatial streams for TDLS
+ * @reason: reason
+ * @state_change_notification: state change notification
+ * @qos: QOS capability of TDLS link
+ */
+struct tdls_peer {
+	qdf_list_node_t node;
+	struct tdls_vdev_priv_obj *vdev_priv;
+	struct qdf_mac_addr peer_mac;
+	uint16_t sta_id;
+	int8_t rssi;
+	enum tdls_peer_capab tdls_support;
+	enum tdls_link_state link_status;
+	uint8_t is_responder;
+	uint8_t discovery_processed;
+	uint16_t discovery_attempt;
+	uint16_t tx_pkt;
+	uint16_t rx_pkt;
+	uint8_t uapsd_queues;
+	uint8_t max_sp;
+	uint8_t buf_sta_capable;
+	uint8_t off_channel_capable;
+	uint8_t supported_channels_len;
+	uint8_t supported_channels[WLAN_MAC_MAX_SUPP_CHANNELS];
+	uint8_t supported_oper_classes_len;
+	uint8_t supported_oper_classes[WLAN_MAX_SUPP_OPER_CLASSES];
+	bool is_forced_peer;
+	uint8_t op_class_for_pref_off_chan;
+	uint8_t pref_off_chan_num;
+	uint8_t op_class_for_pref_off_chan_is_set;
+	qdf_mc_timer_t peer_idle_timer;
+	bool is_peer_idle_timer_initialised;
+	uint8_t spatial_streams;
+	enum tdls_link_state_reason reason;
+	tdls_state_change_callback state_change_notification;
+	uint8_t qos;
+	struct tdls_peer_mlme_info *tdls_info;
+};
+
+/**
+ * struct tdls_os_if_event - TDLS os event info
+ * @type: type of event
+ * @info: pointer to event information
+ */
+struct tdls_os_if_event {
+	uint32_t type;
+	void *info;
+};
+
+/**
+ * enum tdls_os_if_notification - TDLS notification from OS IF
+ * @TDLS_NOTIFY_STA_SESSION_INCREMENT: sta session count incremented
+ * @TDLS_NOTIFY_STA_SESSION_DECREMENT: sta session count decremented
+ */
+enum tdls_os_if_notification {
+	TDLS_NOTIFY_STA_SESSION_INCREMENT,
+	TDLS_NOTIFY_STA_SESSION_DECREMENT
+};
+/**
+ * wlan_vdev_get_tdls_soc_obj - private API to get tdls soc object from vdev
+ * @vdev: vdev object
+ *
+ * Return: tdls soc object
+ */
+static inline struct tdls_soc_priv_obj *
+wlan_vdev_get_tdls_soc_obj(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct tdls_soc_priv_obj *soc_obj;
+
+	if (!vdev) {
+		tdls_err("NULL vdev");
+		return NULL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		tdls_err("can't get psoc");
+		return NULL;
+	}
+
+	soc_obj = (struct tdls_soc_priv_obj *)
+		wlan_objmgr_psoc_get_comp_private_obj(psoc,
+						      WLAN_UMAC_COMP_TDLS);
+
+	return soc_obj;
+}
+
+/**
+ * wlan_psoc_get_tdls_soc_obj - private API to get tdls soc object from psoc
+ * @psoc: psoc object
+ *
+ * Return: tdls soc object
+ */
+static inline struct tdls_soc_priv_obj *
+wlan_psoc_get_tdls_soc_obj(struct wlan_objmgr_psoc *psoc)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+	if (!psoc) {
+		tdls_err("NULL psoc");
+		return NULL;
+	}
+	soc_obj = (struct tdls_soc_priv_obj *)
+		wlan_objmgr_psoc_get_comp_private_obj(psoc,
+						      WLAN_UMAC_COMP_TDLS);
+
+	return soc_obj;
+}
+
+/**
+ * wlan_vdev_get_tdls_vdev_obj - private API to get tdls vdev object from vdev
+ * @vdev: vdev object
+ *
+ * Return: tdls vdev object
+ */
+static inline struct tdls_vdev_priv_obj *
+wlan_vdev_get_tdls_vdev_obj(struct wlan_objmgr_vdev *vdev)
+{
+	struct tdls_vdev_priv_obj *vdev_obj;
+
+	if (!vdev) {
+		tdls_err("NULL vdev");
+		return NULL;
+	}
+
+	vdev_obj = (struct tdls_vdev_priv_obj *)
+		wlan_objmgr_vdev_get_comp_private_obj(vdev,
+						      WLAN_UMAC_COMP_TDLS);
+
+	return vdev_obj;
+}
+
+/**
+ * tdls_set_link_status - tdls set link status
+ * @vdev: vdev object
+ * @mac: mac address of tdls peer
+ * @link_state: tdls link state
+ * @link_reason: reason
+ */
+void tdls_set_link_status(struct tdls_vdev_priv_obj *vdev,
+			  const uint8_t *mac,
+			  enum tdls_link_state link_state,
+			  enum tdls_link_state_reason link_reason);
+/**
+ * tdls_psoc_obj_create_notification() - tdls psoc create notification handler
+ * @psoc: psoc object
+ * @arg_list: Argument list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc,
+					     void *arg_list);
+
+/**
+ * tdls_psoc_obj_destroy_notification() - tdls psoc destroy notification handler
+ * @psoc: psoc object
+ * @arg_list: Argument list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc,
+					      void *arg_list);
+
+/**
+ * tdls_vdev_obj_create_notification() - tdls vdev create notification handler
+ * @vdev: vdev object
+ * @arg_list: Argument list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev,
+					     void *arg_list);
+
+/**
+ * tdls_vdev_obj_destroy_notification() - tdls vdev destroy notification handler
+ * @vdev: vdev object
+ * @arg_list: Argument list
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev,
+					      void *arg_list);
+
+/**
+ * tdls_process_cmd() - tdls main command process function
+ * @msg: scheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg);
+
+/**
+ * tdls_process_evt() - tdls main event process function
+ * @msg: scheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_process_evt(struct scheduler_msg *msg);
+
+/**
+ * tdls_timer_restart() - restart TDLS timer
+ * @vdev: VDEV object manager
+ * @timer: timer to restart
+ * @expiration_time: new expiration time to set for the timer
+ *
+ * Return: Void
+ */
+void tdls_timer_restart(struct wlan_objmgr_vdev *vdev,
+				 qdf_mc_timer_t *timer,
+				 uint32_t expiration_time);
+
+/**
+ * wlan_hdd_tdls_timers_stop() - stop all the tdls timers running
+ * @tdls_vdev: TDLS vdev
+ *
+ * Return: none
+ */
+void tdls_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev);
+
+/**
+ * tdls_get_vdev_objects() - Get TDLS private objects
+ * @vdev: VDEV object manager
+ * @tdls_vdev_obj: tdls vdev object
+ * @tdls_soc_obj: tdls soc object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_get_vdev_objects(struct wlan_objmgr_vdev *vdev,
+				   struct tdls_vdev_priv_obj **tdls_vdev_obj,
+				   struct tdls_soc_priv_obj **tdls_soc_obj);
+
+/**
+ * cds_set_tdls_ct_mode() - Set the tdls connection tracker mode
+ * @hdd_ctx: hdd context
+ *
+ * This routine is called to set the tdls connection tracker operation status
+ *
+ * Return: NONE
+ */
+void tdls_set_ct_mode(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tdls_set_operation_mode() - set tdls operating mode
+ * @tdls_set_mode: tdls mode set params
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_set_operation_mode(struct tdls_set_mode_params *tdls_set_mode);
+
+/**
+ * tdls_notify_sta_connect() - Update tdls state for every
+ * connect event.
+ * @notify: sta connect params
+ *
+ * After every connect event in the system, check whether TDLS
+ * can be enabled in the system. If TDLS can be enabled, update the
+ * TDLS state as needed.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify);
+
+/**
+ * tdls_notify_sta_disconnect() - Update tdls state for every
+ * disconnect event.
+ * @notify: sta disconnect params
+ *
+ * After every disconnect event in the system, check whether TDLS
+ * can be disabled/enabled in the system and update the
+ * TDLS state as needed.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify);
+
+/**
+ * tdls_notify_reset_adapter() - notify reset adapter
+ * @vdev: vdev object
+ *
+ * Notify TDLS about the adapter reset
+ *
+ * Return: None
+ */
+void tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * tdls_peers_deleted_notification() - peer delete notification
+ * @psoc: soc object
+ * @vdev_id: vdev id
+ *
+ * Legacy lim layer will delete tdls peers for roaming and heart beat failures
+ * and notify the component about the delete event to update the tdls.
+ * state.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
+					   uint8_t vdev_id);
+
+/**
+ * tdls_notify_decrement_session() - Notify the session decrement
+ * @psoc: psoc  object manager
+ *
+ * Policy manager notify TDLS about session decrement
+ *
+ * Return: None
+ */
+void tdls_notify_decrement_session(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tdls_send_update_to_fw - update tdls status info
+ * @tdls_vdev_obj: tdls vdev private object.
+ * @tdls_prohibited: indicates whether tdls is prohibited.
+ * @tdls_chan_swit_prohibited: indicates whether tdls channel switch
+ *                             is prohibited.
+ * @sta_connect_event: indicate sta connect or disconnect event
+ * @session_id: session id
+ *
+ * Normally an AP does not influence TDLS connection between STAs
+ * associated to it. But AP may set bits for TDLS Prohibited or
+ * TDLS Channel Switch Prohibited in Extended Capability IE in
+ * Assoc/Re-assoc response to STA. So after STA is connected to
+ * an AP, call this function to update TDLS status as per those
+ * bits set in Ext Cap IE in received Assoc/Re-assoc response
+ * from AP.
+ *
+ * Return: None.
+ */
+void tdls_send_update_to_fw(struct tdls_vdev_priv_obj *tdls_vdev_obj,
+			    struct tdls_soc_priv_obj *tdls_soc_obj,
+			    bool tdls_prohibited,
+			    bool tdls_chan_swit_prohibited,
+			    bool sta_connect_event,
+			    uint8_t session_id);
+
+/**
+ * tdls_notify_increment_session() - Notify the session increment
+ * @psoc: psoc  object manager
+ *
+ * Policy manager notify TDLS about session increment
+ *
+ * Return: None
+ */
+void tdls_notify_increment_session(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tdls_check_is_tdls_allowed() - check is tdls allowed or not
+ * @vdev: vdev object
+ *
+ * Function determines the whether TDLS allowed in the system
+ *
+ * Return: true or false
+ */
+bool tdls_check_is_tdls_allowed(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * tdls_get_vdev() - Get tdls specific vdev object manager
+ * @psoc: wlan psoc object manager
+ * @dbg_id: debug id
+ *
+ * If TDLS possible, return the corresponding vdev
+ * to enable TDLS in the system.
+ *
+ * Return: vdev manager pointer or NULL.
+ */
+struct wlan_objmgr_vdev *tdls_get_vdev(struct wlan_objmgr_psoc *psoc,
+					  wlan_objmgr_ref_dbgid dbg_id);
+
+/**
+ * tdls_process_policy_mgr_notification() - process policy manager notification
+ * @psoc: soc object manager
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tdls_scan_complete_event_handler() - scan complete event handler for tdls
+ * @vdev: vdev object
+ * @event: scan event
+ * @arg: tdls soc object
+ *
+ * Return: None
+ */
+void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev,
+			struct scan_event *event,
+			void *arg);
+
+/**
+ * tdls_scan_callback() - callback for TDLS scan operation
+ * @soc: tdls soc pvt object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_scan_callback(struct tdls_soc_priv_obj *tdls_soc);
+
+/**
+ * wlan_hdd_tdls_scan_done_callback() - callback for tdls scan done event
+ * @tdls_soc: tdls soc object
+ *
+ * Return: Void
+ */
+void tdls_scan_done_callback(struct tdls_soc_priv_obj *tdls_soc);
+
+/**
+ * tdls_scan_serialization_comp_info_cb() - callback for scan start
+ * @vdev: VDEV on which the scan command is being processed
+ * @comp_info: serialize rules info
+ *
+ * Return: negative = caller should stop and return error code immediately
+ *         1 = caller can continue to scan
+ */
+void tdls_scan_serialization_comp_info_cb(struct wlan_objmgr_vdev *vdev,
+		union wlan_serialization_rules_info *comp_info);
+
+/**
+ * tdls_set_offchan_mode() - update tdls status info
+ * @psoc: soc object
+ * @param: channel switch params
+ *
+ * send message to WMI to set TDLS off channel in f/w
+ *
+ * Return: QDF_STATUS.
+ */
+QDF_STATUS tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc,
+				     struct tdls_channel_switch_params *param);
+
+/**
+ * tdls_delete_all_peers_indication() - update tdls status info
+ * @psoc: soc object
+ * @vdev_id: vdev id
+ *
+ * Notify tdls component to cleanup all peers
+ *
+ * Return: QDF_STATUS.
+ */
+
+QDF_STATUS tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc,
+					    uint8_t vdev_id);
+#endif

+ 449 - 0
components/tdls/core/src/wlan_tdls_mgmt.c

@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_mgmt.c
+ *
+ * TDLS management frames implementation
+ */
+
+#include "wlan_tdls_main.h"
+#include "wlan_tdls_tgt_api.h"
+#include <wlan_serialization_api.h>
+#include "wlan_mgmt_txrx_utils_api.h"
+#include "wlan_tdls_peer.h"
+#include "wlan_tdls_ct.h"
+#include "wlan_tdls_cmds_process.h"
+#include "wlan_tdls_mgmt.h"
+
+static
+const char *const tdls_action_frames_type[] = { "TDLS Setup Request",
+					 "TDLS Setup Response",
+					 "TDLS Setup Confirm",
+					 "TDLS Teardown",
+					 "TDLS Peer Traffic Indication",
+					 "TDLS Channel Switch Request",
+					 "TDLS Channel Switch Response",
+					 "TDLS Peer PSM Request",
+					 "TDLS Peer PSM Response",
+					 "TDLS Peer Traffic Response",
+					 "TDLS Discovery Request"};
+
+/**
+ * tdls_set_rssi() - Set TDLS RSSI on peer given by mac
+ * @tdls_vdev: tdls vdev object
+ * @mac: MAC address of Peer
+ * @rx_rssi: rssi value
+ *
+ * Set RSSI on TDSL peer
+ *
+ * Return: 0 for success or -EINVAL otherwise
+ */
+static int tdls_set_rssi(struct tdls_vdev_priv_obj *tdls_vdev,
+		  const uint8_t *mac,
+		  int8_t rx_rssi)
+{
+	struct tdls_peer *curr_peer;
+
+	curr_peer = tdls_find_peer(tdls_vdev, mac);
+	if (curr_peer == NULL) {
+		tdls_err("curr_peer is NULL");
+		return -EINVAL;
+	}
+
+	curr_peer->rssi = rx_rssi;
+
+	return 0;
+}
+
+/**
+ * tdls_process_rx_mgmt() - process tdls rx mgmt frames
+ * @rx_mgmt_event: tdls rx mgmt event
+ * @tdls_vdev: tdls vdev object
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS tdls_process_rx_mgmt(
+	struct tdls_rx_mgmt_event *rx_mgmt_event,
+	struct tdls_vdev_priv_obj *tdls_vdev)
+{
+	struct tdls_rx_mgmt_frame *rx_mgmt;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	uint8_t *mac;
+	enum tdls_actioncode action_frame_type;
+
+	if (!rx_mgmt_event)
+		return QDF_STATUS_E_INVAL;
+
+	tdls_soc_obj = rx_mgmt_event->tdls_soc_obj;
+	rx_mgmt = rx_mgmt_event->rx_mgmt;
+
+	if (!tdls_soc_obj || !rx_mgmt) {
+		tdls_err("invalid psoc object or rx mgmt");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	tdls_debug("soc:%pK, frame_len:%d, rx_chan:%d, vdev_id:%d, frm_type:%d, rx_rssi:%d, buf:%pK",
+		tdls_soc_obj->soc, rx_mgmt->frame_len,
+		rx_mgmt->rx_chan, rx_mgmt->vdev_id, rx_mgmt->frm_type,
+		rx_mgmt->rx_rssi, rx_mgmt->buf);
+
+	if (rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET + 1] ==
+						TDLS_PUBLIC_ACTION_DISC_RESP) {
+		mac = &rx_mgmt->buf[TDLS_80211_PEER_ADDR_OFFSET];
+		tdls_notice("[TDLS] TDLS Discovery Response,"
+		       QDF_MAC_ADDR_STR " RSSI[%d] <--- OTA",
+		       QDF_MAC_ADDR_ARRAY(mac), rx_mgmt->rx_rssi);
+			tdls_recv_discovery_resp(tdls_vdev, mac);
+			tdls_set_rssi(tdls_vdev, mac, rx_mgmt->rx_rssi);
+	}
+
+	if (rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET] ==
+	    TDLS_ACTION_FRAME) {
+		action_frame_type =
+			rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET + 1];
+		if (action_frame_type >= TDLS_ACTION_FRAME_TYPE_MAX) {
+			tdls_debug("[TDLS] unknown[%d] <--- OTA",
+				   action_frame_type);
+		} else {
+			tdls_notice("[TDLS] %s <--- OTA",
+				   tdls_action_frames_type[action_frame_type]);
+		}
+	}
+
+	/* tdls_soc_obj->tdls_rx_cb ==> wlan_cfg80211_tdls_rx_callback() */
+	if (tdls_soc_obj && tdls_soc_obj->tdls_rx_cb)
+		tdls_soc_obj->tdls_rx_cb(tdls_soc_obj->tdls_rx_cb_data,
+					 rx_mgmt);
+	else
+		tdls_debug("rx mgmt, but no valid up layer callback");
+
+	qdf_mem_free(rx_mgmt);
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_process_rx_frame(struct scheduler_msg *msg)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_rx_mgmt_event *tdls_rx;
+	struct tdls_vdev_priv_obj *tdls_vdev;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	if (!(msg->bodyptr)) {
+		tdls_err("invalid message body");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	tdls_rx = (struct tdls_rx_mgmt_event *) msg->bodyptr;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(tdls_rx->tdls_soc_obj->soc,
+				tdls_rx->rx_mgmt->vdev_id, WLAN_TDLS_NB_ID);
+
+	if (vdev) {
+		tdls_debug("tdls rx mgmt frame received");
+		tdls_vdev = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+							WLAN_UMAC_COMP_TDLS);
+		if (tdls_vdev)
+			status = tdls_process_rx_mgmt(tdls_rx, tdls_vdev);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+	}
+
+	qdf_mem_free(msg->bodyptr);
+	msg->bodyptr = NULL;
+
+	return status;
+}
+
+QDF_STATUS tdls_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc,
+	bool isregister)
+{
+	struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info;
+	QDF_STATUS status;
+	int num_of_entries;
+
+	tdls_debug("psoc:%pK, is register rx:%d", psoc, isregister);
+
+	frm_cb_info.frm_type = MGMT_ACTION_TDLS_DISCRESP;
+	frm_cb_info.mgmt_rx_cb = tgt_tdls_mgmt_frame_rx_cb;
+	num_of_entries = 1;
+
+	if (isregister)
+		status = wlan_mgmt_txrx_register_rx_cb(psoc,
+				WLAN_UMAC_COMP_TDLS, &frm_cb_info,
+				num_of_entries);
+	else
+		status = wlan_mgmt_txrx_deregister_rx_cb(psoc,
+				WLAN_UMAC_COMP_TDLS, &frm_cb_info,
+				num_of_entries);
+
+	return status;
+}
+
+static QDF_STATUS
+tdls_internal_send_mgmt_tx_done(struct tdls_action_frame_request *req,
+				QDF_STATUS status)
+{
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	struct tdls_osif_indication indication;
+
+	if (!req || !req->vdev)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	indication.status = status;
+	indication.vdev = req->vdev;
+	tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev);
+	if (tdls_soc_obj && tdls_soc_obj->tdls_event_cb)
+		tdls_soc_obj->tdls_event_cb(tdls_soc_obj->tdls_evt_cb_data,
+			TDLS_EVENT_MGMT_TX_ACK_CNF, &indication);
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS tdls_activate_send_mgmt_request_flush_cb(
+	struct scheduler_msg *msg)
+{
+	struct tdls_send_mgmt_request *tdls_mgmt_req;
+
+	tdls_mgmt_req = msg->bodyptr;
+
+	qdf_mem_free(tdls_mgmt_req);
+	msg->bodyptr = NULL;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS tdls_activate_send_mgmt_request(
+				struct tdls_action_frame_request *action_req)
+{
+	struct wlan_objmgr_peer *peer;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct scheduler_msg msg = {0};
+	struct tdls_send_mgmt_request *tdls_mgmt_req;
+
+	if (!action_req || !action_req->vdev)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(action_req->vdev);
+	if (!tdls_soc_obj) {
+		status = QDF_STATUS_E_NULL_VALUE;
+		goto release_cmd;
+	}
+
+	tdls_mgmt_req = qdf_mem_malloc(sizeof(struct tdls_send_mgmt_request) +
+				action_req->tdls_mgmt.len);
+	if (NULL == tdls_mgmt_req) {
+		status = QDF_STATUS_E_NOMEM;
+		tdls_err("mem alloc failed ");
+		QDF_ASSERT(0);
+		goto release_cmd;
+	}
+
+	tdls_debug("session_id %d "
+		   "tdls_mgmt.dialog %d "
+		   "tdls_mgmt.frame_type %d "
+		   "tdls_mgmt.status_code %d "
+		   "tdls_mgmt.responder %d "
+		   "tdls_mgmt.peer_capability %d",
+		   action_req->session_id,
+		   action_req->tdls_mgmt.dialog,
+		   action_req->tdls_mgmt.frame_type,
+		   action_req->tdls_mgmt.status_code,
+		   action_req->tdls_mgmt.responder,
+		   action_req->tdls_mgmt.peer_capability);
+
+	tdls_mgmt_req->session_id = action_req->session_id;
+	/* Using dialog as transactionId. This can be used to
+	 * match response with request
+	 */
+	tdls_mgmt_req->transaction_id = action_req->tdls_mgmt.dialog;
+	tdls_mgmt_req->req_type = action_req->tdls_mgmt.frame_type;
+	tdls_mgmt_req->dialog = action_req->tdls_mgmt.dialog;
+	tdls_mgmt_req->status_code = action_req->tdls_mgmt.status_code;
+	tdls_mgmt_req->responder = action_req->tdls_mgmt.responder;
+	tdls_mgmt_req->peer_capability = action_req->tdls_mgmt.peer_capability;
+
+	peer = wlan_vdev_get_bsspeer(action_req->vdev);
+
+	status =  wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_SB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(tdls_mgmt_req);
+		goto release_cmd;
+	}
+
+	qdf_mem_copy(tdls_mgmt_req->bssid.bytes,
+		     wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE);
+
+	qdf_mem_copy(tdls_mgmt_req->peer_mac.bytes,
+		     action_req->tdls_mgmt.peer_mac.bytes, QDF_MAC_ADDR_SIZE);
+
+	if (action_req->tdls_mgmt.len) {
+		qdf_mem_copy(tdls_mgmt_req->add_ie, action_req->tdls_mgmt.buf,
+			     action_req->tdls_mgmt.len);
+	}
+
+	tdls_mgmt_req->length = sizeof(struct tdls_send_mgmt_request) +
+				action_req->tdls_mgmt.len;
+	if (action_req->use_default_ac)
+		tdls_mgmt_req->ac = WIFI_AC_VI;
+	else
+		tdls_mgmt_req->ac = WIFI_AC_BK;
+
+	/* Send the request to PE. */
+	qdf_mem_zero(&msg, sizeof(msg));
+
+	tdls_debug("sending TDLS Mgmt Frame req to PE ");
+	tdls_mgmt_req->message_type = tdls_soc_obj->tdls_send_mgmt_req;
+
+	msg.type = tdls_soc_obj->tdls_send_mgmt_req;
+	msg.bodyptr = tdls_mgmt_req;
+	msg.flush_callback = tdls_activate_send_mgmt_request_flush_cb;
+
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_PE, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("failed to post msg, status %d", status);
+		qdf_mem_free(tdls_mgmt_req);
+	}
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID);
+
+release_cmd:
+	/*update tdls nss infornation based on action code */
+	tdls_reset_nss(tdls_soc_obj, action_req->chk_frame->action_code);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_internal_send_mgmt_tx_done(action_req, status);
+		tdls_release_serialization_command(action_req->vdev,
+						   WLAN_SER_CMD_TDLS_SEND_MGMT);
+	}
+
+	return status;
+}
+
+static QDF_STATUS
+tdls_send_mgmt_serialize_callback(struct wlan_serialization_command *cmd,
+	 enum wlan_serialization_cb_reason reason)
+{
+	struct tdls_action_frame_request *req;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!cmd || !cmd->umac_cmd) {
+		tdls_err("invalid params cmd: %pK, ", cmd);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	req = cmd->umac_cmd;
+
+	tdls_debug("reason: %d, vdev_id: %d",
+		reason, req->vdev_id);
+
+	switch (reason) {
+	case WLAN_SER_CB_ACTIVATE_CMD:
+		/* command moved to active list */
+		status = tdls_activate_send_mgmt_request(req);
+		break;
+
+	case WLAN_SER_CB_CANCEL_CMD:
+	case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT:
+		/* command removed from pending list.
+		 * notify status complete with failure
+		 */
+		status = tdls_internal_send_mgmt_tx_done(req,
+				QDF_STATUS_E_FAILURE);
+		break;
+
+	case WLAN_SER_CB_RELEASE_MEM_CMD:
+		/* command successfully completed.
+		 * release tdls_action_frame_request memory
+		 */
+		wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(req);
+		break;
+
+	default:
+		/* Do nothing but logging */
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		break;
+	}
+
+	return status;
+}
+
+QDF_STATUS tdls_process_mgmt_req(
+			struct tdls_action_frame_request *tdls_mgmt_req)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_serialization_command cmd = {0, };
+	enum wlan_serialization_status ser_cmd_status;
+
+	/* If connected and in Infra. Only then allow this */
+	status = tdls_validate_mgmt_request(tdls_mgmt_req);
+	if (status != QDF_STATUS_SUCCESS) {
+		status = tdls_internal_send_mgmt_tx_done(tdls_mgmt_req,
+							 status);
+		goto error_mgmt;
+	}
+
+	/* update the responder, status code information
+	 * after the  cmd validation
+	 */
+	tdls_mgmt_req->tdls_mgmt.responder =
+			!tdls_mgmt_req->chk_frame->responder;
+	tdls_mgmt_req->tdls_mgmt.status_code =
+			tdls_mgmt_req->chk_frame->status_code;
+
+	cmd.cmd_type = WLAN_SER_CMD_TDLS_SEND_MGMT;
+	/* Cmd Id not applicable for non scan cmds */
+	cmd.cmd_id = 0;
+	cmd.cmd_cb = (wlan_serialization_cmd_callback)
+		tdls_send_mgmt_serialize_callback;
+	cmd.umac_cmd = tdls_mgmt_req;
+	cmd.source = WLAN_UMAC_COMP_TDLS;
+	cmd.is_high_priority = false;
+	cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT;
+
+	cmd.vdev = tdls_mgmt_req->vdev;
+	cmd.is_blocking = true;
+
+	ser_cmd_status = wlan_serialization_request(&cmd);
+	tdls_debug("wlan_serialization_request status:%d", ser_cmd_status);
+
+	switch (ser_cmd_status) {
+	case WLAN_SER_CMD_PENDING:
+		/* command moved to pending list.Do nothing */
+		break;
+	case WLAN_SER_CMD_ACTIVE:
+		/* command moved to active list. Do nothing */
+		break;
+	case WLAN_SER_CMD_DENIED_LIST_FULL:
+	case WLAN_SER_CMD_DENIED_RULES_FAILED:
+	case WLAN_SER_CMD_DENIED_UNSPECIFIED:
+		status = QDF_STATUS_E_FAILURE;
+		goto error_mgmt;
+	default:
+		QDF_ASSERT(0);
+		status = QDF_STATUS_E_INVAL;
+		goto error_mgmt;
+	}
+	return status;
+
+error_mgmt:
+	wlan_objmgr_vdev_release_ref(tdls_mgmt_req->vdev, WLAN_TDLS_NB_ID);
+	qdf_mem_free(tdls_mgmt_req);
+	return status;
+}

+ 111 - 0
components/tdls/core/src/wlan_tdls_mgmt.h

@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_mgmt.h
+ *
+ * TDLS management frames include file
+ */
+
+#ifndef _WLAN_TDLS_MGMT_H_
+#define _WLAN_TDLS_MGMT_H_
+
+#define TDLS_PUBLIC_ACTION_FRAME_OFFSET 24
+#define TDLS_PUBLIC_ACTION_FRAME 4
+#define TDLS_PUBLIC_ACTION_DISC_RESP 14
+#define TDLS_ACTION_FRAME 12
+#define TDLS_80211_PEER_ADDR_OFFSET (TDLS_PUBLIC_ACTION_FRAME + \
+				     QDF_MAC_ADDR_SIZE)
+#define TDLS_ACTION_FRAME_TYPE_MAX 11
+
+/**
+ * struct tdls_rx_mgmt_event - tdls rx mgmt frame event
+ * @tdls_soc_obj: tdls soc private object
+ * @rx_mgmt: tdls rx mgmt frame structure
+ */
+struct tdls_rx_mgmt_event {
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	struct tdls_rx_mgmt_frame *rx_mgmt;
+};
+
+/*
+ * struct tdls_send_mgmt_request - tdls management request
+ * @message_type: type of pe message
+ * @length: length of the frame.
+ * @session_id: session id
+ * @transaction_id: transaction ID for cmd
+ * @req_type: type of action frame
+ * @dialog: dialog token used in the frame.
+ * @status_code: status to be incuded in the frame.
+ * @responder: tdls request type
+ * @peer_capability: peer capability information
+ * @bssid: bssid
+ * @peer_mac: mac address of the peer
+ * @add_ie: additional ie's to be included
+ */
+struct tdls_send_mgmt_request {
+	uint16_t message_type;
+	uint16_t length;
+	uint8_t session_id;
+	uint16_t transaction_id;
+	uint8_t req_type;
+	uint8_t dialog;
+	uint16_t status_code;
+	uint8_t responder;
+	uint32_t peer_capability;
+	struct qdf_mac_addr bssid;
+	struct qdf_mac_addr peer_mac;
+	enum wifi_traffic_ac ac;
+	/* Variable length. Dont add any field after this. */
+	uint8_t add_ie[1];
+};
+
+/**
+ * tdls_process_mgmt_req() - send a TDLS mgmt request to serialize module
+ * @tdls_mgmt_req: tdls management request
+ *
+ * TDLS request API, called from cfg80211 to send a TDLS frame in
+ * serialized manner to PE
+ *
+ *Return: QDF_STATUS
+ */
+QDF_STATUS tdls_process_mgmt_req(
+			struct tdls_action_frame_request *tdls_mgmt_req);
+
+/**
+ * tdls_mgmt_rx_ops() - register or unregister rx callback
+ * @psoc: psoc object
+ * @isregister: register if true, unregister if false
+ *
+ * This function registers or unregisters rx callback to mgmt txrx
+ * component.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc,
+	bool isregister);
+
+/**
+ * tdls_process_rx_frame() - process tdls rx frames
+ * @msg: scheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tdls_process_rx_frame(struct scheduler_msg *msg);
+#endif
+

+ 819 - 0
components/tdls/core/src/wlan_tdls_peer.c

@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_peer.c
+ *
+ * TDLS peer basic operations
+ */
+#include "wlan_tdls_main.h"
+#include "wlan_tdls_peer.h"
+#include <wlan_reg_services_api.h>
+#include <wlan_utility.h>
+#include <wlan_policy_mgr_api.h>
+
+static uint8_t calculate_hash_key(const uint8_t *macaddr)
+{
+	uint8_t i, key;
+
+	for (i = 0, key = 0; i < 6; i++)
+		key ^= macaddr[i];
+
+	return key % WLAN_TDLS_PEER_LIST_SIZE;
+}
+
+struct tdls_peer *tdls_find_peer(struct tdls_vdev_priv_obj *vdev_obj,
+				 const uint8_t *macaddr)
+{
+	uint8_t key;
+	QDF_STATUS status;
+	struct tdls_peer *peer;
+	qdf_list_t *head;
+	qdf_list_node_t *p_node;
+
+	key = calculate_hash_key(macaddr);
+	head = &vdev_obj->peer_list[key];
+
+	status = qdf_list_peek_front(head, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		peer = qdf_container_of(p_node, struct tdls_peer, node);
+		if (WLAN_ADDR_EQ(&peer->peer_mac, macaddr)
+		    == QDF_STATUS_SUCCESS) {
+			return peer;
+		}
+		status = qdf_list_peek_next(head, p_node, &p_node);
+	}
+
+	tdls_debug("no tdls peer " QDF_MAC_ADDR_STR,
+		   QDF_MAC_ADDR_ARRAY(macaddr));
+	return NULL;
+}
+
+/**
+ * tdls_find_peer_handler() - helper function for tdls_find_all_peer
+ * @psoc: soc object
+ * @obj: vdev object
+ * @arg: used to keep search peer parameters
+ *
+ * Return: None.
+ */
+static void
+tdls_find_peer_handler(struct wlan_objmgr_psoc *psoc, void *obj, void *arg)
+{
+	struct wlan_objmgr_vdev *vdev = obj;
+	struct tdls_search_peer_param *tdls_param = arg;
+	struct tdls_vdev_priv_obj *vdev_obj;
+
+	if (tdls_param->peer)
+		return;
+
+	if (!vdev) {
+		tdls_err("invalid vdev");
+		return;
+	}
+
+	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE &&
+	    wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE)
+		return;
+
+	vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+							 WLAN_UMAC_COMP_TDLS);
+	if (!vdev_obj)
+		return;
+
+	tdls_param->peer = tdls_find_peer(vdev_obj, tdls_param->macaddr);
+}
+
+struct tdls_peer *
+tdls_find_all_peer(struct tdls_soc_priv_obj *soc_obj, const uint8_t *macaddr)
+{
+	struct tdls_search_peer_param tdls_search_param;
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!soc_obj) {
+		tdls_err("tdls soc object is NULL");
+		return NULL;
+	}
+
+	psoc = soc_obj->soc;
+	if (!psoc) {
+		tdls_err("psoc is NULL");
+		return NULL;
+	}
+	tdls_search_param.macaddr = macaddr;
+	tdls_search_param.peer = NULL;
+
+	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
+				     tdls_find_peer_handler,
+				     &tdls_search_param, 0, WLAN_TDLS_NB_ID);
+
+	return tdls_search_param.peer;
+}
+
+uint8_t tdls_find_opclass(struct wlan_objmgr_psoc *psoc, uint8_t channel,
+				 uint8_t bw_offset)
+{
+	char country[REG_ALPHA2_LEN + 1];
+	QDF_STATUS status;
+
+	if (!psoc) {
+		tdls_err("psoc is NULL");
+		return 0;
+	}
+
+	status = wlan_reg_read_default_country(psoc, country);
+	if (QDF_IS_STATUS_ERROR(status))
+		return 0;
+
+	return wlan_reg_dmn_get_opclass_from_channel(country, channel,
+						     bw_offset);
+}
+
+/**
+ * tdls_add_peer() - add TDLS peer in TDLS vdev object
+ * @vdev_obj: TDLS vdev object
+ * @macaddr: MAC address of peer
+ *
+ * Allocate memory for the new peer, and add it to hash table.
+ *
+ * Return: new added TDLS peer, NULL if failed.
+ */
+static struct tdls_peer *tdls_add_peer(struct tdls_vdev_priv_obj *vdev_obj,
+				       const uint8_t *macaddr)
+{
+	struct tdls_peer *peer;
+	struct tdls_soc_priv_obj *soc_obj;
+	uint8_t key = 0;
+	qdf_list_t *head;
+
+	peer = qdf_mem_malloc(sizeof(*peer));
+	if (!peer) {
+		tdls_err("add tdls peer malloc memory failed!");
+		return NULL;
+	}
+
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
+	if (!soc_obj) {
+		tdls_err("NULL tdls soc object");
+		return NULL;
+	}
+
+	key = calculate_hash_key(macaddr);
+	head = &vdev_obj->peer_list[key];
+
+	qdf_mem_copy(&peer->peer_mac, macaddr, sizeof(peer->peer_mac));
+	peer->vdev_priv = vdev_obj;
+
+	peer->pref_off_chan_num =
+		soc_obj->tdls_configs.tdls_pre_off_chan_num;
+	peer->op_class_for_pref_off_chan =
+		tdls_find_opclass(soc_obj->soc,
+				  peer->pref_off_chan_num,
+				  soc_obj->tdls_configs.tdls_pre_off_chan_bw);
+	peer->sta_id = INVALID_TDLS_PEER_ID;
+
+	qdf_list_insert_back(head, &peer->node);
+
+	tdls_debug("add tdls peer: " QDF_MAC_ADDR_STR,
+		   QDF_MAC_ADDR_ARRAY(macaddr));
+	return peer;
+}
+
+struct tdls_peer *tdls_get_peer(struct tdls_vdev_priv_obj *vdev_obj,
+				const uint8_t *macaddr)
+{
+	struct tdls_peer *peer;
+
+	peer = tdls_find_peer(vdev_obj, macaddr);
+	if (!peer)
+		peer = tdls_add_peer(vdev_obj, macaddr);
+
+	return peer;
+}
+
+static struct tdls_peer *
+tdls_find_progress_peer_in_list(qdf_list_t *head,
+				const uint8_t *macaddr, uint8_t skip_self)
+{
+	QDF_STATUS status;
+	struct tdls_peer *peer;
+	qdf_list_node_t *p_node;
+
+	status = qdf_list_peek_front(head, &p_node);
+	while (QDF_IS_STATUS_SUCCESS(status)) {
+		peer = qdf_container_of(p_node, struct tdls_peer, node);
+		if (skip_self && macaddr &&
+		    WLAN_ADDR_EQ(&peer->peer_mac, macaddr)
+		    == QDF_STATUS_SUCCESS) {
+			status = qdf_list_peek_next(head, p_node, &p_node);
+			continue;
+		} else if (TDLS_LINK_CONNECTING == peer->link_status) {
+			tdls_debug(QDF_MAC_ADDR_STR " TDLS_LINK_CONNECTING",
+				   QDF_MAC_ADDR_ARRAY(peer->peer_mac.bytes));
+			return peer;
+		}
+		status = qdf_list_peek_next(head, p_node, &p_node);
+	}
+
+	return NULL;
+}
+
+/**
+ * tdls_find_progress_peer() - find the peer with ongoing TDLS progress
+ *                             on present vdev
+ * @vdev_obj: TDLS vdev object
+ * @macaddr: MAC address of peer, if NULL check for all the peer list
+ * @skip_self: If true, skip this macaddr. Otherwise, check all the peer list.
+ *             if macaddr is NULL, this argument is ignored, and check for all
+ *             the peer list.
+ *
+ * Return: Pointer to tdls_peer if TDLS is ongoing. Otherwise return NULL.
+ */
+static struct tdls_peer *
+tdls_find_progress_peer(struct tdls_vdev_priv_obj *vdev_obj,
+			const uint8_t *macaddr, uint8_t skip_self)
+{
+	uint8_t i;
+	struct tdls_peer *peer;
+	qdf_list_t *head;
+
+	if (!vdev_obj) {
+		tdls_err("invalid tdls vdev object");
+		return NULL;
+	}
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &vdev_obj->peer_list[i];
+
+		peer = tdls_find_progress_peer_in_list(head, macaddr,
+						       skip_self);
+		if (peer)
+			return peer;
+	}
+
+	return NULL;
+}
+
+/**
+ * tdls_find_progress_peer_handler() - helper function for tdls_is_progress
+ * @psoc: soc object
+ * @obj: vdev object
+ * @arg: used to keep search peer parameters
+ *
+ * Return: None.
+ */
+static void
+tdls_find_progress_peer_handler(struct wlan_objmgr_psoc *psoc,
+				void *obj, void *arg)
+{
+	struct wlan_objmgr_vdev *vdev = obj;
+	struct tdls_search_progress_param *tdls_progress = arg;
+	struct tdls_vdev_priv_obj *vdev_obj;
+
+	if (tdls_progress->peer)
+		return;
+
+	if (!vdev) {
+		tdls_err("invalid vdev");
+		return;
+	}
+
+	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE &&
+	    wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE)
+		return;
+
+	vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev,
+							 WLAN_UMAC_COMP_TDLS);
+
+	tdls_progress->peer = tdls_find_progress_peer(vdev_obj,
+						      tdls_progress->macaddr,
+						      tdls_progress->skip_self);
+}
+
+struct tdls_peer *tdls_is_progress(struct tdls_vdev_priv_obj *vdev_obj,
+				   const uint8_t *macaddr, uint8_t skip_self)
+{
+	struct tdls_search_progress_param tdls_progress;
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!vdev_obj) {
+		tdls_err("invalid tdls vdev object");
+		return NULL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev_obj->vdev);
+	if (!psoc) {
+		tdls_err("invalid psoc");
+		return NULL;
+	}
+	tdls_progress.macaddr = macaddr;
+	tdls_progress.skip_self = skip_self;
+	tdls_progress.peer = NULL;
+
+	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
+				     tdls_find_progress_peer_handler,
+				     &tdls_progress, 0, WLAN_TDLS_NB_ID);
+
+	return tdls_progress.peer;
+}
+
+struct tdls_peer *
+tdls_find_first_connected_peer(struct tdls_vdev_priv_obj *vdev_obj)
+{
+	uint16_t i;
+	struct tdls_peer *peer;
+	qdf_list_t *head;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	if (!vdev_obj) {
+		tdls_err("invalid tdls vdev object");
+		return NULL;
+	}
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &vdev_obj->peer_list[i];
+
+		status = qdf_list_peek_front(head, &p_node);
+		while (QDF_IS_STATUS_SUCCESS(status)) {
+			peer = qdf_container_of(p_node, struct tdls_peer, node);
+
+			if (peer && TDLS_LINK_CONNECTED == peer->link_status) {
+				tdls_debug(QDF_MAC_ADDR_STR
+					   " TDLS_LINK_CONNECTED",
+					   QDF_MAC_ADDR_ARRAY(
+						   peer->peer_mac.bytes));
+				return peer;
+			}
+			status = qdf_list_peek_next(head, p_node, &p_node);
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * tdls_determine_channel_opclass() - determine channel and opclass
+ * @soc_obj: TDLS soc object
+ * @vdev_obj: TDLS vdev object
+ * @peer: TDLS peer
+ * @channel: pointer to channel
+ * @opclass: pinter to opclass
+ *
+ * Function determines the channel and operating class
+ *
+ * Return: None.
+ */
+static void tdls_determine_channel_opclass(struct tdls_soc_priv_obj *soc_obj,
+					   struct tdls_vdev_priv_obj *vdev_obj,
+					   struct tdls_peer *peer,
+					   uint32_t *channel, uint32_t *opclass)
+{
+	uint32_t vdev_id;
+	enum QDF_OPMODE opmode;
+	/*
+	 * If tdls offchannel is not enabled then we provide base channel
+	 * and in that case pass opclass as 0 since opclass is mainly needed
+	 * for offchannel cases.
+	 */
+	if (!(TDLS_IS_OFF_CHANNEL_ENABLED(
+		      soc_obj->tdls_configs.tdls_feature_flags)) ||
+	      soc_obj->tdls_fw_off_chan_mode != ENABLE_CHANSWITCH) {
+		vdev_id = wlan_vdev_get_id(vdev_obj->vdev);
+		opmode = wlan_vdev_mlme_get_opmode(vdev_obj->vdev);
+
+		*channel = policy_mgr_get_channel(soc_obj->soc,
+			policy_mgr_convert_device_mode_to_qdf_type(opmode),
+			&vdev_id);
+		*opclass = 0;
+	} else {
+		*channel = peer->pref_off_chan_num;
+		*opclass = peer->op_class_for_pref_off_chan;
+	}
+	tdls_debug("channel:%d opclass:%d", *channel, *opclass);
+}
+
+/**
+ * tdls_get_wifi_hal_state() - get TDLS wifi hal state on current peer
+ * @peer: TDLS peer
+ * @state: output parameter to store the TDLS wifi hal state
+ * @reason: output parameter to store the reason of the current peer
+ *
+ * Return: None.
+ */
+static void tdls_get_wifi_hal_state(struct tdls_peer *peer, uint32_t *state,
+				    int32_t *reason)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_soc_priv_obj *soc_obj;
+
+	vdev = peer->vdev_priv->vdev;
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev);
+	if (!soc_obj) {
+		tdls_err("can't get tdls object");
+		return;
+	}
+
+	*reason = peer->reason;
+
+	switch (peer->link_status) {
+	case TDLS_LINK_IDLE:
+	case TDLS_LINK_DISCOVERED:
+	case TDLS_LINK_DISCOVERING:
+	case TDLS_LINK_CONNECTING:
+		*state = QCA_WIFI_HAL_TDLS_S_ENABLED;
+		break;
+	case TDLS_LINK_CONNECTED:
+		if ((TDLS_IS_OFF_CHANNEL_ENABLED(
+			     soc_obj->tdls_configs.tdls_feature_flags)) &&
+		     (soc_obj->tdls_fw_off_chan_mode == ENABLE_CHANSWITCH))
+			*state = QCA_WIFI_HAL_TDLS_S_ESTABLISHED_OFF_CHANNEL;
+		else
+			*state = QCA_WIFI_HAL_TDLS_S_ENABLED;
+		break;
+	case TDLS_LINK_TEARING:
+		*state = QCA_WIFI_HAL_TDLS_S_DROPPED;
+		break;
+	}
+}
+
+/**
+ * tdls_extract_peer_state_param() - extract peer update params from TDLS peer
+ * @peer_param: output peer update params
+ * @peer: TDLS peer
+ *
+ * This is used when enable TDLS link
+ *
+ * Return: None.
+ */
+void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param,
+				   struct tdls_peer *peer)
+{
+	uint16_t i, num;
+	struct tdls_vdev_priv_obj *vdev_obj;
+	struct tdls_soc_priv_obj *soc_obj;
+	enum channel_state ch_state;
+	struct wlan_objmgr_pdev *pdev;
+	uint8_t chan_id;
+
+	vdev_obj = peer->vdev_priv;
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
+	pdev = wlan_vdev_get_pdev(vdev_obj->vdev);
+	if (!soc_obj || !pdev) {
+		tdls_err("soc_obj: %pK, pdev: %pK", soc_obj, pdev);
+		return;
+	}
+
+	qdf_mem_zero(peer_param, sizeof(*peer_param));
+	peer_param->vdev_id = wlan_vdev_get_id(vdev_obj->vdev);
+
+	qdf_mem_copy(peer_param->peer_macaddr,
+		     peer->peer_mac.bytes, QDF_MAC_ADDR_SIZE);
+	peer_param->peer_state = TDLS_PEER_STATE_CONNCTED;
+	peer_param->peer_cap.is_peer_responder = peer->is_responder;
+	peer_param->peer_cap.peer_uapsd_queue = peer->uapsd_queues;
+	peer_param->peer_cap.peer_max_sp = peer->max_sp;
+	peer_param->peer_cap.peer_buff_sta_support = peer->buf_sta_capable;
+	peer_param->peer_cap.peer_off_chan_support =
+		peer->off_channel_capable;
+	peer_param->peer_cap.peer_curr_operclass = 0;
+	peer_param->peer_cap.self_curr_operclass = 0;
+	peer_param->peer_cap.pref_off_channum = peer->pref_off_chan_num;
+	peer_param->peer_cap.pref_off_chan_bandwidth =
+		soc_obj->tdls_configs.tdls_pre_off_chan_bw;
+	peer_param->peer_cap.opclass_for_prefoffchan =
+		peer->op_class_for_pref_off_chan;
+
+	if (wlan_reg_is_dfs_ch(pdev, peer_param->peer_cap.pref_off_channum)) {
+		tdls_err("Resetting TDLS off-channel from %d to %d",
+			 peer_param->peer_cap.pref_off_channum,
+			 WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF);
+		peer_param->peer_cap.pref_off_channum =
+			WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF;
+	}
+
+	num = 0;
+	for (i = 0; i < peer->supported_channels_len; i++) {
+		chan_id = peer->supported_channels[i];
+		ch_state = wlan_reg_get_channel_state(pdev, chan_id);
+
+		if (CHANNEL_STATE_INVALID != ch_state &&
+		    CHANNEL_STATE_DFS != ch_state &&
+		    !wlan_reg_is_dsrc_chan(pdev, chan_id)) {
+			peer_param->peer_cap.peer_chan[num].chan_id = chan_id;
+			peer_param->peer_cap.peer_chan[num].pwr =
+				wlan_reg_get_channel_reg_power(pdev, chan_id);
+			peer_param->peer_cap.peer_chan[num].dfs_set = false;
+			peer_param->peer_cap.peer_chanlen++;
+			num++;
+		}
+	}
+
+	peer_param->peer_cap.peer_oper_classlen =
+		peer->supported_oper_classes_len;
+	for (i = 0; i < peer->supported_oper_classes_len; i++)
+		peer_param->peer_cap.peer_oper_class[i] =
+			peer->supported_oper_classes[i];
+}
+
+/**
+ * tdls_set_link_status() - set link statue for TDLS peer
+ * @vdev_obj: TDLS vdev object
+ * @mac: MAC address of current TDLS peer
+ * @link_status: link status
+ * @link_reason: reason with link status
+ *
+ * Return: None.
+ */
+void tdls_set_link_status(struct tdls_vdev_priv_obj *vdev_obj,
+			  const uint8_t *mac,
+			  enum tdls_link_state link_status,
+			  enum tdls_link_state_reason link_reason)
+{
+	uint32_t state = 0;
+	int32_t res = 0;
+	uint32_t op_class = 0;
+	uint32_t channel = 0;
+	struct tdls_peer *peer;
+	struct tdls_soc_priv_obj *soc_obj;
+
+	peer = tdls_find_peer(vdev_obj, mac);
+	if (!peer) {
+		tdls_err("peer is NULL, can't set link status %d, reason %d",
+			 link_status, link_reason);
+		return;
+	}
+
+	peer->link_status = link_status;
+
+	if (link_status >= TDLS_LINK_DISCOVERED)
+		peer->discovery_attempt = 0;
+
+	if (peer->is_forced_peer && peer->state_change_notification) {
+		peer->reason = link_reason;
+
+		soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
+		if (!soc_obj) {
+			tdls_err("NULL psoc object");
+			return;
+		}
+
+		tdls_determine_channel_opclass(soc_obj, vdev_obj,
+					       peer, &channel, &op_class);
+		tdls_get_wifi_hal_state(peer, &state, &res);
+		peer->state_change_notification(mac, op_class, channel,
+						state, res, soc_obj->soc);
+	}
+}
+
+void tdls_set_peer_link_status(struct tdls_peer *peer,
+			       enum tdls_link_state link_status,
+			       enum tdls_link_state_reason link_reason)
+{
+	uint32_t state = 0;
+	int32_t res = 0;
+	uint32_t op_class = 0;
+	uint32_t channel = 0;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_vdev_priv_obj *vdev_obj;
+
+	peer->link_status = link_status;
+
+	if (link_status >= TDLS_LINK_DISCOVERED)
+		peer->discovery_attempt = 0;
+
+	if (peer->is_forced_peer && peer->state_change_notification) {
+		peer->reason = link_reason;
+
+		vdev_obj = peer->vdev_priv;
+		soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
+		if (!soc_obj) {
+			tdls_err("NULL psoc object");
+			return;
+		}
+
+		tdls_determine_channel_opclass(soc_obj, vdev_obj,
+					       peer, &channel, &op_class);
+		tdls_get_wifi_hal_state(peer, &state, &res);
+		peer->state_change_notification(peer->peer_mac.bytes,
+						op_class, channel, state,
+						res, soc_obj->soc);
+	}
+}
+
+void tdls_set_peer_caps(struct tdls_vdev_priv_obj *vdev_obj,
+			const uint8_t *macaddr,
+			struct tdls_update_peer_params  *req_info)
+{
+	uint8_t is_buffer_sta = 0;
+	uint8_t is_off_channel_supported = 0;
+	uint8_t is_qos_wmm_sta = 0;
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_peer *curr_peer;
+	uint32_t feature;
+
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
+	if (!soc_obj) {
+		tdls_err("NULL psoc object");
+		return;
+	}
+
+	curr_peer = tdls_find_peer(vdev_obj, macaddr);
+	if (!curr_peer) {
+		tdls_err("NULL tdls peer");
+		return;
+	}
+
+	feature = soc_obj->tdls_configs.tdls_feature_flags;
+	if ((1 << 4) & req_info->extn_capability[3])
+		is_buffer_sta = 1;
+
+	if ((1 << 6) & req_info->extn_capability[3])
+		is_off_channel_supported = 1;
+
+	if (TDLS_IS_WMM_ENABLED(feature) && req_info->is_qos_wmm_sta)
+		is_qos_wmm_sta = 1;
+
+	curr_peer->uapsd_queues = req_info->uapsd_queues;
+	curr_peer->max_sp = req_info->max_sp;
+	curr_peer->buf_sta_capable = is_buffer_sta;
+	curr_peer->off_channel_capable = is_off_channel_supported;
+
+	qdf_mem_copy(curr_peer->supported_channels,
+		     req_info->supported_channels,
+		     req_info->supported_channels_len);
+
+	curr_peer->supported_channels_len = req_info->supported_channels_len;
+
+	qdf_mem_copy(curr_peer->supported_oper_classes,
+		     req_info->supported_oper_classes,
+		     req_info->supported_oper_classes_len);
+
+	curr_peer->supported_oper_classes_len =
+		req_info->supported_oper_classes_len;
+
+	curr_peer->qos = is_qos_wmm_sta;
+}
+
+QDF_STATUS tdls_set_sta_id(struct tdls_vdev_priv_obj *vdev_obj,
+			   const uint8_t *macaddr, uint8_t sta_id)
+{
+	struct tdls_peer *peer;
+
+	peer = tdls_find_peer(vdev_obj, macaddr);
+	if (!peer) {
+		tdls_err("peer is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	peer->sta_id = sta_id;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_set_force_peer(struct tdls_vdev_priv_obj *vdev_obj,
+			       const uint8_t *macaddr, bool forcepeer)
+{
+	struct tdls_peer *peer;
+
+	peer = tdls_find_peer(vdev_obj, macaddr);
+	if (!peer) {
+		tdls_err("peer is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	peer->is_forced_peer = forcepeer;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_set_callback(struct tdls_peer *peer,
+			     tdls_state_change_callback callback)
+{
+	if (!peer) {
+		tdls_err("peer is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	peer->state_change_notification = callback;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_set_extctrl_param(struct tdls_peer *peer, uint32_t chan,
+				  uint32_t max_latency, uint32_t op_class,
+				  uint32_t min_bandwidth)
+{
+	if (!peer) {
+		tdls_err("peer is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	peer->op_class_for_pref_off_chan = (uint8_t)op_class;
+	peer->pref_off_chan_num = (uint8_t)chan;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tdls_reset_peer(struct tdls_vdev_priv_obj *vdev_obj,
+			   const uint8_t *macaddr)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+	struct tdls_peer *curr_peer;
+	struct tdls_user_config *config;
+
+	soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev);
+	if (!soc_obj) {
+		tdls_err("NULL psoc object");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	curr_peer = tdls_find_peer(vdev_obj, macaddr);
+	if (!curr_peer) {
+		tdls_err("NULL tdls peer");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!curr_peer->is_forced_peer) {
+		config = &soc_obj->tdls_configs;
+		curr_peer->pref_off_chan_num = config->tdls_pre_off_chan_num;
+		curr_peer->op_class_for_pref_off_chan =
+			tdls_find_opclass(soc_obj->soc,
+					  curr_peer->pref_off_chan_num,
+					  config->tdls_pre_off_chan_bw);
+	}
+
+	tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE,
+				  TDLS_LINK_UNSPECIFIED);
+	curr_peer->sta_id = INVALID_TDLS_PEER_ID;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void tdls_peer_idle_timers_destroy(struct tdls_vdev_priv_obj *vdev_obj)
+{
+	uint16_t i;
+	struct tdls_peer *peer;
+	qdf_list_t *head;
+	qdf_list_node_t *p_node;
+	QDF_STATUS status;
+
+	if (!vdev_obj) {
+		tdls_err("NULL tdls vdev object");
+		return;
+	}
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &vdev_obj->peer_list[i];
+
+		status = qdf_list_peek_front(head, &p_node);
+		while (QDF_IS_STATUS_SUCCESS(status)) {
+			peer = qdf_container_of(p_node, struct tdls_peer, node);
+			if (peer && peer->is_peer_idle_timer_initialised) {
+				tdls_debug(QDF_MAC_ADDR_STR
+					   ": destroy  idle timer ",
+					   QDF_MAC_ADDR_ARRAY(
+						   peer->peer_mac.bytes));
+				qdf_mc_timer_stop(&peer->peer_idle_timer);
+				qdf_mc_timer_destroy(&peer->peer_idle_timer);
+			}
+			status = qdf_list_peek_next(head, p_node, &p_node);
+		}
+	}
+}
+
+void tdls_free_peer_list(struct tdls_vdev_priv_obj *vdev_obj)
+{
+	uint16_t i;
+	struct tdls_peer *peer;
+	qdf_list_t *head;
+	qdf_list_node_t *p_node;
+
+	if (!vdev_obj) {
+		tdls_err("NULL tdls vdev object");
+		return;
+	}
+
+	for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) {
+		head = &vdev_obj->peer_list[i];
+
+		while (QDF_IS_STATUS_SUCCESS(
+			       qdf_list_remove_front(head, &p_node))) {
+			peer = qdf_container_of(p_node, struct tdls_peer, node);
+			qdf_mem_free(peer);
+		}
+		qdf_list_destroy(head);
+	}
+}

+ 246 - 0
components/tdls/core/src/wlan_tdls_peer.h

@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_peer.h
+ *
+ * TDLS peer function declaration
+ */
+
+#if !defined(_WLAN_TDLS_PEER_H_)
+#define _WLAN_TDLS_PEER_H_
+
+/**
+ * struct tdls_search_peer_param - used to search TDLS peer
+ * @macaddr: MAC address of peer
+ * @peer: pointer to the found peer
+ */
+struct tdls_search_peer_param {
+	const uint8_t *macaddr;
+	struct tdls_peer *peer;
+};
+
+/**
+ * struct tdls_progress_param - used to search progress TDLS peer
+ * @skip_self: skip self peer
+ * @macaddr: MAC address of peer
+ * @peer: pointer to the found peer
+ */
+struct tdls_search_progress_param {
+	uint8_t skip_self;
+	const uint8_t *macaddr;
+	struct tdls_peer *peer;
+};
+
+/**
+ * tdls_get_peer() -  find or add an TDLS peer in TDLS vdev object
+ * @vdev_obj: TDLS vdev object
+ * @macaddr: MAC address of peer
+ *
+ * Search the TDLS peer in the hash table and create a new one if not found.
+ *
+ * Return: Pointer to tdls_peer, NULL if failed.
+ */
+struct tdls_peer *tdls_get_peer(struct tdls_vdev_priv_obj *vdev_obj,
+				const uint8_t *macaddr);
+
+/**
+ * tdls_find_peer() - find TDLS peer in TDLS vdev object
+ * @vdev_obj: TDLS vdev object
+ * @macaddr: MAC address of peer
+ *
+ * This is in scheduler thread context, no lock required.
+ *
+ * Return: If peer is found, then it returns pointer to tdls_peer;
+ *         otherwise, it returns NULL.
+ */
+struct tdls_peer *tdls_find_peer(struct tdls_vdev_priv_obj *vdev_obj,
+				 const uint8_t *macaddr);
+
+/**
+ * tdls_find_all_peer() - find peer matching the input MACaddr in soc range
+ * @soc_obj: TDLS soc object
+ * @macaddr: MAC address of TDLS peer
+ *
+ * This is in scheduler thread context, no lock required.
+ *
+ * Return: TDLS peer if a matching is detected; NULL otherwise
+ */
+struct tdls_peer *
+tdls_find_all_peer(struct tdls_soc_priv_obj *soc_obj, const uint8_t *macaddr);
+
+/**
+ * tdls_find_all_peer() - find peer matching the input MACaddr in soc range
+ * @soc_obj: TDLS soc object
+ * @channel:channel number
+ * @bw_offset: offset to bandwidth
+ *
+ * This is in scheduler thread context, no lock required.
+ *
+ * Return: Operating class
+ */
+uint8_t tdls_find_opclass(struct wlan_objmgr_psoc *psoc,
+				 uint8_t channel,
+				 uint8_t bw_offset);
+
+/**
+ * tdls_find_first_connected_peer() - find the 1st connected tdls peer from vdev
+ * @vdev_obj: tdls vdev object
+ *
+ * This function searches for the 1st connected TDLS peer
+ *
+ * Return: The 1st connected TDLS peer if found; NULL otherwise
+ */
+struct tdls_peer *
+tdls_find_first_connected_peer(struct tdls_vdev_priv_obj *vdev_obj);
+
+/**
+ * tdls_is_progress() - find the peer with ongoing TDLS progress on present psoc
+ * @vdev_obj: TDLS vdev object
+ * @macaddr: MAC address of the peer
+ * @skip_self: if 1, skip checking self. If 0, search include self
+ *
+ * This is used in scheduler thread context, no lock required.
+ *
+ * Return: TDLS peer if found; NULL otherwise
+ */
+struct tdls_peer *tdls_is_progress(struct tdls_vdev_priv_obj *vdev_obj,
+				   const uint8_t *macaddr, uint8_t skip_self);
+
+/**
+ * tdls_extract_peer_state_param() - extract peer update params from TDL peer
+ * @peer_param: output peer update params
+ * @peer: TDLS peer
+ *
+ * This is used when enable TDLS link
+ *
+ * Return: None.
+ */
+void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param,
+				   struct tdls_peer *peer);
+
+/**
+ * tdls_set_link_status() - set link statue for TDLS peer
+ * @peer: TDLS peer
+ * @link_state: link state
+ * @link_reason: reason with link status
+ *
+ * This is in scheduler thread context, no lock required.
+ *
+ * Return: None.
+ */
+void tdls_set_peer_link_status(struct tdls_peer *peer,
+			       enum tdls_link_state link_state,
+			       enum tdls_link_state_reason link_reason);
+
+/**
+ * tdls_set_peer_caps() - set capability for TDLS peer
+ * @vdev_obj: TDLS vdev object
+ * @macaddr: MAC address for the TDLS peer
+ * @req_info: parameters to update peer capability
+ *
+ * This is in scheduler thread context, no lock required.
+ *
+ * Return: None.
+ */
+void tdls_set_peer_caps(struct tdls_vdev_priv_obj *vdev_obj,
+			const uint8_t *macaddr,
+			struct tdls_update_peer_params  *req_info);
+
+/**
+ * tdls_set_sta_id() - set station ID on a TDLS peer
+ * @vdev_obj: TDLS vdev object
+ * @macaddr: MAC address of the TDLS peer
+ * @sta_id: station ID
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other values if failed
+ */
+QDF_STATUS tdls_set_sta_id(struct tdls_vdev_priv_obj *vdev_obj,
+			   const uint8_t *macaddr, uint8_t sta_id);
+
+/**
+ * tdls_set_force_peer() - set/clear is_forced_peer flag on peer
+ * @vdev_obj: TDLS vdev object
+ * @macaddr: MAC address of TDLS peer
+ * @forcepeer: value used to set is_forced_peer flag
+ *
+ * This is used in scheduler thread context, no lock required.
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other values if failed
+ */
+QDF_STATUS tdls_set_force_peer(struct tdls_vdev_priv_obj *vdev_obj,
+			       const uint8_t *macaddr, bool forcepeer);
+
+/**
+ * tdls_set_callback() - set state change callback on current TDLS peer
+ * @peer: TDLS peer
+ * @callback: state change callback
+ *
+ * This is used in scheduler thread context, no lock required.
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other values if failed
+ */
+QDF_STATUS tdls_set_callback(struct tdls_peer *peer,
+			     tdls_state_change_callback callback);
+
+/**
+ * tdls_set_extctrl_param() - set external control parameter on TDLS peer
+ * @peer: TDLS peer
+ * @chan: channel
+ * @max_latency: maximum latency
+ * @op_class: operation class
+ * @min_bandwidth: minimal bandwidth
+ *
+ * This is used in scheduler thread context, no lock required.
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other values if failed
+ */
+QDF_STATUS tdls_set_extctrl_param(struct tdls_peer *peer, uint32_t chan,
+				  uint32_t max_latency, uint32_t op_class,
+				  uint32_t min_bandwidth);
+
+/**
+ * tdls_reset_peer() - reset TDLS peer identified by MAC address
+ * @vdev_obj: TDLS vdev object
+ * @mac: MAC address of the peer
+ *
+ * Return: QDF_STATUS_SUCCESS if success; other values if failed
+ */
+QDF_STATUS tdls_reset_peer(struct tdls_vdev_priv_obj *vdev_obj,
+			   const uint8_t *mac);
+
+/**
+ * tdls_peer_idle_timers_destroy() - destroy peer idle timers
+ * @vdev_obj: TDLS vdev object
+ *
+ * Loop through the idle peer list and destroy their timers
+ *
+ * Return: None
+ */
+void tdls_peer_idle_timers_destroy(struct tdls_vdev_priv_obj *vdev_obj);
+
+/**
+ * tdls_free_peer_list() - free TDLS peer list
+ * @vdev_obj: TDLS vdev object
+ *
+ * Free all the tdls peers
+ *
+ * Return: None
+ */
+void tdls_free_peer_list(struct tdls_vdev_priv_obj *vdev_obj);
+#endif

+ 23 - 0
components/tdls/core/src/wlan_tdls_txrx.c

@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_txrx.c
+ *
+ * TDLS txrx function definitions
+ */

+ 23 - 0
components/tdls/core/src/wlan_tdls_txrx.h

@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_txrx.h
+ *
+ * TDLS txrx api declaration
+ */

+ 759 - 0
components/tdls/dispatcher/inc/wlan_tdls_cfg.h

@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. 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.
+ */
+
+#if !defined(CONFIG_TDLS_H__)
+#define CONFIG_TDLS_H__
+
+#include "cfg_define.h"
+#include "cfg_converged.h"
+#include "qdf_types.h"
+
+/*
+ * <ini>
+ * gTDLSUapsdMask - ACs to setup U-APSD for TDLS Sta.
+ * @Min: 0
+ * @Max: 0x0F
+ * @Default: 0x0F
+ *
+ * This ini is used to configure the ACs for which mask needs to be enabled.
+ * 0x1: Background	0x2: Best effort
+ * 0x4: Video		0x8: Voice
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_QOS_WMM_UAPSD_MASK CFG_INI_UINT( \
+	"gTDLSUapsdMask", \
+	0, \
+	0x0F, \
+	0x0F, \
+	CFG_VALUE_OR_DEFAULT, \
+	"ACs to setup U-APSD for TDLS Sta")
+
+/*
+ * <ini>
+ * gEnableTDLSBufferSta - Controls the TDLS buffer.
+ * @Min: 0
+ * @Max: 1
+ * @Default: 1
+ *
+ * This ini is used to control the TDLS buffer.
+ * Buffer STA is not enabled in CLD 2.0 yet.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_BUF_STA_ENABLED CFG_INI_BOOL( \
+	"gEnableTDLSBufferSta", \
+	1, \
+	"Controls the TDLS buffer")
+
+/*
+ * <ini>
+ * gTDLSPuapsdInactivityTime - Peer UAPSD Inactivity time.
+ * @Min: 0
+ * @Max: 10
+ * @Default: 0
+ *
+ * This ini is used to configure peer uapsd inactivity time.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_PUAPSD_INACT_TIME CFG_INI_UINT( \
+	"gTDLSPuapsdInactivityTime", \
+	0, \
+	10, \
+	0, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Peer UAPSD Inactivity time")
+
+/*
+ * <ini>
+ * gTDLSPuapsdRxFrameThreshold - Peer UAPSD Rx frame threshold.
+ * @Min: 10
+ * @Max: 20
+ * @Default: 10
+ *
+ * This ini is used to configure maximum Rx frame during SP.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_RX_FRAME_THRESHOLD CFG_INI_UINT( \
+	"gTDLSPuapsdRxFrameThreshold", \
+	10, \
+	20, \
+	10, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Peer UAPSD Rx frame threshold")
+
+/*
+ * <ini>
+ * gEnableTDLSOffChannel - Enables off-channel support for TDLS link.
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to enable/disable off-channel support for TDLS link.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_OFF_CHANNEL_ENABLED CFG_INI_BOOL( \
+	"gEnableTDLSOffChannel", \
+	0, \
+	"Enables off-channel support for TDLS")
+
+/*
+ * <ini>
+ * gEnableTDLSSupport - Enable support for TDLS.
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to enable/disable TDLS support.
+ *
+ * Related: None.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_SUPPORT_ENABLE CFG_INI_BOOL( \
+	"gEnableTDLSSupport", \
+	0, \
+	"enable/disable TDLS support")
+
+/*
+ * <ini>
+ * gEnableTDLSImplicitTrigger - Enable Implicit TDLS.
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to enable/disable implicit TDLS.
+ * CLD driver initiates TDLS Discovery towards a peer whenever TDLS Setup
+ * criteria (throughput and RSSI thresholds) is met and then it tears down
+ * TDLS when teardown criteria (idle packet count and RSSI) is met.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_IMPLICIT_TRIGGER CFG_INI_BOOL( \
+	"gEnableTDLSImplicitTrigger", \
+	0, \
+	"enable/disable implicit TDLS")
+
+/*
+ * <ini>
+ * gTDLSTxStatsPeriod - TDLS TX statistics time period.
+ * @Min: 1000
+ * @Max: 4294967295
+ * @Default: 2000
+ *
+ * This ini is used to configure the time period (in ms) to evaluate whether
+ * the number of Tx/Rx packets exceeds TDLSTxPacketThreshold and triggers a
+ * TDLS Discovery request.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_TX_STATS_PERIOD CFG_INI_UINT( \
+	"gTDLSTxStatsPeriod", \
+	1000, \
+	4294967295UL, \
+	2000, \
+	CFG_VALUE_OR_DEFAULT, \
+	"TDLS TX statistics time period")
+
+/*
+ * <ini>
+ * gTDLSTxPacketThreshold - Tx/Rx Packet threshold for initiating TDLS.
+ * @Min: 0
+ * @Max: 4294967295
+ * @Default: 40
+ *
+ * This ini is used to configure the number of Tx/Rx packets during the
+ * period of gTDLSTxStatsPeriod when exceeded, a TDLS Discovery request
+ * is triggered.
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_TX_PACKET_THRESHOLD CFG_INI_UINT( \
+	"gTDLSTxPacketThreshold", \
+	0, \
+	4294967295UL, \
+	40, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Tx/Rx Packet threshold for initiating TDLS")
+
+/*
+ * <ini>
+ * gTDLSMaxDiscoveryAttempt - Attempts for sending TDLS discovery requests.
+ * @Min: 1
+ * @Max: 100
+ * @Default: 5
+ *
+ * This ini is used to configure the number of failures of discover request,
+ * when exceeded, the peer is assumed to be not TDLS capable and no further
+ * TDLS Discovery request is made.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT CFG_INI_UINT( \
+	"gTDLSMaxDiscoveryAttempt", \
+	1, \
+	100, \
+	5, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Attempts for sending TDLS discovery requests")
+
+/*
+ * <ini>
+ * gTDLSIdleTimeout - Duration within which number of TX / RX frames meet the
+ * criteria for TDLS teardown.
+ * @Min: 500
+ * @Max: 40000
+ * @Default: 5000
+ *
+ * This ini is used to configure the time period (in ms) to evaluate whether
+ * the number of Tx/Rx packets exceeds gTDLSIdlePacketThreshold and thus meets
+ * criteria for TDLS teardown.
+ * Teardown notification interval (gTDLSIdleTimeout) should be multiple of
+ * setup notification (gTDLSTxStatsPeriod) interval.
+ * e.g.
+ *      if setup notification (gTDLSTxStatsPeriod) interval = 500, then
+ *      teardown notification (gTDLSIdleTimeout) interval should be 1000,
+ *      1500, 2000, 2500...
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ */
+#define CFG_TDLS_IDLE_TIMEOUT CFG_INI_UINT( \
+	"gTDLSIdleTimeout", \
+	500, \
+	40000, \
+	5000, \
+	CFG_VALUE_OR_DEFAULT, \
+	"this is idle time period")
+
+/*
+ * <ini>
+ * gTDLSIdlePacketThreshold - Number of idle packet.
+ * @Min: 0
+ * @Max: 40000
+ * @Default: 3
+ *
+ * This ini is used to configure the number of Tx/Rx packet, below which
+ * within last gTDLSTxStatsPeriod period is considered as idle condition.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_IDLE_PACKET_THRESHOLD CFG_INI_UINT( \
+	"gTDLSIdlePacketThreshold", \
+	0, \
+	40000, \
+	3, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Number of idle packet")
+
+/*
+ * <ini>
+ * gTDLSRSSITriggerThreshold - RSSI threshold for TDLS connection.
+ * @Min: -120
+ * @Max: 0
+ * @Default: -75
+ *
+ * This ini is used to configure the absolute value (in dB) of the peer RSSI,
+ * below which a TDLS setup request is triggered.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD CFG_INI_INT( \
+	"gTDLSRSSITriggerThreshold", \
+	-120, \
+	0, \
+	-75, \
+	CFG_VALUE_OR_DEFAULT, \
+	"RSSI threshold for TDLS connection")
+
+/*
+ * <ini>
+ * gTDLSRSSITeardownThreshold - RSSI threshold for TDLS teardown.
+ * @Min: -120
+ * @Max: 0
+ * @Default: -75
+ *
+ * This ini is used to configure the absolute value (in dB) of the peer RSSI,
+ * when exceed, a TDLS teardown is triggered.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD CFG_INI_INT( \
+	"gTDLSRSSITeardownThreshold", \
+	-120, \
+	0, \
+	-75, \
+	CFG_VALUE_OR_DEFAULT, \
+	"RSSI threshold for TDLS teardown")
+
+/*
+ * <ini>
+ * gTDLSRSSITeardownThreshold - RSSI threshold for TDLS teardown.
+ * @Min: -120
+ * @Max: 0
+ * @Default: -75
+ *
+ * This ini is used to configure the absolute value (in dB) of the peer RSSI,
+ * when exceed, a TDLS teardown is triggered.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_RSSI_DELTA CFG_INI_INT( \
+	"gTDLSRSSIDelta", \
+	-30, \
+	0, \
+	-20, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Delta value for the peer RSSI that can trigger teardown")
+
+/*
+ * <ini>
+ * gTDLSPrefOffChanNum - Preferred TDLS channel number when off-channel support
+ * is enabled.
+ * @Min: 1
+ * @Max: 165
+ * @Default: 36
+ *
+ * This ini is used to configure preferred TDLS channel number when off-channel
+ * support is enabled.
+ *
+ * Related: gEnableTDLSSupport, gEnableTDLSOffChannel.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM CFG_INI_UINT( \
+	"gTDLSPrefOffChanNum", \
+	1, \
+	165, \
+	36, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Preferred TDLS channel number")
+
+/*
+ * <ini>
+ * gTDLSPrefOffChanBandwidth - Preferred TDLS channel bandwidth when
+ * off-channel support is enabled.
+ * @Min: 0x01
+ * @Max: 0x0F
+ * @Default: 0x07
+ *
+ * This ini is used to configure preferred TDLS channel bandwidth when
+ * off-channel support is enabled.
+ * 0x1: 20 MHz	0x2: 40 MHz	0x4: 80 MHz	0x8: 160 MHz
+ * When more than one bits are set then firmware starts from the highest and
+ * selects one based on capability of peer.
+ *
+ * Related: gEnableTDLSSupport, gEnableTDLSOffChannel.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW CFG_INI_UINT( \
+	"gTDLSPrefOffChanBandwidth", \
+	1, \
+	15, \
+	7, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Preferred TDLS channel bandwidth")
+
+/*
+ * <ini>
+ * gTDLSPuapsdInactivityTime - Peer UAPSD Inactivity time.
+ * @Min: 0
+ * @Max: 10
+ * @Default: 0
+ *
+ * This ini is used to configure peer uapsd inactivity time.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_PUAPSD_INACTIVITY_TIME CFG_INI_UINT( \
+	"gTDLSPuapsdInactivityTime", \
+	0, \
+	10, \
+	0, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Peer UAPSD Inactivity time")
+
+/*
+ * <ini>
+ * gTDLSPuapsdInactivityTime - Peer UAPSD Inactivity time.
+ * @Min: 0
+ * @Max: 10
+ * @Default: 0
+ *
+ * This ini is used to configure peer uapsd inactivity time.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD CFG_INI_UINT( \
+	"gTDLSPuapsdRxFrameThreshold", \
+	10, \
+	20, \
+	10, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Peer UAPSD Rx frame threshold")
+
+/*
+ * <ini>
+ * gTDLSPuapsdPTIWindow - This ini is used to configure peer traffic indication
+ * window.
+ * @Min: 1
+ * @Max: 5
+ * @Default: 2
+ *
+ * This ini is used to configure buffering time in number of beacon intervals.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW CFG_INI_UINT( \
+	"gTDLSPuapsdPTIWindow", \
+	1, \
+	5, \
+	2, \
+	CFG_VALUE_OR_DEFAULT, \
+	"This ini is used to configure peer traffic indication")
+
+/*
+ * <ini>
+ * gTDLSPuapsdPTIWindow - This ini is used to configure peer traffic indication
+ * window.
+ * @Min: 1
+ * @Max: 5
+ * @Default: 2
+ *
+ * This ini is used to configure buffering time in number of beacon intervals.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT CFG_INI_UINT( \
+	"gTDLSPuapsdPTRTimeout", \
+	0, \
+	10000, \
+	5000, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Peer Traffic Response timer duration in ms")
+
+/*
+ * <ini>
+ * gTDLSPuapsdPTIWindow - This ini is used to configure peer traffic indication
+ * window.
+ * @Min: 1
+ * @Max: 5
+ * @Default: 2
+ *
+ * This ini is used to configure buffering time in number of beacon intervals.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_EXTERNAL_CONTROL CFG_INI_BOOL( \
+	"gTDLSExternalControl", \
+	1, \
+	"Enable external TDLS control")
+
+/*
+ * <ini>
+ * gEnableTDLSWmmMode - Enables WMM support over TDLS link.
+ * @Min: 0
+ * @Max: 1
+ * @Default: 1
+ *
+ * This ini is used to enable/disable WMM support over TDLS link.
+ * This is required to be set to 1 for any TDLS and uAPSD functionality.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_WMM_MODE_ENABLE CFG_INI_BOOL( \
+	"gEnableTDLSWmmMode", \
+	1, \
+	"Enables WMM support over TDLS link")
+
+/*
+ * <ini>
+ * gEnableTDLSScan - Allow scan and maintain TDLS link.
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to enable/disable TDLS scan.
+ *  0: If peer is not buffer STA capable and device is not sleep STA
+ *     capable, then teardown TDLS link when scan is initiated. If peer
+ *     is buffer STA and we can be sleep STA then TDLS link is maintained
+ *     during scan.
+ *  1: Maintain TDLS link and allow scan even if peer is not buffer STA
+ *     capable and device is not sleep STA capable. There will be loss of
+ *     Rx pkts since peer would not know when device moves away from tdls
+ *     channel. Tx on TDLS link would stop when device moves away from tdls
+ *     channel.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_SCAN_ENABLE CFG_INI_BOOL( \
+	"gEnableTDLSScan", \
+	0, \
+	"Allow scan and maintain TDLS link")
+
+/*
+ * <ini>
+ * gTDLSPeerKickoutThreshold - TDLS peer kick out threshold to firmware.
+ * @Min: 10
+ * @Max: 5000
+ * @Default: 96
+ *
+ * This ini is used to configure TDLS peer kick out threshold to firmware.
+ *     Firmware will use this value to determine, when to send TDLS
+ *     peer kick out event to host.
+ *     E.g.
+ *        if peer kick out threshold is 10, then firmware will wait for 10
+ *        consecutive packet failures and then send TDLS kick out
+ *        notification to host driver
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_PEER_KICKOUT_THRESHOLD CFG_INI_UINT( \
+	"gTDLSPeerKickoutThreshold", \
+	10, \
+	5000, \
+	96, \
+	CFG_VALUE_OR_DEFAULT, \
+	"TDLS peer kick out threshold to firmware")
+
+/*
+ * <ini>
+ * gTDLSEnableDeferTime - Timer to defer for enabling TDLS on P2P listen.
+ * @Min: 500
+ * @Max: 6000
+ * @Default: 2000
+ *
+ * This ini is used to set the timer to defer for enabling TDLS on P2P
+ * listen (value in milliseconds).
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_ENABLE_DEFER_TIMER CFG_INI_UINT( \
+	"gTDLSEnableDeferTime", \
+	500, \
+	6000, \
+	2000, \
+	CFG_VALUE_OR_DEFAULT, \
+	"Timer to defer for enabling TDLS on P2P listen")
+
+/*
+ * <ini>
+ * DelayedTriggerFrmInt - delayed trigger frame interval.
+ * @Min: 500
+ * @Max: 6000
+ * @Default: 2000
+ *
+ * This ini is used to set the delayed trigger frame interval.
+ *
+ * Related: gEnableTDLSSupport.
+ *
+ * Supported Feature: TDLS
+ *
+ * Usage: Internal/External
+ *
+ * </ini>
+ */
+#define CFG_TDLS_DELAYED_TRGR_FRM_INT CFG_INI_UINT( \
+	"DelayedTriggerFrmInt", \
+	1, \
+	4294967295UL, \
+	3000, \
+	CFG_VALUE_OR_DEFAULT, \
+	"delayed trigger frame interval")
+
+#define CFG_TDLS_ALL \
+	CFG(CFG_TDLS_QOS_WMM_UAPSD_MASK) \
+	CFG(CFG_TDLS_BUF_STA_ENABLED) \
+	CFG(CFG_TDLS_PUAPSD_INACT_TIME) \
+	CFG(CFG_TDLS_RX_FRAME_THRESHOLD) \
+	CFG(CFG_TDLS_OFF_CHANNEL_ENABLED) \
+	CFG(CFG_TDLS_SUPPORT_ENABLE) \
+	CFG(CFG_TDLS_IMPLICIT_TRIGGER) \
+	CFG(CFG_TDLS_TX_STATS_PERIOD) \
+	CFG(CFG_TDLS_TX_PACKET_THRESHOLD) \
+	CFG(CFG_TDLS_MAX_DISCOVERY_ATTEMPT) \
+	CFG(CFG_TDLS_IDLE_TIMEOUT) \
+	CFG(CFG_TDLS_IDLE_PACKET_THRESHOLD) \
+	CFG(CFG_TDLS_RSSI_TRIGGER_THRESHOLD) \
+	CFG(CFG_TDLS_RSSI_TEARDOWN_THRESHOLD) \
+	CFG(CFG_TDLS_RSSI_DELTA) \
+	CFG(CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM) \
+	CFG(CFG_TDLS_PREFERRED_OFF_CHANNEL_BW) \
+	CFG(CFG_TDLS_PUAPSD_INACTIVITY_TIME) \
+	CFG(CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD) \
+	CFG(CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW) \
+	CFG(CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT) \
+	CFG(CFG_TDLS_EXTERNAL_CONTROL) \
+	CFG(CFG_TDLS_WMM_MODE_ENABLE) \
+	CFG(CFG_TDLS_SCAN_ENABLE) \
+	CFG(CFG_TDLS_PEER_KICKOUT_THRESHOLD) \
+	CFG(CFG_TDLS_ENABLE_DEFER_TIMER) \
+	CFG(CFG_TDLS_DELAYED_TRGR_FRM_INT)
+
+#endif

+ 217 - 0
components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h

@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. 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 p2p configures interface definitions
+ */
+
+#ifndef _WLAN_TDLS_CFG_API_H_
+#define _WLAN_TDLS_CFG_API_H_
+
+#include <qdf_types.h>
+
+struct wlan_objmgr_psoc;
+
+/**
+ * cfg_tdls_get_support_enable() - get tdls support enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls support enable/disable
+ *
+ * This function gets tdls support enable
+ */
+QDF_STATUS
+cfg_tdls_get_support_enable(struct wlan_objmgr_psoc *psoc,
+			    bool *val);
+
+/**
+ * cfg_tdls_set_support_enable() - set tdls support enable
+ * @psoc:        pointer to psoc object
+ * @val:         set tdls support enable/disable
+ *
+ * This function sets tdls support enable
+ */
+QDF_STATUS
+cfg_tdls_set_support_enable(struct wlan_objmgr_psoc *psoc,
+			    bool val);
+
+/**
+ * cfg_tdls_get_external_control() - get tdls external control
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls external control enable/disable
+ *
+ * This function gets tdls external control
+ */
+QDF_STATUS
+cfg_tdls_get_external_control(struct wlan_objmgr_psoc *psoc,
+			      bool *val);
+
+/**
+ * cfg_tdls_get_uapsd_mask() - get tdls uapsd mask
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls uapsd mask
+ *
+ * This function gets tdls uapsd mask
+ */
+QDF_STATUS
+cfg_tdls_get_uapsd_mask(struct wlan_objmgr_psoc *psoc,
+			uint32_t *val);
+
+/**
+ * cfg_tdls_get_buffer_sta_enable() - get tdls buffer sta enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls buffer sta enable
+ *
+ * This function gets tdls buffer sta enable
+ */
+QDF_STATUS
+cfg_tdls_get_buffer_sta_enable(struct wlan_objmgr_psoc *psoc,
+			       bool *val);
+
+/**
+ * cfg_tdls_set_buffer_sta_enable() - set tdls buffer sta enable
+ * @psoc:        pointer to psoc object
+ * @val:         tdls buffer sta enable
+ *
+ * This function sets tdls buffer sta enable
+ */
+QDF_STATUS
+cfg_tdls_set_buffer_sta_enable(struct wlan_objmgr_psoc *psoc,
+			       bool val);
+
+/**
+ * cfg_tdls_get_uapsd_inactivity_time() - get tdls uapsd inactivity time
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls uapsd inactivity time
+ *
+ * This function gets tdls uapsd inactivity time
+ */
+QDF_STATUS
+cfg_tdls_get_uapsd_inactivity_time(struct wlan_objmgr_psoc *psoc,
+				   uint32_t *val);
+
+/**
+ * cfg_tdls_get_rx_pkt_threshold() - get tdls rx pkt threshold
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls tdls rx pkt threshold
+ *
+ * This function gets tdls rx pkt threshold
+ */
+QDF_STATUS
+cfg_tdls_get_rx_pkt_threshold(struct wlan_objmgr_psoc *psoc,
+			      uint32_t *val);
+
+/**
+ * cfg_tdls_get_off_channel_enable() - get tdls off channel enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls off channel enable
+ *
+ * This function gets tdls off channel enable
+ */
+QDF_STATUS
+cfg_tdls_get_off_channel_enable(struct wlan_objmgr_psoc *psoc,
+				bool *val);
+
+/**
+ * cfg_tdls_set_off_channel_enable() - set tdls off channel enable
+ * @psoc:        pointer to psoc object
+ * @val:         tdls off channel enable
+ *
+ * This function sets tdls off channel enable
+ */
+QDF_STATUS
+cfg_tdls_set_off_channel_enable(struct wlan_objmgr_psoc *psoc,
+				bool val);
+
+/**
+ * cfg_tdls_get_wmm_mode_enable() - get tdls wmm mode enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls wmm mode enable
+ *
+ * This function gets tdls wmm mode enable
+ */
+QDF_STATUS
+cfg_tdls_get_wmm_mode_enable(struct wlan_objmgr_psoc *psoc,
+			     bool *val);
+
+/**
+ * cfg_tdls_set_vdev_nss_2g() - set tdls vdev nss 2g
+ * @psoc:        pointer to psoc object
+ * @val:         tdls vdev nss 2g
+ *
+ * This function sets tdls vdev nss 2g
+ */
+QDF_STATUS
+cfg_tdls_set_vdev_nss_2g(struct wlan_objmgr_psoc *psoc,
+			 uint8_t val);
+
+/**
+ * cfg_tdls_set_vdev_nss_5g() - set tdls vdev nss 5g
+ * @psoc:        pointer to psoc object
+ * @val:         tdls vdev nss 5g
+ *
+ * This function sets tdls vdev nss 5g
+ */
+QDF_STATUS
+cfg_tdls_set_vdev_nss_5g(struct wlan_objmgr_psoc *psoc,
+			 uint8_t val);
+
+/**
+ * cfg_tdls_get_sleep_sta_enable() - get tdls sleep sta enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls sleep sta enable
+ *
+ * This function gets tdls sleep sta enable
+ */
+QDF_STATUS
+cfg_tdls_get_sleep_sta_enable(struct wlan_objmgr_psoc *psoc,
+			      bool *val);
+
+/**
+ * cfg_tdls_set_sleep_sta_enable() - set tdls sleep sta enable
+ * @psoc:        pointer to psoc object
+ * @val:         tdls sleep sta enable
+ *
+ * This function sets tdls sleep sta enable
+ */
+QDF_STATUS
+cfg_tdls_set_sleep_sta_enable(struct wlan_objmgr_psoc *psoc,
+			      bool val);
+
+/**
+ * cfg_tdls_get_scan_enable() - get tdls scan enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls scan enable
+ *
+ * This function gets tdls scan enable
+ */
+QDF_STATUS
+cfg_tdls_get_scan_enable(struct wlan_objmgr_psoc *psoc,
+			 bool *val);
+
+/**
+ * cfg_tdls_set_scan_enable() - set tdls scan enable
+ * @psoc:        pointer to psoc object
+ * @val:         tdls scan enable
+ *
+ * This function sets tdls scan enable
+ */
+QDF_STATUS
+cfg_tdls_set_scan_enable(struct wlan_objmgr_psoc *psoc,
+			 bool val);
+
+#endif /* _WLAN_TDLS_CFG_API_H_ */

+ 1169 - 0
components/tdls/dispatcher/inc/wlan_tdls_public_structs.h

@@ -0,0 +1,1169 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_public_structs.h
+ *
+ * TDLS public structure definations
+ */
+
+#ifndef _WLAN_TDLS_STRUCTS_H_
+#define _WLAN_TDLS_STRUCTS_H_
+#include <qdf_timer.h>
+#include <qdf_list.h>
+#include <qdf_mc_timer.h>
+#include <wlan_cmn.h>
+#include <wlan_cmn_ieee80211.h>
+
+
+#define WLAN_TDLS_STA_MAX_NUM                        8
+#define WLAN_TDLS_STA_P_UAPSD_OFFCHAN_MAX_NUM        1
+#define WLAN_TDLS_PEER_LIST_SIZE                     16
+#define WLAN_TDLS_CT_TABLE_SIZE                      8
+#define WLAN_TDLS_PEER_SUB_LIST_SIZE                 10
+#define WLAN_MAC_MAX_EXTN_CAP                        8
+#define WLAN_MAC_MAX_SUPP_CHANNELS                   100
+#define WLAN_MAC_WMI_MAX_SUPP_CHANNELS               128
+#define WLAN_MAX_SUPP_OPER_CLASSES                   32
+#define WLAN_MAC_MAX_SUPP_RATES                      32
+#define WLAN_CHANNEL_14                              14
+#define ENABLE_CHANSWITCH                            1
+#define DISABLE_CHANSWITCH                           2
+#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN      1
+#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX      165
+#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF      36
+
+#define AC_PRIORITY_NUM                 4
+
+/* default tdls serialize timeout is set to 10 secs */
+#define TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT 10000
+
+/** Maximum time(ms) to wait for tdls add sta to complete **/
+#define WAIT_TIME_TDLS_ADD_STA  (TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT + 1000)
+
+/** Maximum time(ms) to wait for tdls del sta to complete **/
+#define WAIT_TIME_TDLS_DEL_STA  (TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT + 1000)
+
+/** Maximum time(ms) to wait for Link Establish Req to complete **/
+#define WAIT_TIME_TDLS_LINK_ESTABLISH_REQ      1500
+
+/** Maximum time(ms) to wait for tdls mgmt to complete **/
+#define WAIT_TIME_FOR_TDLS_MGMT         11000
+
+/** Maximum time(ms) to wait for tdls mgmt to complete **/
+#define WAIT_TIME_FOR_TDLS_USER_CMD     11000
+
+/** Maximum waittime for TDLS teardown links **/
+#define WAIT_TIME_FOR_TDLS_TEARDOWN_LINKS 10000
+
+/** Maximum waittime for TDLS antenna switch **/
+#define WAIT_TIME_FOR_TDLS_ANTENNA_SWITCH 1000
+
+#define TDLS_TEARDOWN_PEER_UNREACHABLE   25
+#define TDLS_TEARDOWN_PEER_UNSPEC_REASON 26
+
+#define INVALID_TDLS_PEER_ID 0xFF
+#define TDLS_STA_INDEX_CHECK(sta_id) \
+	(((sta_id) >= 0) && ((sta_id) < 0xFF))
+
+/**
+ * enum tdls_add_oper - add peer type
+ * @TDLS_OPER_NONE: none
+ * @TDLS_OPER_ADD: add new peer
+ * @TDLS_OPER_UPDATE: used to update peer
+ */
+enum tdls_add_oper {
+	TDLS_OPER_NONE,
+	TDLS_OPER_ADD,
+	TDLS_OPER_UPDATE
+};
+
+/**
+ * enum tdls_conc_cap - tdls concurrency support
+ * @TDLS_SUPPORTED_ONLY_ON_STA: only support sta tdls
+ * @TDLS_SUPPORTED_ONLY_ON_P2P_CLIENT: only support p2p client tdls
+ */
+enum tdls_conc_cap {
+	TDLS_SUPPORTED_ONLY_ON_STA = 0,
+	TDLS_SUPPORTED_ONLY_ON_P2P_CLIENT,
+};
+
+/**
+ * enum tdls_peer_capab - tdls capability type
+ * @TDLS_CAP_NOT_SUPPORTED: tdls not supported
+ * @TDLS_CAP_UNKNOWN: unknown capability
+ * @TDLS_CAP_SUPPORTED: tdls capability supported
+ */
+enum tdls_peer_capab {
+	TDLS_CAP_NOT_SUPPORTED = -1,
+	TDLS_CAP_UNKNOWN       = 0,
+	TDLS_CAP_SUPPORTED     = 1,
+};
+
+/**
+ * enum tdls_peer_state - tdls peer state
+ * @TDLS_PEER_STATE_PEERING: tdls connection in progress
+ * @TDLS_PEER_STATE_CONNCTED: tdls peer is connected
+ * @TDLS_PEER_STATE_TEARDOWN: tdls peer is tear down
+ * @TDLS_PEER_ADD_MAC_ADDR: add peer mac into connection table
+ * @TDLS_PEER_REMOVE_MAC_ADDR: remove peer mac from connection table
+ */
+enum tdls_peer_state {
+	TDLS_PEER_STATE_PEERING,
+	TDLS_PEER_STATE_CONNCTED,
+	TDLS_PEER_STATE_TEARDOWN,
+	TDLS_PEER_ADD_MAC_ADDR,
+	TDLS_PEER_REMOVE_MAC_ADDR
+};
+
+/**
+ * enum tdls_link_state - tdls link state
+ * @TDLS_LINK_IDLE: tdls link idle
+ * @TDLS_LINK_DISCOVERING: tdls link discovering
+ * @TDLS_LINK_DISCOVERED: tdls link discovered
+ * @TDLS_LINK_CONNECTING: tdls link connecting
+ * @TDLS_LINK_CONNECTED: tdls link connected
+ * @TDLS_LINK_TEARING: tdls link tearing
+ */
+enum tdls_link_state {
+	TDLS_LINK_IDLE = 0,
+	TDLS_LINK_DISCOVERING,
+	TDLS_LINK_DISCOVERED,
+	TDLS_LINK_CONNECTING,
+	TDLS_LINK_CONNECTED,
+	TDLS_LINK_TEARING,
+};
+
+/**
+ * enum tdls_link_state_reason - tdls link reason
+ * @TDLS_LINK_SUCCESS: Success
+ * @TDLS_LINK_UNSPECIFIED: Unspecified reason
+ * @TDLS_LINK_NOT_SUPPORTED: Remote side doesn't support TDLS
+ * @TDLS_LINK_UNSUPPORTED_BAND: Remote side doesn't support this band
+ * @TDLS_LINK_NOT_BENEFICIAL: Going to AP is better than direct
+ * @TDLS_LINK_DROPPED_BY_REMOTE: Remote side doesn't want it anymore
+ */
+enum tdls_link_state_reason {
+	TDLS_LINK_SUCCESS,
+	TDLS_LINK_UNSPECIFIED         = -1,
+	TDLS_LINK_NOT_SUPPORTED       = -2,
+	TDLS_LINK_UNSUPPORTED_BAND    = -3,
+	TDLS_LINK_NOT_BENEFICIAL      = -4,
+	TDLS_LINK_DROPPED_BY_REMOTE   = -5,
+};
+
+/**
+ * enum tdls_feature_mode - TDLS support mode
+ * @TDLS_SUPPORT_DISABLED: Disabled in ini or FW
+ * @TDLS_SUPPORT_SUSPENDED: TDLS supported by ini and FW, but disabled
+ *            temporarily due to off-channel operations or due to other reasons
+ * @TDLS_SUPPORT_EXP_TRIG_ONLY: Explicit trigger mode
+ * @TDLS_SUPPORT_IMP_MODE: Implicit mode
+ * @TDLS_SUPPORT_EXT_CONTROL: External control mode
+ */
+enum tdls_feature_mode {
+	TDLS_SUPPORT_DISABLED = 0,
+	TDLS_SUPPORT_SUSPENDED,
+	TDLS_SUPPORT_EXP_TRIG_ONLY,
+	TDLS_SUPPORT_IMP_MODE,
+	TDLS_SUPPORT_EXT_CONTROL,
+};
+
+/**
+ * enum tdls_command_type - TDLS command type
+ * @TDLS_CMD_TX_ACTION: send tdls action frame
+ * @TDLS_CMD_ADD_STA: add tdls peer
+ * @TDLS_CMD_CHANGE_STA: change tdls peer
+ * @TDLS_CMD_ENABLE_LINK: enable tdls link
+ * @TDLS_CMD_DISABLE_LINK: disable tdls link
+ * @TDLS_CMD_CONFIG_FORCE_PEER: config external peer
+ * @TDLS_CMD_REMOVE_FORCE_PEER: remove external peer
+ * @TDLS_CMD_STATS_UPDATE: update tdls stats
+ * @TDLS_CMD_CONFIG_UPDATE: config tdls
+ * @TDLS_CMD_SCAN_DONE: scon done event
+ * @TDLS_CMD_SET_RESPONDER: responder event
+ * @TDLS_NOTIFY_STA_CONNECTION: notify sta connection
+ * @TDLS_NOTIFY_STA_DISCONNECTION: notify sta disconnection
+ * @TDLS_CMD_SET_TDLS_MODE: set the tdls mode
+ * @TDLS_CMD_SESSION_INCREMENT: notify session increment
+ * @TDLS_CMD_SESSION_DECREMENT: notify session decrement
+ * @TDLS_CMD_TEARDOWN_LINKS: notify teardown
+ * @TDLS_NOTIFY_RESET_ADAPTERS: notify adapter reset
+ * @TDLS_CMD_GET_ALL_PEERS: get all the tdls peers from the list
+ * @TDLS_CMD_ANTENNA_SWITCH: dynamic tdls antenna switch
+ * @TDLS_CMD_SET_OFFCHANNEL: tdls offchannel
+ * @TDLS_CMD_SET_OFFCHANMODE: tdls offchannel mode
+ * @TDLS_CMD_SET_SECOFFCHANOFFSET: tdls secondary offchannel offset
+ * @TDLS_DELETE_ALL_PEERS_INDICATION: tdls delete all peers indication
+ */
+enum tdls_command_type {
+	TDLS_CMD_TX_ACTION = 1,
+	TDLS_CMD_ADD_STA,
+	TDLS_CMD_CHANGE_STA,
+	TDLS_CMD_ENABLE_LINK,
+	TDLS_CMD_DISABLE_LINK,
+	TDLS_CMD_CONFIG_FORCE_PEER,
+	TDLS_CMD_REMOVE_FORCE_PEER,
+	TDLS_CMD_STATS_UPDATE,
+	TDLS_CMD_CONFIG_UPDATE,
+	TDLS_CMD_SCAN_DONE,
+	TDLS_CMD_SET_RESPONDER,
+	TDLS_NOTIFY_STA_CONNECTION,
+	TDLS_NOTIFY_STA_DISCONNECTION,
+	TDLS_CMD_SET_TDLS_MODE,
+	TDLS_CMD_SESSION_INCREMENT,
+	TDLS_CMD_SESSION_DECREMENT,
+	TDLS_CMD_TEARDOWN_LINKS,
+	TDLS_NOTIFY_RESET_ADAPTERS,
+	TDLS_CMD_GET_ALL_PEERS,
+	TDLS_CMD_ANTENNA_SWITCH,
+	TDLS_CMD_SET_OFFCHANNEL,
+	TDLS_CMD_SET_OFFCHANMODE,
+	TDLS_CMD_SET_SECOFFCHANOFFSET,
+	TDLS_DELETE_ALL_PEERS_INDICATION
+};
+
+/**
+ * enum tdls_event_type - TDLS event type
+ * @TDLS_EVENT_VDEV_STATE_CHANGE: umac connect/disconnect event
+ * @TDLS_EVENT_MGMT_TX_ACK_CNF: tx tdls frame ack event
+ * @TDLS_EVENT_RX_MGMT: rx discovery response frame
+ * @TDLS_EVENT_ADD_PEER: add peer or update peer
+ * @TDLS_EVENT_DEL_PEER: delete peer
+ * @TDLS_EVENT_DISCOVERY_REQ: dicovery request
+ * @TDLS_EVENT_TEARDOWN_REQ: teardown request
+ * @TDLS_EVENT_SETUP_REQ: setup request
+ * @TDLS_EVENT_TEARDOWN_LINKS_DONE: teardown completion event
+ * @TDLS_EVENT_USER_CMD: tdls user command
+ * @TDLS_EVENT_ANTENNA_SWITCH: antenna switch event
+ */
+enum tdls_event_type {
+	TDLS_EVENT_VDEV_STATE_CHANGE = 0,
+	TDLS_EVENT_MGMT_TX_ACK_CNF,
+	TDLS_EVENT_RX_MGMT,
+	TDLS_EVENT_ADD_PEER,
+	TDLS_EVENT_DEL_PEER,
+	TDLS_EVENT_DISCOVERY_REQ,
+	TDLS_EVENT_TEARDOWN_REQ,
+	TDLS_EVENT_SETUP_REQ,
+	TDLS_EVENT_TEARDOWN_LINKS_DONE,
+	TDLS_EVENT_USER_CMD,
+	TDLS_EVENT_ANTENNA_SWITCH,
+};
+
+/**
+ * enum tdls_state_t - tdls state
+ * @QCA_WIFI_HAL_TDLS_DISABLED: TDLS is not enabled, or is disabled now
+ * @QCA_WIFI_HAL_TDLS_ENABLED: TDLS is enabled, but not yet tried
+ * @QCA_WIFI_HAL_TDLS_ESTABLISHED: Direct link is established
+ * @QCA_WIFI_HAL_TDLS_ESTABLISHED_OFF_CHANNEL: Direct link established using MCC
+ * @QCA_WIFI_HAL_TDLS_DROPPED: Direct link was established, but is now dropped
+ * @QCA_WIFI_HAL_TDLS_FAILED: Direct link failed
+ */
+enum tdls_state_t {
+	QCA_WIFI_HAL_TDLS_S_DISABLED = 1,
+	QCA_WIFI_HAL_TDLS_S_ENABLED,
+	QCA_WIFI_HAL_TDLS_S_ESTABLISHED,
+	QCA_WIFI_HAL_TDLS_S_ESTABLISHED_OFF_CHANNEL,
+	QCA_WIFI_HAL_TDLS_S_DROPPED,
+	QCA_WIFI_HAL_TDLS_S_FAILED,
+};
+
+/**
+ * enum tdls_off_chan_mode - mode for WMI_TDLS_SET_OFFCHAN_MODE_CMDID
+ * @TDLS_ENABLE_OFFCHANNEL: enable off channel
+ * @TDLS_DISABLE_OFFCHANNEL: disable off channel
+ */
+enum tdls_off_chan_mode {
+	TDLS_ENABLE_OFFCHANNEL,
+	TDLS_DISABLE_OFFCHANNEL
+};
+
+/**
+ * enum tdls_event_msg_type - TDLS event message type
+ * @TDLS_SHOULD_DISCOVER: should do discover for peer (based on tx bytes per
+ * second > tx_discover threshold)
+ * @TDLS_SHOULD_TEARDOWN: recommend teardown the link for peer due to tx bytes
+ * per second below tx_teardown_threshold
+ * @TDLS_PEER_DISCONNECTED: tdls peer disconnected
+ * @TDLS_CONNECTION_TRACKER_NOTIFY: TDLS/BT role change notification for
+ * connection tracker
+ */
+enum tdls_event_msg_type {
+	TDLS_SHOULD_DISCOVER = 0,
+	TDLS_SHOULD_TEARDOWN,
+	TDLS_PEER_DISCONNECTED,
+	TDLS_CONNECTION_TRACKER_NOTIFY
+};
+
+/**
+ * enum tdls_event_reason - TDLS event reason
+ * @TDLS_TEARDOWN_TX: tdls teardown recommended due to low transmits
+ * @TDLS_TEARDOWN_RSSI: tdls link tear down recommended due to poor RSSI
+ * @TDLS_TEARDOWN_SCAN: tdls link tear down recommended due to offchannel scan
+ * @TDLS_TEARDOWN_PTR_TIMEOUT: tdls peer disconnected due to PTR timeout
+ * @TDLS_TEARDOWN_BAD_PTR: tdls peer disconnected due wrong PTR format
+ * @TDLS_TEARDOWN_NO_RSP: tdls peer not responding
+ * @TDLS_DISCONNECTED_PEER_DELETE: tdls peer disconnected due to peer deletion
+ * @TDLS_PEER_ENTER_BUF_STA: tdls entered buffer STA role, TDLS connection
+ * tracker needs to handle this
+ * @TDLS_PEER_EXIT_BUF_STA: tdls exited buffer STA role, TDLS connection tracker
+ * needs to handle this
+ * @TDLS_ENTER_BT_BUSY: BT entered busy mode, TDLS connection tracker needs to
+ * handle this
+ * @TDLS_EXIT_BT_BUSY: BT exited busy mode, TDLS connection tracker needs to
+ * handle this
+ * @DLS_SCAN_STARTED: TDLS module received a scan start event, TDLS connection
+ * tracker needs to handle this
+ * @TDLS_SCAN_COMPLETED: TDLS module received a scan complete event, TDLS
+ * connection tracker needs to handle this
+ */
+enum tdls_event_reason {
+	TDLS_TEARDOWN_TX,
+	TDLS_TEARDOWN_RSSI,
+	TDLS_TEARDOWN_SCAN,
+	TDLS_TEARDOWN_PTR_TIMEOUT,
+	TDLS_TEARDOWN_BAD_PTR,
+	TDLS_TEARDOWN_NO_RSP,
+	TDLS_DISCONNECTED_PEER_DELETE,
+	TDLS_PEER_ENTER_BUF_STA,
+	TDLS_PEER_EXIT_BUF_STA,
+	TDLS_ENTER_BT_BUSY,
+	TDLS_EXIT_BT_BUSY,
+	TDLS_SCAN_STARTED,
+	TDLS_SCAN_COMPLETED,
+};
+
+/**
+ * enum tdls_disable_sources - TDLS disable sources
+ * @TDLS_SET_MODE_SOURCE_USER: disable from user
+ * @TDLS_SET_MODE_SOURCE_SCAN: disable during scan
+ * @TDLS_SET_MODE_SOURCE_OFFCHANNEL: disable during offchannel
+ * @TDLS_SET_MODE_SOURCE_BTC: disable during bluetooth
+ * @TDLS_SET_MODE_SOURCE_P2P: disable during p2p
+ */
+enum tdls_disable_sources {
+	TDLS_SET_MODE_SOURCE_USER = 0,
+	TDLS_SET_MODE_SOURCE_SCAN,
+	TDLS_SET_MODE_SOURCE_OFFCHANNEL,
+	TDLS_SET_MODE_SOURCE_BTC,
+	TDLS_SET_MODE_SOURCE_P2P,
+};
+
+/**
+ * struct tdls_osif_indication - tdls indication to os if layer
+ * @vdev: vdev object
+ * @reason: used with teardown indication
+ * @peer_mac: MAC address of the TDLS peer
+ */
+struct tdls_osif_indication {
+	struct wlan_objmgr_vdev *vdev;
+	uint16_t reason;
+	uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
+	QDF_STATUS status;
+};
+
+/**
+ * struct tx_frame - tx frame
+ * @buf: frame buffer
+ * @buf_len: buffer length
+ * @tx_timer: tx send timer
+ */
+struct tx_frame {
+	uint8_t *buf;
+	size_t buf_len;
+	qdf_timer_t tx_timer;
+};
+
+/**
+ * enum tdls_feature_bit
+ * @TDLS_FEATURE_OFF_CHANNEL: tdls off channel
+ * @TDLS_FEATURE_WMM: tdls wmm
+ * @TDLS_FEATURE_BUFFER_STA: tdls buffer sta
+ * @TDLS_FEATURE_SLEEP_STA: tdls sleep sta feature
+ * @TDLS_FEATURE_SCAN: tdls scan
+ * @TDLS_FEATURE_ENABLE: tdls enabled
+ * @TDLS_FEAUTRE_IMPLICIT_TRIGGER: tdls implicit trigger
+ * @TDLS_FEATURE_EXTERNAL_CONTROL: tdls external control
+ */
+enum tdls_feature_bit {
+	TDLS_FEATURE_OFF_CHANNEL,
+	TDLS_FEATURE_WMM,
+	TDLS_FEATURE_BUFFER_STA,
+	TDLS_FEATURE_SLEEP_STA,
+	TDLS_FEATURE_SCAN,
+	TDLS_FEATURE_ENABLE,
+	TDLS_FEAUTRE_IMPLICIT_TRIGGER,
+	TDLS_FEATURE_EXTERNAL_CONTROL
+};
+
+#define TDLS_IS_OFF_CHANNEL_ENABLED(flags) \
+	CHECK_BIT(flags, TDLS_FEATURE_OFF_CHANNEL)
+#define TDLS_IS_WMM_ENABLED(flags) \
+	CHECK_BIT(flags, TDLS_FEATURE_WMM)
+#define TDLS_IS_BUFFER_STA_ENABLED(flags) \
+	CHECK_BIT(flags, TDLS_FEATURE_BUFFER_STA)
+#define TDLS_IS_SLEEP_STA_ENABLED(flags) \
+	CHECK_BIT(flags, TDLS_FEATURE_SLEEP_STA)
+#define TDLS_IS_SCAN_ENABLED(flags) \
+	CHECK_BIT(flags, TDLS_FEATURE_SCAN)
+#define TDLS_IS_ENABLED(flags) \
+	CHECK_BIT(flags, TDLS_FEATURE_ENABLE)
+#define TDLS_IS_IMPLICIT_TRIG_ENABLED(flags) \
+	CHECK_BIT(flags, TDLS_FEAUTRE_IMPLICIT_TRIGGER)
+#define TDLS_IS_EXTERNAL_CONTROL_ENABLED(flags) \
+	CHECK_BIT(flags, TDLS_FEATURE_EXTERNAL_CONTROL)
+
+/**
+ * struct tdls_user_config - TDLS user configuration
+ * @tdls_tx_states_period: tdls tx states period
+ * @tdls_tx_pkt_threshold: tdls tx packets threshold
+ * @tdls_rx_pkt_threshold: tdls rx packets threshold
+ * @tdls_max_discovery_attempt: tdls discovery max times
+ * @tdls_idle_timeout: tdls idle timeout
+ * @tdls_idle_pkt_threshold: tdls idle packets threshold
+ * @tdls_rssi_trigger_threshold: tdls rssi trigger threshold
+ * @tdls_rssi_teardown_threshold: tdls rssi tear down threshold
+ * @tdls_rssi_delta: tdls rssi delta
+ * @tdls_uapsd_mask: tdls uapsd mask
+ * @tdls_uapsd_inactivity_time: tdls uapsd inactivity time
+ * @tdls_uapsd_pti_window: tdls peer traffic indication window
+ * @tdls_uapsd_ptr_timeout: tdls peer response timeout
+ * @tdls_feature_flags: tdls feature flags
+ * @tdls_pre_off_chan_num: tdls off channel number
+ * @tdls_pre_off_chan_bw: tdls off channel bandwidth
+ * @tdls_peer_kickout_threshold: sta kickout threshold for tdls peer
+ * @delayed_trig_framint: delayed trigger frame interval
+ * @tdls_vdev_nss_2g: tdls NSS setting for 2G band
+ * @tdls_vdev_nss_5g: tdls NSS setting for 5G band
+ * @tdls_buffer_sta_enable: tdls buffer station enable
+ * @tdls_off_chan_enable: tdls off channel enable
+ * @tdls_wmm_mode_enable: tdls wmm mode enable
+ * @tdls_external_control: tdls external control enable
+ * @tdls_implicit_trigger_enable: tdls implicit trigger enable
+ * @tdls_scan_enable: tdls scan enable
+ * @tdls_sleep_sta_enable: tdls sleep sta enable
+ * @tdls_support_enable: tdls support enable
+ */
+struct tdls_user_config {
+	uint32_t tdls_tx_states_period;
+	uint32_t tdls_tx_pkt_threshold;
+	uint32_t tdls_rx_pkt_threshold;
+	uint32_t tdls_max_discovery_attempt;
+	uint32_t tdls_idle_timeout;
+	uint32_t tdls_idle_pkt_threshold;
+	int32_t tdls_rssi_trigger_threshold;
+	int32_t tdls_rssi_teardown_threshold;
+	uint32_t tdls_rssi_delta;
+	uint32_t tdls_uapsd_mask;
+	uint32_t tdls_uapsd_inactivity_time;
+	uint32_t tdls_uapsd_pti_window;
+	uint32_t tdls_uapsd_ptr_timeout;
+	uint32_t tdls_feature_flags;
+	uint32_t tdls_pre_off_chan_num;
+	uint32_t tdls_pre_off_chan_bw;
+	uint32_t tdls_peer_kickout_threshold;
+	uint32_t delayed_trig_framint;
+	uint8_t tdls_vdev_nss_2g;
+	uint8_t tdls_vdev_nss_5g;
+	bool tdls_buffer_sta_enable;
+	bool tdls_off_chan_enable;
+	bool tdls_wmm_mode_enable;
+	bool tdls_external_control;
+	bool tdls_implicit_trigger_enable;
+	bool tdls_scan_enable;
+	bool tdls_sleep_sta_enable;
+	bool tdls_support_enable;
+};
+
+/**
+ * struct tdls_config_params - tdls configure paramets
+ * @tdls: tdls support mode
+ * @tx_period_t: tdls tx stats period
+ * @tx_packet_n: tdls tx packets number threshold
+ * @discovery_tries_n: tdls max discovery attempt count
+ * @idle_timeout_t: tdls idle time timeout
+ * @idle_packet_n: tdls idle pkt threshold
+ * @rssi_trigger_threshold: tdls rssi trigger threshold, checked before setup
+ * @rssi_teardown_threshold: tdls rssi teardown threshold
+ * @rssi_delta: rssi delta
+ */
+struct tdls_config_params {
+	uint32_t tdls;
+	uint32_t tx_period_t;
+	uint32_t tx_packet_n;
+	uint32_t discovery_tries_n;
+	uint32_t idle_timeout_t;
+	uint32_t idle_packet_n;
+	int32_t rssi_trigger_threshold;
+	int32_t rssi_teardown_threshold;
+	int32_t rssi_delta;
+};
+
+/**
+ * struct tdls_tx_cnf: tdls tx ack
+ * @vdev_id: vdev id
+ * @action_cookie: frame cookie
+ * @buf: frame buf
+ * @buf_len: buffer length
+ * @status: tx send status
+ */
+struct tdls_tx_cnf {
+	int vdev_id;
+	uint64_t action_cookie;
+	void *buf;
+	size_t buf_len;
+	int status;
+};
+
+/**
+ * struct tdls_rx_mgmt_frame - rx mgmt frame structure
+ * @frame_len: frame length
+ * @rx_chan: rx channel
+ * @vdev_id: vdev id
+ * @frm_type: frame type
+ * @rx_rssi: rx rssi
+ * @buf: buffer address
+ */
+struct tdls_rx_mgmt_frame {
+	uint32_t frame_len;
+	uint32_t rx_chan;
+	uint32_t vdev_id;
+	uint32_t frm_type;
+	uint32_t rx_rssi;
+	uint8_t buf[1];
+};
+
+/**
+ * tdls_rx_callback() - Callback for rx mgmt frame
+ * @user_data: user data associated to this rx mgmt frame.
+ * @rx_frame: RX mgmt frame
+ *
+ * This callback will be used to give rx frames to hdd.
+ *
+ * Return: None
+ */
+typedef void (*tdls_rx_callback)(void *user_data,
+	struct tdls_rx_mgmt_frame *rx_frame);
+
+/**
+ * tdls_wmm_check() - Callback for wmm info
+ * @psoc: psoc object
+ *
+ * This callback will be used to check wmm information
+ *
+ * Return: true or false
+ */
+typedef bool (*tdls_wmm_check)(uint8_t vdev_id);
+
+
+/* This callback is used to report state change of peer to wpa_supplicant */
+typedef int (*tdls_state_change_callback)(const uint8_t *mac,
+					  uint32_t opclass,
+					  uint32_t channel,
+					  uint32_t state,
+					  int32_t reason, void *ctx);
+
+/* This callback is used to report events to os_if layer */
+typedef void (*tdls_evt_callback) (void *data,
+				   enum tdls_event_type ev_type,
+				   struct tdls_osif_indication *event);
+
+/* This callback is used to register TDLS peer with the datapath */
+typedef QDF_STATUS (*tdls_register_peer_callback)(void *userdata,
+						  uint32_t vdev_id,
+						  const uint8_t *mac,
+						  uint16_t stat_id,
+						  uint8_t qos);
+
+/* This callback is used to deregister TDLS peer from the datapath */
+typedef QDF_STATUS (*tdls_deregister_peer_callback)(void *userdata,
+						    uint32_t vdev_id,
+						    uint8_t sta_id);
+
+/* This callback is used to update datapath vdev flags */
+typedef QDF_STATUS
+(*tdls_dp_vdev_update_flags_callback)(void *cbk_data,
+				      uint8_t sta_id,
+				      uint32_t vdev_param,
+				      bool is_link_up);
+
+/* This callback is to release vdev ref for tdls offchan param related msg */
+typedef void (*tdls_offchan_parms_callback)(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * struct tdls_start_params - tdls start params
+ * @config: tdls user config
+ * @tdls_send_mgmt_req: pass eWNI_SME_TDLS_SEND_MGMT_REQ value
+ * @tdls_add_sta_req: pass eWNI_SME_TDLS_ADD_STA_REQ value
+ * @tdls_del_sta_req: pass eWNI_SME_TDLS_DEL_STA_REQ value
+ * @tdls_update_peer_state: pass WMA_UPDATE_TDLS_PEER_STATE value
+ * @tdls_del_all_peers: pass eWNI_SME_DEL_ALL_TDLS_PEERS
+ * @tdls_update_dp_vdev_flags: pass CDP_UPDATE_TDLS_FLAGS
+ * @tdls_event_cb: tdls event callback
+ * @tdls_evt_cb_data: tdls event data
+ * @tdls_peer_context: userdata for register/deregister TDLS peer
+ * @tdls_reg_peer: register tdls peer with datapath
+ * @tdls_dereg_peer: deregister tdls peer from datapath
+ * @tdls_dp_vdev_update: update vdev flags in datapath
+ */
+struct tdls_start_params {
+	struct tdls_user_config config;
+	uint16_t tdls_send_mgmt_req;
+	uint16_t tdls_add_sta_req;
+	uint16_t tdls_del_sta_req;
+	uint16_t tdls_update_peer_state;
+	uint16_t tdls_del_all_peers;
+	uint32_t tdls_update_dp_vdev_flags;
+	tdls_rx_callback tdls_rx_cb;
+	void *tdls_rx_cb_data;
+	tdls_wmm_check tdls_wmm_cb;
+	void *tdls_wmm_cb_data;
+	tdls_evt_callback tdls_event_cb;
+	void *tdls_evt_cb_data;
+	void *tdls_peer_context;
+	tdls_register_peer_callback tdls_reg_peer;
+	tdls_deregister_peer_callback tdls_dereg_peer;
+	tdls_dp_vdev_update_flags_callback tdls_dp_vdev_update;
+};
+
+/**
+ * struct tdls_add_peer_params - add peer request parameter
+ * @peer_addr: peer mac addr
+ * @peer_type: peer type
+ * @vdev_id: vdev id
+ */
+struct tdls_add_peer_params {
+	uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
+	uint32_t peer_type;
+	uint32_t vdev_id;
+};
+
+/**
+ * struct tdls_add_peer_request - peer add request
+ * @vdev: vdev
+ * @add_peer_req: add peer request parameters
+ */
+struct tdls_add_peer_request {
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_add_peer_params add_peer_req;
+};
+
+/**
+ * struct tdls_del_peer_params - delete peer request parameter
+ * @peer_addr: peer mac addr
+ * @peer_type: peer type
+ * @vdev_id: vdev id
+ */
+struct tdls_del_peer_params {
+	const uint8_t *peer_addr;
+	uint32_t peer_type;
+	uint32_t vdev_id;
+};
+
+/**
+ * struct tdls_del_peer_request - peer delete request
+ * @vdev: vdev
+ * @del_peer_req: delete peer request parameters
+ */
+struct tdls_del_peer_request {
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_del_peer_params del_peer_req;
+};
+
+/**
+ * struct vhgmcsinfo - VHT MCS information
+ * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams
+ * @rx_highest: Indicates highest long GI VHT PPDU data rate
+ *      STA can receive. Rate expressed in units of 1 Mbps.
+ *      If this field is 0 this value should not be used to
+ *      consider the highest RX data rate supported.
+ * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams
+ * @tx_highest: Indicates highest long GI VHT PPDU data rate
+ *      STA can transmit. Rate expressed in units of 1 Mbps.
+ *      If this field is 0 this value should not be used to
+ *      consider the highest TX data rate supported.
+ */
+struct vhtmcsinfo {
+	uint16_t rx_mcs_map;
+	uint16_t rx_highest;
+	uint16_t tx_mcs_map;
+	uint16_t tx_highest;
+};
+
+/**
+ * struct vhtcap - VHT capabilities
+ *
+ * This structure is the "VHT capabilities element" as
+ * described in 802.11ac D3.0 8.4.2.160
+ * @vht_cap_info: VHT capability info
+ * @supp_mcs: VHT MCS supported rates
+ */
+struct vhtcap {
+	uint32_t vht_capinfo;
+	struct vhtmcsinfo supp_mcs;
+};
+
+struct tdls_update_peer_params {
+	uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
+	uint32_t peer_type;
+	uint32_t vdev_id;
+	uint16_t capability;
+	uint8_t extn_capability[WLAN_MAC_MAX_EXTN_CAP];
+	uint8_t supported_rates_len;
+	uint8_t supported_rates[WLAN_MAC_MAX_SUPP_RATES];
+	uint8_t htcap_present;
+	struct htcap_cmn_ie ht_cap;
+	uint8_t vhtcap_present;
+	struct vhtcap vht_cap;
+	uint8_t uapsd_queues;
+	uint8_t max_sp;
+	uint8_t supported_channels_len;
+	uint8_t supported_channels[WLAN_MAC_MAX_SUPP_CHANNELS];
+	uint8_t supported_oper_classes_len;
+	uint8_t supported_oper_classes[WLAN_MAX_SUPP_OPER_CLASSES];
+	bool is_qos_wmm_sta;
+};
+
+struct tdls_update_peer_request {
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_update_peer_params update_peer_req;
+};
+
+/**
+ * struct tdls_oper_request - tdls operation request
+ * @vdev: vdev object
+ * @peer_addr: MAC address of the TDLS peer
+ */
+struct tdls_oper_request {
+	struct wlan_objmgr_vdev *vdev;
+	uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
+};
+
+/**
+ * struct tdls_oper_config_force_peer_request - tdls enable force peer request
+ * @vdev: vdev object
+ * @peer_addr: MAC address of the TDLS peer
+ * @chan: channel
+ * @max_latency: maximum latency
+ * @op_class: operation class
+ * @min_bandwidth: minimal bandwidth
+ * @callback: state change callback
+ */
+struct tdls_oper_config_force_peer_request {
+	struct wlan_objmgr_vdev *vdev;
+	uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
+	uint32_t chan;
+	uint32_t max_latency;
+	uint32_t op_class;
+	uint32_t min_bandwidth;
+	tdls_state_change_callback callback;
+};
+
+/**
+ * struct tdls_info - tdls info
+ *
+ * @vdev_id: vdev id
+ * @tdls_state: tdls state
+ * @notification_interval_ms: notification interval in ms
+ * @tx_discovery_threshold: tx discovery threshold
+ * @tx_teardown_threshold: tx teardown threshold
+ * @rssi_teardown_threshold: rx teardown threshold
+ * @rssi_delta: rssi delta
+ * @tdls_options: tdls options
+ * @peer_traffic_ind_window: peer traffic indication window
+ * @peer_traffic_response_timeout: peer traffic response timeout
+ * @puapsd_mask: puapsd mask
+ * @puapsd_inactivity_time: puapsd inactivity time
+ * @puapsd_rx_frame_threshold: puapsd rx frame threshold
+ * @teardown_notification_ms: tdls teardown notification interval
+ * @tdls_peer_kickout_threshold: tdls packets threshold
+ *    for peer kickout operation
+ */
+struct tdls_info {
+	uint32_t vdev_id;
+	uint32_t tdls_state;
+	uint32_t notification_interval_ms;
+	uint32_t tx_discovery_threshold;
+	uint32_t tx_teardown_threshold;
+	int32_t rssi_teardown_threshold;
+	int32_t rssi_delta;
+	uint32_t tdls_options;
+	uint32_t peer_traffic_ind_window;
+	uint32_t peer_traffic_response_timeout;
+	uint32_t puapsd_mask;
+	uint32_t puapsd_inactivity_time;
+	uint32_t puapsd_rx_frame_threshold;
+	uint32_t teardown_notification_ms;
+	uint32_t tdls_peer_kickout_threshold;
+};
+
+/**
+ * struct tdls_ch_params - channel parameters
+ * @chan_id: ID of the channel
+ * @pwr: power level
+ * @dfs_set: is dfs supported or not
+ * @half_rate: is the channel operating at 10MHz
+ * @quarter_rate: is the channel operating at 5MHz
+ */
+struct tdls_ch_params {
+	uint8_t chan_id;
+	uint8_t pwr;
+	bool dfs_set;
+	bool half_rate;
+	bool quarter_rate;
+};
+
+/**
+ * struct tdls_peer_params - TDLS peer capablities parameters
+ * @is_peer_responder: is peer responder or not
+ * @peer_uapsd_queue: peer uapsd queue
+ * @peer_max_sp: peer max SP value
+ * @peer_buff_sta_support: peer buffer sta supported or not
+ * @peer_off_chan_support: peer offchannel support
+ * @peer_curr_operclass: peer current operating class
+ * @self_curr_operclass: self current operating class
+ * @peer_chanlen: peer channel length
+ * @peer_chan: peer channel list
+ * @peer_oper_classlen: peer operating class length
+ * @peer_oper_class: peer operating class
+ * @pref_off_channum: peer offchannel number
+ * @pref_off_chan_bandwidth: peer offchannel bandwidth
+ * @opclass_for_prefoffchan: operating class for offchannel
+ */
+struct tdls_peer_params {
+	uint8_t is_peer_responder;
+	uint8_t peer_uapsd_queue;
+	uint8_t peer_max_sp;
+	uint8_t peer_buff_sta_support;
+	uint8_t peer_off_chan_support;
+	uint8_t peer_curr_operclass;
+	uint8_t self_curr_operclass;
+	uint8_t peer_chanlen;
+	struct tdls_ch_params peer_chan[WLAN_MAC_WMI_MAX_SUPP_CHANNELS];
+	uint8_t peer_oper_classlen;
+	uint8_t peer_oper_class[WLAN_MAX_SUPP_OPER_CLASSES];
+	uint8_t pref_off_channum;
+	uint8_t pref_off_chan_bandwidth;
+	uint8_t opclass_for_prefoffchan;
+};
+
+/**
+ * struct tdls_peer_update_state - TDLS peer state parameters
+ * @vdev_id: vdev id
+ * @peer_macaddr: peer mac address
+ * @peer_cap: peer capabality
+ * @resp_reqd: response needed
+ */
+struct tdls_peer_update_state {
+	uint32_t vdev_id;
+	uint8_t peer_macaddr[QDF_MAC_ADDR_SIZE];
+	uint32_t peer_state;
+	struct tdls_peer_params peer_cap;
+	bool resp_reqd;
+};
+
+/**
+ * struct tdls_channel_switch_params - channel switch parameter structure
+ * @vdev_id: vdev ID
+ * @peer_mac_addr: Peer mac address
+ * @tdls_off_ch_bw_offset: Target off-channel bandwitdh offset
+ * @tdls_off_ch: Target Off Channel
+ * @oper_class: Operating class for target channel
+ * @is_responder: Responder or initiator
+ */
+struct tdls_channel_switch_params {
+	uint32_t    vdev_id;
+	uint8_t     peer_mac_addr[QDF_MAC_ADDR_SIZE];
+	uint16_t    tdls_off_ch_bw_offset;
+	uint8_t     tdls_off_ch;
+	uint8_t     tdls_sw_mode;
+	uint8_t     oper_class;
+	uint8_t     is_responder;
+};
+
+/**
+ * enum uapsd_access_cat - U-APSD Access Categories
+ * @UAPSD_AC_BE: best effort
+ * @UAPSD_AC_BK: back ground
+ * @UAPSD_AC_VI: video
+ * @UAPSD_AC_VO: voice
+ */
+enum uapsd_access_cat {
+	UAPSD_AC_BE,
+	UAPSD_AC_BK,
+	UAPSD_AC_VI,
+	UAPSD_AC_VO
+};
+
+/**
+ * enum tspec_dir_type - TSPEC Direction type
+ * @TX_DIR: uplink
+ * @RX_DIR: downlink
+ * @BI_DIR: bidirectional
+ */
+enum tspec_dir_type {
+	TX_DIR = 0,
+	RX_DIR = 1,
+	BI_DIR = 2,
+};
+
+/**
+ * struct sta_uapsd_params - uapsd auto trig params
+ * @wmm_ac: WMM access category from 0 to 3
+ * @user_priority: User priority to use in trigger frames
+ * @service_interval: service interval
+ * @suspend_interval: suspend interval
+ * @delay_interval: delay interval
+ */
+struct sta_uapsd_params {
+	uint32_t wmm_ac;
+	uint32_t user_priority;
+	uint32_t service_interval;
+	uint32_t suspend_interval;
+	uint32_t delay_interval;
+};
+
+/**
+ * struct sta_uapsd_trig_params - uapsd trigger parameter
+ * @vdevid: vdev id
+ * @peer_addr: peer address
+ * @auto_triggerparam: trigger parameters
+ * @num_ac: no of access category
+ */
+struct sta_uapsd_trig_params {
+	uint32_t vdevid;
+	uint8_t peer_addr[QDF_MAC_ADDR_SIZE];
+	struct sta_uapsd_params *auto_triggerparam;
+	uint32_t num_ac;
+};
+
+/**
+ * struct tdls_event_info - firmware tdls event
+ * @vdev_id: vdev id
+ * @peermac: peer mac address
+ * @message_type: message type
+ * @peer_reason: reason
+ */
+struct tdls_event_info {
+	uint8_t vdev_id;
+	struct qdf_mac_addr peermac;
+	uint16_t message_type;
+	uint32_t peer_reason;
+};
+
+/**
+ * struct tdls_event_notify - tdls event notify
+ * @vdev: vdev object
+ * @event: tdls event
+ */
+struct tdls_event_notify {
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_event_info event;
+};
+
+/**
+ * struct tdls_event_notify - tdls event notify
+ * @peer_mac: peer's mac address
+ * @frame_type: Type of TDLS mgmt frame to be sent
+ * @dialog: dialog token used in the frame.
+ * @status_code: status to be incuded in the frame
+ * @responder: Tdls request type
+ * @peer_capability: peer cpabilities
+ * @len: length of additional Ies
+ * @buf: additional IEs to be included
+ */
+struct tdls_send_mgmt {
+	struct qdf_mac_addr peer_mac;
+	uint8_t frame_type;
+	uint8_t dialog;
+	uint16_t status_code;
+	uint8_t responder;
+	uint32_t peer_capability;
+	uint8_t len;
+	/* Variable length, do not add anything after this */
+	uint8_t buf[];
+};
+
+/**
+ * struct tdls_validate_action_req - tdls validate mgmt request
+ * @vdev: vdev object
+ * @action_code: action code
+ * @peer_mac: peer mac address
+ * @dialog_token: dialog code
+ * @status_code: status code to add
+ * @len: len of the frame
+ * @responder: whether to respond or not
+ * @max_sta_failed: mgmt failure reason
+ */
+struct tdls_validate_action_req {
+	struct wlan_objmgr_vdev *vdev;
+	uint8_t action_code;
+	uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
+	uint8_t dialog_token;
+	uint8_t status_code;
+	size_t len;
+	int responder;
+	int max_sta_failed;
+};
+
+/**
+ * struct tdls_get_all_peers - get all peers from the list
+ * @vdev: vdev object
+ * @buf: output string buffer to hold the peer info
+ * @buf_len: the size of output string buffer
+ */
+struct tdls_get_all_peers {
+	struct wlan_objmgr_vdev *vdev;
+	char *buf;
+	int buf_len;
+};
+
+/**
+ * struct tdls_send_action_frame_request - tdls send mgmt request
+ * @vdev: vdev object
+ * @chk_frame: frame validation structure
+ * @session_id: session id
+ * @vdev_id: vdev id
+ * @cmd_buf: cmd buffer
+ * @len: length of the frame
+ * @use_default_ac: access category
+ * @tdls_mgmt: tdls management
+ */
+struct tdls_action_frame_request {
+	struct wlan_objmgr_vdev *vdev;
+	struct tdls_validate_action_req *chk_frame;
+	uint8_t session_id;
+	uint8_t vdev_id;
+	const uint8_t *cmd_buf;
+	uint8_t len;
+	bool use_default_ac;
+	/* Variable length, do not add anything after this */
+	struct tdls_send_mgmt tdls_mgmt;
+};
+
+/**
+ * struct tdls_set_responder_req - tdls set responder in peer
+ * @vdev: vdev object
+ * @peer_mac: peer mac address
+ * @responder: whether to respond or not
+ */
+struct tdls_set_responder_req {
+	struct wlan_objmgr_vdev *vdev;
+	uint8_t peer_mac[QDF_MAC_ADDR_SIZE];
+	uint8_t responder;
+};
+
+/**
+ * struct tdls_sta_notify_params - STA connection notify info
+ * @vdev: vdev object
+ * @tdls_prohibited: peer mac addr
+ * @tdls_chan_swit_prohibited: peer type
+ * @lfr_roam: is trigger due to lfr
+ * @session_id: session id
+ */
+struct tdls_sta_notify_params {
+	struct wlan_objmgr_vdev *vdev;
+	bool tdls_prohibited;
+	bool tdls_chan_swit_prohibited;
+	bool lfr_roam;
+	bool user_disconnect;
+	uint8_t session_id;
+};
+
+/**
+ * struct tdls_delete_all_peers_params - TDLS set mode params
+ * @vdev: vdev object
+ */
+struct tdls_delete_all_peers_params {
+	struct wlan_objmgr_vdev *vdev;
+};
+
+/**
+ * struct tdls_set_mode_params - TDLS set mode params
+ * @vdev: vdev object
+ * @tdls_mode: tdls mode to set
+ * @update_last: inform to update last tdls mode
+ * @source: mode change requester
+ */
+struct tdls_set_mode_params {
+	struct wlan_objmgr_vdev *vdev;
+	enum tdls_feature_mode tdls_mode;
+	bool update_last;
+	enum tdls_disable_sources source;
+};
+
+/**
+ * struct tdls_del_all_tdls_peers - delete all tdls peers
+ * @msg_type: type of message
+ * @msg_len: length of message
+ * @bssid: bssid of peer device
+ */
+struct tdls_del_all_tdls_peers {
+	uint16_t msg_type;
+	uint16_t msg_len;
+	struct qdf_mac_addr bssid;
+};
+
+/**
+ * struct tdls_antenna_switch_request - TDLS antenna switch request
+ * @vdev: vdev object
+ * @mode: antenna mode, 1x1 or 2x2
+ */
+struct tdls_antenna_switch_request {
+	struct wlan_objmgr_vdev *vdev;
+	uint32_t mode;
+};
+
+/**
+ * struct tdls_set_offchannel - TDLS set offchannel
+ * @vdev: vdev object
+ * @offchannel: Updated tdls offchannel value.
+ * @callback: callback to release vdev ref.
+ */
+struct tdls_set_offchannel {
+	struct wlan_objmgr_vdev *vdev;
+	uint16_t offchannel;
+	tdls_offchan_parms_callback callback;
+};
+
+/**
+ * struct tdls_set_offchan_mode - TDLS set offchannel mode
+ * @vdev: vdev object
+ * @offchan_mode: Updated tdls offchannel mode value.
+ * @callback: callback to release vdev ref.
+ */
+struct tdls_set_offchanmode {
+	struct wlan_objmgr_vdev *vdev;
+	uint8_t offchan_mode;
+	tdls_offchan_parms_callback callback;
+};
+
+/**
+ * struct tdls_set_offchan_offset - TDLS set offchannel mode
+ * @vdev: vdev object
+ * @offchan_offset: Offchan offset value.
+ * @callback: callback to release vdev ref.
+ */
+struct tdls_set_secoffchanneloffset {
+	struct wlan_objmgr_vdev *vdev;
+	int offchan_offset;
+	tdls_offchan_parms_callback callback;
+};
+
+#endif

+ 173 - 0
components/tdls/dispatcher/inc/wlan_tdls_tgt_api.h

@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_tgt_api.h
+ *
+ * TDLS south bound interface declaration
+ */
+
+#ifndef _WLAN_TDLS_TGT_API_H_
+#define _WLAN_TDLS_TGT_API_H_
+#include <wlan_tdls_public_structs.h>
+#include "../../core/src/wlan_tdls_main.h"
+
+/**
+ * tgt_tdls_set_fw_state() - invoke lmac tdls update fw
+ * @psoc: soc object
+ * @tdls_param: update tdls state parameters
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_set_fw_state(struct wlan_objmgr_psoc *psoc,
+				 struct tdls_info *tdls_param);
+
+/**
+ * tgt_tdls_set_peer_state() - invoke lmac tdls update peer state
+ * @psoc: soc object
+ * @peer_param: update tdls peer parameters
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_set_peer_state(struct wlan_objmgr_psoc *psoc,
+				   struct tdls_peer_update_state *peer_param);
+
+/**
+ * tgt_tdls_set_offchan_mode() - invoke lmac tdls set off-channel mode
+ * @psoc: soc object
+ * @param: set tdls off channel parameters
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc,
+				     struct tdls_channel_switch_params *param);
+
+/**
+ * tgt_tdls_set_uapsd()- invoke lamc tdls set uapsd function
+ * @psoc: soc object
+ * @params: uapsd parameters
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_set_uapsd(struct wlan_objmgr_psoc *psoc,
+			      struct sta_uapsd_trig_params *params);
+
+/**
+ * tgt_tdls_send_mgmt_rsp() - process tdls mgmt response
+ * @pmsg: sheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_send_mgmt_rsp(struct scheduler_msg *pmsg);
+
+/**
+ * tgt_tdls_send_mgmt_tx_completion() -process tx completion message
+ * @pmsg: sheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_send_mgmt_tx_completion(struct scheduler_msg *pmsg);
+
+/**
+ * tgt_tdls_del_peer_rsp() - handle TDLS del peer response
+ * @pmsg: sheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_del_peer_rsp(struct scheduler_msg *pmsg);
+
+/**
+ * tgt_tdls_add_peer_rsp() - handle TDLS add peer response
+ * @pmsg: sheduler msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS tgt_tdls_add_peer_rsp(struct scheduler_msg *pmsg);
+
+/**
+ * tgt_tdls_register_ev_handler() - invoke lmac register tdls event handler
+ * @psoc: soc object
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code.
+ */
+QDF_STATUS tgt_tdls_register_ev_handler(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tgt_tdls_unregister_ev_handler() - invoke lmac unregister tdls event handler
+ * @psoc: soc object
+ *
+ * Return: QDF_STATUS_SUCCESS for success or error code.
+ */
+QDF_STATUS tgt_tdls_unregister_ev_handler(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * tgt_tdls_event_handler() - The callback registered to WMI for tdls events
+ * @psoc: psoc object
+ * @info: tdls event info
+ *
+ * The callback is registered by tgt as tdls rx ops handler.
+ *
+ * Return: 0 for success or err code.
+ */
+QDF_STATUS
+tgt_tdls_event_handler(struct wlan_objmgr_psoc *psoc,
+		       struct tdls_event_info *info);
+
+/**
+ * tgt_tdls_mgmt_frame_rx_cb() - callback for rx mgmt frame
+ * @psoc: soc context
+ * @peer: peer context
+ * @buf: rx buffer
+ * @mgmt_rx_params: mgmt rx parameters
+ * @frm_type: frame type
+ *
+ * This function gets called from mgmt tx/rx component when rx mgmt
+ * received.
+ *
+ * Return: QDF_STATUS_SUCCESS
+ */
+QDF_STATUS tgt_tdls_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc,
+	struct wlan_objmgr_peer *peer, qdf_nbuf_t buf,
+	struct mgmt_rx_event_params *mgmt_rx_params,
+	enum mgmt_frame_type frm_type);
+
+/**
+ * tgt_tdls_peers_deleted_notification()- notification from legacy lim
+ * @psoc: soc object
+ * @session_id: session id
+ *
+ * This function called from legacy lim to notify tdls peer deletion
+ *
+ * Return: None
+ */
+void tgt_tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
+					 uint32_t session_id);
+
+/**
+ * tgt_tdls_delete_all_peers_indication()- Indication to tdls component
+ * @psoc: soc object
+ * @session_id: session id
+ *
+ * This function called from legacy lim to tdls component to delete tdls peers.
+ *
+ * Return: None
+ */
+void tgt_tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc,
+					  uint32_t session_id);
+
+#endif

+ 254 - 0
components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h

@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_ucfg_api.h
+ *
+ * TDLS north bound interface declaration
+ */
+
+#if !defined(_WLAN_TDLS_UCFG_API_H_)
+#define _WLAN_TDLS_UCFG_API_H_
+
+#include <scheduler_api.h>
+#include <wlan_tdls_public_structs.h>
+#include <wlan_objmgr_cmn.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+
+/**
+ * ucfg_tdls_init() - TDLS module initialization API
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_init(void);
+
+/**
+ * ucfg_tdls_deinit() - TDLS module deinitialization API
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_deinit(void);
+
+/**
+ * ucfg_tdls_psoc_open() - TDLS module psoc open API
+ * @psoc: psoc object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_psoc_open(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_tdls_psoc_close() - TDLS module psoc close API
+ * @psoc: psoc object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_psoc_close(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_tdls_psoc_start() - TDLS module start
+ * @psoc: psoc object
+ * @req: tdls start paramets
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc,
+				   struct tdls_start_params *req);
+
+/**
+ * ucfg_tdls_psoc_enable() - TDLS module enable API
+ * @psoc: psoc object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_psoc_enable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_tdls_psoc_disable() - TDLS moudle disable API
+ * @psoc: psoc object
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_psoc_disable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_tdls_add_peer() - handle TDLS add peer
+ * @vdev: vdev object
+ * @add_peer_req: add peer request parameters
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_add_peer(struct wlan_objmgr_vdev *vdev,
+			      struct tdls_add_peer_params *add_peer_req);
+
+/**
+ * ucfg_tdls_update_peer() - handle TDLS update peer
+ * @vdev: vdev object
+ * @update_peer: update TDLS request parameters
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_update_peer(struct wlan_objmgr_vdev *vdev,
+				 struct tdls_update_peer_params *update_peer);
+
+/**
+ * ucfg_tdls_oper() - handle TDLS oper functions
+ * @vdev: vdev object
+ * @macaddr: MAC address of TDLS peer
+ * @cmd: oper cmd
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_oper(struct wlan_objmgr_vdev *vdev,
+			  const uint8_t *macaddr, enum tdls_command_type cmd);
+
+/**
+ * ucfg_tdls_get_all_peers() - get all tdls peers from the list
+ * @vdev: vdev object
+ * @buf: output buffer
+ * @buflen: length of written data
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev,
+				   char *buf, int buflen);
+
+/**
+ * ucfg_tdls_send_mgmt_frame() - send TDLS mgmt frame
+ * @mgmt_req: pointer to TDLS action frame request struct
+ *
+ * This will TDLS action frames to peer
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_send_mgmt_frame(
+				struct tdls_action_frame_request *mgmt_req);
+
+/**
+ * ucfg_tdls_responder() - set responder in TDLS peer
+ * @msg_req: responder msg
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_responder(struct tdls_set_responder_req *msg_req);
+
+/**
+ * ucfg_tdls_teardown_links() - teardown all TDLS links
+ * @vdev: vdev object manager
+ *
+ * Return: None
+ */
+QDF_STATUS ucfg_tdls_teardown_links(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_tdls_notify_reset_adapter() - notify reset adapter
+ * @vdev: vdev object manager
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * ucfg_tdls_notify_sta_connect() - notify sta connect
+ * @notify_info: sta notification info
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_notify_sta_connect(
+			struct tdls_sta_notify_params *notify_info);
+
+/**
+ * ucfg_tdls_notify_sta_disconnect() - notify sta disconnect
+ * @notify_info: sta notification info
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_notify_sta_disconnect(
+			struct tdls_sta_notify_params *notify_info);
+
+/**
+ * ucfg_tdls_set_operating_mode() - set operating mode
+ * @set_mode_params: set mode params
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_set_operating_mode(
+			struct tdls_set_mode_params *set_mode_params);
+
+/**
+ * ucfg_tdls_update_rx_pkt_cnt() - update rx pkt count
+ * @vdev: tdls vdev object
+ * @mac_addr: peer mac address
+ *
+ * Return: None
+ */
+void ucfg_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
+				 struct qdf_mac_addr *mac_addr);
+
+/**
+ * ucfg_tdls_update_tx_pkt_cnt() - update tx pkt count
+ * @vdev: tdls vdev object
+ * @mac_addr: peer mac address
+ *
+ * Return: None
+ */
+void ucfg_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
+				 struct qdf_mac_addr *mac_addr);
+
+/**
+ * ucfg_tdls_antenna_switch() - tdls antenna switch
+ * @vdev: tdls vdev object
+ * @mode: antenna mode
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev,
+				    uint32_t mode);
+
+/**
+ * ucfg_set_tdls_offchannel() - Handle TDLS set offchannel
+ * @vdev: vdev object
+ * @offchannel: updated offchannel
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_set_tdls_offchannel(struct wlan_objmgr_vdev *vdev,
+				    int offchannel);
+
+/**
+ * ucfg_set_tdls_offchan_mode() - Handle TDLS set offchannel mode
+ * @vdev: vdev object
+ * @offchanmode: updated off-channel mode
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_set_tdls_offchan_mode(struct wlan_objmgr_vdev *vdev,
+				      int offchanmode);
+
+/**
+ * ucfg_set_tdls_secoffchanneloffset() - Handle TDLS set offchannel offset
+ * @vdev: vdev object
+ * @offchanoffset: tdls off-channel offset
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_set_tdls_secoffchanneloffset(struct wlan_objmgr_vdev *vdev,
+					     int offchanoffset);
+#endif

+ 324 - 0
components/tdls/dispatcher/src/wlan_tdls_cfg.c

@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. 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: This file contains TDLS configures interface definitions
+ */
+
+#include <wlan_objmgr_psoc_obj.h>
+#include "wlan_tdls_cfg_api.h"
+#include "../../core/src/wlan_tdls_main.h"
+
+QDF_STATUS
+cfg_tdls_get_support_enable(struct wlan_objmgr_psoc *psoc,
+			    bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_support_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_support_enable(struct wlan_objmgr_psoc *psoc,
+			    bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_support_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_external_control(struct wlan_objmgr_psoc *psoc,
+			      bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_external_control;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_uapsd_mask(struct wlan_objmgr_psoc *psoc,
+			uint32_t *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = 0;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_uapsd_mask;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_buffer_sta_enable(struct wlan_objmgr_psoc *psoc,
+			       bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_buffer_sta_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_buffer_sta_enable(struct wlan_objmgr_psoc *psoc,
+			       bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_buffer_sta_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_uapsd_inactivity_time(struct wlan_objmgr_psoc *psoc,
+				   uint32_t *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = 0;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_uapsd_inactivity_time;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_rx_pkt_threshold(struct wlan_objmgr_psoc *psoc,
+			      uint32_t *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = 0;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_rx_pkt_threshold;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_off_channel_enable(struct wlan_objmgr_psoc *psoc,
+				bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_off_chan_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_off_channel_enable(struct wlan_objmgr_psoc *psoc,
+				bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_off_chan_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_wmm_mode_enable(struct wlan_objmgr_psoc *psoc,
+			     bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_wmm_mode_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_vdev_nss_2g(struct wlan_objmgr_psoc *psoc,
+			 uint8_t val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_vdev_nss_2g = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_vdev_nss_5g(struct wlan_objmgr_psoc *psoc,
+			 uint8_t val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_vdev_nss_5g = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_sleep_sta_enable(struct wlan_objmgr_psoc *psoc,
+			      bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_sleep_sta_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_sleep_sta_enable(struct wlan_objmgr_psoc *psoc,
+			      bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_sleep_sta_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_scan_enable(struct wlan_objmgr_psoc *psoc,
+			 bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_scan_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_scan_enable(struct wlan_objmgr_psoc *psoc,
+			 bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_scan_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}

+ 383 - 0
components/tdls/dispatcher/src/wlan_tdls_tgt_api.c

@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_tgt_api.c
+ *
+ * TDLS south bound interface definitions
+ */
+
+#include "qdf_status.h"
+#include <wlan_tdls_tgt_api.h>
+#include "../../core/src/wlan_tdls_main.h"
+#include "../../core/src/wlan_tdls_cmds_process.h"
+#include "../../core/src/wlan_tdls_mgmt.h"
+
+static inline struct wlan_lmac_if_tdls_tx_ops *
+wlan_psoc_get_tdls_txops(struct wlan_objmgr_psoc *psoc)
+{
+	return &psoc->soc_cb.tx_ops.tdls_tx_ops;
+}
+
+static inline struct wlan_lmac_if_tdls_rx_ops *
+wlan_psoc_get_tdls_rxops(struct wlan_objmgr_psoc *psoc)
+{
+	return &psoc->soc_cb.rx_ops.tdls_rx_ops;
+}
+
+QDF_STATUS tgt_tdls_set_fw_state(struct wlan_objmgr_psoc *psoc,
+				 struct tdls_info *tdls_param)
+{
+	struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL;
+
+	tdls_ops = wlan_psoc_get_tdls_txops(psoc);
+	if (tdls_ops && tdls_ops->update_fw_state)
+		return tdls_ops->update_fw_state(psoc, tdls_param);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tgt_tdls_set_peer_state(struct wlan_objmgr_psoc *psoc,
+				   struct tdls_peer_update_state *peer_param)
+{
+	struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL;
+
+	tdls_ops = wlan_psoc_get_tdls_txops(psoc);
+	if (tdls_ops && tdls_ops->update_peer_state)
+		return tdls_ops->update_peer_state(psoc, peer_param);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tgt_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc,
+				     struct tdls_channel_switch_params *param)
+{
+	struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL;
+
+	tdls_ops = wlan_psoc_get_tdls_txops(psoc);
+	if (tdls_ops && tdls_ops->set_offchan_mode)
+		return tdls_ops->set_offchan_mode(psoc, param);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tgt_tdls_set_uapsd(struct wlan_objmgr_psoc *psoc,
+			      struct sta_uapsd_trig_params *params)
+{
+	struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL;
+
+	tdls_ops = wlan_psoc_get_tdls_txops(psoc);
+	if (tdls_ops && tdls_ops->tdls_set_uapsd)
+		return tdls_ops->tdls_set_uapsd(psoc, params);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tgt_tdls_send_mgmt_tx_completion(struct scheduler_msg *pmsg)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!pmsg || !pmsg->bodyptr) {
+		tdls_err("msg: 0x%pK", pmsg);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	status = tdls_send_mgmt_tx_completion(pmsg->bodyptr);
+
+	return status;
+}
+
+QDF_STATUS tgt_tdls_send_mgmt_rsp(struct scheduler_msg *pmsg)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!pmsg || !pmsg->bodyptr) {
+		tdls_err("msg: 0x%pK", pmsg);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	status = tdls_process_send_mgmt_rsp(pmsg->bodyptr);
+
+	return status;
+}
+
+QDF_STATUS tgt_tdls_add_peer_rsp(struct scheduler_msg *pmsg)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!pmsg || !pmsg->bodyptr) {
+		tdls_err("msg: 0x%pK", pmsg);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	status = tdls_process_add_peer_rsp(pmsg->bodyptr);
+
+	return status;
+}
+
+QDF_STATUS tgt_tdls_del_peer_rsp(struct scheduler_msg *pmsg)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!pmsg || !pmsg->bodyptr) {
+		tdls_err("msg: 0x%pK", pmsg);
+		QDF_ASSERT(0);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	status = tdls_process_del_peer_rsp(pmsg->bodyptr);
+
+	return status;
+}
+
+QDF_STATUS tgt_tdls_register_ev_handler(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL;
+
+	tdls_ops = wlan_psoc_get_tdls_txops(psoc);
+	if (tdls_ops && tdls_ops->tdls_reg_ev_handler)
+		return tdls_ops->tdls_reg_ev_handler(psoc, NULL);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS tgt_tdls_unregister_ev_handler(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL;
+
+	tdls_ops = wlan_psoc_get_tdls_txops(psoc);
+	if (tdls_ops->tdls_unreg_ev_handler)
+		return tdls_ops->tdls_unreg_ev_handler(psoc, NULL);
+	else
+		return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS tgt_tdls_event_flush_cb(struct scheduler_msg *msg)
+{
+	struct tdls_event_notify *notify;
+
+	notify = msg->bodyptr;
+	if (notify && notify->vdev) {
+		wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_SB_ID);
+		qdf_mem_free(notify);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+tgt_tdls_event_handler(struct wlan_objmgr_psoc *psoc,
+		       struct tdls_event_info *info)
+{
+	struct scheduler_msg msg = {0,};
+	struct tdls_event_notify *notify;
+	uint8_t vdev_id;
+	QDF_STATUS status;
+
+	if (!psoc || !info) {
+		tdls_err("psoc: 0x%pK, info: 0x%pK", psoc, info);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	tdls_debug("vdev: %d, type: %d, reason: %d" QDF_MAC_ADDR_STR,
+		   info->vdev_id, info->message_type, info->peer_reason,
+		   QDF_MAC_ADDR_ARRAY(info->peermac.bytes));
+	notify = qdf_mem_malloc(sizeof(*notify));
+	if (!notify) {
+		tdls_err("mem allocate fail");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	vdev_id = info->vdev_id;
+	notify->vdev =
+		wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+						     vdev_id, WLAN_TDLS_SB_ID);
+	if (!notify->vdev) {
+		tdls_err("null vdev, vdev_id: %d, psoc: 0x%pK", vdev_id, psoc);
+		return QDF_STATUS_E_INVAL;
+	}
+	qdf_mem_copy(&notify->event, info, sizeof(*info));
+
+	msg.bodyptr = notify;
+	msg.callback = tdls_process_evt;
+	msg.flush_callback = tgt_tdls_event_flush_cb;
+
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TARGET_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't post msg to handle tdls event");
+		wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_SB_ID);
+		qdf_mem_free(notify);
+	}
+
+	return status;
+}
+
+static QDF_STATUS tgt_tdls_mgmt_frame_rx_flush_cb(struct scheduler_msg *msg)
+{
+	struct tdls_rx_mgmt_event *rx_mgmt_event;
+
+	rx_mgmt_event = msg->bodyptr;
+
+	if (rx_mgmt_event) {
+		if (rx_mgmt_event->rx_mgmt)
+			qdf_mem_free(rx_mgmt_event->rx_mgmt);
+
+		qdf_mem_free(rx_mgmt_event);
+	}
+	msg->bodyptr = NULL;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static
+QDF_STATUS tgt_tdls_mgmt_frame_process_rx_cb(
+			struct wlan_objmgr_psoc *psoc,
+			struct wlan_objmgr_peer *peer,
+			qdf_nbuf_t buf,
+			struct mgmt_rx_event_params *mgmt_rx_params,
+			enum mgmt_frame_type frm_type)
+{
+	struct tdls_rx_mgmt_frame *rx_mgmt;
+	struct tdls_rx_mgmt_event *rx_mgmt_event;
+	struct tdls_soc_priv_obj *tdls_soc_obj;
+	struct scheduler_msg msg = {0};
+	struct wlan_objmgr_vdev *vdev;
+	uint32_t vdev_id;
+	uint8_t *pdata;
+	QDF_STATUS status;
+
+	tdls_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+			WLAN_UMAC_COMP_TDLS);
+	if (!tdls_soc_obj) {
+		tdls_err("tdls ctx is NULL, drop this frame");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	if (!peer) {
+		vdev = tdls_get_vdev(psoc, WLAN_TDLS_SB_ID);
+		if (!vdev) {
+			tdls_err("current tdls vdev is null, can't get vdev id");
+			return QDF_STATUS_E_FAILURE;
+		}
+		vdev_id = wlan_vdev_get_id(vdev);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
+	} else {
+		vdev = wlan_peer_get_vdev(peer);
+		if (!vdev) {
+			tdls_err("vdev is NULL in peer, drop this frame");
+			return QDF_STATUS_E_FAILURE;
+		}
+		vdev_id = wlan_vdev_get_id(vdev);
+	}
+
+	rx_mgmt_event = qdf_mem_malloc(sizeof(*rx_mgmt_event));
+	if (!rx_mgmt_event) {
+		tdls_err("Failed to allocate rx mgmt event");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	rx_mgmt = qdf_mem_malloc(sizeof(*rx_mgmt) +
+			mgmt_rx_params->buf_len);
+	if (!rx_mgmt) {
+		tdls_err("Failed to allocate rx mgmt frame");
+		qdf_mem_free(rx_mgmt_event);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	pdata = (uint8_t *)qdf_nbuf_data(buf);
+	rx_mgmt->frame_len = mgmt_rx_params->buf_len;
+	rx_mgmt->rx_chan = mgmt_rx_params->channel;
+	rx_mgmt->vdev_id = vdev_id;
+	rx_mgmt->frm_type = frm_type;
+	rx_mgmt->rx_rssi = mgmt_rx_params->rssi;
+
+	rx_mgmt_event->rx_mgmt = rx_mgmt;
+	rx_mgmt_event->tdls_soc_obj = tdls_soc_obj;
+	qdf_mem_copy(rx_mgmt->buf, pdata, mgmt_rx_params->buf_len);
+	msg.type = TDLS_EVENT_RX_MGMT;
+	msg.bodyptr = rx_mgmt_event;
+	msg.callback = tdls_process_rx_frame;
+	msg.flush_callback = tgt_tdls_mgmt_frame_rx_flush_cb;
+	status = scheduler_post_message(QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TARGET_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		qdf_mem_free(rx_mgmt);
+		qdf_mem_free(rx_mgmt_event);
+	}
+
+	qdf_nbuf_free(buf);
+
+	return status;
+}
+
+QDF_STATUS tgt_tdls_mgmt_frame_rx_cb(
+			struct wlan_objmgr_psoc *psoc,
+			struct wlan_objmgr_peer *peer,
+			qdf_nbuf_t buf,
+			struct mgmt_rx_event_params *mgmt_rx_params,
+			enum mgmt_frame_type frm_type)
+{
+	QDF_STATUS status;
+
+	tdls_debug("psoc:%pK, peer:%pK, type:%d", psoc, peer, frm_type);
+
+
+	if (!buf) {
+		tdls_err("rx frame buff is null buf:%pK", buf);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!mgmt_rx_params || !psoc) {
+		tdls_err("input is NULL mgmt_rx_params:%pK psoc:%pK, peer:%pK",
+			  mgmt_rx_params, psoc, peer);
+		status = QDF_STATUS_E_INVAL;
+		goto release_nbuf;
+	}
+
+	status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_SB_ID);
+	if (QDF_STATUS_SUCCESS != status)
+		goto release_nbuf;
+
+	status = tgt_tdls_mgmt_frame_process_rx_cb(psoc, peer, buf,
+						   mgmt_rx_params, frm_type);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID);
+
+	if (QDF_STATUS_SUCCESS != status)
+release_nbuf:
+		qdf_nbuf_free(buf);
+	return status;
+}
+
+void tgt_tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
+					 uint32_t session_id)
+{
+	tdls_peers_deleted_notification(psoc, session_id);
+}
+
+void tgt_tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc,
+					  uint32_t session_id)
+{
+
+	tdls_delete_all_peers_indication(psoc, session_id);
+}

+ 1127 - 0
components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c

@@ -0,0 +1,1127 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_ucfg_api.c
+ *
+ * TDLS north bound interface definitions
+ */
+
+#include <wlan_tdls_ucfg_api.h>
+#include <wlan_tdls_tgt_api.h>
+#include "../../core/src/wlan_tdls_main.h"
+#include "../../core/src/wlan_tdls_cmds_process.h"
+#include "../../core/src/wlan_tdls_ct.h"
+#include "../../core/src/wlan_tdls_mgmt.h"
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_cmn.h>
+#include "wlan_policy_mgr_api.h"
+#include "wlan_scan_ucfg_api.h"
+#include "wlan_tdls_cfg.h"
+#include "cfg_ucfg_api.h"
+
+QDF_STATUS ucfg_tdls_init(void)
+{
+	QDF_STATUS status;
+
+	tdls_notice("tdls module dispatcher init");
+	status = wlan_objmgr_register_psoc_create_handler(WLAN_UMAC_COMP_TDLS,
+		tdls_psoc_obj_create_notification, NULL);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("Failed to register psoc create handler for tdls");
+		return status;
+	}
+
+	status = wlan_objmgr_register_psoc_destroy_handler(WLAN_UMAC_COMP_TDLS,
+		tdls_psoc_obj_destroy_notification, NULL);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("Failed to register psoc delete handler for tdls");
+		goto fail_delete_psoc;
+	}
+
+	status = wlan_objmgr_register_vdev_create_handler(WLAN_UMAC_COMP_TDLS,
+		tdls_vdev_obj_create_notification, NULL);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("Failed to register vdev create handler for tdls");
+		goto fail_create_vdev;
+	}
+
+	status = wlan_objmgr_register_vdev_destroy_handler(WLAN_UMAC_COMP_TDLS,
+		tdls_vdev_obj_destroy_notification, NULL);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("Failed to register vdev create handler for tdls");
+		goto fail_delete_vdev;
+	}
+	tdls_notice("tdls module dispatcher init done");
+
+	return status;
+fail_delete_vdev:
+	wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_TDLS,
+		tdls_vdev_obj_create_notification, NULL);
+
+fail_create_vdev:
+	wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_TDLS,
+		tdls_psoc_obj_destroy_notification, NULL);
+
+fail_delete_psoc:
+	wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_TDLS,
+		tdls_psoc_obj_create_notification, NULL);
+
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_deinit(void)
+{
+	QDF_STATUS ret;
+
+	tdls_notice("tdls module dispatcher deinit");
+	ret = wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_TDLS,
+				tdls_psoc_obj_create_notification, NULL);
+	if (QDF_IS_STATUS_ERROR(ret))
+		tdls_err("Failed to unregister psoc create handler");
+
+	ret = wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_TDLS,
+				tdls_psoc_obj_destroy_notification, NULL);
+	if (QDF_IS_STATUS_ERROR(ret))
+		tdls_err("Failed to unregister psoc delete handler");
+
+	ret = wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_TDLS,
+				tdls_vdev_obj_create_notification, NULL);
+	if (QDF_IS_STATUS_ERROR(ret))
+		tdls_err("Failed to unregister vdev create handler");
+
+	ret = wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_TDLS,
+				tdls_vdev_obj_destroy_notification, NULL);
+
+	if (QDF_IS_STATUS_ERROR(ret))
+		tdls_err("Failed to unregister vdev delete handler");
+
+	return ret;
+}
+
+/**
+ * tdls_update_feature_flag() - update tdls feature flag
+ * @tdls_soc_obj:   pointer to tdls psoc object
+ *
+ * This function updates tdls feature flag
+ */
+static void
+tdls_update_feature_flag(struct tdls_soc_priv_obj *tdls_soc_obj)
+{
+	tdls_soc_obj->tdls_configs.tdls_feature_flags =
+		((tdls_soc_obj->tdls_configs.tdls_off_chan_enable ?
+		  1 << TDLS_FEATURE_OFF_CHANNEL : 0) |
+		 (tdls_soc_obj->tdls_configs.tdls_wmm_mode_enable ?
+		  1 << TDLS_FEATURE_WMM : 0) |
+		 (tdls_soc_obj->tdls_configs.tdls_buffer_sta_enable ?
+		  1 << TDLS_FEATURE_BUFFER_STA : 0) |
+		 (tdls_soc_obj->tdls_configs.tdls_sleep_sta_enable ?
+		  1 << TDLS_FEATURE_SLEEP_STA : 0) |
+		 (tdls_soc_obj->tdls_configs.tdls_scan_enable ?
+		  1 << TDLS_FEATURE_SCAN : 0) |
+		 (tdls_soc_obj->tdls_configs.tdls_support_enable ?
+		  1 << TDLS_FEATURE_ENABLE : 0) |
+		 (tdls_soc_obj->tdls_configs.tdls_implicit_trigger_enable ?
+		  1 << TDLS_FEAUTRE_IMPLICIT_TRIGGER : 0) |
+		 (tdls_soc_obj->tdls_configs.tdls_external_control ?
+		  1 << TDLS_FEATURE_EXTERNAL_CONTROL : 0));
+}
+
+/**
+ * tdls_object_init_params() - init parameters for tdls object
+ * @tdls_soc_obj: pointer to tdls psoc object
+ *
+ * This function init parameters for tdls object
+ */
+static QDF_STATUS tdls_object_init_params(
+	struct tdls_soc_priv_obj *tdls_soc_obj)
+{
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!tdls_soc_obj) {
+		tdls_err("invalid param");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	psoc = tdls_soc_obj->soc;
+	if (!psoc) {
+		tdls_err("invalid psoc object");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	tdls_soc_obj->tdls_configs.tdls_tx_states_period =
+			cfg_get(psoc, CFG_TDLS_TX_STATS_PERIOD);
+	tdls_soc_obj->tdls_configs.tdls_tx_pkt_threshold =
+			cfg_get(psoc, CFG_TDLS_TX_PACKET_THRESHOLD);
+	tdls_soc_obj->tdls_configs.tdls_rx_pkt_threshold =
+			cfg_get(psoc, CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD);
+	tdls_soc_obj->tdls_configs.tdls_max_discovery_attempt =
+			cfg_get(psoc, CFG_TDLS_MAX_DISCOVERY_ATTEMPT);
+	tdls_soc_obj->tdls_configs.tdls_idle_timeout =
+			cfg_get(psoc, CFG_TDLS_IDLE_TIMEOUT);
+	tdls_soc_obj->tdls_configs.tdls_idle_pkt_threshold =
+			cfg_get(psoc, CFG_TDLS_IDLE_PACKET_THRESHOLD);
+	tdls_soc_obj->tdls_configs.tdls_rssi_trigger_threshold =
+			cfg_get(psoc, CFG_TDLS_RSSI_TRIGGER_THRESHOLD);
+	tdls_soc_obj->tdls_configs.tdls_rssi_teardown_threshold =
+			cfg_get(psoc, CFG_TDLS_RSSI_TEARDOWN_THRESHOLD);
+	tdls_soc_obj->tdls_configs.tdls_rssi_delta =
+			cfg_get(psoc, CFG_TDLS_RSSI_DELTA);
+	tdls_soc_obj->tdls_configs.tdls_uapsd_mask =
+			cfg_get(psoc, CFG_TDLS_QOS_WMM_UAPSD_MASK);
+	tdls_soc_obj->tdls_configs.tdls_uapsd_inactivity_time =
+			cfg_get(psoc, CFG_TDLS_PUAPSD_INACT_TIME);
+	tdls_soc_obj->tdls_configs.tdls_uapsd_pti_window =
+			cfg_get(psoc, CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW);
+	tdls_soc_obj->tdls_configs.tdls_uapsd_ptr_timeout =
+			cfg_get(psoc, CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT);
+	tdls_soc_obj->tdls_configs.tdls_pre_off_chan_num =
+			cfg_get(psoc, CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM);
+	tdls_soc_obj->tdls_configs.tdls_pre_off_chan_bw =
+			cfg_get(psoc, CFG_TDLS_PREFERRED_OFF_CHANNEL_BW);
+	tdls_soc_obj->tdls_configs.tdls_peer_kickout_threshold =
+			cfg_get(psoc, CFG_TDLS_PEER_KICKOUT_THRESHOLD);
+	tdls_soc_obj->tdls_configs.delayed_trig_framint =
+			cfg_get(psoc, CFG_TDLS_DELAYED_TRGR_FRM_INT);
+	tdls_soc_obj->tdls_configs.tdls_wmm_mode_enable =
+			cfg_get(psoc,  CFG_TDLS_WMM_MODE_ENABLE);
+	tdls_soc_obj->tdls_configs.tdls_off_chan_enable =
+			cfg_get(psoc, CFG_TDLS_OFF_CHANNEL_ENABLED);
+	tdls_soc_obj->tdls_configs.tdls_buffer_sta_enable =
+			cfg_get(psoc, CFG_TDLS_BUF_STA_ENABLED);
+	tdls_soc_obj->tdls_configs.tdls_scan_enable =
+			cfg_get(psoc, CFG_TDLS_SCAN_ENABLE);
+	tdls_soc_obj->tdls_configs.tdls_support_enable =
+			cfg_get(psoc, CFG_TDLS_SUPPORT_ENABLE);
+	tdls_soc_obj->tdls_configs.tdls_implicit_trigger_enable =
+			cfg_get(psoc, CFG_TDLS_IMPLICIT_TRIGGER);
+	tdls_soc_obj->tdls_configs.tdls_external_control =
+			cfg_get(psoc, CFG_TDLS_EXTERNAL_CONTROL);
+
+	tdls_update_feature_flag(tdls_soc_obj);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS tdls_global_init(struct tdls_soc_priv_obj *soc_obj)
+{
+	uint8_t sta_idx;
+	uint32_t feature;
+
+	tdls_object_init_params(soc_obj);
+	soc_obj->connected_peer_count = 0;
+	soc_obj->tdls_nss_switch_in_progress = false;
+	soc_obj->tdls_teardown_peers_cnt = 0;
+	soc_obj->tdls_nss_teardown_complete = false;
+	soc_obj->tdls_nss_transition_mode = TDLS_NSS_TRANSITION_S_UNKNOWN;
+
+	feature = soc_obj->tdls_configs.tdls_feature_flags;
+	if (TDLS_IS_BUFFER_STA_ENABLED(feature) ||
+	    TDLS_IS_SLEEP_STA_ENABLED(feature) ||
+	    TDLS_IS_OFF_CHANNEL_ENABLED(feature))
+		soc_obj->max_num_tdls_sta =
+			WLAN_TDLS_STA_P_UAPSD_OFFCHAN_MAX_NUM;
+		else
+			soc_obj->max_num_tdls_sta = WLAN_TDLS_STA_MAX_NUM;
+
+	for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta; sta_idx++) {
+		soc_obj->tdls_conn_info[sta_idx].sta_id = INVALID_TDLS_PEER_ID;
+		soc_obj->tdls_conn_info[sta_idx].session_id = 255;
+		qdf_mem_zero(&soc_obj->tdls_conn_info[sta_idx].peer_mac,
+			     QDF_MAC_ADDR_SIZE);
+	}
+	soc_obj->enable_tdls_connection_tracker = false;
+	soc_obj->tdls_external_peer_count = 0;
+	soc_obj->tdls_disable_in_progress = false;
+
+	qdf_spinlock_create(&soc_obj->tdls_ct_spinlock);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS tdls_global_deinit(struct tdls_soc_priv_obj *soc_obj)
+{
+	qdf_spinlock_destroy(&soc_obj->tdls_ct_spinlock);
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS ucfg_tdls_psoc_open(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+	struct tdls_soc_priv_obj *soc_obj;
+
+	tdls_debug("tdls psoc open");
+	soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+							WLAN_UMAC_COMP_TDLS);
+	if (!soc_obj) {
+		tdls_err("Failed to get tdls psoc component");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = tdls_global_init(soc_obj);
+
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc,
+				   struct tdls_start_params *req)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+	uint32_t tdls_feature_flags;
+	struct policy_mgr_tdls_cbacks tdls_pm_call_backs;
+
+	tdls_debug("tdls update config ");
+	if (!psoc || !req) {
+		tdls_err("psoc: 0x%pK, req: 0x%pK", psoc, req);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+							WLAN_UMAC_COMP_TDLS);
+	if (!soc_obj) {
+		tdls_err("Failed to get tdls psoc component");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	soc_obj->tdls_rx_cb = req->tdls_rx_cb;
+	soc_obj->tdls_rx_cb_data = req->tdls_rx_cb_data;
+
+	soc_obj->tdls_wmm_cb = req->tdls_wmm_cb;
+	soc_obj->tdls_wmm_cb_data = req->tdls_wmm_cb_data;
+
+	soc_obj->tdls_event_cb = req->tdls_event_cb;
+	soc_obj->tdls_evt_cb_data = req->tdls_evt_cb_data;
+
+	/* Save callbacks to register/deregister TDLS sta with datapath */
+	soc_obj->tdls_reg_peer = req->tdls_reg_peer;
+	soc_obj->tdls_dereg_peer = req->tdls_dereg_peer;
+	soc_obj->tdls_peer_context = req->tdls_peer_context;
+
+	/* Save legacy PE/WMA commands in TDLS soc object */
+	soc_obj->tdls_send_mgmt_req = req->tdls_send_mgmt_req;
+	soc_obj->tdls_add_sta_req = req->tdls_add_sta_req;
+	soc_obj->tdls_del_sta_req = req->tdls_del_sta_req;
+	soc_obj->tdls_update_peer_state = req->tdls_update_peer_state;
+	soc_obj->tdls_del_all_peers = req->tdls_del_all_peers;
+	soc_obj->tdls_update_dp_vdev_flags = req->tdls_update_dp_vdev_flags;
+	soc_obj->tdls_dp_vdev_update = req->tdls_dp_vdev_update;
+	tdls_pm_call_backs.tdls_notify_increment_session =
+			tdls_notify_increment_session;
+
+	tdls_pm_call_backs.tdls_notify_decrement_session =
+			tdls_notify_decrement_session;
+	if (QDF_STATUS_SUCCESS != policy_mgr_register_tdls_cb(
+		psoc, &tdls_pm_call_backs)) {
+		tdls_err("policy manager callback registration failed ");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	tdls_update_feature_flag(soc_obj);
+	tdls_feature_flags = soc_obj->tdls_configs.tdls_feature_flags;
+
+	if (!TDLS_IS_IMPLICIT_TRIG_ENABLED(tdls_feature_flags))
+		soc_obj->tdls_current_mode = TDLS_SUPPORT_EXP_TRIG_ONLY;
+	else if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(tdls_feature_flags))
+		soc_obj->tdls_current_mode = TDLS_SUPPORT_EXT_CONTROL;
+	else
+		soc_obj->tdls_current_mode = TDLS_SUPPORT_IMP_MODE;
+
+	soc_obj->tdls_last_mode = soc_obj->tdls_current_mode;
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS ucfg_tdls_psoc_enable(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+
+	tdls_notice("psoc tdls enable: 0x%pK", psoc);
+	if (!psoc) {
+		tdls_err("NULL psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = tgt_tdls_register_ev_handler(psoc);
+
+	if (status != QDF_STATUS_SUCCESS)
+		return status;
+
+	status = wlan_serialization_register_comp_info_cb(psoc,
+					WLAN_UMAC_COMP_TDLS,
+					WLAN_SER_CMD_SCAN,
+					tdls_scan_serialization_comp_info_cb);
+	if (QDF_STATUS_SUCCESS != status) {
+		tdls_err("Serialize scan cmd register failed ");
+		return status;
+	}
+
+	/* register callbacks with tx/rx mgmt */
+	status = tdls_mgmt_rx_ops(psoc, true);
+	if (status != QDF_STATUS_SUCCESS)
+		tdls_err("Failed to register mgmt rx callback, status:%d",
+			status);
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_psoc_disable(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status;
+	struct tdls_soc_priv_obj *soc_obj = NULL;
+
+	tdls_notice("psoc tdls disable: 0x%pK", psoc);
+	if (!psoc) {
+		tdls_err("NULL psoc");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = tgt_tdls_unregister_ev_handler(psoc);
+	if (QDF_IS_STATUS_ERROR(status))
+		tdls_err("Failed to unregister tdls event handler");
+
+	status = tdls_mgmt_rx_ops(psoc, false);
+	if (QDF_IS_STATUS_ERROR(status))
+		tdls_err("Failed to unregister mgmt rx callback");
+
+	soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+							WLAN_UMAC_COMP_TDLS);
+	if (!soc_obj) {
+		tdls_err("Failed to get tdls psoc component");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	soc_obj->tdls_event_cb = NULL;
+	soc_obj->tdls_evt_cb_data = NULL;
+
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_psoc_close(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct tdls_soc_priv_obj *tdls_soc;
+
+	tdls_notice("tdls psoc close");
+	tdls_soc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+							WLAN_UMAC_COMP_TDLS);
+	if (!tdls_soc) {
+		tdls_err("Failed to get tdls psoc component");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	status = tdls_global_deinit(tdls_soc);
+
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_add_peer(struct wlan_objmgr_vdev *vdev,
+			      struct tdls_add_peer_params *add_peer_req)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_add_peer_request *req;
+	QDF_STATUS status;
+
+	if (!vdev || !add_peer_req) {
+		tdls_err("vdev: %pK, req %pK", vdev, add_peer_req);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	tdls_debug("vdevid: %d, peertype: %d",
+		   add_peer_req->vdev_id, add_peer_req->peer_type);
+
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get vdev");
+		return status;
+	}
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		tdls_err("mem allocate fail");
+		status = QDF_STATUS_E_NOMEM;
+		goto dec_ref;
+	}
+
+	qdf_mem_copy(&req->add_peer_req, add_peer_req, sizeof(*add_peer_req));
+	req->vdev = vdev;
+
+	msg.bodyptr = req;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_CMD_ADD_STA;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("post add peer msg fail");
+		qdf_mem_free(req);
+		goto dec_ref;
+	}
+
+	return status;
+dec_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_update_peer(struct wlan_objmgr_vdev *vdev,
+				 struct tdls_update_peer_params *update_peer)
+{
+	struct scheduler_msg msg = {0,};
+	struct tdls_update_peer_request *req;
+	QDF_STATUS status;
+
+	if (!vdev || !update_peer) {
+		tdls_err("vdev: %pK, update_peer: %pK", vdev, update_peer);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	tdls_debug("vdev_id: %d, peertype: %d",
+		   update_peer->vdev_id, update_peer->peer_type);
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get vdev");
+		return status;
+	}
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		tdls_err("mem allocate fail");
+		status = QDF_STATUS_E_NOMEM;
+		goto dec_ref;
+	}
+	qdf_mem_copy(&req->update_peer_req, update_peer, sizeof(*update_peer));
+	req->vdev = vdev;
+
+	msg.bodyptr = req;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_CMD_CHANGE_STA;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("post update peer msg fail");
+		qdf_mem_free(req);
+		goto dec_ref;
+	}
+
+	return status;
+dec_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+	return status;
+}
+
+static char *tdls_get_oper_str(enum tdls_command_type cmd_type)
+{
+	switch (cmd_type) {
+	case TDLS_CMD_ENABLE_LINK:
+		return "Enable_TDLS_LINK";
+	case TDLS_CMD_DISABLE_LINK:
+		return "DISABLE_TDLS_LINK";
+	case TDLS_CMD_REMOVE_FORCE_PEER:
+		return "REMOVE_FORCE_PEER";
+	case TDLS_CMD_CONFIG_FORCE_PEER:
+		return "CONFIG_FORCE_PEER";
+	default:
+		return "ERR:UNKNOWN OPER";
+	}
+}
+
+QDF_STATUS ucfg_tdls_oper(struct wlan_objmgr_vdev *vdev,
+			  const uint8_t *macaddr, enum tdls_command_type cmd)
+{
+	struct scheduler_msg msg = {0,};
+	struct tdls_oper_request *req;
+	QDF_STATUS status;
+
+	if (!vdev || !macaddr) {
+		tdls_err("vdev: %pK, mac %pK", vdev, macaddr);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	tdls_debug("%s for peer " QDF_MAC_ADDR_STR,
+		   tdls_get_oper_str(cmd),
+		   QDF_MAC_ADDR_ARRAY(macaddr));
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		tdls_err("%s: mem allocate fail", tdls_get_oper_str(cmd));
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get vdev");
+		goto error;
+	}
+
+	qdf_mem_copy(req->peer_addr, macaddr, QDF_MAC_ADDR_SIZE);
+	req->vdev = vdev;
+
+	msg.bodyptr = req;
+	msg.callback = tdls_process_cmd;
+	msg.type = cmd;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("post msg for %s fail", tdls_get_oper_str(cmd));
+		goto dec_ref;
+	}
+
+	return status;
+dec_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+error:
+	qdf_mem_free(req);
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev,
+				   char *buf, int buflen)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_get_all_peers *tdls_peers;
+	QDF_STATUS status;
+
+	tdls_peers = qdf_mem_malloc(sizeof(*tdls_peers));
+
+	if (!tdls_peers) {
+		tdls_err("mem allocate fail");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	tdls_peers->vdev = vdev;
+	tdls_peers->buf_len = buflen;
+	tdls_peers->buf = buf;
+
+	msg.bodyptr = tdls_peers;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_CMD_GET_ALL_PEERS;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+
+	if (status != QDF_STATUS_SUCCESS)
+		qdf_mem_free(tdls_peers);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS tdls_send_mgmt_frame_flush_callback(struct scheduler_msg *msg)
+{
+	struct tdls_action_frame_request *req;
+
+	if (!msg || !msg->bodyptr) {
+		tdls_err("msg or msg->bodyptr is NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	req = msg->bodyptr;
+	if (req->vdev)
+		wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
+
+	qdf_mem_free(req);
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS ucfg_tdls_post_msg_flush_cb(struct scheduler_msg *msg)
+{
+	void *ptr = msg->bodyptr;
+	struct wlan_objmgr_vdev *vdev = NULL;
+
+	switch (msg->type) {
+	case TDLS_CMD_TEARDOWN_LINKS:
+	case TDLS_NOTIFY_RESET_ADAPTERS:
+		ptr = NULL;
+		break;
+	case TDLS_NOTIFY_STA_CONNECTION:
+		vdev = ((struct tdls_sta_notify_params *)ptr)->vdev;
+		break;
+	case TDLS_NOTIFY_STA_DISCONNECTION:
+		vdev = ((struct tdls_sta_notify_params *)ptr)->vdev;
+		break;
+	case TDLS_CMD_SET_TDLS_MODE:
+		vdev = ((struct tdls_set_mode_params *)ptr)->vdev;
+		break;
+	case TDLS_CMD_TX_ACTION:
+	case TDLS_CMD_SET_RESPONDER:
+		break;
+	}
+
+	if (vdev)
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+
+	if (ptr)
+		qdf_mem_free(ptr);
+
+	msg->bodyptr = NULL;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS ucfg_tdls_send_mgmt_frame(
+				struct tdls_action_frame_request *req)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_action_frame_request *mgmt_req;
+	QDF_STATUS status;
+
+	if (!req || !req->vdev) {
+		tdls_err("Invalid mgmt req params %pK", req);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	mgmt_req = qdf_mem_malloc(sizeof(*mgmt_req) +
+					req->len);
+	if (!mgmt_req) {
+		tdls_err("mem allocate fail");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	qdf_mem_copy(mgmt_req, req, sizeof(*req));
+
+	/*populate the additional IE's */
+	if ((0 != req->len) && (NULL != req->cmd_buf)) {
+		qdf_mem_copy(mgmt_req->tdls_mgmt.buf, req->cmd_buf,
+				req->len);
+		mgmt_req->tdls_mgmt.len = req->len;
+	} else {
+		mgmt_req->tdls_mgmt.len = 0;
+	}
+
+	tdls_debug("vdev id: %d, session id : %d", mgmt_req->vdev_id,
+		    mgmt_req->session_id);
+	status = wlan_objmgr_vdev_try_get_ref(req->vdev, WLAN_TDLS_NB_ID);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("Unable to get vdev reference for tdls module");
+		goto mem_free;
+	}
+
+	msg.bodyptr = mgmt_req;
+	msg.callback = tdls_process_cmd;
+	msg.flush_callback = tdls_send_mgmt_frame_flush_callback;
+	msg.type = TDLS_CMD_TX_ACTION;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("Failed to post the mgmt tx cmd to scheduler thread");
+		goto release_ref;
+	}
+
+	return status;
+
+release_ref:
+	wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID);
+mem_free:
+	qdf_mem_free(mgmt_req);
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_responder(struct tdls_set_responder_req *req)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_set_responder_req *msg_req;
+	QDF_STATUS status;
+
+	if (!req || !req->vdev) {
+		tdls_err("invalid input %pK", req);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	msg_req = qdf_mem_malloc(sizeof(*msg_req));
+	if (!msg_req)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	msg_req->responder = req->responder;
+	msg_req->vdev = req->vdev;
+	qdf_mem_copy(msg_req->peer_mac, req->peer_mac, QDF_MAC_ADDR_SIZE);
+
+	msg.bodyptr = msg_req;
+	msg.callback = tdls_process_cmd;
+	msg.flush_callback = ucfg_tdls_post_msg_flush_cb;
+	msg.type = TDLS_CMD_SET_RESPONDER;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("failed to post msg, status %d", status);
+		qdf_mem_free(msg_req);
+	}
+
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_teardown_links(struct wlan_objmgr_vdev *vdev)
+{
+	QDF_STATUS status;
+	struct scheduler_msg msg = {0, };
+
+	if (!vdev) {
+		tdls_err("vdev is NULL ");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	tdls_debug("Enter ");
+
+	msg.bodyptr = vdev;
+	msg.callback = tdls_process_cmd;
+	msg.flush_callback = ucfg_tdls_post_msg_flush_cb;
+	msg.type = TDLS_CMD_TEARDOWN_LINKS;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+
+	tdls_debug("Exit ");
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev)
+{
+	QDF_STATUS status;
+	struct scheduler_msg msg = {0, };
+
+	if (!vdev) {
+		tdls_err("vdev is NULL ");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	tdls_debug("Enter ");
+	msg.bodyptr = vdev;
+	msg.callback = tdls_process_cmd;
+	msg.flush_callback = ucfg_tdls_post_msg_flush_cb;
+	msg.type = TDLS_NOTIFY_RESET_ADAPTERS;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_notify_sta_connect(
+	struct tdls_sta_notify_params *notify_info)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_sta_notify_params *notify;
+	QDF_STATUS status;
+
+	if (!notify_info || !notify_info->vdev) {
+		tdls_err("notify_info %pK", notify_info);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+	tdls_debug("Enter ");
+
+	notify = qdf_mem_malloc(sizeof(*notify));
+	if (!notify) {
+		wlan_objmgr_vdev_release_ref(notify_info->vdev,
+					     WLAN_TDLS_NB_ID);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	*notify = *notify_info;
+
+	msg.bodyptr = notify;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_NOTIFY_STA_CONNECTION;
+	msg.flush_callback = ucfg_tdls_post_msg_flush_cb;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TARGET_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("failed to post message, status %d", status);
+		wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(notify);
+	}
+
+	tdls_debug("Exit ");
+	return status;
+}
+
+QDF_STATUS ucfg_tdls_notify_sta_disconnect(
+			struct tdls_sta_notify_params *notify_info)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_sta_notify_params *notify;
+	QDF_STATUS status;
+
+	if (!notify_info || !notify_info->vdev) {
+		tdls_err("notify_info %pK", notify_info);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	tdls_debug("Enter ");
+
+	notify = qdf_mem_malloc(sizeof(*notify));
+	if (!notify)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	*notify = *notify_info;
+
+	msg.bodyptr = notify;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_NOTIFY_STA_DISCONNECTION;
+	msg.flush_callback = ucfg_tdls_post_msg_flush_cb;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_TARGET_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("failed to post message, status %d", status);
+		wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(notify);
+	}
+
+	tdls_debug("Exit ");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS ucfg_tdls_set_operating_mode(
+			struct tdls_set_mode_params *set_mode_params)
+{
+	struct scheduler_msg msg = {0, };
+	struct tdls_set_mode_params *set_mode;
+	QDF_STATUS status;
+
+	if (!set_mode_params || !set_mode_params->vdev) {
+		tdls_err("set_mode_params %pK", set_mode_params);
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	tdls_debug("Enter ");
+
+	set_mode = qdf_mem_malloc(sizeof(*set_mode));
+	if (!set_mode) {
+		tdls_err("memory allocate fail");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	status = wlan_objmgr_vdev_try_get_ref(set_mode->vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("failed to get vdev ref");
+		qdf_mem_free(set_mode);
+		return status;
+	}
+
+	set_mode->source = set_mode_params->source;
+	set_mode->tdls_mode = set_mode_params->tdls_mode;
+	set_mode->update_last = set_mode_params->update_last;
+	set_mode->vdev = set_mode_params->vdev;
+
+	msg.bodyptr = set_mode;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_CMD_SET_TDLS_MODE;
+	msg.flush_callback = ucfg_tdls_post_msg_flush_cb;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		wlan_objmgr_vdev_release_ref(set_mode->vdev, WLAN_TDLS_NB_ID);
+		qdf_mem_free(set_mode);
+	}
+
+	tdls_debug("Exit ");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void ucfg_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
+				 struct qdf_mac_addr *mac_addr)
+{
+	QDF_STATUS status;
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (status != QDF_STATUS_SUCCESS)
+		return;
+	tdls_update_rx_pkt_cnt(vdev, mac_addr);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+}
+
+void ucfg_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev,
+				 struct qdf_mac_addr *mac_addr)
+{
+	QDF_STATUS status;
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (status != QDF_STATUS_SUCCESS)
+		return;
+	tdls_update_tx_pkt_cnt(vdev, mac_addr);
+
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+
+}
+
+QDF_STATUS ucfg_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev,
+				    uint32_t mode)
+{
+	QDF_STATUS status;
+	struct tdls_antenna_switch_request *req;
+	struct scheduler_msg msg = {0, };
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		tdls_err("mem allocate fail");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get vdev");
+		goto error;
+	}
+
+	req->vdev = vdev;
+	req->mode = mode;
+
+	msg.bodyptr = req;
+	msg.callback = tdls_process_cmd;
+	msg.flush_callback = tdls_antenna_switch_flush_callback;
+	msg.type = TDLS_CMD_ANTENNA_SWITCH;
+	status = scheduler_post_message(QDF_MODULE_ID_HDD,
+					QDF_MODULE_ID_TDLS,
+					QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("post antenna switch msg fail");
+		goto dec_ref;
+	}
+
+	return status;
+
+dec_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+error:
+	qdf_mem_free(req);
+	return status;
+}
+
+QDF_STATUS ucfg_set_tdls_offchannel(struct wlan_objmgr_vdev *vdev,
+				    int offchannel)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct scheduler_msg msg = {0, };
+	struct tdls_set_offchannel *req;
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		tdls_err("mem allocate fail");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get vdev");
+		goto free;
+	}
+
+	req->offchannel = offchannel;
+	req->vdev = vdev;
+	req->callback = wlan_tdls_offchan_parms_callback;
+	msg.bodyptr = req;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_CMD_SET_OFFCHANNEL;
+	status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("post set tdls offchannel msg fail");
+		goto dec_ref;
+	}
+
+	return status;
+
+dec_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+
+free:
+	qdf_mem_free(req);
+	return status;
+}
+
+QDF_STATUS ucfg_set_tdls_offchan_mode(struct wlan_objmgr_vdev *vdev,
+				      int offchanmode)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct scheduler_msg msg = {0, };
+	struct tdls_set_offchanmode *req;
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		tdls_err("mem allocate fail");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get vdev");
+		goto free;
+	}
+
+	req->offchan_mode = offchanmode;
+	req->vdev = vdev;
+	req->callback = wlan_tdls_offchan_parms_callback;
+	msg.bodyptr = req;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_CMD_SET_OFFCHANMODE;
+	status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("post set offchanmode msg fail");
+		goto dec_ref;
+	}
+
+	return status;
+
+dec_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+
+free:
+	qdf_mem_free(req);
+	return status;
+}
+
+QDF_STATUS ucfg_set_tdls_secoffchanneloffset(struct wlan_objmgr_vdev *vdev,
+					     int offchanoffset)
+{
+	int status = QDF_STATUS_SUCCESS;
+	struct scheduler_msg msg = {0, };
+	struct tdls_set_secoffchanneloffset *req;
+
+	req = qdf_mem_malloc(sizeof(*req));
+	if (!req) {
+		tdls_err("mem allocate fail");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("can't get vdev");
+		goto free;
+	}
+
+	req->offchan_offset = offchanoffset;
+	req->vdev = vdev;
+	req->callback = wlan_tdls_offchan_parms_callback;
+	msg.bodyptr = req;
+	msg.callback = tdls_process_cmd;
+	msg.type = TDLS_CMD_SET_SECOFFCHANOFFSET;
+	status = scheduler_post_msg(QDF_MODULE_ID_OS_IF, &msg);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		tdls_err("post set secoffchan offset msg fail");
+		goto dec_ref;
+	}
+	return status;
+
+dec_ref:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+
+free:
+	qdf_mem_free(req);
+	return status;
+}

+ 23 - 0
components/tdls/dispatcher/src/wlan_tdls_utils_api.c

@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_tdls_utils_api.c
+ *
+ * TDLS utility functions definitions
+ */

+ 0 - 3
core/cds/inc/cds_config.h

@@ -63,7 +63,6 @@ enum active_apf_mode {
  * @sta_maxlimod_dtim: station max listen interval
  * @driver_type: Enumeration of Driver Type whether FTM or Mission mode
  * currently rest of bits are not used
- * @dfs_phyerr_filter_offload: DFS Phyerror Filtering offload status from ini
  * Indicates whether support is enabled or not
  * @ap_disable_intrabss_fwd: pass intra-bss-fwd info to txrx module
  * @ap_maxoffload_peers: max offload peer
@@ -110,7 +109,6 @@ struct cds_config_info {
 	uint16_t max_bssid;
 	uint8_t sta_maxlimod_dtim;
 	enum qdf_driver_type driver_type;
-	uint8_t dfs_phyerr_filter_offload;
 	uint8_t ap_maxoffload_peers;
 	uint8_t ap_maxoffload_reorderbuffs;
 #ifdef FEATURE_WLAN_RA_FILTERING
@@ -118,7 +116,6 @@ struct cds_config_info {
 	bool is_ra_ratelimit_enabled;
 #endif
 	uint8_t reorder_offload;
-	int32_t dfs_pri_multiplier;
 	uint8_t uc_offload_enabled;
 	uint32_t uc_txbuf_count;
 	uint32_t uc_txbuf_size;

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

@@ -2201,70 +2201,6 @@ enum hdd_link_speed_rpt_type {
 	eHDD_LINK_SPEED_REPORT_MAX_SCALED = 2,
 };
 
-/*
- * <ini>
- * gDisableDFSChSwitch - Disable channel switch if radar is found
- * @Min: 0
- * @Max: 1
- * @Default: 0
- *
- * This ini is used to disable channel switch if radar is found
- * on that channel.
- * Related: NA.
- *
- * Supported Feature: DFS
- *
- * Usage: Internal
- *
- * </ini>
- */
-#define CFG_DISABLE_DFS_CH_SWITCH                 "gDisableDFSChSwitch"
-#define CFG_DISABLE_DFS_CH_SWITCH_MIN             (0)
-#define CFG_DISABLE_DFS_CH_SWITCH_MAX             (1)
-#define CFG_DISABLE_DFS_CH_SWITCH_DEFAULT         (0)
-
-/*
- * <ini>
- * gDisableDfsJapanW53 - Block W53 channels in random channel selection
- * @Min: 0
- * @Max: 1
- * @Default: 0
- *
- * This ini is used to block W53 Japan channel in random channel selection
- * Related: NA.
- *
- * Supported Feature: DFS
- *
- * Usage: Internal/External
- *
- * </ini>
- */
-#define CFG_DISABLE_DFS_JAPAN_W53                      "gDisableDfsJapanW53"
-#define CFG_DISABLE_DFS_JAPAN_W53_MIN                  (0)
-#define CFG_DISABLE_DFS_JAPAN_W53_MAX                  (1)
-#define CFG_DISABLE_DFS_JAPAN_W53_DEFAULT              (0)
-
-/*
- * <ini>
- * dfsPhyerrFilterOffload - DFS PHY error filter offload
- * @Min: 0
- * @Max: 1
- * @Default: 0
- *
- * This ini is used to enable firmware to do DFS PHY error filtering.
- * Related: NA.
- *
- * Supported Feature: DFS
- *
- * Usage: Internal/External
- *
- * </ini>
- */
-#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_NAME       "dfsPhyerrFilterOffload"
-#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MIN        (0)
-#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MAX        (1)
-#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_DEFAULT    (0)
-
 /*
  * <ini>
  * gReportMaxLinkSpeed - Reporting of max link speed
@@ -2936,34 +2872,6 @@ enum hdd_link_speed_rpt_type {
 
 #endif /* MSM_PLATFORM */
 
-/*
- * <ini>
- * gIgnoreCAC - Used to ignore CAC
- * @Min: 0
- * @Max: 1
- * @Default: 0
- *
- * This ini is used to set default CAC
- *
- * Related: None
- *
- * Supported Feature: STA
- *
- * Usage: Internal/External
- *
- * </ini>
- */
-
-#define CFG_IGNORE_CAC_NAME                        "gIgnoreCAC"
-#define CFG_IGNORE_CAC_MIN                         (0)
-#define CFG_IGNORE_CAC_MAX                         (1)
-#define CFG_IGNORE_CAC_DEFAULT                     (0)
-
-#define CFG_DFS_RADAR_PRI_MULTIPLIER_NAME          "gDFSradarMappingPriMultiplier"
-#define CFG_DFS_RADAR_PRI_MULTIPLIER_DEFAULT       (4)
-#define CFG_DFS_RADAR_PRI_MULTIPLIER_MIN           (0)
-#define CFG_DFS_RADAR_PRI_MULTIPLIER_MAX           (10)
-
 #define CFG_ENABLE_SAP_SUSPEND                     "gEnableSapSuspend"
 #define CFG_ENABLE_SAP_SUSPEND_MIN                 (0)
 #define CFG_ENABLE_SAP_SUSPEND_MAX                 (1)
@@ -3101,11 +3009,6 @@ enum hdd_link_speed_rpt_type {
 #define CFG_GO_11AC_OVERRIDE_MAX              (1)
 #define CFG_GO_11AC_OVERRIDE_DEFAULT          (1)
 
-#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR           "gPreferNonDfsChanOnRadar"
-#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MIN       (0)
-#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MAX       (1)
-#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_DEFAULT   (0)
-
 /*
  * set the self gen power value from
  * 0 to 0xffff
@@ -3115,34 +3018,6 @@ enum hdd_link_speed_rpt_type {
 #define CFG_SELF_GEN_FRM_PWR_MAX      (0xffff)
 #define CFG_SELF_GEN_FRM_PWR_DEFAULT  (0)
 
-/*
- * fine timing measurement capability information
- *
- * <----- fine_time_meas_cap (in bits) ----->
- *+----------+-----+-----+------+------+-------+-------+-----+-----+
- *|   8-31   |  7  |  6  |   5  |   4  |   3   |   2   |  1  |  0  |
- *+----------+-----+-----+------+------+-------+-------+-----+-----+
- *| reserved | SAP | SAP |P2P-GO|P2P-GO|P2P-CLI|P2P-CLI| STA | STA |
- *|          |resp |init |resp  |init  |resp   |init   |resp |init |
- *+----------+-----+-----+------+------+-------+-------+-----+-----+
- *
- * resp - responder role; init- initiator role
- *
- * CFG_FINE_TIME_MEAS_CAPABILITY_MAX computed based on the table
- * +-----------------+-----------------+-----------+
- * |  Device Role    |   Initiator     | Responder |
- * +-----------------+-----------------+-----------+
- * |   Station       |       Y         |     N     |
- * |   P2P-CLI       |       Y         |     Y     |
- * |   P2P-GO        |       Y         |     Y     |
- * |   SAP           |       N         |     Y     |
- * +-----------------+-----------------+-----------+
- */
-#define CFG_FINE_TIME_MEAS_CAPABILITY              "gfine_time_meas_cap"
-#define CFG_FINE_TIME_MEAS_CAPABILITY_MIN          (0x0000)
-#define CFG_FINE_TIME_MEAS_CAPABILITY_MAX          (0x00BD)
-#define CFG_FINE_TIME_MEAS_CAPABILITY_DEFAULT      (0x000D)
-
 /*
  * <ini>
  * etsi13_srd_chan_in_master_mode - Enable/disable ETSI SRD channels in
@@ -3461,16 +3336,6 @@ enum hdd_link_speed_rpt_type {
 #define CFG_MARK_INDOOR_AS_DISABLE_MAX      (1)
 #define CFG_MARK_INDOOR_AS_DISABLE_DEFAULT  (0)
 
-/*
- * sap tx leakage threshold
- * customer can set this value from 100 to 1000 which means
- * sap tx leakage threshold is -10db to -100db
- */
-#define CFG_SAP_TX_LEAKAGE_THRESHOLD_NAME    "gsap_tx_leakage_threshold"
-#define CFG_SAP_TX_LEAKAGE_THRESHOLD_MIN     (100)
-#define CFG_SAP_TX_LEAKAGE_THRESHOLD_MAX     (1000)
-#define CFG_SAP_TX_LEAKAGE_THRESHOLD_DEFAULT (310)
-
 /*
  * <ini>
  * enable_5g_band_pref - Enable preference for 5G from INI.
@@ -4231,26 +4096,6 @@ enum hdd_link_speed_rpt_type {
 #define CFG_ENABLE_PACKET_FILTERS_MAX      (63)
 #endif /* WLAN_FEATURE_PACKET_FILTERING */
 
-/*
- * <ini>
- * gDfsBeaconTxEnhanced - beacon tx enhanced
- * @Min: 0
- * @Max: 1
- * @Default: 0
- *
- * This ini is used to enhance dfs beacon tx
- *
- * Related: none
- *
- * Usage: External
- *
- * </ini>
- */
-#define CFG_DFS_BEACON_TX_ENHANCED         "gDfsBeaconTxEnhanced"
-#define CFG_DFS_BEACON_TX_ENHANCED_MIN     (0)
-#define CFG_DFS_BEACON_TX_ENHANCED_MAX     (1)
-#define CFG_DFS_BEACON_TX_ENHANCED_DEFAULT (0)
-
 /*
  * <ini>
  * btm_offload_config - Configure BTM
@@ -4561,29 +4406,6 @@ enum hdd_link_speed_rpt_type {
 #define CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_MAX     (300)
 #define CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_DEFAULT (3)
 
-/*
- * <ini>
- * wmi_wq_watchdog - Sets timeout period for wmi watchdog bite
- * @Min: 0
- * @Max: 30
- * @Default: 20
- *
- * This ini is used to set timeout period for wmi watchdog bite. If it is
- * 0 then wmi watchdog bite is disabled.
- *
- * Related: None
- *
- * Supported Feature: STA
- *
- * Usage: External
- *
- * </ini>
- */
-#define CFG_WMI_WQ_WATCHDOG          "wmi_wq_watchdog"
-#define CFG_WMI_WQ_WATCHDOG_MIN      (0)
-#define CFG_WMI_WQ_WATCHDOG_MAX      (30) /* 30s */
-#define CFG_WMI_WQ_WATCHDOG_DEFAULT  (20) /* 20s */
-
 /*
  * <ini>
  * gEnableDTIMSelectionDiversity - Enable/Disable chain
@@ -5241,8 +5063,6 @@ struct hdd_config {
 	uint32_t ibssPs1RxChainInAtimEnable;
 	uint32_t IpaConfig;
 	bool IpaClkScalingEnable;
-	uint8_t disableDFSChSwitch;
-	bool fDfsPhyerrFilterOffload;
 	uint8_t gDisableDfsJapanW53;
 	bool gEnableOverLapCh;
 	bool fRegChangeDefCountry;
@@ -5250,12 +5070,8 @@ struct hdd_config {
 
 	uint8_t enableFwModuleLogLevel[FW_MODULE_LOG_LEVEL_STRING_LENGTH];
 
-	uint8_t ignoreCAC;
-
 	bool enable_sap_mandatory_chan_list;
 
-	int32_t dfsRadarPriMultiplier;
-
 #ifdef FEATURE_WLAN_FORCE_SAP_SCC
 	uint8_t SapSccChanAvoidance;
 #endif /* FEATURE_WLAN_FORCE_SAP_SCC */
@@ -5273,9 +5089,6 @@ struct hdd_config {
 #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
 	uint8_t sap_11ac_override;
 	uint8_t go_11ac_override;
-	uint8_t prefer_non_dfs_on_radar;
-	/* parameter for defer timer for enabling TDLS on p2p listen */
-	uint32_t fine_time_meas_cap;
 	uint8_t max_scan_count;
 	bool etsi13_srd_chan_in_master_mode;
 	uint32_t dual_mac_feature_disable;
@@ -5367,7 +5180,6 @@ struct hdd_config {
 #ifdef WLAN_FEATURE_PACKET_FILTERING
 	uint8_t packet_filters_bitmap;
 #endif
-	uint8_t dfs_beacon_tx_enhanced;
 	uint32_t btm_offload_config;
 #ifdef WLAN_FEATURE_SAE
 	bool is_sae_enabled;
@@ -5388,7 +5200,6 @@ struct hdd_config {
 	uint32_t neighbor_report_offload_max_req_cap;
 	bool action_oui_enable;
 	uint8_t action_oui_str[ACTION_OUI_MAXIMUM_ID][ACTION_OUI_MAX_STR_LEN];
-	uint16_t wmi_wq_watchdog_timeout;
 	uint8_t enable_tx_sch_delay;
 	uint32_t enable_secondary_rate;
 	bool is_unit_test_framework_enabled;

+ 3 - 94
core/hdd/src/wlan_hdd_cfg.c

@@ -48,14 +48,6 @@
 #include "cfg_ucfg_api.h"
 #include "hdd_dp_cfg.h"
 
-static void ch_notify_set_g_disable_dfs_japan_w53(struct hdd_context *hdd_ctx,
-						  unsigned long notify_id)
-{
-	bool disabled = hdd_ctx->config->gDisableDfsJapanW53;
-
-	wlansap_set_dfs_restrict_japan_w53(hdd_ctx->mac_handle, disabled);
-}
-
 struct reg_table_entry g_registry_table[] = {
 	REG_VARIABLE(CFG_ENABLE_CONNECTED_SCAN_NAME, WLAN_PARAM_Integer,
 		     struct hdd_config, enable_connected_scan,
@@ -495,22 +487,6 @@ struct reg_table_entry g_registry_table[] = {
 		     CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MIN,
 		     CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MAX),
 
-	REG_VARIABLE(CFG_DISABLE_DFS_CH_SWITCH, WLAN_PARAM_Integer,
-		     struct hdd_config, disableDFSChSwitch,
-		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-		     CFG_DISABLE_DFS_CH_SWITCH_DEFAULT,
-		     CFG_DISABLE_DFS_CH_SWITCH_MIN,
-		     CFG_DISABLE_DFS_CH_SWITCH_MAX),
-
-	REG_DYNAMIC_VARIABLE(CFG_DISABLE_DFS_JAPAN_W53, WLAN_PARAM_Integer,
-			     struct hdd_config, gDisableDfsJapanW53,
-			     VAR_FLAGS_OPTIONAL |
-			     VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-			     CFG_DISABLE_DFS_JAPAN_W53_DEFAULT,
-			     CFG_DISABLE_DFS_JAPAN_W53_MIN,
-			     CFG_DISABLE_DFS_JAPAN_W53_MAX,
-			     ch_notify_set_g_disable_dfs_japan_w53, 0),
-
 	REG_VARIABLE(CFG_ENABLE_FIRST_SCAN_2G_ONLY_NAME, WLAN_PARAM_Integer,
 		     struct hdd_config, enableFirstScan2GOnly,
 		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
@@ -640,14 +616,6 @@ struct reg_table_entry g_registry_table[] = {
 		     CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MIN,
 		     CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MAX),
 
-	REG_VARIABLE(CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_NAME,
-		     WLAN_PARAM_Integer,
-		     struct hdd_config, fDfsPhyerrFilterOffload,
-		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-		     CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_DEFAULT,
-		     CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MIN,
-		     CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MAX),
-
 	REG_VARIABLE(CFG_ENABLE_OVERLAP_CH, WLAN_PARAM_Integer,
 		     struct hdd_config, gEnableOverLapCh,
 		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK,
@@ -698,20 +666,6 @@ struct reg_table_entry g_registry_table[] = {
 			    VAR_FLAGS_OPTIONAL,
 			    (void *)CFG_ENABLE_FW_MODULE_LOG_DEFAULT),
 
-	REG_VARIABLE(CFG_IGNORE_CAC_NAME, WLAN_PARAM_Integer,
-		     struct hdd_config, ignoreCAC,
-		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-		     CFG_IGNORE_CAC_DEFAULT,
-		     CFG_IGNORE_CAC_MIN,
-		     CFG_IGNORE_CAC_MAX),
-
-	REG_VARIABLE(CFG_DFS_RADAR_PRI_MULTIPLIER_NAME, WLAN_PARAM_Integer,
-		     struct hdd_config, dfsRadarPriMultiplier,
-		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-		     CFG_DFS_RADAR_PRI_MULTIPLIER_DEFAULT,
-		     CFG_DFS_RADAR_PRI_MULTIPLIER_MIN,
-		     CFG_DFS_RADAR_PRI_MULTIPLIER_MAX),
-
 	REG_VARIABLE(CFG_ENABLE_SAP_SUSPEND, WLAN_PARAM_Integer,
 		     struct hdd_config, enable_sap_suspend,
 		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
@@ -773,20 +727,6 @@ struct reg_table_entry g_registry_table[] = {
 		     CFG_GO_11AC_OVERRIDE_MIN,
 		     CFG_GO_11AC_OVERRIDE_MAX),
 
-	REG_VARIABLE(CFG_ENABLE_NON_DFS_CHAN_ON_RADAR, WLAN_PARAM_Integer,
-		     struct hdd_config, prefer_non_dfs_on_radar,
-		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-		     CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_DEFAULT,
-		     CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MIN,
-		     CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MAX),
-
-	REG_VARIABLE(CFG_FINE_TIME_MEAS_CAPABILITY, WLAN_PARAM_HexInteger,
-		struct hdd_config, fine_time_meas_cap,
-		VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-		CFG_FINE_TIME_MEAS_CAPABILITY_DEFAULT,
-		CFG_FINE_TIME_MEAS_CAPABILITY_MIN,
-		CFG_FINE_TIME_MEAS_CAPABILITY_MAX),
-
 	REG_VARIABLE(CFG_MAX_SCAN_COUNT_NAME, WLAN_PARAM_Integer,
 		     struct hdd_config, max_scan_count,
 		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
@@ -996,14 +936,6 @@ struct reg_table_entry g_registry_table[] = {
 		     CFG_MARK_INDOOR_AS_DISABLE_MIN,
 		     CFG_MARK_INDOOR_AS_DISABLE_MAX),
 
-	REG_VARIABLE(CFG_SAP_TX_LEAKAGE_THRESHOLD_NAME,
-		WLAN_PARAM_Integer,
-		struct hdd_config, sap_tx_leakage_threshold,
-		VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-		CFG_SAP_TX_LEAKAGE_THRESHOLD_DEFAULT,
-		CFG_SAP_TX_LEAKAGE_THRESHOLD_MIN,
-		CFG_SAP_TX_LEAKAGE_THRESHOLD_MAX),
-
 	REG_VARIABLE(CFG_RESTART_BEACONING_ON_CH_AVOID_NAME, WLAN_PARAM_Integer,
 		struct hdd_config, restart_beaconing_on_chan_avoid_event,
 		VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
@@ -1223,14 +1155,6 @@ struct reg_table_entry g_registry_table[] = {
 		     CFG_LATENCY_FLAGS_ULTRALOW_MIN,
 		     CFG_LATENCY_FLAGS_ULTRALOW_MAX),
 
-
-	REG_VARIABLE(CFG_DFS_BEACON_TX_ENHANCED, WLAN_PARAM_Integer,
-		struct hdd_config, dfs_beacon_tx_enhanced,
-		VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-		CFG_DFS_BEACON_TX_ENHANCED_DEFAULT,
-		CFG_DFS_BEACON_TX_ENHANCED_MIN,
-		CFG_DFS_BEACON_TX_ENHANCED_MAX),
-
 	REG_VARIABLE(CFG_BTM_ENABLE_NAME, WLAN_PARAM_HexInteger,
 		     struct hdd_config, btm_offload_config,
 		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
@@ -1341,13 +1265,6 @@ struct reg_table_entry g_registry_table[] = {
 		     CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_MIN,
 		     CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_MAX),
 
-	REG_VARIABLE(CFG_WMI_WQ_WATCHDOG, WLAN_PARAM_Integer,
-		     struct hdd_config, wmi_wq_watchdog_timeout,
-		     VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
-		     CFG_WMI_WQ_WATCHDOG_DEFAULT,
-		     CFG_WMI_WQ_WATCHDOG_MIN,
-		     CFG_WMI_WQ_WATCHDOG_MAX),
-
 	REG_VARIABLE(CFG_DTIM_SELECTION_DIVERSITY_NAME,
 		     WLAN_PARAM_Integer,
 		     struct hdd_config, enable_dtim_selection_diversity,
@@ -2540,16 +2457,11 @@ QDF_STATUS hdd_set_idle_ps_config(struct hdd_context *hdd_ctx, bool val)
  */
 static void hdd_set_fine_time_meas_cap(struct hdd_context *hdd_ctx)
 {
-	struct hdd_config *config = hdd_ctx->config;
-	uint32_t capability = config->fine_time_meas_cap;
+	uint32_t capability = 0;
 
-	/* Make sure only supported capabilities are enabled in INI */
-	capability &= CFG_FINE_TIME_MEAS_CAPABILITY_MAX;
+	ucfg_mlme_get_fine_time_meas_cap(hdd_ctx->psoc, &capability);
 	ucfg_wifi_pos_set_ftm_cap(hdd_ctx->psoc, capability);
-
-	hdd_debug("fine time meas capability - INI: %04x Enabled: %04x",
-		config->fine_time_meas_cap,
-		capability);
+	hdd_debug("fine time meas capability - Enabled: %04x", capability);
 }
 
 /**
@@ -3029,9 +2941,6 @@ QDF_STATUS hdd_set_sme_config(struct hdd_context *hdd_ctx)
 		hdd_ctx->config->sap_channel_avoidance;
 #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
 
-	smeConfig->csrConfig.f_prefer_non_dfs_on_radar =
-		hdd_ctx->config->prefer_non_dfs_on_radar;
-
 	smeConfig->csrConfig.is_ps_enabled = hdd_ctx->config->is_ps_enabled;
 	smeConfig->csrConfig.auto_bmps_timer_val =
 		hdd_ctx->config->auto_bmps_timer_val;

+ 18 - 7
core/hdd/src/wlan_hdd_cfg80211.c

@@ -5589,6 +5589,7 @@ __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
 	uint16_t latency_level;
 	mac_handle_t mac_handle;
 	bool b_value;
+	uint32_t fine_time_meas_cap = 0;
 	struct wlan_objmgr_vdev *vdev;
 	uint8_t bmiss_first_bcnt;
 	uint8_t bmiss_final_bcnt;
@@ -5616,16 +5617,26 @@ __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
 	if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT]) {
 		ftm_capab = nla_get_u32(tb[
 			QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT]);
-		hdd_ctx->config->fine_time_meas_cap =
+		fine_time_meas_cap =
 			hdd_ctx->fine_time_meas_cap_target & ftm_capab;
+
+		qdf_status =
+			ucfg_mlme_set_fine_time_meas_cap(hdd_ctx->psoc,
+							 fine_time_meas_cap);
+		if (QDF_IS_STATUS_ERROR(qdf_status)) {
+			hdd_err("FTM capability:  values 0x%x, 0x%x, 0x%x",
+				ftm_capab, hdd_ctx->fine_time_meas_cap_target,
+				fine_time_meas_cap);
+			return -EINVAL;
+		}
+
 		sme_update_fine_time_measurement_capab(mac_handle,
-			adapter->session_id,
-			hdd_ctx->config->fine_time_meas_cap);
-		ucfg_wifi_pos_set_ftm_cap(hdd_ctx->psoc,
-			hdd_ctx->config->fine_time_meas_cap);
+						       adapter->session_id,
+						       fine_time_meas_cap);
+		ucfg_wifi_pos_set_ftm_cap(hdd_ctx->psoc, fine_time_meas_cap);
 		hdd_debug("FTM capability: user value: 0x%x, target value: 0x%x, final value: 0x%x",
-			 ftm_capab, hdd_ctx->fine_time_meas_cap_target,
-			 hdd_ctx->config->fine_time_meas_cap);
+			  ftm_capab, hdd_ctx->fine_time_meas_cap_target,
+			  fine_time_meas_cap);
 	}
 
 	if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM]) {

+ 7 - 8
core/hdd/src/wlan_hdd_hostapd.c

@@ -4628,10 +4628,11 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter,
 	uint16_t prev_rsn_length = 0;
 	enum dfs_mode mode;
 	struct hdd_adapter *sta_adapter;
-	uint8_t ignore_cac = 0;
+	bool ignore_cac = 0;
 	uint8_t beacon_fixed_len;
 	int value;
 	bool val;
+	uint32_t tx_leakage_threshold = 0;
 	uint32_t auto_channel_select_weight =
 		cfg_default(CFG_AUTO_CHANNEL_SELECT_WEIGHT);
 	uint8_t pref_chan_location = 0;
@@ -4768,7 +4769,6 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter,
 		hdd_err("ucfg_mlme_get_auto_channel_weight failed, set def");
 
 	pConfig->auto_channel_select_weight = auto_channel_select_weight;
-	pConfig->disableDFSChSwitch = iniConfig->disableDFSChSwitch;
 	ucfg_mlme_get_sap_chn_switch_bcn_count(hdd_ctx->psoc, &value);
 	pConfig->sap_chanswitch_beacon_cnt = value;
 	ucfg_mlme_get_sap_channel_switch_mode(hdd_ctx->psoc, &val);
@@ -4793,7 +4793,6 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter,
 
 	ucfg_mlme_get_sap_reduces_beacon_interval(hdd_ctx->psoc, &value);
 	pConfig->dtim_period = pBeacon->dtim_period;
-	pConfig->dfs_beacon_tx_enhanced = iniConfig->dfs_beacon_tx_enhanced;
 
 	pConfig->reduced_beacon_interval = value;
 	hdd_debug("acs_mode %d", pConfig->acs_cfg.acs_mode);
@@ -4866,14 +4865,13 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter,
 			goto error;
 		}
 
-		if (iniConfig->ignoreCAC ||
+		ucfg_mlme_get_dfs_ignore_cac(hdd_ctx->psoc, &ignore_cac);
+		if (ignore_cac ||
 		    ((mcc_to_scc_switch != QDF_MCC_TO_SCC_SWITCH_DISABLE) &&
 		    iniConfig->sta_sap_scc_on_dfs_chan))
 			ignore_cac = 1;
 
 		wlansap_set_dfs_ignore_cac(mac_handle, ignore_cac);
-		wlansap_set_dfs_restrict_japan_w53(mac_handle,
-			iniConfig->gDisableDfsJapanW53);
 		ucfg_mlme_get_pref_chan_location(hdd_ctx->psoc,
 						 &pref_chan_location);
 		wlansap_set_dfs_preferred_channel_location(mac_handle,
@@ -4890,8 +4888,9 @@ int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter,
 		pConfig->ieee80211d = 0;
 	}
 
-	wlansap_set_tx_leakage_threshold(mac_handle,
-		iniConfig->sap_tx_leakage_threshold);
+	ucfg_mlme_get_sap_tx_leakage_threshold(hdd_ctx->psoc,
+					       &tx_leakage_threshold);
+	tgt_dfs_set_tx_leakage_threshold(hdd_ctx->pdev, tx_leakage_threshold);
 
 	capab_info = pMgmt_frame->u.beacon.capab_info;
 

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

@@ -1885,6 +1885,7 @@ void hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg)
 	mac_handle_t mac_handle;
 	bool bval = false;
 	uint8_t value = 0;
+	uint32_t fine_time_meas_cap = 0;
 
 	if (!hdd_ctx) {
 		hdd_err("HDD context is NULL");
@@ -2051,10 +2052,19 @@ void hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg)
 	hdd_update_hw_dbs_capable(hdd_ctx);
 	hdd_ctx->dynamic_nss_chains_support =
 					cfg->dynamic_nss_chains_support;
-	hdd_ctx->config->fine_time_meas_cap &= cfg->fine_time_measurement_cap;
+	ucfg_mlme_get_fine_time_meas_cap(hdd_ctx->psoc, &fine_time_meas_cap);
+	fine_time_meas_cap &= cfg->fine_time_measurement_cap;
+	status = ucfg_mlme_set_fine_time_meas_cap(hdd_ctx->psoc,
+						  fine_time_meas_cap);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("failed to set fine_time_meas_cap, 0x%x, ox%x",
+			fine_time_meas_cap, cfg->fine_time_measurement_cap);
+		ucfg_mlme_get_fine_time_meas_cap(hdd_ctx->psoc,
+						 &fine_time_meas_cap);
+	}
+
 	hdd_ctx->fine_time_meas_cap_target = cfg->fine_time_measurement_cap;
-	hdd_debug("fine_time_meas_cap: 0x%x",
-		  hdd_ctx->config->fine_time_meas_cap);
+	hdd_debug("fine_time_meas_cap: 0x%x", fine_time_meas_cap);
 
 	status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
 	if (!QDF_IS_STATUS_SUCCESS(status))
@@ -2126,15 +2136,18 @@ bool hdd_dfs_indicate_radar(struct hdd_context *hdd_ctx)
 {
 	struct hdd_adapter *adapter;
 	struct hdd_ap_ctx *ap_ctx;
+	bool dfs_disable_channel_switch = false;
 
 	if (!hdd_ctx) {
 		hdd_info("Couldn't get hdd_ctx");
 		return true;
 	}
 
-	if (hdd_ctx->config->disableDFSChSwitch) {
+	ucfg_mlme_get_dfs_disable_channel_switch(hdd_ctx->psoc,
+						 &dfs_disable_channel_switch);
+	if (dfs_disable_channel_switch) {
 		hdd_info("skip tx block hdd_ctx=%pK, disableDFSChSwitch=%d",
-			 hdd_ctx, hdd_ctx->config->disableDFSChSwitch);
+			 hdd_ctx, dfs_disable_channel_switch);
 		return true;
 	}
 
@@ -9577,6 +9590,7 @@ int hdd_start_ap_adapter(struct hdd_adapter *adapter)
 	bool is_ssr = false;
 	int ret;
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	uint32_t fine_time_meas_cap = 0;
 
 	hdd_enter();
 
@@ -9606,12 +9620,14 @@ int hdd_start_ap_adapter(struct hdd_adapter *adapter)
 		return ret;
 	}
 
-	if (adapter->device_mode == QDF_SAP_MODE)
+	if (adapter->device_mode == QDF_SAP_MODE) {
+		ucfg_mlme_get_fine_time_meas_cap(hdd_ctx->psoc,
+						 &fine_time_meas_cap);
 		sme_cli_set_command(adapter->session_id,
 			WMI_VDEV_PARAM_ENABLE_DISABLE_RTT_RESPONDER_ROLE,
-			(bool)(hdd_ctx->config->fine_time_meas_cap &
-							WMI_FW_AP_RTT_RESPR),
+			(bool)(fine_time_meas_cap & WMI_FW_AP_RTT_RESPR),
 			VDEV_CMD);
+	}
 
 	status = hdd_init_ap_mode(adapter, is_ssr);
 
@@ -9712,14 +9728,6 @@ static int hdd_update_cds_config(struct hdd_context *hdd_ctx)
 	ucfg_mlme_get_sap_max_modulated_dtim(hdd_ctx->psoc,
 					     &cds_cfg->sta_maxlimod_dtim);
 
-	/*
-	 * Copy the DFS Phyerr Filtering Offload status.
-	 * This parameter reflects the value of the
-	 * dfs_phyerr_filter_offload flag as set in the ini.
-	 */
-	cds_cfg->dfs_phyerr_filter_offload =
-		hdd_ctx->config->fDfsPhyerrFilterOffload;
-
 	status = ucfg_mlme_get_crash_inject(hdd_ctx->psoc, &crash_inject);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("Failed to get crash inject ini config");
@@ -9754,8 +9762,6 @@ static int hdd_update_cds_config(struct hdd_context *hdd_ctx)
 						    &value);
 	cds_cfg->ap_maxoffload_reorderbuffs = value;
 
-	cds_cfg->dfs_pri_multiplier =
-		hdd_ctx->config->dfsRadarPriMultiplier;
 	cds_cfg->reorder_offload =
 			cfg_get(hdd_ctx->psoc, CFG_DP_REORDER_OFFLOAD_SUPPORT);
 
@@ -14229,11 +14235,11 @@ QDF_STATUS hdd_update_score_config(
 static int hdd_update_dfs_config(struct hdd_context *hdd_ctx)
 {
 	struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc;
-	struct hdd_config *cfg = hdd_ctx->config;
 	struct dfs_user_config dfs_cfg;
 	QDF_STATUS status;
 
-	dfs_cfg.dfs_is_phyerr_filter_offload = !!cfg->fDfsPhyerrFilterOffload;
+	ucfg_mlme_get_dfs_filter_offload(hdd_ctx->psoc,
+					 &dfs_cfg.dfs_is_phyerr_filter_offload);
 	status = ucfg_dfs_update_config(psoc, &dfs_cfg);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		hdd_err("failed dfs psoc configuration");

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

@@ -834,7 +834,6 @@ struct mac_context {
 	uint8_t beacon_offload;
 	bool pmf_offload;
 	bool is_fils_roaming_supported;
-	uint8_t f_prefer_non_dfs_on_radar;
 	uint32_t f_sta_miracast_mcc_rest_time_val;
 #ifdef WLAN_FEATURE_EXTWOW_SUPPORT
 	csr_readyToExtWoWCallback readyToExtWoWCallback;

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

@@ -32,9 +32,9 @@
 #define QWLAN_VERSION_MAJOR            5
 #define QWLAN_VERSION_MINOR            2
 #define QWLAN_VERSION_PATCH            0
-#define QWLAN_VERSION_EXTRA            "T"
+#define QWLAN_VERSION_EXTRA            "U"
 #define QWLAN_VERSION_BUILD            109
 
-#define QWLAN_VERSIONSTR               "5.2.0.109T"
+#define QWLAN_VERSIONSTR               "5.2.0.109U"
 
 #endif /* QWLAN_VERSION_H */

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

@@ -7936,7 +7936,7 @@ void lim_process_ap_ecsa_timeout(void *data)
 
 		ch = session->gLimChannelSwitch.primaryChannel;
 		ch_width = session->gLimChannelSwitch.ch_width;
-		if (mac_ctx->sap.SapDfsInfo.dfs_beacon_tx_enhanced)
+		if (mac_ctx->mlme_cfg->dfs_cfg.dfs_beacon_tx_enhanced)
 			/* Send Action frame after updating beacon */
 			lim_send_chan_switch_action_frame(mac_ctx, ch, ch_width,
 							  session);

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

@@ -587,7 +587,6 @@ typedef struct sap_config {
 	uint32_t ap_table_expiration_time;
 	uint32_t ht_op_mode_fixed;
 	enum QDF_OPMODE persona; /* Tells us which persona, GO or AP */
-	uint8_t disableDFSChSwitch;
 	bool enOverLapCh;
 #ifdef WLAN_FEATURE_11W
 	bool mfpRequired;
@@ -625,7 +624,6 @@ typedef struct sap_config {
 	uint8_t sap_chanswitch_beacon_cnt;
 	uint8_t sap_chanswitch_mode;
 	bool chan_switch_hostapd_rate_enabled;
-	bool dfs_beacon_tx_enhanced;
 	uint16_t reduced_beacon_interval;
 } tsap_config_t;
 
@@ -720,7 +718,6 @@ typedef struct sSapDfsInfo {
 	/* beacon count before channel switch */
 	uint8_t sap_ch_switch_beacon_cnt;
 	uint8_t sap_ch_switch_mode;
-	bool dfs_beacon_tx_enhanced;
 	uint16_t reduced_beacon_interval;
 } tSapDfsInfo;
 
@@ -1268,19 +1265,6 @@ QDF_STATUS wlansap_get_dfs_ignore_cac(mac_handle_t mac_handle,
 QDF_STATUS wlansap_set_dfs_ignore_cac(mac_handle_t mac_handle,
 				      uint8_t ignore_cac);
 
-/**
- * wlansap_set_dfs_restrict_japan_w53() - enable/disable dfS for japan
- * @mac_handle: Opaque handle to the global MAC context
- * @disable_dfs_w53: Indicates if Japan W53 is disabled when set to 1
- *                   Indicates if Japan W53 is enabled when set to 0
- *
- * This API is used to enable or disable Japan W53 Band
- * Return: The QDF_STATUS code associated with performing the operation
- *         QDF_STATUS_SUCCESS:  Success
- */
-QDF_STATUS wlansap_set_dfs_restrict_japan_w53(mac_handle_t mac_handle,
-					      uint8_t disable_dfs_w53);
-
 #ifdef FEATURE_AP_MCC_CH_AVOIDANCE
 QDF_STATUS
 wlan_sap_set_channel_avoidance(mac_handle_t mac_handle,
@@ -1438,18 +1422,6 @@ QDF_STATUS wlansap_acs_chselect(struct sap_context *sap_context,
  */
 uint32_t wlansap_get_chan_width(struct sap_context *sap_ctx);
 
-/**
- * wlansap_set_tx_leakage_threshold() - set sap tx leakage threshold.
- * @mac_handle: Opaque handle to the global MAC context
- * @tx_leakage_threshold: sap tx leakage threshold
- *
- * This function set sap tx leakage threshold.
- *
- * Return: QDF_STATUS.
- */
-QDF_STATUS wlansap_set_tx_leakage_threshold(mac_handle_t mac_handle,
-					    uint16_t tx_leakage_threshold);
-
 /*
  * wlansap_set_invalid_session() - set session ID to invalid
  * @sap_ctx: pointer to the SAP context

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

@@ -419,7 +419,7 @@ wlansap_roam_process_dfs_chansw_update(mac_handle_t mac_handle,
 	uint8_t dfs_beacon_start_req = 0;
 	bool sap_scc_dfs;
 
-	if (sap_ctx->csr_roamProfile.disableDFSChSwitch) {
+	if (mac_ctx->mlme_cfg->dfs_cfg.dfs_disable_channel_switch) {
 		QDF_TRACE(QDF_MODULE_ID_SAP,
 			  QDF_TRACE_LEVEL_ERROR,
 			  FL("sapdfs: DFS channel switch disabled"));
@@ -582,7 +582,7 @@ wlansap_roam_process_dfs_radar_found(tpAniSirGlobal mac_ctx,
 	tWLAN_SAPEvent sap_event;
 
 	if (sap_is_dfs_cac_wait_state(sap_ctx)) {
-		if (sap_ctx->csr_roamProfile.disableDFSChSwitch) {
+		if (mac_ctx->mlme_cfg->dfs_cfg.dfs_disable_channel_switch) {
 			QDF_TRACE(QDF_MODULE_ID_SAP,
 				QDF_TRACE_LEVEL_ERROR,
 				"sapdfs: DFS channel switch disabled");

+ 8 - 27
core/sap/src/sap_fsm.c

@@ -193,7 +193,7 @@ static uint8_t sap_random_channel_sel(struct sap_context *sap_ctx)
 	uint8_t ch_wd;
 	struct wlan_objmgr_pdev *pdev = NULL;
 	struct ch_params *ch_params;
-	uint32_t hw_mode;
+	uint32_t hw_mode, flag  = 0;
 	struct mac_context *mac_ctx;
 	struct dfs_acs_info acs_info = {0};
 
@@ -226,8 +226,12 @@ static uint8_t sap_random_channel_sel(struct sap_context *sap_ctx)
 	} else {
 		acs_info.acs_mode = false;
 	}
+
+	if (mac_ctx->mlme_cfg->dfs_cfg.dfs_prefer_non_dfs)
+		flag |= DFS_RANDOM_CH_FLAG_NO_DFS_CH;
+
 	if (QDF_IS_STATUS_ERROR(utils_dfs_get_random_channel(
-	    pdev, 0, ch_params, &hw_mode, &ch, &acs_info))) {
+	    pdev, flag, ch_params, &hw_mode, &ch, &acs_info))) {
 		/* No available channel found */
 		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
 			  FL("No available channel found!!!"));
@@ -544,34 +548,12 @@ void sap_dfs_set_current_channel(void *ctx)
 			tgt_dfs_get_radars(pdev);
 		}
 		tgt_dfs_set_phyerr_filter_offload(pdev);
-		if (sap_ctx->csr_roamProfile.disableDFSChSwitch)
+		if (mac_ctx->mlme_cfg->dfs_cfg.dfs_disable_channel_switch)
 			tgt_dfs_control(pdev, DFS_SET_USENOL, &use_nol,
 					sizeof(uint32_t), NULL, NULL, &error);
 	}
 }
 
-bool sap_dfs_is_w53_invalid(mac_handle_t mac_handle, uint8_t channel_id)
-{
-	tpAniSirGlobal mac;
-
-	mac = MAC_CONTEXT(mac_handle);
-	if (NULL == mac) {
-		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
-			  FL("invalid mac"));
-		return false;
-	}
-
-	/*
-	 * Check for JAPAN W53 Channel operation capability
-	 */
-	if (true == mac->sap.SapDfsInfo.is_dfs_w53_disabled &&
-	    true == IS_CHAN_JAPAN_W53(channel_id)) {
-		return true;
-	}
-
-	return false;
-}
-
 bool sap_dfs_is_channel_in_preferred_location(mac_handle_t mac_handle,
 					      uint8_t channel_id)
 {
@@ -2826,7 +2808,6 @@ sapconvert_to_csr_profile(tsap_config_t *pconfig_params, eCsrRoamBssType bssType
 	profile->BSSType = eCSR_BSS_TYPE_INFRA_AP;
 	profile->SSIDs.numOfSSIDs = 1;
 	profile->csrPersona = pconfig_params->persona;
-	profile->disableDFSChSwitch = pconfig_params->disableDFSChSwitch;
 
 	qdf_mem_zero(profile->SSIDs.SSIDList[0].SSID.ssId,
 		     sizeof(profile->SSIDs.SSIDList[0].SSID.ssId));
@@ -3462,7 +3443,7 @@ uint8_t sap_indicate_radar(struct sap_context *sap_ctx)
 	if (sap_ctx->fsm_state == SAP_STARTED)
 		mac->sap.SapDfsInfo.csaIERequired = true;
 
-	if (sap_ctx->csr_roamProfile.disableDFSChSwitch)
+	if (mac->mlme_cfg->dfs_cfg.dfs_disable_channel_switch)
 		return sap_ctx->channel;
 
 	/* set the Radar Found flag in SapDfsInfo */

+ 0 - 15
core/sap/src/sap_internal.h

@@ -387,21 +387,6 @@ bool sap_is_conc_sap_doing_scc_dfs(mac_handle_t mac_handle,
 
 uint8_t sap_get_total_number_sap_intf(mac_handle_t mac_handle);
 
-/**
- * sap_dfs_is_w53_invalid() - Check to see if invalid W53 operation requested
- * @mac_handle: Opaque handle to the global MAC context
- * @channel_id: Channel number to be verified
- *
- * This function checks if the passed channel is W53 and, if so, if
- * SAP W53 operation is allowed.
- *
- * Return:
- * * true - operation is invalid because the channel is W53 and W53
- *          operation has been disabled
- * * false - operation is valid
- */
-bool sap_dfs_is_w53_invalid(mac_handle_t mac_handle, uint8_t channel_id);
-
 /**
  * sap_dfs_is_channel_in_preferred_location() - Verify a channel is valid
  *	with respect to indoor/outdoor location setting

+ 0 - 64
core/sap/src/sap_module.c

@@ -721,8 +721,6 @@ QDF_STATUS wlansap_start_bss(struct sap_context *sap_ctx,
 	 * Copy the DFS Test Mode setting to pmac for
 	 * access in lower layers
 	 */
-	pmac->sap.SapDfsInfo.disable_dfs_ch_switch =
-				pConfig->disableDFSChSwitch;
 	pmac->sap.SapDfsInfo.sap_ch_switch_beacon_cnt =
 				pConfig->sap_chanswitch_beacon_cnt;
 	pmac->sap.SapDfsInfo.sap_ch_switch_mode =
@@ -733,8 +731,6 @@ QDF_STATUS wlansap_start_bss(struct sap_context *sap_ctx,
 		sap_ctx->csr_roamProfile.csrPersona;
 	pmac->sap.sapCtxList[sap_ctx->sessionId].sessionID =
 		sap_ctx->sessionId;
-	pmac->sap.SapDfsInfo.dfs_beacon_tx_enhanced =
-		pConfig->dfs_beacon_tx_enhanced;
 	pmac->sap.SapDfsInfo.reduced_beacon_interval =
 				pConfig->reduced_beacon_interval;
 
@@ -1857,47 +1853,6 @@ QDF_STATUS wlansap_set_dfs_ignore_cac(mac_handle_t mac_handle,
 	return QDF_STATUS_SUCCESS;
 }
 
-QDF_STATUS
-wlansap_set_dfs_restrict_japan_w53(mac_handle_t mac_handle,
-				   uint8_t disable_dfs_w53)
-{
-	tpAniSirGlobal mac = NULL;
-	QDF_STATUS status;
-	enum dfs_reg dfs_region;
-
-	if (NULL != mac_handle) {
-		mac = MAC_CONTEXT(mac_handle);
-	} else {
-		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
-			  "%s: Invalid mac_handle pointer", __func__);
-		return QDF_STATUS_E_FAULT;
-	}
-
-	wlan_reg_get_dfs_region(mac->pdev, &dfs_region);
-
-	/*
-	 * Set the JAPAN W53 restriction only if the current
-	 * regulatory domain is JAPAN.
-	 */
-	if (DFS_MKK_REGION == dfs_region) {
-		mac->sap.SapDfsInfo.is_dfs_w53_disabled = disable_dfs_w53;
-		QDF_TRACE(QDF_MODULE_ID_SAP,
-			  QDF_TRACE_LEVEL_INFO_LOW,
-			  FL("sapdfs: SET DFS JAPAN W53 DISABLED = %d"),
-			  mac->sap.SapDfsInfo.is_dfs_w53_disabled);
-
-		status = QDF_STATUS_SUCCESS;
-	} else {
-		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
-			  FL
-			 ("Regdomain not japan, set disable JP W53 not valid"));
-
-		status = QDF_STATUS_E_FAULT;
-	}
-
-	return status;
-}
-
 bool sap_is_auto_channel_select(struct sap_context *sapcontext)
 {
 	if (NULL == sapcontext) {
@@ -2448,25 +2403,6 @@ uint32_t wlansap_get_chan_width(struct sap_context *sap_ctx)
 	return wlan_sap_get_vht_ch_width(sap_ctx);
 }
 
-QDF_STATUS wlansap_set_tx_leakage_threshold(mac_handle_t mac_handle,
-					    uint16_t tx_leakage_threshold)
-{
-	tpAniSirGlobal mac;
-
-	if (NULL == mac_handle) {
-		QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
-			"%s: Invalid mac_handle pointer", __func__);
-		return QDF_STATUS_E_FAULT;
-	}
-
-	mac = MAC_CONTEXT(mac_handle);
-	tgt_dfs_set_tx_leakage_threshold(mac->pdev, tx_leakage_threshold);
-	QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG,
-		  "%s: leakage_threshold %d", __func__,
-		  tx_leakage_threshold);
-	return QDF_STATUS_SUCCESS;
-}
-
 QDF_STATUS wlansap_set_invalid_session(struct sap_context *sap_ctx)
 {
 	if (NULL == sap_ctx) {

+ 0 - 2
core/sme/inc/csr_api.h

@@ -880,7 +880,6 @@ struct csr_roam_profile {
 	uint8_t wps_state;
 	tCsrMobilityDomainInfo MDID;
 	enum QDF_OPMODE csrPersona;
-	uint8_t disableDFSChSwitch;
 	/* addIe params */
 	tSirAddIeParams addIeParams;
 	uint16_t beacon_tx_rate;
@@ -1119,7 +1118,6 @@ typedef struct tagCsrConfigParam {
 #ifdef FEATURE_AP_MCC_CH_AVOIDANCE
 	bool sap_channel_avoidance;
 #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
-	uint8_t f_prefer_non_dfs_on_radar;
 	bool is_ps_enabled;
 	uint32_t auto_bmps_timer_val;
 	uint32_t dual_mac_feature_disable;

+ 0 - 5
core/sme/src/csr/csr_api_roam.c

@@ -2721,9 +2721,6 @@ QDF_STATUS csr_change_default_config_param(tpAniSirGlobal mac,
 			pParam->sap_channel_avoidance;
 #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
 
-		mac->f_prefer_non_dfs_on_radar =
-			pParam->f_prefer_non_dfs_on_radar;
-
 		mac->sme.ps_global_info.ps_enabled =
 			pParam->is_ps_enabled;
 		mac->sme.ps_global_info.auto_bmps_timer_val =
@@ -2888,8 +2885,6 @@ QDF_STATUS csr_get_config_param(tpAniSirGlobal mac, tCsrConfigParam *pParam)
 	pParam->sap_channel_avoidance = mac->sap.sap_channel_avoidance;
 #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */
 	pParam->max_intf_count = mac->sme.max_intf_count;
-	pParam->f_prefer_non_dfs_on_radar =
-		mac->f_prefer_non_dfs_on_radar;
 	pParam->dual_mac_feature_disable =
 		mac->dual_mac_feature_disable;
 	pParam->sta_sap_scc_on_dfs_chan =

+ 115 - 0
os_if/p2p/inc/wlan_cfg80211_p2p.h

@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. 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: declares P2P functions interfacing with linux kernel
+ */
+
+#ifndef _WLAN_CFG80211_P2P_H_
+#define _WLAN_CFG80211_P2P_H_
+
+#include <qdf_types.h>
+
+struct wlan_objmgr_psoc;
+struct wlan_objmgr_vdev;
+struct ieee80211_channel;
+
+/**
+ * wlan_p2p_start() - start p2p component
+ * @psoc: soc object
+ *
+ * This function used to start P2P component and register events.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS wlan_p2p_start(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wlan_p2p_stop() - stop p2p component
+ * @psoc: soc object
+ *
+ * This function used to stop P2P component and unregister events.
+ *
+ * Return: QDF_STATUS_SUCCESS - in case of success
+ */
+QDF_STATUS wlan_p2p_stop(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * wlan_cfg80211_roc() - API to process cfg80211 roc request
+ * @vdev: Pointer to vdev object
+ * @chan: Pointer to channel
+ * @duration: Duration for this roc request
+ * @cookie: Pointer to return cookie to up layer
+ *
+ * API to trigger remain on channel request. It returns cookie
+ * as the identifier of roc.
+ *
+ * Return: 0 for success, non zero for failure
+ */
+int wlan_cfg80211_roc(struct wlan_objmgr_vdev *vdev,
+	struct ieee80211_channel *chan, uint32_t duration,
+	uint64_t *cookie);
+
+/**
+ * wlan_cfg80211_cancel_roc() - API to process cfg80211 cancel remain
+ * on channel request
+ * @vdev: Pointer to vdev object
+ * @cookie: Find out the roc request by cookie
+ *
+ * API to trigger cancel remain on channel request.
+ *
+ * Return: 0 for success, non zero for failure
+ */
+int wlan_cfg80211_cancel_roc(struct wlan_objmgr_vdev *vdev,
+	uint64_t cookie);
+
+/**
+ * wlan_cfg80211_mgmt_tx() - API to process cfg80211 mgmt tx request
+ * @vdev: Pointer to vdev object
+ * @chan: Pointer to channel
+ * @wait: wait time for this mgmt tx request
+ * @buf: TX buffer
+ * @len: Length of tx buffer
+ * @no_cck: Required cck or not
+ * @dont_wait_for_ack: Wait for ack or not
+ * @cookie: Return the cookie to caller
+ *
+ * API to trigger mgmt frame tx request. It returns cookie as the
+ * identifier of this tx.
+ *
+ * Return: 0 for success, non zero for failure
+ */
+int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev,
+	struct ieee80211_channel *chan, bool offchan, uint32_t wait,
+	const uint8_t *buf, uint32_t len, bool no_cck,
+	bool dont_wait_for_ack, uint64_t *cookie);
+
+/**
+ * wlan_cfg80211_mgmt_tx_cancel() - API to process cfg80211 cancel to
+ * wait mgmt tx
+ * @vdev: Pointer to vdev object
+ * @cookie: Find out the mgmt tx request by cookie
+ *
+ * API to trigger cancel mgmt frame tx request.
+ *
+ * Return: 0 for success, non zero for failure
+ */
+int wlan_cfg80211_mgmt_tx_cancel(struct wlan_objmgr_vdev *vdev,
+		uint64_t cookie);
+
+#endif /* _WLAN_CFG80211_P2P_H_ */

+ 499 - 0
os_if/p2p/src/wlan_cfg80211_p2p.c

@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: defines driver functions interfacing with linux kernel
+ */
+
+#include <qdf_util.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <wlan_objmgr_vdev_obj.h>
+#include <wlan_objmgr_peer_obj.h>
+#include <wlan_p2p_public_struct.h>
+#include <wlan_p2p_ucfg_api.h>
+#include <wlan_policy_mgr_api.h>
+#include <wlan_utility.h>
+#include <wlan_osif_priv.h>
+#include "wlan_cfg80211.h"
+#include "wlan_cfg80211_p2p.h"
+
+#define MAX_NO_OF_2_4_CHANNELS 14
+#define MAX_OFFCHAN_TIME_FOR_DNBS 150
+
+/**
+ * wlan_p2p_rx_callback() - Callback for rx mgmt frame
+ * @user_data: pointer to soc object
+ * @rx_frame: RX mgmt frame information
+ *
+ * This callback will be used to rx frames in os interface.
+ *
+ * Return: None
+ */
+static void wlan_p2p_rx_callback(void *user_data,
+	struct p2p_rx_mgmt_frame *rx_frame)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_vdev *vdev;
+	struct vdev_osif_priv *osif_priv;
+	struct wireless_dev *wdev;
+	uint16_t freq;
+
+	cfg80211_debug("user data:%pK, vdev id:%d, rssi:%d, buf:%pK, len:%d",
+		user_data, rx_frame->vdev_id, rx_frame->rx_rssi,
+		rx_frame->buf, rx_frame->frame_len);
+
+	psoc = user_data;
+	if (!psoc) {
+		cfg80211_err("psoc is null");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+		rx_frame->vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		cfg80211_err("vdev is null");
+		return;
+	}
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	if (!osif_priv) {
+		cfg80211_err("osif_priv is null");
+		goto fail;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		cfg80211_err("wdev is null");
+		goto fail;
+	}
+
+	if (rx_frame->rx_chan <= MAX_NO_OF_2_4_CHANNELS)
+		freq = ieee80211_channel_to_frequency(
+			rx_frame->rx_chan, NL80211_BAND_2GHZ);
+	else
+		freq = ieee80211_channel_to_frequency(
+			rx_frame->rx_chan, NL80211_BAND_5GHZ);
+
+	cfg80211_debug("Indicate frame over nl80211, vdev id:%d, idx:%d",
+		   rx_frame->vdev_id, wdev->netdev->ifindex);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len,
+		NL80211_RXMGMT_FLAG_ANSWERED);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len,
+		NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
+#else
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len, GFP_ATOMIC);
+#endif /* LINUX_VERSION_CODE */
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+}
+
+/**
+ * wlan_p2p_action_tx_cnf_callback() - Callback for tx confirmation
+ * @user_data: pointer to soc object
+ * @tx_cnf: tx confirmation information
+ *
+ * This callback will be used to give tx mgmt frame confirmation to
+ * os interface.
+ *
+ * Return: None
+ */
+static void wlan_p2p_action_tx_cnf_callback(void *user_data,
+	struct p2p_tx_cnf *tx_cnf)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_vdev *vdev;
+	struct vdev_osif_priv *osif_priv;
+	struct wireless_dev *wdev;
+	bool is_success;
+
+	cfg80211_debug("user data:%pK, action cookie:%llx, buf:%pK, len:%d, tx status:%d",
+		user_data, tx_cnf->action_cookie, tx_cnf->buf,
+		tx_cnf->buf_len, tx_cnf->status);
+
+	psoc = user_data;
+	if (!psoc) {
+		cfg80211_err("psoc is null");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+		tx_cnf->vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		cfg80211_err("vdev is null");
+		return;
+	}
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	if (!osif_priv) {
+		cfg80211_err("osif_priv is null");
+		goto fail;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		cfg80211_err("wireless dev is null");
+		goto fail;
+	}
+
+	is_success = tx_cnf->status ? false : true;
+	cfg80211_mgmt_tx_status(
+		wdev,
+		tx_cnf->action_cookie,
+		tx_cnf->buf, tx_cnf->buf_len,
+		is_success, GFP_KERNEL);
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+}
+
+#ifdef FEATURE_P2P_LISTEN_OFFLOAD
+/**
+ * wlan_p2p_lo_event_callback() - Callback for listen offload event
+ * @user_data: pointer to soc object
+ * @p2p_lo_event: listen offload event information
+ *
+ * This callback will be used to give listen offload event to os interface.
+ *
+ * Return: None
+ */
+static void wlan_p2p_lo_event_callback(void *user_data,
+	struct p2p_lo_event *p2p_lo_event)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_vdev *vdev;
+	struct vdev_osif_priv *osif_priv;
+	struct wireless_dev *wdev;
+	struct sk_buff *vendor_event;
+
+	cfg80211_debug("user data:%pK, vdev id:%d, reason code:%d",
+		user_data, p2p_lo_event->vdev_id,
+		p2p_lo_event->reason_code);
+
+	psoc = user_data;
+	if (!psoc) {
+		cfg80211_err("psoc is null");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+		p2p_lo_event->vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		cfg80211_err("vdev is null");
+		return;
+	}
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	if (!osif_priv) {
+		cfg80211_err("osif_priv is null");
+		goto fail;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		cfg80211_err("wireless dev is null");
+		goto fail;
+	}
+
+	vendor_event = cfg80211_vendor_event_alloc(wdev->wiphy, NULL,
+			sizeof(uint32_t) + NLMSG_HDRLEN,
+			QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX,
+			GFP_KERNEL);
+	if (!vendor_event) {
+		cfg80211_err("cfg80211_vendor_event_alloc failed");
+		goto fail;
+	}
+
+	if (nla_put_u32(vendor_event,
+		QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON,
+		p2p_lo_event->reason_code)) {
+		cfg80211_err("nla put failed");
+		kfree_skb(vendor_event);
+		goto fail;
+	}
+
+	cfg80211_vendor_event(vendor_event, GFP_KERNEL);
+
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+}
+
+static inline void wlan_p2p_init_lo_event(struct p2p_start_param *start_param,
+					  struct wlan_objmgr_psoc *psoc)
+{
+	start_param->lo_event_cb = wlan_p2p_lo_event_callback;
+	start_param->lo_event_cb_data = psoc;
+}
+#else
+static inline void wlan_p2p_init_lo_event(struct p2p_start_param *start_param,
+					  struct wlan_objmgr_psoc *psoc)
+{
+}
+#endif /* FEATURE_P2P_LISTEN_OFFLOAD */
+/**
+ * wlan_p2p_event_callback() - Callback for P2P event
+ * @user_data: pointer to soc object
+ * @p2p_event: p2p event information
+ *
+ * This callback will be used to give p2p event to os interface.
+ *
+ * Return: None
+ */
+static void wlan_p2p_event_callback(void *user_data,
+	struct p2p_event *p2p_event)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_vdev *vdev;
+	struct ieee80211_channel *chan;
+	struct vdev_osif_priv *osif_priv;
+	struct wireless_dev *wdev;
+
+	cfg80211_debug("user data:%pK, vdev id:%d, event type:%d",
+		user_data, p2p_event->vdev_id, p2p_event->roc_event);
+
+	psoc = user_data;
+	if (!psoc) {
+		cfg80211_err("psoc is null");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+		p2p_event->vdev_id, WLAN_P2P_ID);
+	if (!vdev) {
+		cfg80211_err("vdev is null");
+		return;
+	}
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	if (!osif_priv) {
+		cfg80211_err("osif_priv is null");
+		goto fail;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		cfg80211_err("wireless dev is null");
+		goto fail;
+	}
+
+	chan = ieee80211_get_channel(wdev->wiphy,
+				     wlan_chan_to_freq(p2p_event->chan));
+	if (!chan) {
+		cfg80211_err("channel conversion failed");
+		goto fail;
+	}
+
+	if (p2p_event->roc_event == ROC_EVENT_READY_ON_CHAN) {
+		cfg80211_ready_on_channel(wdev,
+			p2p_event->cookie, chan,
+			p2p_event->duration, GFP_KERNEL);
+	} else if (p2p_event->roc_event == ROC_EVENT_COMPLETED) {
+		cfg80211_remain_on_channel_expired(wdev,
+			p2p_event->cookie, chan, GFP_KERNEL);
+	} else {
+		cfg80211_err("Invalid p2p event");
+	}
+
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID);
+}
+
+QDF_STATUS wlan_p2p_start(struct wlan_objmgr_psoc *psoc)
+{
+	struct p2p_start_param start_param;
+
+	if (!psoc) {
+		cfg80211_err("psoc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	start_param.rx_cb = wlan_p2p_rx_callback;
+	start_param.rx_cb_data = psoc;
+	start_param.event_cb = wlan_p2p_event_callback;
+	start_param.event_cb_data = psoc;
+	start_param.tx_cnf_cb = wlan_p2p_action_tx_cnf_callback;
+	start_param.tx_cnf_cb_data = psoc;
+	wlan_p2p_init_lo_event(&start_param, psoc);
+
+	return ucfg_p2p_psoc_start(psoc, &start_param);
+}
+
+QDF_STATUS wlan_p2p_stop(struct wlan_objmgr_psoc *psoc)
+{
+	if (!psoc) {
+		cfg80211_err("psoc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return ucfg_p2p_psoc_stop(psoc);
+}
+
+int wlan_cfg80211_roc(struct wlan_objmgr_vdev *vdev,
+	struct ieee80211_channel *chan, uint32_t duration,
+	uint64_t *cookie)
+{
+	struct p2p_roc_req roc_req = {0};
+	struct wlan_objmgr_psoc *psoc;
+	uint8_t vdev_id;
+	bool ok;
+	int ret;
+
+	if (!vdev) {
+		cfg80211_err("invalid vdev object");
+		return -EINVAL;
+	}
+
+	if (!chan) {
+		cfg80211_err("invalid channel");
+		return -EINVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	vdev_id = wlan_vdev_get_id(vdev);
+	if (!psoc) {
+		cfg80211_err("psoc handle is NULL");
+		return -EINVAL;
+	}
+
+	roc_req.chan = (uint32_t)wlan_freq_to_chan(chan->center_freq);
+	roc_req.duration = duration;
+	roc_req.vdev_id = (uint32_t)vdev_id;
+
+	ret = policy_mgr_is_chan_ok_for_dnbs(psoc, roc_req.chan, &ok);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		cfg80211_err("policy_mgr_is_chan_ok_for_dnbs():ret:%d",
+			ret);
+		return -EINVAL;
+	}
+
+	if (!ok) {
+		cfg80211_err("channel%d not OK for DNBS", roc_req.chan);
+		return -EINVAL;
+	}
+
+	return qdf_status_to_os_return(
+		ucfg_p2p_roc_req(psoc, &roc_req, cookie));
+}
+
+int wlan_cfg80211_cancel_roc(struct wlan_objmgr_vdev *vdev,
+		uint64_t cookie)
+{
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!vdev) {
+		cfg80211_err("invalid vdev object");
+		return -EINVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		cfg80211_err("psoc handle is NULL");
+		return -EINVAL;
+	}
+
+	return qdf_status_to_os_return(
+		ucfg_p2p_roc_cancel_req(psoc, cookie));
+}
+
+int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev,
+		struct ieee80211_channel *chan, bool offchan,
+		unsigned int wait,
+		const uint8_t *buf, uint32_t len, bool no_cck,
+		bool dont_wait_for_ack, uint64_t *cookie)
+{
+	struct p2p_mgmt_tx mgmt_tx = {0};
+	struct wlan_objmgr_psoc *psoc;
+	uint8_t vdev_id;
+
+	if (!vdev) {
+		cfg80211_err("invalid vdev object");
+		return -EINVAL;
+	}
+
+	if (!chan) {
+		cfg80211_err("invalid channel");
+		return -EINVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	vdev_id = wlan_vdev_get_id(vdev);
+	if (!psoc) {
+		cfg80211_err("psoc handle is NULL");
+		return -EINVAL;
+	}
+
+	/**
+	 * When offchannel time is more than MAX_OFFCHAN_TIME_FOR_DNBS,
+	 * allow offchannel only if Do_Not_Switch_Channel is not set.
+	 */
+	if (wait > MAX_OFFCHAN_TIME_FOR_DNBS) {
+		int ret;
+		bool ok;
+		uint32_t channel = wlan_freq_to_chan(chan->center_freq);
+
+		ret = policy_mgr_is_chan_ok_for_dnbs(psoc, channel, &ok);
+		if (QDF_IS_STATUS_ERROR(ret)) {
+			cfg80211_err("policy_mgr_is_chan_ok_for_dnbs():ret:%d",
+				ret);
+			return -EINVAL;
+		}
+		if (!ok) {
+			cfg80211_err("Rejecting mgmt_tx for channel:%d as DNSC is set",
+				channel);
+			return -EINVAL;
+		}
+	}
+
+	mgmt_tx.vdev_id = (uint32_t)vdev_id;
+	mgmt_tx.chan = (uint32_t)wlan_freq_to_chan(chan->center_freq);
+	mgmt_tx.wait = wait;
+	mgmt_tx.len = len;
+	mgmt_tx.no_cck = (uint32_t)no_cck;
+	mgmt_tx.dont_wait_for_ack = (uint32_t)dont_wait_for_ack;
+	mgmt_tx.off_chan = (uint32_t)offchan;
+	mgmt_tx.buf = buf;
+
+	return qdf_status_to_os_return(
+		ucfg_p2p_mgmt_tx(psoc, &mgmt_tx, cookie));
+}
+
+int wlan_cfg80211_mgmt_tx_cancel(struct wlan_objmgr_vdev *vdev,
+	uint64_t cookie)
+{
+	struct wlan_objmgr_psoc *psoc;
+
+	if (!vdev) {
+		cfg80211_err("invalid vdev object");
+		return -EINVAL;
+	}
+
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (!psoc) {
+		cfg80211_err("psoc handle is NULL");
+		return -EINVAL;
+	}
+
+	return qdf_status_to_os_return(
+		ucfg_p2p_mgmt_tx_cancel(psoc, vdev, cookie));
+}

+ 309 - 0
os_if/tdls/inc/wlan_cfg80211_tdls.h

@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: declares driver functions interfacing with linux kernel
+ */
+
+#ifndef _WLAN_CFG80211_TDLS_H_
+#define _WLAN_CFG80211_TDLS_H_
+
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/completion.h>
+#include <net/cfg80211.h>
+#include <qca_vendor.h>
+#include <wlan_tdls_public_structs.h>
+#include <qdf_list.h>
+#include <qdf_types.h>
+#include <wlan_tdls_ucfg_api.h>
+
+#ifdef CONVERGED_TDLS_ENABLE
+
+#define TDLS_VDEV_MAGIC 0x54444c53       /* "TDLS" */
+
+/**
+ * struct osif_tdls_vdev - OS tdls vdev private structure
+ * @tdls_add_peer_comp: Completion to add tdls peer
+ * @tdls_del_peer_comp: Completion to delete tdls peer
+ * @tdls_mgmt_comp: Completion to send tdls mgmt packets
+ * @tdls_link_establish_req_comp: Completion to establish link, sync to
+ * send establish params to firmware, not used today.
+ * @tdls_teardown_comp: Completion to teardown tdls peer
+ * @tdls_user_cmd_comp: tdls user command completion event
+ * @tdls_antenna_switch_comp: Completion to switch antenna
+ * @tdls_add_peer_status: Peer status after add peer
+ * @mgmt_tx_completion_status: Tdls mgmt frames TX completion status code
+ * @tdls_user_cmd_len: tdls user command written buffer length
+ * @tdls_antenna_switch_status: return status after antenna switch
+ */
+struct osif_tdls_vdev {
+	struct completion tdls_add_peer_comp;
+	struct completion tdls_del_peer_comp;
+	struct completion tdls_mgmt_comp;
+	struct completion tdls_link_establish_req_comp;
+	struct completion tdls_teardown_comp;
+	struct completion tdls_user_cmd_comp;
+	struct completion tdls_antenna_switch_comp;
+	QDF_STATUS tdls_add_peer_status;
+	uint32_t mgmt_tx_completion_status;
+	uint32_t tdls_user_cmd_len;
+	int tdls_antenna_switch_status;
+};
+
+/**
+ * enum qca_wlan_vendor_tdls_trigger_mode_vdev_map: Maps the user space TDLS
+ *	trigger mode in the host driver.
+ * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: TDLS Connection and
+ *	disconnection handled by user space.
+ * @WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: TDLS connection and
+ *	disconnection controlled by host driver based on data traffic.
+ * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: TDLS connection and
+ *	disconnection jointly controlled by user space and host driver.
+ */
+enum qca_wlan_vendor_tdls_trigger_mode_vdev_map {
+	WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT =
+		QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT,
+	WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT =
+		QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT,
+	WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL =
+		((QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT |
+		  QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT) << 1),
+};
+
+/**
+ * wlan_cfg80211_tdls_priv_init() - API to initialize tdls os private
+ * @osif_priv: vdev os private
+ *
+ * API to initialize tdls os private
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_cfg80211_tdls_priv_init(struct vdev_osif_priv *osif_priv);
+
+/**
+ * wlan_cfg80211_tdls_priv_deinit() - API to deinitialize tdls os private
+ * @osif_priv: vdev os private
+ *
+ * API to deinitialize tdls os private
+ *
+ * Return: None
+ */
+void wlan_cfg80211_tdls_priv_deinit(struct vdev_osif_priv *osif_priv);
+
+/**
+ * wlan_cfg80211_tdls_add_peer() - process cfg80211 add TDLS peer request
+ * @vdev: vdev object
+ * @mac: MAC address for TDLS peer
+ *
+ * Return: 0 for success; negative errno otherwise
+ */
+int wlan_cfg80211_tdls_add_peer(struct wlan_objmgr_vdev *vdev,
+				const uint8_t *mac);
+
+/**
+ * wlan_cfg80211_tdls_update_peer() - process cfg80211 update TDLS peer request
+ * @vdev: vdev object
+ * @mac: MAC address for TDLS peer
+ * @params: Pointer to station parameters
+ *
+ * Return: 0 for success; negative errno otherwise
+ */
+int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_vdev *vdev,
+				   const uint8_t *mac,
+				   struct station_parameters *params);
+
+/**
+ * wlan_cfg80211_tdls_configure_mode() - configure tdls mode
+ * @vdev: vdev obj manager
+ * @trigger_mode: tdls trgger mode
+ *
+ * Return: 0 for success; negative errno otherwise
+ */
+int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev,
+						uint32_t trigger_mode);
+
+/**
+ * wlan_cfg80211_tdls_oper() - process cfg80211 operation on an TDLS peer
+ * @vdev: vdev object
+ * @peer: MAC address of the TDLS peer
+ * @oper: cfg80211 TDLS operation
+ *
+ * Return: 0 on success; negative errno otherwise
+ */
+int wlan_cfg80211_tdls_oper(struct wlan_objmgr_vdev *vdev,
+			    const uint8_t *peer,
+			    enum nl80211_tdls_operation oper);
+
+/**
+ * wlan_cfg80211_tdls_get_all_peers() - get all the TDLS peers from the list
+ * @vdev: vdev object
+ * @buf: output buffer
+ * @buflen: valid length of the output error
+ *
+ * Return: length of the output buffer
+ */
+int wlan_cfg80211_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev,
+				char *buf, int buflen);
+
+/**
+ * wlan_cfg80211_tdls_mgmt() - process tdls management frames from the supplicant
+ * @vdev: vdev object
+ * @peer: MAC address of the TDLS peer
+ * @action_code: type of TDLS mgmt frame to be sent
+ * @dialog_token: dialog token used in the frame
+ * @status_code: status to be incuded in the frame
+ * @peer_capability: peer capability information
+ * @buf: additional IEs to be included
+ * @len: length of additional Ies
+ * @oper: cfg80211 TDLS operation
+ *
+ * Return: 0 on success; negative errno otherwise
+ */
+int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_vdev *vdev,
+			    const uint8_t *peer,
+			    uint8_t action_code, uint8_t dialog_token,
+			    uint16_t status_code, uint32_t peer_capability,
+			    const uint8_t *buf, size_t len);
+
+/**
+ * wlan_tdls_antenna_switch() - process tdls antenna switch
+ * @vdev: vdev object
+ * @mode: antenna mode
+ *
+ * Return: 0 on success; -EAGAIN to retry
+ */
+int wlan_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev, uint32_t mode);
+
+/**
+ * wlan_cfg80211_tdls_event_callback() - callback for tdls module
+ * @userdata: user data
+ * @type: request callback type
+ * @param: passed parameter
+ *
+ * This is used by TDLS to sync with os interface
+ *
+ * Return: None
+ */
+void wlan_cfg80211_tdls_event_callback(void *userdata,
+				       enum tdls_event_type type,
+				       struct tdls_osif_indication *param);
+
+/**
+ * wlan_cfg80211_tdls_rx_callback() - Callback for rx mgmt frame
+ * @user_data: pointer to soc object
+ * @rx_frame: RX mgmt frame information
+ *
+ * This callback will be used to rx frames in os interface.
+ *
+ * Return: None
+ */
+void wlan_cfg80211_tdls_rx_callback(void *user_data,
+	struct tdls_rx_mgmt_frame *rx_frame);
+
+/**
+ * hdd_notify_tdls_reset_adapter() - notify reset adapter to TDLS
+ * @vdev: vdev object manager
+ *
+ * Notify hdd reset adapter to TDLS component
+ *
+ * Return: None
+ */
+void hdd_notify_tdls_reset_adapter(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * hdd_notify_sta_connect() - notify sta connect to TDLS
+ * @session_id: pointer to soc object
+ * @tdls_chan_swit_prohibited: indicates channel switch capability
+ * @tdls_prohibited: indicates tdls allowed or not
+ * @vdev: vdev object manager
+ *
+ * Notify sta connect event to TDLS component
+ *
+ * Return: None
+ */
+void
+hdd_notify_sta_connect(uint8_t session_id,
+		       bool tdls_chan_swit_prohibited,
+		       bool tdls_prohibited,
+		       struct wlan_objmgr_vdev *vdev);
+
+/**
+ * hdd_notify_sta_disconnect() - notify sta disconnect to TDLS
+ * @session_id: pointer to soc object
+ * @lfr_roam: indicate, whether disconnect due to lfr roam
+ * @bool user_disconnect: disconnect from user space
+ * @vdev: vdev object manager
+ *
+ * Notify sta disconnect event to TDLS component
+ *
+ * Return: None
+ */
+void hdd_notify_sta_disconnect(uint8_t session_id,
+			       bool lfr_roam,
+			       bool user_disconnect,
+			       struct wlan_objmgr_vdev *vdev);
+
+/**
+ * hdd_notify_teardown_tdls_links() - notify TDLS to teardown links
+ * @vdev: vdev object manager
+ *
+ * Notify tdls to teardown all the links, due to certain events
+ * in the system
+ *
+ * Return: None
+ */
+void hdd_notify_teardown_tdls_links(struct wlan_objmgr_vdev *vdev);
+
+#else
+static inline void
+hdd_notify_tdls_reset_adapter(struct wlan_objmgr_vdev *vdev)
+{
+}
+
+static inline void
+hdd_notify_sta_connect(uint8_t session_id,
+		       bool tdls_chan_swit_prohibited,
+		       bool tdls_prohibited,
+		       struct wlan_objmgr_vdev *vdev)
+{
+}
+
+static inline
+void hdd_notify_sta_disconnect(uint8_t session_id,
+			       bool lfr_roam,
+			       bool user_disconnect,
+			       struct wlan_objmgr_vdev *vdev)
+{
+
+}
+
+static inline
+int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev,
+						uint32_t trigger_mode)
+{
+	return 0;
+}
+
+static inline
+void hdd_notify_teardown_tdls_links(struct wlan_objmgr_vdev *vdev)
+{
+
+}
+#endif
+#endif

+ 922 - 0
os_if/tdls/src/wlan_cfg80211_tdls.c

@@ -0,0 +1,922 @@
+/*
+ * Copyright (c) 2017-2018 The Linux Foundation. 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: defines driver functions interfacing with linux kernel
+ */
+
+#include <qdf_list.h>
+#include <qdf_status.h>
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <net/cfg80211.h>
+#include <wlan_cfg80211.h>
+#include <wlan_cfg80211_tdls.h>
+#include <wlan_osif_priv.h>
+#include <wlan_tdls_public_structs.h>
+#include <wlan_tdls_ucfg_api.h>
+#include <qdf_mem.h>
+#include <wlan_utility.h>
+#include <wlan_reg_services_api.h>
+
+#define MAX_CHANNEL (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS)
+
+
+#define TDLS_MAX_NO_OF_2_4_CHANNELS 14
+
+static int wlan_cfg80211_tdls_validate_mac_addr(const uint8_t *mac)
+{
+	static const uint8_t temp_mac[QDF_MAC_ADDR_SIZE] = {0};
+
+	if (!qdf_mem_cmp(mac, temp_mac, QDF_MAC_ADDR_SIZE)) {
+		cfg80211_debug("Invalid Mac address " QDF_MAC_ADDR_STR " cmd declined.",
+		QDF_MAC_ADDR_ARRAY(mac));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+QDF_STATUS wlan_cfg80211_tdls_priv_init(struct vdev_osif_priv *osif_priv)
+{
+	struct osif_tdls_vdev *tdls_priv;
+
+	cfg80211_debug("initialize tdls os if layer private structure");
+	tdls_priv = qdf_mem_malloc(sizeof(*tdls_priv));
+	if (!tdls_priv) {
+		cfg80211_err("failed to allocate memory for tdls_priv");
+		return QDF_STATUS_E_NOMEM;
+	}
+	init_completion(&tdls_priv->tdls_add_peer_comp);
+	init_completion(&tdls_priv->tdls_del_peer_comp);
+	init_completion(&tdls_priv->tdls_mgmt_comp);
+	init_completion(&tdls_priv->tdls_link_establish_req_comp);
+	init_completion(&tdls_priv->tdls_teardown_comp);
+	init_completion(&tdls_priv->tdls_user_cmd_comp);
+	init_completion(&tdls_priv->tdls_antenna_switch_comp);
+
+	osif_priv->osif_tdls = tdls_priv;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void wlan_cfg80211_tdls_priv_deinit(struct vdev_osif_priv *osif_priv)
+{
+	cfg80211_debug("deinitialize tdls os if layer private structure");
+	if (!osif_priv) {
+		cfg80211_err("OS private structure of vdev is null ");
+		return;
+	}
+	if (osif_priv->osif_tdls)
+		qdf_mem_free(osif_priv->osif_tdls);
+	osif_priv->osif_tdls = NULL;
+}
+
+void hdd_notify_teardown_tdls_links(struct wlan_objmgr_vdev *vdev)
+{
+	struct vdev_osif_priv *osif_priv;
+	struct osif_tdls_vdev *tdls_priv;
+	QDF_STATUS status;
+	unsigned long rc;
+
+	if (!vdev)
+		return;
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+
+	tdls_priv = osif_priv->osif_tdls;
+
+	reinit_completion(&tdls_priv->tdls_teardown_comp);
+	status = ucfg_tdls_teardown_links(vdev);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("ucfg_tdls_teardown_links failed err %d", status);
+		return;
+	}
+
+	cfg80211_debug("Wait for tdls teardown completion. Timeout %u ms",
+		       WAIT_TIME_FOR_TDLS_TEARDOWN_LINKS);
+
+	rc = wait_for_completion_timeout(
+		&tdls_priv->tdls_teardown_comp,
+		msecs_to_jiffies(WAIT_TIME_FOR_TDLS_TEARDOWN_LINKS));
+
+	if (0 == rc) {
+		cfg80211_err(" Teardown Completion timed out rc: %ld", rc);
+		return;
+	}
+
+	cfg80211_debug("TDLS teardown completion status %ld ", rc);
+}
+
+void hdd_notify_tdls_reset_adapter(struct wlan_objmgr_vdev *vdev)
+{
+	ucfg_tdls_notify_reset_adapter(vdev);
+}
+
+void
+hdd_notify_sta_connect(uint8_t session_id,
+		       bool tdls_chan_swit_prohibited,
+		       bool tdls_prohibited,
+		       struct wlan_objmgr_vdev *vdev)
+{
+	struct tdls_sta_notify_params notify_info = {0};
+	QDF_STATUS status;
+
+	if (!vdev) {
+		cfg80211_err("vdev is NULL");
+		return;
+	}
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("can't get vdev");
+		return;
+	}
+
+	notify_info.session_id = session_id;
+	notify_info.vdev = vdev;
+	notify_info.tdls_chan_swit_prohibited = tdls_chan_swit_prohibited;
+	notify_info.tdls_prohibited = tdls_prohibited;
+	ucfg_tdls_notify_sta_connect(&notify_info);
+}
+
+void hdd_notify_sta_disconnect(uint8_t session_id,
+			       bool lfr_roam,
+			       bool user_disconnect,
+			       struct wlan_objmgr_vdev *vdev)
+{
+	struct tdls_sta_notify_params notify_info = {0};
+	QDF_STATUS status;
+
+	if (!vdev) {
+		cfg80211_err("vdev is NULL");
+		return;
+	}
+
+	status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("can't get vdev");
+		return;
+	}
+
+	notify_info.session_id = session_id;
+	notify_info.lfr_roam = lfr_roam;
+	notify_info.tdls_chan_swit_prohibited = false;
+	notify_info.tdls_prohibited = false;
+	notify_info.vdev = vdev;
+	notify_info.user_disconnect = user_disconnect;
+	ucfg_tdls_notify_sta_disconnect(&notify_info);
+}
+
+int wlan_cfg80211_tdls_add_peer(struct wlan_objmgr_vdev *vdev,
+				const uint8_t *mac)
+{
+	struct tdls_add_peer_params *add_peer_req;
+	int status;
+	struct vdev_osif_priv *osif_priv;
+	struct osif_tdls_vdev *tdls_priv;
+	unsigned long rc;
+
+	status = wlan_cfg80211_tdls_validate_mac_addr(mac);
+
+	if (status)
+		return status;
+
+	cfg80211_debug("Add TDLS peer " QDF_MAC_ADDR_STR,
+		       QDF_MAC_ADDR_ARRAY(mac));
+
+	add_peer_req = qdf_mem_malloc(sizeof(*add_peer_req));
+	if (!add_peer_req) {
+		cfg80211_err("Failed to allocate tdls add peer request mem");
+		return -EINVAL;
+	}
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	tdls_priv = osif_priv->osif_tdls;
+	add_peer_req->vdev_id = wlan_vdev_get_id(vdev);
+
+	qdf_mem_copy(add_peer_req->peer_addr, mac, QDF_MAC_ADDR_SIZE);
+
+	reinit_completion(&tdls_priv->tdls_add_peer_comp);
+	status = ucfg_tdls_add_peer(vdev, add_peer_req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("ucfg_tdls_add_peer returned err %d", status);
+		status = -EIO;
+		goto error;
+	}
+
+	rc = wait_for_completion_timeout(
+	    &tdls_priv->tdls_add_peer_comp,
+	    msecs_to_jiffies(WAIT_TIME_TDLS_ADD_STA));
+	if (!rc) {
+		cfg80211_err("timeout for tdls add peer indication %ld", rc);
+		status = -EPERM;
+		goto error;
+	}
+
+	if (QDF_IS_STATUS_ERROR(tdls_priv->tdls_add_peer_status)) {
+		cfg80211_err("tdls add peer failed, status:%d",
+			     tdls_priv->tdls_add_peer_status);
+		status = -EPERM;
+	}
+error:
+	qdf_mem_free(add_peer_req);
+	return status;
+}
+
+static bool
+is_duplicate_channel(uint8_t *arr, int index, uint8_t match)
+{
+	int i;
+
+	for (i = 0; i < index; i++) {
+		if (arr[i] == match)
+			return true;
+	}
+	return false;
+}
+
+static void
+tdls_calc_channels_from_staparams(struct tdls_update_peer_params *req_info,
+				  struct station_parameters *params)
+{
+	int i = 0, j = 0, k = 0, no_of_channels = 0;
+	int num_unique_channels;
+	int next;
+	uint8_t *dest_chans;
+	const uint8_t *src_chans;
+
+	dest_chans = req_info->supported_channels;
+	src_chans = params->supported_channels;
+
+	/* Convert (first channel , number of channels) tuple to
+	 * the total list of channels. This goes with the assumption
+	 * that if the first channel is < 14, then the next channels
+	 * are an incremental of 1 else an incremental of 4 till the number
+	 * of channels.
+	 */
+	for (i = 0; i < params->supported_channels_len &&
+	     j < WLAN_MAC_MAX_SUPP_CHANNELS; i += 2) {
+		int wifi_chan_index;
+
+		if (!is_duplicate_channel(dest_chans, j, src_chans[i]))
+			dest_chans[j] = src_chans[i];
+		else
+			continue;
+
+		wifi_chan_index = ((dest_chans[j] <= WLAN_CHANNEL_14) ? 1 : 4);
+		no_of_channels = src_chans[i + 1];
+
+		cfg80211_debug("i:%d,j:%d,k:%d,[%d]:%d,index:%d,chans_num: %d",
+			       i, j, k, j,
+			       dest_chans[j],
+			       wifi_chan_index,
+			       no_of_channels);
+
+		for (k = 1; k <= no_of_channels &&
+		     j < WLAN_MAC_MAX_SUPP_CHANNELS - 1; k++) {
+			next = dest_chans[j] + wifi_chan_index;
+
+			if (!is_duplicate_channel(dest_chans, j + 1, next))
+				dest_chans[j + 1] = next;
+			else
+				continue;
+
+			cfg80211_debug("i: %d, j: %d, k: %d, [%d]: %d",
+				       i, j, k, j + 1, dest_chans[j + 1]);
+			j += 1;
+		}
+	}
+	num_unique_channels = j + 1;
+	cfg80211_debug("Unique Channel List: supported_channels ");
+	for (i = 0; i < num_unique_channels; i++)
+		cfg80211_debug("[%d]: %d,", i, dest_chans[i]);
+
+	if (MAX_CHANNEL < num_unique_channels)
+		num_unique_channels = MAX_CHANNEL;
+	req_info->supported_channels_len = num_unique_channels;
+	cfg80211_debug("After removing duplcates supported_channels_len: %d",
+		       req_info->supported_channels_len);
+}
+
+static void
+wlan_cfg80211_tdls_extract_params(struct tdls_update_peer_params *req_info,
+				  struct station_parameters *params)
+{
+	int i;
+
+	cfg80211_debug("sta cap %d, uapsd_queue %d, max_sp %d",
+		       params->capability,
+		       params->uapsd_queues, params->max_sp);
+
+	if (!req_info) {
+		cfg80211_err("reg_info is NULL");
+		return;
+	}
+	req_info->capability = params->capability;
+	req_info->uapsd_queues = params->uapsd_queues;
+	req_info->max_sp = params->max_sp;
+
+	if (params->supported_channels_len)
+		tdls_calc_channels_from_staparams(req_info, params);
+
+	qdf_mem_copy(req_info->supported_oper_classes,
+		     params->supported_oper_classes,
+		     params->supported_oper_classes_len);
+	req_info->supported_oper_classes_len =
+		params->supported_oper_classes_len;
+
+	if (params->ext_capab_len)
+		qdf_mem_copy(req_info->extn_capability, params->ext_capab,
+			     sizeof(req_info->extn_capability));
+
+	if (params->ht_capa) {
+		req_info->htcap_present = 1;
+		qdf_mem_copy(&req_info->ht_cap, params->ht_capa,
+			     sizeof(struct htcap_cmn_ie));
+	}
+
+	req_info->supported_rates_len = params->supported_rates_len;
+
+	/* Note : The Maximum sizeof supported_rates sent by the Supplicant is
+	 * 32. The supported_rates array , for all the structures propogating
+	 * till Add Sta to the firmware has to be modified , if the supplicant
+	 * (ieee80211) is modified to send more rates.
+	 */
+
+	/* To avoid Data Currption , set to max length to SIR_MAC_MAX_SUPP_RATES
+	 */
+	if (req_info->supported_rates_len > WLAN_MAC_MAX_SUPP_RATES)
+		req_info->supported_rates_len = WLAN_MAC_MAX_SUPP_RATES;
+
+	if (req_info->supported_rates_len) {
+		qdf_mem_copy(req_info->supported_rates,
+			     params->supported_rates,
+			     req_info->supported_rates_len);
+		cfg80211_debug("Supported Rates with Length %d",
+			       req_info->supported_rates_len);
+
+		for (i = 0; i < req_info->supported_rates_len; i++)
+			cfg80211_debug("[%d]: %0x", i,
+				       req_info->supported_rates[i]);
+	}
+
+	if (params->vht_capa) {
+		req_info->vhtcap_present = 1;
+		qdf_mem_copy(&req_info->vht_cap, params->vht_capa,
+			     sizeof(struct vhtcap));
+	}
+
+	if (params->ht_capa || params->vht_capa ||
+	    (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
+		req_info->is_qos_wmm_sta = true;
+}
+
+int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_vdev *vdev,
+				   const uint8_t *mac,
+				   struct station_parameters *params)
+{
+	struct tdls_update_peer_params *req_info;
+	int status;
+	struct vdev_osif_priv *osif_priv;
+	struct osif_tdls_vdev *tdls_priv;
+	unsigned long rc;
+
+	status = wlan_cfg80211_tdls_validate_mac_addr(mac);
+
+	if (status)
+		return status;
+
+	cfg80211_debug("Update TDLS peer " QDF_MAC_ADDR_STR,
+		       QDF_MAC_ADDR_ARRAY(mac));
+
+	req_info = qdf_mem_malloc(sizeof(*req_info));
+	if (!req_info) {
+		cfg80211_err("Failed to allocate tdls add peer request mem");
+		return -EINVAL;
+	}
+	wlan_cfg80211_tdls_extract_params(req_info, params);
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	tdls_priv = osif_priv->osif_tdls;
+	req_info->vdev_id = wlan_vdev_get_id(vdev);
+	qdf_mem_copy(req_info->peer_addr, mac, QDF_MAC_ADDR_SIZE);
+
+	reinit_completion(&tdls_priv->tdls_add_peer_comp);
+	status = ucfg_tdls_update_peer(vdev, req_info);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("ucfg_tdls_update_peer returned err %d", status);
+		status = -EIO;
+		goto error;
+	}
+
+	rc = wait_for_completion_timeout(
+		&tdls_priv->tdls_add_peer_comp,
+		msecs_to_jiffies(WAIT_TIME_TDLS_ADD_STA));
+	if (!rc) {
+		cfg80211_err("timeout for tdls update peer indication %ld", rc);
+		status = -EPERM;
+		goto error;
+	}
+
+	if (QDF_IS_STATUS_ERROR(tdls_priv->tdls_add_peer_status)) {
+		cfg80211_err("tdls update peer failed, status:%d",
+			     tdls_priv->tdls_add_peer_status);
+		status = -EPERM;
+	}
+error:
+	qdf_mem_free(req_info);
+	return status;
+}
+
+static char *tdls_oper_to_str(enum nl80211_tdls_operation oper)
+{
+	switch (oper) {
+	case NL80211_TDLS_ENABLE_LINK:
+		return "TDLS_ENABLE_LINK";
+	case NL80211_TDLS_DISABLE_LINK:
+		return "TDLS_DISABLE_LINK";
+	case NL80211_TDLS_TEARDOWN:
+		return "TDLS_TEARDOWN";
+	case NL80211_TDLS_SETUP:
+		return "TDLS_SETUP";
+	default:
+		return "UNKNOWN:ERR";
+	}
+}
+
+static enum tdls_command_type tdls_oper_to_cmd(enum nl80211_tdls_operation oper)
+{
+	if (oper == NL80211_TDLS_ENABLE_LINK)
+		return TDLS_CMD_ENABLE_LINK;
+	else if (oper == NL80211_TDLS_DISABLE_LINK)
+		return TDLS_CMD_DISABLE_LINK;
+	else if (oper == NL80211_TDLS_TEARDOWN)
+		return TDLS_CMD_REMOVE_FORCE_PEER;
+	else if (oper == NL80211_TDLS_SETUP)
+		return TDLS_CMD_CONFIG_FORCE_PEER;
+	else
+		return 0;
+}
+
+int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev,
+						uint32_t trigger_mode)
+{
+	enum tdls_feature_mode tdls_mode;
+	struct tdls_set_mode_params set_mode_params;
+	int status;
+
+	if (!vdev)
+		return -EINVAL;
+
+	switch (trigger_mode) {
+	case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT:
+		tdls_mode = TDLS_SUPPORT_EXP_TRIG_ONLY;
+		return 0;
+	case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL:
+		tdls_mode = TDLS_SUPPORT_EXT_CONTROL;
+		break;
+	case WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT:
+		tdls_mode = TDLS_SUPPORT_IMP_MODE;
+		return 0;
+	default:
+		cfg80211_err("Invalid TDLS trigger mode");
+		return -EINVAL;
+	}
+
+	cfg80211_notice("cfg80211 tdls trigger mode %d", trigger_mode);
+	set_mode_params.source = TDLS_SET_MODE_SOURCE_USER;
+	set_mode_params.tdls_mode = tdls_mode;
+	set_mode_params.update_last = false;
+	set_mode_params.vdev = vdev;
+
+	status = ucfg_tdls_set_operating_mode(&set_mode_params);
+	return status;
+}
+
+int wlan_cfg80211_tdls_oper(struct wlan_objmgr_vdev *vdev,
+			    const uint8_t *peer,
+			    enum nl80211_tdls_operation oper)
+{
+	struct vdev_osif_priv *osif_priv;
+	struct osif_tdls_vdev *tdls_priv;
+	int status;
+	unsigned long rc;
+	enum tdls_command_type cmd;
+
+	status = wlan_cfg80211_tdls_validate_mac_addr(peer);
+
+	if (status)
+		return status;
+
+	if (NL80211_TDLS_DISCOVERY_REQ == oper) {
+		cfg80211_warn(
+			"We don't support in-driver setup/teardown/discovery");
+		return -ENOTSUPP;
+	}
+
+	cfg80211_debug("%s start", tdls_oper_to_str(oper));
+	cmd = tdls_oper_to_cmd(oper);
+	switch (oper) {
+	case NL80211_TDLS_ENABLE_LINK:
+	case NL80211_TDLS_TEARDOWN:
+	case NL80211_TDLS_SETUP:
+		status = ucfg_tdls_oper(vdev, peer, cmd);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			cfg80211_err("%s fail %d",
+				     tdls_oper_to_str(oper), status);
+			status = -EIO;
+			goto error;
+		}
+		break;
+	case NL80211_TDLS_DISABLE_LINK:
+		osif_priv = wlan_vdev_get_ospriv(vdev);
+		tdls_priv = osif_priv->osif_tdls;
+		reinit_completion(&tdls_priv->tdls_del_peer_comp);
+		status = ucfg_tdls_oper(vdev, peer, cmd);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			cfg80211_err("ucfg_tdls_disable_link fail %d", status);
+			status = -EIO;
+			goto error;
+		}
+
+		rc = wait_for_completion_timeout(
+			&tdls_priv->tdls_del_peer_comp,
+			msecs_to_jiffies(WAIT_TIME_TDLS_DEL_STA));
+		if (!rc) {
+			cfg80211_err("timeout for tdls disable link %ld", rc);
+			status = -EPERM;
+		}
+		break;
+	default:
+		cfg80211_err("unsupported event %d", oper);
+		status = -ENOTSUPP;
+	}
+
+error:
+	return status;
+}
+
+void wlan_cfg80211_tdls_rx_callback(void *user_data,
+	struct tdls_rx_mgmt_frame *rx_frame)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct wlan_objmgr_vdev *vdev;
+	struct vdev_osif_priv *osif_priv;
+	struct wireless_dev *wdev;
+	uint16_t freq;
+
+	cfg80211_debug("user data:%pK, vdev id:%d, rssi:%d, buf:%pK, len:%d",
+		user_data, rx_frame->vdev_id, rx_frame->rx_rssi,
+		rx_frame->buf, rx_frame->frame_len);
+
+	psoc = user_data;
+	if (!psoc) {
+		cfg80211_err("psoc is null");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
+		rx_frame->vdev_id, WLAN_TDLS_NB_ID);
+	if (!vdev) {
+		cfg80211_err("vdev is null");
+		return;
+	}
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	if (!osif_priv) {
+		cfg80211_err("osif_priv is null");
+		goto fail;
+	}
+
+	wdev = osif_priv->wdev;
+	if (!wdev) {
+		cfg80211_err("wdev is null");
+		goto fail;
+	}
+
+	if (rx_frame->rx_chan <= TDLS_MAX_NO_OF_2_4_CHANNELS)
+		freq = ieee80211_channel_to_frequency(
+			rx_frame->rx_chan, NL80211_BAND_2GHZ);
+	else
+		freq = ieee80211_channel_to_frequency(
+			rx_frame->rx_chan, NL80211_BAND_5GHZ);
+
+	cfg80211_notice("Indicate frame over nl80211, vdev id:%d, idx:%d",
+		   rx_frame->vdev_id, wdev->netdev->ifindex);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len,
+		NL80211_RXMGMT_FLAG_ANSWERED);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len,
+		NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC);
+#else
+	cfg80211_rx_mgmt(wdev, freq, rx_frame->rx_rssi * 100,
+		rx_frame->buf, rx_frame->frame_len, GFP_ATOMIC);
+#endif /* LINUX_VERSION_CODE */
+fail:
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
+}
+
+int wlan_cfg80211_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev,
+				char *buf, int buflen)
+{
+	struct vdev_osif_priv *osif_priv;
+	struct osif_tdls_vdev *tdls_priv;
+	int32_t len;
+	QDF_STATUS status;
+	unsigned long rc;
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	tdls_priv = osif_priv->osif_tdls;
+
+	reinit_completion(&tdls_priv->tdls_user_cmd_comp);
+	status = ucfg_tdls_get_all_peers(vdev, buf, buflen);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("ucfg_tdls_get_all_peers failed err %d", status);
+		len = scnprintf(buf, buflen,
+				"\nucfg_tdls_send_mgmt failed\n");
+		goto error_get_tdls_peers;
+	}
+
+	cfg80211_debug("Wait for tdls_user_cmd_comp. Timeout %u ms",
+		       WAIT_TIME_FOR_TDLS_USER_CMD);
+
+	rc = wait_for_completion_timeout(
+		&tdls_priv->tdls_user_cmd_comp,
+		msecs_to_jiffies(WAIT_TIME_FOR_TDLS_USER_CMD));
+
+	if (0 == rc) {
+		cfg80211_err("TDLS user cmd get all peers timed out rc %ld",
+			     rc);
+		len = scnprintf(buf, buflen,
+				"\nTDLS user cmd get all peers timed out\n");
+		goto error_get_tdls_peers;
+	}
+
+	len = tdls_priv->tdls_user_cmd_len;
+
+error_get_tdls_peers:
+	return len;
+}
+
+int wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_vdev *vdev,
+			    const uint8_t *peer_mac,
+			    uint8_t action_code, uint8_t dialog_token,
+			    uint16_t status_code, uint32_t peer_capability,
+			    const uint8_t *buf, size_t len)
+{
+	struct tdls_action_frame_request mgmt_req;
+	struct vdev_osif_priv *osif_priv;
+	struct osif_tdls_vdev *tdls_priv;
+	int status;
+	unsigned long rc;
+	int max_sta_failed = 0;
+	struct tdls_validate_action_req chk_frame;
+	struct tdls_set_responder_req set_responder;
+
+	status = wlan_cfg80211_tdls_validate_mac_addr(peer_mac);
+
+	if (status)
+		return status;
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+
+	tdls_priv = osif_priv->osif_tdls;
+
+	/* make sure doesn't call send_mgmt() while it is pending */
+	if (TDLS_VDEV_MAGIC == tdls_priv->mgmt_tx_completion_status) {
+		cfg80211_err(QDF_MAC_ADDR_STR " action %d couldn't sent, as one is pending. return EBUSY",
+			     QDF_MAC_ADDR_ARRAY(peer_mac), action_code);
+		return -EBUSY;
+	}
+
+	/* Reset TDLS VDEV magic */
+	tdls_priv->mgmt_tx_completion_status = TDLS_VDEV_MAGIC;
+
+
+	/*prepare the request */
+
+	/* Validate the management Request */
+	chk_frame.vdev = vdev;
+	chk_frame.action_code = action_code;
+	qdf_mem_copy(chk_frame.peer_mac, peer_mac, QDF_MAC_ADDR_SIZE);
+	chk_frame.dialog_token = dialog_token;
+	chk_frame.action_code = action_code;
+	chk_frame.status_code = status_code;
+	chk_frame.len = len;
+	chk_frame.max_sta_failed = max_sta_failed;
+
+	mgmt_req.chk_frame = &chk_frame;
+
+	mgmt_req.vdev = vdev;
+	mgmt_req.vdev_id = wlan_vdev_get_id(vdev);
+	mgmt_req.session_id = mgmt_req.vdev_id;
+	/* populate management req params */
+	qdf_mem_copy(mgmt_req.tdls_mgmt.peer_mac.bytes,
+		     peer_mac, QDF_MAC_ADDR_SIZE);
+	mgmt_req.tdls_mgmt.dialog = dialog_token;
+	mgmt_req.tdls_mgmt.frame_type = action_code;
+	mgmt_req.tdls_mgmt.len = len;
+	mgmt_req.tdls_mgmt.peer_capability = peer_capability;
+	mgmt_req.tdls_mgmt.status_code = chk_frame.status_code;
+
+	/*populate the additional IE's */
+	mgmt_req.cmd_buf = buf;
+	mgmt_req.len = len;
+
+	reinit_completion(&tdls_priv->tdls_mgmt_comp);
+	status = ucfg_tdls_send_mgmt_frame(&mgmt_req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cfg80211_err("ucfg_tdls_send_mgmt failed err %d", status);
+		status = -EIO;
+		tdls_priv->mgmt_tx_completion_status = false;
+		goto error_mgmt_req;
+	}
+
+	cfg80211_debug("Wait for tdls_mgmt_comp. Timeout %u ms",
+		       WAIT_TIME_FOR_TDLS_MGMT);
+
+	rc = wait_for_completion_timeout(
+		&tdls_priv->tdls_mgmt_comp,
+		msecs_to_jiffies(WAIT_TIME_FOR_TDLS_MGMT));
+
+	if ((0 == rc) || (true != tdls_priv->mgmt_tx_completion_status)) {
+		cfg80211_err("%s rc %ld mgmtTxCompletionStatus %u",
+			     !rc ? "Mgmt Tx Completion timed out" :
+			     "Mgmt Tx Completion failed",
+			     rc, tdls_priv->mgmt_tx_completion_status);
+
+		tdls_priv->mgmt_tx_completion_status = false;
+		status = -EINVAL;
+		goto error_mgmt_req;
+	}
+
+	cfg80211_debug("Mgmt Tx Completion status %ld TxCompletion %u",
+		       rc, tdls_priv->mgmt_tx_completion_status);
+
+	if (chk_frame.max_sta_failed) {
+		status = max_sta_failed;
+		goto error_mgmt_req;
+	}
+
+	if (TDLS_SETUP_RESPONSE == action_code ||
+	    TDLS_SETUP_CONFIRM == action_code) {
+		qdf_mem_copy(set_responder.peer_mac, peer_mac,
+			     QDF_MAC_ADDR_SIZE);
+		set_responder.vdev = vdev;
+		if (TDLS_SETUP_RESPONSE == action_code)
+			set_responder.responder = false;
+		if (TDLS_SETUP_CONFIRM == action_code)
+			set_responder.responder = true;
+		ucfg_tdls_responder(&set_responder);
+	}
+
+error_mgmt_req:
+	return status;
+}
+
+int wlan_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev, uint32_t mode)
+{
+	struct vdev_osif_priv *osif_priv;
+	struct osif_tdls_vdev *tdls_priv;
+	int ret;
+	unsigned long rc;
+
+	if (!vdev) {
+		cfg80211_err("vdev is NULL");
+		return -EAGAIN;
+	}
+
+	osif_priv = wlan_vdev_get_ospriv(vdev);
+	tdls_priv = osif_priv->osif_tdls;
+
+	reinit_completion(&tdls_priv->tdls_antenna_switch_comp);
+	ret = ucfg_tdls_antenna_switch(vdev, mode);
+	if (QDF_IS_STATUS_ERROR(ret)) {
+		cfg80211_err("ucfg_tdls_antenna_switch failed err %d", ret);
+		ret = -EAGAIN;
+		goto error;
+	}
+
+	rc = wait_for_completion_timeout(
+		&tdls_priv->tdls_antenna_switch_comp,
+		msecs_to_jiffies(WAIT_TIME_FOR_TDLS_ANTENNA_SWITCH));
+	if (!rc) {
+		cfg80211_err("timeout for tdls antenna switch %ld", rc);
+		ret = -EAGAIN;
+		goto error;
+	}
+
+	ret = tdls_priv->tdls_antenna_switch_status;
+	cfg80211_debug("tdls antenna switch status:%d", ret);
+error:
+	return ret;
+}
+
+static void
+wlan_cfg80211_tdls_indicate_discovery(struct tdls_osif_indication *ind)
+{
+	struct vdev_osif_priv *osif_vdev;
+
+	osif_vdev = wlan_vdev_get_ospriv(ind->vdev);
+
+	cfg80211_debug("Implicit TDLS, request Send Discovery request");
+	cfg80211_tdls_oper_request(osif_vdev->wdev->netdev,
+				   ind->peer_mac, NL80211_TDLS_DISCOVERY_REQ,
+				   false, GFP_KERNEL);
+}
+
+static void
+wlan_cfg80211_tdls_indicate_setup(struct tdls_osif_indication *ind)
+{
+	struct vdev_osif_priv *osif_vdev;
+
+	osif_vdev = wlan_vdev_get_ospriv(ind->vdev);
+
+	cfg80211_debug("Indication to request TDLS setup");
+	cfg80211_tdls_oper_request(osif_vdev->wdev->netdev,
+				   ind->peer_mac, NL80211_TDLS_SETUP, false,
+				   GFP_KERNEL);
+}
+
+static void
+wlan_cfg80211_tdls_indicate_teardown(struct tdls_osif_indication *ind)
+{
+	struct vdev_osif_priv *osif_vdev;
+
+	osif_vdev = wlan_vdev_get_ospriv(ind->vdev);
+
+	cfg80211_debug("Teardown reason %d", ind->reason);
+	cfg80211_tdls_oper_request(osif_vdev->wdev->netdev,
+				   ind->peer_mac, NL80211_TDLS_TEARDOWN,
+				   ind->reason, GFP_KERNEL);
+}
+
+void wlan_cfg80211_tdls_event_callback(void *user_data,
+				       enum tdls_event_type type,
+				       struct tdls_osif_indication *ind)
+{
+	struct vdev_osif_priv *osif_vdev;
+	struct osif_tdls_vdev *tdls_priv;
+
+	if (!ind || !ind->vdev) {
+		cfg80211_err("ind: %pK", ind);
+		return;
+	}
+	osif_vdev = wlan_vdev_get_ospriv(ind->vdev);
+	tdls_priv = osif_vdev->osif_tdls;
+
+	switch (type) {
+	case TDLS_EVENT_MGMT_TX_ACK_CNF:
+		tdls_priv->mgmt_tx_completion_status = ind->status;
+		complete(&tdls_priv->tdls_mgmt_comp);
+		break;
+	case TDLS_EVENT_ADD_PEER:
+		tdls_priv->tdls_add_peer_status = ind->status;
+		complete(&tdls_priv->tdls_add_peer_comp);
+		break;
+	case TDLS_EVENT_DEL_PEER:
+		complete(&tdls_priv->tdls_del_peer_comp);
+		break;
+	case TDLS_EVENT_DISCOVERY_REQ:
+		wlan_cfg80211_tdls_indicate_discovery(ind);
+		break;
+	case TDLS_EVENT_TEARDOWN_REQ:
+		wlan_cfg80211_tdls_indicate_teardown(ind);
+		break;
+	case TDLS_EVENT_SETUP_REQ:
+		wlan_cfg80211_tdls_indicate_setup(ind);
+		break;
+	case TDLS_EVENT_TEARDOWN_LINKS_DONE:
+		complete(&tdls_priv->tdls_teardown_comp);
+		break;
+	case TDLS_EVENT_USER_CMD:
+		tdls_priv->tdls_user_cmd_len = ind->status;
+		complete(&tdls_priv->tdls_user_cmd_comp);
+		break;
+
+	case TDLS_EVENT_ANTENNA_SWITCH:
+		tdls_priv->tdls_antenna_switch_status = ind->status;
+		complete(&tdls_priv->tdls_antenna_switch_comp);
+	default:
+		break;
+	}
+}