wlan: Enabling caching EAPOL packets at pre-assoc

Enable TL caching at pre assoc and forwarding/flushing
packets after pre assoc.

Change-Id: Ibf9db6dfc709e6510983bf04d11014d952ee2b70
CRs-Fixed: 1115231
diff --git a/CORE/HDD/inc/wlan_hdd_assoc.h b/CORE/HDD/inc/wlan_hdd_assoc.h
index 8194730..a474443 100644
--- a/CORE/HDD/inc/wlan_hdd_assoc.h
+++ b/CORE/HDD/inc/wlan_hdd_assoc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -135,6 +135,9 @@
 int hdd_SetGENIEToCsr( hdd_adapter_t *pAdapter, eCsrAuthType *RSNAuthType );
 
 int hdd_set_csr_auth_type( hdd_adapter_t *pAdapter, eCsrAuthType RSNAuthType );
+
+void hdd_assoc_registerFwdEapolCB(void *pContext);
+
 VOS_STATUS hdd_roamRegisterTDLSSTA( hdd_adapter_t *pAdapter,
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,0))
                                     const tANI_U8 *peerMac,
diff --git a/CORE/HDD/inc/wlan_hdd_tx_rx.h b/CORE/HDD/inc/wlan_hdd_tx_rx.h
index 68f7174..06c5acc 100644
--- a/CORE/HDD/inc/wlan_hdd_tx_rx.h
+++ b/CORE/HDD/inc/wlan_hdd_tx_rx.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -400,4 +400,14 @@
 }
 #endif /* FEATURE_WLAN_DIAG_SUPPORT */
 
+/**
+ * hdd_rx_fwd_eapol() - forward cached eapol frames
+ * @vosContext : pointer to vos global context
+ * @pVosPacket: pointer to vos packet
+ *
+ * Return: None
+ *
+ */
+void hdd_rx_fwd_eapol(v_VOID_t *vosContext, vos_pkt_t *pVosPacket);
+
 #endif    // end #if !defined( WLAN_HDD_TX_RX_H )
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index f45ad5b..f88f7c7 100644
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -4096,6 +4096,19 @@
     return 0;
 }
 
