/*
* 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;
}