wlan: Fix ULA Logic to remove EAPOL 4/4 race-condition.

Call ULA done callback from TL when it receives
EAPOL 4/4 packet. ULA done callback unblocks
set key to go through. Remove ULA logic from
SAP mode as it doesn't have race-condition.

Change-Id: Id5e08378019bb31f1829b257d32855a051ac4dcf
CRs-Fixed: 784553
diff --git a/CORE/HDD/inc/wlan_hdd_tx_rx.h b/CORE/HDD/inc/wlan_hdd_tx_rx.h
index a94dacf..acad7ab 100644
--- a/CORE/HDD/inc/wlan_hdd_tx_rx.h
+++ b/CORE/HDD/inc/wlan_hdd_tx_rx.h
@@ -49,6 +49,14 @@
 #define HDD_ETHERTYPE_802_1_X              ( 0x888E )
 #define HDD_ETHERTYPE_802_1_X_FRAME_OFFSET ( 12 )
 #define HDD_ETHERTYPE_802_1_X_SIZE         ( 2 )
+
+#define HDD_ETHERTYPE_802_1_X_FRAME_SUB_TYPE_OFFSET ( 19 )
+#define HDD_ETHERTYPE_802_1_X_SUB_TYPE_MASK ( 0x8003 )
+#define HDD_ETHERTYPE_802_1_X_M1_VALUE      ( 0x8000 )
+#define HDD_ETHERTYPE_802_1_X_M2_VALUE      ( 0x0001 )
+#define HDD_ETHERTYPE_802_1_X_M3_VALUE      ( 0x8003 )
+#define HDD_ETHERTYPE_802_1_X_M4_VALUE      ( 0x0003 )
+
 #ifdef FEATURE_WLAN_WAPI
 #define HDD_ETHERTYPE_WAI                  ( 0x88b4 )
 #endif
@@ -266,6 +274,14 @@
 extern v_BOOL_t hdd_IsEAPOLPacket( vos_pkt_t *pVosPacket );
 
 /**============================================================================
+  @brief hdd_FindEapolSubType() - Find EAPOL SubType.
+
+  @param pVosPacket : [in] pointer to vos packet
+  @return         : EAPOL_SubType value
+  ===========================================================================*/
+extern EAPOL_SubType hdd_FindEapolSubType( vos_pkt_t *pVosPacket );
+
+/**============================================================================
   @brief hdd_mon_tx_mgmt_pkt() - Transmit MGMT packet received on monitor 
                                  interface.
 
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index b022c69..ac4083d 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -8356,21 +8356,6 @@
         pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter);
         if( pHostapdState->bssState == BSS_START )
         {
-            hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
-            vos_status = wlan_hdd_check_ula_done(pAdapter);
-
-            if ( vos_status != VOS_STATUS_SUCCESS )
-            {
-                VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                        "[%4d] wlan_hdd_check_ula_done returned ERROR status= %d",
-                        __LINE__, vos_status );
-
-                pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE;
-
-                status = -EINVAL;
-                goto end;
-            }
-
             status = WLANSAP_SetKeySta( pVosContext, &setKey);
 
             if ( status != eHAL_STATUS_SUCCESS )
@@ -8438,19 +8423,36 @@
                 setKey.peerMac[4], setKey.peerMac[5],
                 setKey.keyDirection);
 
-        vos_status = wlan_hdd_check_ula_done(pAdapter);
-
-        if ( vos_status != VOS_STATUS_SUCCESS )
+        /* Wait for EAPOL M4 before setting key.
+         * No need to consider Dynamic WEP as we will receive M8.
+         */
+        if ( (setKey.encType == eCSR_ENCRYPT_TYPE_AES ||
+             setKey.encType == eCSR_ENCRYPT_TYPE_TKIP) &&
+             ( 1
+#if defined WLAN_FEATURE_VOWIFI_11R
+               && pHddStaCtx->conn_info.authType != eCSR_AUTH_TYPE_FT_RSN
+               && pHddStaCtx->conn_info.authType != eCSR_AUTH_TYPE_FT_RSN_PSK
+#endif
+#ifdef FEATURE_WLAN_ESE
+               && pHddStaCtx->conn_info.authType != eCSR_AUTH_TYPE_CCKM_WPA
+               && pHddStaCtx->conn_info.authType != eCSR_AUTH_TYPE_CCKM_RSN
+#endif
+               ))
         {
-            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+            vos_status = wlan_hdd_check_ula_done(pAdapter);
+
+            if ( vos_status != VOS_STATUS_SUCCESS )
+            {
+               VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                     "[%4d] wlan_hdd_check_ula_done returned ERROR status= %d",
                     __LINE__, vos_status );
 
-            pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE;
+               pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE;
 
-            status = -EINVAL;
-            goto end;
+               status = -EINVAL;
+               goto end;
 
+            }
         }
 
 #ifdef WLAN_FEATURE_VOWIFI_11R
