Fix for the crash in wlan_hdd_tdls_update_peer_cb

Prevent the start of the update peer timer with mutex lock when
we enable implicit trigger or we connect to an AP.
Enable the rescheduling of scan till all the TDLS link torn down
when there is already some TDLS link.
Check the device mode with WLAN_HDD_INFRA_STATION or
WLAN_HDD_P2P_CLIENT while going through the adapters in function
wlan_hdd_tdls_set_mode.

Change-Id: I496ecf90a55efb8e6dbb865e8346f86cb1675af3
CRs-Fixed: 464577, 466452
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index a8070f9..678baba 100755
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -4196,6 +4196,10 @@
      * to process the connect request to AP */
     hdd_allow_suspend_timeout(100);
 
+#ifdef FEATURE_WLAN_TDLS
+    wlan_hdd_tdls_scan_done_callback(pAdapter);
+#endif
+
     EXIT();
     return 0;
 }
@@ -4357,28 +4361,21 @@
         return -EBUSY;
     }
 #ifdef FEATURE_WLAN_TDLS
-    if (wlan_hdd_tdlsConnectedPeers(pAdapter))
-    {
-        tANI_U8 staIdx;
-
-        for (staIdx = 0; staIdx < HDD_MAX_NUM_TDLS_STA; staIdx++)
-        {
-            if (pHddCtx->tdlsConnInfo[staIdx].staId)
-            {
-                VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                          ("scan: indicate TDLS teadown (staId %d)"), pHddCtx->tdlsConnInfo[staIdx].staId);
-            }
-#ifdef CONFIG_TDLS_IMPLICIT
-            cfg80211_tdls_oper_request(pAdapter->dev,
-                                       pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes,
-                                       NL80211_TDLS_TEARDOWN,
-                                       eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON,
-                                       GFP_KERNEL);
+    /* if tdls disagree scan right now, return immediately.
+       tdls will schedule the scan when scan is allowed. (return SUCCESS)
+       or will reject the scan if any TDLS is in progress. (return -EBUSY)
+    */
+    status = wlan_hdd_tdls_scan_callback (pAdapter,
+                                          wiphy,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0))
+                                          dev,
 #endif
-        }
-        return -EBUSY;
+                                          request);
+    if(status <= 0)
+    {
+        hddLog(VOS_TRACE_LEVEL_INFO, "%s: TDLS Pending %d", __func__, status);
+        return status;
     }
-
 #endif
 
     if (mutex_lock_interruptible(&pHddCtx->tmInfo.tmOperationLock))
diff --git a/CORE/HDD/src/wlan_hdd_tdls.c b/CORE/HDD/src/wlan_hdd_tdls.c
index ca99712..08fefdf 100644
--- a/CORE/HDD/src/wlan_hdd_tdls.c
+++ b/CORE/HDD/src/wlan_hdd_tdls.c
@@ -210,10 +210,10 @@
     }
     discover_expiry = pHddTdlsCtx->threshold_config.discovery_period_t;
 
-    mutex_unlock(&tdls_lock);
-
     wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx);
 
+    mutex_unlock(&tdls_lock);
+
     /* Commenting out the following function as it was introducing
      * a race condition when pHddTdlsCtx is deleted. Also , this
      * function is consuming more time in the timer callback.
@@ -580,13 +580,6 @@
     else
     {
         pHddCtx->tdls_mode = eTDLS_SUPPORT_ENABLED;
-#ifdef FEATURE_WLAN_TDLS_INTERNAL
-        vos_timer_start( &pHddTdlsCtx->peerDiscoverTimer,
-                   pHddTdlsCtx->threshold_config.discovery_period_t );
-#endif
-
-        vos_timer_start( &pHddTdlsCtx->peerUpdateTimer,
-                            pHddTdlsCtx->threshold_config.tx_period_t );
     }
 
     return 0;
@@ -1117,6 +1110,7 @@
     return 0;
 }
 
+/* Caller has to take the lock before calling this function */
 static void wlan_tdd_tdls_reset_tx_rx(tdlsCtx_t *pHddTdlsCtx)
 {
     int i;
@@ -1124,18 +1118,6 @@
     hddTdlsPeer_t *tmp;
     struct list_head *pos, *q;
 
-    if (mutex_lock_interruptible(&tdls_lock))
-    {
-        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-        "%s: unable to lock list", __func__);
-        return ;
-    }
-    if ( NULL == pHddTdlsCtx )
-    {
-        mutex_unlock(&tdls_lock);
-        return ;
-    }
-
     for (i = 0; i < 256; i++) {
         head = &pHddTdlsCtx->peer_list[i];
         list_for_each_safe (pos, q, head) {
@@ -1144,11 +1126,11 @@
             tmp->rx_pkt = 0;
         }
     }
