Pārlūkot izejas kodu

qcacld-3.0: Enable/Disable TDLS from different sources

qcacld-2.0 to qcacld-3.0 propagation

Currently, TDLS can be enabled/disabled by different sources
without knowledge of each other which would lead to issue
if one of the resource enable and other would disable TDLS.

Fix is to ensure that TDLS will not be enabled/disabled
until all the resources agree upon it.

Change-Id: Id8ab5ddda88fa554f2837ded3540b3c7b3afb54d
CRs-Fixed: 948121
Nitesh Shah 8 gadi atpakaļ
vecāks
revīzija
2b946fa578

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

@@ -1546,6 +1546,8 @@ struct hdd_context_s {
 	/* counters for failed suspend reasons */
 	uint32_t suspend_fail_stats[SUSPEND_FAIL_MAX_COUNT];
 	struct hdd_runtime_pm_context runtime_context;
+	/* bit map to set/reset TDLS by different sources */
+	unsigned long tdls_source_bitmap;
 };
 
 /*---------------------------------------------------------------------------

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

@@ -69,6 +69,22 @@
 
 #define TDLS_CT_MAC_MAX_TABLE_SIZE 8
 
+/**
+ * enum tdls_disable_source - TDLS disable sources
+ * @HDD_SET_TDLS_MODE_SOURCE_USER: disable from user
+ * @HDD_SET_TDLS_MODE_SOURCE_SCAN: disable during scan
+ * @HDD_SET_TDLS_MODE_SOURCE_OFFCHANNEL: disable during offchannel
+ * @HDD_SET_TDLS_MODE_SOURCE_BTC: disable during bluetooth
+ * @HDD_SET_TDLS_MODE_SOURCE_P2P: disable during p2p
+ */
+enum tdls_disable_source {
+	HDD_SET_TDLS_MODE_SOURCE_USER = 0,
+	HDD_SET_TDLS_MODE_SOURCE_SCAN,
+	HDD_SET_TDLS_MODE_SOURCE_OFFCHANNEL,
+	HDD_SET_TDLS_MODE_SOURCE_BTC,
+	HDD_SET_TDLS_MODE_SOURCE_P2P,
+};
+
 /**
  * struct tdls_config_params_t - tdls config params
  *

+ 76 - 13
core/hdd/src/wlan_hdd_tdls.c

@@ -1594,11 +1594,14 @@ static void wlan_hdd_tdls_implicit_enable(tdlsCtx_t *pHddTdlsCtx)
  * @bUpdateLast: Switch on if to set pHddCtx->tdls_mode_last to tdls_mode.
  *               If 1, set pHddCtx->tdls_mode_last to tdls_mode, otherwise
  *               set pHddCtx->tdls_mode_last to pHddCtx->tdls_mode
+ * @source: TDLS disable source enum values
  *
  * Return: Void
  */
 static void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx,
