/*
 * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
 *
 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
 *
 *
 * Permission to use, copy, modify, and/or distribute this software for
 * any purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * This file was originally distributed by Qualcomm Atheros, Inc.
 * under proprietary terms before Copyright ownership was assigned
 * to the Linux Foundation.
 */

/*===========================================================================

                       W L A N _ Q C T _ T L _ B A. C
                                               
  OVERVIEW:
  
  This software unit holds the implementation of the WLAN Transport Layer
  Block Ack session support. Also included are the AMSDU de-aggregation 
  completion and MSDU re-ordering functionality. 
  
  The functions externalized by this module are to be called ONLY by the main
  TL module or the HAL layer.

  DEPENDENCIES: 

  Are listed for each API below. 
===========================================================================*/

/*===========================================================================

                      EDIT HISTORY FOR FILE


  This section contains comments describing changes made to the module.
  Notice that changes are listed in reverse chronological order.


   $Header$$DateTime$$Author$


  when        who     what, where, why
----------    ---    --------------------------------------------------------
2010-10-xx    dli     Change ucCIndex to point to the slot the next frame to be expected to fwd
2008-08-22    sch     Update based on unit test
2008-07-31    lti     Created module

===========================================================================*/

/*----------------------------------------------------------------------------
 * Include Files
 * -------------------------------------------------------------------------*/
#include "wlan_qct_tl.h" 
#include "wlan_qct_wda.h" 
#include "wlan_qct_tli.h" 
#include "wlan_qct_tli_ba.h" 
#include "wlan_qct_hal.h" 
#include "wlan_qct_tl_trace.h"
#include "vos_trace.h"
#include "vos_types.h"
#include "vos_list.h"
#include "vos_lock.h"
#include "tlDebug.h"
/*----------------------------------------------------------------------------
 * Preprocessor Definitions and Constants
 * -------------------------------------------------------------------------*/
//#define WLANTL_REORDER_DEBUG_MSG_ENABLE
#define WLANTL_BA_REORDERING_AGING_TIMER   30   /* 30 millisec */
#define WLANTL_BA_MIN_FREE_RX_VOS_BUFFER   0    /* RX VOS buffer low threshold */
#define CSN_WRAP_AROUND_THRESHOLD          3000 /* CSN wrap around threshold */


const v_U8_t  WLANTL_TID_2_AC[WLAN_MAX_TID] = {   WLANTL_AC_BE,
                                                  WLANTL_AC_BK,
                                                  WLANTL_AC_BK,
                                                  WLANTL_AC_BE,
                                                  WLANTL_AC_VI,
                                                  WLANTL_AC_VI,
                                                  WLANTL_AC_VO,
                                                  WLANTL_AC_VO };

/*==========================================================================

   FUNCTION    tlReorderingAgingTimerExpierCB

   DESCRIPTION 
      After aging timer expiered, all Qed frames have to be routed to upper
      layer. Otherwise, there is possibilitied that ahng some frames
    
   PARAMETERS 
      v_PVOID_t  timerUdata    Timer callback user data
                               Has information about where frames should be
                               routed
   
   RETURN VALUE
      VOS_STATUS_SUCCESS       General success
      VOS_STATUS_E_INVAL       Invalid frame handle
  
============================================================================*/
v_VOID_t WLANTL_ReorderingAgingTimerExpierCB
(
   v_PVOID_t  timerUdata
)
{
   WLANTL_TIMER_EXPIER_UDATA_T *expireHandle;
   WLANTL_BAReorderType        *ReorderInfo;
   WLANTL_CbType               *pTLHandle;
   WLANTL_STAClientType*       pClientSTA = NULL;
   vos_pkt_t                   *vosDataBuff;
   VOS_STATUS                   status = VOS_STATUS_SUCCESS;
   v_U8_t                       ucSTAID;
   v_U8_t                       ucTID;
   v_U8_t                       opCode;
   WLANTL_RxMetaInfoType        wRxMetaInfo;
   v_U32_t                      fwIdx = 0;
   WDI_DS_RxMetaInfoType       *pRxMetadata;
   vos_pkt_t                   *pCurrent;
   vos_pkt_t                   *pNext;
   v_S15_t                      seq = 0;
   v_U32_t                      cIndex;
   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

   if(NULL == timerUdata)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Timer Callback User data NULL"));
      return;
   }

   expireHandle = (WLANTL_TIMER_EXPIER_UDATA_T *)timerUdata;
   ucSTAID      = (v_U8_t)expireHandle->STAID;
   ucTID        = expireHandle->TID;
   if(WLANTL_STA_ID_INVALID(ucSTAID) || WLANTL_TID_INVALID(ucTID))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"SID %d or TID %d is not valid",
                  ucSTAID, ucTID));
      return;
   }

   pTLHandle    = (WLANTL_CbType *)expireHandle->pTLHandle;
   if(NULL == pTLHandle)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"TL Control block NULL"));
      return;
   }

   pClientSTA = pTLHandle->atlSTAClients[ucSTAID];
   if( NULL == pClientSTA ){
      TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
          "TL:STA Memory not allocated STA ID: %d, %s", ucSTAID, __func__));
      return;
   }

   ReorderInfo = &pClientSTA->atlBAReorderInfo[ucTID];
   if(NULL == ReorderInfo)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Reorder data NULL, this could not happen SID %d, TID %d", 
                  ucSTAID, ucTID));
      return;
   }

   if(0 == pClientSTA->atlBAReorderInfo[ucTID].ucExists)
   {
       TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Reorder session doesn't exist SID %d, TID %d", 
                   ucSTAID, ucTID));
       return;
   }

   if(!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(&ReorderInfo->reorderLock)))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_ReorderingAgingTimerExpierCB, Get LOCK Fail"));
      return;
   }

   if( 0 == pClientSTA->atlBAReorderInfo[ucTID].ucExists )
   {
      vos_lock_release(&ReorderInfo->reorderLock);
      return;
   }

   opCode      = WLANTL_OPCODE_FWDALL_DROPCUR;
   vosDataBuff = NULL;

   MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_REORDER_TIMER_EXP_CB,
                      ucSTAID , opCode ));


   TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"BA timeout with %d pending frames, curIdx %d", ReorderInfo->pendingFramesCount, ReorderInfo->ucCIndex));

   if(ReorderInfo->pendingFramesCount == 0)
   {
      if(!VOS_IS_STATUS_SUCCESS(vos_lock_release(&ReorderInfo->reorderLock)))
      {
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_ReorderingAgingTimerExpierCB, Release LOCK Fail"));
      }
      return;
   }

   if(0 == ReorderInfo->ucCIndex)
   {
      fwIdx = ReorderInfo->winSize;
   }
   else
   {
      fwIdx = ReorderInfo->ucCIndex - 1;
   }

   cIndex = ReorderInfo->ucCIndex;
   status = WLANTL_ChainFrontPkts(fwIdx, opCode, 
                                  &vosDataBuff, ReorderInfo, NULL);
   ReorderInfo->ucCIndex = cIndex;
   if(!VOS_IS_STATUS_SUCCESS(status))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make packet chain fail with Qed frames %d", status));
      if(!VOS_IS_STATUS_SUCCESS(vos_lock_release(&ReorderInfo->reorderLock)))
      {
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_ReorderingAgingTimerExpierCB, Release LOCK Fail"));
      }
      return;
   }

   if(NULL == pClientSTA->pfnSTARx)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Callback function NULL with STAID %d", ucSTAID));
      if(!VOS_IS_STATUS_SUCCESS(vos_lock_release(&ReorderInfo->reorderLock)))
      {
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_ReorderingAgingTimerExpierCB, Release LOCK Fail"));
      }
      return;
   }

   if(NULL == vosDataBuff)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"No pending frames, why triggered timer? "));
      if(!VOS_IS_STATUS_SUCCESS(vos_lock_release(&ReorderInfo->reorderLock)))
      {
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_ReorderingAgingTimerExpierCB, Release LOCK Fail"));
      }
      return;
   }

   /* Do replay check before giving packets to upper layer
      replay check code : check whether replay check is needed or not */
   if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid) {
      WLANTL_ReorderReplayCheck(pClientSTA, &vosDataBuff, ucTID);
   }

   pCurrent = vosDataBuff;

   while (pCurrent != NULL)
   {
       vos_pkt_walk_packet_chain(pCurrent, &pNext, VOS_FALSE);

       if (NULL == pNext)
       {
           /* This is the last packet, retrieve its sequence number */
           pRxMetadata = WDI_DS_ExtractRxMetaData(VOS_TO_WPAL_PKT(pCurrent));
           seq = WDA_GET_RX_REORDER_CUR_PKT_SEQ_NO(pRxMetadata);
       }
       pCurrent = pNext;
   }
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
          "%s: Sending out Frame no: %d to HDD", __func__, seq));
   ReorderInfo->LastSN = seq;

   if( WLAN_STA_SOFTAP == pClientSTA->wSTADesc.wSTAType)
   {
      WLANTL_FwdPktToHDD( expireHandle->pAdapter, vosDataBuff, ucSTAID);
   }
   else
   {
      wRxMetaInfo.ucUP = ucTID;
      pClientSTA->pfnSTARx(expireHandle->pAdapter,
                                           vosDataBuff, ucSTAID, &wRxMetaInfo);
   }
   if(!VOS_IS_STATUS_SUCCESS(vos_lock_release(&ReorderInfo->reorderLock)))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_ReorderingAgingTimerExpierCB, Release LOCK Fail"));
   }
   return;
}/*WLANTL_ReorderingAgingTimerExpierCB*/

