Преглед изворни кода

qcacld-3.0: Add support for TDLS over P2P clients

P2P data traffic can be improved by creating TDLS
connection between two P2P clients.
Add changes in the host driver to enable TDLS
connection between two P2P clients.

Change-Id: I2a9fe21bb3be160428ab5d8f04281802faa5f21b
CRs-Fixed: 999560
Kabilan Kannan пре 9 година
родитељ
комит
163fd0b20b

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

@@ -550,6 +550,7 @@ struct cds_conc_connection_info {
 
 bool cds_is_connection_in_progress(void);
 void cds_dump_concurrency_info(void);
+bool cds_check_is_tdls_allowed(enum tQDF_ADAPTER_MODE device_mode);
 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);
@@ -782,4 +783,6 @@ QDF_STATUS cds_set_hw_mode_on_channel_switch(uint8_t session_id);
 void cds_set_do_hw_mode_change_flag(bool flag);
 bool cds_is_hw_mode_change_after_vdev_up(void);
 void cds_dump_connection_status_info(void);
+uint32_t cds_mode_specific_connection_count(enum cds_con_mode mode,
+						uint32_t *list);
 #endif /* __CDS_CONCURRENCY_H */

+ 85 - 37
core/cds/src/cds_concurrency.c

@@ -1950,6 +1950,27 @@ next_action_three_connection_table[CDS_MAX_TWO_CONNECTION_MODE]
 
 };
 
+/**
+ * cds_get_connection_count() - provides the count of
+ * current connections
+ *
+ * This function provides the count of current connections
+ *
+ * Return: connection count
+ */
+uint32_t cds_get_connection_count(void)
+{
+	uint32_t conn_index, count = 0;
+
+	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
+		 conn_index++) {
+		if (conc_connection_list[conn_index].in_use)
+			count++;
+	}
+
+	return count;
+}
+
 /**
  * cds_is_sta_connection_pending() - This function will check if sta connection
  *                                   is pending or not.
@@ -2136,7 +2157,7 @@ static void cds_update_conc_list(uint32_t conn_index,
  *
  * Return: connection count of specific type
  */
-static uint32_t cds_mode_specific_connection_count(enum cds_con_mode mode,
+uint32_t cds_mode_specific_connection_count(enum cds_con_mode mode,
 						uint32_t *list)
 {
 	uint32_t conn_index = 0, count = 0;
@@ -3295,6 +3316,34 @@ void cds_dump_concurrency_info(void)
 	hdd_ctx->mcc_mode = !cds_current_concurrency_is_scc();
 }
 
+/*
+ * cds_check_is_tdls_allowed() - check is tdls allowed or not
+ * @adapter: pointer to adapter
+ *
+ * Function determines the whether TDLS allowed in the system
+ *
+ * Return: true or false
+ */
+bool cds_check_is_tdls_allowed(enum tQDF_ADAPTER_MODE device_mode)
+{
+	bool state = false;
+	uint32_t count;
+
+	count = cds_get_connection_count();
+
+	if (count > 1)
+		state = false;
+	else if (device_mode == QDF_STA_MODE ||
+		 device_mode == QDF_P2P_CLIENT_MODE)
+		state = true;
+
+	/* If any concurrency is detected */
+	if (!state)
+		cds_dump_concurrency_info();
+
+	return state;
+}
+
 /**
  * cds_set_tdls_ct_mode() - Set the tdls connection tracker mode
  * @hdd_ctx: hdd context
@@ -3308,17 +3357,34 @@ 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 {
+	if (cds_get_connection_count() > 1) {
+		state = false;
+		goto set_state;
+	}
+
+	if (eTDLS_SUPPORT_DISABLED == hdd_ctx->tdls_mode ||
+	    (!hdd_ctx->config->fEnableTDLSImplicitTrigger)) {
+		state = false;
+		goto set_state;
+	} else if (cds_mode_specific_connection_count(QDF_STA_MODE,
+						      NULL) == 1) {
+		state = true;
+	} else if (cds_mode_specific_connection_count(QDF_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 (hdd_ctx->config->fTDLSExternalControl) {
+		if (hdd_ctx->tdls_external_peer_count)
 			state = true;
-		}
+		else
+			state = false;
 	}
 
 set_state:
@@ -3518,8 +3584,6 @@ void cds_incr_active_session(enum tQDF_ADAPTER_MODE mode,
 		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]);
@@ -3535,6 +3599,10 @@ void cds_incr_active_session(enum tQDF_ADAPTER_MODE mode,
 		cds_info("Set PCL of STA to FW");
 	}
 	cds_incr_connection_count(session_id);
+
+	/* set tdls connection tracker state */
+	cds_set_tdls_ct_mode(hdd_ctx);
+
 	qdf_mutex_release(&cds_ctx->qdf_conc_list_lock);
 }
 
