Browse Source

Merge branch 'wlan-cmn.driver.lnx.2.0' of ../qca-wifi-host-cmn into HEAD

Linux Build Service Account 6 years ago
parent
commit
951c7235f4

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: Contains p2p configures interface definitions
+ */
+
+#ifndef _WLAN_TDLS_CFG_API_H_
+#define _WLAN_TDLS_CFG_API_H_
+
+#include <qdf_types.h>
+
+struct wlan_objmgr_psoc;
+
+/**
+ * cfg_tdls_get_support_enable() - get tdls support enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls support enable/disable
+ *
+ * This function gets tdls support enable
+ */
+QDF_STATUS
+cfg_tdls_get_support_enable(struct wlan_objmgr_psoc *psoc,
+			    bool *val);
+
+/**
+ * cfg_tdls_set_support_enable() - set tdls support enable
+ * @psoc:        pointer to psoc object
+ * @val:         set tdls support enable/disable
+ *
+ * This function sets tdls support enable
+ */
+QDF_STATUS
+cfg_tdls_set_support_enable(struct wlan_objmgr_psoc *psoc,
+			    bool val);
+
+/**
+ * cfg_tdls_get_external_control() - get tdls external control
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls external control enable/disable
+ *
+ * This function gets tdls external control
+ */
+QDF_STATUS
+cfg_tdls_get_external_control(struct wlan_objmgr_psoc *psoc,
+			      bool *val);
+
+/**
+ * cfg_tdls_get_uapsd_mask() - get tdls uapsd mask
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls uapsd mask
+ *
+ * This function gets tdls uapsd mask
+ */
+QDF_STATUS
+cfg_tdls_get_uapsd_mask(struct wlan_objmgr_psoc *psoc,
+			uint32_t *val);
+
+/**
+ * cfg_tdls_get_buffer_sta_enable() - get tdls buffer sta enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls buffer sta enable
+ *
+ * This function gets tdls buffer sta enable
+ */
+QDF_STATUS
+cfg_tdls_get_buffer_sta_enable(struct wlan_objmgr_psoc *psoc,
+			       bool *val);
+
+/**
+ * cfg_tdls_set_buffer_sta_enable() - set tdls buffer sta enable
+ * @psoc:        pointer to psoc object
+ * @val:         tdls buffer sta enable
+ *
+ * This function sets tdls buffer sta enable
+ */
+QDF_STATUS
+cfg_tdls_set_buffer_sta_enable(struct wlan_objmgr_psoc *psoc,
+			       bool val);
+
+/**
+ * cfg_tdls_get_uapsd_inactivity_time() - get tdls uapsd inactivity time
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls uapsd inactivity time
+ *
+ * This function gets tdls uapsd inactivity time
+ */
+QDF_STATUS
+cfg_tdls_get_uapsd_inactivity_time(struct wlan_objmgr_psoc *psoc,
+				   uint32_t *val);
+
+/**
+ * cfg_tdls_get_rx_pkt_threshold() - get tdls rx pkt threshold
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls tdls rx pkt threshold
+ *
+ * This function gets tdls rx pkt threshold
+ */
+QDF_STATUS
+cfg_tdls_get_rx_pkt_threshold(struct wlan_objmgr_psoc *psoc,
+			      uint32_t *val);
+
+/**
+ * cfg_tdls_get_off_channel_enable() - get tdls off channel enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls off channel enable
+ *
+ * This function gets tdls off channel enable
+ */
+QDF_STATUS
+cfg_tdls_get_off_channel_enable(struct wlan_objmgr_psoc *psoc,
+				bool *val);
+
+/**
+ * cfg_tdls_set_off_channel_enable() - set tdls off channel enable
+ * @psoc:        pointer to psoc object
+ * @val:         tdls off channel enable
+ *
+ * This function sets tdls off channel enable
+ */
+QDF_STATUS
+cfg_tdls_set_off_channel_enable(struct wlan_objmgr_psoc *psoc,
+				bool val);
+
+/**
+ * cfg_tdls_get_wmm_mode_enable() - get tdls wmm mode enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls wmm mode enable
+ *
+ * This function gets tdls wmm mode enable
+ */
+QDF_STATUS
+cfg_tdls_get_wmm_mode_enable(struct wlan_objmgr_psoc *psoc,
+			     bool *val);
+
+/**
+ * cfg_tdls_set_vdev_nss_2g() - set tdls vdev nss 2g
+ * @psoc:        pointer to psoc object
+ * @val:         tdls vdev nss 2g
+ *
+ * This function sets tdls vdev nss 2g
+ */
+QDF_STATUS
+cfg_tdls_set_vdev_nss_2g(struct wlan_objmgr_psoc *psoc,
+			 uint8_t val);
+
+/**
+ * cfg_tdls_set_vdev_nss_5g() - set tdls vdev nss 5g
+ * @psoc:        pointer to psoc object
+ * @val:         tdls vdev nss 5g
+ *
+ * This function sets tdls vdev nss 5g
+ */
+QDF_STATUS
+cfg_tdls_set_vdev_nss_5g(struct wlan_objmgr_psoc *psoc,
+			 uint8_t val);
+
+/**
+ * cfg_tdls_get_sleep_sta_enable() - get tdls sleep sta enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls sleep sta enable
+ *
+ * This function gets tdls sleep sta enable
+ */
+QDF_STATUS
+cfg_tdls_get_sleep_sta_enable(struct wlan_objmgr_psoc *psoc,
+			      bool *val);
+
+/**
+ * cfg_tdls_set_sleep_sta_enable() - set tdls sleep sta enable
+ * @psoc:        pointer to psoc object
+ * @val:         tdls sleep sta enable
+ *
+ * This function sets tdls sleep sta enable
+ */
+QDF_STATUS
+cfg_tdls_set_sleep_sta_enable(struct wlan_objmgr_psoc *psoc,
+			      bool val);
+
+/**
+ * cfg_tdls_get_scan_enable() - get tdls scan enable
+ * @psoc:        pointer to psoc object
+ * @val:         pointer to tdls scan enable
+ *
+ * This function gets tdls scan enable
+ */
+QDF_STATUS
+cfg_tdls_get_scan_enable(struct wlan_objmgr_psoc *psoc,
+			 bool *val);
+
+/**
+ * cfg_tdls_set_scan_enable() - set tdls scan enable
+ * @psoc:        pointer to psoc object
+ * @val:         tdls scan enable
+ *
+ * This function sets tdls scan enable
+ */
+QDF_STATUS
+cfg_tdls_set_scan_enable(struct wlan_objmgr_psoc *psoc,
+			 bool val);
+
+#endif /* _WLAN_TDLS_CFG_API_H_ */

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

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

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

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

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

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

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