diff --git a/CORE/HDD/src/wlan_hdd_softap_tx_rx.c b/CORE/HDD/src/wlan_hdd_softap_tx_rx.c
index 692e256..2db04f4 100644
--- a/CORE/HDD/src/wlan_hdd_softap_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_softap_tx_rx.c
@@ -1360,6 +1360,7 @@
          VOS_TRACE( VOS_MODULE_ID_HDD_SAP_DATA, VOS_TRACE_LEVEL_INFO_HIGH,
                     "%s: VOS packet is EAPOL packet", __func__);
          pPktMetaInfo->ucIsEapol = 1;
+         pPktMetaInfo->ucEapolSubType = hdd_FindEapolSubType(pVosPacket);
       }
    }
  
@@ -1371,7 +1372,7 @@
       if (VOS_PKT_PROTO_TYPE_EAPOL & proto_type)
       {
          VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
-                   "SAP TX EAPOL");
+                   "SAP TX EAPOL SubType %d",pPktMetaInfo->ucEapolSubType);
       }
       else if (VOS_PKT_PROTO_TYPE_DHCP & proto_type)
       {
@@ -1526,6 +1527,7 @@
    vos_pkt_t* pNextVosPacket;   
    hdd_context_t *pHddCtx = NULL;   
    v_U8_t proto_type;
+   EAPOL_SubType eapolSubType;
 
    //Sanity check on inputs
    if ( ( NULL == vosContext ) || 
@@ -1593,6 +1595,12 @@
          return VOS_STATUS_E_FAILURE;
       }
 
+      if (pHddCtx->cfg_ini->gEnableDebugLog)
+      {
+         if(hdd_IsEAPOLPacket(pVosPacket))
+            eapolSubType = hdd_FindEapolSubType(pVosPacket);
+      }
+
       // Extract the OS packet (skb).
       // Tell VOS to detach the OS packet from the VOS packet
       status = vos_pkt_get_os_packet( pVosPacket, (v_VOID_t **)&skb, VOS_TRUE );
@@ -1625,7 +1633,7 @@
          if (VOS_PKT_PROTO_TYPE_EAPOL & proto_type)
          {
             VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
-                      "SAP RX EAPOL");
+                      "SAP RX EAPOL SubType %d",eapolSubType);
          }
          else if (VOS_PKT_PROTO_TYPE_DHCP & proto_type)
          {
diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c
index 370fd71..eab8bf8 100644
--- a/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -967,7 +967,9 @@
       status = hdd_wmm_acquire_access( pAdapter, ac, &granted );
       pAdapter->psbChanged |= (1 << ac);
    }