@@ -3786,13 +3854,14 @@ void cds_decr_active_session(enum tQDF_ADAPTER_MODE mode,
 		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);
+
+	/* set tdls connection tracker state */
+	cds_set_tdls_ct_mode(hdd_ctx);
+
 	qdf_mutex_release(&cds_ctx->qdf_conc_list_lock);
 }
 
@@ -3969,27 +4038,6 @@ uint32_t cds_get_connection_for_vdev_id(uint32_t vdev_id)
 	return conn_index;
 }
 
-
-/**
- * cds_get_connection_count() - provides the count of
- * current connections
- *
- *
- * This function provides the count of current connections
- *
- * Return: connection count
- */
-uint32_t cds_get_connection_count(void)
-{
-	uint32_t conn_index, count = 0;
-	for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS;
-		 conn_index++) {
-		if (conc_connection_list[conn_index].in_use)
-			count++;
-	}
-	return count;
-}
-
 /**
  * cds_get_mode() - Get mode from type and subtype
  * @type: type

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

@@ -1261,6 +1261,7 @@ struct hdd_context_s {
 
 #ifdef FEATURE_WLAN_TDLS
 	eTDLSSupportMode tdls_mode;
+	bool concurrency_marked;
 	eTDLSSupportMode tdls_mode_last;
 	tdlsConnInfo_t tdlsConnInfo[HDD_MAX_NUM_TDLS_STA];
 	/* maximum TDLS station number allowed upon runtime condition */
