wlan_bearer/wlanldd/wlan_symbian/wlanldd_symbian/src/FrameXferBlock.cpp
changeset 0 c40eb8fe8501
child 22 c6a1762761b8
--- /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;
+    }