/*
* 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:   Declaration of the TDataBuffer and the RFrameXferBlock class.
*
*/

/*
* %version: 25 %
*/

#ifndef FRAMEXFERBLOCK_H
#define FRAMEXFERBLOCK_H

#include "802dot11.h"
#include "umac_types.h"
#include "pack.h"
#include "wllddcircularbuffer.h"

/** Max number of completed Rx buffers */
static const TUint KMaxCompletedRxBufs = 300;

/** Max number of to be completed Rx buffers */
static const TUint KMaxToBeCompletedRxBufs = KMaxCompletedRxBufs;

/** 
* This value (bytes) should be at least as large as the Tx offset required
* by the used WLAN vendor implementation. 
* As we need to decide the max size of the Tx buffers already at compile
* time, we use this value when doing that.
* If the value is too small, WLAN Mgmt client may receive an error when trying 
* to submit a close to maximum length frame for transmit
*/
static const TUint KVendorTxHdrMax = 200;

/** 
* Extra space to enable us to align the start of a 802.11 MAC Tx frame on four 
* byte boundary, if it isn't aligned already. Shall also make the total
* buffer length divisible by four
*/
static const TUint KSpaceForAlignment = 4;

/** 
* This value (bytes) should be at least as large as the Tx trailer space 
* required by the used WLAN vendor implementation.
* The other comments for KVendorTxHdrMax (above) apply also to this value.
*/
static const TUint KVendorTxTrailerMax = 4;

/** 
* The length (in bytes) of the only WLAN Mgmt client Tx buffer
*/
static const TUint KMgmtSideTxBufferLength =                 // 2576
    KVendorTxHdrMax +                                        //  200
    KMaxDot11TxMpduLength +                                  // 2368
    KSpaceForAlignment +                                     //    4
    KVendorTxTrailerMax;                                     //    4

/** Protocol Stack Side client's Tx queue max lengths in packets */

static const TUint KVoiceTxQueueLen = 4;
static const TUint KVideoTxQueueLen = 8;
static const TUint KBestEffortTxQueueLen = 24;
static const TUint KBackgroundTxQueueLen = 4;

/** 
 * Estimates used for calculating the total Protocol Stack Side client Tx 
 * memory pool size 
 */

static const TUint KEthernetVoiceTxFrameLenEstimate = 256;
static const TUint KEthernetVideoTxFrameLenEstimate = 1024;
static const TUint KEthernetBestEffortTxFrameLenEstimate = 
                       KMaxEthernetFrameLength;
static const TUint KEthernetBackgroundTxFrameLenEstimate = 
                       KMaxEthernetFrameLength;

static const TUint KVendorTxHdrLenEstimate = 64;
static const TUint KVendorTxTrailerLenEstimate = 4;

static const TUint KProtocolStackSideFrameLenOverhead = 
    KVendorTxHdrLenEstimate +
    KHtQoSMacHeaderLength +  
    KMaxDot11SecurityEncapsulationLength +
    sizeof( SSnapHeader ) +
    KSpaceForAlignment +
    KVendorTxTrailerLenEstimate;

/** 
* Protocol stack side Tx memory pool size in packets
*/
static const TUint KTxPoolSizeInPackets = 
    KVoiceTxQueueLen +
    KVideoTxQueueLen +
    KBestEffortTxQueueLen +
    KBackgroundTxQueueLen;

/** 
* Protocol stack side Tx data chunk size in bytes
* Note! Needs to be divisible by 4
*/
static const TUint KProtocolStackSideTxDataChunkSize = 
    KVoiceTxQueueLen * ( KEthernetVoiceTxFrameLenEstimate + 
                         KProtocolStackSideFrameLenOverhead ) +
    KVideoTxQueueLen * ( KEthernetVideoTxFrameLenEstimate + 
                         KProtocolStackSideFrameLenOverhead ) +
    KBestEffortTxQueueLen * ( KEthernetBestEffortTxFrameLenEstimate +
                              KProtocolStackSideFrameLenOverhead ) +
    KBackgroundTxQueueLen * ( KEthernetBackgroundTxFrameLenEstimate + 
                              KProtocolStackSideFrameLenOverhead );                        
    
