Ver Fonte

qcacld-3.0: Add TDLS connection tracker in WLAN host

TDLS implicit trigger mode works based on data traffic without
user intervention. When the traffic meets setup threshold,
TDLS connection is initiated and when the traffic
reaches a teardown threshold/rssi TDLS connection
is torn down.
Add TDLS connection tracker in the host driver to determine,
when to initiate and teardown the TDLS connection based
on data traffic.

Change-Id: I995ea9c391372515faabe5086b638f254b6b93d7
CRs-Fixed: 996988
Kabilan Kannan há 9 anos atrás
pai
commit
36090ce8b4

+ 1 - 0
core/cds/inc/cds_concurrency.h

@@ -554,6 +554,7 @@ struct cds_conc_connection_info {
 
 bool cds_is_connection_in_progress(void);
 void cds_dump_concurrency_info(void);
+void cds_set_tdls_ct_mode(hdd_context_t *hdd_ctx);
 void cds_set_concurrency_mode(enum tQDF_ADAPTER_MODE mode);
 void cds_clear_concurrency_mode(enum tQDF_ADAPTER_MODE mode);
 uint32_t cds_get_connection_count(void);

+ 53 - 0
core/cds/src/cds_concurrency.c

@@ -3371,6 +3371,41 @@ void cds_dump_concurrency_info(void)
 	}
 }
 
+/**
+ * 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 cds_set_tdls_ct_mode(hdd_context_t *hdd_ctx)
+{
+	bool state = false;
+
+	/* If any concurrency is detected, skip tdls pkt tracker */
+	if (((1 << QDF_STA_MODE) == hdd_ctx->concurrency_mode) &&
+	    (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] == 1) &&
+	    (hdd_ctx->config->fEnableTDLSImplicitTrigger) &&
+	    (eTDLS_SUPPORT_DISABLED != hdd_ctx->tdls_mode)) {
+		if (hdd_ctx->config->fTDLSExternalControl) {
+			if (hdd_ctx->tdls_external_peer_count)
+				state = true;
+			goto set_state;
+		} else {
+			state = true;
+		}
+	}
+
+set_state:
+	mutex_lock(&hdd_ctx->tdls_lock);
+	hdd_ctx->enable_tdls_connection_tracker = state;
+	mutex_unlock(&hdd_ctx->tdls_lock);
+
+	cds_info("enable_tdls_connection_tracker %d",
+		 hdd_ctx->enable_tdls_connection_tracker);
+}
+
 /**
  * cds_set_concurrency_mode() - To set concurrency mode
  * @mode: adapter mode
@@ -3402,6 +3437,10 @@ void cds_set_concurrency_mode(enum tQDF_ADAPTER_MODE mode)
 	default:
 		break;
 	}
+
+	/* set tdls connection tracker state */
+	cds_set_tdls_ct_mode(hdd_ctx);
+
 	cds_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d",
 		hdd_ctx->concurrency_mode, mode,
 		hdd_ctx->no_of_open_sessions[mode]);
@@ -3438,6 +3477,10 @@ void cds_clear_concurrency_mode(enum tQDF_ADAPTER_MODE mode)
 	default:
 		break;
 	}
+
+	/* set tdls connection tracker state */
+	cds_set_tdls_ct_mode(hdd_ctx);
+
 	cds_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d",
 		hdd_ctx->concurrency_mode, mode,
 		hdd_ctx->no_of_open_sessions[mode]);
@@ -3550,8 +3593,13 @@ void cds_incr_active_session(enum tQDF_ADAPTER_MODE mode,
 	default:
 		break;
 	}
+
+	/* set tdls connection tracker state */
+	cds_set_tdls_ct_mode(hdd_ctx);
+
 	cds_info("No.# of active sessions for mode %d = %d",
 		mode, hdd_ctx->no_of_active_sessions[mode]);
+
 	/*
 	 * Get PCL logic makes use of the connection info structure.
 	 * Let us set the PCL to the FW before updating the connection
@@ -3826,8 +3874,13 @@ void cds_decr_active_session(enum tQDF_ADAPTER_MODE mode,
 	default:
 		break;
 	}
+
+	/* set tdls connection tracker state */
+	cds_set_tdls_ct_mode(hdd_ctx);
+
 	cds_info("No.# of active sessions for mode %d = %d",
 		mode, hdd_ctx->no_of_active_sessions[mode]);
+
 	cds_decr_connection_count(session_id);
 	qdf_mutex_release(&cds_ctx->qdf_conc_list_lock);
 }

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

@@ -1257,10 +1257,13 @@ struct hdd_context_s {
 	uint16_t connected_peer_count;
 	tdls_scan_context_t tdls_scan_ctxt;
 	/* Lock to avoid race condition during TDLS operations */
+	qdf_spinlock_t tdls_ct_spinlock;
 	struct mutex tdls_lock;
 	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;
 #endif
 
 	void *hdd_ipa;

+ 47 - 5
core/hdd/inc/wlan_hdd_tdls.h

@@ -63,8 +63,12 @@
 
 #define TDLS_PEER_LIST_SIZE   256
 
+#define TDLS_CT_MAC_AGE_OUT_TIME (30*60*1000) /* Age out time is 30 mins */
+
 #define EXTTDLS_EVENT_BUF_SIZE (4096)
 
+#define TDLS_CT_MAC_MAX_TABLE_SIZE 8
+
 /**
  * struct tdls_config_params_t - tdls config params
  *
@@ -72,6 +76,7 @@
  * @tx_period_t: tx period
  * @tx_packet_n: tx packets number
  * @discovery_tries_n: discovery tries
+ * @idle_timeout_t: idle traffic time out value
  * @idle_packet_n: idle packet number
  * @rssi_trigger_threshold: rssi trigger threshold
  * @rssi_teardown_threshold: rssi tear down threshold
@@ -82,6 +87,7 @@ typedef struct {
 	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;
@@ -285,11 +291,25 @@ typedef struct {
 
 struct _hddTdlsPeer_t;
 
+/**
+ * struct tdls_ct_mac_table - connection tracker peer mac address 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_ct_mac_table {
+	struct qdf_mac_addr mac_address;
+	uint32_t tx_packet_cnt;
+	uint32_t rx_packet_cnt;
+	uint32_t peer_timestamp_ms;
+};
 /**
  * struct tdlsCtx_t - tdls context
  *
  * @peer_list: peer list
  * @pAdapter: pointer to adapter
+ * @peer_update_timer: connection tracker timer
  * @peerDiscoverTimer: peer discovery timer
  * @peerDiscoveryTimeoutTimer: peer discovery timeout timer
  * @threshold_config: threshold config
@@ -298,12 +318,15 @@ struct _hddTdlsPeer_t;
  * @ap_rssi: ap rssi
  * @curr_candidate: current candidate
  * @implicit_setup: implicit setup work queue
+ * @ct_peer_mac_table: linear mac address table for counting the packets
+ * @valid_mac_entries: number of valid mac entry in @ct_peer_mac_table
  * @magic: magic
  *
  */
 typedef struct {
 	struct list_head peer_list[TDLS_PEER_LIST_SIZE];
 	hdd_adapter_t *pAdapter;
+	qdf_mc_timer_t peer_update_timer;
 	qdf_mc_timer_t peerDiscoveryTimeoutTimer;
 	tdls_config_params_t threshold_config;
 	int32_t discovery_peer_cnt;
@@ -311,6 +334,8 @@ typedef struct {
 	int8_t ap_rssi;
 	struct _hddTdlsPeer_t *curr_candidate;
 	struct work_struct implicit_setup;
+	struct tdls_ct_mac_table ct_peer_mac_table[TDLS_CT_MAC_MAX_TABLE_SIZE];
+	uint8_t valid_mac_entries;
 	uint32_t magic;
 } tdlsCtx_t;
 
@@ -342,6 +367,8 @@ typedef struct {
  * @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
  * @reason: reason
  * @state_change_notification: state change notification
  */
@@ -371,6 +398,8 @@ typedef struct _hddTdlsPeer_t {
 	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;
 	tTDLSLinkReason reason;
 	cfg80211_exttdls_callback state_change_notification;
 } hddTdlsPeer_t;
@@ -451,14 +480,16 @@ int wlan_hdd_tdls_get_link_establish_params(hdd_adapter_t *pAdapter,
 					    tCsrTdlsLinkEstablishParams *
 					    tdlsLinkEstablishParams);
 hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter,
-				      const uint8_t *mac);
+				      const uint8_t *mac,
+				      bool need_mutex_lock);
 
 int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac,
 			  tTDLSCapType cap);
 
 void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer,
 					tTDLSLinkStatus status,