@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: This file contains TDLS configures interface definitions
+ */
+
+#include <wlan_objmgr_psoc_obj.h>
+#include "wlan_tdls_cfg_api.h"
+#include "../../core/src/wlan_tdls_main.h"
+
+QDF_STATUS
+cfg_tdls_get_support_enable(struct wlan_objmgr_psoc *psoc,
+			    bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_support_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_support_enable(struct wlan_objmgr_psoc *psoc,
+			    bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_support_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_external_control(struct wlan_objmgr_psoc *psoc,
+			      bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_external_control;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_uapsd_mask(struct wlan_objmgr_psoc *psoc,
+			uint32_t *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = 0;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_uapsd_mask;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_buffer_sta_enable(struct wlan_objmgr_psoc *psoc,
+			       bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_buffer_sta_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_buffer_sta_enable(struct wlan_objmgr_psoc *psoc,
+			       bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_buffer_sta_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_uapsd_inactivity_time(struct wlan_objmgr_psoc *psoc,
+				   uint32_t *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = 0;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_uapsd_inactivity_time;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_rx_pkt_threshold(struct wlan_objmgr_psoc *psoc,
+			      uint32_t *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = 0;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_rx_pkt_threshold;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_off_channel_enable(struct wlan_objmgr_psoc *psoc,
+				bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_off_chan_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_off_channel_enable(struct wlan_objmgr_psoc *psoc,
+				bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_off_chan_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_wmm_mode_enable(struct wlan_objmgr_psoc *psoc,
+			     bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_wmm_mode_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_vdev_nss_2g(struct wlan_objmgr_psoc *psoc,
+			 uint8_t val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_vdev_nss_2g = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_vdev_nss_5g(struct wlan_objmgr_psoc *psoc,
+			 uint8_t val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_vdev_nss_5g = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_sleep_sta_enable(struct wlan_objmgr_psoc *psoc,
+			      bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_sleep_sta_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_sleep_sta_enable(struct wlan_objmgr_psoc *psoc,
+			      bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_sleep_sta_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_get_scan_enable(struct wlan_objmgr_psoc *psoc,
+			 bool *val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		*val = false;
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*val = soc_obj->tdls_configs.tdls_scan_enable;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+cfg_tdls_set_scan_enable(struct wlan_objmgr_psoc *psoc,
+			 bool val)
+{
+	struct tdls_soc_priv_obj *soc_obj;
+
+	soc_obj = wlan_psoc_get_tdls_soc_obj(psoc);
+	if (!soc_obj) {
+		tdls_err("tdls soc null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	soc_obj->tdls_configs.tdls_scan_enable = val;
+
+	return QDF_STATUS_SUCCESS;
+}

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

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

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

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

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

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