blob: a15597e7744ed15e129661882afbe1d78d75940d [file] [log] [blame]
/*
* Copyright (c) 2012, 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.
*/
/*===========================================================================
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.
Copyright (c) 2008 QUALCOMM Incorporated.
All Rights Reserved.
Qualcomm Confidential and Proprietary
===========================================================================*/
/*===========================================================================
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 "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 */
/*==========================================================================
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;
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;
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
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;
}
ReorderInfo = &pTLHandle->atlSTAClients[ucSTAID].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 == pTLHandle->atlSTAClients[ucSTAID].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( pTLHandle->atlSTAClients[ucSTAID].atlBAReorderInfo[ucTID].ucExists == 0 )
{
vos_lock_release(&ReorderInfo->reorderLock);
return;
}
opCode = WLANTL_OPCODE_FWDALL_DROPCUR;
vosDataBuff = NULL;
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;
}
#ifdef ANI_CHIPSET_VOLANS
/* Do replay check before giving packets to upper layer
replay check code : check whether replay check is needed or not */
if(VOS_TRUE == pTLHandle->atlSTAClients[ucSTAID].ucIsReplayCheckValid)
{
v_U64_t ullpreviousReplayCounter = 0;
v_U64_t ullcurrentReplayCounter = 0;
v_U8_t ucloopCounter = 0;
v_BOOL_t status = 0;
/*Do replay check for all packets which are in Reorder buffer */
for(ucloopCounter = 0; ucloopCounter < WLANTL_MAX_WINSIZE; ucloopCounter++)
{
/*Get previous reply counter*/
ullpreviousReplayCounter = pTLHandle->atlSTAClients[ucSTAID].ullReplayCounter[ucTID];
/*Get current replay counter of packet in reorder buffer*/
ullcurrentReplayCounter = ReorderInfo->reorderBuffer->ullReplayCounter[ucloopCounter];
/*Check for holes, if a hole is found in Reorder buffer then
no need to do replay check on it, skip the current
hole and do replay check on other packets*/
if(NULL != (ReorderInfo->reorderBuffer->arrayBuffer[ucloopCounter]))
{
status = WLANTL_IsReplayPacket(ullcurrentReplayCounter, ullpreviousReplayCounter);
if(VOS_TRUE == status)
{
/*Increment the debug counter*/
pTLHandle->atlSTAClients[ucSTAID].ulTotalReplayPacketsDetected++;
/*A replay packet found*/
VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
"WLANTL_ReorderingAgingTimerExpierCB: total dropped replay packets on STA ID %X is [0x%lX]\n",
ucSTAID, pTLHandle->atlSTAClients[ucSTAID].ulTotalReplayPacketsDetected);
VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
"WLANTL_ReorderingAgingTimerExpierCB: replay packet found with PN : [0x%llX]\n",
ullcurrentReplayCounter);
VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
"WLANTL_ReorderingAgingTimerExpierCB: Drop the replay packet with PN : [0x%llX]\n",
ullcurrentReplayCounter);
ReorderInfo->reorderBuffer->arrayBuffer[ucloopCounter] = NULL;
ReorderInfo->reorderBuffer->ullReplayCounter[ucloopCounter] = 0;
}
else
{
/*Not a replay packet update previous replay counter*/
pTLHandle->atlSTAClients[ucSTAID].ullReplayCounter[ucTID] = ullcurrentReplayCounter;
}
}
else
{
/* A hole detected in Reorder buffer*/
//BAMSGERROR("WLANTL_ReorderingAgingTimerExpierCB,hole detected\n",0,0,0);
}
}
}
#endif
status = WLANTL_ChainFrontPkts(fwIdx, opCode,
&vosDataBuff, ReorderInfo, NULL);
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 == pTLHandle->atlSTAClients[ucSTAID].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;
}
#ifdef WLAN_SOFTAP_FEATURE
if( WLAN_STA_SOFTAP == pTLHandle->atlSTAClients[ucSTAID].wSTADesc.wSTAType)
{
WLANTL_FwdPktToHDD( expireHandle->pAdapter, vosDataBuff, ucSTAID);
}
else
#endif
{
wRxMetaInfo.ucUP = ucTID;
pTLHandle->atlSTAClients[ucSTAID].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", __FUNCTION__));
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;
#ifdef ANI_CHIPSET_VOLANS
pTLCb->reorderBufferPool[idx].ullReplayCounter[pIdx] = 0;
#endif
}
}
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_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;
}
if ( 0 == pTLCb->atlSTAClients[ucSTAId].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;
}
/*------------------------------------------------------------------------
Verify that BA session was not already added
------------------------------------------------------------------------*/
if ( 0 != pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].ucExists )
{
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].ucExists++;
VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
"WLAN TL:BA session already exists on WLANTL_BaSessionAdd");
return VOS_STATUS_E_EXISTS;
}
/*------------------------------------------------------------------------
Initialize new BA session
------------------------------------------------------------------------*/
reorderInfo = &pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid];
for(idx = 0; idx < WLANTL_MAX_BA_SESSION; idx++)
{
if(VOS_TRUE == pTLCb->reorderBufferPool[idx].isAvailable)
{
pTLCb->atlSTAClients[ucSTAId].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%p",
idx,
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].reorderBuffer
));
break;
}
}
#ifdef WLAN_SOFTAP_FEATURE
if( WLAN_STA_SOFTAP == pTLCb->atlSTAClients[ucSTAId].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 \n");
return VOS_STATUS_E_NOSUPPORT;
}
}
#endif
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,"Timer Init Fail"));
return status;
}
/* Reorder LOCK
* During handle normal RX frame, if timer sxpier, abnormal race condition happen
* Frames should be protected from double handle */
status = vos_lock_init(&reorderInfo->reorderLock);
if(!VOS_IS_STATUS_SUCCESS(status))
{
TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Lock Init Fail"));
return status;
}
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].ucExists++;
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].usCount = 0;
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].ucCIndex = 0;
if(0 == winSize)
{
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].winSize =
WLANTL_MAX_WINSIZE;
}
else
{
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].winSize = winSize;
}
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].SSN = SSN;
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].sessionID = sessionID;
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].pendingFramesCount = 0;
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));
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;
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;
tANI_U8 lockRetryCnt = 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;
}
if (( 0 == pTLCb->atlSTAClients[ucSTAId].ucExists ) &&
( 0 == pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].ucExists ))
{
VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
"WLAN TL:Station was not yet registered on WLANTL_BaSessionDel");
return VOS_STATUS_E_EXISTS;
}
else if(( 0 == pTLCb->atlSTAClients[ucSTAId].ucExists ) &&
( 0 != pTLCb->atlSTAClients[ucSTAId].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 = &pTLCb->atlSTAClients[ucSTAId].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 == pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].ucExists )
{
VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
"WLAN TL:BA session does not exists on WLANTL_BaSessionDel");
return VOS_STATUS_E_EXISTS;
}
/*------------------------------------------------------------------------
Send all pending packets to HDD
------------------------------------------------------------------------*/
reOrderInfo = &pTLCb->atlSTAClients[ucSTAId].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\n", __FUNCTION__));
return lockStatus;
}
pTLCb->atlSTAClients[ucSTAId].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 ));
#ifdef WLAN_SOFTAP_FEATURE
if ( WLAN_STA_SOFTAP == pTLCb->atlSTAClients[ucSTAId].wSTADesc.wSTAType )
{
WLANTL_FwdPktToHDD( pvosGCtx, vosDataBuff, ucSTAId);
}
else
#endif
{
wRxMetaInfo.ucUP = ucTid;
pTLCb->atlSTAClients[ucSTAId].pfnSTARx( pvosGCtx, vosDataBuff, ucSTAId,
&wRxMetaInfo );
}
}
vos_lock_release(&reOrderInfo->reorderLock);
/*------------------------------------------------------------------------
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", vosStatus));
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
------------------------------------------------------------------------*/
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].usCount = 0;
pTLCb->atlSTAClients[ucSTAId].atlBAReorderInfo[ucTid].ucCIndex = 0;
reOrderInfo->winSize = 0;
reOrderInfo->SSN = 0;
reOrderInfo->sessionID = 0;
while (vos_lock_destroy(&reOrderInfo->reorderLock) == VOS_STATUS_E_BUSY)
{
if( lockRetryCnt > 2)
{
TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
"Unable to destroy reorderLock\n"));
break;
}
vos_sleep(1);
lockRetryCnt++;
}
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;
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;
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 = 0;
vos_pkt_t* vosDataBuff;
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/*------------------------------------------------------------------------
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;
}
/*------------------------------------------------------------------------
Check frame
------------------------------------------------------------------------*/
ucAef = (v_U8_t)WDA_GET_RX_AEF( pvBDHeader );
ucFsf = (v_U8_t)WDA_GET_RX_ESF( pvBDHeader );
#ifndef FEATURE_WLAN_INTEGRATED_SOC
MPDUDataOffset = (v_U16_t)WDA_GET_RX_MPDU_DATA_OFFSET(pvBDHeader) - WLANHAL_RX_BD_HEADER_SIZE;
#else
/* On Prima, MPDU data offset not includes BD header size */
MPDUDataOffset = (v_U16_t)WDA_GET_RX_MPDU_DATA_OFFSET(pvBDHeader);
#endif /* FEATURE_WLAN_INTEGRATED_SOC */
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
*/
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*/
}
pTLCb->atlSTAClients[ucSTAId].ucMPDUHeaderLen = ucMPDUHLen;
memcpy(pTLCb->atlSTAClients[ucSTAId].aucMPDUHeader, MPDUHeaderAMSDUHeader, ucMPDUHLen);
/* AMSDU header stored to handle gabage data within next frame */
}
else
{
/* Trim gabage, 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, pTLCb->atlSTAClients[ucSTAId].aucMPDUHeader, pTLCb->atlSTAClients[ucSTAId].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*/
}
/* Find Padding and remove */
memcpy(&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,"%lu 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;
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;
#ifdef ANI_CHIPSET_VOLANS
v_U64_t ullreplayCounter = 0; /* 48-bit replay counter */
#endif
if((NULL == pTLCb) || (*vosDataBuff == NULL))
{
TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid ARG pTLCb 0x%p, vosDataBuff 0x%p",
pTLCb, *vosDataBuff));
return VOS_STATUS_E_INVAL;
}
currentReorderInfo = &pTLCb->atlSTAClients[ucSTAId].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( pTLCb->atlSTAClients[ucSTAId].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);
#ifdef WLANTL_HAL_VOLANS
/* Replay check code : check whether replay check is needed or not */
if(VOS_TRUE == pTLCb->atlSTAClients[ucSTAId].ucIsReplayCheckValid)
{
/* Getting 48-bit replay counter from the RX BD */
ullreplayCounter = WDA_DS_GetReplayCounter(aucBDHeader);
}
#endif
#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(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);
#ifdef ANI_CHIPSET_VOLANS
if(VOS_TRUE == pTLCb->atlSTAClients[ucSTAId].ucIsReplayCheckValid)
{
WLANTL_FillReplayCounter(currentReorderInfo,
ullreplayCounter, ucSlotIdx);
}
#endif
if(VOS_STATUS_E_RESOURCES == status)
{
/* 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;
}
*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\n"));
}
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:
status = WLANTL_QueueCurrent(currentReorderInfo,
vosDataBuff,
ucSlotIdx);
#ifdef ANI_CHIPSET_VOLANS
if(VOS_TRUE == pTLCb->atlSTAClients[ucSTAId].ucIsReplayCheckValid)
{
WLANTL_FillReplayCounter(currentReorderInfo,
ullreplayCounter, ucSlotIdx);
}
#endif
if(VOS_STATUS_E_RESOURCES == status)
{
/* 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);
#ifdef ANI_CHIPSET_VOLANS
if(VOS_TRUE == pTLCb->atlSTAClients[ucSTAId].ucIsReplayCheckValid)
{
WLANTL_FillReplayCounter(currentReorderInfo,
ullreplayCounter, ucSlotIdx);
}
#endif
if(VOS_STATUS_E_RESOURCES == status)
{
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);
#ifdef ANI_CHIPSET_VOLANS
if(VOS_TRUE == pTLCb->atlSTAClients[ucSTAId].ucIsReplayCheckValid)
{
WLANTL_FillReplayCounter(currentReorderInfo,
ullreplayCounter, ucSlotIdx);
}
#endif
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_ERROR,"RX Free", rxFree));
TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"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
*/
timerState = vos_timer_getCurrentState(&currentReorderInfo->agingTimer);
if ((VOS_TIMER_STATE_RUNNING == timerState) &&
(ucCIndexOrig != currentReorderInfo->ucCIndex))
{
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));
timerStatus = vos_timer_start(&currentReorderInfo->agingTimer,
WLANTL_BA_REORDERING_AGING_TIMER);
if(!VOS_IS_STATUS_SUCCESS(timerStatus))
{
TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Timer start fail", 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%p",
*vosDataBuff));
if(NULL != pwBaReorder->reorderBuffer->arrayBuffer[ucSlotIndex])
{
TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"One Cycle rounded, lost many frames already, not in Q %d\n",
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%p",
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\n"));
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*/
#ifdef ANI_CHIPSET_VOLANS
/*==========================================================================
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*/
#endif /*End of #ifdef WLANTL_HAL_VOLANS*/