--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/platforms/os/Symbian/WVSS/src/wha/TIWhaTxRx.cpp Tue Jun 29 12:34:26 2010 +0100
@@ -0,0 +1,963 @@
+/*
+ * 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);
+}
+
+