+/**
+ * hdd_rx_fwd_eapol() - forward cached eapol frames
+ * @vosContext : pointer to vos global context
+ * @pVosPacket: pointer to vos packet
+ *
+ * Return: None
+ *
+ */
+void hdd_assoc_registerFwdEapolCB(void *pContext)
+{
+     WLANTL_RegisterFwdEapol(pContext, hdd_rx_fwd_eapol);
+}
+
 /**---------------------------------------------------------------------------
 
   \brief __iw_set_essid() -
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index ad9c081..94984b6 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -12660,6 +12660,9 @@
 
    pHddCtx->is_ap_mode_wow_supported =
               sme_IsFeatureSupportedByFW(SAP_MODE_WOW);
+
+   hdd_assoc_registerFwdEapolCB(pVosContext);
+
    goto success;
 
 err_reg_netdev:
diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c
index b08ac0d..089282a 100644
--- a/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -2879,6 +2879,74 @@
     return;
 }
 
+/**
+ * hdd_rx_fwd_eapol() - forward cached eapol frames
+ * @vosContext : pointer to vos global context
+ * @pVosPacket: pointer to vos packet
+ *
+ * Return: None
+ *
+ */
+void hdd_rx_fwd_eapol(v_VOID_t *vosContext, vos_pkt_t *pVosPacket)
+{
+   hdd_context_t *pHddCtx = NULL;
+   hdd_adapter_t * pAdapter;
+   hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+   struct sk_buff *skb = NULL;
+   uint8_t proto_type;
+   uint8_t status;
+
+   if ((NULL == vosContext) || (NULL == pVosPacket))
+   {
+      VOS_TRACE(VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
+                        "%s: Null global context", __func__);
+      return;
+   }
+
+   pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, vosContext);
+   if (NULL == pHddCtx)
+   {
+      VOS_TRACE( VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
+                           "%s: HDD adapter context is Null", __func__);
+      return;
+   }
+
+   status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+   while ( NULL != pAdapterNode && 0 == status )
+   {
+      pAdapter = pAdapterNode->pAdapter;
+
+      if (pAdapter->device_mode == WLAN_HDD_INFRA_STATION)
+         break;
+
+      status = hdd_get_next_adapter (pHddCtx, pAdapterNode, &pNext);
+      pAdapterNode = pNext;
+   }
+
+   if (NULL == pAdapter)
+   {
+      VOS_TRACE(VOS_MODULE_ID_HDD_DATA, VOS_TRACE_LEVEL_ERROR,
+                        "%s: No adapter", __func__);
+      return;
+   }
+
+   vos_pkt_get_os_packet(pVosPacket, (v_VOID_t **)&skb, VOS_FALSE);
+   proto_type = vos_pkt_get_proto_type(skb,
+                                       pHddCtx->cfg_ini->gEnableDebugLog);
+   if (VOS_PKT_PROTO_TYPE_EAPOL & proto_type)
+   {
+      VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                   "STA RX EAPOL");
+   }
+
+   skb->dev = pAdapter->dev;
+   skb->protocol = eth_type_trans(skb, skb->dev);
+   skb->ip_summed = CHECKSUM_NONE;
+
+   netif_rx_ni(skb);
+}
+
 #ifdef FEATURE_WLAN_DIAG_SUPPORT
 /*
  * wlan_hdd_get_eapol_params() - Function to extract EAPOL params
diff --git a/CORE/TL/inc/wlan_qct_tl.h b/CORE/TL/inc/wlan_qct_tl.h
index 9d1a7ea..631be11 100644
--- a/CORE/TL/inc/wlan_qct_tl.h
+++ b/CORE/TL/inc/wlan_qct_tl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -721,7 +721,16 @@
                                           vos_pkt_t*             vosDataBuff,
                                           v_U8_t                 ucSTAId,
                                           WLANTL_RxMetaInfoType* pRxMetaInfo);
-
+/**
+ * WLANTL_FwdEapolCBType() - Call back to forward Eapol packet
+ * @pvosGCtx : pointer to vos global context
+ * @vosDataBuff: pointer to vos packet
+ *
+ * Return: None
+ *
+ */
+typedef void (*WLANTL_FwdEapolCBType) (v_PVOID_t pvosGCtx,
+                                             vos_pkt_t* vosDataBuff);
 
 /*----------------------------------------------------------------------------
     INTERACTION WITH BAP
@@ -3388,4 +3397,26 @@
  */
 void WLANTL_SampleTx(void *data);
 
+/*
+ * WLANTL_EnablePreAssocCaching - Enable caching during pre-assoc
+ * @staid: sta client where frames are cached
+ *
+ * Return: none
+ */
+void WLANTL_EnablePreAssocCaching(void);
+
+/*
+ * WLANTL_PreAssocForward - Forward the cached packets
+ *
+ * This function forwards or flushes the packets after
+ * pre assoc success/failure.
+ *
+ * Return: none
+ */
+void WLANTL_PreAssocForward(bool flag);
+
+/* make before break */
+void WLANTL_RegisterFwdEapol(v_PVOID_t pvosGCtx,
+                             WLANTL_FwdEapolCBType pfnFwdEapol);
+
 #endif /* #ifndef WLAN_QCT_WLANTL_H */
diff --git a/CORE/TL/src/wlan_qct_tl.c b/CORE/TL/src/wlan_qct_tl.c
old mode 100644
new mode 100755
index 74a1fe9..014927b
--- a/CORE/TL/src/wlan_qct_tl.c
+++ b/CORE/TL/src/wlan_qct_tl.c
@@ -6078,6 +6078,30 @@
    return true;
 }
 
