Fix to enhance the mutex lock acquire

Multiple mutex locks in discover_peer_cb results in failure to
synchronize with tdls_exit.
Acquire the mutex locks to prevent the preemption for the desired
atomic operations.

Change-Id: I8a8cdbc384db03117cf9ff845192464c3e1f3ee5
CRs-fixed: 454901
diff --git a/CORE/HDD/inc/wlan_hdd_tdls.h b/CORE/HDD/inc/wlan_hdd_tdls.h
index 3b4672d..6f88077 100644
--- a/CORE/HDD/inc/wlan_hdd_tdls.h
+++ b/CORE/HDD/inc/wlan_hdd_tdls.h
@@ -113,7 +113,6 @@
 
 typedef struct {
     struct list_head peer_list[256];
-    struct mutex lock;
     struct net_device *dev;
     vos_timer_t     peerDiscoverTimer;
     vos_timer_t     peerUpdateTimer;
@@ -127,10 +126,6 @@
 
 void wlan_hdd_tdls_exit(void);
 
-void wlan_hdd_tdls_timers_stop(void);
-
-void wlan_hdd_tdls_timers_destroy(void);
-
 void wlan_hdd_tdls_extract_da(struct sk_buff *skb, u8 *mac);
 
 void wlan_hdd_tdls_extract_sa(struct sk_buff *skb, u8 *mac);
diff --git a/CORE/HDD/src/wlan_hdd_tdls.c b/CORE/HDD/src/wlan_hdd_tdls.c
index f222593..7769d41 100644
--- a/CORE/HDD/src/wlan_hdd_tdls.c
+++ b/CORE/HDD/src/wlan_hdd_tdls.c
@@ -40,8 +40,10 @@
 
 
 static tdlsCtx_t *pHddTdlsCtx;
+static struct mutex tdls_lock;
 static tANI_S32 wlan_hdd_get_tdls_discovery_peer_cnt(void);
 static tANI_S32 wlan_hdd_tdls_peer_reset_discovery_processed(void);
+static void wlan_hdd_tdls_timers_destroy(void);
 
 #ifndef WLAN_FEATURE_TDLS_DEBUG
 #define TDLS_LOG_LEVEL VOS_TRACE_LEVEL_INFO
@@ -60,6 +62,52 @@
     return key;
 }
 
+static v_VOID_t wlan_hdd_tdls_start_peer_discover_timer(tANI_BOOLEAN mutexLock, v_U32_t discoveryExpiry)
+{
+    hdd_adapter_t *pAdapter;
+    hdd_context_t *pHddCtx;
+    hdd_station_ctx_t *pHddStaCtx;
+
+
+    if ( mutexLock )
+    {
+        if (mutex_lock_interruptible(&tdls_lock))
+        {
+           VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                     "%s: unable to lock list: %d", __func__, __LINE__);
+           return;
+        }
+    }
+    if (NULL == pHddTdlsCtx)
+    {
+        if ( mutexLock )
+            mutex_unlock(&tdls_lock);
+        return;
+    }
+
+    pAdapter = WLAN_HDD_GET_PRIV_PTR(pHddTdlsCtx->dev);
+
+    if (NULL == pAdapter)
+    {
+        if ( mutexLock )
+            mutex_unlock(&tdls_lock);
+        return;
+    }
+
+    pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+    pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
+    if (hdd_connIsConnected( pHddStaCtx ))
+    {
+        vos_timer_start(&pHddTdlsCtx->peerDiscoverTimer, discoveryExpiry);
+        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "beacon rssi: %d",
+                   pHddTdlsCtx->ap_rssi);
+    }
+    if ( mutexLock )
+        mutex_unlock(&tdls_lock);
+
+    return;
+}
+
 static v_VOID_t wlan_hdd_tdls_discover_peer_cb( v_PVOID_t userData )
 {
     int i;
@@ -71,13 +119,28 @@
     hdd_station_ctx_t *pHddStaCtx;
     int discover_req_sent = 0;
     v_U32_t discover_expiry = TDLS_SUB_DISCOVERY_PERIOD;
+    tANI_BOOLEAN doMutexLock = eANI_BOOLEAN_TRUE;
 
+    if (mutex_lock_interruptible(&tdls_lock))
+    {
+       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                 "%s: unable to lock list : %d", __func__, __LINE__);
+       return;
+    }
 