/*----------------------------------------------------------------------------
    INTERACTION WITH TL Main
 ---------------------------------------------------------------------------*/
/*==========================================================================

   FUNCTION    WLANTL_InitBAReorderBuffer

   DESCRIPTION 
      Init Reorder buffer array
    
   PARAMETERS 
      v_PVOID_t   pvosGCtx Global context

   RETURN VALUE
      NONE
  
============================================================================*/

void WLANTL_InitBAReorderBuffer
(
   v_PVOID_t   pvosGCtx
)
{
   WLANTL_CbType        *pTLCb;
   v_U32_t              idx;
   v_U32_t              pIdx;

   pTLCb = VOS_GET_TL_CB(pvosGCtx);
   if (NULL == pTLCb)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                       "%s: Invalid TL Control Block", __func__));
      return;
   }

   for(idx = 0; idx < WLANTL_MAX_BA_SESSION; idx++)
   {
      pTLCb->reorderBufferPool[idx].isAvailable = VOS_TRUE;
      for(pIdx = 0; pIdx < WLANTL_MAX_WINSIZE; pIdx++)
      {
         pTLCb->reorderBufferPool[idx].arrayBuffer[pIdx] = NULL;
         pTLCb->reorderBufferPool[idx].ullReplayCounter[pIdx] = 0; 
      }
   }

   TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"BA reorder buffer init"));
   return;
}

/*==========================================================================

  FUNCTION    WLANTL_BaSessionAdd

  DESCRIPTION 
    HAL notifies TL when a new Block Ack session is being added. 
    
  DEPENDENCIES 
    A BA session on Rx needs to be added in TL before the response is 
    being sent out 
    
  PARAMETERS 

    IN
    pvosGCtx:       pointer to the global vos context; a handle to TL's 
                    control block can be extracted from its context 
    ucSTAId:        identifier of the station for which requested the BA 
                    session
    ucTid:          Tspec ID for the new BA session
    uSize:          size of the reordering window

   
  RETURN VALUE
    The result code associated with performing the operation  

    VOS_STATUS_E_INVAL:      Input parameters are invalid 
    VOS_STATUS_E_FAULT:      Station ID is outside array boundaries or pointer 
                             to TL cb is NULL ; access would cause a page fault  
    VOS_STATUS_E_EXISTS:     Station was not registered or BA session already
                             exists
    VOS_STATUS_E_NOSUPPORT:  Not yet supported
    
  SIDE EFFECTS 
  
============================================================================*/
VOS_STATUS
WLANTL_BaSessionAdd 
( 
  v_PVOID_t   pvosGCtx, 
  v_U16_t     sessionID,
  v_U32_t     ucSTAId,
  v_U8_t      ucTid, 
  v_U32_t     uBufferSize,
  v_U32_t     winSize,
  v_U32_t     SSN
)
{
  WLANTL_CbType        *pTLCb = NULL;
  WLANTL_STAClientType *pClientSTA = NULL;
  WLANTL_BAReorderType *reorderInfo;
  v_U32_t               idx;
  VOS_STATUS            status = VOS_STATUS_SUCCESS;
  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

  /*------------------------------------------------------------------------
    Sanity check
   ------------------------------------------------------------------------*/
  if ( WLANTL_TID_INVALID(ucTid))
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
              "WLAN TL:Invalid parameter sent on WLANTL_BaSessionAdd");
    return VOS_STATUS_E_INVAL;
  }

  if ( WLANTL_STA_ID_INVALID( ucSTAId ) )
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
              "WLAN TL:Invalid station id requested on WLANTL_BaSessionAdd");
    return VOS_STATUS_E_FAULT;
  }

  /*------------------------------------------------------------------------
    Extract TL control block and check existance
   ------------------------------------------------------------------------*/
  pTLCb = VOS_GET_TL_CB(pvosGCtx);
  if ( NULL == pTLCb ) 
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
          "WLAN TL:Invalid TL pointer from pvosGCtx on WLANTL_BaSessionAdd");
    return VOS_STATUS_E_FAULT;
  }

  pClientSTA  = pTLCb->atlSTAClients[ucSTAId];
  if ( NULL == pClientSTA )
  {
      TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
          "WLAN TL:Client Memory was not allocated on %s", __func__));
      return VOS_STATUS_E_FAILURE;
  }

  if ( 0 == pClientSTA->ucExists )
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
          "WLAN TL:Station was not yet registered on WLANTL_BaSessionAdd");
    return VOS_STATUS_E_EXISTS;
  }

  reorderInfo = &pClientSTA->atlBAReorderInfo[ucTid];
  if (!VOS_IS_STATUS_SUCCESS(
     vos_lock_acquire(&reorderInfo->reorderLock)))
  {
    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
           "%s: Release LOCK Fail", __func__));
    return VOS_STATUS_E_FAULT;
  }
  /*------------------------------------------------------------------------
    Verify that BA session was not already added
   ------------------------------------------------------------------------*/
  if ( 0 != reorderInfo->ucExists )
  {
    reorderInfo->ucExists++;
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
              "WLAN TL:BA session already exists on WLANTL_BaSessionAdd");
    vos_lock_release(&reorderInfo->reorderLock);
    return VOS_STATUS_E_EXISTS;
  }

  /*------------------------------------------------------------------------
    Initialize new BA session 
   ------------------------------------------------------------------------*/
  for(idx = 0; idx < WLANTL_MAX_BA_SESSION; idx++)
  {
    if(VOS_TRUE == pTLCb->reorderBufferPool[idx].isAvailable)
    {
      pClientSTA->atlBAReorderInfo[ucTid].reorderBuffer =
                                            &(pTLCb->reorderBufferPool[idx]);
      pTLCb->reorderBufferPool[idx].isAvailable = VOS_FALSE;
      TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"%dth buffer available, buffer PTR 0x%pK",
                  idx,
                  pClientSTA->atlBAReorderInfo[ucTid].reorderBuffer
                  ));
      break;
    }
  }

  
  if (WLAN_STA_SOFTAP == pClientSTA->wSTADesc.wSTAType)
  {
      if (WLANTL_MAX_BA_SESSION == idx)
      {
          VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
              "Number of Add BA request received more than allowed");
          vos_lock_release(&reorderInfo->reorderLock);
          return VOS_STATUS_E_NOSUPPORT;
      }
  }
  reorderInfo->timerUdata.pAdapter     = pvosGCtx;
  reorderInfo->timerUdata.pTLHandle    = (v_PVOID_t)pTLCb;
  reorderInfo->timerUdata.STAID        = ucSTAId;
  reorderInfo->timerUdata.TID          = ucTid;

  /* BA aging timer */
  status = vos_timer_init(&reorderInfo->agingTimer,
                          VOS_TIMER_TYPE_SW,
                          WLANTL_ReorderingAgingTimerExpierCB,
                          (v_PVOID_t)(&reorderInfo->timerUdata));
  if(!VOS_IS_STATUS_SUCCESS(status))
  {
     TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
            "%s: Timer Init Fail", __func__));
     vos_lock_release(&reorderInfo->reorderLock);
     return status;
  }

  pClientSTA->atlBAReorderInfo[ucTid].ucExists++;
  pClientSTA->atlBAReorderInfo[ucTid].usCount   = 0;
  pClientSTA->atlBAReorderInfo[ucTid].ucCIndex  = 0;
  if(0 == winSize)
  {
    pClientSTA->atlBAReorderInfo[ucTid].winSize = WLANTL_MAX_WINSIZE;
  }
  else
  {
    pClientSTA->atlBAReorderInfo[ucTid].winSize   = winSize;
  }
  pClientSTA->atlBAReorderInfo[ucTid].SSN       = SSN;
  pClientSTA->atlBAReorderInfo[ucTid].sessionID = sessionID;
  pClientSTA->atlBAReorderInfo[ucTid].pendingFramesCount = 0;
  pClientSTA->atlBAReorderInfo[ucTid].LastSN = SSN;
  TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
             "WLAN TL:New BA session added for STA: %d TID: %d",
             ucSTAId, ucTid));

  if(!VOS_IS_STATUS_SUCCESS(
     vos_lock_release(&reorderInfo->reorderLock)))
  {
    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
           "%s: Release LOCK Fail", __func__));
    return VOS_STATUS_E_FAULT;
  }
  return VOS_STATUS_SUCCESS;
}/* WLANTL_BaSessionAdd */

