/* * RxQueue.c * * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Texas Instruments nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** \file RxQueue.c * \brief RX Queue module that responsible to support re-ordering of received packets to upper layers. * * \see RxQueue.h */ #define __FILE_ID__ FILE_ID_98 #include "tidef.h" #include "osApi.h" #include "report.h" #include "RxBuf.h" #include "TWDriver.h" #include "public_descriptors.h" /************************ static definition declaration *****************************/ #define RX_QUEUE_ARRAY_SIZE 8 #define RX_QUEUE_ARRAY_SIZE_BIT_MASK 0x7 /* RX_QUEUE_ARRAY_SIZE -1 */ #define RX_QUEUE_WIN_SIZE RX_QUEUE_ARRAY_SIZE #define BA_SESSION_IS_A_BIGGER_THAN_B(A,B) (((((A)-(B)) & 0xFFF) < 0x7FF) && ((A)!=(B))) #define BA_SESSION_IS_A_BIGGER_EQUAL_THAN_B(A,B) (((((A)-(B)) & 0xFFF) < 0x7FF)) #define SEQ_NUM_WRAP 0x1000 #define SEQ_NUM_MASK 0xFFF /************************ static structures declaration *****************************/ /* structure describe one entry of save packet information in the packet queue array */ typedef struct { void *pPacket; /* Packet address of the packet */ TI_STATUS tStatus; /* RxXfer status. */ TI_UINT16 uFrameSn; } TRxQueuePacketEntry; /* structure describe set of data that one Tid, also including the arras himself */ typedef struct { /* array packets Entries */ TRxQueuePacketEntry aPaketsQueue [RX_QUEUE_ARRAY_SIZE]; /* TID BA state */ TI_BOOL aTidBaEstablished; /* index that winStar point on */ TI_UINT32 aWinStartArrayInex; /* windows size */ TI_UINT32 aTidWinSize; /* expected sequence number (ESN) */ TI_UINT16 aTidExpectedSn; } TRxQueueTidDataBase; /* structure describe set of data that assist of manage one SA RxQueue arrays */ typedef struct { TRxQueueTidDataBase tSa1ArrayMng [MAX_NUM_OF_802_1d_TAGS]; } TRxQueueArraysMng; /* main RxQueue structure in order to management the packets disordered array. */ typedef struct { TI_HANDLE hOs; /* OS handler */ TI_HANDLE hReport; /* Report handler */ TRxQueueArraysMng tRxQueueArraysMng; /* manage each Source Address RxQueue arrays */ TPacketReceiveCb tReceivePacketCB; /* Receive packets CB address */ TI_HANDLE hReceivePacketCB_handle; /* Receive packets CB handler */ } TRxQueue; /************************ static function declaration *****************************/ static TI_STATUS RxQueue_PassPacket (TI_HANDLE hRxQueue, TI_STATUS tStatus, const void *pBuffer); /** * \fn RxQueue_Create() * \brief Create the RxQueue module. * * Allocate and clear the RxQueue module object. * * \param hOs - Handle to Os Abstraction Layer * \return Handle of the allocated object * \sa RxQueue_Destroy */ TI_HANDLE RxQueue_Create (TI_HANDLE hOs) { TRxQueue *pRxQueue; /* allocate module object */ pRxQueue = os_memoryAlloc (hOs, sizeof(TRxQueue)); if (!pRxQueue) { WLAN_OS_REPORT (("RxQueue_Create(): Allocation failed!!\n")); return NULL; } os_memoryZero (hOs, pRxQueue, (sizeof(TRxQueue))); pRxQueue->hOs = hOs; return (pRxQueue); } /** * \fn RxQueue_Destroy() * \brief Destroy the module. * * Free the module's queues and object. * * \param hRxQueue - The module object * \return TI_OK on success or TI_NOK on failure * \sa RxQueue_Create */ TI_STATUS RxQueue_Destroy (TI_HANDLE hRxQueue) { TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; /* free module object */ os_memoryFree (pRxQueue->hOs, pRxQueue, sizeof(TRxQueue)); return TI_OK; } /** * \fn RxQueue_Init() * \brief Init required handles * * Init required handles and module variables. * * \note * \param hRxQueue - The module object * \param hReport - Report module Handles * \return TI_OK on success or TI_NOK on failure * \sa */ TI_STATUS RxQueue_Init (TI_HANDLE hRxQueue, TI_HANDLE hReport) { TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; pRxQueue->hReport = hReport; return TI_OK; } /** * \fn RxQueue_Register_CB() * \brief Register the function to be called for received Rx. * * \note * \param hRxQueue - The module object * \param CallBackID - event ID * \param CBFunc - function address. * \param CBObj - function parameter. * \return TI_OK on success or TI_NOK on failure * \sa */ void RxQueue_Register_CB (TI_HANDLE hRxQueue, TI_UINT32 uCallBackID, void *CBFunc, TI_HANDLE CBObj) { TRxQueue* pRxQueue = (TRxQueue *)hRxQueue; TRACE1(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION , "RxQueue_Register_CB: CallBack ID = 0x%x\n", uCallBackID); switch(uCallBackID) { case TWD_INT_RECEIVE_PACKET: pRxQueue->tReceivePacketCB = (TPacketReceiveCb)CBFunc; pRxQueue->hReceivePacketCB_handle = CBObj; break; default: TRACE0(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_Register_CB: Illegal value\n"); break; } } /** * \fn RxQueue_CloseBaSession () * \brief Close BA session receiver and pass all packets in the TID queue to upper layer. * * \note * \param hRxQueue - RxQueue handle. * \param uFrameTid - TID session. * \return None * \sa */ void RxQueue_CloseBaSession(TI_HANDLE hRxQueue, TI_UINT8 uFrameTid) { TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; TI_UINT32 i; /*set the SA Tid pointer */ TRxQueueTidDataBase *pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); /* TID illegal value ? */ if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_CloseBaSession: BA event - DELBA frame with TID value too big, TID = %d\n", uFrameTid); return; } if(pTidDataBase->aTidBaEstablished == TI_TRUE) { /* clean BA session */ pTidDataBase->aTidBaEstablished = TI_FALSE; /* pass all valid entries at the array */ for (i = 0; (i < RX_QUEUE_ARRAY_SIZE) && (i < RX_QUEUE_WIN_SIZE); i++) { if (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) { RxQueue_PassPacket (pRxQueue, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; } pTidDataBase->aWinStartArrayInex ++; /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; } } } /** * \fn RxQueue_PassPacket() * \brief Responsible on decode packet parameters and pass it to upper layer. * * \note * \param hRxQueue - RxQueue handle. * \param aStatus - RxXfer status that indicate if the upper layer should free the packet or use it. * \param pFrame - paket address of the packet * \param pRxParams - address to structure of the Rx Descriptor received by FW. * \return TI_OK on success or TI_NOK on failure * \sa */ static TI_STATUS RxQueue_PassPacket (TI_HANDLE hRxQueue, TI_STATUS tStatus, const void *pBuffer) { TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; if (tStatus == TI_OK) { /* Get the mac header location in the packet Buffer */ dot11_header_t *pMacHdr = (dot11_header_t *)(TI_UINT8*)RX_BUF_DATA(pBuffer); /* Handle endian for the frame control fields */ pMacHdr->fc = ENDIAN_HANDLE_WORD(pMacHdr->fc); pMacHdr->duration = ENDIAN_HANDLE_WORD(pMacHdr->duration); pMacHdr->seqCtrl = ENDIAN_HANDLE_WORD(pMacHdr->seqCtrl); } else { RxIfDescriptor_t *pRxParams = (RxIfDescriptor_t*)pBuffer; pRxParams->status &= ~RX_DESC_STATUS_MASK; pRxParams->status |= RX_DESC_STATUS_DRIVER_RX_Q_FAIL; } TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION , "RxQueue_PassPacket: call TWD_OWNER_RX_QUEUE CB. In std rxData_ReceivePacket()\n"); /* Set the packet to upper layer */ /* if the packet status not success it will be discarded */ pRxQueue->tReceivePacketCB (pRxQueue->hReceivePacketCB_handle, pBuffer); return TI_OK; } /** * \fn RxQueue_ReceivePacket() * \brief Main function of the RxQueue module. * Responsible on reorder of the packets from the RxXfer to the RX module. * Call from RxXfer in order to pass packet to uppers layers. * In order to save disordered packets the module use array of structures per TID * that each entry describe a packet. The array elements is sorted in the way that * the winStart array index represent always the winStar packet and the lowest SN. * Each increment index represent index at the BA window. Array index winEnd always * represent winEnd packet. The indexes of winStart and winEnd handled in cyclic manner. * The function functionality devided to parts: * Part 1: * in case the modulo receive packet with SN equal to winStart: * " pass it to upper layers * " increases winStart and array index winStart * " validate that all sequential queue packet are pass to the upper layers. * Part 2: * in case the modulo receive packet that SN between winStart to winEnd: * " Save it sorted at the array at index: Save index = ((SN - winStart) + index array winStart) % arraySize. * Part 3: * in case the modulo receive packet that SN higher then winEnd: * " Update winStart and WinEnd. * " Save it sorted at the array in index winEnd index. * " Pass to the upper layers all packets at the array indexes from old winStart index to the updated winStart index. * Part 4 + 5: * in case the modulo receive BA event packet: * " Update winStart and WinEnd * " Pass to the upper layers all packets at the array indexes from old winStart index to the updated winStart index. * " Free BA event packet via pass it to upper layers with error status. * * \note * \param hRxQueue - RxQueue handle. * \param aStatus - RxXfer status that indicate if the upper layer should free the packet or use it. * \param pBuffer - paket address of the packet * \return None * \sa */ void RxQueue_ReceivePacket (TI_HANDLE hRxQueue, const void * pBuffer) { TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; RxIfDescriptor_t *pRxParams = (RxIfDescriptor_t*)pBuffer; TI_UINT8 *pFrame = RX_BUF_DATA((TI_UINT8 *)pBuffer); TI_STATUS tStatus = TI_OK; dot11_header_t *pHdr = (dot11_header_t *)pFrame; TI_UINT16 uQosControl; COPY_WLAN_WORD(&uQosControl, &pHdr->qosControl); /* copy with endianess handling. */ /* * Retrieving the TAG from the packet itself and not from the Rx Descriptor since by now it is not correct * Note: in the DR TAG_CLASS_EAPOL packet handled as TAG_CLASS_QOS_DATA */ if (IS_QOS_FRAME(*(TI_UINT16*)pFrame) && (pRxParams->packet_class_tag != TAG_CLASS_QOS_DATA) && (pRxParams->packet_class_tag != TAG_CLASS_AMSDU)) { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_WARNING, "RxQueue_ReceivePacket: BAD CLASS TAG =0x%x from FW.\n", pRxParams->packet_class_tag); /* Get AMSDU bit from frame */ if( uQosControl & DOT11_QOS_CONTROL_FIELD_A_MSDU_BITS) { pRxParams->packet_class_tag = TAG_CLASS_AMSDU; } else { pRxParams->packet_class_tag = TAG_CLASS_QOS_DATA; } } /* * packet doesn't need reorder ? */ if ((pRxParams->packet_class_tag != TAG_CLASS_QOS_DATA) && (pRxParams->packet_class_tag != TAG_CLASS_BA_EVENT) && (pRxParams->packet_class_tag != TAG_CLASS_AMSDU)) { TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: pass packet without reorder.\n"); RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); return; } /* * pRxParams->type == TAG_CLASS_QOS_DATA ? */ if ((pRxParams->packet_class_tag == TAG_CLASS_QOS_DATA) || (pRxParams->packet_class_tag == TAG_CLASS_AMSDU)) { TI_UINT8 uFrameTid; TI_UINT16 uFrameSn; TI_UINT16 uSequenceControl; TRxQueueTidDataBase *pTidDataBase; /* Get TID from frame */ uFrameTid = uQosControl & DOT11_QOS_CONTROL_FIELD_TID_BITS; /* TID illegal value ? */ if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR, "RxQueue_ReceivePacket: TID value too big, TID = %d. packet discarded!\n",uFrameTid); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } /*set the SA Tid pointer */ pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); /* TID legal value */ /* packet TID BA not established ? */ if (pTidDataBase->aTidBaEstablished != TI_TRUE) { TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: pass packet without reorder.\n"); RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); return; } /* packet TID BA established */ /* Get Sequence Number from frame */ COPY_WLAN_WORD(&uSequenceControl, &pHdr->seqCtrl); /* copy with endianess handling. */ uFrameSn = (uSequenceControl & DOT11_SC_SEQ_NUM_MASK) >> 4; /* * note: * the FW never send paket, in establish TID BA, that the SN less then ESN !!! */ /* frame Sequence Number is the expected one ? */ if (uFrameSn == pTidDataBase->aTidExpectedSn) { TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: frame Sequence Number == expected one Sequence Number.\n"); /* pass the packet */ RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); pTidDataBase->aTidExpectedSn++; pTidDataBase->aTidExpectedSn &= 0xfff; /* increase the ArrayInex to the next */ pTidDataBase->aWinStartArrayInex++; /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; /* pass all saved queue packets with SN higher then the expected one */ while (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) { RxQueue_PassPacket (pRxQueue, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; pTidDataBase->aWinStartArrayInex++; /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; pTidDataBase->aTidExpectedSn++; pTidDataBase->aTidExpectedSn &= 0xfff; } return; } /* frame Sequence Number is lower then Expected sequence number (ISN) ? */ if (! BA_SESSION_IS_A_BIGGER_THAN_B (uFrameSn, pTidDataBase->aTidExpectedSn)) { /* WLAN_OS_REPORT(("%s: ERROR - SN=%u is less than ESN=%u\n", __FUNCTION__, uFrameSn, pTidDataBase->aTidExpectedSn)); */ TRACE2(pRxQueue->hReport, REPORT_SEVERITY_ERROR, "RxQueue_ReceivePacket: frame SN=%u is less than ESN=%u\n",uFrameSn,pTidDataBase->aTidExpectedSn); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } /* frame Sequence Number between winStart and winEnd ? */ if ((BA_SESSION_IS_A_BIGGER_THAN_B (uFrameSn, pTidDataBase->aTidExpectedSn)) && /* mean: uFrameSn <= pTidDataBase->aTidExpectedSn + pTidDataBase->aTidWinSize) */ ( ! BA_SESSION_IS_A_BIGGER_THAN_B (uFrameSn,(pTidDataBase->aTidExpectedSn + pTidDataBase->aTidWinSize - 1)))) { TI_UINT16 uSaveInex = pTidDataBase->aWinStartArrayInex + (TI_UINT16)((uFrameSn + SEQ_NUM_WRAP - pTidDataBase->aTidExpectedSn) & SEQ_NUM_MASK); /* uSaveInex % RX_QUEUE_ARRAY_SIZE */ uSaveInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; if (pTidDataBase->aPaketsQueue[uSaveInex].pPacket == NULL) { /* save the packet in the queue */ pTidDataBase->aPaketsQueue[uSaveInex].tStatus = tStatus; pTidDataBase->aPaketsQueue[uSaveInex].pPacket = (void *)pBuffer; pTidDataBase->aPaketsQueue[uSaveInex].uFrameSn = uFrameSn; } else { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR, "RxQueue_ReceivePacket: frame Sequence has allready saved. uFrameSn = %d\n",uFrameSn); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } return; } /* frame Sequence Number higher then winEnd ? */ if ( BA_SESSION_IS_A_BIGGER_THAN_B (uFrameSn, (pTidDataBase->aTidExpectedSn + pTidDataBase->aTidWinSize - 1)) ) { TI_UINT32 i; TI_UINT16 uNewWinStartSn = (uFrameSn + SEQ_NUM_WRAP - pTidDataBase->aTidWinSize + 1) & SEQ_NUM_MASK; TI_UINT16 uSaveInex; TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: frame Sequence Number higher then winEnd.\n"); /* increase the ArrayInex to the next */ pTidDataBase->aWinStartArrayInex++; /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; /* update the Expected SN since the current one is lost */ pTidDataBase->aTidExpectedSn++; pTidDataBase->aTidExpectedSn &= 0xFFF; /* pass all saved queue packets with SN lower then the new win start */ for (i = 0; BA_SESSION_IS_A_BIGGER_THAN_B(uNewWinStartSn,pTidDataBase->aTidExpectedSn) && (i < RX_QUEUE_ARRAY_SIZE) && (i < pTidDataBase->aTidWinSize); i++) { if (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) { RxQueue_PassPacket (pRxQueue, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; } pTidDataBase->aWinStartArrayInex++; /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; pTidDataBase->aTidExpectedSn++; pTidDataBase->aTidExpectedSn &= 0xFFF; } /* Calculate the new Expected SN */ if (i == pTidDataBase->aTidWinSize) { pTidDataBase->aTidExpectedSn = uNewWinStartSn; } else { /* Incase the uWinStartDelta lower than aTidWinSize check if ther are packets stored in Array */ while (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) { RxQueue_PassPacket (pRxQueue, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; pTidDataBase->aWinStartArrayInex++; /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; pTidDataBase->aTidExpectedSn++; pTidDataBase->aTidExpectedSn &= 0xFFF; } } if(pTidDataBase->aTidExpectedSn == uFrameSn) { /* pass the packet */ RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); pTidDataBase->aTidExpectedSn++; pTidDataBase->aTidExpectedSn &= 0xfff; } else { uSaveInex = pTidDataBase->aWinStartArrayInex + (TI_UINT16)((uFrameSn + SEQ_NUM_WRAP - pTidDataBase->aTidExpectedSn) & SEQ_NUM_MASK); /* uSaveInex % RX_QUEUE_ARRAY_SIZE */ uSaveInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; /* save the packet in the last entry of the queue */ pTidDataBase->aPaketsQueue[uSaveInex].tStatus = tStatus; pTidDataBase->aPaketsQueue[uSaveInex].pPacket = (void *)pBuffer; pTidDataBase->aPaketsQueue[uSaveInex].pPacket = (void *)pBuffer; } return; } } /* * BA event ? */ if (pRxParams->packet_class_tag == TAG_CLASS_BA_EVENT) { TRxQueueTidDataBase *pTidDataBase; TI_UINT8 *pDataFrameBody; TI_UINT16 ufc; TI_UINT8 uFrameTid; TI_UINT16 uStartingSequenceNumber; TI_UINT16 uWinStartDelta; TI_UINT16 uBarControlField; TI_UINT16 uBaStartingSequenceControlField; TI_UINT16 uBAParameterField; TI_UINT32 i; /* Get sub type from frame */ COPY_WLAN_WORD(&ufc, &pHdr->fc); /* copy with endianess handling. */ /* get the type to BA event */ switch ((dot11_Fc_Sub_Type_e)(ufc & DOT11_FC_SUB_MASK)) { case DOT11_FC_SUB_BAR: TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION , "RxQueue_ReceivePacket: BA event - BAR frame.\n"); /* get pointer to the frame body */ pDataFrameBody = pFrame + sizeof(dot11_BarFrameHeader_t); /* Get TID from BAR frame */ COPY_WLAN_WORD (&uBarControlField, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ uFrameTid = (uBarControlField & DOT11_BAR_CONTROL_FIELD_TID_BITS) >> 12; /* TID illegal value ? */ if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - BAR frame with TID value too big, TID = %d.\n",uFrameTid); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } /* set the SA Tid pointer */ pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); /* TID legal value */ /* packet TID BA not established ? */ if (pTidDataBase->aTidBaEstablished != TI_TRUE) { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - BAR frame for TID not established, TID = %d.\n",uFrameTid); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } /* Get Starting Sequence number from BAR frame */ pDataFrameBody = pDataFrameBody + 2; COPY_WLAN_WORD (&uBaStartingSequenceControlField, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ uStartingSequenceNumber = (uBaStartingSequenceControlField & DOT11_SC_SEQ_NUM_MASK) >> 4; /* Starting Sequence Number is higher then winStart ? */ if ( BA_SESSION_IS_A_BIGGER_THAN_B (uStartingSequenceNumber, pTidDataBase->aTidExpectedSn) ) { uWinStartDelta = (uStartingSequenceNumber + SEQ_NUM_WRAP - pTidDataBase->aTidExpectedSn) & SEQ_NUM_MASK; /* pass all saved queue packets with SN lower then the new win start */ for (i = 0; ((i < uWinStartDelta) || (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL)) && (i < RX_QUEUE_ARRAY_SIZE) && (i < RX_QUEUE_WIN_SIZE); i++) { if (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) { RxQueue_PassPacket (pRxQueue, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; } pTidDataBase->aWinStartArrayInex++; /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; } pTidDataBase->aTidExpectedSn = uStartingSequenceNumber; } break; case DOT11_FC_SUB_ACTION: /* get pointer to the frame body */ pDataFrameBody = pFrame + sizeof(dot11_mgmtHeader_t); /* get Action field from BA action frame */ pDataFrameBody++; switch(*pDataFrameBody) { case DOT11_BA_ACTION_ADDBA: TRACE0( pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: BA event - ADDBA frame.\n"); /* get TID field and winSize from ADDBA action frame */ pDataFrameBody = pDataFrameBody + 2; COPY_WLAN_WORD(&uBAParameterField, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ uFrameTid = (uBAParameterField & DOT11_BA_PARAMETER_SET_FIELD_TID_BITS) >> 2; /* TID illegal value ? */ if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - ADDBA frame with TID value too big, TID = %d.\n",uFrameTid); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } /*set the SA Tid pointer */ pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); /* TID legal value */ /* packet TID BA established ? */ if (pTidDataBase->aTidBaEstablished == TI_TRUE) { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - ADDBA frame for TID already established, TID = %d.\n",uFrameTid); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } /* get winSize from ADDBA action frame */ pTidDataBase->aTidWinSize = (uBAParameterField & DOT11_BA_PARAMETER_SET_FIELD_WINSIZE_BITS) >> 6; /* winSize illegal value ? */ if (pTidDataBase->aTidWinSize > RX_QUEUE_WIN_SIZE) { /* In case the win Size is higher then 8 the driver and the FW set it to 8 and inform the AP in ADDBA respond */ pTidDataBase->aTidWinSize = RX_QUEUE_WIN_SIZE; } /* packet TID BA not yet established and winSize legal */ /* establishe BA TID */ pTidDataBase->aTidBaEstablished = TI_TRUE; /* get initial sequence number (ISN) from ADDBA action frame */ pDataFrameBody = pDataFrameBody + 4; COPY_WLAN_WORD (&uStartingSequenceNumber, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ pTidDataBase->aTidExpectedSn = (uStartingSequenceNumber & DOT11_SC_SEQ_NUM_MASK) >> 4; pTidDataBase->aWinStartArrayInex = 0; os_memoryZero (pRxQueue->hOs, pTidDataBase->aPaketsQueue, sizeof (TRxQueuePacketEntry) * RX_QUEUE_ARRAY_SIZE); break; case DOT11_BA_ACTION_DELBA: TRACE0( pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: BA event - DELBA frame.\n"); /* get TID field and winSize from ADDBA action frame */ pDataFrameBody = pDataFrameBody + 2; COPY_WLAN_WORD(&uBAParameterField, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ uFrameTid = (uBAParameterField & DOT11_DELBA_PARAMETER_FIELD_TID_BITS) >> 12; /* TID illegal value ? */ if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - DELBA frame with TID value too big, TID = %d.\n",uFrameTid); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } /*set the SA Tid pointer */ pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); /* TID legal value */ /* packet TID BA not established ? */ if (pTidDataBase->aTidBaEstablished != TI_TRUE) { TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - DELBA frame for TID not established, TID = %d.\n",uFrameTid); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } RxQueue_CloseBaSession(hRxQueue, uFrameTid); break; default: TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event Action field from BA action frame illegal. action = 0x%x\n",*pDataFrameBody); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } break; default: TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event with Subtype illegal. Subtype = 0x%x\n",((ufc & DOT11_FC_SUB_MASK) >> 4)); RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); return; } } TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR, "RxQueue_ReceivePacket: unknow type tag. tag = %d\n", pRxParams->packet_class_tag); RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); return; }