| /* |
| * 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; |
| /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ |
| /*------------------------------------------------------------------------ |
| 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 */ |
| } |
| 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*/ |
| } |
| |
| /* 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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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(¤tReorderInfo->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); |
| } |