/*==========================================================================

  FUNCTION    WLANTL_BaSessionDel

  DESCRIPTION 
    HAL notifies TL when a new Block Ack session is being deleted. 
    
  DEPENDENCIES 
    
  PARAMETERS 

    IN
    pvosGCtx:       pointer to the global vos context; a handle to TL's 
                    control block can be extracted from its context 
    ucSTAId:        identifier of the station for which requested the BA 
                    session
    ucTid:          Tspec ID for the new BA session
   
  RETURN VALUE
    The result code associated with performing the operation  

    VOS_STATUS_E_INVAL:      Input parameters are invalid 
    VOS_STATUS_E_FAULT:      Station ID is outside array boundaries or pointer 
                             to TL cb is NULL ; access would cause a page fault  
    VOS_STATUS_E_EXISTS:     Station was not registered or BA session already
                             exists
    VOS_STATUS_E_NOSUPPORT:  Not yet supported
    
  SIDE EFFECTS 
  
============================================================================*/
VOS_STATUS
WLANTL_BaSessionDel 
( 
  v_PVOID_t      pvosGCtx, 
  v_U16_t        ucSTAId,
  v_U8_t         ucTid
)
{
  WLANTL_CbType*          pTLCb       = NULL;
  WLANTL_STAClientType    *pClientSTA   = NULL;
  vos_pkt_t*              vosDataBuff = NULL;
  VOS_STATUS              vosStatus   = VOS_STATUS_E_FAILURE;
  VOS_STATUS              lockStatus = VOS_STATUS_E_FAILURE;  
  WLANTL_BAReorderType*   reOrderInfo = NULL;
  WLANTL_RxMetaInfoType   wRxMetaInfo;
  v_U32_t                 fwIdx = 0;
  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

   /*------------------------------------------------------------------------
    Sanity check
   ------------------------------------------------------------------------*/
  if ( WLANTL_TID_INVALID(ucTid))
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
              "WLAN TL:Invalid parameter sent on WLANTL_BaSessionDel");
    return VOS_STATUS_E_INVAL;
  }

   if ( WLANTL_STA_ID_INVALID( ucSTAId ) )
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
              "WLAN TL:Invalid station id requested on WLANTL_BaSessionDel");
    return VOS_STATUS_E_FAULT;
  }

  /*------------------------------------------------------------------------
    Extract TL control block and check existance
   ------------------------------------------------------------------------*/
  pTLCb = VOS_GET_TL_CB(pvosGCtx);
  if ( NULL == pTLCb ) 
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
          "WLAN TL:Invalid TL pointer from pvosGCtx on WLANTL_BaSessionDel");
    return VOS_STATUS_E_FAULT;
  }

  pClientSTA = pTLCb->atlSTAClients[ucSTAId];

  if ( NULL == pClientSTA )
  {
    TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
        "WLAN TL:Client Memory was not allocated on %s", __func__));
    return VOS_STATUS_E_FAILURE;
  }

  if (( 0 == pClientSTA->ucExists ) &&
      ( 0 == pClientSTA->atlBAReorderInfo[ucTid].ucExists ))
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
          "WLAN TL:Station was not yet registered on WLANTL_BaSessionDel");
    return VOS_STATUS_E_EXISTS;
  }
  else if(( 0 == pClientSTA->ucExists ) &&
          ( 0 != pClientSTA->atlBAReorderInfo[ucTid].ucExists ))
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
          "STA was deleted but BA info is still there, just remove BA info");

    reOrderInfo = &pClientSTA->atlBAReorderInfo[ucTid];
    reOrderInfo->reorderBuffer->isAvailable = VOS_TRUE;
    memset(&reOrderInfo->reorderBuffer->arrayBuffer[0],
           0,
           WLANTL_MAX_WINSIZE * sizeof(v_PVOID_t));
    vos_timer_destroy(&reOrderInfo->agingTimer);
    memset(reOrderInfo, 0, sizeof(WLANTL_BAReorderType));

    return VOS_STATUS_SUCCESS;
  }

  /*------------------------------------------------------------------------
    Verify that BA session was added
   ------------------------------------------------------------------------*/
  if ( 0 == pClientSTA->atlBAReorderInfo[ucTid].ucExists )
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
               "WLAN TL:BA session does not exists on WLANTL_BaSessionDel");
    return VOS_STATUS_E_EXISTS;
  }

  
  /*------------------------------------------------------------------------
     Send all pending packets to HDD 
   ------------------------------------------------------------------------*/
  reOrderInfo = &pClientSTA->atlBAReorderInfo[ucTid];

  /*------------------------------------------------------------------------
     Invalidate reorder info here. This ensures that no packets are 
     bufferd after  reorder buffer is cleaned.
   */
  lockStatus = vos_lock_acquire(&reOrderInfo->reorderLock);
  if(!VOS_IS_STATUS_SUCCESS(lockStatus))
  {
    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
          "Unable to acquire reorder vos lock in %s", __func__));
    return lockStatus;
  }
  pClientSTA->atlBAReorderInfo[ucTid].ucExists = 0;

  TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
               "WLAN TL: Fwd all packets to HDD on WLANTL_BaSessionDel"));

  if(0 == reOrderInfo->ucCIndex)
  {
     fwIdx = reOrderInfo->winSize;
  }
  else
  {
     fwIdx = reOrderInfo->ucCIndex - 1;
  }

  if(0 != reOrderInfo->pendingFramesCount)
  {
    vosStatus = WLANTL_ChainFrontPkts(fwIdx,
                                      WLANTL_OPCODE_FWDALL_DROPCUR,
                                      &vosDataBuff, reOrderInfo, pTLCb);
  }

  if ((VOS_STATUS_SUCCESS == vosStatus) && (NULL != vosDataBuff))
  {
    TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
             "WLAN TL: Chaining was successful sending all pkts to HDD : %x",
              vosDataBuff ));

    /* Do replay check before giving packets to upper layer
       replay check code : check whether replay check is needed or not */
    if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid) {
      WLANTL_ReorderReplayCheck(pClientSTA, &vosDataBuff, ucTid);
    }

    if ( WLAN_STA_SOFTAP == pClientSTA->wSTADesc.wSTAType )
    {
      WLANTL_FwdPktToHDD( pvosGCtx, vosDataBuff, ucSTAId);
    }
    else
    {
      wRxMetaInfo.ucUP = ucTid;
      pClientSTA->pfnSTARx( pvosGCtx, vosDataBuff, ucSTAId,
                                            &wRxMetaInfo );
    }
  }

  /*------------------------------------------------------------------------
     Delete reordering timer
   ------------------------------------------------------------------------*/
  if(VOS_TIMER_STATE_RUNNING == vos_timer_getCurrentState(&reOrderInfo->agingTimer))
  {
    vosStatus = vos_timer_stop(&reOrderInfo->agingTimer);
    if(!VOS_IS_STATUS_SUCCESS(vosStatus))
    { 
       TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Timer stop fail: %d", vosStatus));
       vos_lock_release(&reOrderInfo->reorderLock);
       return vosStatus;
    }
  }

  if(VOS_TIMER_STATE_STOPPED == vos_timer_getCurrentState(&reOrderInfo->agingTimer))
  {
     vosStatus = vos_timer_destroy(&reOrderInfo->agingTimer);
  }
  else
  {
    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Timer is not stopped state current state is %d",
                vos_timer_getCurrentState(&reOrderInfo->agingTimer)));
  }
  if ( VOS_STATUS_SUCCESS != vosStatus ) 
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
              "WLAN TL:Failed to destroy reorder timer on WLANTL_BaSessionAdd");
  }

  /*------------------------------------------------------------------------
    Delete session 
   ------------------------------------------------------------------------*/
  pClientSTA->atlBAReorderInfo[ucTid].usCount  = 0;
  pClientSTA->atlBAReorderInfo[ucTid].ucCIndex = 0;
  reOrderInfo->winSize   = 0;
  reOrderInfo->SSN       = 0;
  reOrderInfo->sessionID = 0;
  reOrderInfo->LastSN = 0;

  MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_BA_SESSION_DEL,
                      ucSTAId, ucTid ));

  TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
             "WLAN TL: BA session deleted for STA: %d TID: %d",
             ucSTAId, ucTid));

  memset((v_U8_t *)(&reOrderInfo->reorderBuffer->arrayBuffer[0]),
                    0,
                    WLANTL_MAX_WINSIZE * sizeof(v_PVOID_t));
  reOrderInfo->reorderBuffer->isAvailable = VOS_TRUE;

  vos_lock_release(&reOrderInfo->reorderLock);
  return VOS_STATUS_SUCCESS;
}/* WLANTL_BaSessionDel */


