wlan_bearer/wlannwif/src/Wlanbase.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 02:03:13 +0200
changeset 0 c40eb8fe8501
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* 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 "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:  Implements functions for LAN interface
*
*/

/*
* %version: 24 %
*/

#include <f32file.h>
#include <e32std.h> // for TTime
#include <nifvar.h>
#include <nifutl.h>
#include <es_mbuf.h>
#include <nifmbuf.h>
#include <comms-infras/nifprvar.h>
#include <comms-infras/connectionsettings.h>  // for KSlashChar
#include <commdb.h>
#include "WlanProto.h"
#include "carddrv.h"
#include <in_sock.h> // Header is retained, but in_sock.h is modified for ipv6
#include "CLanIp4Bearer.h"
#include "CLanIp6Bearer.h"
#include <cdbcols.h>
#include <cdblen.h>
#include "CLanxBearer.h"
#include "WlanProvision.h"
#include <comms-infras/ss_metaconnprov.h> // for SAccessPointConfig
#include <comms-infras/linkmessages.h>
#include <elements/nm_messages_base.h>
#include <elements/nm_messages_child.h>

// From old wlan implementation
#include <ip4_hdr.h>
#include <ip6_hdr.h>
#include <centralrepository.h>
#include "am_debug.h"
#include "EtherCardApi.h"
#include "wlandevicesettingsinternalcrkeys.h"
#include "NifWLMServerIf.h"


using namespace ESock;
using namespace Messages;

_LIT8(KDescIp, "ip");
_LIT8(KDescIcmp, "icmp");
_LIT8(KDescIp6, "ip6");

const TInt KLanxBearerPtrArrayGranularity = 2;
const TInt KContinueSending = 1;
const TInt KMaxDSCPValues = 64;

/**
 * Mapping of user priority values to the corresponding access classes.
 */
const TWlmAccessClass KUPtoAC[E8021DUserPriorityMax] =
    {
    EWlmAccessClassBestEffort,      // E8021DUserPriorityBE
    EWlmAccessClassBackground,      // E8021DUserPriorityBK1
    EWlmAccessClassBackground,      // E8021DUserPriorityBK2
    EWlmAccessClassBestEffort,      // E8021DUserPriorityEE
    EWlmAccessClassVideo,           // E8021DUserPriorityCL
    EWlmAccessClassVideo,           // E8021DUserPriorityVI
    EWlmAccessClassVoice,           // E8021DUserPriorityVO
    EWlmAccessClassVoice,           // E8021DUserPriorityNC
    };

/**
 * Mapping of access class transitions on packet downgrade.
 */
const TWlmAccessClass KNextAC[EWlmAccessClassMax] =
    {
    EWlmAccessClassBackground,      // EWlmAccessClassBestEffort -> EWlmAccessClassBackground
    EWlmAccessClassMax,             // EWlmAccessClassBackground -> EWlmAccessClassMax
    EWlmAccessClassBestEffort,      // EWlmAccessClassVideo -> EWlmAccessClassBestEffort
    EWlmAccessClassVideo            // EWlmAccessClassVoice -> EWlmAccessClassVideo
    };

/**
 * Mapping of IP TOS (DSCP) bits to the corresponding user priority values.
 */
const T8021DPriority KDSCPtoUP[KMaxDSCPValues] =
    {
    /* DSCP bits as binary format, DSCP byte in IPv4 packet as HEX */
    
    /* 000000, 0x00 */E8021DUserPriorityBE,  /* 000001, 0x04 */E8021DUserPriorityBE,  
    /* 000010, 0x08 */E8021DUserPriorityBE,  /* 000011, 0x0C */E8021DUserPriorityBE,
    /* 000100, 0x10 */E8021DUserPriorityBE,  /* 000101, 0x14 */E8021DUserPriorityBE,  
    /* 000110, 0x18 */E8021DUserPriorityBE,  /* 000111, 0x1C */E8021DUserPriorityBE,
    /* 001000, 0x20 */E8021DUserPriorityBK1, /* 001001, 0x24 */E8021DUserPriorityBK1,  
    /* 001010, 0x28 */E8021DUserPriorityEE,  /* 001011, 0x2C */E8021DUserPriorityEE,
    /* 001100, 0x30 */E8021DUserPriorityEE,  /* 001101, 0x34 */E8021DUserPriorityEE,  
    /* 001110, 0x38 */E8021DUserPriorityEE,  /* 001111, 0x3C */E8021DUserPriorityEE,

    /* 010000, 0x40 */E8021DUserPriorityEE,  /* 010001, 0x44 */E8021DUserPriorityEE,  
    /* 010010, 0x48 */E8021DUserPriorityEE,  /* 010011, 0x4C */E8021DUserPriorityEE,
    /* 010100, 0x50 */E8021DUserPriorityEE,  /* 010101, 0x54 */E8021DUserPriorityEE,  
    /* 010110, 0x58 */E8021DUserPriorityEE,  /* 010111, 0x5C */E8021DUserPriorityEE,
    /* 011000, 0x60 */E8021DUserPriorityVI,  /* 011001, 0x64 */E8021DUserPriorityVI,  
    /* 011010, 0x68 */E8021DUserPriorityVI,  /* 011011, 0x6C */E8021DUserPriorityVI,
    /* 011100, 0x70 */E8021DUserPriorityVI,  /* 011101, 0x74 */E8021DUserPriorityVI,  
    /* 011110, 0x78 */E8021DUserPriorityVI,  /* 011111, 0x7C */E8021DUserPriorityVI,

    /* 100000, 0x80 */E8021DUserPriorityVI,  /* 100001, 0x84 */E8021DUserPriorityVI,  
    /* 100010, 0x88 */E8021DUserPriorityVI,  /* 100011, 0x8C */E8021DUserPriorityVI,
    /* 100100, 0x90 */E8021DUserPriorityVI,  /* 100101, 0x94 */E8021DUserPriorityVI,  
    /* 100110, 0x98 */E8021DUserPriorityVI,  /* 100111, 0x9C */E8021DUserPriorityVI,
    /* 101000, 0xA0 */E8021DUserPriorityCL,  /* 101001, 0xA4 */E8021DUserPriorityCL,  
    /* 101010, 0xA8 */E8021DUserPriorityCL,  /* 101011, 0xAC */E8021DUserPriorityCL,
    /* 101100, 0xB0 */E8021DUserPriorityCL,  /* 101101, 0xB4 */E8021DUserPriorityCL,  
    /* 101110, 0xB8 */E8021DUserPriorityVO,  /* 101111, 0xBC */E8021DUserPriorityVO,

    /* 110000, 0xC0 */E8021DUserPriorityNC,  /* 110001, 0xC4 */E8021DUserPriorityNC,  
    /* 110010, 0xC8 */E8021DUserPriorityNC,  /* 110011, 0xCC */E8021DUserPriorityNC,
    /* 110100, 0xD0 */E8021DUserPriorityNC,  /* 110101, 0xD4 */E8021DUserPriorityNC,  
    /* 110110, 0xD8 */E8021DUserPriorityNC,  /* 110111, 0xDC */E8021DUserPriorityNC,
    /* 111000, 0xE0 */E8021DUserPriorityNC,  /* 111001, 0xE4 */E8021DUserPriorityNC,  
    /* 111010, 0xE8 */E8021DUserPriorityNC,  /* 111011, 0xEC */E8021DUserPriorityNC,
    /* 111100, 0xF0 */E8021DUserPriorityNC,  /* 111101, 0xF4 */E8021DUserPriorityNC,  
    /* 111110, 0xF8 */E8021DUserPriorityNC,  /* 111111, 0xFC */E8021DUserPriorityNC
    };