-				   eTDLSSupportMode tdls_mode, bool bUpdateLast)
+				   eTDLSSupportMode tdls_mode,
+				   bool bUpdateLast,
+				   enum tdls_disable_source source)
 {
 	hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
 	QDF_STATUS status;
@@ -1614,9 +1617,28 @@ static void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx,
 
 	mutex_lock(&pHddCtx->tdls_lock);
 
+	if (bUpdateLast)
+		pHddCtx->tdls_mode_last = tdls_mode;
+
 	if (pHddCtx->tdls_mode == tdls_mode) {
 		mutex_unlock(&pHddCtx->tdls_lock);
 		hdd_notice("already in mode %d", (int)tdls_mode);
+
+		/* TDLS is already disabled hence set source mask, return */
+		if (eTDLS_SUPPORT_DISABLED == tdls_mode) {
+			set_bit((unsigned long)source,
+				&pHddCtx->tdls_source_bitmap);
+			hdd_notice("set source mask:%d", source);
+			return;
+		}
+
+		/* TDLS is already enabled hence clear source mask, return */
+		if (eTDLS_SUPPORT_ENABLED == tdls_mode) {
+			clear_bit((unsigned long)source,
+				  &pHddCtx->tdls_source_bitmap);
+			hdd_notice("clear source mask:%d", source);
+			return;
+		}
 		return;
 	}
 
@@ -1628,27 +1650,64 @@ static void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx,
 		if (NULL != pHddTdlsCtx) {
 			if (eTDLS_SUPPORT_ENABLED == tdls_mode ||
 			    eTDLS_SUPPORT_EXTERNAL_CONTROL == tdls_mode) {
+				clear_bit((unsigned long)source,
+					  &pHddCtx->tdls_source_bitmap);
+
+				/*
+				 * Check if any TDLS source bit is set and if
+				 * bitmap is not zero then we should not
+				 * enable TDLS
+				 */
+				if (pHddCtx->tdls_source_bitmap) {
+					mutex_unlock(&pHddCtx->tdls_lock);
+					hdd_notice("Don't enable TDLS, source"
+						"bitmap: %lu",
+						pHddCtx->tdls_source_bitmap);
+					return;
+				}
 				wlan_hdd_tdls_implicit_enable(pHddTdlsCtx);
-			} else if ((eTDLS_SUPPORT_DISABLED == tdls_mode) ||
-				   (eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY ==
-				    tdls_mode)) {
+				/* tdls implicit mode is enabled, so
+				 * enable the connection tracker
+				 */
+				pHddCtx->enable_tdls_connection_tracker =
+					true;
+			} else if (eTDLS_SUPPORT_DISABLED == tdls_mode) {
+				set_bit((unsigned long)source,
+					&pHddCtx->tdls_source_bitmap);
 				wlan_hdd_tdls_implicit_disable(pHddTdlsCtx);
-
 				/* If tdls implicit mode is disabled, then
 				 * stop the connection tracker.
 				 */
 				pHddCtx->enable_tdls_connection_tracker =
 					false;
+			} else if (eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY ==
+				   tdls_mode) {
+				clear_bit((unsigned long)source,
+					  &pHddCtx->tdls_source_bitmap);
+				wlan_hdd_tdls_implicit_disable(pHddTdlsCtx);
+				/* If tdls implicit mode is disabled, then
+				 * stop the connection tracker.
+				 */
+				pHddCtx->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 (pHddCtx->tdls_source_bitmap) {
+					mutex_unlock(&pHddCtx->tdls_lock);
+					return;
+				}
 			}
 		}
 		status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext);
 		pAdapterNode = pNext;
 	}
-	if (bUpdateLast) {
-		pHddCtx->tdls_mode_last = tdls_mode;
-	} else {
+	if (!bUpdateLast)
 		pHddCtx->tdls_mode_last = pHddCtx->tdls_mode;
-	}
+
 	pHddCtx->tdls_mode = tdls_mode;
 
 	mutex_unlock(&pHddCtx->tdls_lock);
@@ -1704,7 +1763,8 @@ int wlan_hdd_tdls_set_params(struct net_device *dev,
 		config->rssi_trigger_threshold,
 		config->rssi_teardown_threshold);
 
-	wlan_hdd_tdls_set_mode(pHddCtx, req_tdls_mode, true);
+	wlan_hdd_tdls_set_mode(pHddCtx, req_tdls_mode, true,
+			       HDD_SET_TDLS_MODE_SOURCE_USER);
 
 	tdlsParams = qdf_mem_malloc(sizeof(tdlsInfo_t));
 	if (NULL == tdlsParams) {
@@ -2772,7 +2832,8 @@ int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy,
 		 eTDLS_SUPPORT_EXTERNAL_CONTROL == pHddCtx->tdls_mode ||
 		 eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode) {
 		/* disable implicit trigger logic & tdls operatoin */
-		wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, false);
+		wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, false,
+				       HDD_SET_TDLS_MODE_SOURCE_SCAN);
 		/* indicate the teardown all connected to peer */
 		connectedTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter);
 		if (connectedTdlsPeers) {
@@ -2894,7 +2955,8 @@ void wlan_hdd_tdls_scan_done_callback(hdd_adapter_t *pAdapter)
 		hdd_notice("revert tdls mode %d",
 			   pHddCtx->tdls_mode_last);
 
-		wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, false);
+		wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, false,
+				       HDD_SET_TDLS_MODE_SOURCE_SCAN);
 	}
 	EXIT();
 }
@@ -3303,7 +3365,8 @@ __wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy,
 		hdd_err("Invalid TDLS trigger mode");
 		return -EINVAL;
 	}
-	wlan_hdd_tdls_set_mode(hdd_ctx, tdls_mode, false);
+	wlan_hdd_tdls_set_mode(hdd_ctx, tdls_mode, false,
+			HDD_SET_TDLS_MODE_SOURCE_USER);
 
 	mutex_lock(&hdd_ctx->tdls_lock);