+/**
+ * WLANTL_CacheEapol() - cache eapol frames
+ * @pTLCb : pointer to TL context
+ * @vosTempBuff: pointer to vos packet buff
+ *
+ * Return: None
+ *
+ */
+static void WLANTL_CacheEapol(WLANTL_CbType* pTLCb, vos_pkt_t* vosTempBuff)
+{
+   if ((NULL == pTLCb) || (NULL == vosTempBuff))
+   {
+      TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+               "%s: Invalid input pointer", __func__));
+      return;
+   }
+
+   if (NULL == pTLCb->vosEapolCachedFrame) {
+      TLLOG1(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
+               "%s: Cache Eapol frame", __func__));
+      pTLCb->vosEapolCachedFrame = vosTempBuff;
+   }
+}
+
 /*==========================================================================
 
   FUNCTION    WLANTL_RxFrames
@@ -6141,8 +6165,8 @@
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
   v_S7_t              currentAvgRSSI = 0;
   v_U8_t              ac;
-
 #endif
+  uint16_t           seq_no;
 
   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
 
@@ -6322,6 +6346,8 @@
     {
       ucSTAId = (v_U8_t)WDA_GET_RX_STAID( pvBDHeader );
       ucTid   = (v_U8_t)WDA_GET_RX_TID( pvBDHeader );
+      uDPUSig = WDA_GET_RX_DPUSIG(pvBDHeader);
+      seq_no = (uint16_t)WDA_GET_RX_REORDER_CUR_PKT_SEQ_NO(pvBDHeader);
 
       TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
                  "WLAN TL:Data packet received for STA %d", ucSTAId));
@@ -6346,6 +6372,16 @@
         }
       }/*if bcast*/
 
+      /* Pre assoc cache eapol */
+      if (pTLCb->preassoc_caching)
+      {
+        TLLOG1(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
+               "WLAN TL:TL preassoc_caching is enabled seq No: %d", seq_no));
+         WLANTL_CacheEapol(pTLCb, vosTempBuff);
+         vosTempBuff = vosDataBuff;
+         continue;
+      }
+
       if (WLANTL_STA_ID_INVALID(ucSTAId))
       {
         TLLOGW(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
@@ -6456,8 +6492,7 @@
            vosTempBuff = vosDataBuff;
            continue;
         }
-        uDPUSig = WDA_GET_RX_DPUSIG( pvBDHeader );
-          //Station has not yet been registered with TL - cache the frame
+        /* Station has not yet been registered with TL - cache the frame */
         TLLOGW(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
                  "%s: staId %d exist %d tlState %d cache rx frame", __func__, ucSTAId,
                  pClientSTA->ucExists, pClientSTA->tlState));
@@ -7069,6 +7104,47 @@
   return VOS_STATUS_SUCCESS;
 }/* WLANTL_RxCachedFrames */
 
+/**
+ * WLANTL_ForwardPkts() - forward cached eapol frames
+ * @pvosGCtx: pointer to vos global context
+ * @data: value to indicate either forward or flush
+ *
+ * Return: None
+ *
+ */
+static VOS_STATUS WLANTL_ForwardPkts(void* pvosGCtx, uint32_t data)
+{
+   WLANTL_CbType*  pTLCb = NULL;
+
+   pTLCb = VOS_GET_TL_CB(pvosGCtx);
+   if (NULL == pTLCb) {
+      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+             "%s: Invalid input pointer", __func__));
+      return VOS_STATUS_E_FAULT;
+   }
+
+   if (!data) {
+      TLLOG2(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
+             "%s: Pre assoc fail flush cache", __func__));
+      WLANTL_FlushCachedFrames(pTLCb->vosEapolCachedFrame);
+      goto done;
+   }
+
+   /* forward packets to HDD */
+   if (NULL != pTLCb->vosEapolCachedFrame) {
+      TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
+             "%s: forward pre assoc cached frames", __func__));
+      WLANTL_MonTranslate80211To8023Header(pTLCb->vosEapolCachedFrame, pTLCb);
+      pTLCb->pfnEapolFwd(pvosGCtx, pTLCb->vosEapolCachedFrame);
+   }
+
+done:
+  pTLCb->vosEapolCachedFrame = NULL;
+  pTLCb->preassoc_caching = false;
+
+  return VOS_STATUS_SUCCESS;
+}
+
 /*==========================================================================
   FUNCTION    WLANTL_RxProcessMsg
 
@@ -7146,6 +7222,11 @@
                                            ucUcastSig, ucBcastSig);
     break;
 
+  case WLANTL_RX_FWD_PRE_ASSOC_CACHED:
+    uData = message->bodyval;
+    vosStatus = WLANTL_ForwardPkts(pvosGCtx, uData);
+    break;
+
   default:
     /*no processing for now*/
     break;