-					tTDLSLinkReason reason);
+					tTDLSLinkReason reason,
+					bool lock_needed);
 void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter,
 				   const uint8_t *mac,
 				   tTDLSLinkStatus linkStatus,
@@ -503,7 +534,8 @@ void wlan_hdd_tdls_tncrement_peer_count(hdd_adapter_t *pAdapter);
 void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter);
 
 hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx,
-					 const uint8_t *mac, uint8_t skip_self);
+					 const uint8_t *mac, uint8_t skip_self,
+					 bool need_lock);
 
 int wlan_hdd_tdls_copy_scan_context(hdd_context_t *pHddCtx,
 				    struct wiphy *wiphy,
@@ -630,10 +662,13 @@ hddTdlsPeer_t *wlan_hdd_tdls_find_first_connected_peer(hdd_adapter_t *adapter);
 int hdd_set_tdls_offchannel(hdd_context_t *hdd_ctx, int offchannel);
 int hdd_set_tdls_secoffchanneloffset(hdd_context_t *hdd_ctx, int offchanoffset);
 int hdd_set_tdls_offchannelmode(hdd_adapter_t *adapter, int offchanmode);
+void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter,
+				     struct sk_buff *skb);
+void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter,
+				     struct sk_buff *skb);
 int hdd_set_tdls_scan_type(hdd_context_t *hdd_ctx, int val);
 void hdd_tdls_context_init(hdd_context_t *hdd_ctx);
 void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx);
-
 #else
 static inline void hdd_tdls_notify_mode_change(hdd_adapter_t *adapter,
 				hdd_context_t *hddctx)
@@ -646,7 +681,14 @@ wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx)
 static inline void wlan_hdd_tdls_exit(hdd_adapter_t *adapter)
 {
 }
-
+static inline void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter,
+						   struct sk_buff *skb)
+{
+}
+static inline void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter,
+						   struct sk_buff *skb)
+{
+}
 static inline void hdd_tdls_context_init(hdd_context_t *hdd_ctx) { }
 static inline void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx) { }
 #endif /* End of FEATURE_WLAN_TDLS */

+ 2 - 1
core/hdd/src/wlan_hdd_assoc.c

@@ -3315,7 +3315,8 @@ hdd_roam_tdls_status_update_handler(hdd_adapter_t *pAdapter,
 
 		curr_peer =
 			wlan_hdd_tdls_get_peer(pAdapter,
-					       pRoamInfo->peerMac.bytes);
+					       pRoamInfo->peerMac.bytes,
+					       true);
 		if (!curr_peer) {
 			hddLog(LOGE, FL("curr_peer is null"));
 			status = QDF_STATUS_E_FAILURE;

+ 835 - 54
core/hdd/src/wlan_hdd_tdls.c

@@ -44,12 +44,15 @@
 #include "wlan_hdd_cfg80211.h"
 #include "cds_sched.h"
 #include "wma_types.h"
+#include "cds_concurrency.h"
+
 
 static int32_t wlan_hdd_tdls_peer_reset_discovery_processed(tdlsCtx_t *
 							    pHddTdlsCtx);
 static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx);
 int wpa_tdls_is_allowed_force_peer(tdlsCtx_t *pHddTdlsCtx, u8 *mac);
 static void wlan_hdd_tdls_pre_setup(struct work_struct *work);
+static void wlan_hdd_tdls_ct_handler(void *user_data);
 
 /*
  * wlan_hdd_tdls_determine_channel_opclass() - determine channel and opclass
@@ -434,7 +437,8 @@ static void wlan_hdd_tdls_discovery_timeout_peer_cb(void *userData)
 					  MAC_ADDR_ARRAY(tmp->peerMac));
 				wlan_hdd_tdls_set_peer_link_status(tmp,
 								   eTDLS_LINK_IDLE,
-								   eTDLS_LINK_NOT_SUPPORTED);
+								   eTDLS_LINK_NOT_SUPPORTED,
+								   true);
 				mutex_lock(&pHddCtx->tdls_lock);
 			}
 		}
@@ -547,6 +551,42 @@ static void wlan_hdd_tdls_monitor_timers_stop(tdlsCtx_t *hdd_tdls_ctx)
 	qdf_mc_timer_stop(&hdd_tdls_ctx->peerDiscoveryTimeoutTimer);
 }
 
+/**
+ * wlan_hdd_tdls_peer_idle_timers_stop() - stop peer idle timers
+ * @hdd_tdls_ctx: TDLS context
+ *
+ * Loop through the idle peer list and stop their timers
+ *
+ * Return: None
+ */
+static void wlan_hdd_tdls_peer_idle_timers_stop(tdlsCtx_t *hdd_tdls_ctx)
+{
+	int i;
+	struct list_head *head;
+	struct list_head *pos;
+	hddTdlsPeer_t *curr_peer;
+
+	for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
+		head = &hdd_tdls_ctx->peer_list[i];
+		list_for_each(pos, head) {
+			curr_peer = list_entry(pos, hddTdlsPeer_t, node);
+			qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
+		}
+	}
+}
+
+/**
+ * wlan_hdd_tdls_ct_timers_stop() - stop tdls connection tracker timers
+ * @hdd_tdls_ctx: TDLS context
+ *
+ * Return: None
+ */
+static void wlan_hdd_tdls_ct_timers_stop(tdlsCtx_t *hdd_tdls_ctx)
+{
+	qdf_mc_timer_stop(&hdd_tdls_ctx->peer_update_timer);
+	wlan_hdd_tdls_peer_idle_timers_stop(hdd_tdls_ctx);
+}
+
 /**
  * wlan_hdd_tdls_timers_stop() - stop all the tdls timers running
  * @hdd_tdls_ctx: TDLS context
@@ -556,6 +596,7 @@ static void wlan_hdd_tdls_monitor_timers_stop(tdlsCtx_t *hdd_tdls_ctx)
 static void wlan_hdd_tdls_timers_stop(tdlsCtx_t *hdd_tdls_ctx)
 {
 	wlan_hdd_tdls_monitor_timers_stop(hdd_tdls_ctx);
+	wlan_hdd_tdls_ct_timers_stop(hdd_tdls_ctx);
 }
 
 /**
@@ -599,6 +640,7 @@ static void wlan_hdd_tdls_del_non_forced_peers(tdlsCtx_t *hdd_tdls_ctx)
 void hdd_tdls_context_init(hdd_context_t *hdd_ctx)
 {
 	mutex_init(&hdd_ctx->tdls_lock);
+	qdf_spinlock_create(&hdd_ctx->tdls_ct_spinlock);
 }
 
 /**
@@ -612,6 +654,7 @@ void hdd_tdls_context_init(hdd_context_t *hdd_ctx)
 void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx)
 {
 	mutex_destroy(&hdd_ctx->tdls_lock);
+	qdf_spinlock_destroy(&hdd_ctx->tdls_ct_spinlock);
 }
 
 /**
@@ -675,6 +718,11 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter)
 		/* initialize TDLS pAdater context */
 		qdf_mem_zero(pHddTdlsCtx, sizeof(tdlsCtx_t));
 
+		/* Initialize connection tracker timer */
+		qdf_mc_timer_init(&pHddTdlsCtx->peer_update_timer,
+				  QDF_TIMER_TYPE_SW,
+				  wlan_hdd_tdls_ct_handler,
+				  pAdapter);
 		qdf_mc_timer_init(&pHddTdlsCtx->peerDiscoveryTimeoutTimer,
 				  QDF_TIMER_TYPE_SW,
 				  wlan_hdd_tdls_discovery_timeout_peer_cb,
@@ -702,6 +750,7 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter)
 	pHddCtx->tdls_scan_ctxt.attempt = 0;
 	pHddCtx->tdls_scan_ctxt.reject = 0;
 	pHddCtx->tdls_scan_ctxt.scan_request = NULL;
