summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CORE/HDD/inc/wlan_hdd_main.h36
-rw-r--r--CORE/HDD/src/wlan_hdd_hostapd.c19
-rw-r--r--CORE/HDD/src/wlan_hdd_main.c159
-rw-r--r--CORE/HDD/src/wlan_hdd_wext.c433
4 files changed, 404 insertions, 243 deletions
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index be1c3b19b7ff..f726493e2a60 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -219,6 +219,37 @@
#define HDD_SESSION_ID_ANY 50 //This should be same as CSR_SESSION_ID_ANY
typedef v_U8_t tWlanHddMacAddr[HDD_MAC_ADDR_LEN];
+/*
+ * Generic asynchronous request/response support
+ *
+ * Many of the APIs supported by HDD require a call to SME to
+ * perform an action or to retrieve some data. In most cases SME
+ * performs the operation asynchronously, and will execute a provided
+ * callback function when the request has completed. In order to
+ * synchronize this the HDD API allocates a context which is then
+ * passed to SME, and which is then, in turn, passed back to the
+ * callback function when the operation completes. The callback
+ * function then sets a completion variable inside the context which
+ * the HDD API is waiting on. In an ideal world the HDD API would
+ * wait forever (or at least for a long time) for the response to be
+ * received and for the completion variable to be set. However in
+ * most cases these HDD APIs are being invoked in the context of a
+ * userspace thread which has invoked either a cfg80211 API or a
+ * wireless extensions ioctl and which has taken the kernel rtnl_lock.
+ * Since this lock is used to synchronize many of the kernel tasks, we
+ * do not want to hold it for a long time. In addition we do not want
+ * to block userspace threads (such as the wpa supplicant's main
+ * thread) for an extended time. Therefore we only block for a short
+ * time waiting for the response before we timeout. This means that
+ * it is possible for the HDD API to timeout, and for the callback to
+ * be invoked afterwards. In order for the callback function to
+ * determine if the HDD API is still waiting, a magic value is also
+ * stored in the shared context. Only if the context has a valid
+ * magic will the callback routine do any work. In order to further
+ * synchronize these activities a spinlock is used so that if any HDD
+ * API timeout coincides with its callback, the operations of the two
+ * threads will be serialized.
+ */
struct statsContext
{
struct completion completion;
@@ -226,7 +257,12 @@ struct statsContext
unsigned int magic;
};
+extern spinlock_t hdd_context_lock;
+
#define STATS_CONTEXT_MAGIC 0x53544154 //STAT
+#define RSSI_CONTEXT_MAGIC 0x52535349 //RSSI
+#define POWER_CONTEXT_MAGIC 0x504F5752 //POWR
+#define SNR_CONTEXT_MAGIC 0x534E5200 //SNR
#ifdef FEATURE_WLAN_BATCH_SCAN
#define HDD_BATCH_SCAN_VERSION (17)
diff --git a/CORE/HDD/src/wlan_hdd_hostapd.c b/CORE/HDD/src/wlan_hdd_hostapd.c
index dff529a78c4a..6655a297071a 100644
--- a/CORE/HDD/src/wlan_hdd_hostapd.c
+++ b/CORE/HDD/src/wlan_hdd_hostapd.c
@@ -93,7 +93,6 @@ extern int process_wma_set_command(int sessid, int paramid,
#define IS_UP_AUTO(_ic) \
(IS_UP((_ic)->ic_dev) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
#define WE_WLAN_VERSION 1
-#define STATS_CONTEXT_MAGIC 0x53544154
#define WE_GET_STA_INFO_SIZE 30
/* WEXT limition: MAX allowed buf len for any *
* IW_PRIV_TYPE_CHAR is 2Kbytes *
@@ -3278,15 +3277,29 @@ static VOS_STATUS wlan_hdd_get_classAstats_for_station(hdd_adapter_t *pAdapter,
{
lrc = wait_for_completion_interruptible_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
- context.magic = 0;
if (lrc <= 0)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: SME %s while retrieving link speed",
__func__, (0 == lrc) ? "timeout" : "interrupt");
- msleep(50);
}
}
+
+ /* either we never sent a request, we sent a request and received a
+ response or we sent a request and timed out. if we never sent a
+ request or if we sent a request and got a response, we want to
+ clear the magic out of paranoia. if we timed out there is a
+ race condition such that the callback function could be
+ executing at the same time we are. of primary concern is if the
+ callback function had already verified the "magic" but had not
+ yet set the completion variable when a timeout occurred. we
+ serialize these activities by invalidating the magic while
+ holding a shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
return VOS_STATUS_SUCCESS;
}
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index d311e4c4b0da..c89f536ab0f3 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -153,6 +153,12 @@ static int wlan_hdd_inited;
#endif
/*
+ * spinlock for synchronizing asynchronous request/response
+ * (full description of use in wlan_hdd_main.h)
+ */
+DEFINE_SPINLOCK(hdd_context_lock);
+
+/*
* The rate at which the driver sends RESTART event to supplicant
* once the function 'vos_wlanRestart()' is called
*
@@ -4417,6 +4423,7 @@ static void hdd_GetTsmStatsCB( tAniTrafStrmMetrics tsmMetrics,
{
struct statsContext *pStatsContext = NULL;
hdd_adapter_t *pAdapter = NULL;
+
if (NULL == pContext)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
@@ -4424,23 +4431,31 @@ static void hdd_GetTsmStatsCB( tAniTrafStrmMetrics tsmMetrics,
__func__, pContext);
return;
}
- /* there is a race condition that exists between this callback function
- and the caller since the caller could time out either before or
- while this code is executing. we'll assume the timeout hasn't
- occurred, but we'll verify that right before we save our work */
+
+ /* there is a race condition that exists between this callback
+ function and the caller since the caller could time out either
+ before or while this code is executing. we use a spinlock to
+ serialize these actions */
+ spin_lock(&hdd_context_lock);
+
pStatsContext = pContext;
pAdapter = pStatsContext->pAdapter;
if ((NULL == pAdapter) || (STATS_CONTEXT_MAGIC != pStatsContext->magic))
{
/* the caller presumably timed out so there is nothing we can do */
+ spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, pAdapter [%p] magic [%08x]",
__func__, pAdapter, pStatsContext->magic);
return;
}
- /* the race is on. caller could have timed out immediately after
- we verified the magic, but if so, caller will wait a short time
- for us to copy over the tsm stats */
+
+ /* context is valid so caller is still waiting */
+
+ /* paranoia: invalidate the magic */
+ pStatsContext->magic = 0;
+
+ /* copy over the tsm stats */
pAdapter->tsmStats.UplinkPktQueueDly = tsmMetrics.UplinkPktQueueDly;
vos_mem_copy(pAdapter->tsmStats.UplinkPktQueueDlyHist,
tsmMetrics.UplinkPktQueueDlyHist,
@@ -4451,8 +4466,12 @@ static void hdd_GetTsmStatsCB( tAniTrafStrmMetrics tsmMetrics,
pAdapter->tsmStats.UplinkPktCount = tsmMetrics.UplinkPktCount;
pAdapter->tsmStats.RoamingCount = tsmMetrics.RoamingCount;
pAdapter->tsmStats.RoamingDly = tsmMetrics.RoamingDly;
- /* and notify the caller */
+
+ /* notify the caller */
complete(&pStatsContext->completion);
+
+ /* serialization is complete */
+ spin_unlock(&hdd_context_lock);
}
static VOS_STATUS hdd_get_tsm_stats(hdd_adapter_t *pAdapter,
@@ -4461,20 +4480,25 @@ static VOS_STATUS hdd_get_tsm_stats(hdd_adapter_t *pAdapter,
{
hdd_station_ctx_t *pHddStaCtx = NULL;
eHalStatus hstatus;
+ VOS_STATUS vstatus = VOS_STATUS_SUCCESS;
long lrc;
struct statsContext context;
hdd_context_t *pHddCtx = NULL;
+
if (NULL == pAdapter)
{
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: pAdapter is NULL", __func__);
return VOS_STATUS_E_FAULT;
}
+
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+
/* we are connected prepare our callback context */
init_completion(&context.completion);
context.pAdapter = pAdapter;
context.magic = STATS_CONTEXT_MAGIC;
+
/* query tsm stats */
hstatus = sme_GetTsmStats(pHddCtx->hHal, hdd_GetTsmStatsCB,
pHddStaCtx->conn_info.staId[ 0 ],
@@ -4485,43 +4509,51 @@ static VOS_STATUS hdd_get_tsm_stats(hdd_adapter_t *pAdapter,
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Unable to retrieve statistics",
__func__);
- return hstatus;
+ vstatus = VOS_STATUS_E_FAULT;
}
else
{
/* request was sent -- wait for the response */
lrc = wait_for_completion_interruptible_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
- /* either we have a response or we timed out
- either way, first invalidate our magic */
- context.magic = 0;
if (lrc <= 0)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: SME %s while retrieving statistics",
__func__, (0 == lrc) ? "timeout" : "interrupt");
- /* there is a race condition such that the callback
- function could be executing at the same time we are. of
- primary concern is if the callback function had already
- verified the "magic" but hasn't yet set the completion
- variable. Since the completion variable is on our
- stack, we'll delay just a bit to make sure the data is
- still valid if that is the case */
- msleep(50);
- return (VOS_STATUS_E_TIMEOUT);
+ vstatus = VOS_STATUS_E_TIMEOUT;
}
}
- pTsmMetrics->UplinkPktQueueDly = pAdapter->tsmStats.UplinkPktQueueDly;
- vos_mem_copy(pTsmMetrics->UplinkPktQueueDlyHist,
- pAdapter->tsmStats.UplinkPktQueueDlyHist,
- sizeof(pAdapter->tsmStats.UplinkPktQueueDlyHist)/
- sizeof(pAdapter->tsmStats.UplinkPktQueueDlyHist[0]));
- pTsmMetrics->UplinkPktTxDly = pAdapter->tsmStats.UplinkPktTxDly;
- pTsmMetrics->UplinkPktLoss = pAdapter->tsmStats.UplinkPktLoss;
- pTsmMetrics->UplinkPktCount = pAdapter->tsmStats.UplinkPktCount;
- pTsmMetrics->RoamingCount = pAdapter->tsmStats.RoamingCount;
- pTsmMetrics->RoamingDly = pAdapter->tsmStats.RoamingDly;
- return VOS_STATUS_SUCCESS;
+
+ /* either we never sent a request, we sent a request and received a
+ response or we sent a request and timed out. if we never sent a
+ request or if we sent a request and got a response, we want to
+ clear the magic out of paranoia. if we timed out there is a
+ race condition such that the callback function could be
+ executing at the same time we are. of primary concern is if the
+ callback function had already verified the "magic" but had not
+ yet set the completion variable when a timeout occurred. we
+ serialize these activities by invalidating the magic while
+ holding a shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
+ if (VOS_STATUS_SUCCESS == vstatus)
+ {
+ pTsmMetrics->UplinkPktQueueDly = pAdapter->tsmStats.UplinkPktQueueDly;
+ vos_mem_copy(pTsmMetrics->UplinkPktQueueDlyHist,
+ pAdapter->tsmStats.UplinkPktQueueDlyHist,
+ sizeof(pAdapter->tsmStats.UplinkPktQueueDlyHist)/
+ sizeof(pAdapter->tsmStats.UplinkPktQueueDlyHist[0]));
+ pTsmMetrics->UplinkPktTxDly = pAdapter->tsmStats.UplinkPktTxDly;
+ pTsmMetrics->UplinkPktLoss = pAdapter->tsmStats.UplinkPktLoss;
+ pTsmMetrics->UplinkPktCount = pAdapter->tsmStats.UplinkPktCount;
+ pTsmMetrics->RoamingCount = pAdapter->tsmStats.RoamingCount;
+ pTsmMetrics->RoamingDly = pAdapter->tsmStats.RoamingDly;
+ }
+ return vstatus;
}
#endif /*FEATURE_WLAN_CCX && FEATURE_WLAN_CCX_UPLOAD */
@@ -8094,13 +8126,6 @@ void hdd_wlan_initial_scan(hdd_adapter_t *pAdapter)
vos_mem_free(scanReq.ChannelInfo.ChannelList);
}
-struct fullPowerContext
-{
- struct completion completion;
- unsigned int magic;
-};
-#define POWER_CONTEXT_MAGIC 0x504F5752 //POWR
-
/**---------------------------------------------------------------------------
\brief hdd_full_power_callback() - HDD full power callback function
@@ -8116,7 +8141,7 @@ struct fullPowerContext
--------------------------------------------------------------------------*/
static void hdd_full_power_callback(void *callbackContext, eHalStatus status)
{
- struct fullPowerContext *pContext = callbackContext;
+ struct statsContext *pContext = callbackContext;
hddLog(VOS_TRACE_LEVEL_INFO,
"%s: context = %p, status = %d", __func__, pContext, status);
@@ -8129,24 +8154,32 @@ static void hdd_full_power_callback(void *callbackContext, eHalStatus status)
return;
}
- /* there is a race condition that exists between this callback function
- and the caller since the caller could time out either before or
- while this code is executing. we'll assume the timeout hasn't
- occurred, but we'll verify that right before we save our work */
+ /* there is a race condition that exists between this callback
+ function and the caller since the caller could time out either
+ before or while this code is executing. we use a spinlock to
+ serialize these actions */
+ spin_lock(&hdd_context_lock);
if (POWER_CONTEXT_MAGIC != pContext->magic)
{
/* the caller presumably timed out so there is nothing we can do */
+ spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, magic [%08x]",
__func__, pContext->magic);
return;
}
- /* the race is on. caller could have timed out immediately after
- we verified the magic, but if so, caller will wait a short time
- for us to notify the caller, so the context will stay valid */
+ /* context is valid so caller is still waiting */
+
+ /* paranoia: invalidate the magic */
+ pContext->magic = 0;
+
+ /* notify the caller */
complete(&pContext->completion);
+
+ /* serialization is complete */
+ spin_unlock(&hdd_context_lock);
}
/**---------------------------------------------------------------------------
@@ -8166,8 +8199,8 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx)
v_CONTEXT_t pVosContext = pHddCtx->pvosContext;
VOS_STATUS vosStatus;
struct wiphy *wiphy = pHddCtx->wiphy;
- hdd_adapter_t* pAdapter = NULL;
- struct fullPowerContext powerContext;
+ hdd_adapter_t* pAdapter;
+ struct statsContext powerContext;
long lrc;
#if defined (QCA_WIFI_2_0) && \
defined (QCA_WIFI_ISOC)
@@ -8303,24 +8336,11 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx)
lrc = wait_for_completion_interruptible_timeout(
&powerContext.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_POWER));
- /* either we have a response or we timed out
- either way, first invalidate our magic */
- powerContext.magic = 0;
if (lrc <= 0)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: %s while requesting full power",
__func__, (0 == lrc) ? "timeout" : "interrupt");
- /*
- * there is a race condition such that the callback
- * function could be executing at the same time we are. of
- * primary concern is if the callback function had already
- * verified the "magic" but hasn't yet set the completion
- * variable. Since the completion variable is on our
- * stack, we'll delay just a bit to make sure the data is
- * still valid if that is the case
- */
- msleep(50);
}
}
else
@@ -8328,10 +8348,23 @@ void hdd_wlan_exit(hdd_context_t *pHddCtx)
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Request for Full Power failed, status %d",
__func__, halStatus);
- VOS_ASSERT(0);
/* continue -- need to clean up as much as possible */
}
}
+ /* either we never sent a request, we sent a request and received a
+ response or we sent a request and timed out. if we never sent a
+ request or if we sent a request and got a response, we want to
+ clear the magic out of paranoia. if we timed out there is a
+ race condition such that the callback function could be
+ executing at the same time we are. of primary concern is if the
+ callback function had already verified the "magic" but had not
+ yet set the completion variable when a timeout occurred. we
+ serialize these activities by invalidating the magic while
+ holding a shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ powerContext.magic = 0;
+ spin_unlock(&hdd_context_lock);
}
else
{
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index bde8b54d28ce..bcfea33acdd0 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -121,11 +121,6 @@ int hdd_setBand_helper(struct net_device *dev, tANI_U8* ptr);
static int ioctl_debug;
module_param(ioctl_debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-#define STATS_CONTEXT_MAGIC 0x53544154 //STAT
-#define RSSI_CONTEXT_MAGIC 0x52535349 //RSSI
-#define POWER_CONTEXT_MAGIC 0x504F5752 //POWR
-#define SNR_CONTEXT_MAGIC 0x534E5200 //SNR
-
/* To Validate Channel against the Frequency and Vice-Versa */
static const hdd_freq_chan_map_t freq_chan_map[] = { {2412, 1}, {2417, 2},
{2422, 3}, {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8},
@@ -768,16 +763,19 @@ static void hdd_GetRssiCB( v_S7_t rssi, tANI_U32 staId, void *pContext )
return;
}
- /* there is a race condition that exists between this callback function
- and the caller since the caller could time out either before or
- while this code is executing. we'll assume the timeout hasn't
- occurred, but we'll verify that right before we save our work */
-
pStatsContext = pContext;
pAdapter = pStatsContext->pAdapter;
+
+ /* there is a race condition that exists between this callback
+ function and the caller since the caller could time out either
+ before or while this code is executing. we use a spinlock to
+ serialize these actions */
+ spin_lock(&hdd_context_lock);
+
if ((NULL == pAdapter) || (RSSI_CONTEXT_MAGIC != pStatsContext->magic))
{
/* the caller presumably timed out so there is nothing we can do */
+ spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, pAdapter [%p] magic [%08x]",
__func__, pAdapter, pStatsContext->magic);
@@ -789,13 +787,19 @@ static void hdd_GetRssiCB( v_S7_t rssi, tANI_U32 staId, void *pContext )
return;
}
- /* the race is on. caller could have timed out immediately after
- we verified the magic, but if so, caller will wait a short time
- for us to copy over the rssi */
+ /* context is valid so caller is still waiting */
+
+ /* paranoia: invalidate the magic */
+ pStatsContext->magic = 0;
+
+ /* copy over the rssi */
pAdapter->rssi = rssi;
- /* and notify the caller */
+ /* notify the caller */
complete(&pStatsContext->completion);
+
+ /* serialization is complete */
+ spin_unlock(&hdd_context_lock);
}
static void hdd_GetSnrCB(tANI_S8 snr, tANI_U32 staId, void *pContext)
@@ -817,17 +821,19 @@ static void hdd_GetSnrCB(tANI_S8 snr, tANI_U32 staId, void *pContext)
return;
}
- /* there is a race condition that exists between this callback function
- * and the caller since the caller could time out either before or
- * while this code is executing. we'll assume the timeout hasn't
- * occurred, but we'll verify that right before we save our work
- */
-
pStatsContext = pContext;
pAdapter = pStatsContext->pAdapter;
+
+ /* there is a race condition that exists between this callback
+ function and the caller since the caller could time out either
+ before or while this code is executing. we use a spinlock to
+ serialize these actions */
+ spin_lock(&hdd_context_lock);
+
if ((NULL == pAdapter) || (SNR_CONTEXT_MAGIC != pStatsContext->magic))
{
/* the caller presumably timed out so there is nothing we can do */
+ spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, pAdapter [%p] magic [%08x]",
__func__, pAdapter, pStatsContext->magic);
@@ -839,14 +845,19 @@ static void hdd_GetSnrCB(tANI_S8 snr, tANI_U32 staId, void *pContext)
return;
}
- /* the race is on. caller could have timed out immediately after
- * we verified the magic, but if so, caller will wait a short time
- * for us to copy over the snr
- */
+ /* context is valid so caller is still waiting */
+
+ /* paranoia: invalidate the magic */
+ pStatsContext->magic = 0;
+
+ /* copy over the snr */
pAdapter->snr = snr;
- /* and notify the caller */
+ /* notify the caller */
complete(&pStatsContext->completion);
+
+ /* serialization is complete */
+ spin_unlock(&hdd_context_lock);
}
VOS_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value)
@@ -893,24 +904,29 @@ VOS_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value)
/* request was sent -- wait for the response */
lrc = wait_for_completion_interruptible_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
- /* either we have a response or we timed out
- either way, first invalidate our magic */
- context.magic = 0;
if (lrc <= 0)
{
- hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while retrieving RSSI ",
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: SME %s while retrieving RSSI",
__func__, (0 == lrc) ? "timeout" : "interrupt");
- /* there is a race condition such that the callback
- function could be executing at the same time we are. of
- primary concern is if the callback function had already
- verified the "magic" but hasn't yet set the completion
- variable. Since the completion variable is on our
- stack, we'll delay just a bit to make sure the data is
- still valid if that is the case */
- msleep(50);
/* we'll now returned a cached value below */
}
}
+
+ /* either we never sent a request, we sent a request and received a
+ response or we sent a request and timed out. if we never sent a
+ request or if we sent a request and got a response, we want to
+ clear the magic out of paranoia. if we timed out there is a
+ race condition such that the callback function could be
+ executing at the same time we are. of primary concern is if the
+ callback function had already verified the "magic" but had not
+ yet set the completion variable when a timeout occurred. we
+ serialize these activities by invalidating the magic while
+ holding a shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
*rssi_value = pAdapter->rssi;
return VOS_STATUS_SUCCESS;
@@ -967,26 +983,29 @@ VOS_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, v_S7_t *snr)
/* request was sent -- wait for the response */
lrc = wait_for_completion_interruptible_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
- /* either we have a response or we timed out
- * either way, first invalidate our magic
- */
- context.magic = 0;
if (lrc <= 0)
{
- hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while retrieving SNR ",
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: SME %s while retrieving SNR",
__func__, (0 == lrc) ? "timeout" : "interrupt");
- /* there is a race condition such that the callback
- * function could be executing at the same time we are. Of
- * primary concern is if the callback function had already
- * verified the "magic" but hasn't yet set the completion
- * variable. Since the completion variable is on our
- * stack, we'll delay just a bit to make sure the data is
- * still valid if that is the case
- */
- msleep(50);
/* we'll now returned a cached value below */
}
}
+
+ /* either we never sent a request, we sent a request and received a
+ response or we sent a request and timed out. if we never sent a
+ request or if we sent a request and got a response, we want to
+ clear the magic out of paranoia. if we timed out there is a
+ race condition such that the callback function could be
+ executing at the same time we are. of primary concern is if the
+ callback function had already verified the "magic" but had not
+ yet set the completion variable when a timeout occurred. we
+ serialize these activities by invalidating the magic while
+ holding a shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
*snr = pAdapter->snr;
return VOS_STATUS_SUCCESS;
@@ -1011,16 +1030,19 @@ static void hdd_GetRoamRssiCB( v_S7_t rssi, tANI_U32 staId, void *pContext )
return;
}
- /* there is a race condition that exists between this callback function
- and the caller since the caller could time out either before or
- while this code is executing. we'll assume the timeout hasn't
- occurred, but we'll verify that right before we save our work */
-
pStatsContext = pContext;
pAdapter = pStatsContext->pAdapter;
+
+ /* there is a race condition that exists between this callback
+ function and the caller since the caller could time out either
+ before or while this code is executing. we use a spinlock to
+ serialize these actions */
+ spin_lock(&hdd_context_lock);
+
if ((NULL == pAdapter) || (RSSI_CONTEXT_MAGIC != pStatsContext->magic))
{
/* the caller presumably timed out so there is nothing we can do */
+ spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, pAdapter [%p] magic [%08x]",
__func__, pAdapter, pStatsContext->magic);
@@ -1032,13 +1054,19 @@ static void hdd_GetRoamRssiCB( v_S7_t rssi, tANI_U32 staId, void *pContext )
return;
}
- /* the race is on. caller could have timed out immediately after
- we verified the magic, but if so, caller will wait a short time
- for us to copy over the rssi */
+ /* context is valid so caller is still waiting */
+
+ /* paranoia: invalidate the magic */
+ pStatsContext->magic = 0;
+
+ /* copy over the rssi */
pAdapter->rssi = rssi;
- /* and notify the caller */
+ /* notify the caller */
complete(&pStatsContext->completion);
+
+ /* serialization is complete */
+ spin_unlock(&hdd_context_lock);
}
@@ -1094,24 +1122,29 @@ VOS_STATUS wlan_hdd_get_roam_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value)
/* request was sent -- wait for the response */
lrc = wait_for_completion_interruptible_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
- /* either we have a response or we timed out
- either way, first invalidate our magic */
- context.magic = 0;
if (lrc <= 0)
{
- hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while retrieving RSSI ",
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while retrieving RSSI",
__func__, (0 == lrc) ? "timeout" : "interrupt");
- /* there is a race condition such that the callback
- function could be executing at the same time we are. of
- primary concern is if the callback function had already
- verified the "magic" but hasn't yet set the completion
- variable. Since the completion variable is on our
- stack, we'll delay just a bit to make sure the data is
- still valid if that is the case */
- msleep(50);
/* we'll now returned a cached value below */
}
}
+
+ /* either we never sent a request, we sent a request and received a
+ response or we sent a request and timed out. if we never sent a
+ request or if we sent a request and got a response, we want to
+ clear the magic out of paranoia. if we timed out there is a
+ race condition such that the callback function could be
+ executing at the same time we are. of primary concern is if the
+ callback function had already verified the "magic" but had not
+ yet set the completion variable when a timeout occurred. we
+ serialize these activities by invalidating the magic while
+ holding a shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
*rssi_value = pAdapter->rssi;
return VOS_STATUS_SUCCESS;
@@ -2379,7 +2412,6 @@ static int iw_get_range(struct net_device *dev, struct iw_request_info *info,
static void iw_power_callback_fn (void *pContext, eHalStatus status)
{
struct statsContext *pStatsContext;
- hdd_adapter_t *pAdapter;
if (NULL == pContext)
{
@@ -2389,31 +2421,40 @@ static void iw_power_callback_fn (void *pContext, eHalStatus status)
return;
}
- /* there is a race condition that exists between this callback function
- and the caller since the caller could time out either before or
- while this code is executing. we'll assume the timeout hasn't
- occurred, but we'll verify that right before we save our work */
-
pStatsContext = (struct statsContext *)pContext;
- pAdapter = pStatsContext->pAdapter;
- if ((NULL == pAdapter) || (POWER_CONTEXT_MAGIC != pStatsContext->magic))
+ /* there is a race condition that exists between this callback
+ function and the caller since the caller could time out either
+ before or while this code is executing. we use a spinlock to
+ serialize these actions */
+ spin_lock(&hdd_context_lock);
+
+ if (POWER_CONTEXT_MAGIC != pStatsContext->magic)
{
/* the caller presumably timed out so there is nothing we can do */
+ spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
- "%s: Invalid context, pAdapter [%p] magic [%08x]",
- __func__, pAdapter, pStatsContext->magic);
+ "%s: Invalid context, magic [%08x]",
+ __func__, pStatsContext->magic);
if (ioctl_debug)
{
- pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n",
- __func__, pAdapter, pStatsContext->magic);
+ pr_info("%s: Invalid context, magic [%08x]\n",
+ __func__, pStatsContext->magic);
}
return;
}
- /* and notify the caller */
+ /* context is valid so caller is still waiting */
+
+ /* paranoia: invalidate the magic */
+ pStatsContext->magic = 0;
+
+ /* notify the caller */
complete(&pStatsContext->completion);
+
+ /* serialization is complete */
+ spin_unlock(&hdd_context_lock);
}
/* Callback function for tx per hit */
@@ -2453,17 +2494,20 @@ void hdd_GetClassA_statisticsCB(void *pStats, void *pContext)
return;
}
- /* there is a race condition that exists between this callback function
- and the caller since the caller could time out either before or
- while this code is executing. we'll assume the timeout hasn't
- occurred, but we'll verify that right before we save our work */
-
pClassAStats = pStats;
pStatsContext = pContext;
pAdapter = pStatsContext->pAdapter;
+
+ /* there is a race condition that exists between this callback
+ function and the caller since the caller could time out either
+ before or while this code is executing. we use a spinlock to
+ serialize these actions */
+ spin_lock(&hdd_context_lock);
+
if ((NULL == pAdapter) || (STATS_CONTEXT_MAGIC != pStatsContext->magic))
{
/* the caller presumably timed out so there is nothing we can do */
+ spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, pAdapter [%p] magic [%08x]",
__func__, pAdapter, pStatsContext->magic);
@@ -2475,13 +2519,19 @@ void hdd_GetClassA_statisticsCB(void *pStats, void *pContext)
return;
}
- /* the race is on. caller could have timed out immediately after
- we verified the magic, but if so, caller will wait a short time
- for us to copy over the stats. do so as a struct copy */
+ /* context is valid so caller is still waiting */
+
+ /* paranoia: invalidate the magic */
+ pStatsContext->magic = 0;
+
+ /* copy over the stats. do so as a struct copy */
pAdapter->hdd_stats.ClassA_stat = *pClassAStats;
- /* and notify the caller */
+ /* notify the caller */
complete(&pStatsContext->completion);
+
+ /* serialization is complete */
+ spin_unlock(&hdd_context_lock);
}
VOS_STATUS wlan_hdd_get_classAstats(hdd_adapter_t *pAdapter)
@@ -2520,7 +2570,7 @@ VOS_STATUS wlan_hdd_get_classAstats(hdd_adapter_t *pAdapter)
if (eHAL_STATUS_SUCCESS != hstatus)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
- "%s: Unable to retrieve Class A statistics ",
+ "%s: Unable to retrieve Class A statistics",
__func__);
/* we'll returned a cached value below */
}
@@ -2529,24 +2579,30 @@ VOS_STATUS wlan_hdd_get_classAstats(hdd_adapter_t *pAdapter)
/* request was sent -- wait for the response */
lrc = wait_for_completion_interruptible_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
- /* either we have a response or we timed out
- either way, first invalidate our magic */
- context.magic = 0;
if (lrc <= 0)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: SME %s while retrieving Class A statistics",
__func__, (0 == lrc) ? "timeout" : "interrupt");
- /* there is a race condition such that the callback
- function could be executing at the same time we are. of
- primary concern is if the callback function had already
- verified the "magic" but hasn't yet set the completion
- variable. Since the completion variable is on our
- stack, we'll delay just a bit to make sure the data is
- still valid if that is the case */
- msleep(50);
}
}
+
+ /* either we never sent a request, we sent a request and received a
+ response or we sent a request and timed out. if we never sent a
+ request or if we sent a request and got a response, we want to
+ clear the magic out of paranoia. if we timed out there is a
+ race condition such that the callback function could be
+ executing at the same time we are. of primary concern is if the
+ callback function had already verified the "magic" but had not
+ yet set the completion variable when a timeout occurred. we
+ serialize these activities by invalidating the magic while
+ holding a shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
+ /* either callback updated pAdapter stats or it has cached data */
return VOS_STATUS_SUCCESS;
}
@@ -2571,10 +2627,11 @@ static void hdd_get_station_statisticsCB(void *pStats, void *pContext)
return;
}
- /* there is a race condition that exists between this callback function
- and the caller since the caller could time out either before or
- while this code is executing. we'll assume the timeout hasn't
- occurred, but we'll verify that right before we save our work */
+ /* there is a race condition that exists between this callback
+ function and the caller since the caller could time out either
+ before or while this code is executing. we use a spinlock to
+ serialize these actions */
+ spin_lock(&hdd_context_lock);
pSummaryStats = (tCsrSummaryStatsInfo *)pStats;
pClassAStats = (tCsrGlobalClassAStatsInfo *)( pSummaryStats + 1 );
@@ -2583,6 +2640,7 @@ static void hdd_get_station_statisticsCB(void *pStats, void *pContext)
if ((NULL == pAdapter) || (STATS_CONTEXT_MAGIC != pStatsContext->magic))
{
/* the caller presumably timed out so there is nothing we can do */
+ spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, pAdapter [%p] magic [%08x]",
__func__, pAdapter, pStatsContext->magic);
@@ -2594,14 +2652,20 @@ static void hdd_get_station_statisticsCB(void *pStats, void *pContext)
return;
}
- /* the race is on. caller could have timed out immediately after
- we verified the magic, but if so, caller will wait a short time
- for us to copy over the stats. do so as a struct copy */
+ /* context is valid so caller is still waiting */
+
+ /* paranoia: invalidate the magic */
+ pStatsContext->magic = 0;
+
+ /* copy over the stats. do so as a struct copy */
pAdapter->hdd_stats.summary_stat = *pSummaryStats;
pAdapter->hdd_stats.ClassA_stat = *pClassAStats;
- /* and notify the caller */
+ /* notify the caller */
complete(&pStatsContext->completion);
+
+ /* serialization is complete */
+ spin_unlock(&hdd_context_lock);
}
VOS_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter)
@@ -2646,24 +2710,31 @@ VOS_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter)
/* request was sent -- wait for the response */
lrc = wait_for_completion_interruptible_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
- /* either we have a response or we timed out
- either way, first invalidate our magic */
- context.magic = 0;
+
if (lrc <= 0)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: SME %s while retrieving statistics",
__func__, (0 == lrc) ? "timeout" : "interrupt");
- /* there is a race condition such that the callback
- function could be executing at the same time we are. of
- primary concern is if the callback function had already
- verified the "magic" but hasn't yet set the completion
- variable. Since the completion variable is on our
- stack, we'll delay just a bit to make sure the data is
- still valid if that is the case */
- msleep(50);
}
}
+
+ /* either we never sent a request, we sent a request and received a
+ response or we sent a request and timed out. if we never sent a
+ request or if we sent a request and got a response, we want to
+ clear the magic out of paranoia. if we timed out there is a
+ race condition such that the callback function could be
+ executing at the same time we are. of primary concern is if the
+ callback function had already verified the "magic" but had not
+ yet set the completion variable when a timeout occurred. we
+ serialize these activities by invalidating the magic while
+ holding a shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
+ /* either callback updated pAdapter stats or it has cached data */
return VOS_STATUS_SUCCESS;
}
@@ -2862,23 +2933,15 @@ VOS_STATUS wlan_hdd_enter_bmps(hdd_adapter_t *pAdapter, int mode)
sme_SetDHCPTillPowerActiveFlag(pHddCtx->hHal, TRUE);
if (eHAL_STATUS_PMC_PENDING == status)
{
+ /* request was sent -- wait for the response */
int lrc = wait_for_completion_interruptible_timeout(
&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_POWER));
- context.magic = 0;
+
if (lrc <= 0)
{
hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while requesting fullpower ",
__func__, (0 == lrc) ? "timeout" : "interrupt");
- /* there is a race condition such that the callback
- function could be executing at the same time we are. of
- primary concern is if the callback function had already
- verified the "magic" but hasn't yet set the completion
- variable. Since the completion variable is on our
- stack, we'll delay just a bit to make sure the data is
- still valid if that is the case */
- msleep(50);
- /* we'll now returned a cached value below */
}
}
}
@@ -2896,23 +2959,15 @@ VOS_STATUS wlan_hdd_enter_bmps(hdd_adapter_t *pAdapter, int mode)
iw_power_callback_fn, &context);
if (eHAL_STATUS_PMC_PENDING == status)
{
+ /* request was sent -- wait for the response */
int lrc = wait_for_completion_interruptible_timeout(
&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_POWER));
- context.magic = 0;
if (lrc <= 0)
{
- hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while requesting BMPS ",
- __func__, (0 == lrc) ? "timeout" : "interrupt");
- /* there is a race condition such that the callback
- function could be executing at the same time we are. of
- primary concern is if the callback function had already
- verified the "magic" but hasn't yet set the completion
- variable. Since the completion variable is on our
- stack, we'll delay just a bit to make sure the data is
- still valid if that is the case */
- msleep(50);
- /* we'll now returned a cached value below */
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: SME %s while requesting BMPS",
+ __func__, (0 == lrc) ? "timeout" : "interrupt");
}
}
}
@@ -2922,6 +2977,22 @@ VOS_STATUS wlan_hdd_enter_bmps(hdd_adapter_t *pAdapter, int mode)
"enabled in the cfg");
}
}
+
+ /* either we never sent a request, we sent a request and received a
+ response or we sent a request and timed out. if we never sent a
+ request or if we sent a request and got a response, we want to
+ clear the magic out of paranoia. if we timed out there is a
+ race condition such that the callback function could be
+ executing at the same time we are. of primary concern is if the
+ callback function had already verified the "magic" but had not
+ yet set the completion variable when a timeout occurred. we
+ serialize these activities by invalidating the magic while
+ holding a shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
return VOS_STATUS_SUCCESS;
}
@@ -4336,29 +4407,33 @@ static int iw_setint_getnone(struct net_device *dev, struct iw_request_info *inf
status = sme_RequestFullPower(WLAN_HDD_GET_HAL_CTX(pAdapter),
iw_power_callback_fn, &context,
eSME_FULL_PWR_NEEDED_BY_HDD);
- if(eHAL_STATUS_PMC_PENDING == status)
+ if (eHAL_STATUS_PMC_PENDING == status)
{
int lrc = wait_for_completion_interruptible_timeout(
&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_POWER));
- context.magic = 0;
+
if (lrc <= 0)
{
- hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while "
- "requesting fullpower ",
- __func__, (0 == lrc) ?
- "timeout" : "interrupt");
- /* there is a race condition such that the callback
- function could be executing at the same time we are. of
- primary concern is if the callback function had already
- verified the "magic" but hasn't yet set the completion
- variable. Since the completion variable is on our
- stack, we'll delay just a bit to make sure the data is
- still valid if that is the case */
- msleep(50);
- /* we'll now returned a cached value below */
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: SME %s while requesting fullpower",
+ __func__, (0 == lrc) ?
+ "timeout" : "interrupt");
}
}
+ /* either we have a response or we timed out. if we timed
+ out there is a race condition such that the callback
+ function could be executing at the same time we are. of
+ primary concern is if the callback function had already
+ verified the "magic" but had not yet set the completion
+ variable when a timeout occurred. we serialize these
+ activities by invalidating the magic while holding a
+ shared spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
hddLog(LOGE, "iwpriv Full Power completed\n");
break;
}
@@ -4380,29 +4455,33 @@ static int iw_setint_getnone(struct net_device *dev, struct iw_request_info *inf
status = sme_RequestBmps(WLAN_HDD_GET_HAL_CTX(pAdapter),
iw_power_callback_fn, &context);
- if(eHAL_STATUS_PMC_PENDING == status)
+ if (eHAL_STATUS_PMC_PENDING == status)
{
int lrc = wait_for_completion_interruptible_timeout(
&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_POWER));
- context.magic = 0;
if (lrc <= 0)
{
- hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while "
- "requesting BMPS",
- __func__, (0 == lrc) ? "timeout" :
- "interrupt");
- /* there is a race condition such that the callback
- function could be executing at the same time we are. of
- primary concern is if the callback function had already
- verified the "magic" but hasn't yet set the completion
- variable. Since the completion variable is on our
- stack, we'll delay just a bit to make sure the data is
- still valid if that is the case */
- msleep(50);
- /* we'll now returned a cached value below */
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: SME %s while requesting BMPS",
+ __func__, (0 == lrc) ? "timeout" :
+ "interrupt");
}
}
+ /* either we have a response or we timed out. if we
+ timed out there is a race condition such that the
+ callback function could be executing at the same
+ time we are. of primary concern is if the callback
+ function had already verified the "magic" but had
+ not yet set the completion variable when a timeout
+ occurred. we serialize these activities by
+ invalidating the magic while holding a shared
+ spinlock which will cause us to block if the
+ callback is currently executing */
+ spin_lock(&hdd_context_lock);
+ context.magic = 0;
+ spin_unlock(&hdd_context_lock);
+
hddLog(LOGE, "iwpriv Request BMPS completed\n");
break;
}