-    if (NULL == pHddTdlsCtx) return;
+    if (NULL == pHddTdlsCtx)
+    {
+        mutex_unlock(&tdls_lock);
+        return;
+    }
 
     pAdapter = WLAN_HDD_GET_PRIV_PTR(pHddTdlsCtx->dev);
 
-    if (NULL == pAdapter) return;
+    if (NULL == pAdapter)
+    {
+        mutex_unlock(&tdls_lock);
+        return;
+    }
 
     pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
     pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
@@ -87,19 +150,6 @@
     if (0 == pHddTdlsCtx->discovery_peer_cnt)
         pHddTdlsCtx->discovery_peer_cnt = wlan_hdd_get_tdls_discovery_peer_cnt();
 
-    if (-1 == pHddTdlsCtx->discovery_peer_cnt)  {
-        discover_expiry = pHddTdlsCtx->threshold_config.discovery_period_t;
-
-        goto done;
-    }
-
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
-    {
-       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                 "%s: unable to lock list : %d", __func__, __LINE__);
-       return;
-    }
-
     for (i = 0; i < 256; i++) {
         head = &pHddTdlsCtx->peer_list[i];
 
@@ -154,38 +204,37 @@
         }
     }
 exit_loop:
-    mutex_unlock(&pHddTdlsCtx->lock);
 
     if (0 != pHddTdlsCtx->discovery_peer_cnt) {
         VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,
                   "discovery_peer_cnt is %d , Starting SUB_DISCOVERY_TIMER",
                   pHddTdlsCtx->discovery_peer_cnt);
         discover_expiry = TDLS_SUB_DISCOVERY_PERIOD;
+        doMutexLock = eANI_BOOLEAN_FALSE;
         goto done;
     }
-
     discover_expiry = pHddTdlsCtx->threshold_config.discovery_period_t;
 
+    mutex_unlock(&tdls_lock);
+
     wlan_hdd_tdls_peer_reset_discovery_processed();
 
-    wlan_hdd_get_rssi(pAdapter, &pHddTdlsCtx->ap_rssi);
+    /* 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.
+     * RSSI based trigger needs to revisit this part of the code.
+     */
+
+    /*
+     * wlan_hdd_get_rssi(pAdapter, &pHddTdlsCtx->ap_rssi);
+     */
 
 done:
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
-    {
-       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                 "%s: unable to lock list: %d", __func__, __LINE__);
-       return;
-    }
+    wlan_hdd_tdls_start_peer_discover_timer(doMutexLock, discover_expiry);
 
-    if (hdd_connIsConnected( pHddStaCtx ))
-    {
-        vos_timer_start(&pHddTdlsCtx->peerDiscoverTimer, discover_expiry);
-        VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "beacon rssi: %d",
-                   pHddTdlsCtx->ap_rssi);
-    }
-    mutex_unlock(&pHddTdlsCtx->lock);
-
+    if ( !doMutexLock )
+        mutex_unlock(&tdls_lock);
+    return;
 }
 
 static v_VOID_t wlan_hdd_tdls_update_peer_cb( v_PVOID_t userData )
@@ -195,15 +244,20 @@
     struct list_head *pos;
     hddTdlsPeer_t *curr_peer;
 
-    if (NULL == pHddTdlsCtx) return;
 
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
+    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];
 
@@ -351,7 +405,7 @@
 
     vos_timer_start( &pHddTdlsCtx->peerUpdateTimer,
                         pHddTdlsCtx->threshold_config.tx_period_t );
-    mutex_unlock(&pHddTdlsCtx->lock);
+    mutex_unlock(&tdls_lock);
 }
 
 static v_VOID_t wlan_hdd_tdls_idle_cb( v_PVOID_t userData )
@@ -364,7 +418,7 @@
                "%s: Tx/Rx Idle " MAC_ADDRESS_STR " trigger teardown",
                __func__,
                MAC_ADDR_ARRAY(curr_peer->peerMac));
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
+    if (mutex_lock_interruptible(&tdls_lock))
     {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                  "%s: unable to lock list", __func__);
@@ -376,7 +430,7 @@
                                NL80211_TDLS_TEARDOWN,
                                eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON,
                                GFP_KERNEL);
-    mutex_unlock(&pHddTdlsCtx->lock);
+    mutex_unlock(&tdls_lock);
 #endif
 }
 