+	pHddCtx->tdls_external_peer_count = 0;
 
 	if (pHddCtx->config->fEnableTDLSSleepSta ||
 	    pHddCtx->config->fEnableTDLSBufferSta ||
@@ -723,6 +772,12 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter)
 
 	pHddTdlsCtx->curr_candidate = NULL;
 	pHddTdlsCtx->magic = 0;
+	pHddTdlsCtx->valid_mac_entries = 0;
+
+	/* This flag will set  be true, only when device operates in
+	 * standalone STA mode
+	 */
+	pHddCtx->enable_tdls_connection_tracker = false;
 
 	/* remember configuration even if it is not used right now. it could be used later */
 	pHddTdlsCtx->threshold_config.tx_period_t =
@@ -731,6 +786,8 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter)
 		pHddCtx->config->fTDLSTxPacketThreshold;
 	pHddTdlsCtx->threshold_config.discovery_tries_n =
 		pHddCtx->config->fTDLSMaxDiscoveryAttempt;
+	pHddTdlsCtx->threshold_config.idle_timeout_t =
+		pHddCtx->config->tdls_idle_timeout;
 	pHddTdlsCtx->threshold_config.idle_packet_n =
 		pHddCtx->config->fTDLSIdlePacketThreshold;
 	pHddTdlsCtx->threshold_config.rssi_trigger_threshold =
@@ -919,6 +976,7 @@ void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter)
 	}
 
 	pHddTdlsCtx->magic = 0;
+	pHddCtx->tdls_external_peer_count = 0;
 	pHddTdlsCtx->pAdapter = NULL;
 
 	qdf_mem_free(pHddTdlsCtx);
@@ -929,6 +987,46 @@ done:
 	clear_bit(TDLS_INIT_DONE, &pAdapter->event_flags);
 }
 
+/**
+ * wlan_hdd_tdls_peer_idle_timers_destroy() - destroy peer idle timers
+ * @hdd_tdls_ctx: TDLS context
+ *
+ * Loop through the idle peer list and destroy their timers
+ *
+ * Return: None
+ */
+static void wlan_hdd_tdls_peer_idle_timers_destroy(tdlsCtx_t *hdd_tdls_ctx)
+{
+	int i;
+	struct list_head *head;
+	struct list_head *pos;
+	hddTdlsPeer_t *curr_peer;
+
+	for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
+		head = &hdd_tdls_ctx->peer_list[i];
+		list_for_each(pos, head) {
+			curr_peer = list_entry(pos, hddTdlsPeer_t, node);
+			hdd_info(MAC_ADDRESS_STR ": destroy idle timer",
+				 MAC_ADDR_ARRAY(curr_peer->peerMac));
+			qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
+			qdf_mc_timer_destroy(&curr_peer->peer_idle_timer);
+		}
+	}
+}
+
+/**
+ * wlan_hdd_tdls_ct_timers_destroy() - destroy tdls connection tracker timers
+ * @hdd_tdls_ctx: TDLS context
+ *
+ * Return: None
+ */
+static void wlan_hdd_tdls_ct_timers_destroy(tdlsCtx_t *hdd_tdls_ctx)
+{
+	qdf_mc_timer_stop(&hdd_tdls_ctx->peer_update_timer);
+	qdf_mc_timer_destroy(&hdd_tdls_ctx->peer_update_timer);
+	wlan_hdd_tdls_peer_idle_timers_destroy(hdd_tdls_ctx);
+}
+
 /**
  * wlan_hdd_tdls_monitor_timers_destroy() - destroy all tdls monitoring timers
  * @pHddTdlsCtx: TDLS context
@@ -950,19 +1048,22 @@ static void wlan_hdd_tdls_monitor_timers_destroy(tdlsCtx_t *pHddTdlsCtx)
 static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx)
 {
 	wlan_hdd_tdls_monitor_timers_destroy(pHddTdlsCtx);
+	wlan_hdd_tdls_ct_timers_destroy(pHddTdlsCtx);
 }
 
 /**
  * wlan_hdd_tdls_get_peer() - find or add an peer given mac address
  * @pAdapter: HDD adapter
  * @mac: MAC address used to find or create peer
+ * @need_mutex_lock: flag identify whether mutex needed or not
  *
  * Search peer given an MAC address and create one if not found.
  *
  * Return: Pointer to peer if mac address exist or peer creation
  *         succeeds; NULL if peer creation fails
  */
-hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac)
+hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac,
+				      bool need_mutex_lock)
 {
 	struct list_head *head;
 	hddTdlsPeer_t *peer;
@@ -974,7 +1075,7 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac)
 		return NULL;
 
 	/* if already there, just update */
-	peer = wlan_hdd_tdls_find_peer(pAdapter, mac, true);
+	peer = wlan_hdd_tdls_find_peer(pAdapter, mac, need_mutex_lock);
 	if (peer != NULL) {
 		return peer;
 	}
@@ -987,13 +1088,15 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac)
 		return NULL;
 	}
 
-	mutex_lock(&pHddCtx->tdls_lock);
+	if (need_mutex_lock)
+		mutex_lock(&pHddCtx->tdls_lock);
 
 	pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
 
 	if (NULL == pHddTdlsCtx) {
 		qdf_mem_free(peer);
-		mutex_unlock(&pHddCtx->tdls_lock);
+		if (need_mutex_lock)
+			mutex_unlock(&pHddCtx->tdls_lock);
 		hddLog(LOG1, FL("pHddTdlsCtx is NULL"));
 		return NULL;
 	}
@@ -1010,7 +1113,9 @@ hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac)
 				pHddCtx->config->fTDLSPrefOffChanBandwidth);
 
 	list_add_tail(&peer->node, head);
-	mutex_unlock(&pHddCtx->tdls_lock);
+
+	if (need_mutex_lock)
+		mutex_unlock(&pHddCtx->tdls_lock);
 
 	return peer;
 }
@@ -1028,7 +1133,7 @@ int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac,
 {
 	hddTdlsPeer_t *curr_peer;
 
-	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 	if (curr_peer == NULL) {
 		hddLog(LOGE, FL("curr_peer is NULL"));
 		return -EINVAL;
@@ -1049,7 +1154,8 @@ int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac,
  */
 void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer,
 					tTDLSLinkStatus status,
-					tTDLSLinkReason reason)
+					tTDLSLinkReason reason,
+					bool lock_needed)
 {
 	uint32_t state = 0;
 	int32_t res = 0;
@@ -1072,7 +1178,9 @@ void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer,
 	       "tdls set peer " MAC_ADDRESS_STR " link status to %u",
 	       MAC_ADDR_ARRAY(curr_peer->peerMac), status);
 
