TDLS: TDLS Scan Coexistence Implementation

This commit introduces TDLS Link and Scan
Coexistence functionality.
Scan coexistence on the TDLS Link is supported
provided a single TDLS session is present, DUT
is not Buffer STA capable and the TDLS peer is
Buffer Sta capable.
This capability shall be enabled based on the
gEnableTDLSScanCoexistence parameter.

CRs-Fixed: 668619
Change-Id: I6dad95ce4f453d774b4f6bea99cccca46b95aa5f
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index 2b4fe94..4dea6d5 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -1832,6 +1832,11 @@
 #define CFG_TDLS_WMM_MODE_ENABLE_MIN                 (0)
 #define CFG_TDLS_WMM_MODE_ENABLE_MAX                 (1)
 #define CFG_TDLS_WMM_MODE_ENABLE_DEFAULT             (0)
+
+#define CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE            "gEnableTDLSScanCoexistence"
+#define CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE_MIN        (0)
+#define CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE_MAX        (1)
+#define CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE_DEFAULT    (0)
 #endif
 
 #ifdef WLAN_ACTIVEMODE_OFFLOAD_FEATURE
@@ -2559,6 +2564,7 @@
    v_BOOL_t                    fTDLSExternalControl;
    v_U32_t                     fEnableTDLSOffChannel;
    v_U32_t                     fEnableTDLSWmmMode;
+   v_BOOL_t                    fEnableTDLSScanCoexSupport;
 #endif
    v_U32_t                     enableLpwrImgTransition;
 #ifdef WLAN_SOFTAP_VSTA_FEATURE
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index de5644c..72b546b 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -1288,6 +1288,7 @@
     vos_timer_t    tx_rx_trafficTmr;
     v_U8_t         drvr_miracast;
     v_U8_t         issplitscan_enabled;
+    v_U8_t         isTdlsScanCoexistence;
 
     /* VHT80 allowed*/
     v_BOOL_t isVHT80Allowed;
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index dec97de..c43697f 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -2531,6 +2531,13 @@
               CFG_TDLS_WMM_MODE_ENABLE_DEFAULT,
               CFG_TDLS_WMM_MODE_ENABLE_MIN,
               CFG_TDLS_WMM_MODE_ENABLE_MAX ),
+
+REG_VARIABLE( CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE, WLAN_PARAM_Integer,
+              hdd_config_t, fEnableTDLSScanCoexSupport,
+              VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+              CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE_DEFAULT,
+              CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE_MIN,
+              CFG_TDLS_SCAN_COEX_SUPPORT_ENABLE_MAX ),
 #endif
 
 #ifdef WLAN_SOFTAP_VSTA_FEATURE
@@ -4591,6 +4598,16 @@
       fStatus = FALSE;
       hddLog(LOGE, "Could not pass on WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK to CCM");
    }
+
+   if (TRUE == pConfig->fEnableTDLSScanCoexSupport)
+   {
+      /* TDLSScanCoexistance feature is supported when the DUT acts as only
+       * the Sleep STA and hence explicitly disable the BufferSta capability
+       * on the DUT. DUT's Buffer STA capability is explicitly disabled to
+       * ensure that the TDLS peer shall not go to TDLS power save mode.
+       */
+      pConfig->fEnableTDLSBufferSta = FALSE;
+   }
    if (ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_TDLS_BUF_STA_ENABLED,
                     pConfig->fEnableTDLSBufferSta, NULL,
                     eANI_BOOLEAN_FALSE) == eHAL_STATUS_FAILURE)
diff --git a/CORE/HDD/src/wlan_hdd_tdls.c b/CORE/HDD/src/wlan_hdd_tdls.c
index 0e2da14..75e0ddd 100644
--- a/CORE/HDD/src/wlan_hdd_tdls.c
+++ b/CORE/HDD/src/wlan_hdd_tdls.c
@@ -1514,6 +1514,17 @@
     curr_peer->link_status = eTDLS_LINK_IDLE;
     curr_peer->staId = 0;
 
+    /* Throughput Monitor shall disable the split scan when
+     * TDLS scan coexistance is disabled.At this point of time
+     * since TDLS scan coexistance is not meeting the criteria
+     * to be operational, explicitly make it false to enable
+     * throughput monitor takes the control of split scan.
+     */
+    if (pHddCtx->isTdlsScanCoexistence == TRUE)
+    {
+        pHddCtx->isTdlsScanCoexistence = FALSE;
+    }
+
     if(eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode) {
         vos_timer_stop( &curr_peer->peerIdleTimer );
     }