@@ -1278,6 +1279,7 @@ struct hdd_context_s {
 	uint8_t tdls_external_peer_count;
 	bool tdls_nss_switch_in_progress;
 	int32_t tdls_teardown_peers_cnt;
+	struct tdls_set_state_info set_state_info;
 #endif
 
 	void *hdd_ipa;

+ 26 - 0
core/hdd/inc/wlan_hdd_tdls.h

@@ -314,6 +314,17 @@ struct tdls_ct_mac_table {
 	uint32_t rx_packet_cnt;
 	uint32_t peer_timestamp_ms;
 };
+
+/**
+ * struct tdls_set_state_db - set state command data base
+ * @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 tdlsCtx_t - tdls context
  *
@@ -684,6 +695,8 @@ void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx);
 int wlan_hdd_tdls_antenna_switch(hdd_context_t *hdd_ctx,
 				 hdd_adapter_t *adapter,
 				 uint32_t mode);
+hdd_adapter_t *wlan_hdd_tdls_check_and_enable(hdd_context_t *hdd_ctx);
+
 
 #else
 static inline void hdd_tdls_notify_mode_change(hdd_adapter_t *adapter,
@@ -714,6 +727,19 @@ static inline int wlan_hdd_tdls_antenna_switch(hdd_context_t *hdd_ctx,
 {
 	return 0;
 }
+
+static inline hdd_adapter_t *wlan_hdd_tdls_check_and_enable(
+						hdd_context_t *hdd_ctx)
+{
+	return NULL;
+}
+
+static inline void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter,
+						bool tdls_prohibited,
+						bool tdls_chan_swit_prohibited)
+{
+}
+
 #endif /* End of FEATURE_WLAN_TDLS */
 
 #ifdef FEATURE_WLAN_DIAG_SUPPORT

+ 26 - 16
core/hdd/src/wlan_hdd_assoc.c

@@ -1247,6 +1247,7 @@ static void hdd_send_association_event(struct net_device *dev,
 	int we_event;
 	char *msg;
 	struct qdf_mac_addr peerMacAddr;
+	hdd_adapter_t *tdls_adapter;
 
 	/* Added to find the auth type on the fly at run time */
 	/* rather than with cfg to see if FT is enabled */
@@ -1340,6 +1341,14 @@ static void hdd_send_association_event(struct net_device *dev,
 							&chan_info,
 							pAdapter->device_mode);
 
+		hdd_info("Assoc: Check and enable or disable TDLS state ");
+		if ((pAdapter->device_mode == QDF_STA_MODE ||
+		     pAdapter->device_mode == QDF_P2P_CLIENT_MODE) &&
+		     !pHddCtx->concurrency_marked)
+			wlan_hdd_update_tdls_info(pAdapter,
+				pCsrRoamInfo->tdls_prohibited,
+				pCsrRoamInfo->tdls_chan_swit_prohibited);
+
 #ifdef MSM_PLATFORM
 #ifdef CONFIG_CNSS
 		/* start timer in sta/p2p_cli */
@@ -1389,16 +1398,21 @@ static void hdd_send_association_event(struct net_device *dev,
 		wlan_hdd_send_status_pkg(pAdapter, pHddStaCtx, 1, 0);
 #endif
 #ifdef FEATURE_WLAN_TDLS
-		if ((pAdapter->device_mode == QDF_STA_MODE) &&
-		    (pCsrRoamInfo)) {
-			hddLog(LOG4,
-				FL("tdls_prohibited: %d, tdls_chan_swit_prohibited: %d"),
-				pCsrRoamInfo->tdls_prohibited,
-				pCsrRoamInfo->tdls_chan_swit_prohibited);
-
-			wlan_hdd_update_tdls_info(pAdapter,
-				pCsrRoamInfo->tdls_prohibited,
-				pCsrRoamInfo->tdls_chan_swit_prohibited);
+		hdd_info("Disassoc: Check and enable or disable TDLS state ");
+		if ((pAdapter->device_mode == QDF_STA_MODE ||
+		     pAdapter->device_mode == QDF_P2P_CLIENT_MODE) &&
+		     !pHddCtx->concurrency_marked) {
+				wlan_hdd_update_tdls_info(pAdapter,
+							  true,
+							  true);
+		}
+		if (!pHddCtx->concurrency_marked) {
+			tdls_adapter = wlan_hdd_tdls_check_and_enable(
+								pHddCtx);
+			if (NULL != tdls_adapter)
+				wlan_hdd_update_tdls_info(tdls_adapter,
+							  false,
+							  false);
 		}
 #endif
 #ifdef MSM_PLATFORM
@@ -3903,12 +3917,8 @@ hdd_roam_tdls_status_update_handler(hdd_adapter_t *pAdapter,
 	case eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER:
 	{
 		/* ignore TDLS_SHOULD_DISCOVER if any concurrency detected */
-		if (((1 << QDF_STA_MODE) != pHddCtx->concurrency_mode) ||
-		    (pHddCtx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
-			hddLog(LOG2,
-				FL("concurrency detected. ignore SHOULD_DISCOVER concurrency_mode: 0x%x, active_sessions: %d"),
-				 pHddCtx->concurrency_mode,
-				 pHddCtx->no_of_active_sessions[QDF_STA_MODE]);
+		if (!cds_check_is_tdls_allowed(pAdapter->device_mode)) {
+			hdd_err("TDLS not allowed, ignore SHOULD_DISCOVER");
 			status = QDF_STATUS_E_FAILURE;
 			break;
 		}

+ 131 - 45
core/hdd/src/wlan_hdd_tdls.c

@@ -641,6 +641,24 @@ void hdd_tdls_context_init(hdd_context_t *hdd_ctx)
 {
 	mutex_init(&hdd_ctx->tdls_lock);
 	qdf_spinlock_create(&hdd_ctx->tdls_ct_spinlock);
+
+	/* initialize TDLS global context */
+	hdd_ctx->connected_peer_count = 0;
+	hdd_ctx->tdls_nss_switch_in_progress = false;
+	hdd_ctx->tdls_teardown_peers_cnt = 0;
+	hdd_ctx->tdls_scan_ctxt.magic = 0;
+	hdd_ctx->tdls_scan_ctxt.attempt = 0;
+	hdd_ctx->tdls_scan_ctxt.reject = 0;
+	hdd_ctx->tdls_scan_ctxt.scan_request = NULL;
+	hdd_ctx->tdls_external_peer_count = 0;
+	hdd_ctx->set_state_info.set_state_cnt = 0;
+	hdd_ctx->set_state_info.vdev_id = 0;
+
+	/* This flag will set  be true, only when device operates in
+	 * standalone STA mode
+	 */
+	hdd_ctx->enable_tdls_connection_tracker = false;
+	hdd_ctx->concurrency_marked = false;
 }
 
 /**
@@ -653,6 +671,9 @@ void hdd_tdls_context_init(hdd_context_t *hdd_ctx)
  */
 void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx)
 {
+	hdd_ctx->tdls_external_peer_count = 0;
+	hdd_ctx->concurrency_marked = false;
+	hdd_ctx->enable_tdls_connection_tracker = false;
 	mutex_destroy(&hdd_ctx->tdls_lock);
 	qdf_spinlock_destroy(&hdd_ctx->tdls_ct_spinlock);
 }
@@ -670,11 +691,12 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter)
 	int i;
 	uint8_t staIdx;
 	tdlsInfo_t *tInfo;
-	QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
 
 	if (NULL == pHddCtx)
 		return -EINVAL;
 
+	ENTER();
+
 	mutex_lock(&pHddCtx->tdls_lock);
 
 	if (false == pHddCtx->config->fEnableTDLSSupport) {
@@ -741,18 +763,9 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter)
 		pHddCtx->connected_peer_count = 0;
 	}
 
-	/* initialize TDLS global context */
-	pHddCtx->connected_peer_count = 0;
-	pHddCtx->tdls_nss_switch_in_progress = false;
-	pHddCtx->tdls_teardown_peers_cnt = 0;
 	sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX(pAdapter),
 					   pAdapter->sessionId, 0);
 
-	pHddCtx->tdls_scan_ctxt.magic = 0;
-	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 ||
@@ -776,11 +789,6 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter)
 	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 =
 		pHddCtx->config->fTDLSTxStatsPeriod;
@@ -864,14 +872,7 @@ int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter)
 		pHddCtx->config->tdls_peer_kickout_threshold;
 	dump_tdls_state_param_setting(tInfo);
 
-	qdf_ret_status = sme_update_fw_tdls_state(pHddCtx->hHal, tInfo, true);
-	if (QDF_STATUS_SUCCESS != qdf_ret_status) {
-		qdf_mem_free(tInfo);
-		qdf_mc_timer_destroy(&pHddTdlsCtx->peerDiscoveryTimeoutTimer);
-		qdf_mem_free(pHddTdlsCtx);
-		return -EINVAL;
-	}
-
+	EXIT();
 	return 0;
 }
 
@@ -886,8 +887,8 @@ void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter)
 	tdlsCtx_t *pHddTdlsCtx;
 	hdd_context_t *pHddCtx;
 	tdlsInfo_t *tInfo;