-	mutex_lock(&pHddCtx->tdls_lock);
+	if (lock_needed)
+		mutex_lock(&pHddCtx->tdls_lock);
+
 	curr_peer->link_status = status;
 
 	/* If TDLS link status is already passed the discovery state
@@ -1082,7 +1190,9 @@ void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer,
 		curr_peer->discovery_attempt = 0;
 	}
 
-	mutex_unlock(&pHddCtx->tdls_lock);
+	if (lock_needed)
+		mutex_unlock(&pHddCtx->tdls_lock);
+
 	if (curr_peer->isForcedPeer && curr_peer->state_change_notification) {
 		uint32_t opclass;
 		uint32_t channel;
@@ -1184,7 +1294,7 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter,
 	if (0 != (wlan_hdd_validate_context(pHddCtx)))
 		return -EINVAL;
 
-	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 	if (NULL == curr_peer) {
 		hddLog(LOGE, FL("curr_peer is NULL"));
 		return -EINVAL;
@@ -1214,7 +1324,8 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter,
 		    rssi_trigger_threshold) {
 			wlan_hdd_tdls_set_peer_link_status(curr_peer,
 							   eTDLS_LINK_DISCOVERED,
-							   eTDLS_LINK_SUCCESS);
+							   eTDLS_LINK_SUCCESS,
+							   true);
 			hddLog(LOG1,
 				  "Rssi Threshold met: " MAC_ADDRESS_STR
 				  " rssi = %d threshold= %d",
@@ -1236,7 +1347,8 @@ int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter,
 				  rssi_trigger_threshold);
 			wlan_hdd_tdls_set_peer_link_status(curr_peer,
 							   eTDLS_LINK_IDLE,
-							   eTDLS_LINK_UNSPECIFIED);
+							   eTDLS_LINK_UNSPECIFIED,
+							   true);
 
 			/* if RSSI threshold is not met then allow further discovery
 			 * attempts by decrementing count for the last attempt
@@ -1268,7 +1380,7 @@ int wlan_hdd_tdls_set_peer_caps(hdd_adapter_t *pAdapter,
 {
 	hddTdlsPeer_t *curr_peer;
 
-	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 	if (curr_peer == NULL) {
 		hddLog(LOGE, FL("curr_peer is NULL"));
 		return -EINVAL;
@@ -1310,7 +1422,7 @@ int wlan_hdd_tdls_get_link_establish_params(hdd_adapter_t *pAdapter,
 {
 	hddTdlsPeer_t *curr_peer;
 
-	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 	if (curr_peer == NULL) {
 		hddLog(LOGE, FL("curr_peer is NULL"));
 		return -EINVAL;
@@ -1378,7 +1490,7 @@ int wlan_hdd_tdls_set_responder(hdd_adapter_t *pAdapter, const uint8_t *mac,
 {
 	hddTdlsPeer_t *curr_peer;
 
-	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 	if (curr_peer == NULL) {
 		hddLog(LOGE, FL("curr_peer is NULL"));
 		return -EINVAL;
@@ -1402,7 +1514,7 @@ int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, const uint8_t *mac,
 {
 	hddTdlsPeer_t *curr_peer;
 
-	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 	if (curr_peer == NULL) {
 		hddLog(LOGE, FL("curr_peer is NULL"));
 		return -EINVAL;
@@ -1413,18 +1525,6 @@ int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, const uint8_t *mac,
 	return 0;
 }
 
-/**
- * wlan_hdd_tdls_extract_da() - Extract destination address from socket buffer
- * @skb: socket buffer
- * @mac: output mac address buffer to store the destination address
- *
- * Return: Void
- */
-void wlan_hdd_tdls_extract_da(struct sk_buff *skb, uint8_t *mac)
-{
-	memcpy(mac, skb->data, 6);
-}
-
 /**
  * wlan_hdd_tdls_extract_sa() - Extract source address from socket buffer
  * @skb: socket buffer
@@ -1455,7 +1555,7 @@ int wlan_hdd_tdls_increment_pkt_count(hdd_adapter_t *pAdapter,
 	    eTDLS_SUPPORT_EXTERNAL_CONTROL != pHddCtx->tdls_mode)
 		return -EINVAL;
 
-	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 	if (curr_peer == NULL) {
 		hddLog(LOG1, FL("curr_peer is NULL"));
 		return -EINVAL;
@@ -1592,6 +1692,11 @@ static void wlan_hdd_tdls_implicit_enable(tdlsCtx_t *pHddTdlsCtx)
 	wlan_tdd_tdls_reset_tx_rx(pHddTdlsCtx);
 	wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter);
 
+	/* Restart the connection tracker timer */
+	wlan_hdd_tdls_timer_restart(pHddTdlsCtx->pAdapter,
+				    &pHddTdlsCtx->peer_update_timer,
+				    pHddTdlsCtx->threshold_config.tx_period_t);
+
 }
 
 /**
@@ -1875,7 +1980,7 @@ int wlan_hdd_tdls_set_sta_id(hdd_adapter_t *pAdapter, const uint8_t *mac,
 {
 	hddTdlsPeer_t *curr_peer;
 
-	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 	if (curr_peer == NULL) {
 		hddLog(LOGE, FL("curr_peer is NULL"));
 		return -EINVAL;
@@ -1999,7 +2104,6 @@ hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter,
 	tdlsCtx_t *pHddTdlsCtx;
 	hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
 
-	ENTER();
 
 	if (0 != (wlan_hdd_validate_context(pHddCtx)))
 		return NULL;
@@ -2031,7 +2135,7 @@ hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter,
 	}
 	if (mutexLock)
 		mutex_unlock(&pHddCtx->tdls_lock);
-	EXIT();
+
 	return NULL;
 }
 
@@ -2087,7 +2191,7 @@ int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, const uint8_t *mac)
 
 	pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
 
-	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 	if (curr_peer == NULL) {
 		hddLog(LOGE, FL("curr_peer is NULL"));
 		return -EINVAL;
@@ -2111,7 +2215,8 @@ int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, const uint8_t *mac)
 
 	wlan_hdd_tdls_set_peer_link_status(curr_peer,
 					   eTDLS_LINK_IDLE,
-					   eTDLS_LINK_UNSPECIFIED);
+					   eTDLS_LINK_UNSPECIFIED,
+					   true);
 	curr_peer->staId = 0;
 
 	return 0;
@@ -2240,6 +2345,7 @@ void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter)
 {
 	tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
 	hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+	uint32_t tx_period_t;
 
 	if ((NULL == pHddCtx) || (NULL == pHddTdlsCtx)) {
 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
@@ -2247,17 +2353,23 @@ void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter)
 		return;
 	}
 
-	mutex_lock(&pHddCtx->tdls_lock);
+	tx_period_t = pHddTdlsCtx->threshold_config.tx_period_t;
 
 	hddLog(LOG1,
 		FL("update %d"),
 		pHddTdlsCtx->threshold_config.tx_period_t);
 
+	mutex_lock(&pHddCtx->tdls_lock);
+
 	if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode ||
 	    eTDLS_SUPPORT_EXTERNAL_CONTROL == pHddCtx->tdls_mode) {
 		wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx);
 		pHddTdlsCtx->discovery_sent_cnt = 0;
 		wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter);
+		/* Start the connection tracker timer */
+		wlan_hdd_tdls_timer_restart(pHddTdlsCtx->pAdapter,
+					    &pHddTdlsCtx->peer_update_timer,
+					    tx_period_t);
 	}
 
 	mutex_unlock(&pHddCtx->tdls_lock);
@@ -2294,7 +2406,7 @@ void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter)
 	pHddTdlsCtx->discovery_sent_cnt = 0;
 	wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter);
 
-	wlan_hdd_tdls_monitor_timers_stop(pHddTdlsCtx);
+	wlan_hdd_tdls_timers_stop(pHddTdlsCtx);
 	wlan_hdd_tdls_free_list(pHddTdlsCtx);
 
 	pHddTdlsCtx->curr_candidate = NULL;
@@ -2431,11 +2543,14 @@ static hddTdlsPeer_t *wlan_hdd_tdls_find_progress_peer(hdd_adapter_t *pAdapter,
  * @pHddCtx: HDD context
  * @mac: mac address of the peer
  * @skip_self: if 1, skip checking self. If 0, search includes self
+ * @need_lock: flag to indicate, whether the caller acquired the mutex or not
  *
  * Return: TDLS peer if found; NULL otherwise
  */
 hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx,
-					 const uint8_t *mac, uint8_t skip_self)
+					 const uint8_t *mac,
+					 uint8_t skip_self,
+					 bool need_lock)
 {
 	hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
 	hdd_adapter_t *pAdapter = NULL;
@@ -2443,7 +2558,8 @@ hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx,
 	hddTdlsPeer_t *curr_peer = NULL;
 	QDF_STATUS status = 0;
 
-	mutex_lock(&pHddCtx->tdls_lock);
+	if (need_lock)
+		mutex_lock(&pHddCtx->tdls_lock);
 
 	status = hdd_get_front_adapter(pHddCtx, &pAdapterNode);
 	while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) {
@@ -2455,14 +2571,18 @@ hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx,
 				wlan_hdd_tdls_find_progress_peer(pAdapter, mac,
 								 skip_self);
 			if (curr_peer) {
-				mutex_unlock(&pHddCtx->tdls_lock);
+				if (need_lock)
+					mutex_unlock(&pHddCtx->tdls_lock);
 				return curr_peer;
 			}
 		}
 		status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
 		pAdapterNode = pNext;
 	}