-    mutex_unlock(&tdls_lock);
 
     return ;
 }
 
+/* Caller has to take the lock before calling this function */
 static tANI_S32 wlan_hdd_tdls_peer_reset_discovery_processed(tdlsCtx_t *pHddTdlsCtx)
 {
     int i;
@@ -1156,18 +1138,6 @@
     hddTdlsPeer_t *tmp;
     struct list_head *pos, *q;
 
-    if (mutex_lock_interruptible(&tdls_lock))
-    {
-        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-        "%s: unable to lock list", __func__);
-        return -1;
-    }
-    if ( NULL == pHddTdlsCtx )
-    {
-        mutex_unlock(&tdls_lock);
-        return -1;
-    }
-
     pHddTdlsCtx->discovery_peer_cnt = 0;
 
     for (i = 0; i < 256; i++) {
@@ -1177,7 +1147,6 @@
             tmp->discovery_processed = 0;
         }
     }
-    mutex_unlock(&tdls_lock);
 
     return 0;
 }
@@ -1276,7 +1245,18 @@
     hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
     tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
 
-    if (NULL == pHddTdlsCtx) return;
+    if (mutex_lock_interruptible(&tdls_lock))
+    {
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                 "%s: unable to lock list", __func__);
+       return;
+    }
+
+    if (NULL == pHddCtx || NULL == pHddTdlsCtx)
+    {
+        mutex_unlock(&tdls_lock);
+        return;
+    }
 
     VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
     "%s, update %d discover %d", __func__,
@@ -1296,6 +1276,7 @@
        vos_timer_start(&pHddTdlsCtx->peerUpdateTimer,
                        pHddTdlsCtx->threshold_config.tx_period_t);
     }
+    mutex_unlock(&tdls_lock);
 
 }
 
@@ -1456,16 +1437,7 @@
 
 static void wlan_hdd_tdls_implicit_disable(tdlsCtx_t *pHddTdlsCtx)
 {
-    if (mutex_lock_interruptible(&tdls_lock))
-    {
-       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                 "%s: unable to lock list", __func__);
-       return;
-    }
-
     wlan_hdd_tdls_timers_stop(pHddTdlsCtx);
-
-    mutex_unlock(&tdls_lock);
 }
 
 static void wlan_hdd_tdls_implicit_enable(tdlsCtx_t *pHddTdlsCtx)
@@ -1494,11 +1466,23 @@
 
     VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,"%s mode %d", __func__, (int)tdls_mode);
 
-    if (NULL == pHddCtx) return;
+    if (mutex_lock_interruptible(&tdls_lock))
+    {
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                 "%s: unable to lock list", __func__);
+       return;
+    }
+
+    if (NULL == pHddCtx)
+    {
+        mutex_unlock(&tdls_lock);
+        return;
+    }
 
     if (pHddCtx->tdls_mode == tdls_mode)
     {
         hddLog(VOS_TRACE_LEVEL_ERROR, "%s already in mode %d", __func__, (int)tdls_mode);
+        mutex_unlock(&tdls_lock);
         return;
     }
 
@@ -1507,20 +1491,25 @@
     while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
     {
        pAdapter = pAdapterNode->pAdapter;
-       pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
-       if (NULL != pHddTdlsCtx)
+       if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
+           (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode))
        {
-           if(eTDLS_SUPPORT_ENABLED == tdls_mode)
-                wlan_hdd_tdls_implicit_enable(pHddTdlsCtx);
-           else if((eTDLS_SUPPORT_DISABLED == tdls_mode) ||
-                   (eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == tdls_mode))
-                wlan_hdd_tdls_implicit_disable(pHddTdlsCtx);
+           pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);
+           if (NULL != pHddTdlsCtx)
+           {
+               if(eTDLS_SUPPORT_ENABLED == tdls_mode)
+                   wlan_hdd_tdls_implicit_enable(pHddTdlsCtx);
+               else if((eTDLS_SUPPORT_DISABLED == tdls_mode) ||
+                       (eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == tdls_mode))
+                   wlan_hdd_tdls_implicit_disable(pHddTdlsCtx);
+           }
        }
        status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
        pAdapterNode = pNext;
     }
     pHddCtx->tdls_mode_last = pHddCtx->tdls_mode;
     pHddCtx->tdls_mode = tdls_mode;
+    mutex_unlock(&tdls_lock);
 }
 
 void wlan_hdd_tdls_pre_setup(tdlsCtx_t *pHddTdlsCtx,