-	QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE;
 
+	ENTER();
 	pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
 	if (!pHddCtx) {
 		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN,
@@ -965,12 +966,6 @@ void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter)
 			tInfo->tdls_peer_kickout_threshold =
 				pHddCtx->config->tdls_peer_kickout_threshold;
 			dump_tdls_state_param_setting(tInfo);
-
-			qdf_ret_status =
-				sme_update_fw_tdls_state(pHddCtx->hHal, tInfo, false);
-			if (QDF_STATUS_SUCCESS != qdf_ret_status) {
-				qdf_mem_free(tInfo);
-			}
 		} else {
 			hddLog(QDF_TRACE_LEVEL_ERROR,
 			       "%s: qdf_mem_malloc failed for tInfo", __func__);
@@ -978,7 +973,6 @@ 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);
@@ -986,6 +980,7 @@ void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter)
 	pHddTdlsCtx = NULL;
 
 done:
+	EXIT();
 	clear_bit(TDLS_INIT_DONE, &pAdapter->event_flags);
 }
 
@@ -1859,6 +1854,31 @@ int wlan_hdd_tdls_set_params(struct net_device *dev,
 	return 0;
 }
 
+/**
+ * wlan_hdd_tdls_check_and_enable() - check system state and enable tdls
+ * @hdd_ctx: hdd context
+ *
+ * After every disassociation in the system, check whether TDLS
+ * can be enabled in the system. If TDLS possible return the
+ * corresponding hdd adapter to enable TDLS.
+ *
+ * Return: hdd adapter pointer or NULL.
+ */
+hdd_adapter_t *wlan_hdd_tdls_check_and_enable(hdd_context_t *hdd_ctx)
+{
+	if (cds_get_connection_count() > 1)
+		return NULL;
+	if (cds_mode_specific_connection_count(QDF_STA_MODE,
+					       NULL) == 1)
+		return hdd_get_adapter(hdd_ctx,
+				       QDF_STA_MODE);
+	if (cds_mode_specific_connection_count(QDF_P2P_CLIENT_MODE,
+					       NULL) == 1)
+		return hdd_get_adapter(hdd_ctx,
+				       QDF_P2P_CLIENT_MODE);
+	return NULL;
+}
+
 /**
  * wlan_hdd_update_tdls_info - update tdls status info
  * @adapter: ptr to device adapter.
@@ -1896,8 +1916,18 @@ void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter, bool tdls_prohibited,
 		return;
 	}
 
-	/* If AP indicated TDLS Prohibited then disable tdls mode */
+	hdd_info("tdls_prohibited: %d, tdls_chan_swit_prohibited: %d",
+		 tdls_prohibited, tdls_chan_swit_prohibited);
+
 	mutex_lock(&hdd_ctx->tdls_lock);