-	mutex_unlock(&pHddCtx->tdls_lock);
+
+	if (need_lock)
+		mutex_unlock(&pHddCtx->tdls_lock);
+
 	return NULL;
 }
 
@@ -2515,7 +2635,7 @@ static void __wlan_hdd_tdls_pre_setup(struct work_struct *work)
 
 	mutex_unlock(&pHddCtx->tdls_lock);
 
-	temp_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0);
+	temp_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, true);
 
 	if (NULL != temp_peer) {
 		hddLog(LOG1,
@@ -2527,7 +2647,8 @@ static void __wlan_hdd_tdls_pre_setup(struct work_struct *work)
 	if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support)
 		wlan_hdd_tdls_set_peer_link_status(curr_peer,
 						   eTDLS_LINK_DISCOVERING,
-						   eTDLS_LINK_SUCCESS);
+						   eTDLS_LINK_SUCCESS,
+						   true);
 
 	mutex_lock(&pHddCtx->tdls_lock);
 
@@ -2563,7 +2684,8 @@ static void __wlan_hdd_tdls_pre_setup(struct work_struct *work)
 	mutex_unlock(&pHddCtx->tdls_lock);
 	wlan_hdd_tdls_set_peer_link_status(curr_peer,
 					   eTDLS_LINK_DISCOVERING,
-					   eTDLS_LINK_SUCCESS);
+					   eTDLS_LINK_SUCCESS,
+					   true);
 
 	status =
 		wlan_hdd_cfg80211_send_tdls_discover_req(pHddTdlsCtx->pAdapter->
@@ -2589,7 +2711,8 @@ static void __wlan_hdd_tdls_pre_setup(struct work_struct *work)
 			mutex_unlock(&pHddCtx->tdls_lock);
 			wlan_hdd_tdls_set_peer_link_status(curr_peer,
 							   eTDLS_LINK_IDLE,
-							   eTDLS_LINK_UNSPECIFIED);
+							   eTDLS_LINK_UNSPECIFIED,
+							   true);
 			mutex_lock(&pHddCtx->tdls_lock);
 		}
 		goto done;
@@ -2717,7 +2840,7 @@ int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy,
 	if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode)
 		return 1;
 
-	curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0);
+	curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0, true);
 	if (NULL != curr_peer) {
 		if (pHddCtx->tdls_scan_ctxt.reject++ >= TDLS_MAX_SCAN_REJECT) {
 			pHddCtx->tdls_scan_ctxt.reject = 0;
@@ -2729,7 +2852,8 @@ int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy,
 
 			wlan_hdd_tdls_set_peer_link_status(curr_peer,
 							   eTDLS_LINK_IDLE,
-							   eTDLS_LINK_UNSPECIFIED);
+							   eTDLS_LINK_UNSPECIFIED,
+							   true);
 			return 1;
 		}
 		hddLog(LOGW,
@@ -2953,7 +3077,8 @@ void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter,
 
 	wlan_hdd_tdls_set_peer_link_status(curr_peer,
 					   eTDLS_LINK_TEARING,
-					   eTDLS_LINK_UNSPECIFIED);
+					   eTDLS_LINK_UNSPECIFIED,
+					   true);
 	hdd_info("Teardown reason %d", reason);
 	cfg80211_tdls_oper_request(pAdapter->dev,
 				   curr_peer->peerMac,
@@ -3531,7 +3656,7 @@ int wlan_hdd_tdls_add_station(struct wiphy *wiphy,
 		return -ENOTSUPP;
 	}
 
-	pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, mac);
+	pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, mac, true);
 
 	if (NULL == pTdlsPeer) {
 		hddLog(LOGE,
@@ -3567,7 +3692,7 @@ int wlan_hdd_tdls_add_station(struct wiphy *wiphy,
 	}
 
 	/* when others are on-going, we want to change link_status to idle */
-	if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, mac, true)) {
+	if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, mac, true, true)) {
 		hddLog(LOG1,
 			  "%s: " MAC_ADDRESS_STR
 			  " TDLS setup is ongoing. Request declined.",
@@ -3821,7 +3946,8 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
 	}
 
 	if (WLAN_IS_TDLS_SETUP_ACTION(action_code)) {
-		if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, peer, true)) {
+		if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, peer,
+		    true, true)) {
 			QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
 				  "%s: " MAC_ADDRESS_STR
 				  " TDLS setup is ongoing. action %d declined.",
@@ -4118,7 +4244,7 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter,
 			  __func__);
 		return -ENOTSUPP;
 	}
-	pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, peer);
+	pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, peer, true);
 	if (pTdlsPeer == NULL) {
 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
 			  "%s: peer " MAC_ADDRESS_STR " does not exist",
@@ -4140,6 +4266,11 @@ int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter,
 		return -EINVAL;
 	}
 
+	pHddCtx->tdls_external_peer_count++;
+
+	/* set tdls connection tracker state */
+	cds_set_tdls_ct_mode(pHddCtx);
+
 	/* validate if off channel is DFS channel */
 	if (CDS_IS_DFS_CH(chan)) {
 		hdd_err("Resetting TDLS off-channel from %d to %d",
@@ -4204,6 +4335,7 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter,
 			  "%s Failed", __func__);
 		return -EINVAL;
 	}
+
 	/* Update the peer mac to firmware, so firmware
 	 * could update the connection table
 	 */
@@ -4213,6 +4345,13 @@ int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter,
 				MAC_ADDR_ARRAY(peer));
 		return -EINVAL;
 	}
+
+	if (pHddCtx->tdls_external_peer_count)
+		pHddCtx->tdls_external_peer_count--;
+
+	/* set tdls connection tracker state */
+	cds_set_tdls_ct_mode(pHddCtx);
+
 	if (0 != wlan_hdd_set_callback(pTdlsPeer, NULL)) {
 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR,
 			  "%s TDLS set callback Failed", __func__);
