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;
}