+
+	if (hdd_ctx->set_state_info.set_state_cnt == 0 &&
+	    tdls_prohibited) {
+		mutex_unlock(&hdd_ctx->tdls_lock);
+		return;
+	}
+
+	/* If AP or caller indicated TDLS Prohibited then disable tdls mode */
 	if (tdls_prohibited) {
 		hdd_ctx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED;
 	} else {
@@ -1908,15 +1938,41 @@ void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter, bool tdls_prohibited,
 		else
 			hdd_ctx->tdls_mode = eTDLS_SUPPORT_ENABLED;
 	}
-	mutex_unlock(&hdd_ctx->tdls_lock);
 	tdls_param = qdf_mem_malloc(sizeof(*tdls_param));
 	if (!tdls_param) {
+		mutex_unlock(&hdd_ctx->tdls_lock);
 		hddLog(QDF_TRACE_LEVEL_ERROR,
 			FL("memory allocation failed for tdlsParams"));
 		return;
 	}
 
-	tdls_param->vdev_id = adapter->sessionId;
+	/* If any concurrency detected, teardown all TDLS links and disable
+	 * the tdls support
+	 */
+	hdd_warn("Concurrency check in TDLS! set state cnt %d tdls_prohibited %d",
+		hdd_ctx->set_state_info.set_state_cnt, tdls_prohibited);
+
+	if (hdd_ctx->set_state_info.set_state_cnt == 1 &&
+	    !tdls_prohibited) {
+		hdd_warn("Concurrency not allowed in TDLS! set state cnt %d",
+			hdd_ctx->set_state_info.set_state_cnt);
+		if (hdd_ctx->connected_peer_count >= 1) {
+			hdd_ctx->concurrency_marked = true;
+			mutex_unlock(&hdd_ctx->tdls_lock);
+			wlan_hdd_tdls_disable_offchan_and_teardown_links(
+								hdd_ctx);
+			qdf_mem_free(tdls_param);
+			return;
+		}
+		tdls_prohibited = true;
+		hdd_ctx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED;
+		tdls_param->vdev_id = hdd_ctx->set_state_info.vdev_id;
+	} else {
+		tdls_param->vdev_id = adapter->sessionId;
+	}
+
+	mutex_unlock(&hdd_ctx->tdls_lock);
+
 	tdls_param->tdls_state = hdd_ctx->tdls_mode;
 	tdls_param->notification_interval_ms =
 	hdd_tdls_ctx->threshold_config.tx_period_t;