@@ -389,12 +443,6 @@
 
     if (NULL == pHddTdlsCtx) return;
 
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
-    {
-       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                 "%s: unable to lock list", __func__);
-       return;
-    }
 
     for (i = 0; i < 256; i++) {
         head = &pHddTdlsCtx->peer_list[i];
@@ -404,8 +452,6 @@
             vos_mem_free(tmp);
         }
     }
-    mutex_unlock(&pHddTdlsCtx->lock);
-
 }
 
 static int wlan_hdd_tdls_core_init(struct net_device *dev, tdls_config_params_t *config)
@@ -450,7 +496,7 @@
                 sizeof(tdls_config_params_t));
         }
 
-        mutex_init(&pHddTdlsCtx->lock);
+        mutex_init(&tdls_lock);
 
         for (i = 0; i < 256; i++)
         {
@@ -506,8 +552,15 @@
 
 void wlan_hdd_tdls_exit()
 {
+    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);
         hddLog(VOS_TRACE_LEVEL_WARN, "%s TDLS not enabled, exiting!", __func__);
         return;
     }
@@ -519,10 +572,11 @@
 
     vos_mem_free(pHddTdlsCtx);
     pHddTdlsCtx = NULL;
+    mutex_unlock(&tdls_lock);
 }
 
 /* stop all the tdls timers running */
-void wlan_hdd_tdls_timers_stop(void)
+static void wlan_hdd_tdls_timers_stop(void)
 {
     int i;
     struct list_head *head;
@@ -532,12 +586,6 @@
     vos_timer_stop(&pHddTdlsCtx->peerDiscoverTimer);
     vos_timer_stop(&pHddTdlsCtx->peerUpdateTimer);
 
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
-    {
-       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                 "%s: unable to lock list", __func__);
-       return;
-    }
 
     for (i = 0; i < 256; i++)
     {
@@ -553,11 +601,10 @@
             vos_timer_stop ( &curr_peer->peerIdleTimer );
         }
     }
-    mutex_unlock(&pHddTdlsCtx->lock);
 }
 
 /* destroy all the tdls timers running */
-void wlan_hdd_tdls_timers_destroy(void)
+static void wlan_hdd_tdls_timers_destroy(void)
 {
     int i;
     struct list_head *head;
@@ -569,12 +616,6 @@
     vos_timer_stop(&pHddTdlsCtx->peerUpdateTimer);
     vos_timer_destroy(&pHddTdlsCtx->peerUpdateTimer);
 
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
-    {
-       VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                 "%s: unable to lock list", __func__);
-       return;
-    }
     for (i = 0; i < 256; i++)
     {
         head = &pHddTdlsCtx->peer_list[i];
@@ -590,7 +631,6 @@
             vos_timer_destroy ( &curr_peer->peerIdleTimer );
         }
     }
-    mutex_unlock(&pHddTdlsCtx->lock);
 }
 
 /* if mac address exist, return pointer
@@ -625,7 +665,7 @@
     key = wlan_hdd_tdls_hash_key(mac);
     head = &pHddTdlsCtx->peer_list[key];
 
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
+    if (mutex_lock_interruptible(&tdls_lock))
     {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                  "%s: unable to lock list", __func__);
@@ -650,7 +690,7 @@
     }
 
     list_add_tail(&peer->node, head);
-    mutex_unlock(&pHddTdlsCtx->lock);
+    mutex_unlock(&tdls_lock);
 
     return peer;
 }
@@ -838,31 +878,34 @@
     struct list_head *head;
     hddTdlsPeer_t *curr_peer;
 
-    if (NULL == pHddTdlsCtx)
-        return NULL;
 
-    key = wlan_hdd_tdls_hash_key(mac);
-
-    head = &pHddTdlsCtx->peer_list[key];
-
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
+    if (mutex_lock_interruptible(&tdls_lock))
     {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                  "%s: unable to lock list", __func__);
        return NULL;
     }
+    if (NULL == pHddTdlsCtx)
+    {
+        mutex_unlock(&tdls_lock);
+        return NULL;
+    }
+
+    key = wlan_hdd_tdls_hash_key(mac);
+
+    head = &pHddTdlsCtx->peer_list[key];
 
     list_for_each(pos, head) {
         curr_peer = list_entry (pos, hddTdlsPeer_t, node);
         if (!memcmp(mac, curr_peer->peerMac, 6)) {
             VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
                      "findTdlsPeer: found staId %d", curr_peer->staId);
-            mutex_unlock(&pHddTdlsCtx->lock);
+            mutex_unlock(&tdls_lock);
             return curr_peer;
         }
     }
 
-    mutex_unlock(&pHddTdlsCtx->lock);
+    mutex_unlock(&tdls_lock);
     return NULL;
 }
 
@@ -898,14 +941,17 @@
     hddTdlsPeer_t *tmp;
     struct list_head *pos, *q;
 
-    if (NULL == pHddTdlsCtx) return -1;
-
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
+    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;
 
@@ -916,7 +962,7 @@
             tmp->discovery_processed = 0;
         }
     }
-    mutex_unlock(&pHddTdlsCtx->lock);
+    mutex_unlock(&tdls_lock);
 
     return 0;
 }
@@ -929,14 +975,9 @@
     int discovery_peer_cnt=0;
     hddTdlsPeer_t *tmp;
 
-    if (NULL == pHddTdlsCtx) return -1;
-
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
-    {
-        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-        "%s: unable to lock list", __func__);
-        return -1;
-    }
+    /*
+     * This function expects the callers to acquire the Mutex.
+     */
 
     for (i = 0; i < 256; i++) {
         head = &pHddTdlsCtx->peer_list[i];
@@ -948,8 +989,6 @@
             discovery_peer_cnt++;
         }
     }