@@ -14152,6 +14233,82 @@
 
    vos_timer_start(&pTLCb->tx_frames_timer, WLANTL_SAMPLE_INTERVAL);
 }
+
+/**
+ * WLANTL_EnablePreAssocCaching() - Enable caching EAPOL frames
+ *
+ * Return: None
+ *
+ */
+void WLANTL_EnablePreAssocCaching(void)
+{
+   v_PVOID_t pvosGCtx= vos_get_global_context(VOS_MODULE_ID_TL,NULL);
+   WLANTL_CbType* pTLCb = VOS_GET_TL_CB(pvosGCtx);
+   if (NULL == pTLCb ) {
+      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            "%s: Invalid TL pointer for global context", __func__));
+      return;
+   }
+
+   pTLCb->vosEapolCachedFrame = NULL;
+   pTLCb->preassoc_caching = true;
+}
+
+/**
+ * WLANTL_ForwardPreAssoc() - forward cached eapol frames
+ * @flag: Value to forward or flush
+ *
+ * Return: vos status
+ *
+ */
+static VOS_STATUS WLANTL_ForwardPreAssoc(bool flag)
+{
+  vos_msg_t sMessage;
+
+  VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+            " ---- Serializing TL for forwarding pre assoc cache frames");
+
+  vos_mem_zero( &sMessage, sizeof(vos_msg_t));
+  sMessage.type    = WLANTL_RX_FWD_PRE_ASSOC_CACHED;
+  sMessage.bodyval = flag;
+
+  return vos_rx_mq_serialize(VOS_MQ_ID_TL, &sMessage);
+}
+
+/**
+ * WLANTL_PreAssocForward() - forward cached eapol frames
+ * @flag: Value to forward or flush
+ *
+ * Return: None
+ *
+ */
+void WLANTL_PreAssocForward(bool flag)
+{
+  if(!VOS_IS_STATUS_SUCCESS(WLANTL_ForwardPreAssoc(flag)))
+  {
+    VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+       " %s fails to forward packets", __func__);
+  }
+}
+
+/**
+ * WLANTL_RegisterFwdEapol() - register call back to forward cached eapol frame
+ * @pvosGCtx : pointer to vos global context
+ * @pfnFwdEapol: call back function pointer
+ *
+ * Return: None
+ *
+ */
+void WLANTL_RegisterFwdEapol(v_PVOID_t pvosGCtx,
+                             WLANTL_FwdEapolCBType pfnFwdEapol)
+{
+   WLANTL_CbType* pTLCb = NULL;
+   pTLCb = VOS_GET_TL_CB(pvosGCtx);
+
+   pTLCb->pfnEapolFwd = pfnFwdEapol;
+
+}
+
 #ifdef WLAN_FEATURE_RMC
 VOS_STATUS WLANTL_RmcInit
 (
diff --git a/CORE/TL/src/wlan_qct_tli.h b/CORE/TL/src/wlan_qct_tli.h
index 254122f..1ea05be 100644
--- a/CORE/TL/src/wlan_qct_tli.h
+++ b/CORE/TL/src/wlan_qct_tli.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -305,6 +305,8 @@
   /* Forwarding RX cached frames */
   WLANTL_RX_FWD_CACHED  = 0,
 
+  /* Forward pre assoc cached frames */
+  WLANTL_RX_FWD_PRE_ASSOC_CACHED = 1,
 }WLANTL_RxSignalsType;
 
 /*---------------------------------------------------------------------------
@@ -1001,6 +1003,9 @@
   vos_timer_t tx_frames_timer;
   uint8_t sample_count;
 
+  bool preassoc_caching;
+  vos_pkt_t* vosEapolCachedFrame;
+  WLANTL_FwdEapolCBType pfnEapolFwd;
 }WLANTL_CbType;