--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanldd/wlan_symbian/wlanldd_symbian/src/FrameXferBlock.cpp Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,589 @@
+/*
+* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Implementation of the RFrameXferBlock class.
+*
+*/
+
+/*
+* %version: 16 %
+*/
+
+#include "WlLddWlanLddConfig.h"
+#include "FrameXferBlock.h"
+#include "wlanlddcommon.h"
+#include "algorithm.h"
+#include <kernel.h> // for Kern::SystemTime()
+
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void RFrameXferBlockBase::KeInitialize()
+ {
+ iRxDataChunk = NULL;
+
+ for ( TUint32 i = 0; i < KMaxCompletedRxBufs; ++i )
+ {
+ iRxCompletedBuffers[i] = 0;
+ }
+
+ for ( TUint j = 0; j < TDataBuffer::KFrameTypeMax; ++j )
+ {
+ iTxOffset[j] = 0;
+ }
+
+ iNumOfCompleted = 0;
+ iCurrentRxBuffer = 0;
+ iFirstRxBufferToFree = 0;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void RFrameXferBlockBase::KeRxComplete(
+ const TUint32* aRxCompletionBuffersArray,
+ TUint32 aNumOfCompleted )
+ {
+ if ( aNumOfCompleted > KMaxCompletedRxBufs )
+ {
+ os_assert( (TUint8*)("WLANLDD: panic"), (TUint8*)(WLAN_FILE), __LINE__ );
+ }
+
+ assign( aRxCompletionBuffersArray, iRxCompletedBuffers, aNumOfCompleted );
+ iNumOfCompleted = aNumOfCompleted;
+ iCurrentRxBuffer = 0;
+ iFirstRxBufferToFree = 0;
+
+ for ( TUint i = 0; i < iNumOfCompleted; ++i )
+ {
+ TraceDump( RX_FRAME,
+ (("WLANLDD: RFrameXferBlockBase::KeRxComplete: completed offset addr: 0x%08x"),
+ iRxCompletedBuffers[i]) );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void RFrameXferBlockBase::KeGetHandledRxBuffers(
+ const TUint32*& aRxHandledBuffersArray,
+ TUint32& aNumOfHandled )
+ {
+ TUint32 numHandled ( iCurrentRxBuffer - iFirstRxBufferToFree );
+
+ // make sure that if an Rx buffer is currently being processed by the user
+ // side client, that buffer is not regarded as being already handled
+ numHandled = numHandled ? numHandled - 1 : numHandled;
+
+ if ( numHandled )
+ {
+ aRxHandledBuffersArray = &(iRxCompletedBuffers[iFirstRxBufferToFree]);
+ aNumOfHandled = numHandled;
+
+ iFirstRxBufferToFree += numHandled;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void RFrameXferBlockBase::KeAllUserSideRxBuffersFreed()
+ {
+ iFirstRxBufferToFree = 0;
+ // need to reset also the current index, so that the difference of these
+ // two indexes is zero, and it then correctly indicates, that there are no
+ // Rx buffers which could be freed incrementally
+ iCurrentRxBuffer = 0;
+ }
+
+// ---------------------------------------------------------------------------
+//
+// ---------------------------------------------------------------------------
+//
+void RFrameXferBlockBase::KeSetTxOffsets(
+ TUint32 aEthernetFrameTxOffset,
+ TUint32 aDot11FrameTxOffset,
+ TUint32 aSnapFrameTxOffset )
+ {
+ iTxOffset[TDataBuffer::KEthernetFrame] = aEthernetFrameTxOffset;
+ iTxOffset[TDataBuffer::KDot11Frame] = aDot11FrameTxOffset;
+ iTxOffset[TDataBuffer::KSnapFrame] = aSnapFrameTxOffset;
+ iTxOffset[TDataBuffer::KEthernetTestFrame] = aEthernetFrameTxOffset;
+
+ for ( TUint i = 0; i < TDataBuffer::KFrameTypeMax ; ++i )
+ {
+ TraceDump( RX_FRAME,
+ (("WLANLDD: RFrameXferBlockBase::KeSetTxOffsets: offset: %d"),
+ iTxOffset[i]) );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+void RFrameXferBlockProtocolStack::Initialise()
+ {
+ // perform base class initialization
+ KeInitialize();
+
+ iThisAddrKernelSpace = reinterpret_cast<TUint32>(this);
+
+ iVoiceTxQueue.DoInit();
+ iVideoTxQueue.DoInit();
+ iBestEffortTxQueue.DoInit();
+ iBackgroundTxQueue.DoInit();
+ iFreeQueue.DoInit();
+
+ for ( TUint i = 0; i < KTxPoolSizeInPackets; i++ )
+ {
+ // Set the default values
+
+ iDataBuffers[i].FrameType( TDataBuffer::KEthernetFrame );
+ iDataBuffers[i].KeClearFlags( TDataBuffer::KTxFrameMustNotBeEncrypted );
+ iDataBuffers[i].SetLength( 0 );
+ iDataBuffers[i].SetUserPriority( 0 );
+
+ iFreeQueue.PutPacket( &iDataBuffers[i] );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TDataBuffer* RFrameXferBlockProtocolStack::AllocTxBuffer(
+ const TUint8* aTxBuf,
+ TUint16 aBufLength )
+ {
+ TDataBuffer* packet( NULL );
+
+ if ( aTxBuf )
+ {
+ // Get Packet from Free Queue
+ packet = iFreeQueue.GetPacket();
+
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: RFrameXferBlockProtocolStack::AllocTxBuffer: krn metahdr addr: 0x%08x"),
+ packet) );
+
+ if ( packet )
+ {
+ packet->KeSetBufferOffset(
+ aTxBuf - reinterpret_cast<TUint8*>(packet) );
+
+ packet->SetBufLength( aBufLength );
+
+ // reserve appropriate amount of empty space before the Ethernet
+ // frame so that there is space for all the necessary headers, including
+ // the 802.11 MAC header
+ packet->KeSetOffsetToFrameBeginning(
+ iTxOffset[TDataBuffer::KEthernetFrame] );
+
+ // return the user space address
+ packet = reinterpret_cast<TDataBuffer*>(
+ reinterpret_cast<TUint8*>(packet) - iUserToKernAddrOffset);
+ }
+ }
+
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: RFrameXferBlockProtocolStack::AllocTxBuffer: user metahdr addr: 0x%08x"),
+ packet) );
+
+ return packet;
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TBool RFrameXferBlockProtocolStack::AddTxFrame(
+ TDataBuffer* aPacketInUserSpace,
+ TDataBuffer*& aPacketInKernSpace,
+ TBool aUserDataTxEnabled )
+ {
+ TBool ret( ETrue );
+ aPacketInKernSpace = NULL;
+ TDataBuffer* metaHdrInKernSpace ( reinterpret_cast<TDataBuffer*>(
+ reinterpret_cast<TUint8*>(aPacketInUserSpace) + iUserToKernAddrOffset) );
+
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: RFrameXferBlockProtocolStack::AddTxFrame: user metahdr addr: 0x%08x"),
+ aPacketInUserSpace));
+
+ // put the packet to the correct Tx queue according to the priority to AC
+ // mapping defined in WiFi WMM Specification v1.1
+
+ if ( aPacketInUserSpace->UserPriority() == 7 ||
+ aPacketInUserSpace->UserPriority() == 6 )
+ {
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: add to VO queue; krn metahdr addr: 0x%08x"),
+ reinterpret_cast<TUint32>(metaHdrInKernSpace)));
+
+ ret = iVoiceTxQueue.PutPacket( metaHdrInKernSpace );
+
+ if ( !ret )
+ {
+ aPacketInKernSpace = metaHdrInKernSpace;
+ }
+
+ ret = TxFlowControl( EVoice, aUserDataTxEnabled );
+ }
+ else if ( aPacketInUserSpace->UserPriority() == 5 ||
+ aPacketInUserSpace->UserPriority() == 4 )
+ {
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: add to VI queue; krn metahdr addr: 0x%08x"),
+ reinterpret_cast<TUint32>(metaHdrInKernSpace)));
+
+ ret = iVideoTxQueue.PutPacket( metaHdrInKernSpace );
+
+ if ( !ret )
+ {
+ aPacketInKernSpace = metaHdrInKernSpace;
+ }
+
+ ret = TxFlowControl( EVideo, aUserDataTxEnabled );
+ }
+ else if ( aPacketInUserSpace->UserPriority() == 2 ||
+ aPacketInUserSpace->UserPriority() == 1 )
+ {
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: add to BG queue; krn metahdr addr: 0x%08x"),
+ reinterpret_cast<TUint32>(metaHdrInKernSpace)));
+
+ ret = iBackgroundTxQueue.PutPacket( metaHdrInKernSpace );
+
+ if ( !ret )
+ {
+ aPacketInKernSpace = metaHdrInKernSpace;
+ }
+
+ ret = TxFlowControl( EBackGround, aUserDataTxEnabled );
+ }
+ else
+ {
+ // user priority is 3 or 0 or invalid
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: add to BE queue; krn metahdr addr: 0x%08x"),
+ reinterpret_cast<TUint32>(metaHdrInKernSpace)));
+
+ ret = iBestEffortTxQueue.PutPacket( metaHdrInKernSpace );
+
+ if ( !ret )
+ {
+ aPacketInKernSpace = metaHdrInKernSpace;
+ }
+
+ ret = TxFlowControl( ELegacy, aUserDataTxEnabled );
+ }
+
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: VO: %d packets"),
+ iVoiceTxQueue.GetLength()));
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: VI: %d packets"),
+ iVideoTxQueue.GetLength()));
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: BE: %d packets"),
+ iBestEffortTxQueue.GetLength()));
+ TraceDump( NWSA_TX_DETAILS,
+ (("WLANLDD: BG: %d packets"),
+ iBackgroundTxQueue.GetLength()));
+
+ return ret;
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TDataBuffer* RFrameXferBlockProtocolStack::GetTxFrame(
+ const TWhaTxQueueState& aWhaTxQueueState,
+ TBool& aMore )
+ {
+ TraceDump( NWSA_TX_DETAILS,
+ ("WLANLDD: RFrameXferBlockProtocolStack::GetTxFrame"));
+ TraceDump( NWSA_TX_DETAILS, (("WLANLDD: VO: %d packets"),
+ iVoiceTxQueue.GetLength()));
+ TraceDump( NWSA_TX_DETAILS, (("WLANLDD: VI: %d packets"),
+ iVideoTxQueue.GetLength()));
+ TraceDump( NWSA_TX_DETAILS, (("WLANLDD: BE: %d packets"),
+ iBestEffortTxQueue.GetLength()));
+ TraceDump( NWSA_TX_DETAILS, (("WLANLDD: BG: %d packets"),
+ iBackgroundTxQueue.GetLength()));
+
+ TDataBuffer* packet = NULL;
+ TQueueId queueId ( EQueueIdMax );
+
+ if ( TxPossible( aWhaTxQueueState, queueId ) )
+ {
+ switch ( queueId )
+ {
+ case EVoice:
+ packet = iVoiceTxQueue.GetPacket();
+ break;
+ case EVideo:
+ packet = iVideoTxQueue.GetPacket();
+ break;
+ case ELegacy:
+ packet = iBestEffortTxQueue.GetPacket();
+ break;
+ case EBackGround:
+ packet = iBackgroundTxQueue.GetPacket();
+ break;
+#ifndef NDEBUG
+ default:
+ TraceDump(ERROR_LEVEL, (("WLANLDD: queueId: %d"), queueId));
+ os_assert(
+ (TUint8*)("WLANLDD: panic"),
+ (TUint8*)(WLAN_FILE),
+ __LINE__ );
+#endif
+ }
+
+ aMore = TxPossible( aWhaTxQueueState, queueId );
+ }
+ else
+ {
+ aMore = EFalse;
+ }
+
+ TraceDump( NWSA_TX_DETAILS, (("WLANLDD: krn meta hdr: 0x%08x"),
+ reinterpret_cast<TUint32>(packet)));
+
+ return packet;
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TBool RFrameXferBlockProtocolStack::ResumeClientTx(
+ TBool aUserDataTxEnabled ) const
+ {
+ TBool ret ( EFalse );
+
+ const TInt64 KTimeNow ( Kern::SystemTime() );
+
+ if ( aUserDataTxEnabled )
+ {
+ // Note that in what follows below we want to consider resuming the
+ // client Tx flow only based on the highest priority queue which is
+ // currently active. In other words: if we find that some queue is
+ // currently active but we don't want to resume the Tx flow yet
+ // based on its situation, we must not consider resuming the Tx flow
+ // based on any other queue with lower priority.
+
+ if ( iVoiceTxQueue.IsActive( KTimeNow ) )
+ {
+ if ( iVoiceTxQueue.GetLength() <
+ ( KVoiceTxQueueLen / 2 ) )
+ {
+ ret = ETrue;
+ }
+ }
+ else if ( iVideoTxQueue.IsActive( KTimeNow ) )
+ {
+ if ( iVideoTxQueue.GetLength() <
+ ( KVideoTxQueueLen / 2 ) )
+ {
+ ret = ETrue;
+ }
+ }
+ else if ( iBestEffortTxQueue.IsActive( KTimeNow ) )
+ {
+ if ( iBestEffortTxQueue.GetLength() <
+ ( KBestEffortTxQueueLen / 2 ) )
+ {
+ ret = ETrue;
+ }
+ }
+ else if ( iBackgroundTxQueue.IsActive( KTimeNow ) )
+ {
+ if ( iBackgroundTxQueue.GetLength() <
+ ( KBackgroundTxQueueLen / 2 ) )
+ {
+ ret = ETrue;
+ }
+ }
+ else
+ {
+ // none of the Tx queues is currently active (meaning also that
+ // they are all empty), but as this method was called, the
+ // client Tx flow has to be currently stopped. So now - at the
+ // latest - we need to resume the client Tx flow
+ ret = ETrue;
+ }
+ }
+ else
+ {
+ // as client Tx flow has been stopped and user data Tx is disabled
+ // (which probably means that we are roaming), its not feasible to
+ // resume the client Tx flow yet. So, no action needed;
+ // EFalse is returned
+ }
+
+#ifndef NDEBUG
+ if ( ret )
+ {
+ TraceDump( NWSA_TX,
+ ("WLANLDD: RFrameXferBlockProtocolStack::ResumeClientTx: resume flow from protocol stack"));
+ }
+#endif
+
+ return ret;
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TBool RFrameXferBlockProtocolStack::TxPossible(
+ const TWhaTxQueueState& aWhaTxQueueState,
+ TQueueId& aQueueId )
+ {
+ TBool txPossible ( ETrue );
+
+ // In queue priority order, try to locate a Tx packet which is for a
+ // non-full WHA Tx queue
+
+ if ( aWhaTxQueueState[EVoice] == ETxQueueNotFull &&
+ !iVoiceTxQueue.IsEmpty() )
+ {
+ aQueueId = EVoice;
+
+ TraceDump( NWSA_TX_DETAILS,
+ ("WLANLDD: RFrameXferBlockProtocolStack::TxPossible: from VO queue"));
+ }
+ else if ( aWhaTxQueueState[EVideo] == ETxQueueNotFull &&
+ !iVideoTxQueue.IsEmpty() )
+ {
+ aQueueId = EVideo;
+
+ TraceDump( NWSA_TX_DETAILS,
+ ("WLANLDD: RFrameXferBlockProtocolStack::TxPossible: from VI queue"));
+ }
+ else if ( aWhaTxQueueState[ELegacy] == ETxQueueNotFull &&
+ !iBestEffortTxQueue.IsEmpty() )
+ {
+ aQueueId = ELegacy;
+
+ TraceDump( NWSA_TX_DETAILS,
+ ("WLANLDD: RFrameXferBlockProtocolStack::TxPossible: from BE queue"));
+ }
+ else if ( aWhaTxQueueState[EBackGround] == ETxQueueNotFull &&
+ !iBackgroundTxQueue.IsEmpty() )
+ {
+ aQueueId = EBackGround;
+
+ TraceDump( NWSA_TX_DETAILS,
+ ("WLANLDD: RFrameXferBlockProtocolStack::TxPossible: from BG queue"));
+ }
+ else
+ {
+ txPossible = EFalse;
+
+ TraceDump( NWSA_TX_DETAILS,
+ ("WLANLDD: RFrameXferBlockProtocolStack::TxPossible: no packet for a non-full wha queue"));
+ }
+
+ return txPossible;
+ }
+
+// -----------------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------------
+//
+TBool RFrameXferBlockProtocolStack::TxFlowControl(
+ TQueueId aTxQueue,
+ TBool aUserDataTxEnabled )
+ {
+ TInt status ( ETrue );
+
+ switch ( aTxQueue )
+ {
+ case EVoice:
+ if ( iVoiceTxQueue.IsFull() )
+ {
+ status = EFalse;
+ }
+ break;
+ case EVideo:
+ if ( iVideoTxQueue.IsFull() )
+ {
+ if ( !aUserDataTxEnabled )
+ {
+ status = EFalse;
+ }
+ else if ( !iVoiceTxQueue.IsActive( Kern::SystemTime() ) )
+ {
+ status = EFalse;
+ }
+ }
+ break;
+ case ELegacy:
+ {
+ const TInt64 KTimeNow ( Kern::SystemTime() );
+
+ if ( iBestEffortTxQueue.IsFull() )
+ {
+ if ( !aUserDataTxEnabled )
+ {
+ status = EFalse;
+ }
+ else if ( !iVoiceTxQueue.IsActive( KTimeNow ) &&
+ !iVideoTxQueue.IsActive( KTimeNow ) )
+ {
+ status = EFalse;
+ }
+ }
+ break;
+ }
+ case EBackGround:
+ {
+ const TInt64 KTimeNow ( Kern::SystemTime() );
+
+ if ( iBackgroundTxQueue.IsFull() )
+ {
+ if ( !aUserDataTxEnabled )
+ {
+ status = EFalse;
+ }
+ else if ( !iVoiceTxQueue.IsActive( KTimeNow ) &&
+ !iVideoTxQueue.IsActive( KTimeNow ) &&
+ !iBestEffortTxQueue.IsActive( KTimeNow ) )
+ {
+ status = EFalse;
+ }
+ }
+ break;
+ }
+#ifndef NDEBUG
+ default:
+ TraceDump(ERROR_LEVEL, (("WLANLDD: aTxQueue: %d"), aTxQueue));
+ os_assert(
+ (TUint8*)("WLANLDD: panic"),
+ (TUint8*)(WLAN_FILE),
+ __LINE__ );
+#endif
+ }
+
+ return status;
+ }