/*----------------------------------------------------------------------------
    INTERACTION WITH TL main module
 ---------------------------------------------------------------------------*/

/*==========================================================================
      AMSDU sub-frame processing module
  ==========================================================================*/
/*==========================================================================
  FUNCTION    WLANTL_AMSDUProcess

  DESCRIPTION 
    Process A-MSDU sub-frame. Start of chain if marked as first frame. 
    Linked at the end of the existing AMSDU chain. 

  DEPENDENCIES 
         
  PARAMETERS 

   IN/OUT:
   vosDataBuff: vos packet for the received data
                 outgoing contains the root of the chain for the rx 
                 aggregated MSDU if the frame is marked as last; otherwise 
                 NULL
   
   IN
   pvosGCtx:     pointer to the global vos context; a handle to TL's 
                 control block can be extracted from its context 
   pvBDHeader:   pointer to the BD header
   ucSTAId:      Station ID 
   ucMPDUHLen:   length of the MPDU header
   usMPDULen:    length of the MPDU 
      
  RETURN VALUE
    The result code associated with performing the operation  

    VOS_STATUS_E_INVAL:   invalid input parameters
    VOS_STATUS_E_FAULT:   pointer to TL cb is NULL ; access would cause a 
                          page fault  
    VOS_STATUS_SUCCESS:   Everything is good :)

  Other values can be returned as a result of a function call, please check 
  corresponding API for more info. 
  
  SIDE EFFECTS 
  
============================================================================*/
VOS_STATUS
WLANTL_AMSDUProcess
( 
  v_PVOID_t   pvosGCtx,
  vos_pkt_t** ppVosDataBuff, 
  v_PVOID_t   pvBDHeader,
  v_U8_t      ucSTAId,
  v_U8_t      ucMPDUHLen,
  v_U16_t     usMPDULen
)
{
  v_U8_t          ucFsf; /* First AMSDU sub frame */
  v_U8_t          ucAef; /* Error in AMSDU sub frame */
  WLANTL_CbType*  pTLCb = NULL; 
  WLANTL_STAClientType *pClientSTA = NULL;
  v_U8_t          MPDUHeaderAMSDUHeader[WLANTL_MPDU_HEADER_LEN + TL_AMSDU_SUBFRM_HEADER_LEN];
  v_U16_t         subFrameLength;
  v_U16_t         paddingSize;
  VOS_STATUS      vStatus = VOS_STATUS_SUCCESS;
  v_U16_t         MPDUDataOffset;
  v_U16_t         packetLength; 
  static v_U32_t  numAMSDUFrames;
  vos_pkt_t*      vosDataBuff;
  uint8_t llc_hdr[6] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
  uint8_t broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  /*------------------------------------------------------------------------
    Sanity check
   ------------------------------------------------------------------------*/
  if (( NULL == ppVosDataBuff ) || (NULL == *ppVosDataBuff) || ( NULL == pvBDHeader ) || 
      ( WLANTL_STA_ID_INVALID(ucSTAId)) )
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
               "WLAN TL:Invalid parameter sent on WLANTL_AMSDUProcess");
    return VOS_STATUS_E_INVAL;
  }

  vosDataBuff = *ppVosDataBuff;
  /*------------------------------------------------------------------------
    Extract TL control block 
   ------------------------------------------------------------------------*/
  pTLCb = VOS_GET_TL_CB(pvosGCtx);
  if ( NULL == pTLCb ) 
  {
    VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
         "WLAN TL:Invalid TL pointer from pvosGCtx on WLANTL_AMSDUProcess");
    return VOS_STATUS_E_FAULT;
  }

  pClientSTA = pTLCb->atlSTAClients[ucSTAId];

  if ( NULL == pClientSTA )
  {
      TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
          "WLAN TL:Client Memory was not allocated on %s", __func__));
      return VOS_STATUS_E_FAILURE;
  }

  /*------------------------------------------------------------------------
    Check frame
   ------------------------------------------------------------------------*/
  ucAef =  (v_U8_t)WDA_GET_RX_AEF( pvBDHeader );
  ucFsf =  (v_U8_t)WDA_GET_RX_ESF( pvBDHeader );
  /* On Prima, MPDU data offset not includes BD header size */
  MPDUDataOffset = (v_U16_t)WDA_GET_RX_MPDU_DATA_OFFSET(pvBDHeader);

  if ( WLANHAL_RX_BD_AEF_SET == ucAef ) 
  {
    TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
               "WLAN TL:Error in AMSDU - dropping entire chain"));

    vos_pkt_return_packet(vosDataBuff);
    *ppVosDataBuff = NULL;
    return VOS_STATUS_SUCCESS; /*Not a transport error*/ 
  }

  if((0 != ucMPDUHLen) && ucFsf)
  {
    /*
     * This is first AMSDU sub frame
     * AMSDU Header should be removed
     * MPDU header should be stored into context to recover next frames
     */
    /* Assumed here Address4 is never part of AMSDU received at TL */
    if (ucMPDUHLen > WLANTL_MPDU_HEADER_LEN)
    {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"MPDU Header length (%d) is greater",ucMPDUHLen));
      vos_pkt_return_packet(vosDataBuff);
      *ppVosDataBuff = NULL;
      return VOS_STATUS_SUCCESS; /*Not a transport error*/
    }

    vStatus = vos_pkt_pop_head(vosDataBuff, MPDUHeaderAMSDUHeader, ucMPDUHLen + TL_AMSDU_SUBFRM_HEADER_LEN);
    if(!VOS_IS_STATUS_SUCCESS(vStatus))
    {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Pop MPDU AMSDU Header fail"));
      vos_pkt_return_packet(vosDataBuff);
      *ppVosDataBuff = NULL;
      return VOS_STATUS_SUCCESS; /*Not a transport error*/ 
    }
    pClientSTA->ucMPDUHeaderLen = ucMPDUHLen;
    vos_mem_copy(pClientSTA->aucMPDUHeader, MPDUHeaderAMSDUHeader, ucMPDUHLen);
    /* AMSDU header stored to handle garbage data within next frame */
    pClientSTA->drop_amsdu = false;
  }
  else
  {
    /* Trim garbage, size is frameLoop */
    if(MPDUDataOffset > 0)
    {
      vStatus = vos_pkt_trim_head(vosDataBuff, MPDUDataOffset);
    }
    if(!VOS_IS_STATUS_SUCCESS(vStatus))
    {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Trim Garbage Data fail"));
      vos_pkt_return_packet(vosDataBuff);
      *ppVosDataBuff = NULL;
      return VOS_STATUS_SUCCESS; /*Not a transport error*/ 
    }

    /* Remove MPDU header and AMSDU header from the packet */
    vStatus = vos_pkt_pop_head(vosDataBuff, MPDUHeaderAMSDUHeader, ucMPDUHLen + TL_AMSDU_SUBFRM_HEADER_LEN);
    if(!VOS_IS_STATUS_SUCCESS(vStatus))
    {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"AMSDU Header Pop fail"));
      vos_pkt_return_packet(vosDataBuff);
      *ppVosDataBuff = NULL;
      return VOS_STATUS_SUCCESS; /*Not a transport error*/ 
    }
  } /* End of henalding not first sub frame specific */

  /* Put in MPDU header into all the frame */
  vStatus = vos_pkt_push_head(vosDataBuff, pClientSTA->aucMPDUHeader, pClientSTA->ucMPDUHeaderLen);
  if(!VOS_IS_STATUS_SUCCESS(vStatus))
  {
    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"MPDU Header Push back fail"));
    vos_pkt_return_packet(vosDataBuff);
    *ppVosDataBuff = NULL;
    return VOS_STATUS_SUCCESS; /*Not a transport error*/ 
  }

  if (pClientSTA->drop_amsdu) {
         vos_pkt_return_packet(vosDataBuff);
         *ppVosDataBuff = NULL;
         return VOS_STATUS_SUCCESS;
  }

  /**
   * Set drop_amsdu flag and drop AMSDU subframe if
   * 1. AMSDU subframe header's DA is equal to LLC header or
   * 2. AMPDU header's DA is a broadcast address
   */
   if ((vos_mem_compare2(MPDUHeaderAMSDUHeader + ucMPDUHLen,
        llc_hdr, 6) == 0) ||
       (vos_mem_compare2(MPDUHeaderAMSDUHeader + 4, broadcast_addr, 6) == 0)) {
      pClientSTA->drop_amsdu = true;
      vos_pkt_return_packet(vosDataBuff);
      *ppVosDataBuff = NULL;
      VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                "WLAN TL:Invalid AMSDU frame - dropping");
      return VOS_STATUS_SUCCESS;
   }

  /* Find Padding and remove */
  vos_mem_copy(&subFrameLength, MPDUHeaderAMSDUHeader + ucMPDUHLen + WLANTL_AMSDU_SUBFRAME_LEN_OFFSET, sizeof(v_U16_t));
  subFrameLength = vos_be16_to_cpu(subFrameLength);
  paddingSize = usMPDULen - ucMPDUHLen - subFrameLength - TL_AMSDU_SUBFRM_HEADER_LEN;

  vos_pkt_get_packet_length(vosDataBuff, &packetLength);
  if((paddingSize > 0) && (paddingSize < packetLength))
  {
    /* There is padding bits, remove it */
    vos_pkt_trim_tail(vosDataBuff, paddingSize);
  }
  else if(0 == paddingSize)
  {
    /* No Padding bits */
    /* Do Nothing */
  }
  else
  {
    /* Padding size is larger than Frame size, Actually negative */
    /* Not a valid case, not a valid frame, drop it */
    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Padding Size is negative, no possible %d", paddingSize));
    vos_pkt_return_packet(vosDataBuff);
    *ppVosDataBuff = NULL;
    return VOS_STATUS_SUCCESS; /*Not a transport error*/ 
  }

  numAMSDUFrames++;
  if(0 == (numAMSDUFrames % 5000))
  {
    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"%u AMSDU frames arrived", numAMSDUFrames));
  }
  return VOS_STATUS_SUCCESS;
}/* WLANTL_AMSDUProcess */