@@ -4345,7 +4484,8 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy,
 			}
 			wlan_hdd_tdls_set_peer_link_status(pTdlsPeer,
 							   eTDLS_LINK_CONNECTED,
-							   eTDLS_LINK_SUCCESS);
+							   eTDLS_LINK_SUCCESS,
+							   true);
 			/* start TDLS client registration with TL */
 			status =
 				hdd_roam_register_tdlssta(pAdapter, peer,
@@ -4558,7 +4698,8 @@ static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy,
 						(pTdlsPeer->link_status ==
 							eTDLS_LINK_TEARING) ?
 						eTDLS_LINK_UNSPECIFIED :
-						eTDLS_LINK_DROPPED_BY_REMOTE);
+						eTDLS_LINK_DROPPED_BY_REMOTE,
+						true);
 		} else {
 			QDF_TRACE(QDF_MODULE_ID_HDD,
 				  QDF_TRACE_LEVEL_ERROR,
@@ -4936,6 +5077,646 @@ int hdd_set_tdls_offchannelmode(hdd_adapter_t *adapter, int offchanmode)
 	return 0;
 }
 
+/**
+ * wlan_hdd_tdls_ct_sampling_tx_rx() - collect tx/rx traffic sample
+ * @adapter: pointer to hdd adapter
+ * @hdd_ctx: hdd context
+ * @tdls_ctx: tdls context
+ *
+ * Function to update data traffic information in tdls connection
+ * tracker data structure for connection tracker operation
+ *
+ * Return: None
+ */
+static void wlan_hdd_tdls_ct_sampling_tx_rx(hdd_adapter_t *adapter,
+				     hdd_context_t *hdd_ctx,
+				     tdlsCtx_t *tdls_ctx)
+{
+	hddTdlsPeer_t *curr_peer;
+	uint8_t mac[QDF_MAC_ADDR_SIZE];
+	uint8_t mac_cnt;
+	uint8_t valid_mac_entries;
+	struct tdls_ct_mac_table ct_peer_mac_table[TDLS_CT_MAC_MAX_TABLE_SIZE];
+
+	qdf_spin_lock(&hdd_ctx->tdls_ct_spinlock);
+
+	if (0 == tdls_ctx->valid_mac_entries) {
+		qdf_spin_unlock(&hdd_ctx->tdls_ct_spinlock);
+		return;
+	}
+
+	valid_mac_entries = tdls_ctx->valid_mac_entries;
+
+	memcpy(ct_peer_mac_table, tdls_ctx->ct_peer_mac_table,
+	       (sizeof(struct tdls_ct_mac_table)) * valid_mac_entries);
+
+	memset(tdls_ctx->ct_peer_mac_table, 0,
+	       (sizeof(struct tdls_ct_mac_table)) * valid_mac_entries);
+
+	tdls_ctx->valid_mac_entries = 0;
+
+	qdf_spin_unlock(&hdd_ctx->tdls_ct_spinlock);
+
+	for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
+		memcpy(mac, ct_peer_mac_table[mac_cnt].mac_address.bytes,
+		       QDF_MAC_ADDR_SIZE);
+		curr_peer = wlan_hdd_tdls_get_peer(adapter, mac, false);
+		if (NULL != curr_peer) {
+			curr_peer->tx_pkt =
+			ct_peer_mac_table[mac_cnt].tx_packet_cnt;
+			curr_peer->rx_pkt =
+			ct_peer_mac_table[mac_cnt].rx_packet_cnt;
+		}
+	}
+}
+
+/**
+ * wlan_hdd_tdls_update_rx_pkt_cnt() - Update rx packet count
+ * @adapter: pointer to hdd adapter
+ * @skb: pointer to sk_buff
+ *
+ * Increase the rx packet count, if the sender is not bssid and the packet is
+ * not broadcast and muticast packet
+ *
+ * This sampling information will be used in TDLS connection tracker
+ *
+ * This function expected to be called in an atomic context so blocking APIs
+ * not allowed
+ *
+ * Return: None
+ */
+void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter,
+				     struct sk_buff *skb)
+{
+	hdd_context_t *hdd_ctx;
+	hdd_station_ctx_t *hdd_sta_ctx;
+	tdlsCtx_t *tdls_ctx;
+	uint8_t mac_cnt;
+	uint8_t valid_mac_entries;
+	struct qdf_mac_addr *mac_addr;
+
+	mac_addr = (struct qdf_mac_addr *)(skb->data+QDF_MAC_ADDR_SIZE);
+	if (qdf_is_macaddr_group(mac_addr))
+		return;
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	if (memcmp(hdd_sta_ctx->conn_info.bssId.bytes,
+			mac_addr, QDF_MAC_ADDR_SIZE) == 0)
+		return;
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx;
+
+	qdf_spin_lock(&hdd_ctx->tdls_ct_spinlock);
+	valid_mac_entries = tdls_ctx->valid_mac_entries;
+
+	for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
+		if (memcmp(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes,
+		    mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
+			tdls_ctx->ct_peer_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 < TDLS_CT_MAC_MAX_TABLE_SIZE) {
+		memcpy(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes,
+		       mac_addr, QDF_MAC_ADDR_SIZE);
+		tdls_ctx->valid_mac_entries = mac_cnt+1;
+		tdls_ctx->ct_peer_mac_table[mac_cnt].rx_packet_cnt = 1;
+	}
+
+rx_cnt_return:
+	qdf_spin_unlock(&hdd_ctx->tdls_ct_spinlock);
+	return;
+}
+
+/**
+ * wlan_hdd_tdls_update_tx_pkt_cnt() - update tx packet
+ * @adapter: pointer to hdd adapter
+ * @skb: pointer to sk_buff
+ *
+ * Increase the tx packet count, if the sender is not bssid and the packet is
+ * not broadcast and muticast packet
+ *
+ * This sampling information will be used in TDLS connection tracker
+ *
+ * This function expected to be called in an atomic context so blocking APIs
+ * not allowed
+ *
+ * Return: None
+ */
+void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter,
+				     struct sk_buff *skb)
+{
+	hdd_context_t *hdd_ctx;
+	hdd_station_ctx_t *hdd_sta_ctx;
+	tdlsCtx_t *tdls_ctx;
+	uint8_t mac_cnt;
+	uint8_t valid_mac_entries;
+	struct qdf_mac_addr *mac_addr;
+
+	mac_addr = (struct qdf_mac_addr *)skb->data;
+	if (qdf_is_macaddr_group(mac_addr))
+		return;
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	if (memcmp(hdd_sta_ctx->conn_info.bssId.bytes, mac_addr,
+	    QDF_MAC_ADDR_SIZE) == 0)
+		return;
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx;
+
+	qdf_spin_lock(&hdd_ctx->tdls_ct_spinlock);
+	valid_mac_entries = tdls_ctx->valid_mac_entries;
+
+	for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) {
+		if (memcmp(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes,
+		    mac_addr, QDF_MAC_ADDR_SIZE) == 0) {
+			tdls_ctx->ct_peer_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 < TDLS_CT_MAC_MAX_TABLE_SIZE) {
+		memcpy(tdls_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes,
+			mac_addr, QDF_MAC_ADDR_SIZE);
+		tdls_ctx->ct_peer_mac_table[mac_cnt].tx_packet_cnt = 1;
+		tdls_ctx->valid_mac_entries++;
+	}
+
+tx_cnt_return:
+	qdf_spin_unlock(&hdd_ctx->tdls_ct_spinlock);
+	return;
+}
+
+/**
+ * wlan_hdd_tdls_implicit_send_discovery_request() - send discovery request
+ * @hdd_tdls_ctx: tdls context
+ *
+ * Return: None
+ */
+static
+void wlan_hdd_tdls_implicit_send_discovery_request(tdlsCtx_t *hdd_tdls_ctx)
+{
+	hdd_context_t *hdd_ctx;
+	hddTdlsPeer_t *curr_peer, *temp_peer;
+
+	ENTER();
+	if (NULL == hdd_tdls_ctx) {
+		hdd_info("hdd_tdls_ctx is NULL");
+		return;
+	}
+
+	hdd_ctx = WLAN_HDD_GET_CTX(hdd_tdls_ctx->pAdapter);
+
+	if (0 != (wlan_hdd_validate_context(hdd_ctx)))
+		return;
+
+	curr_peer = hdd_tdls_ctx->curr_candidate;
+	if (NULL == curr_peer) {
+		hdd_err("curr_peer is NULL");
+		return;
+	}
+
+	/* This function is called in mutex_lock */
+	temp_peer = wlan_hdd_tdls_is_progress(hdd_ctx, NULL, 0, false);
+	if (NULL != temp_peer) {
+		hdd_info(MAC_ADDRESS_STR " ongoing. pre_setup ignored",
+			 MAC_ADDR_ARRAY(temp_peer->peerMac));
+		goto done;
+	}
+
+	if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support)
+		wlan_hdd_tdls_set_peer_link_status(curr_peer,
+					   eTDLS_LINK_DISCOVERING,
+					   eTDLS_LINK_SUCCESS,
+					   false);
+
+	hdd_info("Implicit TDLS, Send Discovery request event");
+	cfg80211_tdls_oper_request(hdd_tdls_ctx->pAdapter->dev,
+				   curr_peer->peerMac,
+				   NL80211_TDLS_DISCOVERY_REQ,
+				   false,
+				   GFP_KERNEL);
+	hdd_tdls_ctx->discovery_sent_cnt++;
+
+	wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter,
+				&hdd_tdls_ctx->peerDiscoveryTimeoutTimer,
+				hdd_tdls_ctx->threshold_config.tx_period_t -
+				TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE);
+
+	hdd_info("discovery count %u timeout %u msec",
+		 hdd_tdls_ctx->discovery_sent_cnt,
+		 hdd_tdls_ctx->threshold_config.tx_period_t -
+		 TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE);
+done:
+	hdd_tdls_ctx->curr_candidate = NULL;
+	hdd_tdls_ctx->magic = 0;
+	EXIT();
+	return;
+}
+
+/**
+ * wlan_hdd_get_conn_info() - get the tdls connection information.
+ * @hdd_ctx: hdd context
+ * @hdd_ctx: sta id
+ *
+ * Function to check tdls sta index
+ *
+ * Return: None
+ */
+static tdlsConnInfo_t *wlan_hdd_get_conn_info(hdd_context_t *hdd_ctx,
+				       uint8_t idx)
+{
+	uint8_t sta_idx;
+
+	/* check if there is available index for this new TDLS STA */
+	for (sta_idx = 0; sta_idx < HDD_MAX_NUM_TDLS_STA; sta_idx++) {
+		if (idx == hdd_ctx->tdlsConnInfo[sta_idx].staId) {
+			hdd_info("tdls peer with staIdx %u exists", idx);
+			return &hdd_ctx->tdlsConnInfo[sta_idx];
+		}
+	}
+	hdd_err("tdls peer with staIdx %u not exists", idx);
+	return NULL;
+}
+
+/**
+ * wlan_hdd_tdls_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
+ */
+static void wlan_hdd_tdls_idle_handler(void *user_data)
+{
+	tdlsConnInfo_t *tdls_info = (tdlsConnInfo_t *) user_data;
+	hddTdlsPeer_t *curr_peer;
+	tdlsCtx_t *hdd_tdls_ctx;
+	hdd_context_t *hdd_ctx;
+	v_CONTEXT_t cds_context;
+	hdd_adapter_t *adapter;
+
+	if (!tdls_info->staId) {
+		hdd_err("peer (staidx %u) doesn't exists", tdls_info->staId);
+		return;
+	}
+
+	cds_context = cds_get_global_context();
+	if (NULL == cds_context) {
+		hdd_err("cds_context points to NULL");
+		return;
+	}
+
+	hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+	if (0 != (wlan_hdd_validate_context(hdd_ctx)))
+		return;
+
+	adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx,
+						    tdls_info->sessionId);
+
+	if (!adapter) {
+		hdd_err("adapter is NULL");
+		return;
+	}
+
+	curr_peer = wlan_hdd_tdls_find_peer(adapter,
+		(u8 *) &tdls_info->peerMac.bytes[0], true);
+
+	if (NULL == curr_peer) {
+		hdd_err("Invalid tdls idle timer expired");
+		goto error_idle_return;
+	}
+
+	hdd_tdls_ctx = curr_peer->pHddTdlsCtx;
+	if (NULL == hdd_tdls_ctx) {
+		hdd_err("Invalid hdd_tdls_ctx context");
+		goto error_idle_return;
+	}
+
+	hdd_info(MAC_ADDRESS_STR " tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d",
+		 MAC_ADDR_ARRAY(curr_peer->peerMac),
+		curr_peer->tx_pkt,
+		curr_peer->rx_pkt,
+		curr_peer->pHddTdlsCtx->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 >=
+	     curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n) ||
+	    (curr_peer->rx_pkt >=
+	     curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n)) {
+		/* this tdls link got back to normal, so keep it */
+		hdd_info("tdls link to " MAC_ADDRESS_STR
+			 " back to normal, will stay",
+			  MAC_ADDR_ARRAY(curr_peer->peerMac));
+	} else {
+		/* this tdls link needs to get torn down */
+		hdd_info("trigger tdls link to "MAC_ADDRESS_STR
+			 " down", MAC_ADDR_ARRAY(curr_peer->peerMac));
+		wlan_hdd_tdls_indicate_teardown(curr_peer->pHddTdlsCtx->pAdapter,
+						curr_peer,
+						eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
+	}
+error_idle_return:
+	return;
+}
+
+/**
+ * tdls_ct_process_idle_and_discovery() - process the traffic data
+ * @curr_peer: tdls peer needs to be examined
+ * @hdd_ctx: hdd context
+ * @hdd_tdls_ctx: tdls context
+ *
+ * Function to check the peer traffic data in idle link and  tdls
+ * discovering link
+ *
+ * Return: None
+ */
+static void tdls_ct_process_idle_and_discovery(hddTdlsPeer_t *curr_peer,
+					       tdlsCtx_t *hdd_tdls_ctx)
+{
+	uint16_t valid_peers;
+
+	valid_peers = wlan_hdd_tdls_connected_peers(hdd_tdls_ctx->pAdapter);
+
+	if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
+	     hdd_tdls_ctx->threshold_config.tx_packet_n) {
+		if (HDD_MAX_NUM_TDLS_STA > valid_peers) {
+			hdd_info("Tput trigger TDLS pre-setup");
+			hdd_tdls_ctx->curr_candidate = curr_peer;
+			wlan_hdd_tdls_implicit_send_discovery_request(
+								  hdd_tdls_ctx);
+		} else {
+			hdd_info("Maximum peers connected already! %d",
+				 valid_peers);
+		}
+	}
+}
+
+
+/**
+ * tdls_ct_process_connected_link() - process the traffic
+ * @curr_peer: tdls peer needs to be examined
+ * @hdd_ctx: hdd context
+ * @hdd_tdls_ctx: tdls context
+ *
+ * Function to check the peer traffic data in active STA
+ * session
+ *
+ * Return: None
+ */
+static void tdls_ct_process_connected_link(hddTdlsPeer_t *curr_peer,
+					   hdd_context_t *hdd_ctx,
+					   tdlsCtx_t *hdd_tdls_ctx)
+{
+	if ((int32_t)curr_peer->rssi <
+	    (int32_t)hdd_tdls_ctx->threshold_config.rssi_teardown_threshold) {
+		hdd_warn("Tear down - low RSSI: " MAC_ADDRESS_STR "!",
+			 MAC_ADDR_ARRAY(curr_peer->peerMac));
+		/* unlock the mutex here, it may used in caller function */
+		mutex_unlock(&hdd_ctx->tdls_lock);
+		wlan_hdd_tdls_indicate_teardown(hdd_tdls_ctx->pAdapter,
+						curr_peer,
+						eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON);
+		mutex_lock(&hdd_ctx->tdls_lock);
+		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 != hdd_tdls_ctx->threshold_config.idle_packet_n) &&
+	    ((curr_peer->tx_pkt <
+	      hdd_tdls_ctx->threshold_config.idle_packet_n) &&
+	     (curr_peer->rx_pkt <
+	      hdd_tdls_ctx->threshold_config.idle_packet_n))) {
+		if (!curr_peer->is_peer_idle_timer_initialised) {
+			uint8_t staId = (uint8_t)curr_peer->staId;
+			tdlsConnInfo_t *tdls_info;
+			tdls_info = wlan_hdd_get_conn_info(hdd_ctx, staId);
+			qdf_mc_timer_init(&curr_peer->peer_idle_timer,
+					  QDF_TIMER_TYPE_SW,
+					  wlan_hdd_tdls_idle_handler,
+					  tdls_info);
+			curr_peer->is_peer_idle_timer_initialised = true;
+		}
+		if (QDF_TIMER_STATE_RUNNING !=
+		    curr_peer->peer_idle_timer.state) {
+			hdd_warn("Tx/Rx Idle timer start: " MAC_ADDRESS_STR "!",
+				MAC_ADDR_ARRAY(curr_peer->peerMac));
+			wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter,
+						    &curr_peer->peer_idle_timer,
+						    hdd_tdls_ctx->threshold_config.idle_timeout_t);
+		}
+	} else if (QDF_TIMER_STATE_RUNNING ==
+		   curr_peer->peer_idle_timer.state) {
+		hdd_warn("Tx/Rx Idle timer stop: " MAC_ADDRESS_STR "!",
+			 MAC_ADDR_ARRAY(curr_peer->peerMac));
+		qdf_mc_timer_stop(&curr_peer->peer_idle_timer);
+	}
+}
+
+/**
+ * wlan_hdd_tdls_ct_process_cap_supported() - process TDLS supported peer.
+ * @curr_peer: tdls peer needs to be examined
+ * @hdd_ctx: hdd context
+ * @hdd_tdls_ctx: tdls context
+ *
+ * Function to check the peer traffic data  for tdls supported peer
+ *
+ * Return: None
+ */
+static void wlan_hdd_tdls_ct_process_cap_supported(hddTdlsPeer_t *curr_peer,
+						   hdd_context_t *hdd_ctx,
+						   tdlsCtx_t *hdd_tdls_ctx)
+{
+	hdd_info("tx %d, rx %d (thr.pkt %d/idle %d), rssi %d (thr.trig %d/tear %d)",
+		 curr_peer->tx_pkt, curr_peer->rx_pkt,
+		 hdd_tdls_ctx->threshold_config.tx_packet_n,
+		 hdd_tdls_ctx->threshold_config.idle_packet_n,
+		 curr_peer->rssi,
+		 hdd_tdls_ctx->threshold_config.rssi_trigger_threshold,
+		 hdd_tdls_ctx->threshold_config.rssi_teardown_threshold);
+
+	switch (curr_peer->link_status) {
+	case eTDLS_LINK_IDLE:
+	case eTDLS_LINK_DISCOVERING:
+		if (hdd_ctx->config->fTDLSExternalControl &&
+		    (!curr_peer->isForcedPeer))
+			break;
+		tdls_ct_process_idle_and_discovery(curr_peer, hdd_tdls_ctx);
+		break;
+	case eTDLS_LINK_CONNECTED:
+		tdls_ct_process_connected_link(curr_peer, hdd_ctx,
+					       hdd_tdls_ctx);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * wlan_hdd_tdls_ct_process_cap_unknown() - process unknown peer
+ * @curr_peer: tdls peer needs to be examined
+ * @hdd_ctx: hdd context
+ * @hdd_tdls_ctx: tdls context
+ *
+ * Function check the peer traffic data , when tdls capability is unknown
+ *
+ * Return: None
+ */
+static void wlan_hdd_tdls_ct_process_cap_unknown(hddTdlsPeer_t *curr_peer,
+						 hdd_context_t *hdd_ctx,
+						 tdlsCtx_t *hdd_tdls_ctx)
+{
+	if (hdd_ctx->config->fTDLSExternalControl &&
+	    (!curr_peer->isForcedPeer)) {
+		return;
+	}
+
+	hdd_info("threshold_config.tx_packet_n = %d curr_peer->tx_pkt = %d curr_peer->rx_pkt = %d ",
+		hdd_tdls_ctx->threshold_config.tx_packet_n, curr_peer->tx_pkt,
+		curr_peer->rx_pkt);
+
+	if (!TDLS_IS_CONNECTED(curr_peer) &&
+	    ((curr_peer->tx_pkt + curr_peer->rx_pkt) >=
+	    hdd_tdls_ctx->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
+		 */
+		hdd_info("TDLS UNKNOWN pre discover ");
+		if (curr_peer->isForcedPeer || curr_peer->discovery_attempt++ <
+		    hdd_tdls_ctx->threshold_config.discovery_tries_n) {
+			hdd_info("TDLS UNKNOWN discover ");
+			hdd_tdls_ctx->curr_candidate = curr_peer;
+			wlan_hdd_tdls_implicit_send_discovery_request(hdd_tdls_ctx);
+		} else {
+			curr_peer->tdls_support = eTDLS_CAP_NOT_SUPPORTED;
+			wlan_hdd_tdls_set_peer_link_status(
+				    curr_peer,
+				    eTDLS_LINK_IDLE,
+				    eTDLS_LINK_NOT_SUPPORTED,
+				    false);
+		}
+	}
+}
+
+
+/**
+ * wlan_hdd_tdls_ct_process_peers() - process the peer
+ * @curr_peer: tdls peer needs to be examined
+ * @hdd_ctx: hdd context
+ * @hdd_tdls_ctx: tdls context
+ *
+ * This function check the peer capability and process the metadata from
+ * the peer
+ *
+ * Return: None
+ */
+static void wlan_hdd_tdls_ct_process_peers(hddTdlsPeer_t *curr_peer,
+					   hdd_context_t *hdd_ctx,
+					   tdlsCtx_t *hdd_tdls_ctx)
+{
+	hdd_info(MAC_ADDRESS_STR " link_status %d tdls_support %d",
+		 MAC_ADDR_ARRAY(curr_peer->peerMac),
+		 curr_peer->link_status, curr_peer->tdls_support);
+
+	switch (curr_peer->tdls_support) {
+	case eTDLS_CAP_SUPPORTED:
+		wlan_hdd_tdls_ct_process_cap_supported(curr_peer, hdd_ctx,
+						       hdd_tdls_ctx);
+		break;
+
+	case eTDLS_CAP_UNKNOWN:
+		wlan_hdd_tdls_ct_process_cap_unknown(curr_peer, hdd_ctx,
+						     hdd_tdls_ctx);
+		break;
+	default:
+		break;
+	}
+
+}
+
+/**
+ * wlan_hdd_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
+ */
+static void wlan_hdd_tdls_ct_handler(void *user_data)
+{
+	int i;
+	hdd_adapter_t *adapter;
+	struct list_head *head;
+	struct list_head *pos;
+	hddTdlsPeer_t *curr_peer;
+	tdlsCtx_t *hdd_tdls_ctx;
+	hdd_context_t *hdd_ctx;
+
+	adapter = (hdd_adapter_t *)user_data;
+
+	if (NULL == adapter) {
+		hdd_err("Invalid adapter context");
+		return;
+	}
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+
+	if (0 != (wlan_hdd_validate_context(hdd_ctx)))
+		return;
+
+	hdd_tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx;
+
+	if (NULL == hdd_tdls_ctx) {
+		hdd_err("Invalid hdd_tdls_ctx context");
+		return;
+	}
+
+	/* If any concurrency is detected */
+	if (!hdd_ctx->enable_tdls_connection_tracker)
+		goto restart_return;
+
+	mutex_lock(&hdd_ctx->tdls_lock);
+
+	/* Update tx rx traffic sample in tdls data structures */
+	wlan_hdd_tdls_ct_sampling_tx_rx(adapter, hdd_ctx,
+					hdd_tdls_ctx);
+
+	for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) {
+		head = &hdd_tdls_ctx->peer_list[i];
+		list_for_each(pos, head) {
+			curr_peer = list_entry(pos, hddTdlsPeer_t, node);
+			wlan_hdd_tdls_ct_process_peers(curr_peer, hdd_ctx,
+						       hdd_tdls_ctx);
+			curr_peer->tx_pkt = 0;
+			curr_peer->rx_pkt = 0;
+		}
+	}
+
+	mutex_unlock(&hdd_ctx->tdls_lock);
+
+restart_return:
+	wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter,
+				    &hdd_tdls_ctx->peer_update_timer,
+				    hdd_tdls_ctx->threshold_config.tx_period_t);
+}
+
 /**
  * hdd_set_tdls_scan_type - set scan during active tdls session
  * @hdd_ctx: ptr to hdd context.

+ 25 - 0
core/hdd/src/wlan_hdd_tx_rx.c

@@ -315,6 +315,10 @@ int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	bool granted;
 	uint8_t STAId = WLAN_MAX_STA_COUNT;
 	hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
+#ifdef QCA_PKT_PROTO_TRACE
+	uint8_t proto_type = 0;
+#endif /* QCA_PKT_PROTO_TRACE */
+	hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
 
 #ifdef QCA_WIFI_FTM
 	if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
@@ -466,7 +470,25 @@ int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		skb->queue_mapping = hdd_linux_up_to_ac_map[up];
 	}
 
