wlan: protect ULA callback against adapter state changes

An issue was observed where when wlan_hdd_ula_done_cb() was invoked
the completion variable used to synchronize threads was in an
uninitialized state, leading to a crash.  Fix this by using a new
completion variable that will not be cleared when the adapter changes
state.  In addition add additional protection to make sure the adapter
is valid before referencing the completion variable, and add logging
when the wait_for_completion() times out so we know when the driver is
in an inconsistent state.

Change-Id: Id7687792e8e9aad20b32754f989fa3a41ab7cc85
CRs-fixed: 455822
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 7a4db4d..c3ca3cf 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -707,6 +707,9 @@
    /* Completion variable for remain on channel ready */
    struct completion rem_on_chan_ready_event;
 
+   /* Completion variable for Upper Layer Authentication */
+   struct completion ula_complete;
+
 #ifdef FEATURE_WLAN_TDLS
    struct completion tdls_add_station_comp;
    struct completion tdls_mgmt_comp;
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index ae56f40..df81455 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -1694,6 +1694,7 @@
 #endif
       init_completion(&pHddCtx->mc_sus_event_var);
       init_completion(&pHddCtx->tx_sus_event_var);
+      init_completion(&pAdapter->ula_complete);
 
       pAdapter->isLinkUpSvcNeeded = FALSE; 
       pAdapter->higherDtimTransition = eANI_BOOLEAN_TRUE;
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index 3b233bb..74b4bcc 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -942,20 +942,27 @@
 void wlan_hdd_ula_done_cb(v_VOID_t *callbackContext)
 {
     hdd_adapter_t *pAdapter = (hdd_adapter_t*)callbackContext;
-    hdd_wext_state_t *pWextState= WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
 
-    complete(&pWextState->completion_var);
+    if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
+    {
+        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                  "%s: Invalid pAdapter magic", __func__);
+    }
+    else
+    {
+        complete(&pAdapter->ula_complete);
+    }
 }
 
 VOS_STATUS wlan_hdd_check_ula_done(hdd_adapter_t *pAdapter)
 {
     hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
-    hdd_wext_state_t  *pWextState =  WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
     VOS_STATUS vos_status;
+    unsigned long rc;
 
     if (VOS_FALSE == pHddStaCtx->conn_info.uIsAuthenticated)
     {
-        INIT_COMPLETION(pWextState->completion_var);
+        INIT_COMPLETION(pAdapter->ula_complete);
 
         /*To avoid race condition between the set key and the last EAPOL
           packet, notify TL to finish upper layer authentication incase if the
@@ -971,8 +978,16 @@
 
         }
 
-        wait_for_completion_timeout(&pWextState->completion_var,
+        rc = wait_for_completion_timeout(&pAdapter->ula_complete,
                                     msecs_to_jiffies(HDD_FINISH_ULA_TIME_OUT));
+        if (0 == rc)
+        {
+            VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                      "%s: Timeout waiting for ULA to complete", __func__);
+            /* we'll still fall through and return success since the
+             * connection may still get established but is just taking
+             * too long for us to wait */
+        }
     }
     return VOS_STATUS_SUCCESS;
 }