diff --git a/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h b/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h
new file mode 100644
index 000000000000..f39b636346ed
--- /dev/null
+++ b/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 */
diff --git a/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_cfg.h b/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_cfg.h
new file mode 100644
index 000000000000..22900022d06e
--- /dev/null
+++ b/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"
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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")
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_CONC_SYS_PREF CFG_INI_UINT(\
+ "gSystemPref", 0, 2, 0, \
+ CFG_VALUE_OR_DEFAULT, \
+ "System preference to predict PCL")
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_MAX_CONC_CXNS CFG_INI_UINT(\
+ "gMaxConcurrentActiveSessions", \
+ 1, 4, 3, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Config max num allowed connections")
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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")
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_DBS_SELECTION_PLCY CFG_INI_UINT(\
+ "dbs_selection_policy", \
+ 0, 3, 0, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Configure dbs selection policy")
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_VDEV_CUSTOM_PRIORITY_LIST CFG_INI_UINT(\
+ "vdev_priority_list", \
+ 0, 0x4444, 0x4321, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Configure vdev priority list")
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_ENABLE_CONC_RULE1 CFG_INI_UINT(\
+ "gEnableCustomConcRule1", \
+ 0, 1, 0, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Enable custom concurrency rule 1")
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_ENABLE_CONC_RULE2 CFG_INI_UINT(\
+ "gEnableCustomConcRule2", \
+ 0, 1, 0, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Enable custom concurrency rule 2")
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_ENABLE_MCC_ADATIVE_SCH_ENABLED_NAME CFG_INI_UINT(\
+ "gEnableMCCAdaptiveScheduler", \
+ 0, 1, 1, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Enable/Disable MCC Adaptive Scheduler")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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
diff --git a/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h b/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h
new file mode 100644
index 000000000000..182afded647a
--- /dev/null
+++ b/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
+
+#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 1x1@2.4 Ghz
+ * @PM_STA_24_2x2: STA connection using 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_P2P_CLI_24_2x2: P2P Client connection using 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_P2P_GO_24_2x2: P2P GO connection using 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_SAP_24_2x2: SAP connection using 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_IBSS_24_2x2: IBSS connection using 2x2@2.4 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
+ * 1x1@2.4 Ghz
+ * @PM_STA_SAP_SCC_24_2x2: STA & SAP connection on SCC using
+ * 2x2@2.4 Ghz
+ * @PM_STA_SAP_MCC_24_1x1: STA & SAP connection on MCC using
+ * 1x1@2.4 Ghz
+ * @PM_STA_SAP_MCC_24_2x2: STA & SAP connection on MCC using
+ * 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_STA_P2P_GO_SCC_24_2x2: STA & P2P GO connection on SCC
+ * using 2x2@2.4 Ghz
+ * @PM_STA_P2P_GO_MCC_24_1x1: STA & P2P GO connection on MCC
+ * using 1x1@2.4 Ghz
+ * @PM_STA_P2P_GO_MCC_24_2x2: STA & P2P GO connection on MCC
+ * using 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_STA_P2P_CLI_SCC_24_2x2: STA & P2P CLI connection on SCC
+ * using 2x2@2.4 Ghz
+ * @PM_STA_P2P_CLI_MCC_24_1x1: STA & P2P CLI connection on MCC
+ * using 1x1@2.4 Ghz
+ * @PM_STA_P2P_CLI_MCC_24_2x2: STA & P2P CLI connection on MCC
+ * using 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_P2P_GO_P2P_CLI_SCC_24_2x2: P2P GO & CLI connection on
+ * SCC using 2x2@2.4 Ghz
+ * @PM_P2P_GO_P2P_CLI_MCC_24_1x1: P2P GO & CLI connection on
+ * MCC using 1x1@2.4 Ghz
+ * @PM_P2P_GO_P2P_CLI_MCC_24_2x2: P2P GO & CLI connection on
+ * MCC using 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_P2P_GO_SAP_SCC_24_2x2: P2P GO & SAP connection on
+ * SCC using 2x2@2.4 Ghz
+ * @PM_P2P_GO_SAP_MCC_24_1x1: P2P GO & SAP connection on
+ * MCC using 1x1@2.4 Ghz
+ * @PM_P2P_GO_SAP_MCC_24_2x2: P2P GO & SAP connection on
+ * MCC using 2x2@2.4 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
+ * 1x1@2.4 Ghz
+ * @PM_P2P_CLI_SAP_SCC_24_2x2: CLI & SAP connection on SCC using
+ * 2x2@2.4 Ghz
+ * @PM_P2P_CLI_SAP_MCC_24_1x1: CLI & SAP connection on MCC using
+ * 1x1@2.4 Ghz
+ * @PM_P2P_CLI_SAP_MCC_24_2x2: CLI & SAP connection on MCC using
+ * 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_SAP_SAP_SCC_24_2x2: SAP & SAP connection on
+ * SCC using 2x2@2.4 Ghz
+ * @PM_SAP_SAP_MCC_24_1x1: SAP & SAP connection on
+ * MCC using 1x1@2.4 Ghz
+ * @PM_SAP_SAP_MCC_24_2x2: SAP & SAP connection on
+ * MCC using 2x2@2.4 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 1x1@2.4 Ghz
+ * @PM_STA_STA_SCC_24_2x2: STA & STA connection on
+ * SCC using 2x2@2.4 Ghz
+ * @PM_STA_STA_MCC_24_1x1: STA & STA connection on
+ * MCC using 1x1@2.4 Ghz
+ * @PM_STA_STA_MCC_24_2x2: STA & STA connection on
+ * MCC using 2x2@2.4 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 */
diff --git a/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ucfg.h b/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ucfg.h
new file mode 100644
index 000000000000..661eebdec81e
--- /dev/null
+++ b/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
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c
new file mode 100644
index 000000000000..809406cc8191
--- /dev/null
+++ b/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
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c
new file mode 100644
index 000000000000..f4dc476c016c
--- /dev/null
+++ b/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;
+}
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c
new file mode 100644
index 000000000000..c41b794d0a6b
--- /dev/null
+++ b/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;
+}
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h
new file mode 100644
index 000000000000..5f29c534f726
--- /dev/null
+++ b/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
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c
new file mode 100644
index 000000000000..3b99c7ce6620
--- /dev/null
+++ b/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;
+}
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c
new file mode 100644
index 000000000000..46d1556c61d3
--- /dev/null
+++ b/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;
+}
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_1x1_dbs_i.h b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_1x1_dbs_i.h
new file mode 100644
index 000000000000..b1f193fe53d9
--- /dev/null
+++ b/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
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_2g_1x1_5g.h b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_2g_1x1_5g.h
new file mode 100644
index 000000000000..54d4c8ab80c6
--- /dev/null
+++ b/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
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_5g_1x1_2g.h b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_5g_1x1_2g.h
new file mode 100644
index 000000000000..bdf8223d8fbb
--- /dev/null
+++ b/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
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_i.h b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_i.h
new file mode 100644
index 000000000000..370c38cff509
--- /dev/null
+++ b/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
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_no_dbs_i.h b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_no_dbs_i.h
new file mode 100644
index 000000000000..204185247d07
--- /dev/null
+++ b/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
diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c
new file mode 100644
index 000000000000..310019ba3249
--- /dev/null
+++ b/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);
+}
diff --git a/components/mlme/core/inc/wlan_mlme_main.h b/components/mlme/core/inc/wlan_mlme_main.h
index 47f4f8a0a67d..a21089abac1e 100644
--- a/components/mlme/core/inc/wlan_mlme_main.h
+++ b/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
diff --git a/components/mlme/core/src/wlan_mlme_main.c b/components/mlme/core/src/wlan_mlme_main.c
index f538a26d3f7d..e21b3a854c4b 100644
--- a/components/mlme/core/src/wlan_mlme_main.c
+++ b/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;
diff --git a/components/mlme/dispatcher/inc/cfg_mlme.h b/components/mlme/dispatcher/inc/cfg_mlme.h
index 3e95ad392c99..8b8292bb6471 100644
--- a/components/mlme/dispatcher/inc/cfg_mlme.h
+++ b/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 */
diff --git a/components/mlme/dispatcher/inc/cfg_mlme_dfs.h b/components/mlme/dispatcher/inc/cfg_mlme_dfs.h
index e3dd2c583825..0a5ce30c5d1b 100644
--- a/components/mlme/dispatcher/inc/cfg_mlme_dfs.h
+++ b/components/mlme/dispatcher/inc/cfg_mlme_dfs.h
@@ -23,6 +23,136 @@
#ifndef __CFG_MLME_DFS_H
#define __CFG_MLME_DFS_H
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_SAP_TX_LEAKAGE_THRESHOLD CFG_INI_UINT( \
+ "gsap_tx_leakage_threshold", \
+ 100, \
+ 1000, \
+ 310, \
+ CFG_VALUE_OR_DEFAULT, \
+ "sap tx leakage threshold")
+
+/*
+ *
+ * gDfsBeaconTxEnhanced - beacon tx enhanced
+ * @Min: 0
+ * @Max: 1
+ * @Default: 0
+ *
+ * This ini is used to enhance dfs beacon tx
+ *
+ * Related: none
+ *
+ * Usage: External
+ *
+ *
+ */
+#define CFG_DFS_BEACON_TX_ENHANCED CFG_INI_BOOL( \
+ "gDfsBeaconTxEnhanced", \
+ 0, \
+ "beacon tx enhanced")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR CFG_INI_BOOL( \
+ "gPreferNonDfsChanOnRadar", \
+ 0, \
+ "channel selection prefer non dfs")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD CFG_INI_BOOL( \
+ "dfsPhyerrFilterOffload", \
+ 0, \
+ "dfs phyerror filtering offload")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_IGNORE_CAC CFG_INI_BOOL( \
+ "gIgnoreCAC", \
+ 0, \
+ "ignore CAC on DFS channel")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_DISABLE_DFS_CH_SWITCH CFG_INI_BOOL( \
+ "gDisableDFSChSwitch", \
+ 0, \
+ "Disable channel switch on radar")
+
/*
*
* 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 */
diff --git a/components/mlme/dispatcher/inc/cfg_mlme_timeout.h b/components/mlme/dispatcher/inc/cfg_mlme_timeout.h
index 7caed90aa9e3..0c23fe357586 100644
--- a/components/mlme/dispatcher/inc/cfg_mlme_timeout.h
+++ b/components/mlme/dispatcher/inc/cfg_mlme_timeout.h
@@ -285,6 +285,32 @@
CFG_VALUE_OR_DEFAULT, \
"PS data inactivity timeout")
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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 */
diff --git a/components/mlme/dispatcher/inc/cfg_mlme_wifi_pos.h b/components/mlme/dispatcher/inc/cfg_mlme_wifi_pos.h
new file mode 100644
index 000000000000..7904e8dee402
--- /dev/null
+++ b/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
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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 */
diff --git a/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h b/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h
index a433c97c5f09..3a59cd7fa9a2 100644
--- a/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h
+++ b/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;
};
diff --git a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h b/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h
index 2dc36010df60..908d9bf768c6 100644
--- a/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h
+++ b/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
diff --git a/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c b/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c
index 9ec2246a36d3..533e045dca38 100644
--- a/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c
+++ b/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)
diff --git a/components/p2p/core/src/wlan_p2p_main.c b/components/p2p/core/src/wlan_p2p_main.c
new file mode 100644
index 000000000000..711542da591b
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+#include
+#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 */
diff --git a/components/p2p/core/src/wlan_p2p_main.h b/components/p2p/core/src/wlan_p2p_main.h
new file mode 100644
index 000000000000..6a6632c44e3d
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+
+#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_ */
diff --git a/components/p2p/core/src/wlan_p2p_off_chan_tx.c b/components/p2p/core/src/wlan_p2p_off_chan_tx.c
new file mode 100644
index 000000000000..1309ccd08df1
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+#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(¶m, 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, ¶m);
+ 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(¶ms);
+ 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;
+}
diff --git a/components/p2p/core/src/wlan_p2p_off_chan_tx.h b/components/p2p/core/src/wlan_p2p_off_chan_tx.h
new file mode 100644
index 000000000000..367ecd632587
--- /dev/null
+++ b/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
+#include
+#include
+
+#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_ */
diff --git a/components/p2p/core/src/wlan_p2p_roc.c b/components/p2p/core/src/wlan_p2p_roc.c
new file mode 100644
index 000000000000..10db8e74d4c3
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#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);
+ }
+}
diff --git a/components/p2p/core/src/wlan_p2p_roc.h b/components/p2p/core/src/wlan_p2p_roc.h
new file mode 100644
index 000000000000..5e49b1497647
--- /dev/null
+++ b/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
+#include
+#include
+
+#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_ */
diff --git a/components/p2p/dispatcher/inc/wlan_p2p_cfg.h b/components/p2p/dispatcher/inc/wlan_p2p_cfg.h
new file mode 100644
index 000000000000..3ee037f5a0a0
--- /dev/null
+++ b/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"
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_GO_KEEP_ALIVE_PERIOD CFG_INI_UINT( \
+ "gGoKeepAlivePeriod", \
+ 1, \
+ 65535, \
+ 20, \
+ CFG_VALUE_OR_DEFAULT, \
+ "P2P GO keep alive period")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED CFG_INI_BOOL( \
+ "isP2pDeviceAddrAdministrated", \
+ 1, \
+ "derive the P2P MAC address from the primary MAC address")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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
diff --git a/components/p2p/dispatcher/inc/wlan_p2p_cfg_api.h b/components/p2p/dispatcher/inc/wlan_p2p_cfg_api.h
new file mode 100644
index 000000000000..18e86055bcd2
--- /dev/null
+++ b/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
+
+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_ */
diff --git a/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h b/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h
new file mode 100644
index 000000000000..d1c597ff35f1
--- /dev/null
+++ b/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
+
+#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_ */
diff --git a/components/p2p/dispatcher/inc/wlan_p2p_tgt_api.h b/components/p2p/dispatcher/inc/wlan_p2p_tgt_api.h
new file mode 100644
index 000000000000..0ca20749892d
--- /dev/null
+++ b/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
+#include
+
+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_ */
diff --git a/components/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h b/components/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h
new file mode 100644
index 000000000000..da397205140f
--- /dev/null
+++ b/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
+
+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_ */
diff --git a/components/p2p/dispatcher/src/wlan_p2p_cfg.c b/components/p2p/dispatcher/src/wlan_p2p_cfg.c
new file mode 100644
index 000000000000..490b95821eaf
--- /dev/null
+++ b/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
+#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;
+}
diff --git a/components/p2p/dispatcher/src/wlan_p2p_tgt_api.c b/components/p2p/dispatcher/src/wlan_p2p_tgt_api.c
new file mode 100644
index 000000000000..d6ee448947eb
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#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;
+}
diff --git a/components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c b/components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c
new file mode 100644
index 000000000000..f2a6c38aa6af
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#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);
+}
diff --git a/components/target_if/p2p/inc/target_if_p2p.h b/components/target_if/p2p/inc/target_if_p2p.h
new file mode 100644
index 000000000000..1306e781554b
--- /dev/null
+++ b/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
+
+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_ */
diff --git a/components/target_if/p2p/src/target_if_p2p.c b/components/target_if/p2p/src/target_if_p2p.c
new file mode 100644
index 000000000000..dbce5991f92f
--- /dev/null
+++ b/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
+#include
+#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, ¶m);
+}
+
+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);
+}
diff --git a/components/target_if/tdls/inc/target_if_tdls.h b/components/target_if/tdls/inc/target_if_tdls.h
new file mode 100644
index 000000000000..7fe21cdf0c4e
--- /dev/null
+++ b/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
diff --git a/components/target_if/tdls/src/target_if_tdls.c b/components/target_if/tdls/src/target_if_tdls.c
new file mode 100644
index 000000000000..6adb2622319e
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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;
+}
diff --git a/components/tdls/core/src/wlan_tdls_cmds_process.c b/components/tdls/core/src/wlan_tdls_cmds_process.c
new file mode 100644
index 000000000000..a27c040ef63a
--- /dev/null
+++ b/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
+#include
+#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;
+}
diff --git a/components/tdls/core/src/wlan_tdls_cmds_process.h b/components/tdls/core/src/wlan_tdls_cmds_process.h
new file mode 100644
index 000000000000..e66b41aa69e5
--- /dev/null
+++ b/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
diff --git a/components/tdls/core/src/wlan_tdls_ct.c b/components/tdls/core/src/wlan_tdls_ct.c
new file mode 100644
index 000000000000..f62a5e1fd929
--- /dev/null
+++ b/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);
+}
diff --git a/components/tdls/core/src/wlan_tdls_ct.h b/components/tdls/core/src/wlan_tdls_ct.h
new file mode 100644
index 000000000000..00e03f20d14f
--- /dev/null
+++ b/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
diff --git a/components/tdls/core/src/wlan_tdls_main.c b/components/tdls/core/src/wlan_tdls_main.c
new file mode 100644
index 000000000000..7295adda9689
--- /dev/null
+++ b/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 = ¬ify->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;
+}
+
+
diff --git a/components/tdls/core/src/wlan_tdls_main.h b/components/tdls/core/src/wlan_tdls_main.h
new file mode 100644
index 000000000000..c03eb16abf36
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#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
diff --git a/components/tdls/core/src/wlan_tdls_mgmt.c b/components/tdls/core/src/wlan_tdls_mgmt.c
new file mode 100644
index 000000000000..47b30c4f9bc6
--- /dev/null
+++ b/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
+#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;
+}
diff --git a/components/tdls/core/src/wlan_tdls_mgmt.h b/components/tdls/core/src/wlan_tdls_mgmt.h
new file mode 100644
index 000000000000..ce6f9307988f
--- /dev/null
+++ b/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
+
diff --git a/components/tdls/core/src/wlan_tdls_peer.c b/components/tdls/core/src/wlan_tdls_peer.c
new file mode 100644
index 000000000000..ff4bf86379a4
--- /dev/null
+++ b/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
+#include
+#include
+
+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);
+ }
+}
diff --git a/components/tdls/core/src/wlan_tdls_peer.h b/components/tdls/core/src/wlan_tdls_peer.h
new file mode 100644
index 000000000000..41ffa8096f54
--- /dev/null
+++ b/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
diff --git a/components/tdls/core/src/wlan_tdls_txrx.c b/components/tdls/core/src/wlan_tdls_txrx.c
new file mode 100644
index 000000000000..6ded57c974f8
--- /dev/null
+++ b/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
+ */
diff --git a/components/tdls/core/src/wlan_tdls_txrx.h b/components/tdls/core/src/wlan_tdls_txrx.h
new file mode 100644
index 000000000000..b001ffe74599
--- /dev/null
+++ b/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
+ */
diff --git a/components/tdls/dispatcher/inc/wlan_tdls_cfg.h b/components/tdls/dispatcher/inc/wlan_tdls_cfg.h
new file mode 100644
index 000000000000..03827e593a58
--- /dev/null
+++ b/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"
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_BUF_STA_ENABLED CFG_INI_BOOL( \
+ "gEnableTDLSBufferSta", \
+ 1, \
+ "Controls the TDLS buffer")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_PUAPSD_INACT_TIME CFG_INI_UINT( \
+ "gTDLSPuapsdInactivityTime", \
+ 0, \
+ 10, \
+ 0, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Peer UAPSD Inactivity time")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_RX_FRAME_THRESHOLD CFG_INI_UINT( \
+ "gTDLSPuapsdRxFrameThreshold", \
+ 10, \
+ 20, \
+ 10, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Peer UAPSD Rx frame threshold")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_OFF_CHANNEL_ENABLED CFG_INI_BOOL( \
+ "gEnableTDLSOffChannel", \
+ 0, \
+ "Enables off-channel support for TDLS")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_SUPPORT_ENABLE CFG_INI_BOOL( \
+ "gEnableTDLSSupport", \
+ 0, \
+ "enable/disable TDLS support")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_IMPLICIT_TRIGGER CFG_INI_BOOL( \
+ "gEnableTDLSImplicitTrigger", \
+ 0, \
+ "enable/disable implicit TDLS")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_TX_STATS_PERIOD CFG_INI_UINT( \
+ "gTDLSTxStatsPeriod", \
+ 1000, \
+ 4294967295UL, \
+ 2000, \
+ CFG_VALUE_OR_DEFAULT, \
+ "TDLS TX statistics time period")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_TX_PACKET_THRESHOLD CFG_INI_UINT( \
+ "gTDLSTxPacketThreshold", \
+ 0, \
+ 4294967295UL, \
+ 40, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Tx/Rx Packet threshold for initiating TDLS")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT CFG_INI_UINT( \
+ "gTDLSMaxDiscoveryAttempt", \
+ 1, \
+ 100, \
+ 5, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Attempts for sending TDLS discovery requests")
+
+/*
+ *
+ * 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")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_IDLE_PACKET_THRESHOLD CFG_INI_UINT( \
+ "gTDLSIdlePacketThreshold", \
+ 0, \
+ 40000, \
+ 3, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Number of idle packet")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD CFG_INI_INT( \
+ "gTDLSRSSITriggerThreshold", \
+ -120, \
+ 0, \
+ -75, \
+ CFG_VALUE_OR_DEFAULT, \
+ "RSSI threshold for TDLS connection")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD CFG_INI_INT( \
+ "gTDLSRSSITeardownThreshold", \
+ -120, \
+ 0, \
+ -75, \
+ CFG_VALUE_OR_DEFAULT, \
+ "RSSI threshold for TDLS teardown")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM CFG_INI_UINT( \
+ "gTDLSPrefOffChanNum", \
+ 1, \
+ 165, \
+ 36, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Preferred TDLS channel number")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW CFG_INI_UINT( \
+ "gTDLSPrefOffChanBandwidth", \
+ 1, \
+ 15, \
+ 7, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Preferred TDLS channel bandwidth")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_PUAPSD_INACTIVITY_TIME CFG_INI_UINT( \
+ "gTDLSPuapsdInactivityTime", \
+ 0, \
+ 10, \
+ 0, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Peer UAPSD Inactivity time")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD CFG_INI_UINT( \
+ "gTDLSPuapsdRxFrameThreshold", \
+ 10, \
+ 20, \
+ 10, \
+ CFG_VALUE_OR_DEFAULT, \
+ "Peer UAPSD Rx frame threshold")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_EXTERNAL_CONTROL CFG_INI_BOOL( \
+ "gTDLSExternalControl", \
+ 1, \
+ "Enable external TDLS control")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_WMM_MODE_ENABLE CFG_INI_BOOL( \
+ "gEnableTDLSWmmMode", \
+ 1, \
+ "Enables WMM support over TDLS link")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_SCAN_ENABLE CFG_INI_BOOL( \
+ "gEnableTDLSScan", \
+ 0, \
+ "Allow scan and maintain TDLS link")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#define CFG_TDLS_PEER_KICKOUT_THRESHOLD CFG_INI_UINT( \
+ "gTDLSPeerKickoutThreshold", \
+ 10, \
+ 5000, \
+ 96, \
+ CFG_VALUE_OR_DEFAULT, \
+ "TDLS peer kick out threshold to firmware")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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")
+
+/*
+ *
+ * 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
+ *
+ *
+ */
+#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
diff --git a/components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h b/components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h
new file mode 100644
index 000000000000..6229c0ca1bd3
--- /dev/null
+++ b/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
+
+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_ */
diff --git a/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h b/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h
new file mode 100644
index 000000000000..07bc155d9591
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+
+
+#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
diff --git a/components/tdls/dispatcher/inc/wlan_tdls_tgt_api.h b/components/tdls/dispatcher/inc/wlan_tdls_tgt_api.h
new file mode 100644
index 000000000000..14a19006b997
--- /dev/null
+++ b/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
+#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
diff --git a/components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h b/components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h
new file mode 100644
index 000000000000..3d6570772c64
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+
+/**
+ * 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
diff --git a/components/tdls/dispatcher/src/wlan_tdls_cfg.c b/components/tdls/dispatcher/src/wlan_tdls_cfg.c
new file mode 100644
index 000000000000..b9ff89221213
--- /dev/null
+++ b/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
+#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;
+}
diff --git a/components/tdls/dispatcher/src/wlan_tdls_tgt_api.c b/components/tdls/dispatcher/src/wlan_tdls_tgt_api.c
new file mode 100644
index 000000000000..bb09a0e8b4a1
--- /dev/null
+++ b/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
+#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(¬ify->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);
+}
diff --git a/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c
new file mode 100644
index 000000000000..cd86729d8a02
--- /dev/null
+++ b/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
+#include
+#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
+#include
+#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;
+}
diff --git a/components/tdls/dispatcher/src/wlan_tdls_utils_api.c b/components/tdls/dispatcher/src/wlan_tdls_utils_api.c
new file mode 100644
index 000000000000..2e9b2ad43ecd
--- /dev/null
+++ b/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
+ */
diff --git a/core/cds/inc/cds_config.h b/core/cds/inc/cds_config.h
index 4e66afe2e57d..6eb627f0cb46 100644
--- a/core/cds/inc/cds_config.h
+++ b/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;
diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h
index ab98bda4f0b3..242bf9ad7988 100644
--- a/core/hdd/inc/wlan_hdd_cfg.h
+++ b/core/hdd/inc/wlan_hdd_cfg.h
@@ -2201,70 +2201,6 @@ enum hdd_link_speed_rpt_type {
eHDD_LINK_SPEED_REPORT_MAX_SCALED = 2,
};
-/*
- *
- * 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
- *
- *
- */
-#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)
-
-/*
- *
- * 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
- *
- *
- */
-#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)
-
-/*
- *
- * 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
- *
- *
- */
-#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)
-
/*
*
* gReportMaxLinkSpeed - Reporting of max link speed
@@ -2936,34 +2872,6 @@ enum hdd_link_speed_rpt_type {
#endif /* MSM_PLATFORM */
-/*
- *
- * 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
- *
- *
- */
-
-#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)
-
/*
*
* 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)
-
/*
*
* 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 */
-/*
- *
- * gDfsBeaconTxEnhanced - beacon tx enhanced
- * @Min: 0
- * @Max: 1
- * @Default: 0
- *
- * This ini is used to enhance dfs beacon tx
- *
- * Related: none
- *
- * Usage: External
- *
- *
- */
-#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)
-
/*
*
* 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)
-/*
- *
- * 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
- *
- *
- */
-#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 */
-
/*
*
* 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;
diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c
index ea772992f7e3..c43d904e28c4 100644
--- a/core/hdd/src/wlan_hdd_cfg.c
+++ b/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;
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 6aa0e5e51527..6b0e24e826b0 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/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]) {
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index 3e1b6c66e673..2e115e71201f 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/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;
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 7f5b17d330ee..9c3462c74374 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/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");
diff --git a/core/mac/inc/ani_global.h b/core/mac/inc/ani_global.h
index b80009a417eb..d267aca8b03f 100644
--- a/core/mac/inc/ani_global.h
+++ b/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;
diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h
index da6559829e1c..0144037e5d22 100644
--- a/core/mac/inc/qwlan_version.h
+++ b/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 */
diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c
index 5c2a2b5f3342..cd96b2a8dfd1 100644
--- a/core/mac/src/pe/lim/lim_utils.c
+++ b/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);
diff --git a/core/sap/inc/sap_api.h b/core/sap/inc/sap_api.h
index 47afecf70343..0794f9fa1773 100644
--- a/core/sap/inc/sap_api.h
+++ b/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
diff --git a/core/sap/src/sap_api_link_cntl.c b/core/sap/src/sap_api_link_cntl.c
index 74d06117ba1a..96e267147f93 100644
--- a/core/sap/src/sap_api_link_cntl.c
+++ b/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");
diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c
index 2e65f68f957c..828c6e09b3d6 100644
--- a/core/sap/src/sap_fsm.c
+++ b/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 */
diff --git a/core/sap/src/sap_internal.h b/core/sap/src/sap_internal.h
index 764fd4f98a16..a3544eca5f4f 100644
--- a/core/sap/src/sap_internal.h
+++ b/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
diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c
index e9fb64f5adae..54b2468a9846 100644
--- a/core/sap/src/sap_module.c
+++ b/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) {
diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h
index 8a85c171416d..a40b9233127f 100644
--- a/core/sme/inc/csr_api.h
+++ b/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;
diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c
index 35b1c245d8be..0c14f40d9509 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/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 =
diff --git a/os_if/p2p/inc/wlan_cfg80211_p2p.h b/os_if/p2p/inc/wlan_cfg80211_p2p.h
new file mode 100644
index 000000000000..1c8484b8de4b
--- /dev/null
+++ b/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
+
+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_ */
diff --git a/os_if/p2p/src/wlan_cfg80211_p2p.c b/os_if/p2p/src/wlan_cfg80211_p2p.c
new file mode 100644
index 000000000000..e4911ae8e23f
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#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));
+}
diff --git a/os_if/tdls/inc/wlan_cfg80211_tdls.h b/os_if/tdls/inc/wlan_cfg80211_tdls.h
new file mode 100644
index 000000000000..c4c6b1c6f8ba
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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
diff --git a/os_if/tdls/src/wlan_cfg80211_tdls.c b/os_if/tdls/src/wlan_cfg80211_tdls.c
new file mode 100644
index 000000000000..6a04713f4de5
--- /dev/null
+++ b/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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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(¬ify_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(¬ify_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;
+ }
+}