-   if ( granted && ( pktListSize == 1 ))
+
+   if ( (granted && ( pktListSize == 1 )) ||
+        (pHddStaCtx->conn_info.uIsAuthenticated == VOS_FALSE))
    {
       //Let TL know we have a packet to send for this AC
       //VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,"%s:Indicating Packet to TL", __func__);
@@ -1316,6 +1318,50 @@
 }
 
 /**============================================================================
+  @brief hdd_FindEapolSubType() - Find EAPOL SubType.
+
+  @param pVosPacket : [in] pointer to vos packet
+  @return         : EAPOL_SubType value
+  ===========================================================================*/
+EAPOL_SubType hdd_FindEapolSubType( vos_pkt_t *pVosPacket )
+{
+    VOS_STATUS vosStatus  = VOS_STATUS_SUCCESS;
+    void       *pBuffer   = NULL;
+    EAPOL_SubType   subType = EAPOL_UNKNOWN;
+    v_U16_t   keyInfo;
+    vosStatus = vos_pkt_peek_data( pVosPacket,
+                         (v_SIZE_t)HDD_ETHERTYPE_802_1_X_FRAME_SUB_TYPE_OFFSET,
+                         &pBuffer, HDD_ETHERTYPE_802_1_X_SIZE );
+    if ( VOS_IS_STATUS_SUCCESS( vosStatus ) )
+    {
+       if ( pBuffer )
+       {
+          keyInfo = (*(unsigned short*)pBuffer &
+                         HDD_ETHERTYPE_802_1_X_SUB_TYPE_MASK);
+
+          switch (keyInfo) {
+            case HDD_ETHERTYPE_802_1_X_M1_VALUE:
+                 subType = EAPOL_M1;
+                 break;
+            case HDD_ETHERTYPE_802_1_X_M2_VALUE:
+                 subType = EAPOL_M2;
+                 break;
+            case HDD_ETHERTYPE_802_1_X_M3_VALUE:
+                 subType = EAPOL_M3;
+                 break;
+            case HDD_ETHERTYPE_802_1_X_M4_VALUE:
+                 subType = EAPOL_M4;
+                 break;
+            default:
+                 break;
+         }
+       }
+    }
+
+   return subType;
+}
+
+/**============================================================================
   @brief hdd_IsARP() - Checks the packet is ARP or not.
 
   @param pVosPacket : [in] pointer to vos packet
@@ -1671,8 +1717,12 @@
    
    if(pAdapter->sessionCtx.station.conn_info.uIsAuthenticated == VOS_TRUE)
       pPktMetaInfo->ucIsEapol = 0;       
-   else 
+   else
+   {
       pPktMetaInfo->ucIsEapol = hdd_IsEAPOLPacket( pVosPacket ) ? 1 : 0;
+      if(pPktMetaInfo->ucIsEapol)
+         pPktMetaInfo->ucEapolSubType = hdd_FindEapolSubType( pVosPacket );
+   }
 
    if ((NULL != pHddCtx) &&
        (pHddCtx->cfg_ini->gEnableDebugLog))
@@ -1682,7 +1732,7 @@
       if (VOS_PKT_PROTO_TYPE_EAPOL & proto_type)
       {
          VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
-                   "STA TX EAPOL");
+                   "STA TX EAPOL SubType %d",pPktMetaInfo->ucEapolSubType);
       }
       else if (VOS_PKT_PROTO_TYPE_DHCP & proto_type)
       {
@@ -1933,6 +1983,7 @@
    vos_pkt_t* pVosPacket;
    vos_pkt_t* pNextVosPacket;
    v_U8_t proto_type;
+   EAPOL_SubType eapolSubType;
 
    //Sanity check on inputs
    if ( ( NULL == vosContext ) || 
@@ -1980,6 +2031,12 @@
          return VOS_STATUS_E_FAILURE;
       }
 
+      if (pHddCtx->cfg_ini->gEnableDebugLog)
+      {
+         if (hdd_IsEAPOLPacket(pVosPacket))
+             eapolSubType = hdd_FindEapolSubType(pVosPacket);
+      }
+
       // Extract the OS packet (skb).
       // Tell VOS to detach the OS packet from the VOS packet
       status = vos_pkt_get_os_packet( pVosPacket, (v_VOID_t **)&skb, VOS_TRUE );
@@ -2038,7 +2095,7 @@
          if (VOS_PKT_PROTO_TYPE_EAPOL & proto_type)
          {
             VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
-                      "STA RX EAPOL");
+                      "STA RX EAPOL SubType %d",eapolSubType);
          }
          else if (VOS_PKT_PROTO_TYPE_DHCP & proto_type)
          {
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index e751579..9e208d1 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -1279,9 +1279,15 @@
         /*To avoid race condition between the set key and the last EAPOL
           packet, notify TL to finish upper layer authentication incase if the
           last EAPOL packet pending in the TL queue.*/
-        vos_status = WLANTL_Finish_ULA(wlan_hdd_ula_done_cb, pAdapter);
+        vos_status = WLANTL_Finish_ULA(wlan_hdd_ula_done_cb, pAdapter,
+                        (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+                        pHddStaCtx->conn_info.staId[0]);
 
-        if ( vos_status != VOS_STATUS_SUCCESS )
+        if ( vos_status == VOS_STATUS_E_ALREADY )
+        {
+            return VOS_STATUS_SUCCESS;
+        }
+        else if ( vos_status != VOS_STATUS_SUCCESS )
         {
             VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
                    "[%4d] WLANTL_Finish_ULA returned ERROR status= %d",