-    mutex_unlock(&pHddTdlsCtx->lock);
-
     return discovery_peer_cnt;
 }
 
@@ -969,10 +1008,6 @@
     struct list_head *pos;
     hddTdlsPeer_t *curr_peer;
 
-    if (NULL == pHddTdlsCtx) {
-        len = snprintf(buf, buflen, "TDLS not enabled\n");
-        return len;
-    }
 
     init_len = buflen;
     len = snprintf(buf, buflen, "\n%-18s%-3s%-4s%-3s%-5s\n", "MAC", "Id", "cap", "up", "RSSI");
@@ -983,12 +1018,17 @@
     buf += len;
     buflen -= len;
 
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
+    if (mutex_lock_interruptible(&tdls_lock))
     {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                  "%s: unable to lock list", __func__);
        return init_len-buflen;
     }
+    if (NULL == pHddTdlsCtx) {
+        mutex_unlock(&tdls_lock);
+        len = snprintf(buf, buflen, "TDLS not enabled\n");
+        return len;
+    }
     for (i = 0; i < 256; i++) {
         head = &pHddTdlsCtx->peer_list[i];
 
@@ -1008,7 +1048,7 @@
             buflen -= len;
         }
     }
-    mutex_unlock(&pHddTdlsCtx->lock);
+    mutex_unlock(&tdls_lock);
     return init_len-buflen;
 }
 
@@ -1036,12 +1076,26 @@
 
 void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter)
 {
-    if (NULL == pHddTdlsCtx) return;
 
     VOS_TRACE( VOS_MODULE_ID_HDD, TDLS_LOG_LEVEL,"%s", __func__);
 
+    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;
+    }
+
+
     wlan_hdd_tdls_timers_stop();
     wlan_hdd_tdls_free_list();
+
+    mutex_unlock(&tdls_lock);
 }
 
 void wlan_hdd_tdls_mgmt_completion_callback(hdd_adapter_t *pAdapter, tANI_U32 statusCode)
@@ -1096,14 +1150,17 @@
     hddTdlsPeer_t *curr_peer;
     struct list_head *pos;
 
-    if (NULL == pHddTdlsCtx) return FALSE;
-
-    if (mutex_lock_interruptible(&pHddTdlsCtx->lock))
+    if (mutex_lock_interruptible(&tdls_lock))
     {
        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                  "%s: unable to lock list", __func__);
        return FALSE;
     }
+    if (NULL == pHddTdlsCtx)
+    {
+        mutex_unlock(&tdls_lock);
+        return FALSE;
+    }
 
     for (i = 0; i < 256; i++) {
         head = &pHddTdlsCtx->peer_list[i];
@@ -1116,14 +1173,14 @@
             {
                 if (curr_peer->isTDLSInProgress)
                 {
-                  mutex_unlock(&pHddTdlsCtx->lock);
+                  mutex_unlock(&tdls_lock);
                   return TRUE;
                 }
             }
         }
     }
 
-    mutex_unlock(&pHddTdlsCtx->lock);
+    mutex_unlock(&tdls_lock);
     return FALSE;
 }