From ee01ebfc2073f8575ba76e3dd0328b3b65c2c7e4 Mon Sep 17 00:00:00 2001 From: Kabilan Kannan Date: Mon, 20 Mar 2017 01:59:24 -0700 Subject: [PATCH] qcacmn: Add connection tracker to TDLS UMAC Add connection tracker support in TDLS UMAC component Change-Id: I725b579ab9f393d5247651bfe53df6b4a3f53649 CRs-Fixed: 2034220 --- umac/tdls/core/src/wlan_tdls_cmds_process.c | 93 +- umac/tdls/core/src/wlan_tdls_ct.c | 894 ++++++++++++++++++ umac/tdls/core/src/wlan_tdls_ct.h | 137 ++- umac/tdls/core/src/wlan_tdls_main.c | 36 +- umac/tdls/core/src/wlan_tdls_main.h | 26 + umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c | 18 + 6 files changed, 1108 insertions(+), 96 deletions(-) diff --git a/umac/tdls/core/src/wlan_tdls_cmds_process.c b/umac/tdls/core/src/wlan_tdls_cmds_process.c index 57e718d82d79..dacabe74a476 100644 --- a/umac/tdls/core/src/wlan_tdls_cmds_process.c +++ b/umac/tdls/core/src/wlan_tdls_cmds_process.c @@ -25,6 +25,7 @@ #include #include "wlan_tdls_main.h" #include "wlan_tdls_peer.h" +#include "wlan_tdls_ct.h" #include "wlan_tdls_cmds_process.h" #include "wlan_tdls_tgt_api.h" @@ -1628,63 +1629,6 @@ static const char *tdls_evt_to_str(enum tdls_event_msg_type type) } } -static void -tdls_implicit_send_discovery_request(struct tdls_vdev_priv_obj *vdev_obj) -{ - struct tdls_soc_priv_obj *soc_obj; - struct tdls_peer *curr_peer, *temp_peer; - struct tdls_osif_indication ind; - - if (!vdev_obj) { - tdls_err("vdev_obj is NULL"); - return; - } - - soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); - if (!soc_obj) { - tdls_err("soc_obj is NULL"); - return; - } - - curr_peer = vdev_obj->curr_candidate; - if (!curr_peer) { - tdls_err("curr_peer is NULL"); - return; - } - - temp_peer = tdls_is_progress(vdev_obj, NULL, 0); - if (temp_peer) { - tdls_notice(QDF_MAC_ADDRESS_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); - - tdls_debug("Implicit TDLS, Send Discovery request event"); - - qdf_mem_copy(ind.peer_mac, curr_peer->peer_mac.bytes, - QDF_MAC_ADDR_SIZE); - ind.vdev = vdev_obj->vdev; - - if (soc_obj->tdls_event_cb) - soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, - TDLS_EVENT_DISCOVERY_REQ, &ind); - - vdev_obj->discovery_sent_cnt++; - /*TODO restart peer discovery timeout*/ - - tdls_debug("discovery count %u, timeout %u msec", - vdev_obj->discovery_sent_cnt, - vdev_obj->threshold_config.tx_period_t - - TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE); -done: - vdev_obj->curr_candidate = NULL; - vdev_obj->magic = 0; -} - QDF_STATUS tdls_process_should_discover(struct wlan_objmgr_vdev *vdev, struct tdls_event_info *evt) { @@ -1743,41 +1687,6 @@ QDF_STATUS tdls_process_should_discover(struct wlan_objmgr_vdev *vdev, return QDF_STATUS_SUCCESS; } -static void -tdls_indicate_teardown(struct tdls_vdev_priv_obj *vdev_obj, - struct tdls_peer *curr_peer, uint16_t reason) -{ - struct tdls_soc_priv_obj *soc_obj; - struct tdls_osif_indication ind; - - soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); - if (!soc_obj || !vdev_obj || !curr_peer) { - tdls_err("soc_obj: %p, vdev_obj: %p, curr_peer: %p", - soc_obj, vdev_obj, curr_peer); - return; - } - - if (TDLS_LINK_CONNECTED != curr_peer->link_status) { - tdls_debug("peer not connected"); - return; - } - - tdls_set_peer_link_status(curr_peer, TDLS_LINK_TEARING, - TDLS_LINK_UNSPECIFIED); - - tdls_debug("Teardown peer " QDF_MAC_ADDRESS_STR "reason %d", - QDF_MAC_ADDR_ARRAY(curr_peer->peer_mac.bytes), reason); - - qdf_mem_copy(ind.peer_mac, curr_peer->peer_mac.bytes, - QDF_MAC_ADDR_SIZE); - ind.reason = reason; - ind.vdev = vdev_obj->vdev; - - if (soc_obj->tdls_event_cb) - soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, - TDLS_EVENT_TEARDOWN_REQ, &ind); -} - QDF_STATUS tdls_process_should_teardown(struct wlan_objmgr_vdev *vdev, struct tdls_event_info *evt) { diff --git a/umac/tdls/core/src/wlan_tdls_ct.c b/umac/tdls/core/src/wlan_tdls_ct.c index 851d0a199968..52ccfcfd2046 100644 --- a/umac/tdls/core/src/wlan_tdls_ct.c +++ b/umac/tdls/core/src/wlan_tdls_ct.c @@ -21,3 +21,897 @@ * * TDLS connection tracker function definitions */ + +#include "wlan_tdls_main.h" +#include "wlan_tdls_peer.h" +#include "wlan_tdls_ct.h" + +bool tdls_is_vdev_connected(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_peer *peer; + enum wlan_peer_state peer_state; + + wlan_vdev_obj_lock(vdev); + peer = wlan_vdev_get_bsspeer(vdev); + wlan_vdev_obj_unlock(vdev); + + if (!peer) { + tdls_err("peer is null"); + return false; + } + + wlan_peer_obj_lock(peer); + peer_state = wlan_peer_mlme_get_state(peer); + wlan_peer_obj_unlock(peer); + + if (peer_state != WLAN_ASSOC_STATE) { + tdls_err("peer state: %d", peer_state); + return false; + } + + return true; +} + +/** + * 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_ADDRESS_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 = tdls_vdev->valid_mac_entries; + + 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; + + tdls_debug("enter "); + 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); + tdls_debug("exit: rx pkt count %d ", mac_table[mac_cnt].rx_packet_cnt); + 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; + + tdls_debug("enter "); + 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); + tdls_debug("exit: tx pkt count %d", mac_table[mac_cnt].tx_packet_cnt); + 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_ADDRESS_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_ADDRESS_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_ADDRESS_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_ADDRESS_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; + + tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev); + if (!tdls_soc || !tdls_vdev || !curr_peer) { + tdls_err("tdls_soc: %p, tdls_vdev: %p, curr_peer: %p", + tdls_soc, tdls_vdev, curr_peer); + 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); + + 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 (!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_ADDRESS_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_ADDRESS_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_ADDRESS_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_ADDRESS_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_ADDRESS_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_ADDRESS_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_ADDRESS_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); +} + diff --git a/umac/tdls/core/src/wlan_tdls_ct.h b/umac/tdls/core/src/wlan_tdls_ct.h index 473f2b556644..d894794eb568 100644 --- a/umac/tdls/core/src/wlan_tdls_ct.h +++ b/umac/tdls/core/src/wlan_tdls_ct.h @@ -19,5 +19,140 @@ /** * DOC: wlan_tdls_ct.h * - * TDLS connection tracker api declaration + * 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 + +/** + * 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 muticast 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 muticast 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); +#endif diff --git a/umac/tdls/core/src/wlan_tdls_main.c b/umac/tdls/core/src/wlan_tdls_main.c index d48134e5c58b..e07ffcec7ba2 100644 --- a/umac/tdls/core/src/wlan_tdls_main.c +++ b/umac/tdls/core/src/wlan_tdls_main.c @@ -25,6 +25,7 @@ #include "wlan_tdls_main.h" #include "wlan_tdls_cmds_process.h" #include "wlan_tdls_peer.h" +#include "wlan_tdls_ct.h" QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, void *arg_list) @@ -111,9 +112,10 @@ static QDF_STATUS tdls_vdev_init(struct tdls_vdev_priv_obj *vdev_obj) WLAN_TDLS_PEER_SUB_LIST_SIZE); } qdf_mc_timer_init(&vdev_obj->peer_update_timer, QDF_TIMER_TYPE_SW, - NULL, vdev_obj); + tdls_ct_handler, vdev_obj->vdev); qdf_mc_timer_init(&vdev_obj->peer_discovery_timer, QDF_TIMER_TYPE_SW, - NULL, vdev_obj); + tdls_discovery_timeout_peer_cb, vdev_obj); + return QDF_STATUS_SUCCESS; } @@ -247,7 +249,7 @@ QDF_STATUS tdls_process_evt(struct scheduler_msg *msg) struct tdls_event_info *event; if (!msg || !msg->bodyptr) { - tdls_err("msg: %p", msg); + tdls_err("msg is not valid: %p", msg); return QDF_STATUS_E_NULL_VALUE; } notify = msg->bodyptr; @@ -355,3 +357,31 @@ 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 tQDF_ADAPTER_MODE 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; + + wlan_vdev_obj_lock(vdev); + device_mode = wlan_vdev_mlme_get_opmode(vdev); + wlan_vdev_obj_unlock(vdev); + + if (device_mode != QDF_STA_MODE && + device_mode != QDF_P2P_CLIENT_MODE) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} diff --git a/umac/tdls/core/src/wlan_tdls_main.h b/umac/tdls/core/src/wlan_tdls_main.h index 391ccbf92aab..cf758e772e06 100644 --- a/umac/tdls/core/src/wlan_tdls_main.h +++ b/umac/tdls/core/src/wlan_tdls_main.h @@ -116,6 +116,16 @@ struct tdls_conn_tracker_mac_table { 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: @@ -164,6 +174,8 @@ struct tdls_set_state_info { * @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_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; @@ -196,6 +208,8 @@ struct tdls_soc_priv_obj { uint16_t tdls_add_sta_req; uint16_t tdls_del_sta_req; uint16_t tdls_update_peer_state; + struct tdls_ct_idle_peer_data tdls_idle_peer_data; + qdf_spinlock_t tdls_ct_spinlock; }; /** @@ -475,4 +489,16 @@ void tdls_timer_restart(struct wlan_objmgr_vdev *vdev, */ 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); + #endif diff --git a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c index 37a94d249592..7a557a3df2ba 100644 --- a/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c +++ b/umac/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -142,7 +142,16 @@ static QDF_STATUS tdls_global_init(struct tdls_soc_priv_obj *soc_obj) } 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; } @@ -259,8 +268,17 @@ QDF_STATUS ucfg_tdls_psoc_disable(struct wlan_objmgr_psoc *psoc) 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; }