/**
 * Inactivity timeouts per access class.
 */
const TUint KTsInactivityTime[EWlmAccessClassMax] =
    {
    600000000,    // 600 seconds for EWlmAccessClassBestEffort
    600000000,    // 600 seconds for EWlmAccessClassBackground
    120000000,    // 120 seconds for EWlmAccessClassVideo
    30000000,     // 30 seconds for EWlmAccessClassVoice
    };

EXPORT_C CLANLinkCommon::CLANLinkCommon(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf)
  : CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf), iMMState(EStopped)
    {
    DEBUG("CLANLinkCommon::CLANLinkCommon()");
    LOG_NODE_CREATE(KWlanLog, CLANLinkCommon);
    }


// -----------------------------------------------------------------------------
// CLANLinkCommon::LoadPacketDriverL
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::LoadPacketDriverL()
    {
    DEBUG("CLANLinkCommon::LoadPacketDriverL() - Creates only new class instance");

    iPktDrv = CPcCardPktDrv::NewL( this ); 
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::NewL
// -----------------------------------------------------------------------------
//
EXPORT_C CLANLinkCommon* CLANLinkCommon::NewL(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf)
    {
    DEBUG("CLANLinkCommon::NewL()");
  
    CLANLinkCommon* s=new (ELeave) CLANLinkCommon(aFactory, aSubConnId, aProtocolIntf);
    CleanupStack::PushL(s);
    s->ConstructL();
    CleanupStack::Pop(s);
    return s;
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::ReadMACSettings
// -----------------------------------------------------------------------------
//
TBool CLANLinkCommon::ReadMACSettings()
    {
    DEBUG("CLANLinkCommon::ReadMACSettings()");

    TBuf8<KMACByteLength> drvMacAddr;
    TUint8* config=iPktDrv->GetInterfaceAddress();
    drvMacAddr.Append(&config[0],KMACByteLength); // First 3 bytes of config not part of address
    iMacAddr.Copy(drvMacAddr); // update Ethints copy of the MAC address
    TUint bearerLim = iBearers->Count();
    for(TUint index=0;index<bearerLim;index++)
        {
        CLanxBearer* bearer=(*iBearers)[index];
        bearer->UpdateMACAddr();
        }

    // check that the macaddress has been passed and is not 0;
    return CheckMac(iMacAddr); // wrong.
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::Mtu
// -----------------------------------------------------------------------------
//
TUint CLANLinkCommon::Mtu() const 
    {
    DEBUG("CLanLinkCommon::Mtu()");
    
    TInt err = KErrNone;
    CRepository* repository = NULL;
    TRAP( err, repository = CRepository::NewL( KCRUidWlanDeviceSettingsRegistryId ) );
    if( err != KErrNone )
        {
        DEBUG1( "Could not access repository (%d), using default value for mtu(1500)", err );
        return KEtherMaxDataLen;
        }
    // No need to use CleanupStack because no possibility to leave

    TInt temp = 0;
    err = repository->Get( KWlanMTU, temp );
    if( err == KErrNone ) 
        {
        delete repository;
        DEBUG1("MTU value from cenrep is:%d", temp);
        if( temp > KEtherMaxDataLen || temp <= 0 )
            {
            DEBUG("MTU from cenrep is out of range 1-1500, setting it to 1500");
            temp = KEtherMaxDataLen;
            }
        return temp;
        }
    else
        {
        DEBUG1( "Could not access repository (%d), using default value for mtu(1500)", err );
        delete repository;
        return KEtherMaxDataLen;
        } 
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::ConstructL
// -----------------------------------------------------------------------------
//
EXPORT_C void CLANLinkCommon::ConstructL()
    {
    DEBUG("CLANLinkCommon::ConstructL()");

    // Initialise class members that do not need to be read from the database
    iBearers = new (ELeave) CLanxBearerPtrArray(KLanxBearerPtrArrayGranularity);
    iEtherType = EStandardEthernet;

    iOnlyThisBearer = NULL;
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::~CLANLinkCommon
// -----------------------------------------------------------------------------
//
EXPORT_C CLANLinkCommon::~CLANLinkCommon()
    {
    DEBUG("CLANLinkCommon::~CLANLinkCommon()");

    delete iPktDrv;
    ASSERT(0 == iBearers->Count());
    delete iBearers;
    delete iPeriodic;
    delete iWLMServerCommon;
	for( TUint idx( 0 ); idx < EWlmAccessClassMax; ++idx )
	    {
	    delete iAcArray[idx];	    
	    }

    LOG_NODE_DESTROY(KWlanLog, CLANLinkCommon);
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::CheckMac
// -----------------------------------------------------------------------------
//
TBool CLANLinkCommon::CheckMac(TDes8& aMacAddr)
    {
    DEBUG("CLANLinkCommon::CheckMac()");

    TUint MacBytes = 6;
    for (TUint i=0;i<MacBytes;i++)
        {
        if (aMacAddr[i] != 0)
            {
            return ETrue;
            }
        }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::AcTrafficModeChanged
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::AcTrafficModeChanged(
    TWlmAccessClass aAccessClass,
    TWlmAcTrafficMode aMode )
    {
    DEBUG( "CLANLinkCommon::AcTrafficModeChanged()" );

    iAcArray[aAccessClass]->SetTrafficMode( aMode );
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::AcTrafficModeChanged
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::AcTrafficStatusChanged(
    TWlmAccessClass aAccessClass,
    TWlmAcTrafficStatus aStatus )
    {
    DEBUG( "CLANLinkCommon::AcTrafficStatusChanged()" );

    iAcArray[aAccessClass]->SetTrafficStatus( aStatus );
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::LinkLayerUp
// -----------------------------------------------------------------------------
//
/**
Link Layer Up
Called by the packet driver when it is happy
*/
EXPORT_C void CLANLinkCommon::LinkLayerUp()
    {
    DEBUG("CLANLinkCommon::LinkLayerUp()");
    
    //some drivers have a valid MAC only after negotiation finishes
    iValidMacAddr = ReadMACSettings();
    PostDataClientStartedMessage();

    /**
     * With the new comms framework, this KLinkLayerOpen always sent and then will be caught and swallowed
     * at the ipproto layer if a netcfgext is being used.
     */
  
    /**
     * We are forced to signal link layer open from here even though there may not
     * be a configured IP address.  This is a dirty fix because of politics...
     */
    PostProgressMessage(KLinkLayerOpen, KErrNone);

    TUint bearerLim = iBearers->Count();
    for(TUint index=0;index<bearerLim;index++)
        {
        CLanxBearer *bearer=(*iBearers)[index];
        bearer->StartSending((CProtocolBase*)this);
        }

	// Get current traffic status for access classes.
	TWlmAcTrafficStatusArray acArray;
	TInt ret = iWLMServerCommon->GetAcTrafficStatus( acArray );
	if( ret != KErrNone )
	    {
	    DEBUG1( "CLANLinkCommon::LinkLayerUp() - RWLMServer::GetAcTrafficStatus() failed with %d",
	        ret );

	    // Assume all access classes are admitted.
	    for( TUint idx( 0 ); idx < EWlmAccessClassMax; ++idx )
	         {
	         iAcArray[idx]->SetTrafficStatus( EWlmAcTrafficStatusAdmitted );
	         }
	    }
	else
	    {
	    // Update access class instances with the current status.
        for( TUint idx( 0 ); idx < EWlmAccessClassMax; ++idx )
             {
             iAcArray[idx]->SetTrafficStatus( acArray[idx] );
             }
	    }
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::LinkLayerDown
// -----------------------------------------------------------------------------
//
EXPORT_C void CLANLinkCommon::LinkLayerDown(TInt aError, TAction aAction)
/**
Link Layer Down
Called by the packet driver when the link has gone down

@param aError error code
@param aAction whether a reconnect is required or not
*/
    {
    DEBUG("CLANLinkCommon::LinkLayerDown()");
    
    // If a stop was requested from the SCpr then this LinkLayerDown()
    // was expected. This also means the SCpr has already been sent a
    // TDataClientStopped and the packet driver has been stopped.
    // If on the other hand the stop was not requested a TDataClientGoneDown
    // message needs to be sent to the SCpr and the packet driver still
    // needs a StopInterface call - usually this would mean that aAction
    // is EReconnect
    if (iStopRequested == EFalse && iMMState == EStarted)
        {
        PostProgressMessage(KLinkLayerClosed, aError);
        PostFlowGoingDownMessage(aError, (aAction == EReconnect) ? MNifIfNotify::EReconnect : MNifIfNotify::EDisconnect);
        iPktDrv->StopInterface();
        MaybePostDataClientIdle();
        iMMState = EStopped;
        }
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::StopCb
// -----------------------------------------------------------------------------
//
TInt CLANLinkCommon::StopCb(TAny* aThisPtr)
    {
    DEBUG("CLANLinkCommon::StopCb()");
    
    CLANLinkCommon* self = static_cast<CLANLinkCommon*>(aThisPtr);
    self->StopInterface();
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::StopInterface
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::StopInterface()
    {
    DEBUG("CLANLinkCommon::StopInterface()");
    
    if(iPeriodic)
        {
        iPeriodic->Cancel();
        delete iPeriodic;
        iPeriodic = NULL;
        }

    iPktDrv->StopInterface();
    PostProgressMessage(KLinkLayerClosed, iError);
    PostFlowDownMessage(iError);

    MaybePostDataClientIdle();
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::EtherFrame
// -----------------------------------------------------------------------------
//
TInt CLANLinkCommon::EtherFrame(RMBufChain &aPdu, TDesC8& aDestAddr, TUint16 aType, TUint8& aDscp)
    {
    RMBufChain ethHdr;
    TUint etherHeaderSize = (iEtherType==EStandardEthernet) ?
        KEtherHeaderSize : KEtherLLCHeaderSize;

    TRAPD(ret, ethHdr.AllocL(etherHeaderSize));
    if(ret != KErrNone)
        {
        return ret;
        }

    TEtherLLCFrame *hdrBuf = reinterpret_cast<TEtherLLCFrame*>(ethHdr.First()->Buffer());

    //Get the packet info:
    RMBufPktInfo* info = RMBufPacket::PeekInfoInChain(aPdu);

    // Fill in the dest, src Mac addresses:
    hdrBuf->SetDestAddr(aDestAddr);
    hdrBuf->SetSrcAddr(iMacAddr);

    switch(iEtherType)
        {
        case EStandardEthernet:
            BigEndian::Put16((TUint8*)&hdrBuf->iType,aType);
            break;
        case ELLCEthernet:
            // Several fields to fill in. According to nifmbuf.h,
            // info->iLength gives the actual length of the packet.
            BigEndian::Put16((TUint8*)&hdrBuf->iLen,static_cast<TInt16>(info->iLength));
            hdrBuf->iDSAP=KLLC_SNAP_DSAP;
            hdrBuf->iSSAP=KLLC_SNAP_SSAP;
            hdrBuf->iCtrl=KLLC_SNAP_CTRL;
            hdrBuf->SetOUI(0);
            hdrBuf->SetType(aType);
            break;
        default:
            // Can't handle any other kind of Ethernet header.
            return KErrGeneral;
        }

    //Remove the original first Packet - by trimming the info from the packet.
    aPdu.TrimStart(aPdu.Length() - info->iLength); // At this point, info becomes invalid.

    //Extract the DSCP value as aPdu points to IP packet now
    if (KIPFrameType == aType)
        {
        TInet6HeaderIP4 *ipv4hdr = (TInet6HeaderIP4 *)aPdu.First()->Ptr();
        TUint8 TOS = ipv4hdr->TOS();
        aDscp = (TOS >> 2) & 0xff;
        DEBUG2( "CLanLinkCommon::EtherFrame() - DSCP of the IPv4 packet: 0x%02X (%u)",
	        aDscp, aDscp );
        }
    else if (KIP6FrameType == aType)
        {
        TInet6HeaderIP *ipv6hdr = (TInet6HeaderIP *)aPdu.First()->Ptr();
        TUint8 TrafficClass = ipv6hdr->TrafficClass();
        aDscp = (TrafficClass >> 2) & 0xff;     
        DEBUG2( "CLanLinkCommon::EtherFrame() - DSCP of the IPv6 packet: 0x%02X (%u)",
	        aDscp, aDscp );
        }

    //Finally, add the saved packet buffer to the mac header
    aPdu.Prepend(ethHdr);
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::FrameSend
// -----------------------------------------------------------------------------
//
TInt CLANLinkCommon::FrameSend(
    RMBufChain& aPdu,
    TDesC8& aDestAddr,
    TUint16 aType )
	{
	// Call down from the Protocol
	// The data begins in the second MBuf - because the first one
	// is the info. The upper layer must have filled in the destination
	// and source Mac addresses before this method is called and must
	// supply the ether header type in aType.
	// EtherFrame strips off the info and replaces it by the proper
	// ether header.

	TUint8 dscp( 0 );
	TInt err = EtherFrame( aPdu, aDestAddr, aType, dscp );
	if( err != KErrNone )
	    {
	    // drop the packet but _don't_ return an error (if we return
	    // an error from here, the stack thinks it is fatal...)
	    aPdu.Free();
	    return KContinueSending;
	    }

    // Map DSCP values to desired access class and user priority values.
	T8021DPriority userPriority( KDSCPtoUP[dscp] );
	TWlmAccessClass accessClass( KUPtoAC[userPriority] );	
	TBool dropPacket( EFalse );

    // ARP packets are treated as Voice traffic.
	if( aType == KArpFrameType )
	    {
        DEBUG( "CLanLinkCommon::FrameSend() - ARP packet" );

        userPriority = E8021DUserPriorityNC;
        accessClass = EWlmAccessClassVoice;
	    }

	if( iAcArray[accessClass]->IsAdmitted() )
	    {
	    DEBUG1( "CLanLinkCommon::FrameSend() - traffic admitted on AC %u",
	        accessClass );
	    }
	else
	    {
	    DEBUG1( "CLanLinkCommon::FrameSend() - traffic NOT admitted on AC %u",
	        accessClass );

	    // Find an admitted access class.
	    DownGradePacket( userPriority, dropPacket );
	    }

	if( !dropPacket )
	    {
	    //Prepend UP value to the packet
	    RMBufChain UPBuf;
	    TRAPD( allocRet, UPBuf.AllocL( sizeof(TUint8) ) );
	    if( allocRet != KErrNone )
	        {
	        // drop the packet but _don't_ return an error (if we return
	        // an error from here, the stack thinks it is fatal...)
	        aPdu.Free();
	        return KContinueSending;
	        }

	    (UPBuf.First())->Put((TUint8)userPriority);
	    aPdu.Prepend( UPBuf );

	    DEBUG2( "CLanLinkCommon::FrameSend() - sending packet on AC %u with UP %u",
	        KUPtoAC[userPriority],
	        userPriority );
	    TInt ret = iPktDrv->Send( aPdu );

	    // ARP packets will never triggers traffic stream creation.
	    if( aType == KArpFrameType )
	        {
	        return ret;
	        }

	    // Notify the per-AC handler.
	    iAcArray[accessClass]->OnFrameSend();

	    if( ret != KContinueSending )
	        {
	        // Suspend inactivity timer for all ACs if NIF Queue is full.
	        for( TUint idx( 0 ); idx < EWlmAccessClassMax; ++idx )
	            {
	            iAcArray[idx]->SuspendInactivityTimer();
	            }
	        }

	    return ret;
	    }
	else
	    {
	    DEBUG( "CLanLinkCommon::FrameSend() - no ACs admitted, dropping packet" );

	    aPdu.Free();

	    return KContinueSending;
	    }
	}

// -----------------------------------------------------------------------------
// CLANLinkCommon::DownGradePacket
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::DownGradePacket(
    T8021DPriority& aUP,
    TBool& aDrop )
    {
    DEBUG1( "CLanLinkCommon::DownGradePacket() - UP before downgrade: %u",
        aUP );

    /**
     * This method wouldn't be called if downgrade wasn't needed,
     * so we don't have to check Voice priority at all.   
     */
    TWlmAccessClass accessClass( KNextAC[KUPtoAC[aUP]] );
    while( accessClass != EWlmAccessClassMax )
        {
        if( iAcArray[accessClass]->IsAdmitted() )
            {
            aUP = KACtoUP[accessClass];
            aDrop = EFalse;
    
            DEBUG1( "CLanLinkCommon::DownGradePacket() - UP after downgrade: %u",
                aUP );

            return;
            }

        accessClass = KNextAC[accessClass];
        }

    DEBUG( "CLanLinkCommon::DownGradePacket() - packet will be dropped" );

    aDrop = ETrue;
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::GetProtocolType
// -----------------------------------------------------------------------------
//
TInt CLANLinkCommon::GetProtocolType(
    TUint8* aEtherHeader,
    TUint16& aEtherType )
    {
    TEtherFrame* etherFrame = reinterpret_cast<TEtherFrame*>(aEtherHeader);   
    TUint16 etherType = etherFrame->GetType();
  
    if( etherType >= KMinEtherType)
        {
        // type/length field >= 1536, this is Ethernet II frame
        aEtherType = etherType; 
        }
    else
        {
        // type/length field is something between KEtherLLCMaxLengthFieldValue
        // and KMinEtherType, this shouldn't happen...
        //__ASSERT_DEBUG(EFalse, User::Panic(_L("wlannif"), KErrGeneral));
        return KErrNotSupported;
        }
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::Process
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::Process(
    RMBufChain& aPdu, 
    TUint8* aEtherHeader, 
    TUint8 aUPValue )
	{
	TUint16 etherCode(0);
	TBool packetProcessed(EFalse);
	TInt ret=GetProtocolType( aEtherHeader, etherCode );
	if( ret==KErrNone )
		{  // It's an ethernet packet of some kind.
	    DEBUG2("CLANLinkCommon::Process() - UP: %u, ethertype: 0x%04X",
	        aUPValue, etherCode );

		TUint bearerLim = iBearers->Count();
		for( TUint index=0;index<bearerLim && !packetProcessed; index++ )
			{
			CLanxBearer *bearer=(*iBearers)[index];
		
			if( bearer->WantsProtocol(
			    etherCode, aPdu.First()->Next()->Buffer()) )
				{	
				bearer->Process( aPdu );
				packetProcessed=ETrue;
				}
			}
		}
	if( ret!=KErrNone || !packetProcessed )
	    {
	    aPdu.Free(); // Something strange about the packet - bin it
	    }
	else
	    {
        // Notify the per-AC handler.   
	    iAcArray[KUPtoAC[aUPValue]]->OnFrameReceive();
	    }
	}

// -----------------------------------------------------------------------------
// CLANLinkCommon::ResumeSending
// -----------------------------------------------------------------------------
//
EXPORT_C void CLANLinkCommon::ResumeSending()
    {
	DEBUG( "CLanLinkCommon::ResumeSending()" );
	
	TUint bearerLim = iBearers->Count();
	for( TUint index=0;index<bearerLim;index++ )
		{
		CLanxBearer *bearer=(*iBearers)[index];
		bearer->StartSending( (CProtocolBase*)this );
		}

    for( TUint idx( 0 ); idx < EWlmAccessClassMax; ++idx )
         {
         iAcArray[idx]->ResumeInactivityTimer();
         }
	}

/**

*/
EXPORT_C TInt CLANLinkCommon::ReadInt(const TDesC& /*aField*/, TUint32& /*aValue*/)
{
  return KErrNotSupported;
}
  
/**

*/
EXPORT_C TInt CLANLinkCommon::WriteInt(const TDesC& /*aField*/, TUint32 /*aValue*/)
{
  return KErrNotSupported;
}
  
/**

*/
EXPORT_C TInt CLANLinkCommon::ReadDes(const TDesC& /*aField*/, TDes8& /*aValue*/)
{
  return KErrNotSupported;
}
  
/**

*/
EXPORT_C TInt CLANLinkCommon::ReadDes(const TDesC& /*aField*/, TDes16& /*aValue*/)
{
  return KErrNotSupported;

}
  
/**

*/
EXPORT_C TInt CLANLinkCommon::WriteDes(const TDesC& /*aField*/, const TDesC8& /*aValue*/)
{
  return KErrNotSupported;
}
  
/**

*/
EXPORT_C TInt CLANLinkCommon::WriteDes(const TDesC& /*aField*/, const TDesC16& /*aValue*/)
{
  return KErrNotSupported;
}
  
/**

*/
EXPORT_C TInt CLANLinkCommon::ReadBool(const TDesC& /*aField*/, TBool& /*aValue*/)
{
  return KErrNotSupported;
}
  
/**

*/
EXPORT_C TInt CLANLinkCommon::WriteBool(const TDesC& /*aField*/, TBool /*aValue*/)
{
  return KErrNotSupported;
}
  
/**

*/
EXPORT_C void CLANLinkCommon::IfProgress(TInt aStage, TInt aError)
{
  PostProgressMessage(aStage, aError);
}
  
/**

*/
EXPORT_C void CLANLinkCommon::IfProgress(TSubConnectionUniqueId /*aSubConnectionUniqueId*/, TInt aStage, TInt aError)
{
  // Not quite correct - there is no subconnection id specific progress message.
  IfProgress(aStage, aError);
}
  
/**

*/
EXPORT_C void CLANLinkCommon::NifEvent(TNetworkAdaptorEventType /*aEventType*/, TUint /*aEvent*/, const TDesC8& /*aEventData*/, TAny* /*aSource*/)
{
}

// ======================================================================================
//
// from MFlowBinderControl

// -----------------------------------------------------------------------------
// CLANLinkCommon::GetControlL
// -----------------------------------------------------------------------------
//
EXPORT_C MLowerControl* CLANLinkCommon::GetControlL(const TDesC8& aName)
/**
Request from upper CFProtocol to retrieve our MLowerControl class.

@param aName Protocol Name.  Presently, only "ip" and "ip6" are supported.
@return pointer to our MLowerControl class instance.  We leave on an error, hence this routine should
never return NULL.
*/
  {
    DEBUG("CLANLinkCommon::GetControlL()");
  
  CLanxBearer* bearer=NULL;
    if (aName.CompareF(KDescIp6) == 0)
      {
        bearer = new(ELeave) CLanIp6Bearer(this);
        }
  else if (aName.CompareF(KDescIp) == 0 || aName.CompareF(KDescIcmp) == 0)
    {
        bearer = new(ELeave) CLanIp4Bearer(this);
        }
  else
    {
    User::Leave(KErrNotSupported);
    }
  
    CleanupStack::PushL(bearer);
    bearer->ConstructL();

  iBearers->AppendL(bearer);
  ProvisionBearerConfigL(aName);
    CleanupStack::Pop();
    return bearer;
  }

  
// -----------------------------------------------------------------------------
// CLANLinkCommon::BindL
// -----------------------------------------------------------------------------
//
EXPORT_C MLowerDataSender* CLANLinkCommon::BindL(const TDesC8& aProtocol, MUpperDataReceiver* aReceiver, MUpperControl* aControl)
/**
Request from upper CFProtocol to bind to this module.

@param aProtocol protocol name (e.g. "ip", "ip6" etc).
@param aReceiver pointer to MUpperDataReceiver instance of upper CFProtocol
@param aControl pointer to MUpperControl instance of upper CFProtocol
@return pointer to our MLowerDataSender instance (eventually passed to the upper CFProtocol)
*/
  {
    DEBUG("CLANLinkCommon::BindL()");
    
  TInt index = 0;
  CLanxBearer* bearer = FindBearerByProtocolName(aProtocol, index);
  if (bearer)
    {
    bearer->SetUpperPointers(aReceiver, aControl);
    if (iValidMacAddr)
      {
      aControl->StartSending();
      }
    }
  else
    {
    User::Leave(KErrNotSupported);
    }
  iSubConnectionProvider.RNodeInterface::PostMessage(Id(), TCFControlProvider::TActive().CRef()); 
  return bearer;
  }

  
// -----------------------------------------------------------------------------
// CLANLinkCommon::Unbind
// -----------------------------------------------------------------------------
//
EXPORT_C void CLANLinkCommon::Unbind(MUpperDataReceiver* /*aReceiver*/, MUpperControl* aControl)
/**
Request from upper CFProtocol to unbind from this module.

@param aReceiver pointer to data receiver class of upper CFProtocol (originally passed to it in downward BindL() request)
@param aControl pointer to control class of upper CFProtocol (originally passed to it in downward BindL() request)
*/

  {
    DEBUG("CLANLinkCommon::Unbind()");
    
  TInt index = 0;
  CLanxBearer* bearer = FindBearerByUpperControl(aControl, index);
  ASSERT(bearer);
  iBearers->Delete(index);
  delete bearer;
  
  // If no-one remains bound to us, signal data client idle to SCPR
  MaybePostDataClientIdle();
  }


//
// Utilities
//

// -----------------------------------------------------------------------------
// CLANLinkCommon::FindBearerByProtocolName
// -----------------------------------------------------------------------------
//
CLanxBearer* CLANLinkCommon::FindBearerByProtocolName(const TDesC8& aProtocol, TInt& aIndex) const
/**
Search the iBearers array searching for a match by protocol name.

@param aProtocol name of protocol (in)
@param aIndex on success, index of found entry (>=0), else -1.
@return pointer to CLanxBearer entry on success else NULL.
*/
  {
    DEBUG("CLANLinkCommon::FindBearerByProtocolName()");
  
  TInt count = iBearers->Count();
  for (TInt i = 0 ; i < count ; ++i)
    {
    CLanxBearer* bearer = iBearers->At(i);
    if (bearer->ProtocolName() == aProtocol)
      {
      aIndex = i;
      return bearer;
      }
    }
  aIndex = -1;
  return NULL;
  }


// -----------------------------------------------------------------------------
// CLANLinkCommon::FindBearerByUpperControl
// -----------------------------------------------------------------------------
//
CLanxBearer* CLANLinkCommon::FindBearerByUpperControl(const MUpperControl* aUpperControl, TInt& aIndex) const
/**
Search the iBearers array searching for a match by protocol name.

@param aProtocol name of protocol (in)
@param aIndex on success, index of found entry (>=0), else -1.
@return pointer to CLanxBearer entry on success else NULL.
*/
  {
    DEBUG("CLANLinkCommon::FindBearerByUpperControl()");
  
  TInt count = iBearers->Count();
  for (TInt i = 0 ; i < count ; ++i)
    {
    CLanxBearer* bearer = iBearers->At(i);
    if (bearer->MatchesUpperControl(aUpperControl))
      {
      aIndex = i;
      return bearer;
      }
    }
  aIndex = -1;
  return NULL;
  }
  
// =====================================================================================
//
// MCFNode

// -----------------------------------------------------------------------------
// CLANLinkCommon::ReceivedL
// -----------------------------------------------------------------------------
//
EXPORT_C void CLANLinkCommon::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
/**
Routine called on an incoming message from SCPR

@param aCFMessage incoming message
@return KErrNone, else a system wide error code.
*/
    {
    DEBUG1("CLANLinkCommon::ReceivedL(), aCFMessage=%d", aMessage.MessageId().MessageId());
    
    CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage);
   
    if (TEBase::ERealmId == aMessage.MessageId().Realm())
        {
        switch (aMessage.MessageId().MessageId())
            {
        case TEBase::TError::EId :
            SubConnectionError(static_cast<TEBase::TError&>(aMessage).iValue);
            break;
        case TEBase::TCancel::EId :
            CancelStartFlow();
            break;                
        default:
            ASSERT(EFalse);
            }
        }
    else if (TEChild::ERealmId == aMessage.MessageId().Realm())
        {
        switch (aMessage.MessageId().MessageId())
            {
        case TEChild::TDestroy::EId :
            Destroy();
            break;
        default:
            ASSERT(EFalse);
            }
        }
    else if (TCFDataClient::ERealmId == aMessage.MessageId().Realm())
        {
        switch (aMessage.MessageId().MessageId())
            {
        case TCFDataClient::TStart::EId :
            StartFlowL();
            break;
        case TCFDataClient::TProvisionConfig::EId:
            ProvisionConfig(static_cast<TCFDataClient::TProvisionConfig&>(aMessage).iConfig);
            break;
        case TCFDataClient::TStop::EId :
            StopFlow(static_cast<TCFDataClient::TStop&>(aMessage).iValue);
            break;
        case TCFDataClient::TBindTo::EId :
      {
            TCFDataClient::TBindTo& bindToReq = message_cast<TCFDataClient::TBindTo>(aMessage);
            if (!bindToReq.iNodeId.IsNull())
                {
                User::Leave(KErrNotSupported);
                }
            RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete().CRef());
            break;
      }
    default:
            ASSERT(EFalse);
            }
        }
    else if (TLinkMessage::ERealmId == aMessage.MessageId().Realm())
        {
        switch (aMessage.MessageId().MessageId())
            {
            case TLinkMessage::TAgentToFlowNotification::EId:
                {                    
              TLinkMessage::TAgentToFlowNotification& msg = message_cast<TLinkMessage::TAgentToFlowNotification>(aMessage);
              if(msg.iValue != EAgentToNifEventVendorSpecific)
                {
                User::Leave(KErrNotSupported);
                }
              else //EAgentToNifEventVendorSpecific
                {
                //User::LeaveIfError((iPktDrv) ? iPktDrv->Notification(
                //    static_cast<TAgentToNifEventType>(msg.iValue), NULL) : KErrNotSupported);
                DEBUG("CLANLinkCommon::ReceivedL(), rcvd disconnect notification from Agent");
                iError = KErrDisconnected;
                StopInterface();
                }         
                }
                break;
            default:
                ASSERT(EFalse);             
            }; //endswitch   
        }
    else
        {
        ASSERT(EFalse);
        }
    }

//
// Methods for handling incoming SCPR messages
//

// -----------------------------------------------------------------------------
// CLANLinkCommon::StartFlowL
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::StartFlowL()
  {
    DEBUG("CLANLinkCommon::StartFlowL()");
    
    if ( !iPktDrv )
        LoadPacketDriverL();
  
  iStopRequested = EFalse;
  
  ASSERT(iMMState == EStopped);

  if (iSavedError != KErrNone)
    {
    // If there were errors during prior processing of the TProvisionConfig message,
    // leave here and cause a TError response to TDataClientStart.
    User::Leave(iSavedError);
    }

  iValidMacAddr = ReadMACSettings();
  
  iMMState = EStarting;
  User::LeaveIfError(iPktDrv->StartInterface());
  }


// -----------------------------------------------------------------------------
// CLANLinkCommon::CancelStartFlow
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::CancelStartFlow()
    {
    if (iMMState == EStarting)
        {
      iStopRequested = ETrue;
    
      iPktDrv->StopInterface();
      PostProgressMessage(KLinkLayerClosed, KErrCancel);
      PostFlowDownMessage(KErrCancel);
    
      MaybePostDataClientIdle();
      }
    }


// half a second should be enough for sending DHCPRELEASE
static const TInt KDhcpReleaseDelay = 500000;
  
// -----------------------------------------------------------------------------
// CLANLinkCommon::StopFlow
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::StopFlow(TInt aError)
  {
    DEBUG("CLANLinkCommon::StopFlow()");
    
  iStopRequested = ETrue;

  iMMState = EStopping;
  
  iError = aError;

  TCallBack callback(StopCb, this);
  TRAPD(err, iPeriodic = CPeriodic::NewL(CActive::EPriorityStandard));
  if(err == KErrNone)
      {
    // Call the callback after KDhcpReleaseDelay. This is done only once,
    // but we need to put something (KMaxTInt) to CPeriodic's interval.
    iPeriodic->Start(TTimeIntervalMicroSeconds32(KDhcpReleaseDelay), TTimeIntervalMicroSeconds32(KMaxTInt), callback);
      }
  else
      {
    iPeriodic = NULL;
      } 
  }


// -----------------------------------------------------------------------------
// CLANLinkCommon::SubConnectionGoingDown
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::SubConnectionGoingDown()
  {
  }
  
// -----------------------------------------------------------------------------
// CLANLinkCommon::SubConnectionError
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::SubConnectionError(TInt /*aError*/)
  {
  }


/*
Provisioning description for Ethernet CFProtocol Flow:

- on receipt of the TProvisionConfig message, the pointer contained within is stored
  in iAccessPointConfig and the provisioning information contained within the AccessPointConfig
  array is validated:
  - at least one of TLanIp4Provision or TLanIp6Provision must be present.  They are added by the EtherMCPr and
    populated from CommsDat.

- the packet driver is loaded.

- if any of the above steps fail, the resulting error is saved in iSaveError so that when TDataClientStart message is
  subsequently received, a TError message can be sent in response (there is no response to TProvisionConfig message).
*/

// -----------------------------------------------------------------------------
// CLANLinkCommon::ProvisionConfig
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::ProvisionConfig( const RMetaExtensionContainerC& aConfigData )
    {
    DEBUG("CLANLinkCommon::ProvisionConfig()");

    iSavedError = KErrNone;

    AccessPointConfig().Close();
    AccessPointConfig().Open(aConfigData);
    
    iLanIp4Provision = static_cast<const TLanIp4Provision*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TLanIp4Provision::EUid, TLanIp4Provision::ETypeId)));
    if (iLanIp4Provision)
        {
        DEBUG("CLANLinkCommon::ProvisionConfig() - IP4 config to be provisioned");
        }

    iLanIp6Provision = static_cast<const TLanIp6Provision*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TLanIp6Provision::EUid, TLanIp6Provision::ETypeId)));
    if (iLanIp6Provision)
        {
        DEBUG("CLANLinkCommon::ProvisionConfig() - IP6 config to be provisioned");
        }

    if (iLanIp4Provision == NULL && iLanIp6Provision == NULL)
        {
        // At least one set of IP4/6 provisioning information must be present
        iSavedError = KErrCorrupt;
        return;
        }

    TRAPD(err, ProvisionConfigL());
    if (err != KErrNone)
        {
        iSavedError = err;
        }
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::ProvisionConfigL
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::ProvisionConfigL()
    {
    DEBUG("CLANLinkCommon::ProvisionConfigL()");

    // Provision Bearers
    if (iBearers->Count())
        {
        ProvisionBearerConfigL(KDescIp());
        ProvisionBearerConfigL(KDescIp6());
        }

    iWLMServerCommon =  new (ELeave) CLANNifWLMServerCommon(this);
    iWLMServerCommon->ConstructL();

	TBool isAutomaticMgmt( ETrue );
	CRepository* repository = NULL;	
	TRAP_IGNORE( repository = CRepository::NewL( KCRUidWlanDeviceSettingsRegistryId ) );
	if( repository )
	    {
	    TInt temp( 0 );
	    TInt ret = repository->Get( KWlanAutomaticTrafficStreamMgmt, temp );
	    if( ret == KErrNone &&
	        !temp )
	        {
	        isAutomaticMgmt = EFalse;
	        }

	    delete repository;
	    repository = NULL;
	    }

	for( TUint idx( 0 ); idx < EWlmAccessClassMax; ++idx )
	    {
	    iAcArray[idx] = CLANNifWLMServerPerAC::NewL(
	        static_cast<TWlmAccessClass>( idx ),
	        KTsInactivityTime[idx],
	        isAutomaticMgmt );
	    }
    }

// -----------------------------------------------------------------------------
// CLANLinkCommon::Destroy
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::Destroy()
  {
    DEBUG("CLANLinkCommon::Destroy()");
    
  ASSERT(iMMState==EStopped);
  DeleteThisFlow();
  }

// Utility functions

void CLANLinkCommon::ProvisionBearerConfigL(const TDesC8& aName)
  {
    DEBUG("CLANLinkCommon::ProvisionBearerConfigL()");
  
  TInt index = -1;
  CLanxBearer* bearer = FindBearerByProtocolName(aName, index);
  if (bearer)
    {
        if (aName.CompareF(KDescIp) == 0)
        {
        if (iLanIp4Provision)
            {
            bearer->SetProvisionL(iLanIp4Provision); // CLanIp4Bearer
            }
        }
    else if (aName.CompareF(KDescIp6) == 0) 
        {
        if (iLanIp6Provision)
            {
            bearer->SetProvisionL(iLanIp6Provision); // CLanIp6Bearer
            }
        }
    }
  }


// -----------------------------------------------------------------------------
// CLANLinkCommon::PostProgressMessage
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::PostProgressMessage(TInt aStage, TInt aError)
  {
    DEBUG("CLANLinkCommon::PostProgressMessage()");
  
  //Be careful when sending TStateChange message as RNodeChannelInterface will override the activity id
  iSubConnectionProvider.RNodeInterface::PostMessage(Id(), TCFMessage::TStateChange( Elements::TStateChange( aStage, aError) ).CRef());
  }

// -----------------------------------------------------------------------------
// CLANLinkCommon::SetAllowedBearer
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::SetAllowedBearer(CLanxBearer* aBearer)
  {
    iOnlyThisBearer = aBearer;
  }
  
// -----------------------------------------------------------------------------
// CLANLinkCommon::BearereIsActive
// -----------------------------------------------------------------------------
//
TBool CLANLinkCommon::BearerIsActive(CLanxBearer* aBearer)
  {
    if (!iOnlyThisBearer || 
        aBearer == iOnlyThisBearer)
      {
      return ETrue;
      }
    return EFalse;      
  }

// -----------------------------------------------------------------------------
// CLANLinkCommon::PostFlowDownMessage
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::PostFlowDownMessage(TInt aError)
  {
    DEBUG("CLANLinkCommon::PostFlowDownMessage()");
  
  if (iMMState == EStopping)
      {
      iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStopped(aError).CRef());     
      }
    else if (iMMState == EStarting)
      {
      iSubConnectionProvider.PostMessage(Id(), TEBase::TError(TCFDataClient::TStart::Id(), aError).CRef());
      }
    else if (iMMState == EStarted)
      {
      iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError).CRef());
      }     
    iMMState = EStopped;  
  }


// -----------------------------------------------------------------------------
// CLANLinkCommon::PostFlowGoingDownMessage
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::PostFlowGoingDownMessage(TInt aError, MNifIfNotify::TAction /*aAction*/)
  {
    DEBUG("CLANLinkCommon::PostFlowGoingDownMessage()");
    
  // TDataClientGoneDown only makes sense if the flow was actually started
  ASSERT(iMMState == EStarted); 
  iMMState = EStopped;
  iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError).CRef());
  }

  
// -----------------------------------------------------------------------------
// CLANLinkCommon::PostDataClientStartedMessage
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::PostDataClientStartedMessage()
  {
    DEBUG("CLANLinkCommon::PostDataClientStartedMessage()");
  
  iMMState = EStarted;
  iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStarted().CRef());
  }


// -----------------------------------------------------------------------------
// CLANLinkCommon::MaybePostDataClientIdle
// -----------------------------------------------------------------------------
//
void CLANLinkCommon::MaybePostDataClientIdle()
  {
    DEBUG("CLANLinkCommon::MaybePostDataClientIdle()");
  
  if (iBearers->Count() == 0 && iMMState == EStopped)
    {
    iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
    }
  }


void TEtherLLCFrame::SetDestAddr( TDesC8& aDest)
{
    DEBUG("TEtherLLCFrame::SetDestAddr()");

    Mem::Copy(iDestAddr, aDest.Ptr(), KMACByteLength);    
}

// -----------------------------------------------------------------------------
// CLANLinkCommon::SetSrcAddr
// -----------------------------------------------------------------------------
//
void TEtherLLCFrame::SetSrcAddr(TDesC8& aSrc)
{
    DEBUG("TEtherLLCFrame::SetSrcAddr()");

    Mem::Copy(iSrcAddr, aSrc.Ptr(), KMACByteLength);
}

// -----------------------------------------------------------------------------
// CLANLinkCommon::SetOUI
// -----------------------------------------------------------------------------
//
void TEtherLLCFrame::SetOUI(TUint32 aOUI)
{
    DEBUG("TEtherLLCFrame::SetOUI()");

  //aOUI is in native order, but the result is
  //always stored in network byte order.
  //Can't use the bigendian methods, because
  //they only work for 16 and 32 -bit items.
  OUI[0] = (TUint8)((aOUI>>16)&0xff);
  OUI[1] = (TUint8)((aOUI>>8)&0xff);
  OUI[2] = (TUint8)(aOUI&0xff);
}