@@ -1966,6 +2022,20 @@ void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter, bool tdls_prohibited,
 		qdf_mem_free(tdls_param);
 		return;
 	}
+
+	mutex_lock(&hdd_ctx->tdls_lock);
+
+	if (!tdls_prohibited) {
+		hdd_ctx->set_state_info.set_state_cnt++;
+		hdd_ctx->set_state_info.vdev_id = adapter->sessionId;
+	} else {
+		hdd_ctx->set_state_info.set_state_cnt--;
+	}
+
+	hdd_info("TDLS Set state cnt %d",
+		hdd_ctx->set_state_info.set_state_cnt);
+
+	mutex_unlock(&hdd_ctx->tdls_lock);
 	return;
 }
 
@@ -2469,6 +2539,8 @@ void wlan_hdd_tdls_increment_peer_count(hdd_adapter_t *pAdapter)
 void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter)
 {
 	hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+	hdd_adapter_t *tdls_adapter;
+	uint16_t connected_peer_count;
 
 	ENTER();
 
@@ -2484,7 +2556,26 @@ void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter)
 	hddLog(LOG1, "%s: %d",
 		  __func__, pHddCtx->connected_peer_count);
 
+	connected_peer_count = pHddCtx->connected_peer_count;
+
 	mutex_unlock(&pHddCtx->tdls_lock);
+
+	if (connected_peer_count == 0 &&
+	    pHddCtx->concurrency_marked) {
+		tdls_adapter = hdd_get_adapter_by_vdev(pHddCtx,
+					pHddCtx->set_state_info.vdev_id);
+		if (tdls_adapter) {
+			wlan_hdd_update_tdls_info(tdls_adapter, true, true);
+			pHddCtx->concurrency_marked = false;
+		} else {
+			hdd_err("TDLS set state is not cleared correctly !!!");
+			pHddCtx->concurrency_marked = false;
+		}
+		tdls_adapter = wlan_hdd_tdls_check_and_enable(pHddCtx);
+		if (tdls_adapter)
+			wlan_hdd_update_tdls_info(tdls_adapter, false, false);
+	}
+
 	EXIT();
 }
 
@@ -3922,8 +4013,8 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
 	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
 
 	/*
-	 * STA should be connected and authenticated before sending
-	 * any TDLS frames
+	 * STA or P2P client should be connected and authenticated before
+	 *  sending any TDLS frames
 	 */
 	if ((eConnectionState_Associated !=
 	     hdd_sta_ctx->conn_info.connState) ||
@@ -3934,17 +4025,12 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
 		return -EAGAIN;
 	}
 
-	/* If any concurrency is detected */
-	if (((1 << QDF_STA_MODE) != pHddCtx->concurrency_mode) ||
-	    (pHddCtx->no_of_active_sessions[QDF_STA_MODE] > 1)) {
-		QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_HIGH,
-			  "%s: Multiple STA OR Concurrency detected. Ignore TDLS MGMT frame. action_code=%d, concurrency_mode: 0x%x, active_sessions: %d",
-			  __func__,
-			  action_code,
-			  pHddCtx->concurrency_mode,
-			  pHddCtx->no_of_active_sessions[QDF_STA_MODE]);
+	if (!cds_check_is_tdls_allowed(pAdapter->device_mode)) {
+		hdd_err("TDLS not allowed, reject TDLS MGMT, action_code=%d",
+			action_code);
 		return -EPERM;
 	}
+
 	/* other than teardown frame, mgmt frames are not sent if disabled */
 	if (SIR_MAC_TDLS_TEARDOWN != action_code) {
 		/* if tdls_mode is disabled to respond to peer's request */