wlan: Fix active cmd timeout issue

There can be a possible race in updation of roam substate
between csrRoamWaitForKeyTimeOutHandler and upper layer
disconnect in csrRoamIssueDeauth. Race can be as follows.

Driver roam substate is eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY by
the time csrRoamWaitForKeyTimeOutHandler is invoked. This
can allow check CSR_IS_WAIT_FOR_KEY to pass. If MC thread
gets preempted and if driver processes upper layer disconnect,
then driver changes roam substate to eCSR_ROAM_SUBSTATE_DEAUTH_REQ
in csrRoamIssueDeauth. When MC thread resumes processing of
csrRoamWaitForKeyTimeOutHandler, then driver changes roam
substate to eCSR_ROAM_SUBSTATE_NONE. This can result in
unhandling of eWNI_SME_DEAUTH_RSP as roam substate is not in
eCSR_ROAM_SUBSTATE_DEAUTH_REQ and can result in active command
timeout. Hence, update roam substate atomically in same context
if CSR_IS_WAIT_FOR_KEY passes in csrRoamWaitForKeyTimeOutHandler.

Change-Id: I05cfc8de54fe4196df941c2fd48db8bedc7df779
CRs-Fixed: 2148178
diff --git a/CORE/SME/src/csr/csrApiRoam.c b/CORE/SME/src/csr/csrApiRoam.c
index 544373a..178f9fa 100644
--- a/CORE/SME/src/csr/csrApiRoam.c
+++ b/CORE/SME/src/csr/csrApiRoam.c
@@ -764,7 +764,7 @@
     for( i = 0; i < CSR_ROAM_SESSION_MAX; i++ )
     {
        csrRoamStateChange( pMac, eCSR_ROAMING_STATE_STOP, i );
-       pMac->roam.curSubState[i] = eCSR_ROAM_SUBSTATE_NONE;
+       csrRoamSubstateChange(pMac, eCSR_ROAM_SUBSTATE_NONE, i);
     }
 
 #ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
@@ -855,6 +855,7 @@
          smsLog(pMac, LOGE, FL("cannot allocate memory for summary Statistics timer"));
          return eHAL_STATUS_FAILURE;
       }
+      vos_spin_lock_init(&pMac->roam.roam_state_lock);
     }while (0);
     return (status);
 }
@@ -870,6 +871,7 @@
     vos_timer_destroy(&pMac->roam.hTimerWaitForKey);
     vos_timer_stop(&pMac->roam.tlStatsReqInfo.hTlStatsTimer);
     vos_timer_destroy(&pMac->roam.tlStatsReqInfo.hTlStatsTimer);
+    vos_spin_lock_destroy(&pMac->roam.roam_state_lock);
     return (eHAL_STATUS_SUCCESS);
 }
 
@@ -1154,7 +1156,9 @@
     {
        return;
     }
+    vos_spin_lock_acquire(&pMac->roam.roam_state_lock);
     pMac->roam.curSubState[sessionId] = NewSubstate;
+    vos_spin_lock_release(&pMac->roam.roam_state_lock);
 }
 
 eCsrRoamState csrRoamStateChange( tpAniSirGlobal pMac, eCsrRoamState NewRoamState, tANI_U8 sessionId)
@@ -11206,8 +11210,15 @@
 
     if (pSession)
     {
+        vos_spin_lock_acquire(&pMac->roam.roam_state_lock);
         if( CSR_IS_WAIT_FOR_KEY( pMac, pInfo->sessionId ) )
         {
+           //Change the substate so command queue is unblocked.
+           if (CSR_ROAM_SESSION_MAX > pInfo->sessionId)
+               pMac->roam.curSubState[pInfo->sessionId] =
+                                           eCSR_ROAM_SUBSTATE_NONE;
+           vos_spin_lock_release(&pMac->roam.roam_state_lock);
+
 #ifdef FEATURE_WLAN_LFR
             if (csrNeighborRoamIsHandoffInProgress(pMac))
             {
@@ -11223,14 +11234,8 @@
                           NULL, eANI_BOOLEAN_FALSE);
             }
 #endif
-            smsLog(pMac, LOGE, " SME pre-auth state timeout. ");
 
-            //Change the substate so command queue is unblocked.
-            if (CSR_ROAM_SESSION_MAX > pInfo->sessionId)
-            {
-                csrRoamSubstateChange(pMac, eCSR_ROAM_SUBSTATE_NONE,
-                                      pInfo->sessionId);
-            }
+            smsLog(pMac, LOGE, " SME pre-auth state timeout. ");
 
             if( csrIsConnStateConnectedInfra(pMac, pInfo->sessionId) )
             {
@@ -11252,6 +11257,7 @@
         }
         else
         {
+            vos_spin_lock_release(&pMac->roam.roam_state_lock);
             smsLog(pMac, LOGW, "%s: session not found", __func__);
         }
     }