/*==========================================================================
      Re-ordering module
  ==========================================================================*/

/*==========================================================================
  FUNCTION    WLANTL_MSDUReorder

  DESCRIPTION 
    MSDU reordering 

  DEPENDENCIES 
         
  PARAMETERS 

   IN
   
   vosDataBuff: vos packet for the received data
   pvBDHeader: pointer to the BD header
   ucSTAId:    Station ID 
      
  RETURN VALUE
    The result code associated with performing the operation  

    VOS_STATUS_SUCCESS:   Everything is good :)

  SIDE EFFECTS 
  
============================================================================*/
VOS_STATUS WLANTL_MSDUReorder
( 
   WLANTL_CbType    *pTLCb,
   vos_pkt_t        **vosDataBuff, 
   v_PVOID_t        pvBDHeader,
   v_U8_t           ucSTAId,
   v_U8_t           ucTid
)
{
   WLANTL_BAReorderType *currentReorderInfo;
   WLANTL_STAClientType *pClientSTA = NULL;
   vos_pkt_t            *vosPktIdx;
   v_U8_t               ucOpCode; 
   v_U8_t               ucSlotIdx;
   v_U8_t               ucFwdIdx;
   v_U16_t              CSN;
   v_U32_t              ucCIndexOrig;
   VOS_STATUS           status      = VOS_STATUS_SUCCESS;
   VOS_STATUS           lockStatus  = VOS_STATUS_SUCCESS; 
   VOS_STATUS           timerStatus = VOS_STATUS_SUCCESS; 
   VOS_TIMER_STATE      timerState;
   v_SIZE_t             rxFree;
   v_U64_t              ullreplayCounter = 0; /* 48-bit replay counter */
   v_U8_t               ac;
   v_U16_t              reorderTime;
   if((NULL == pTLCb) || (*vosDataBuff == NULL))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid ARG pTLCb 0x%pK, vosDataBuff 0x%pK",
                  pTLCb, *vosDataBuff));
      return VOS_STATUS_E_INVAL;
   }

   pClientSTA = pTLCb->atlSTAClients[ucSTAId];

   if ( NULL == pClientSTA )
   {
       TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
           "WLAN TL:Client Memory was not allocated on %s", __func__));
       return VOS_STATUS_E_FAILURE;
   }

   currentReorderInfo = &pClientSTA->atlBAReorderInfo[ucTid];

   lockStatus = vos_lock_acquire(&currentReorderInfo->reorderLock);
   if(!VOS_IS_STATUS_SUCCESS(lockStatus))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
      return lockStatus;
   }

   if( pClientSTA->atlBAReorderInfo[ucTid].ucExists == 0 )
   {
     vos_lock_release(&currentReorderInfo->reorderLock);
     return VOS_STATUS_E_INVAL;
   }
   ucOpCode  = (v_U8_t)WDA_GET_RX_REORDER_OPCODE(pvBDHeader);
   ucSlotIdx = (v_U8_t)WDA_GET_RX_REORDER_SLOT_IDX(pvBDHeader);
   ucFwdIdx  = (v_U8_t)WDA_GET_RX_REORDER_FWD_IDX(pvBDHeader);
   CSN       = (v_U16_t)WDA_GET_RX_REORDER_CUR_PKT_SEQ_NO(pvBDHeader);

   /* Replay check code : check whether replay check is needed or not */
   if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid)
   {
           /* Getting 48-bit replay counter from the RX BD */
           ullreplayCounter = WDA_DS_GetReplayCounter(pvBDHeader);
   }

#ifdef WLANTL_REORDER_DEBUG_MSG_ENABLE
   TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"opCode %d SI %d, FI %d, CI %d seqNo %d", ucOpCode, ucSlotIdx, ucFwdIdx, currentReorderInfo->ucCIndex, CSN));
#else
   TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"opCode %d SI %d, FI %d, CI %d seqNo %d", ucOpCode, ucSlotIdx, ucFwdIdx, currentReorderInfo->ucCIndex, CSN));
