HDD: Wait for firmware response to MON_MODE(START/STOP)_REQ
During driver unload, in monitor mode, it issues MON_MODE_STOP event
to firmware via WDA layer. As driver won't wait for firmware response
it goes ahead and posts WDI_STOP_REQ. So there is possibility of
processing WDI_STOP_REQ prior to MON_MODE_STOP_REQ, leading
MON_MODE_STOP_REQ to be added to WDI pending queue and this may lead
to improper driver unload.
Hence to avoid this scenario, wait for firmware response to
MON_MODE(START/STOP)_REQ and then post WDI_STOP_REQ to firmware.
Change-Id: I288d993e674fc9cf5dcceb992dee80f0a388f9db
CRs-Fixed: 903542
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index f4af360..95a7e2b 100755
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -6884,6 +6884,24 @@
}
return status;
}
+
+void hdd_monPostMsgCb(tANI_U32 *magic, struct completion *cmpVar)
+{
+ if (magic == NULL || cmpVar == NULL) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ FL("invalid arguments %p %p"), magic, cmpVar);
+ return;
+ }
+ if (*magic != MON_MODE_MSG_MAGIC) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ FL("maic: %x"), *magic);
+ return;
+ }
+
+ complete(cmpVar);
+ return;
+}
+
void hdd_init_mon_mode (hdd_adapter_t *pAdapter)
{
hdd_mon_ctx_t *pMonCtx = NULL;
@@ -8394,37 +8412,44 @@
pMonCtx->typeSubtypeBitmap |= 0xFFFF00000000;
}
-VOS_STATUS wlan_hdd_mon_poststartmsg( hdd_mon_ctx_t *pMonCtx )
+VOS_STATUS wlan_hdd_mon_postMsg(tANI_U32 *magic, struct completion *cmpVar,
+ hdd_mon_ctx_t *pMonCtx , void* callback)
{
vos_msg_t monMsg;
+ tSirMonModeReq *pMonModeReq;
- monMsg.type = WDA_MON_START_REQ;
- monMsg.reserved = 0;
- monMsg.bodyptr = (v_U8_t*)pMonCtx;
- monMsg.bodyval = 0;
-
- if (VOS_STATUS_SUCCESS != vos_mq_post_message(
- VOS_MODULE_ID_WDA,(vos_msg_t *)&monMsg)) {
- hddLog(VOS_TRACE_LEVEL_ERROR,"%s: : Failed to post Msg to HAL",__func__);
+ if (MON_MODE_START == pMonCtx->state)
+ monMsg.type = WDA_MON_START_REQ;
+ else if (MON_MODE_STOP == pMonCtx->state)
+ monMsg.type = WDA_MON_STOP_REQ;
+ else {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("invalid monitor state %d"), pMonCtx->state);
return VOS_STATUS_E_FAILURE;
}
- return VOS_STATUS_SUCCESS;
-}
+ pMonModeReq = vos_mem_malloc(sizeof(tSirMonModeReq));
+ if (pMonModeReq == NULL) {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ FL("fail to allocate memory for monitor mode req"));
+ return VOS_STATUS_E_FAILURE;
+ }
-void wlan_hdd_mon_poststopmsg(void)
-{
- vos_msg_t monMsg;
+ pMonModeReq->magic = magic;
+ pMonModeReq->cmpVar = cmpVar;
+ pMonModeReq->data = pMonCtx;
+ pMonModeReq->callback = callback;
- monMsg.type = WDA_MON_STOP_REQ;
monMsg.reserved = 0;
- monMsg.bodyptr = NULL;
+ monMsg.bodyptr = pMonModeReq;
monMsg.bodyval = 0;
if (VOS_STATUS_SUCCESS != vos_mq_post_message(
VOS_MODULE_ID_WDA,(vos_msg_t *)&monMsg)) {
hddLog(VOS_TRACE_LEVEL_ERROR,"%s: : Failed to post Msg to HAL",__func__);
+ vos_mem_free(pMonModeReq);
}
+ return VOS_STATUS_SUCCESS;
}
void wlan_hdd_mon_close(hdd_context_t *pHddCtx)
@@ -8432,7 +8457,10 @@
VOS_STATUS vosStatus;
v_CONTEXT_t pVosContext = pHddCtx->pvosContext;
struct wiphy *wiphy = pHddCtx->wiphy;
-
+ long ret;
+ hdd_mon_ctx_t *pMonCtx = NULL;
+ v_U32_t magic;
+ struct completion cmpVar;
hdd_adapter_t *pAdapter = hdd_get_adapter(pHddCtx,WLAN_HDD_MONITOR);
if(pAdapter == NULL || pVosContext == NULL)
{
@@ -8440,7 +8468,28 @@
return ;
}
- wlan_hdd_mon_poststopmsg();
+ pMonCtx = WLAN_HDD_GET_MONITOR_CTX_PTR(pAdapter);
+ if (pMonCtx!= NULL && pMonCtx->state == MON_MODE_START) {
+ pMonCtx->state = MON_MODE_STOP;
+ magic = MON_MODE_MSG_MAGIC;
+ init_completion(&cmpVar);
+ if (VOS_STATUS_SUCCESS !=
+ wlan_hdd_mon_postMsg(&magic, &cmpVar,
+ pMonCtx, hdd_monPostMsgCb)) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ FL("failed to post MON MODE REQ"));
+ pMonCtx->state = MON_MODE_START;
+ magic = 0;
+ return;
+ }
+ ret = wait_for_completion_timeout(&cmpVar, MON_MODE_MSG_TIMEOUT);
+ magic = 0;
+ if (ret <= 0 ) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ FL("timeout on monitor mode completion %ld"), ret);
+ }
+ }
+
hdd_UnregisterWext(pAdapter->dev);
vos_mon_stop( pVosContext );