+#ifdef QCA_PKT_PROTO_TRACE
+	if ((hdd_ctx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) ||
+	    (hdd_ctx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) {
+		proto_type = cds_pkt_get_proto_type(skb,
+						    hdd_ctx->config->gEnableDebugLog,
+						    0);
+		if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) {
+			cds_pkt_trace_buf_update("ST:T:EPL");
+		} else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) {
+			cds_pkt_trace_buf_update("ST:T:DHC");
+		}
+	}
+#endif /* QCA_PKT_PROTO_TRACE */
+
 	pAdapter->stats.tx_bytes += skb->len;
+
+	if (hdd_ctx->enable_tdls_connection_tracker)
+		wlan_hdd_tdls_update_tx_pkt_cnt(pAdapter, skb);
+
 	++pAdapter->stats.tx_packets;
 
 	/* Zero out skb's context buffer for the driver to use */
@@ -805,6 +827,9 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf)
 		qdf_nbuf_data_addr(rxBuf),
 		sizeof(qdf_nbuf_data(rxBuf)), QDF_RX));
 
+	if (pHddCtx->enable_tdls_connection_tracker)
+		wlan_hdd_tdls_update_rx_pkt_cnt(pAdapter, skb);
+
 	skb->dev = pAdapter->dev;
 	skb->protocol = eth_type_trans(skb, skb->dev);
 	++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index];