#endif

   // remember our current CI so that later we can tell if it advanced
   ucCIndexOrig = currentReorderInfo->ucCIndex;

   switch(ucOpCode)
   {
      case WLANTL_OPCODE_INVALID:
         /* Do nothing just pass through current frame */
         break;

      case WLANTL_OPCODE_QCUR_FWDBUF:
         if ((currentReorderInfo->LastSN > CSN) &&
              !(currentReorderInfo->set_data_filter))
         {
             if ((currentReorderInfo->LastSN - CSN) < CSN_WRAP_AROUND_THRESHOLD)
             {
                 //this frame is received after BA timer is expired, discard it
                 TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
                          "(QCUR_FWDBUF) dropping old frame, SN=%d LastSN=%d",
                          CSN, currentReorderInfo->LastSN));
                 if (vos_is_arp_pkt((*vosDataBuff)->pSkb, true))
                    vos_update_arp_rx_drop_reorder();

                 status = vos_pkt_return_packet(*vosDataBuff);
                 if (!VOS_IS_STATUS_SUCCESS(status))
                 {
                      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                             "(QCUR_FWDBUF) drop old frame fail %d", status));
                 }
                 *vosDataBuff = NULL;
                 lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
                 if (!VOS_IS_STATUS_SUCCESS(lockStatus))
                 {
                     TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                            "WLANTL_MSDUReorder, Release LOCK Fail"));
                     return lockStatus;
                 }
                 return status;
             }
         }
         currentReorderInfo->LastSN = CSN;
         if(0 == currentReorderInfo->pendingFramesCount)
         {
            //This frame will be fwd'ed to the OS. The next slot is the one we expect next
            currentReorderInfo->ucCIndex = (ucSlotIdx + 1) % currentReorderInfo->winSize;
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return status;
         }
         status = WLANTL_QueueCurrent(currentReorderInfo,
                                      vosDataBuff,
                                      ucSlotIdx);
         if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid)
         {
             WLANTL_FillReplayCounter(currentReorderInfo,
                               ullreplayCounter, ucSlotIdx);
         }
         if(VOS_STATUS_E_RESOURCES == status)
         {
            MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT,
                    currentReorderInfo->sessionID , ucOpCode ));

            /* This is the case slot index is already cycle one route, route all the frames Qed */
            vosPktIdx = NULL;
            status = WLANTL_ChainFrontPkts(ucFwdIdx,
                                           WLANTL_OPCODE_FWDALL_QCUR, 
                                           &vosPktIdx,
                                           currentReorderInfo,
                                           pTLCb);
            if(!VOS_IS_STATUS_SUCCESS(status))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make frame chain fail %d", status));
               lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
               if(!VOS_IS_STATUS_SUCCESS(lockStatus))
               {
                  TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
                  return lockStatus;
               }
               return status;
            }
            status = vos_pkt_chain_packet(vosPktIdx, *vosDataBuff, 1);
            *vosDataBuff = vosPktIdx;
            currentReorderInfo->pendingFramesCount = 0;
         }
         else
         {
            vosPktIdx = NULL;
            status = WLANTL_ChainFrontPkts(ucFwdIdx,
                                           WLANTL_OPCODE_QCUR_FWDBUF, 
                                           &vosPktIdx,
                                           currentReorderInfo,
                                           pTLCb);
            if(!VOS_IS_STATUS_SUCCESS(status))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make frame chain fail %d", status));
               lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
               if(!VOS_IS_STATUS_SUCCESS(lockStatus))
               {
                  TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
                  return lockStatus;
               }
               return status;
            }
            currentReorderInfo->ucCIndex = ucFwdIdx;
            *vosDataBuff = vosPktIdx;
         }
         break;

      case WLANTL_OPCODE_FWDBUF_FWDCUR:
         vosPktIdx = NULL;
         status = WLANTL_ChainFrontPkts(ucFwdIdx,
                                        WLANTL_OPCODE_FWDBUF_FWDCUR, 
                                        &vosPktIdx,
                                        currentReorderInfo,
                                        pTLCb);
         if(!VOS_IS_STATUS_SUCCESS(status))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make frame chain fail %d", status));
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return status;
         }

         if(NULL == vosPktIdx)
         {
            TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"Nothing to chain, just send current frame"));
         }
         else
         {
            status = vos_pkt_chain_packet(vosPktIdx, *vosDataBuff, 1);
            if(!VOS_IS_STATUS_SUCCESS(status))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make frame chain with CUR frame fail %d",
                           status));
               lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
               if(!VOS_IS_STATUS_SUCCESS(lockStatus))
               {
                  TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
                  return lockStatus;
               }
               return status;
            }
            *vosDataBuff = vosPktIdx;
         }
         //ucFwdIdx is the slot this packet supposes to take but there is a hole there
         //It looks that the chip will put the next packet into the slot ucFwdIdx.
         currentReorderInfo->ucCIndex = ucFwdIdx;
         break;

      case WLANTL_OPCODE_QCUR:
        if ((currentReorderInfo->LastSN > CSN) &&
            !(currentReorderInfo->set_data_filter))
        {
            if ((currentReorderInfo->LastSN - CSN) < CSN_WRAP_AROUND_THRESHOLD)
            {
                // this frame is received after BA timer is expired, so disard it
                TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
                                "(QCUR) dropping old frame, SN=%d LastSN=%d",
                                CSN, currentReorderInfo->LastSN));
                status = vos_pkt_return_packet(*vosDataBuff);
                if (!VOS_IS_STATUS_SUCCESS(status))
                {
                    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                               "*** (QCUR) drop old frame fail %d", status));
                }
                *vosDataBuff = NULL;
                lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
                if (!VOS_IS_STATUS_SUCCESS(lockStatus))
                {
                    TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                                   "WLANTL_MSDUReorder, Release LOCK Fail"));
                    return lockStatus;
                }
                return status;
            }
        }

         status = WLANTL_QueueCurrent(currentReorderInfo,
                                      vosDataBuff,
                                      ucSlotIdx);
           if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid)
           {
               WLANTL_FillReplayCounter(currentReorderInfo,
                                 ullreplayCounter, ucSlotIdx);
           }
         if(VOS_STATUS_E_RESOURCES == status)
         {
            MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT,
                                  currentReorderInfo->sessionID , ucOpCode ));

            /* This is the case slot index is already cycle one route, route all the frames Qed */
            vosPktIdx = NULL;
            status = WLANTL_ChainFrontPkts(ucFwdIdx,
                                           WLANTL_OPCODE_FWDALL_QCUR, 
                                           &vosPktIdx,
                                           currentReorderInfo,
                                           pTLCb);
            if(!VOS_IS_STATUS_SUCCESS(status))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make frame chain fail %d", status));
               lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
               if(!VOS_IS_STATUS_SUCCESS(lockStatus))
               {
                  TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
                  return lockStatus;
               }
               return status;
            }
            status = vos_pkt_chain_packet(vosPktIdx, *vosDataBuff, 1);
            *vosDataBuff = vosPktIdx;
            currentReorderInfo->pendingFramesCount = 0;
         }
         else
         {
            /* Since current Frame is Qed, no frame will be routed */
            *vosDataBuff = NULL; 
         }
         break;

      case WLANTL_OPCODE_FWDBUF_QUEUECUR:
         vosPktIdx = NULL;
         status = WLANTL_ChainFrontPkts(ucFwdIdx,
                                        WLANTL_OPCODE_FWDBUF_QUEUECUR, 
                                        &vosPktIdx,
                                        currentReorderInfo,
                                        pTLCb);
         if(!VOS_IS_STATUS_SUCCESS(status))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make chain with buffered frame fail %d",
                        status));
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return status;
         }
         //This opCode means the window shift. Enforce the current Index
         currentReorderInfo->ucCIndex = ucFwdIdx;

         status = WLANTL_QueueCurrent(currentReorderInfo,
                                      vosDataBuff,
                                      ucSlotIdx);
           if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid)
           {
               WLANTL_FillReplayCounter(currentReorderInfo,
                                 ullreplayCounter, ucSlotIdx);
           }
         if(VOS_STATUS_E_RESOURCES == status)
         {
            MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT,
                                   currentReorderInfo->sessionID , ucOpCode ));

            vos_pkt_return_packet(vosPktIdx); 
            /* This is the case slot index is already cycle one route, route all the frames Qed */
            vosPktIdx = NULL;
            status = WLANTL_ChainFrontPkts(ucFwdIdx,
                                           WLANTL_OPCODE_FWDALL_QCUR, 
                                           &vosPktIdx,
                                           currentReorderInfo,
                                           pTLCb);
            if(!VOS_IS_STATUS_SUCCESS(status))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make frame chain fail %d", status));
               lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
               if(!VOS_IS_STATUS_SUCCESS(lockStatus))
               {
                  TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
                  return lockStatus;
               }
               return status;
            }
            status = vos_pkt_chain_packet(vosPktIdx, *vosDataBuff, 1);
            *vosDataBuff = vosPktIdx;
            currentReorderInfo->pendingFramesCount = 0;
         }
         *vosDataBuff = vosPktIdx;
         break;

      case WLANTL_OPCODE_FWDBUF_DROPCUR:
         vosPktIdx = NULL;
         status = WLANTL_ChainFrontPkts(ucFwdIdx,
                                        WLANTL_OPCODE_FWDBUF_DROPCUR, 
                                        &vosPktIdx,
                                        currentReorderInfo,
                                        pTLCb);
         if(!VOS_IS_STATUS_SUCCESS(status))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make chain with buffered frame fail %d",
                        status));
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return status;
         }

         //Since BAR frame received, set the index to the right location
         currentReorderInfo->ucCIndex = ucFwdIdx;

         /* Current frame has to be dropped, BAR frame */
         status = vos_pkt_return_packet(*vosDataBuff);
         if(!VOS_IS_STATUS_SUCCESS(status))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Drop BAR frame fail %d",
                        status));
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return status;
         }
         *vosDataBuff = vosPktIdx;
         break;
 
      case WLANTL_OPCODE_FWDALL_DROPCUR:
         vosPktIdx = NULL;
         status = WLANTL_ChainFrontPkts(ucFwdIdx,
                                        WLANTL_OPCODE_FWDALL_DROPCUR, 
                                        &vosPktIdx,
                                        currentReorderInfo,
                                        pTLCb);
         if(!VOS_IS_STATUS_SUCCESS(status))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make chain with buffered frame fail %d",
                        status));
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return status;
         }

         //Since BAR frame received and beyond cur window, set the index to the right location
         currentReorderInfo->ucCIndex = 0;

         status = vos_pkt_return_packet(*vosDataBuff);
         if(!VOS_IS_STATUS_SUCCESS(status))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Drop BAR frame fail %d",
                        status));
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return status;
         }

         *vosDataBuff = vosPktIdx;
         break;

      case WLANTL_OPCODE_FWDALL_QCUR:
         vosPktIdx = NULL;
         status = WLANTL_ChainFrontPkts(currentReorderInfo->winSize,
                                        WLANTL_OPCODE_FWDALL_DROPCUR, 
                                        &vosPktIdx,
                                        currentReorderInfo,
                                        pTLCb);
         if(!VOS_IS_STATUS_SUCCESS(status))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make chain with buffered frame fail %d",
                        status));
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return status;
         }
         status = WLANTL_QueueCurrent(currentReorderInfo,
                                      vosDataBuff,
                                      ucSlotIdx);
           if(VOS_TRUE == pClientSTA->ucIsReplayCheckValid)
           {
               WLANTL_FillReplayCounter(currentReorderInfo,
                                 ullreplayCounter, ucSlotIdx);
           }

         if(VOS_STATUS_E_RESOURCES == status)
         {
             MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT,
                                   currentReorderInfo->sessionID , ucOpCode ));
         }

         if(!VOS_IS_STATUS_SUCCESS(status))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Q Current frame fail %d",
                        status));
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return status;
         }
         currentReorderInfo->ucCIndex = ucSlotIdx;
         *vosDataBuff = vosPktIdx;
         break;

      case WLANTL_OPCODE_TEARDOWN:
         // do we have a procedure in place to teardown BA?

         // fall through to drop the current packet
      case WLANTL_OPCODE_DROPCUR:
         vos_pkt_return_packet(*vosDataBuff);
         *vosDataBuff = NULL;
         break;

      default:
         break;
   }

   /* Check the available VOS RX buffer size
    * If remaining VOS RX buffer is too few, have to make space
    * Route all the Qed frames upper layer
    * Otherwise, RX thread could be stall */
   vos_pkt_get_available_buffer_pool(VOS_PKT_TYPE_RX_RAW, &rxFree);
   if(WLANTL_BA_MIN_FREE_RX_VOS_BUFFER >= rxFree)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, "RX Free: %d", rxFree));
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, "RX free buffer count is too low, Pending frame count is %d",
                  currentReorderInfo->pendingFramesCount));
      vosPktIdx = NULL;
      status = WLANTL_ChainFrontPkts(ucFwdIdx,
                                     WLANTL_OPCODE_FWDALL_DROPCUR, 
                                     &vosPktIdx,
                                     currentReorderInfo,
                                     pTLCb);
      if(!VOS_IS_STATUS_SUCCESS(status))
      {
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Make frame chain fail %d", status));
         lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
         if(!VOS_IS_STATUS_SUCCESS(lockStatus))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
            return lockStatus;
         }
         return status;
      }
      if(NULL != *vosDataBuff)
      {
         TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"Already something, Chain it"));
         vos_pkt_chain_packet(*vosDataBuff, vosPktIdx, 1);
      }
      else
      {
         *vosDataBuff = vosPktIdx;
      }
      currentReorderInfo->pendingFramesCount = 0;
   }

   /*
    * Current aging timer logic:
    * 1) if we forwarded any packets and the timer is running:
    *    stop the timer
    * 2) if there are packets queued and the timer is not running:
    *    start the timer
    * 3) if timer is running and no pending frame:
    *    stop the timer
    */
   timerState = vos_timer_getCurrentState(&currentReorderInfo->agingTimer);
   if ((VOS_TIMER_STATE_RUNNING == timerState) &&
       ((ucCIndexOrig != currentReorderInfo->ucCIndex) ||
        (0 == currentReorderInfo->pendingFramesCount)))
   {
      TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"HOLE filled, Pending Frames Count %d",
                 currentReorderInfo->pendingFramesCount));

      // we forwarded some packets so stop aging the current hole
      timerStatus = vos_timer_stop(&currentReorderInfo->agingTimer);
      timerState = VOS_TIMER_STATE_STOPPED;

      // ignore the returned status since there is a race condition
      // whereby between the time we called getCurrentState() and the
      // time we call stop() the timer could have fired.  In that case
      // stop() will return an error, but we don't care since the
      // timer has stopped
   }

   if (currentReorderInfo->pendingFramesCount > 0)
   {
      if (VOS_TIMER_STATE_STOPPED == timerState)
      {
         TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"There is a new HOLE, Pending Frames Count %d",
                    currentReorderInfo->pendingFramesCount));
         ac = WLANTL_TID_2_AC[ucTid];
         if (WLANTL_AC_INVALID(ac))
         {
             reorderTime = WLANTL_BA_REORDERING_AGING_TIMER;
             TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid AC %d using default reorder time %d",
                              ac, reorderTime));
         }
         else
         {
             reorderTime = pTLCb->tlConfigInfo.ucReorderAgingTime[ac];
         }
         timerStatus = vos_timer_start(&currentReorderInfo->agingTimer,
                                       reorderTime);
         if(!VOS_IS_STATUS_SUCCESS(timerStatus))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Timer start fail: %d", timerStatus));
            lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
            if(!VOS_IS_STATUS_SUCCESS(lockStatus))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
               return lockStatus;
            }
            return timerStatus;
         }
      }
      else
      {
         // we didn't forward any packets and the timer was already
         // running so we're still aging the same hole
         TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"Still HOLE, Pending Frames Count %d",
                    currentReorderInfo->pendingFramesCount));
      }
   }

   lockStatus = vos_lock_release(&currentReorderInfo->reorderLock);
   if(!VOS_IS_STATUS_SUCCESS(lockStatus))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_MSDUReorder, Release LOCK Fail"));
      return lockStatus;
   }
   return VOS_STATUS_SUCCESS;
}/* WLANTL_MSDUReorder */