/**
*  Meta header for Rx and Tx frames
*
*  @since S60 v3.1
*/
#pragma pack( 1 )
class TDataBuffer 
    {
    friend class RFrameXferBlock; 
    friend class RFrameXferBlockProtocolStack; // because of SetLength()

public:

    typedef TUint32 TFrameType;

    /** ethernet II frame */
    static const TFrameType KEthernetFrame      = 0;
    /** complete 802.11 frame */
    static const TFrameType KDot11Frame         = 1;
    /** frame beginning with a SNAP header */
    static const TFrameType KSnapFrame          = 2;
    /** ethernet II frame used to test an AP */
    static const TFrameType KEthernetTestFrame  = 3;
    /** upper bound, so not a real type */
    static const TFrameType KFrameTypeMax       = 4;

    typedef TUint32 TFlag;
    
    /** 
    * flag indicating that the associated Rx buffer shall not be released 
    * when releasing this meta header 
    */
    static const TFlag KDontReleaseBuffer = ( 1 << 0 );
    /** 
    * flag indicating that the Tx frame in the associated buffer shall not 
    * be encrypted even if a valid encryption key existed. If not set, the
    * frame may be encrypted if a valid key exists
    */
    static const TFlag KTxFrameMustNotBeEncrypted = ( 1 << 1 );
    
public:

    /**
    * Appends data to Tx Buffer
    * @param aData data to be apended
    * @param aLength length of data in bytes
    * @return KErrNone on success,
    *         KErrOverflow if aLength is greater than the available space in
    *         the buffer
    */
    inline TInt AppendBuffer( 
        const TUint8* aData, 
        TUint32 aLength );

    /**
    * Gets length of the data in the buffer
    *
    * @since S60 3.1
    * @return length of the data in the buffer
    */
    inline TUint32 GetLength() const;

    /**
    * Gets the begin of the buffer
    *
    * @since S60 3.1
    * @return beginning of the buffer
    */
    inline const TUint8* GetBuffer() const;

    /**
    * Gets the beginning of the buffer
    *
    * @since S60 3.1
    * @return begin of the buffer
    */
    inline TUint8* GetBuffer();

    /**
    * Gets the frame type in the buffer
    *
    * @since S60 3.1
    * @return frame type in the buffer
    */
    inline TFrameType FrameType() const;

    /**
    * Sets the frame type in the buffer
    *
    * @since S60 3.1
    */
    inline void FrameType( TFrameType aFrameType );

    /**
    * Sets the 802.1D User Priority of the frame
    *
    * @since S60 3.2
    * @param aUp UP value to be set
    */
    inline void SetUserPriority( TUint8 aUp );

    /**
    * Gets the 802.1D User Priority of the frame
    *
    * @since S60 3.2
    * @return UP value
    */
    inline TUint8 UserPriority() const;

    /**
    * Gets the RCPI value of a received frame
    *
    * @since S60 3.2
    * @return RCPI value
    */
    inline TUint8 Rcpi() const;

    
    //////////////////////////////////////////////////////////////////////////
    // Rest of the methods are meant to be used only in the device driver code
    //////////////////////////////////////////////////////////////////////////

    /**
    * Gets the beginning of the data buffer
    * NOTE: to be used only by the device driver
    *
    * @return Buffer beginning
    */
    inline TUint8* KeGetBufferStart() const;
    
    /**
    * Sets the specified flag(s)
    * NOTE: to be used only by the device driver
    *
    * @param aFlag The flag(s) to set
    */
    inline void KeSetFlags( TFlag aFlags );

    /**
    * Returns the flags set in this object
    * NOTE: to be used only by the device driver
    *
    * @return Flags set in this object
    */
    inline TFlag KeFlags() const;
    
    /**
    * Clears the specified flag(s)
    * NOTE: to be used only by the device driver
    *
    * @param aFlag The flag(s) to clear
    */
    inline void KeClearFlags( TFlag aFlags );


#ifdef __KERNEL_MODE__ /* Kernel mode */
    
    /**
    * Sets the RCPI value of a received frame
    * NOTE: to be used only by the device driver
    *
    * @since S60 3.2
    * @param aRcpi RCPI value to be set
    */
    inline void KeSetRcpi( TUint8 aRcpi );

   /**
    * Gets the Destination Address of the frame to be transmitted
    * NOTE: to be used only by the device driver
    *
    * @return Destination Address
    */
    inline const TMacAddress& KeDestinationAddress() const;

    /**
    * Sets the offset to actual frame beginning within the data buffer
    * NOTE: to be used only by the device driver
    *
    * @param aOffset Offset to frame beginning
    */
    inline void KeSetOffsetToFrameBeginning( TUint32 aOffset );

    /**
    * Returns the offset to actual frame beginning within the data buffer
    * NOTE: to be used only by the device driver
    *
    * @return Offset to frame beginning
    */
    inline TUint32 KeOffsetToFrameBeginning() const;

    /**
    * Sets the offset from the start address of this object to the actual data 
    * buffer start address
    * NOTE: to be used only by the device driver
    *
    * @param aOffset Offset to data buffer start address. May be positive or 
    *        negative.
    */
    inline void KeSetBufferOffset( TInt32 aOffset );
    
    /**
    * Sets the length field
    * NOTE: to be used only by the device driver
    *
    * @since S60 3.1
    * @param aLength length to be set
    */
    inline void KeSetLength( TUint32 aLength )
        {
        iLength = aLength;
        };

#endif /* Kernel mode end */
    
private:

    /** Default Ctor */
    TDataBuffer() :
        iFrameType( KEthernetFrame ), 
        iLength( 0 ), 
        iUp( 0 ), 
        iRcpi( 0 ),
        iDestinationAddress( KZeroMacAddr ),
        iBufLength( 0 ),
        iOffsetToFrameBeginning( 0 ),
        iBufferOffsetAddr( sizeof( TDataBuffer ) ),
        iFlags( 0 )
        {};

    /**
    * Adds a value to the length field
    * @param aValue length to be set
    */
    inline void IncrementLength( TUint32 aValue );

    /**
    * Appends data to Buffer
    * @param aData data to be apended
    * @param aLength length of data in BYTEs
    * @param aOffsetToFrameBeginning Amount of empty space to leave in the
    *        beginning of the buffer, i.e. before the frame beginning
    */
    inline void AppendBuffer( 
        const TUint8* aData, 
        TUint32 aLength,
        TUint32 aOffsetToFrameBeginning );

    /**
    * Sets the length field
    * @param aLength length to be set
    */
    inline void SetLength( TUint32 aLength );

    /**
    * Sets the length of the attached data buffer
    * @param aBufLength length to be set
    */
    inline void SetBufLength( TUint16 aBufLength );

    /**
    * Sets the Destination Address of the frame to be transmitted
    *
    * @param aDa Destination Address to be set
    */
    inline void SetDestinationAddress( const TMacAddress& aDa );

    /** Prohibit copy constructor */
    TDataBuffer( const TDataBuffer& );
    /** Prohibit assigment operator */
    TDataBuffer& operator= ( const TDataBuffer& );

private:    // Data

    /** type of the frame in buffer */
    TFrameType iFrameType;
        
    /** length of the data in buffer */
    TUint32 iLength;
    
    /** 
    * 802.1D User Priority of the frame
    * stored as a 32-bit value to keep the length of this object 32-bit
    * aligned
    */
    TUint32 iUp;

    /** 
    * RCPI of the received frame; range: [0..250]
    * stored as a 32-bit value to keep the length of this object 32-bit
    * aligned
    */
    TUint32 iRcpi;

    /** 
    * Destination address of the frame to be transmitted. Used only when
    * the address cannot be determined from the frame content  
    */
    TMacAddress iDestinationAddress;
    
    /** 
    * Length of the attached data buffer. Currently used only for Protocol
    * Stack Side client Tx frames 
    */
    TUint16 iBufLength;
    
    /** the offset to actual frame beginning within the data buffer */
    TUint32 iOffsetToFrameBeginning;

    /** 
    * the offset from the start address of this object to the start address 
    * of the data buffer. May be positive or negative.
    */
    TInt32 iBufferOffsetAddr;

    /** may contain a combination of the flags defined for this class */
    TFlag iFlags;
    
    /** 
    * Note! The total length of this object needs to be divisible by four
    * to enable the items following it to be correctly aligned. 
    */
    } __PACKED;
