/*
* TIWhaTxRx.cpp
*
* Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved.
* All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 or BSD License which accompanies
* this distribution. The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the BSD License is as below.
*
* 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 TIWhaTxRx.cpp
* \brief Control the data path from UMAC and back to UMAC
*
* \see
*/
#include "TIWha.h"
/*******************************************************************************
* stuff for C file linking. *
*******************************************************************************/
extern "C"
{
#include "tidef.h"
#include "report.h"
#include "timer.h"
#include "TWDriver.h"
#include "version.h"
#include "osApi.h"
#include "context.h"
#include "BusDrv.h"
#include "public_types.h"
#define __FILE_ID__ FILE_ID_147
}
static const TI_UINT8 WMEQosAcToTid[MAX_NUM_OF_AC] = { 0, 2, 4, 6 };
#define WORD_SIZE 4
#define WORD_ALIGN_MASK 0xFFFC
#define GET_EXTRA_BYTES(status) ( (status & 0xc0) >> 6)
#define KEY_GEM_TYPE 4
#define QOS_PADDING_SIZE 4
#define QOS_SHIFT_SIZE 2
/********************************************************************************
* *
* MACROS and INLINE FUNCTIONS *
* *
*********************************************************************************/
/* Update packet length in the descriptor according to HW interface requirements */
static inline TI_UINT16 TranslateLengthToFw (TTxCtrlBlk *pPktCtrlBlk)
{
TI_UINT16 uPktLen = pPktCtrlBlk->tTxDescriptor.length;
TI_UINT16 uLastWordPad = (4 - (uPktLen & 3)) & 0x3; /* Find number of bytes needed to align */
uPktLen = (uPktLen + uLastWordPad) >> 2; /* Add alignment bytes and convert to words */
pPktCtrlBlk->tTxDescriptor.length = ENDIAN_HANDLE_WORD(uPktLen);
return uLastWordPad;
}
/* Translate packet timestamp to FW time, and update also lifeTime and uDriverDelay */
static inline void TranslateTimeToFw (TwdCtrl *iTwdCtrl, TTxCtrlBlk *pPktCtrlBlk, TI_UINT16 uLifeTime)
{
TI_UINT32 uPktStartTime = pPktCtrlBlk->tTxDescriptor.startTime; /* Contains host start time */
/* Save host packet handling time until this point (for statistics) */
pPktCtrlBlk->tTxPktParams.uDriverDelay = os_timeStampMs (iTwdCtrl->tOsContext.hOsa) - uPktStartTime;
/* Translate packet timestamp to FW time and undate descriptor */
uPktStartTime = TWD_TranslateToFwTime (iTwdCtrl->hTWD, uPktStartTime);
pPktCtrlBlk->tTxDescriptor.startTime = ENDIAN_HANDLE_LONG (uPktStartTime);
pPktCtrlBlk->tTxDescriptor.lifeTime = ENDIAN_HANDLE_WORD (uLifeTime);
}
/**
* \fn RxMemFailTimerCb
* \brief Call again the rxXfer module to handle all pending packets.
* \note
* \return
* \sa
*/
void TIWha::RxMemFailTimerCb ()
{
TRACE1(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "RxMemFailTimerCb uRxMemFailCount %d\n",uRxMemFailCount);
bRxMemFailTimerRunning = TI_FALSE;
/* if uRxMemFailCount == 0 it means that Rx allocation is back to life - no need to call RxXfer */
if (uRxMemFailCount)
{
TWD_rxXfer_Handle(iTwdCtrl.hTWD);
}
}
/**
* \fn RequestForBuffer
* \brief member function. calls LDD
*
* \note
* \param aLength - aligned length of packet.
* \return
* \sa
*/
ERxBufferStatus TIWha::RequestForBufferCb (void **pWbuf, TI_UINT16 aLength, TI_UINT32 uEncryptionFlag)
{
/* Total security overhead to be asked for in RequestForBuffer () */
TI_UINT32 uExtraSecurityLength = 0;
/* Offset to be used when returning the buffer pointer. It will be used shifting the header backwards */
TI_UINT32 uSecurityOffset = 0;
ERxBufferStatus eBufferStatus;
TI_UINT8* pRequestedBuf = NULL;
/*
* We should manipulate the packet according to the security mode. See ReceivePacket() for
* more details.
* We have 2 issues to deal with:
* 1) Add additional length to the buffer request.
* 2) Change the pointer such that it will point forward by the size that should be added after the header.
* It is done in order to pull back the header later in GWSI_AdaptCB_ReceivePacket() to support GWSI spec.
*/
switch (uEncryptionFlag)
{
case KEY_NULL:
uExtraSecurityLength = 0;
uSecurityOffset = 0;
break;
case KEY_WEP:
uExtraSecurityLength = IV_FIELD_SIZE + ICV_FIELD_SIZE;
uSecurityOffset = IV_FIELD_SIZE;
break;
case KEY_TKIP:
uExtraSecurityLength = IV_FIELD_SIZE + EIV_FIELD_SIZE + MIC_FIELD_SIZE + ICV_FIELD_SIZE;
uSecurityOffset = IV_FIELD_SIZE + EIV_FIELD_SIZE;
break;
case KEY_AES:
uExtraSecurityLength = AES_AFTER_HEADER_FIELD_SIZE + MIC_FIELD_SIZE;
uSecurityOffset = AES_AFTER_HEADER_FIELD_SIZE;
break;
#ifdef GEM_SUPPORT
case KEY_GEM_TYPE:
uExtraSecurityLength = GEM_AFTER_HEADER_FIELD_SIZE + GEM_MIC_FIELD_SIZE;
uSecurityOffset = GEM_AFTER_HEADER_FIELD_SIZE + GEM_BUFFER_ALIGNMENT;
break;
#endif
default:
TRACE2(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "RequestForBuffer: uEncryptionFlag = %d uExtraSecurityLength = %d\n", uEncryptionFlag, uExtraSecurityLength);
break;
}
if (iRxPacketsAllocated < MAX_WHA_RX_BUFFERS)
{
/*
* We are requesting extra bytes for security, but decreasing WSPI_PAD_LEN_READ since the spec indicates
* that the Rx offset will be added any way
*/
if( bErrorIndication == TI_FALSE)
{
pRequestedBuf = (TI_UINT8*) WhaCb()->RequestForBuffer(aLength - sizeof(RxIfDescriptor_t) + uExtraSecurityLength + QOS_PADDING_SIZE + PAYLOAD_ALIGN_PAD_BYTES);
}
#if TI_DBG
else
{
WLAN_OS_REPORT(("%s : CommandResponse Block call to LDD response \n",__FUNCTION__));
}
#endif
if ( pRequestedBuf == NULL )
{
#ifdef PLT_TESTER
return RX_BUF_ALLOC_OUT_OF_MEM;
#endif
uRxMemFailCount++;
/* In case no timer is running - start a new timer to call RxXfer later */
if (!bRxMemFailTimerRunning)
{
#ifdef TI_DBG
if (uRxMemFailCount == 1)
{
/* Print error only for the first time */
TRACE0(iTwdCtrl.hReport, REPORT_SEVERITY_ERROR, "Start hRxMemFailTimer for the first time\n");
}
#endif
TRACE1(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "Start hRxMemFailTimer uRxMemFailCount %d\n",uRxMemFailCount);
/* In case we fail too many times, just mark as OUT_OF_MEM so the Rx packet will be dropped */
if (uRxMemFailCount > MAX_CONSECUTIVE_RX_MEM_FAIL)
{
return RX_BUF_ALLOC_OUT_OF_MEM;
}
bRxMemFailTimerRunning = TI_TRUE;
os_timerStart(&iTwdCtrl.tOsContext,hRxMemFailTimer,RX_ALLOC_FAIL_TIME_OUT);
}
/* In this case rxXfer will exit the loop and wait for someone to trigger the SM again */
return RX_BUF_ALLOC_PENDING;
}
/* Increase the number of allocated buffers */
iRxPacketsAllocated++;
#ifdef TI_DBG
/* Just have a print in case we are out of the bad situation of RX_BUF_ALLOC_OUT_OF_MEM */
if (uRxMemFailCount)
{
TRACE1(iTwdCtrl.hReport, REPORT_SEVERITY_ERROR, "Rx allocation succeeded after %d times\n",uRxMemFailCount);
}
#endif /* TI_DBG */
/* Rx allocation succeeded so set counter to zero */
uRxMemFailCount = 0;
TRACE2(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "RequestForBuffer: uEncryptionFlag = %d uExtraSecurityLength = %d\n", uEncryptionFlag, uExtraSecurityLength);
TRACE3(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "RequestForBuffer: len = %d OriginalPointer = 0x%x, allocatedBuffer#= %d \n", aLength, *pWbuf, iRxPacketsAllocated);
TRACE2(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "RequestForBuffer: Pointer2Buffer= 0x%x, Buffer= 0x%x \n",pWbuf, *pWbuf);
/* The packet will be read as if it started uSecurityOffset bytes ahead and ReceivePacket() will take it back */
/* pWbuf points to the actual start of the data */
pRequestedBuf += uSecurityOffset + WSPI_PAD_LEN_READ;
*pWbuf = (void*)pRequestedBuf;
eBufferStatus = RX_BUF_ALLOC_COMPLETE;
}
else
{
TRACE0(iTwdCtrl.hReport, REPORT_SEVERITY_WARNING, "RequestForBuffer: RX_BUF_ALLOC_PENDING");
/* RxXfer will try to allocate the buffer again when other buffer will be released */
eBufferStatus = RX_BUF_ALLOC_PENDING;
}
return eBufferStatus;
}
/**
* \fn ReceivePacket
* \brief member function. calls LDD
*
* \note
* \param aStatus - not used but retrieved from RxIfDescriptor_t.
* \param aBuf - pointer to start of RxIfDescriptor_t.
* \return
* \sa
*/
void TIWha::ReceivePacketCb (const void *aBuf)
{
WHA::TStatus aStatus;
TUint16 aLength;
WHA::TRate aRate;
WHA::TRcpi aRcpi;
WHA::TChannelNumber aChannel;
TUint32 aFlags;
/* move aBuf to begeinnig of MAC heder */
const void* aFrame = (TI_UINT8*)aBuf + sizeof(RxIfDescriptor_t);
dot11_header_t *pDot11Hdr = (dot11_header_t*)aFrame;
RxIfDescriptor_t* pRxParams = (RxIfDescriptor_t*)aBuf;
TBool bQos;
switch (pRxParams->status)
{
case RX_FAILURE_NONE:
aStatus = WHA::KSuccess;
break;
case RX_FAILURE_MIC_ERROR:
aStatus = WHA::KMicFailure;
TRACE0(iTwdCtrl.hReport, REPORT_SEVERITY_ERROR , "ReceivePacket MIC_FAILURE !!! \n");
break;
case RX_FAILURE_DECRYPT:
aStatus = WHA::KDecryptFailure;
TRACE0(iTwdCtrl.hReport, REPORT_SEVERITY_ERROR , "ReceivePacket DECRYPT_FAILURE !!! \n");
break;
default:
TRACE0(iTwdCtrl.hReport, REPORT_SEVERITY_ERROR ,"ReceivePacketCb : WHA::KFailed");
aStatus = WHA::KFailed;
}
/* convert to LDD rate */
aRate = TIWhaUtils::PolicyToWhaRate ((ETxRateClassId)pRxParams->rate);
/* calculate RCPI form RSSI */
if (pRxParams->rx_level >= 0)
aRcpi = 220;
else
if (pRxParams->rx_level <= -110)
aRcpi = 0;
else
aRcpi = (pRxParams->rx_level + 110)*2;
/* Channel of received frame */
aChannel = pRxParams->channel;
/* pRxParams->length refer to total length form MAC heder in bytes */
aLength = pRxParams->length*WORD_SIZE - pRxParams->extraBytes - sizeof(RxIfDescriptor_t);
/* flags description:
1. bits 0 - 15 are optional
2. bits 16 - 18 security TBD when security integrated
3. bit 19 for more pending frames
4. bit 20 packet was received during a measurement process or not
*/
aFlags = 0;
/*
* The next adaptation code is meant to align with the driver legacy operation of extra padding for security:
*
* WEP: TnetwDrv HEADER - DATA
* Upper layer HEADER - IV (4) - DATA - ICV (4)
*
* TKIP: TnetwDrv HEADER - DATA
* Upper layer HEADER - IV (4) - EIV (4) - DATA - MIC (8) - ICV (4)
*
* AES: TnetwDrv HEADER - DATA
* Upper layer HEADER - RSN (8) - DATA - MIC (8)
*
* GEM: TnetwDrv HEADER - DATA
* Upper layer HEADER - KeyIdx(1) - Reserved(1) - PN(16) - DATA - MIC (16)
*
* Note: Adding the offset is done even if the packet status is error
*/
bQos = IS_QOS_FRAME(pDot11Hdr->fc);
TUint8 shiftBytes = WSPI_PAD_LEN_READ;
switch (pRxParams->flags & RX_DESC_ENCRYPT_MASK)
{
case RX_DESC_ENCRYPT_WEP:
ALIGN_HEADER_TO_DATA_BACKWARD (aFrame, WEP_AFTER_HEADER_FIELD_SIZE, bQos)
shiftBytes += WEP_AFTER_HEADER_FIELD_SIZE;
/* Increase length size by 8 (IV + ICV) */
aLength += (WEP_AFTER_HEADER_FIELD_SIZE + ICV_FIELD_SIZE);
aFlags |= WHA_WEP;
break;
case RX_DESC_ENCRYPT_TKIP:
ALIGN_HEADER_TO_DATA_BACKWARD (aFrame, TKIP_AFTER_HEADER_FIELD_SIZE, bQos)
shiftBytes += TKIP_AFTER_HEADER_FIELD_SIZE;
/* Increase length size by 20 (IV + EIV + MIC + ICV) */
aLength += (TKIP_AFTER_HEADER_FIELD_SIZE + MIC_FIELD_SIZE + ICV_FIELD_SIZE);
aFlags |= WHA_TKIP;
break;
case RX_DESC_ENCRYPT_AES:
ALIGN_HEADER_TO_DATA_BACKWARD (aFrame, AES_AFTER_HEADER_FIELD_SIZE, bQos)
shiftBytes += AES_AFTER_HEADER_FIELD_SIZE;
/* Increase length size by 16 (AES(RSN padding) + MIC) */
aLength += (AES_AFTER_HEADER_FIELD_SIZE + MIC_FIELD_SIZE);
aFlags |= WHA_AES;
break;
#ifdef GEM_SUPPORT
case RX_DESC_ENCRYPT_GEM:
ALIGN_HEADER_TO_DATA_BACKWARD (aFrame, GEM_AFTER_HEADER_FIELD_SIZE, bQos)
shiftBytes += GEM_AFTER_HEADER_FIELD_SIZE + GEM_BUFFER_ALIGNMENT;
/* Increase length size by 34 ( GEM_KeyIdx(1) + GEM_Reserved(1) + GEM_PN(16) + GEM_MIC(16) ) */
aLength += (GEM_AFTER_HEADER_FIELD_SIZE + GEM_MIC_FIELD_SIZE);
aFlags |= WHA_GEM;
break;
#endif
default:
/* Do nothing */
break;
}
/*if QOS frame the pointer starts 2 bytes before so the shiftbytes will be 2 mor bytes*/
if (bQos)
{
shiftBytes += QOS_SHIFT_SIZE;
}
/* Call upper layer */
if( bErrorIndication == TI_FALSE)
{
WhaCb()->ReceivePacket (aStatus,
aFrame,
aLength,
aRate,
aRcpi,
aChannel,
(TUint8*)aBuf - shiftBytes,
aFlags);
}
#if TI_DBG
else
{
WLAN_OS_REPORT(("%s : CommandResponse Block call to LDD response \n",__FUNCTION__));
}
#endif
/* Decrease the number of allocated buffers */
iRxPacketsAllocated--;
TRACE1(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "end of ReceivePacket(), allocated buffer = %d\n", iRxPacketsAllocated);
}
/**
* \fn SendPacket
* \brief member function.
*
* \note
* \return
* \sa
*/
WHA::TStatus TIWha::SendPacket(
const void* aFrame,
TUint16 aLength,
WHA::TQueueId aQueueId,
TUint8 aTxRateClassId,
WHA::TRate aMaxTransmitRate,
TBool aMore,
WHA::TPacketId aPacketId,
WHA::TPowerLevel aPowerLevel,
TUint32 aExpiryTime,
void* aReserved )
{
TTxCtrlBlk *pPktCtrlBlk;
void* aData = (void*)aFrame;
WHA::TStatus whaStatus;
TI_STATUS tiStatus;
TRACE4(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, " aFrame = 0x%x len = %d aQueue = %d rateClass = %d\n", aFrame, aLength, aQueueId, aTxRateClassId);
TRACE3(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, " aMaxTransmitRate = 0x%x aPacketId = 0x%x aExpiryTime = %d \n",aMaxTransmitRate, aPacketId, aExpiryTime);
AlignTxForTWD (aData, aLength);
/*
* Prepare packet for transmision by filling up all the fields.
*/
whaStatus = preparePktCtrlBlk ( &pPktCtrlBlk,
aData,
aLength,
aQueueId,
aTxRateClassId,
aMaxTransmitRate,
aMore,
aPacketId,
aPowerLevel,
aExpiryTime);
if ( whaStatus == WHA::KQueueFull)
{
TRACE0(iTwdCtrl.hReport, REPORT_SEVERITY_WARNING , "****** KQueueFull ****** \n");
AlignTxSecurityForUMAC (TRUE);
return WHA::KQueueFull;
}
TRACE2(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "aFrame=%x, Buffer= %x \n", aFrame, pPktCtrlBlk->tTxnStruct.aBuf[0]);
/*
* Call the Tx-Xfer to start packet transfer to the FW and return its result.
*/
tiStatus = TWD_txXfer_SendPacket ( iTwdCtrl.hTWD, pPktCtrlBlk);
TRACE1(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, " status = %d \n", tiStatus);
switch (tiStatus)
{
case TXN_STATUS_COMPLETE:
/* TxXferCb () won't be called so Align Tx packet before */
AlignTxSecurityForUMAC (TRUE);
/* Mark that TxXferCb won't be called */
pPktCtrlBlk->tTxPktParams.uFlags = TX_CTRL_FLAG_XFER_DONE_ISSUED;
return WHA::KSuccessXfer;
case TXN_STATUS_OK:
pPktCtrlBlk->tTxPktParams.uFlags = 0;
if (whaStatus == WHA::KPending) {
return WHA::KPending;
}
return WHA::KSuccess;
case TXN_STATUS_PENDING:
/* The packet is pending in spi level and not in driver level */
pPktCtrlBlk->tTxPktParams.uFlags = 0;
if (whaStatus == WHA::KPending) {
return WHA::KPending;
}
return WHA::KSuccess;
case TXN_STATUS_ERROR:
/* TxXferCb () won't be called so Align Tx packet before */
AlignTxSecurityForUMAC (TRUE);
return WHA::KQueueFull;
default:
/* TxXferCb () won't be called so Align Tx packet before */
AlignTxSecurityForUMAC (TRUE);
return WHA::KFailed;
}
}
/**
* \fn preparePktCtrlBlk
* \brief prepare the Ctrl Block with the given parameters
*
* \note
* \return txCtrlBlkEntry_t*
* \sa
*/
WHA::TStatus TIWha::preparePktCtrlBlk ( TTxCtrlBlk **pPktCtrlBlk,
const void* aFrame,
TUint16 aLength,
WHA::TQueueId aQueueId,
TUint8 aTxRateClassId,
WHA::TRate aMaxTransmitRate,
TBool aMore,
WHA::TPacketId aPacketId,
WHA::TPowerLevel aPowerLevel,
TUint32 aExpiryTime)
{
TI_UINT16 txDescAttr; /* Tx-descriptor fields values. */
TI_UINT16 uLastWordPad;
TI_UINT8 uAligmentPad;
TI_UINT32 tempaFrame;
*pPktCtrlBlk = NULL;
ETxHwQueStatus eHwQueStatus;
/* Allocates a Control-Block for the packet Tx parameters and descriptor. */
*pPktCtrlBlk = TWD_txCtrlBlk_Alloc (iTwdCtrl.hTWD);
/* If null entry (not expected to happen) return ERROR. */
if (!*pPktCtrlBlk)
{
TRACE0(iTwdCtrl.hReport, REPORT_SEVERITY_ERROR, ": Tx Ctrl-Blk allocation failed!!!\n");
return WHA::KQueueFull;
}
/* Save the aPacketId for use in TxXferCb & TxCompleteCb */
iPacketIdTable[(*pPktCtrlBlk)->tTxDescriptor.descID] = aPacketId;
TRACE2(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, ": iPacketIdTable[%d]= %d\n", (*pPktCtrlBlk)->tTxDescriptor.descID, aPacketId);
/*
* Fill in parameters of pPktCtrlBlk
*/
/* Move aFrame back in order to leave room for the tx_descriptor */
tempaFrame = (TI_UINT32)aFrame - TX_DESCRIPTOR_SIZE;
aFrame = (void*)tempaFrame;
uAligmentPad = ((4 -(aLength & 0x3)) & 0x3);
/* data is given with the header, this is different then full driver */
(*pPktCtrlBlk)->tTxnStruct.aLen[0] = aLength + TX_DESCRIPTOR_SIZE + uAligmentPad;
(*pPktCtrlBlk)->tTxnStruct.aBuf[0] = (TI_UINT8*)aFrame;
/* Not relevant since we are not incharge on the memory release */
(*pPktCtrlBlk)->tTxPktParams.uInputPktLen = 0;
(*pPktCtrlBlk)->tTxPktParams.pInputPkt = 0;
/*
* Build packet descriptor (for FW interface).
*/
(*pPktCtrlBlk)->tTxDescriptor.tid = WMEQosAcToTid[aQueueId];
(*pPktCtrlBlk)->tTxDescriptor.startTime = os_timeStampMs (iTwdCtrl.tOsContext.hOsa);
TranslateTimeToFw (&iTwdCtrl, (*pPktCtrlBlk), 2000/*aExpiryTime*/);
TRACE3(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, ": aExpiryTime= %d, desc.startTime= %d, desc.lifeTime= %d \n", aExpiryTime, (*pPktCtrlBlk)->tTxDescriptor.startTime, (*pPktCtrlBlk)->tTxDescriptor.lifeTime);
/* Initialize tTxDescriptor.length with the real packet length in bytes */
(*pPktCtrlBlk)->tTxDescriptor.length = aLength + TX_DESCRIPTOR_SIZE;
/* Call HwQueue for Hw resources allocation. If not available return NULL. */
eHwQueStatus = TWD_txHwQueue_AllocResources (iTwdCtrl.hTWD, (*pPktCtrlBlk));
if (eHwQueStatus == TX_HW_QUE_STATUS_STOP_CURRENT)
{
/* Free Ctrl block. */
TWD_txCtrlBlk_Free(iTwdCtrl.hTWD, (*pPktCtrlBlk));
TRACE0(iTwdCtrl.hReport, REPORT_SEVERITY_WARNING, ": Tx Hw resources allocation failed!!!\n");
return WHA::KQueueFull;
}
/* txCtrl_TranslateLengthToFw() will translate it to the length in FW format */
uLastWordPad = TranslateLengthToFw((*pPktCtrlBlk));
/* Upper layer is using '1' for first policy, while TnetwDrv is using '0' for it. */
txDescAttr = (aTxRateClassId - 1 ) << TX_ATTR_OFST_RATE_POLICY;
/* if there is a security padding then the WLAN packet was stuffed with 2 extra bytes for alignment */
if (iSecurityPadding != 0)
{
txDescAttr |= TX_ATTR_HEADER_PAD;
}
txDescAttr |= uLastWordPad << TX_ATTR_OFST_LAST_WORD_PAD;
(*pPktCtrlBlk)->tTxDescriptor.txAttr = txDescAttr;
/*
* Copy the descriptor parameters to the packet header.
*/
os_memoryCopy(iTwdCtrl.tOsContext.hOsa, const_cast<void*>(aFrame), (TxIfDescriptor_t*)&(*pPktCtrlBlk)->tTxDescriptor, sizeof(TxIfDescriptor_t));
return eHwQueStatus == TX_HW_QUE_STATUS_STOP_NEXT ? WHA::KPending : WHA::KSuccess;
}
/**
* \fn AlignTxForTWD
* \brief Aligment header to TWD structure -- Check HT and Security.
*
* \note
* \return
* \sa
*/
WHA::TStatus TIWha::AlignTxForTWD (void*& aFrame,TUint16& aLength)
{
/* Use the header to retrieve the frame ctrl of the packet */
dot11_header_t *pDot11Hdr = (dot11_header_t*)aFrame;
TI_UINT32 tempaFrame;
/* By default we won't handle any alignment */
iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrSend] = 0;
#ifdef HT_SUPPORT
if (IS_HT_FRAME(pDot11Hdr->fc))
{
iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrSend] = HT_CONTROL_FILED_SIZE;
aLength -= HT_CONTROL_FILED_SIZE;
}
#endif /* HT_SUPPORT */
/* Qos heaser is needed to determine the WLAN Header size */
iTwdCtrl.TxAlign.bIsQosHeader[iTwdCtrl.TxAlign.uCurrSend] = IS_QOS_FRAME(pDot11Hdr->fc);
/* zero iSecurityPadding for every new packet */
iSecurityPadding = 0;
/* Check if using security. If so we should convert the packet format as the description below */
if (IS_WEP_ON(pDot11Hdr->fc))
{
TI_UINT8* pMac;
ECipherSuite eSecurityMode;
pMac = &pDot11Hdr->address1[0]; /* hold the first mac address */
/* Use group key on Multicast/broadcast. else use pairwise */
if (MAC_MULTICAST(pMac))
{
eSecurityMode = iTwdCtrl.eGroupKeyMode;
}
else
{
eSecurityMode = iTwdCtrl.ePairwiseKeyMode;
}
/*
* The next adaptation code is meant to align with the driver legacy operation of extra padding for security:
*
* WEP: Upper layer HEADER - IV (4) - DATA - ICV (4)
* TnetwDrv HEADER - DATA
*
* TKIP: Upper layer HEADER - IV (4) - EIV (4) - DATA - MIC (8) - ICV (4)
* TnetwDrv HEADER - EIV (4) - DATA
*
* AES: Upper layer HEADER - RSN (8) - DATA - MIC (8)
* TnetwDrv HEADER - RSN (8) - DATA
*/
TRACE4(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "SendPacket(): send = %d Handle = %d, QoS = %d, encryption = %d\n",iTwdCtrl.TxAlign.uCurrSend, iTwdCtrl.TxAlign.uCurrHandle,
iTwdCtrl.TxAlign.bIsQosHeader[iTwdCtrl.TxAlign.uCurrSend], eSecurityMode);
switch (eSecurityMode)
{
case TWD_CIPHER_WEP:
/* Mark the offset between header and data */
iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrSend] += WEP_AFTER_HEADER_FIELD_SIZE;
/* Decrease length size by 8 (IV + ICV) */
aLength -= (IV_FIELD_SIZE + ICV_FIELD_SIZE);
break;
case TWD_CIPHER_TKIP:
/* Mark the offset between header and data */
iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrSend] += IV_FIELD_SIZE;
/* Decrease length size by 16 (IV + MIC + ICV) */
aLength -= (IV_FIELD_SIZE + MIC_FIELD_SIZE + ICV_FIELD_SIZE);
break;
case TWD_CIPHER_AES_WRAP:
case TWD_CIPHER_AES_CCMP:
/* Decrease length size by 8 (MIC) */
aLength -= MIC_FIELD_SIZE;
break;
#ifdef GEM_SUPPORT
case TWD_CIPHER_GEM:
/* Mark the offset between header and data */
iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrSend] += GEM_AFTER_HEADER_FIELD_SIZE;
/* Decrease length size by 34 bytes (KEY_IDX_FIELD_SIZE + RESERVED_FIELD_SIZE + PN_FIELD_SIZE + MIC) */
aLength -= (GEM_AFTER_HEADER_FIELD_SIZE + GEM_MIC_FIELD_SIZE);
/* Add padding of two bytes before wlan header, */
/* because it will be unaligned after the header will be moved 18 bytes */
iSecurityPadding = GEM_AFTER_HEADER_PAD;
break;
#endif
default:
/* Unknown security with Encryption ON. return ERROR */
TRACE1(iTwdCtrl.hReport, REPORT_SEVERITY_ERROR, "SendPacket(): Encryption ON but unknown security mode = %d\n", eSecurityMode);
return WHA::KFailed;
}
}
/* Check if the header packet should move */
if (iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrSend] > 0)
{
ALIGN_HEADER_TO_DATA_FORWARD (aFrame, iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrSend],
iTwdCtrl.TxAlign.bIsQosHeader[iTwdCtrl.TxAlign.uCurrSend])
}
/* Move the frame iSecurityPadding (2 bytes) backward */
tempaFrame = (TI_UINT32)aFrame - iSecurityPadding;
aFrame = (void*)tempaFrame;
/* Increase the length by size of iSecurityPadding (2 bytes) */
aLength+= iSecurityPadding;
/* Mark the current packet - Note that it is needed only when we have security */
iTwdCtrl.TxAlign.pFrame[iTwdCtrl.TxAlign.uCurrSend] = (void*)aFrame;
/* For the next packet to be send */
iTwdCtrl.TxAlign.uCurrSend++;
iTwdCtrl.TxAlign.uCurrSend %= MAX_XFER_WAITING_PACKETS;
return WHA::KSuccess;
}
/**
* \fn AlignTxSecurityForUMAC
* \brief security alignment.
*
* Handle packet alignment after Xfer done
* It is done here after the pointer was changed in TIWha::SendPacket()
* and at this point the pointer is not needed any more.
* \note
* \return
* \sa
*/
void TIWha::AlignTxSecurityForUMAC (TBool aQFull)
{
TRACE5(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "AlignTxSecurityForUMAC(): send = %d Handle = %d, QoS = %d, Offset = %d pFrame = %p\n",iTwdCtrl.TxAlign.uCurrSend, iTwdCtrl.TxAlign.uCurrHandle,iTwdCtrl.TxAlign.bIsQosHeader[iTwdCtrl.TxAlign.uCurrHandle],
iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrHandle],iTwdCtrl.TxAlign.pFrame[iTwdCtrl.TxAlign.uCurrHandle]);
if (aQFull) {
iTwdCtrl.TxAlign.uCurrSend = iTwdCtrl.TxAlign.uCurrSend > 0? iTwdCtrl.TxAlign.uCurrSend - 1 : 49;
TRACE5(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "AlignTxSecurityForUMAC() -- ** aQFull **: send = %d Handle = %d, QoS = %d, Offset = %d pFrame = %p\n",iTwdCtrl.TxAlign.uCurrSend, iTwdCtrl.TxAlign.uCurrHandle,iTwdCtrl.TxAlign.bIsQosHeader[iTwdCtrl.TxAlign.uCurrHandle],
iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrHandle],iTwdCtrl.TxAlign.pFrame[iTwdCtrl.TxAlign.uCurrHandle]);
ALIGN_HEADER_TO_DATA_BACKWARD (iTwdCtrl.TxAlign.pFrame[iTwdCtrl.TxAlign.uCurrSend],
iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrSend],
iTwdCtrl.TxAlign.bIsQosHeader[iTwdCtrl.TxAlign.uCurrSend])
return;
}
/* Check if the packet should be aligned */
if (iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrHandle])
{
ALIGN_HEADER_TO_DATA_BACKWARD (iTwdCtrl.TxAlign.pFrame[iTwdCtrl.TxAlign.uCurrHandle],
iTwdCtrl.TxAlign.uHeaderToDataOffset[iTwdCtrl.TxAlign.uCurrHandle],
iTwdCtrl.TxAlign.bIsQosHeader[iTwdCtrl.TxAlign.uCurrHandle])
}
/* For the next packet to be handled */
iTwdCtrl.TxAlign.uCurrHandle++;
iTwdCtrl.TxAlign.uCurrHandle %= MAX_XFER_WAITING_PACKETS;
}
/**
* \fn TxXferCb
* \brief
* Called by the TNETW driver upon Xfer-Done of transmitted packet.
* Calls the UMAC Xfer-Done handler.
*
* \note
* \return
* \sa
*/
void TIWha::TxXferCb ( TTxCtrlBlk *pPktCtrlBlk)
{
TRACE2(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "TxXferCb(): packetId=0x%x flags = 0x%x\n",iPacketIdTable[pPktCtrlBlk->tTxDescriptor.descID], pPktCtrlBlk->tTxPktParams.uFlags);
#ifdef TI_DBG
/* If the pointed entry is already free, print error and exit (not expected to happen). */
if (pPktCtrlBlk->pNextFreeEntry != NULL)
{
TRACE3(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "TxXferCb(): Pkt already free!!, DescID=%d, flags=%d, packetId=0x%x\n",pPktCtrlBlk->tTxDescriptor.descID, pPktCtrlBlk->tTxPktParams.uFlags,iPacketIdTable[pPktCtrlBlk->tTxDescriptor.descID]);
return;
}
#endif
/* Check If this is the second time we call TxXferCb for this packet (i.e. TxCompleteCb called it explicitly) */
if (pPktCtrlBlk->tTxPktParams.uFlags & TX_CTRL_FLAG_XFER_DONE_ISSUED)
{
/* TRACE2(iTwdCtrl.hReport, REPORT_SEVERITY_ERROR, TIWLANWHA_MODULE_LOG, MSG_2262, "TxXferCb(): already called for this packet!!, DescID=%d, flags=%d, packetId=0x%x\n",pPktCtrlBlk->tTxDescriptor.descID, pPktCtrlBlk->tTxPktParams.uFlagsiPacketIdTable[pPktCtrlBlk->tTxDescriptor.descID]); */
}
else /* TxXferCB called for the first time. call UMAC */
{
pPktCtrlBlk->tTxPktParams.uFlags |= TX_CTRL_FLAG_XFER_DONE_ISSUED;
AlignTxSecurityForUMAC ();
TRACE1(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "TxXferCb(): call WhaCb()->SendPacketTransfer, descID= %d\n", pPktCtrlBlk->tTxDescriptor.descID);
TRACE1(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "TxXferCb(): call WhaCb()->SendPacketTransfer, PacketID= %d\n", iPacketIdTable[pPktCtrlBlk->tTxDescriptor.descID]);
if( bErrorIndication == TI_FALSE)
{
WhaCb()->SendPacketTransfer ((WHA::TPacketId)iPacketIdTable[pPktCtrlBlk->tTxDescriptor.descID]);
}
#if TI_DBG
else
{
WLAN_OS_REPORT(("%s : CommandResponse Block call to LDD response \n",__FUNCTION__));
}
#endif
}
}
/**
* \fn TxCompleteCb
* \brief Called upon Tx-complete of transmitted packet.
* Handles it as follows:
* 1) Update the HwQueue to free queue resources.
* 2) Call the upper driver's tx-complete handler.
* 3) Free the packet's Control-Block if Xfer-Done already occured.
*
* \note
* \return
* \sa
*/
void TIWha::TxCompleteCb ( TxResultDescriptor_t *pTxResultInfo, TI_UINT32 backpressure)
{
/* Get the packet's control block pointer by the descId index. */
TTxCtrlBlk *pPktCtrlBlk = TWD_txCtrlBlk_GetPointer(iTwdCtrl.hTWD, pTxResultInfo->descID);
WHA::TStatus status;
TRACE3(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "TxCompleteCb(): DescID=%d, flags=%d, packetId=0x%x\n",
pTxResultInfo->descID, pPktCtrlBlk->tTxPktParams.uFlags,
iPacketIdTable[pPktCtrlBlk->tTxDescriptor.descID]);
#ifdef TI_DBG
/* If the pointed entry is already free, print error and exit (not expected to happen). */
if (pPktCtrlBlk->pNextFreeEntry != NULL)
{
TRACE3(iTwdCtrl.hReport, REPORT_SEVERITY_INFORMATION, "TxCompleteCb(): Pkt already free!!, DescID=%d, flags=%d, packetId=0x%x\n",
pPktCtrlBlk->tTxDescriptor.descID, pPktCtrlBlk->tTxPktParams.uFlags,
iPacketIdTable[pPktCtrlBlk->tTxDescriptor.descID]);
return;
}
#endif
/* Check if TxXferCb was called for this packet */
if ((pPktCtrlBlk->tTxPktParams.uFlags & TX_CTRL_FLAG_XFER_DONE_ISSUED) == 0)
{
/* Xfer was not called, so call it here. Note that once TxComplete was called, there will be no TxXfer */
TxXferCb (pPktCtrlBlk);
}
/* We return Success on every tx result because of stange behaviour in the upper layer */
/* It seems that on results other than success the OS closes the socket */
switch (pTxResultInfo->status)
{
case TX_SUCCESS:
status = WHA::KSuccess;
break;
case TX_RETRY_EXCEEDED:
status = WHA::KErrorRetryExceeded;
WLAN_OS_REPORT(("ERROR: TxCompletewith status = %d",pTxResultInfo->status));
break;
case TX_TIMEOUT:
status = WHA::KErrorLifetimeExceeded;
WLAN_OS_REPORT(("ERROR: TxCompletewith status = %d",pTxResultInfo->status));
break;
case TX_PEER_NOT_FOUND:
status = WHA::KErrorNoLink;
WLAN_OS_REPORT(("ERROR: TxCompletewith status = %d",pTxResultInfo->status));
break;
case TX_DISABLED:
status = WHA::KErrorMacNotResponding;
WLAN_OS_REPORT(("ERROR: TxCompletewith status = %d",pTxResultInfo->status));
break;
default:
status = WHA::KFailed;
WLAN_OS_REPORT(("ERROR: TxCompletewith status = %d",pTxResultInfo->status));
break;
}
/* Call the UMAC tx-complete handler */
if( bErrorIndication == TI_FALSE)
{
WhaCb()->SendPacketComplete( status,
(WHA::TPacketId)iPacketIdTable[pPktCtrlBlk->tTxDescriptor.descID],
TIWhaUtils::PolicyToWhaRate ((ETxRateClassId)pTxResultInfo->rate),
pTxResultInfo->mediumDelay, /* aPacketQueueDelay */
pTxResultInfo->fwHandlingTime, /* aMediaDelay */
pTxResultInfo->ackFailures);
}
#if TI_DBG
else
{
WLAN_OS_REPORT(("%s : CommandResponse Block call to LDD response \n",__FUNCTION__));
}
#endif
/* Free Ctrl block. */
TWD_txCtrlBlk_Free(iTwdCtrl.hTWD, pPktCtrlBlk);
}