/*==========================================================================
     Utility functions 
  ==========================================================================*/

/*==========================================================================

  FUNCTION    WLANTL_QueueCurrent

  DESCRIPTION 
    It will queue a packet at a given slot index in the MSDU reordering list. 
    
  DEPENDENCIES 
    
  PARAMETERS 

    IN
    pwBaReorder:   pointer to the BA reordering session info 
    vosDataBuff:   data buffer to be queued
    ucSlotIndex:   slot index 
   
  RETURN VALUE
    The result code associated with performing the operation  

    VOS_STATUS_SUCCESS:     Everything is OK

    
  SIDE EFFECTS 
  
============================================================================*/
VOS_STATUS WLANTL_QueueCurrent
(
   WLANTL_BAReorderType*  pwBaReorder,
   vos_pkt_t**            vosDataBuff,
   v_U8_t                 ucSlotIndex
)
{
   VOS_STATUS  status = VOS_STATUS_SUCCESS;

   TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"vos Packet has to be Qed 0x%pK",
               *vosDataBuff));
   if(NULL != pwBaReorder->reorderBuffer->arrayBuffer[ucSlotIndex])
   {
      MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT,
                      pwBaReorder->sessionID , pwBaReorder->pendingFramesCount ));

      MTRACE(vos_trace(VOS_MODULE_ID_TL, TRACE_CODE_TL_QUEUE_CURRENT,
                                        pwBaReorder->sessionID , ucSlotIndex ));

      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"One Cycle rounded, lost many frames already, not in Q %d",
                  pwBaReorder->pendingFramesCount));
      return VOS_STATUS_E_RESOURCES;
   }

   pwBaReorder->reorderBuffer->arrayBuffer[ucSlotIndex] =
                                           (v_PVOID_t)(*vosDataBuff);
   pwBaReorder->pendingFramesCount++;
   TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"Assigned, Pending Frames %d at slot %d, dataPtr 0x%x",
               pwBaReorder->pendingFramesCount,
               ucSlotIndex,
               pwBaReorder->reorderBuffer->arrayBuffer[ucSlotIndex]));

   return status;
}/*WLANTL_QueueCurrent*/