@@ -1600,6 +1611,44 @@
     return pHddCtx->connected_peer_count;
 }
 
+hddTdlsPeer_t *wlan_hdd_tdls_get_first_connected_peer(hdd_adapter_t *pAdapter)
+{
+    int i;
+    struct list_head *head;
+    struct list_head *pos;
+    hddTdlsPeer_t *curr_peer = NULL;
+    tdlsCtx_t *pHddTdlsCtx;
+    hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+
+    if(0 != (wlan_hdd_validate_context(pHddCtx)))
+    {
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                 FL("pHddCtx is not valid"));
+        return NULL;
+    }
+
+    mutex_lock(&pHddCtx->tdls_lock);
+    pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
+    if (NULL == pHddTdlsCtx) {
+        mutex_unlock(&pHddCtx->tdls_lock);
+        return NULL;
+    }
+    for (i = 0; i < 256; i++) {
+        head = &pHddTdlsCtx->peer_list[i];
+
+        list_for_each(pos, head) {
+            curr_peer= list_entry (pos, hddTdlsPeer_t, node);
+            if (curr_peer)
+            {
+               mutex_unlock(&pHddCtx->tdls_lock);
+               return curr_peer;
+            }
+        }
+    }
+    mutex_unlock(&pHddCtx->tdls_lock);
+    return NULL;
+}
+
 int wlan_hdd_tdls_get_all_peers(hdd_adapter_t *pAdapter, char *buf, int buflen)
 {
     int i;
@@ -2212,8 +2261,9 @@
 {
     hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
     u16 connectedTdlsPeers;
-    hddTdlsPeer_t *curr_peer;
+    hddTdlsPeer_t *curr_peer, *connected_peer;
     unsigned long delay;
+    hdd_config_t  *cfg_param = pHddCtx->cfg_ini;
 
     if(0 != (wlan_hdd_validate_context(pHddCtx)))
     {
@@ -2278,6 +2328,66 @@
         wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, FALSE);
         /* indicate the teardown all connected to peer */
         connectedTdlsPeers = wlan_hdd_tdlsConnectedPeers(pAdapter);
+
+        /* check the TDLS link and Scan coexistance Capability */
+        if ( (TRUE == pHddCtx->cfg_ini->fEnableTDLSScanCoexSupport) &&
+             (TRUE == sme_IsFeatureSupportedByFW(TDLS_SCAN_COEXISTENCE)) &&
+             (connectedTdlsPeers == 1) )
+        {
+            /* get connected peer information */
+            connected_peer = wlan_hdd_tdls_get_first_connected_peer(pAdapter);
+            if (NULL == connected_peer) {
+                VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+                    "%s: Invalid connected_peer, Continue Scanning", __func__);
+                /* scan should continue */
+                return 1;
+            }
+            VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                      ("%s: TDLS Scan Co-exist supported connectedTdlsPeers =%d buffersta =%d"),
+                       __func__,connectedTdlsPeers,connected_peer->isBufSta);
+
+            if (connected_peer->isBufSta)
+            {
+                 pHddCtx->isTdlsScanCoexistence = TRUE;
+                 if ((cfg_param->dynSplitscan) && (!pHddCtx->issplitscan_enabled))
+                 {
+                           pHddCtx->issplitscan_enabled = TRUE;
+                           sme_enable_disable_split_scan(
+                                               WLAN_HDD_GET_HAL_CTX(pAdapter),
+                                               cfg_param->nNumStaChanCombinedConc,
+                                               cfg_param->nNumP2PChanCombinedConc);
+                 }
+                 VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                           ("%s:%d TDLS Scan Co-exist supported splitscan_enabled =%d "),
+                            __func__, __LINE__, pHddCtx->issplitscan_enabled);
+                 return 1;
+            }
+
+        }
+        else
+        {
+            /* Throughput Monitor shall disable the split scan when
+             * TDLS scan coexistance is disabled.At this point of time
+             * since TDLS scan coexistance is not meeting the criteria
+             * to be operational, explicitly make it false to enable
+             * throughput monitor takes the control of split scan.
+             */
+            pHddCtx->isTdlsScanCoexistence = FALSE;
+        }
+        VOS_TRACE(VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
+                  ("%s: TDLS Scan Co-exist not supported connectedTdlsPeers =%d"
+                   " TDLSScanCoexSupport param =%d TDLS_SCAN_COEXISTENCE =%d"),
+                    __func__, connectedTdlsPeers,
+                    pHddCtx->cfg_ini->fEnableTDLSScanCoexSupport,
+                    sme_IsFeatureSupportedByFW(TDLS_SCAN_COEXISTENCE));
+
+        /* fall back to the implementation of teardown the peers on the scan
+         * when the number of connected peers are more than one. TDLS Scan
+         * coexistance feature is exercised only when a single peer is
+         * connected and the DUT shall not advertize the Buffer Sta capability,
+         * so that the peer shall not go to the TDLS power save
+         */
+
         if (connectedTdlsPeers)
         {
             tANI_U8 staIdx;
@@ -2380,6 +2490,8 @@
                                            hddTdlsPeer_t *curr_peer,
                                            tANI_U16 reason)
 {
+    hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+
     if (NULL == pAdapter || NULL == curr_peer)
     {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
@@ -2390,6 +2502,17 @@
     if (eTDLS_LINK_CONNECTED != curr_peer->link_status)
         return;
 
+    /* Throughput Monitor shall disable the split scan when
+     * TDLS scan coexistance is disabled.At this point of time
+     * since TDLS scan coexistance is not meeting the criteria
+     * to be operational, explicitly make it false to enable
+     * throughput monitor takes the control of split scan.
+     */
+    if (pHddCtx->isTdlsScanCoexistence == TRUE)
+    {
+        pHddCtx->isTdlsScanCoexistence = FALSE;
+    }
+
     wlan_hdd_tdls_set_peer_link_status(curr_peer, eTDLS_LINK_TEARING);
     cfg80211_tdls_oper_request(pAdapter->dev,
                                curr_peer->peerMac,
diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c
index a2e6fae..8ee6f80 100644
--- a/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -1916,7 +1916,11 @@
         pAdapterNode = pNext;
     }
 
-    if (pHddCtx->issplitscan_enabled)
+    /* If TDLSScanCoexistence is enabled, then the TDLS module shall take care
+     * of disabling the split scan and thus do not disable the same when the
+     * low TXRX condition is met.
+     */
+    if ((pHddCtx->isTdlsScanCoexistence == FALSE) && (pHddCtx->issplitscan_enabled))
     {
        VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
                         "%s: Disable split scan", __func__);
diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h
index f7090d3..6002b4a 100644
--- a/CORE/MAC/src/include/sirParams.h
+++ b/CORE/MAC/src/include/sirParams.h
@@ -102,6 +102,9 @@
    UPDATE_CHANNEL_LIST    = 35,
    WLAN_MCADDR_FLT        = 36,
    WLAN_CH144             = 37,
+#ifdef FEATURE_WLAN_TDLS
+   TDLS_SCAN_COEXISTENCE  = 39,
+#endif
 
    //MAX_FEATURE_SUPPORTED = 128
 } placeHolderInCapBitmap;
diff --git a/CORE/WDI/CP/src/wlan_qct_wdi.c b/CORE/WDI/CP/src/wlan_qct_wdi.c
index 0efc00b..a839f05 100644
--- a/CORE/WDI/CP/src/wlan_qct_wdi.c
+++ b/CORE/WDI/CP/src/wlan_qct_wdi.c
@@ -167,6 +167,14 @@
     ,CH_SWITCH_V1                   //33
     ,HT40_OBSS_SCAN                 //34
     ,UPDATE_CHANNEL_LIST            //35
+    ,FEATURE_NOT_SUPPORTED          //36
+    ,FEATURE_NOT_SUPPORTED          //37
+    ,FEATURE_NOT_SUPPORTED          //38
+#ifdef FEATURE_WLAN_TDLS
+    ,TDLS_SCAN_COEXISTENCE          //39
+#else
+    ,FEATURE_NOT_SUPPORTED          //39
+#endif
 
 };
 
@@ -1215,6 +1223,9 @@
                                               "%s", "EXTENDED_NSOFFLOAD_SLOT");
                           pCapStr += strlen("EXTENDED_NSOFFLOAD_SLOT");
                           break;
+                     case TDLS_SCAN_COEXISTENCE: snprintf(pCapStr, sizeof("TDLS_SCAN_COEXISTENCE"), "%s", "TDLS_SCAN_COEXISTENCE");
+                          pCapStr += strlen("TDLS_SCAN_COEXISTENCE");
+                          break;
 
                  }
                  *pCapStr++ = ',';