#pragma pack()

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline TInt TDataBuffer::AppendBuffer( 
    const TUint8* aData, 
    TUint32 aLength )
    {
    if ( aLength <= iBufLength - iLength )
        {
        os_memcpy( 
            KeGetBufferStart() + iOffsetToFrameBeginning + iLength, 
            aData, 
            aLength );
        IncrementLength( aLength );
        
        return KErrNone;
        }
    else
        {
        return KErrOverflow;
        }
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline TUint32 TDataBuffer::GetLength() const
    {
    return iLength;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline const TUint8* TDataBuffer::GetBuffer() const
    {
    return KeGetBufferStart() + iOffsetToFrameBeginning;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline TUint8* TDataBuffer::GetBuffer()
    {
    return KeGetBufferStart() + iOffsetToFrameBeginning;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline TDataBuffer::TFrameType TDataBuffer::FrameType() const
    {
    return iFrameType;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::FrameType( TFrameType aFrameType )
    {
    iFrameType = aFrameType;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::SetLength( TUint32 aLength )
    {
    iLength = aLength;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::SetBufLength( TUint16 aBufLength )
    {
    iBufLength = aBufLength;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::IncrementLength( TUint32 aValue )
    {
    iLength += aValue;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::AppendBuffer( 
    const TUint8* aData, 
    TUint32 aLength,
    TUint32 aOffsetToFrameBeginning )
    {
    iOffsetToFrameBeginning = aOffsetToFrameBeginning;
    os_memcpy( 
        KeGetBufferStart() + aOffsetToFrameBeginning + iLength, 
        aData, 
        aLength );
    IncrementLength( aLength );
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::SetUserPriority( TUint8 aUp )
    {
    iUp = aUp;
    }

// ---------------------------------------------------------------------------
// return as a TUint8 value as the range of User Priority is [0..7]
// ---------------------------------------------------------------------------
//
inline TUint8 TDataBuffer::UserPriority() const
    {
    return static_cast<TUint8>(iUp);
    }

// ---------------------------------------------------------------------------
// return as a TUint8 value as the range of RCPI is [0..250]
// ---------------------------------------------------------------------------
//
inline TUint8 TDataBuffer::Rcpi() const
    {
    return static_cast<TUint8>(iRcpi);
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::SetDestinationAddress( const TMacAddress& aDa )
    {
    iDestinationAddress = aDa;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline TUint8* TDataBuffer::KeGetBufferStart() const
    {
    return reinterpret_cast<TUint8*>(
        const_cast<TDataBuffer*>(this)) 
        + iBufferOffsetAddr;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::KeSetFlags( TFlag aFlags )
    {
    iFlags |= aFlags;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline TDataBuffer::TFlag TDataBuffer::KeFlags() const
    {
    return iFlags;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::KeClearFlags( TFlag aFlags )
    {
    iFlags &= ~aFlags;    
    }

#ifdef __KERNEL_MODE__ /* Kernel mode */
    
// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::KeSetRcpi( TUint8 aRcpi )
    {
    iRcpi = aRcpi;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline const TMacAddress& TDataBuffer::KeDestinationAddress() const
    {
    return iDestinationAddress;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::KeSetOffsetToFrameBeginning( TUint32 aOffset )
    {
    iOffsetToFrameBeginning = aOffset;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline TUint32 TDataBuffer::KeOffsetToFrameBeginning() const
    {
    return iOffsetToFrameBeginning;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void TDataBuffer::KeSetBufferOffset( TInt32 aOffset )
    {
    iBufferOffsetAddr = aOffset;
    }

#endif /* Kernel mode end */

/**
* Ethernet frame transfer context block base class between user and 
* kernel space
*/
class RFrameXferBlockBase
    {

public:

#ifndef __KERNEL_MODE__ /* User mode */
    
    /**
    * Gets next Rx-data buffer that has data to be read
    *
    * @since S60 3.1
    * @param aBuf OUT parameter where Rx-data buffers address that is to
    * be read is copied
    * @return ETrue Rx-data exists after this call still to read,
    * otherwise EFalse
    */
    inline TBool GetNextRxDataBuffer( TDataBuffer*& aBuf );

    //////////////////////////////////////////////////////////////////////////
    // Rest of the methods are meant to be used only in the device driver code
    //////////////////////////////////////////////////////////////////////////

    /**
    * Set data chunk address
    *
    * Note! This method is executed in user mode context by the user mode
    * client interface, i.e. not the client itself!
    * @since S60 3.1
    * @param aUserAddr user address of the buffer
    */
    inline void SetRxDataChunkField( TLinAddr aUserAddr );

#endif /* User mode end */

#ifdef __KERNEL_MODE__ /* Kernel mode */
    
    /**
    * Completes Rx buffers to user space
    *
    * @since S60 3.1
    * @param aRxCompletionBuffersArray Rx buffer addresses as offsets from
    *        Rx memory pool beginning
    * @param aNumOfCompleted number of buffers
    */
    void KeRxComplete( 
        const TUint32* aRxCompletionBuffersArray, 
        TUint32 aNumOfCompleted );

    /**
    * Gets the array of Rx buffers (their offset addresses) which have already
    * been handled by the user space client
    *
    * @since S60 5.0
    * @param aRxHandledBuffersArray Pointer to the beginning of the array
    * @param aNumOfHandled Number of buffers (offset addresses) on the array
    */
    void KeGetHandledRxBuffers( 
        const TUint32*& aRxHandledBuffersArray, 
        TUint32& aNumOfHandled );

    /**
    * Notes, that all Rx buffers, which were completed to user space
    * the previous time, are now free.
    *
    * @since S60 5.0
    */
    void KeAllUserSideRxBuffersFreed();

    /**
    * Sets the Tx offset for every frame type which can be transmitted
    *
    * @since S60 5.0
    * @param aEthernetFrameTxOffset Tx offset for Ethernet frames and Ethernet
    *        Test frames
    * @param aDot11FrameTxOffset Tx offset for 802.11 frames
    * @param aSnapFrameTxOffset Tx offset for SNAP frames
    */
    void KeSetTxOffsets( 
        TUint32 aEthernetFrameTxOffset,
        TUint32 aDot11FrameTxOffset,
        TUint32 aSnapFrameTxOffset );    

protected:
    
    /**
    * Initialises the buffer.
    *
    * @since S60 3.1
    */
    void KeInitialize();
    
#endif /* Kernel mode end */    
    
private:

    /** Prohibit default constructor */
    RFrameXferBlockBase();

    /** Prohibit copy constructor */
    RFrameXferBlockBase( const RFrameXferBlockBase& );
    /** Prohibit assigment operator */
    RFrameXferBlockBase& operator= ( const RFrameXferBlockBase& );
    
protected:    // Data

    /** the beginning of the Rx data area in user address space */
    TUint8*         iRxDataChunk;

    /**
    * number of Rx-data buffers that were completed by the device driver
    */
    TUint32         iNumOfCompleted;

    /**
    * index to iRxCompletedBuffers denoting the Rx buffer that is to be
    * extracted next by the user application
    */
    TUint32         iCurrentRxBuffer;

    /** 
    * index of the first Rx buffer in iRxCompletedBuffers array
    * - which the user side client has already handled and
    *   which can therefore be freed & re-used AND
    * - which hasn't been freed yet
    */
    TUint32         iFirstRxBufferToFree;
    
    /** 
    * defines a Tx offset for every frame type which can be transmitted
    */
    TUint32         iTxOffset[TDataBuffer::KFrameTypeMax];

    /** 
    * array of TDataBuffer offset addresses from the memory pool start address,
    * denoting Rx buffers which are ready to be read
    */
    TUint32         iRxCompletedBuffers[KMaxCompletedRxBufs];
    
    /**
    * Note! The length of this object needs to be divisible by 4 to make
    * the objects following it to be aligned correctly
    */
    };

#ifndef __KERNEL_MODE__ /* User mode */

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline TBool RFrameXferBlockBase::GetNextRxDataBuffer( TDataBuffer*& aBuf )
    {
    TBool ret( EFalse );

    if ( iNumOfCompleted )
        {
        --iNumOfCompleted;
        aBuf = reinterpret_cast<TDataBuffer*>(
                // Rx memory pool user mode start address
                iRxDataChunk + 
                // offset from the memory pool start address
                iRxCompletedBuffers[iCurrentRxBuffer]);
                
        ++iCurrentRxBuffer;
        ret = ETrue;
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void RFrameXferBlockBase::SetRxDataChunkField( TLinAddr aUserAddr )
    {
    iRxDataChunk = reinterpret_cast<TUint8*>(aUserAddr); 
    }

#endif /* User mode end */


/**
* Ethernet frame transfer context block between user and kernel space
* for the Management Client
*/
class RFrameXferBlock : public RFrameXferBlockBase
    {

public:

#ifndef __KERNEL_MODE__ /* User mode */
    
    /**
    * Appends data to iTxDataBuffer
    *
    * @since S60 3.1
    * @param aData data to be apended
    * @param aLength length of data in BYTEs
    * @param aFrameType frame type idenitifier
    * @param aUserPriority 802.1D User Priority of the frame
    * @param aMustNotBeEncrypted If EFalse it is allowed to encrypt the frame
    *        if a valid encryption key exists. This is the default behavior.
    *        If ETrue, the frame must not be encrypted even if a valid 
    *        encryption key existed. 
    * @param aDestinationAddress If not NULL, specifies the destination MAC
    *        address for the frame to be transmitted
    * @return KErrNone on success,
    *         KErrOverflow if aLength is greater than the available space in
    *         the Tx buffer
    */
    inline TInt AppendTxDataBuffer( 
        const TUint8* aData, 
        TUint32 aLength,
        TDataBuffer::TFrameType aFrameType = TDataBuffer::KEthernetFrame,
        TUint8 aUserPriority = 0,
        TBool aMustNotBeEncrypted = EFalse,
        const TMacAddress* aDestinationAddress = NULL );

    /**
    * Clears TxDataBuffer, makes it zero length size
    *
    * @since S60 3.1
    */
    inline void ClearTxDataBuffer();
    
    /**
    * Set data buffer address
    *
    * Note! This method is executed in user mode context by the user mode
    * client interface, i.e. not the client itself!
    * @since S60 3.1
    * @param aUserAddr user address of the buffer
    */
    inline void SetTxDataBufferField( TLinAddr aUserAddr );

#endif /* User mode end*/    

#ifdef __KERNEL_MODE__ /* Kernel mode */
    
    /**
    * Initialises the buffer.
    *
    *  @param aTxBufLength
    */
    inline void Initialize( TUint32 aTxBufLength );
    
#endif /* Kernel mode end */
    
private:

    /** Prohibit default constructor */
    RFrameXferBlock();

    /** Prohibit copy constructor */
    RFrameXferBlock( const RFrameXferBlock& );
    /** Prohibit assigment operator */
    RFrameXferBlock& operator= ( const RFrameXferBlock& );
    
private: // data

    /** Tx-data buffer */
    TDataBuffer*    iTxDataBuffer;

    /** 
    * stores the total capacity (length) of the Tx buffer (iTxDataBuffer) 
    * associated with this object instance
    */
    TUint32         iTxBufLength;
    };

#ifndef __KERNEL_MODE__ /* User mode */

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline TInt RFrameXferBlock::AppendTxDataBuffer( 
    const TUint8* aData, 
    TUint32 aLength,
    TDataBuffer::TFrameType aFrameType,
    TUint8 aUserPriority,
    TBool aMustNotBeEncrypted,
    const TMacAddress* aDestinationAddress )
    {
    if ( aLength <= 
        iTxBufLength - 
        iTxOffset[aFrameType] - 
        iTxDataBuffer->GetLength() )
        {
        // provided data fits into buffer
        
        iTxDataBuffer->FrameType( aFrameType );
        iTxDataBuffer->AppendBuffer( aData, aLength, iTxOffset[aFrameType] );
        iTxDataBuffer->SetUserPriority( aUserPriority );

        if ( aMustNotBeEncrypted )
            {
            iTxDataBuffer->KeSetFlags( 
                TDataBuffer::KTxFrameMustNotBeEncrypted );
            }
        else
            {
            iTxDataBuffer->KeClearFlags( 
                TDataBuffer::KTxFrameMustNotBeEncrypted );
            }

        if ( aDestinationAddress )
            {
            iTxDataBuffer->SetDestinationAddress( *aDestinationAddress );
            }
        
        return KErrNone;
        }
    else
        {
        return KErrOverflow;        
        }    
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void RFrameXferBlock::ClearTxDataBuffer()
    {
    iTxDataBuffer->SetLength( 0 );
    }

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void RFrameXferBlock::SetTxDataBufferField( TLinAddr aUserAddr )
    {
    iTxDataBuffer = reinterpret_cast<TDataBuffer*>(aUserAddr);
    }

#endif /* User mode end */

#ifdef __KERNEL_MODE__ /* Kernel mode */

// ---------------------------------------------------------------------------
// 
// ---------------------------------------------------------------------------
//
inline void RFrameXferBlock::Initialize( TUint32 aTxBufLength )
    {
    // perform base class initialization first
    KeInitialize();
    
    iTxDataBuffer = NULL;
    iTxBufLength = aTxBufLength;
    }

#endif  /* Kernel mode end */

/**
* Ethernet frame transfer context block between user and kernel space 
* for the protocol stack side client 
* 
*/
class RFrameXferBlockProtocolStack : public RFrameXferBlock
    {

public:

#ifndef __KERNEL_MODE__ /* User mode */
    
    /** 
     * Initializes TX Data pool, with the address of this in user space.
     * 
     * @param aThisAddrUserSpace Address of this object in user space.
     */
    inline void UserInitialize( TUint32 aThisAddrUserSpace );
    
#endif /* User mode end */    

#ifdef __KERNEL_MODE__ /* Kernel mode */
    
    /**
     * Initialises Kernel's memory interface to shared memory between User
     * and Kernel Space.
     */ 
    void Initialise();
    
    /**
     * Allocates a Tx buffer from the shared memory.
     * 
     * @param aTxBuf Pointer to the pre-allocated actual Tx buffer.
     * @param aBufLength Length of the Tx buffer.
     * @return Pointer to the meta header attached to the allocated buffer, on
     *         success.
     *         NULL, in case of allocation failure.
     */
    TDataBuffer* AllocTxBuffer( const TUint8* aTxBuf, TUint16 aBufLength );
    
    /**
     * Adds the specified Tx frame (contained in the buffer allocated from the 
     * shared memory) to the relevant Tx queue according to its AC (i.e.
     * priority).
     *  
     * @param aPacketInUserSpace Meta header attached to the frame; as a user
     *        space pointer.
     * @param aPacketInKernSpace If not NULL on return, the frame needs to be 
     *        discarded and this is the kernel space pointer to its meta header.
     *        If NULL on return, the frame must not be discarded. 
     * @param aUserDataTxEnabled ETrue if user data Tx is enabled
     *        EFalse otherwise
     * @return ETrue if the client is allowed to continue calling this method
     *         (i.e. Tx flow is not stopped).
     *         EFalse if the client is not allowed to call this method again
     *         (i.e. Tx flow is stopped) until it is re-allowed.
     */
    TBool AddTxFrame( 
        TDataBuffer* aPacketInUserSpace, 
        TDataBuffer*& aPacketInKernSpace, 
        TBool aUserDataTxEnabled );
    
    /**
     * Gets the frame to be transmitted next from the Tx queues.
     * 
     * @param aWhaTxQueueState State (full / not full) of every WHA transmit 
     *        queue
     * @param aMore On return is ETrue if another frame is also ready to be 
     *        transmitted, EFalse otherwise
     * @return Pointer to the meta header of the frame to be transmitted, on
     *         success
     *         NULL, if there's no frame that could be transmitted, given the
     *         current status of the WHA Tx queues
     */ 
    TDataBuffer* GetTxFrame( 
        const TWhaTxQueueState& aWhaTxQueueState,
        TBool& aMore );
    
    /**
     * Deallocates a Tx packet.
     * 
     * All Tx packets allocated with AllocTxBuffer() must be deallocated using
     * this method.
     * 
     * @param aPacket Meta header of the packet to the deallocated
     */ 
    inline void FreeTxPacket( TDataBuffer*& aPacket );
    
    /** 
     * Determines if Tx from protocol stack side client should be resumed
     * 
     * @param aUserDataTxEnabled ETrue if user data Tx is enabled
     *        EFalse otherwise
     * @return ETrue if Tx should be resumed
     *         EFalse otherwise
     */
    TBool ResumeClientTx( TBool aUserDataTxEnabled ) const;
    
    /** 
     * Determines if all Tx queues are empty
     * 
     * @return ETrue if all Tx queues are empty
     *         EFalse otherwise
     */
    inline TBool AllTxQueuesEmpty() const;

#endif /* Kernel mode end */
    
private:

    /** 
     * With the current WLAN LDD Tx queue contents and WHA queue status, is
     * it possible to schedule a new Tx packet
     * 
     * @param aWhaTxQueueState Status of all WHA Tx queues (full/not full)
     * @param aQueueId Upon returning ETrue, denotes the WLAN LDD queue from
     *        which a packet can be scheduled  
     * @return ETrue if Tx packet scheduling is possible
     *         EFalse if Tx packet scheduling is not possible
     */
    TBool TxPossible(
        const TWhaTxQueueState& aWhaTxQueueState,
        TQueueId& aQueueId );
    
    /** 
     * Determines if the Tx flow from client needs to be stopped
     *  
     * @param aTxQueue Tx queue to which the latest packet was added
     * @param aUserDataTxEnabled ETrue if user data Tx is enabled
     *        EFalse otherwise
     * return EFalse if Tx flow needs to be stopped
     *        ETrue otherwise
     */
    TBool TxFlowControl( TQueueId aTxQueue, TBool aUserDataTxEnabled );
    
    /** Prohibit default constructor */
    RFrameXferBlockProtocolStack();

    /** Prohibit copy constructor */
    RFrameXferBlockProtocolStack( const RFrameXferBlockProtocolStack& );
    /** Prohibit assigment operator */
    RFrameXferBlockProtocolStack& operator= ( const RFrameXferBlockProtocolStack& );
    
private:    // Data

    /** Tx Queue for Voice priority frames */
    RWlanCircularBuffer<KVoiceTxQueueLen> iVoiceTxQueue;
    
    /** Tx Queue for Video priority frames */
    RWlanCircularBuffer<KVideoTxQueueLen> iVideoTxQueue;
    
    /** Tx Queue for Best Effort priority frames */
    RWlanCircularBuffer<KBestEffortTxQueueLen> iBestEffortTxQueue;
    
    /** Tx Queue for Background priority frames */
    RWlanCircularBuffer<KBackgroundTxQueueLen> iBackgroundTxQueue;
    
    /** Free Queue */
    RWlanCircularBuffer<KTxPoolSizeInPackets> iFreeQueue;

    /** Tx frame meta header objects */
    TDataBuffer iDataBuffers[KTxPoolSizeInPackets];
    
    /** Address of this object instance in the user mode address space */
    TUint32 iThisAddrUserSpace;
    
    /** Address of this object instance in the kernel mode address space */
    TUint32 iThisAddrKernelSpace;
    
    /** 
    * the offset from a User space address to the corresponding address
    * in the Kernel space in the shared memory chunk. May also be negative 
    */
    TInt32 iUserToKernAddrOffset;

    /**
    * Note! The length of this object needs to be divisible by 4 to make
    * the objects following it to be aligned correctly
    */
    };


#ifndef __KERNEL_MODE__ /* User mode */
#include <e32debug.h>

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
inline void RFrameXferBlockProtocolStack::UserInitialize( 
    TUint32 aThisAddrUserSpace)
    {
    iThisAddrUserSpace = aThisAddrUserSpace;
    iUserToKernAddrOffset = iThisAddrKernelSpace - iThisAddrUserSpace;
    }
#endif /* User mode end */

#ifdef __KERNEL_MODE__ /* Kernel mode */

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
inline void RFrameXferBlockProtocolStack::FreeTxPacket( TDataBuffer*& aPacket )
    {
    aPacket->SetLength( 0 );
    aPacket->SetUserPriority( 0 );
    // put the packet to the Free Queue
    iFreeQueue.PutPacket( aPacket );
    aPacket = NULL;
    }

// -----------------------------------------------------------------------------
// 
// -----------------------------------------------------------------------------
//
inline TBool RFrameXferBlockProtocolStack::AllTxQueuesEmpty() const
    {
    return ( iVoiceTxQueue.IsEmpty() &&  
             iVideoTxQueue.IsEmpty() &&
             iBestEffortTxQueue.IsEmpty() &&
             iBackgroundTxQueue.IsEmpty() ) ? ETrue : EFalse;
    }

#endif /* Kernel mode end */

#endif // FRAMEXFERBLOCK_H