/*==========================================================================

  FUNCTION    WLANTL_ChainFrontPkts

  DESCRIPTION 
    It will remove all the packets from the front of a vos list and chain 
    them to a vos pkt . 
    
  DEPENDENCIES 
    
  PARAMETERS 

    IN
    ucCount:       number of packets to extract
    pwBaReorder:   pointer to the BA reordering session info 

    OUT
    vosDataBuff:   data buffer containing the extracted chain of packets
   
  RETURN VALUE
    The result code associated with performing the operation  

    VOS_STATUS_SUCCESS:     Everything is OK

    
  SIDE EFFECTS 
  
============================================================================*/
VOS_STATUS WLANTL_ChainFrontPkts
( 
   v_U32_t                fwdIndex,
   v_U8_t                 opCode,
   vos_pkt_t              **vosDataBuff,
   WLANTL_BAReorderType   *pwBaReorder,
   WLANTL_CbType          *pTLCb
)
{
   VOS_STATUS          status = VOS_STATUS_SUCCESS;
   v_U32_t             idx; 
   v_PVOID_t           currentDataPtr = NULL;
   int                 negDetect;
#ifdef WLANTL_REORDER_DEBUG_MSG_ENABLE
#define WLANTL_OUT_OF_WINDOW_IDX    65
   v_U32_t frameIdx[2] = {0, 0}, ffidx = fwdIndex, idx2 = WLANTL_OUT_OF_WINDOW_IDX;
   int pending = pwBaReorder->pendingFramesCount, start = WLANTL_OUT_OF_WINDOW_IDX, end;
#endif

   if(pwBaReorder->ucCIndex >= fwdIndex)
   {
      fwdIndex += pwBaReorder->winSize;
   }

   if((WLANTL_OPCODE_FWDALL_DROPCUR == opCode) ||
      (WLANTL_OPCODE_FWDALL_QCUR == opCode))
   {
      fwdIndex = pwBaReorder->ucCIndex + pwBaReorder->winSize;
   }

   TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"Current Index %d, FWD Index %d, reorderBuffer 0x%pK",
               pwBaReorder->ucCIndex % pwBaReorder->winSize,
               fwdIndex % pwBaReorder->winSize,
               pwBaReorder->reorderBuffer));

   negDetect = pwBaReorder->pendingFramesCount;
   for(idx = pwBaReorder->ucCIndex; idx <= fwdIndex; idx++)
   {
      currentDataPtr = 
      pwBaReorder->reorderBuffer->arrayBuffer[idx % pwBaReorder->winSize];
      if(NULL != currentDataPtr)
      {
#ifdef WLANTL_REORDER_DEBUG_MSG_ENABLE
         idx2 = (idx >=  pwBaReorder->winSize) ? (idx -  pwBaReorder->winSize) : idx;
         frameIdx[idx2 / 32] |= 1 << (idx2 % 32);
         if(start == WLANTL_OUT_OF_WINDOW_IDX) start = idx2;
#endif
         TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"There is buffered frame %d",
                     idx % pwBaReorder->winSize));
         if(NULL == *vosDataBuff)
         {
            *vosDataBuff = (vos_pkt_t *)currentDataPtr;
            TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"This is new head %d",
                        idx % pwBaReorder->winSize));
         }
         else
         {
            TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"There is bufered Just add %d",
                        idx % pwBaReorder->winSize));
            vos_pkt_chain_packet(*vosDataBuff,
                                 (vos_pkt_t *)currentDataPtr,
                                 VOS_TRUE);
         }
         pwBaReorder->reorderBuffer->arrayBuffer[idx  % pwBaReorder->winSize]
                                                                       = NULL;
         pwBaReorder->pendingFramesCount--;
         negDetect--;
         if(negDetect < 0)
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"This is not possible, some balance has problem"));
            VOS_ASSERT(0);
            return VOS_STATUS_E_FAULT;
         }
         TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"Slot Index %d, set as NULL, Pending Frames %d",
                     idx  % pwBaReorder->winSize,
                     pwBaReorder->pendingFramesCount
                     ));
         pwBaReorder->ucCIndex = (idx + 1) % pwBaReorder->winSize;
      }
      else
      {
         TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"Empty Array %d",
                     idx % pwBaReorder->winSize));
      }
      TLLOG4(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_LOW,"Current Index %d, winSize %d",
                  pwBaReorder->ucCIndex,
                  pwBaReorder->winSize
                  ));
   }

#ifdef WLANTL_REORDER_DEBUG_MSG_ENABLE
   end = idx2;

   TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Fwd 0x%08X-%08X opCode %d fwdIdx %d windowSize %d pending frame %d fw no. %d from idx %d to %d",
                     frameIdx[1], frameIdx[0], opCode, ffidx, pwBaReorder->winSize, pending, pending - negDetect, start, end));
#endif

   return status; 
}/*WLANTL_ChainFrontPkts*/
/*==========================================================================
 
  FUNCTION    WLANTL_FillReplayCounter
 
  DESCRIPTION 
    It will fill repaly counter at a given slot index in the MSDU reordering list. 
            
  DEPENDENCIES 
                    
  PARAMETERS 

  IN
      pwBaReorder  :   pointer to the BA reordering session info 
      replayCounter:   replay counter to be filled
      ucSlotIndex  :   slot index 
                                      
  RETURN VALUE
     NONE 

                                                 
  SIDE EFFECTS 
     NONE
        
 ============================================================================*/
void WLANTL_FillReplayCounter
(
   WLANTL_BAReorderType*  pwBaReorder,
   v_U64_t                ullreplayCounter,
   v_U8_t                 ucSlotIndex
)
{

   //BAMSGDEBUG("replay counter to be filled in Qed frames %llu",
               //replayCounter, 0, 0);

   pwBaReorder->reorderBuffer->ullReplayCounter[ucSlotIndex] = ullreplayCounter;
   //BAMSGDEBUG("Assigned, replay counter Pending Frames %d at slot %d, replay counter[0x%llX]\n",
               //pwBaReorder->pendingFramesCount,
               //ucSlotIndex,
               //pwBaReorder->reorderBuffer->ullReplayCounter);
   return;
}/*WLANTL_FillReplayCounter*/

void WLANTL_ReorderReplayCheck(WLANTL_STAClientType *pClientSTA,
                               vos_pkt_t **vosDataBuff, v_U8_t ucTid)
{
   vos_pkt_t *pVosCurPkt;
   vos_pkt_t *pNextVosPkt;
   vos_pkt_t *pVosHeadPkt = NULL;
   vos_pkt_t *pfreeVosPkt = NULL;
   v_U64_t   prevReplayCounter = 0;
   v_BOOL_t status;

   pVosCurPkt = *vosDataBuff;

   do {
      vos_pkt_walk_packet_chain(pVosCurPkt, &pNextVosPkt, VOS_FALSE);
      prevReplayCounter = pClientSTA->ullReplayCounter[ucTid];
      status =  WLANTL_IsReplayPacket(pVosCurPkt->pn_num,
                                      prevReplayCounter);
      if(VOS_FALSE == status) {
         pClientSTA->ullReplayCounter[ucTid] = pVosCurPkt->pn_num;
         pVosHeadPkt = pVosCurPkt;
      } else {
         VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                   "%s: Non-AMSDU Drop the replay packet PN: [0x%llX]",
                   __func__, pVosCurPkt->pn_num);
         pClientSTA->ulTotalReplayPacketsDetected++;

         pfreeVosPkt = pVosCurPkt;
         pfreeVosPkt->pNext = NULL;
         vos_pkt_return_packet(pfreeVosPkt);

         if (pVosHeadPkt != NULL) {
            pVosHeadPkt->pNext = pNextVosPkt;
         }
         else {
            *vosDataBuff = pNextVosPkt;
         }
      }

      pVosCurPkt = pNextVosPkt;
   } while (pVosCurPkt);
}
