diff -r 000000000000 -r af10295192d8 linklayerprotocols/ethernetnif/EthInt/Ethbase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linklayerprotocols/ethernetnif/EthInt/Ethbase.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,1223 @@ +// Copyright (c) 1997-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: +// Ethernet and 802.3 protocol suite common link layer (interface) code +// +// + +/** + @file +*/ + +#include +#include // for TTime +#include +#include +#include +#include +#include +#include +#include // for KSlashChar +#include +#include "EthProto.h" +#include "PKTDRV.H" +#include // Header is retained, but in_sock.h is modified for ipv6 +#include +#include "CLanIp4Bearer.h" +#include "CLanIp6Bearer.h" +#include "eth_log.h" +#include +#include +#include "CLanxBearer.h" +#include "eth_log.h" +#include "EthProvision.h" +#include // for SAccessPointConfig +#include +#include +#include +#include + +using namespace Messages; +using namespace MeshMachine; +using namespace ESock; +using namespace Elements; + +_LIT8(KDescIp, "ip"); +_LIT8(KDescIcmp, "icmp"); +_LIT8(KDescIp6, "ip6"); + +/** +Constant supports Broadcasting or Multicasting +@internalComponent +*/ + +/** +Packet driver Function Pointer +@internalComponent +*/ +typedef CPktDrvFactory* (*TPktDrvFactoryNewL)(); + +EXPORT_C CLANLinkCommon::CLANLinkCommon(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf) + : CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf), iMMState(EStopped) +{ + LOG_NODE_CREATE(KEthLogTag2, CLANLinkCommon); +} + +/** +Loads, creates and starts the packet driver. +The packet driver's name is found from the LAN service table in commdb. +The name then has '.drv' appended and its driver factory is found using DoFindDriverFactoryL. +If found, the packet driver is created using the factory's NewDriverL method and the driver state is set to EDrvStarted. +@note Should be called from the ConstructL phase of the CLANLinkCommon initialisation. +*/ +void CLANLinkCommon::LoadPacketDriverL() +{ + TBuf drvName; // plus 4 is for the filename extension added below + + ASSERT(iLanLinkProvision); + + if (LinkProvision().PacketDriverName().Length() == 0) + { + __FLOG_STATIC(KEther802LogTag1,KEthLogTag2, _L("Empty packet driver name - is .cfg file up-to-date? See ether802.ini for information on required fields in commdb.")); + User::Leave(KErrArgument); + } + + drvName.Copy(LinkProvision().PacketDriverName()); + + if(!(drvName.Right(4)==KPacketDriverFileExtension())) // no != for comparing strings, so a bit of laboured logic + { + drvName.Append(KPacketDriverFileExtension); + } + + // Ref counted library ownership to ensure the library is not unloaded prematurely + CPktDrvFactory* pktFactory = (CPktDrvFactory *)DoCreateDriverFactoryL(TUid::Uid(KUidNifmanPktDrv), drvName); + CleanupStack::PushL(pktFactory); + iPktDrvOwner = new(ELeave)CPacketDriverOwner(pktFactory); + CleanupStack::Pop(); + iPktDrvOwner->Open(); + + iPktDrv=pktFactory->NewDriverL(this); +} + +EXPORT_C CLANLinkCommon* CLANLinkCommon::NewL(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf) + { + CLANLinkCommon* s=new (ELeave) CLANLinkCommon(aFactory, aSubConnId, aProtocolIntf); + CleanupStack::PushL(s); + s->ConstructL(); + CleanupStack::Pop(); + return s; + } + +/** Ethernet Type - Encapsulation +@internalComponent +*/ +_LIT(KEtherType,"encapsulation"); + +/** +Reads the Link layer Ethernet settings in Ether802.ini. Currently this is just the ethernet +encapsulation type, stored in parameter encapsulation in section [ethernet], sets iEtherType +on the basis of the encapsulation type: ELLCEthernet, if the encapsulation parameter = 1, or +EStandardEthernet otherwise. +*/ +void CLANLinkCommon::ReadEthintSettingsL() +{ + CESockIniData* ini = CESockIniData::NewL(ETHER802_CONFIG_FILENAME); + CleanupStack::PushL(ini); + TInt encapType = 0; + ini->FindVar(KEthernetSection,KEtherType,encapType); + + CleanupStack::PopAndDestroy(); + + switch(encapType) + { + case 0 : + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L("Framing type set to Ethernet II")); + iEtherType=EStandardEthernet; + break; + case 1 : + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L("Framing type set to IEEE802.3 LLC-SNAP")); + iEtherType=ELLCEthernet; + break; + default : + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L("Unrecognised or no framing type in config file - framing type set to Ethernet II")); + iEtherType=EStandardEthernet; // not a valid type + } +} + +/** +Implementation of the pure virtual from CLANLinkBase, for use by the bearers. Returns the +hardware interface obtained from the packet layer in the aBuffer descriptor in a 6 byte binary +Big-endian format. +@return ETrue if the hardware address was non-zero, EFalse otherwise. +*/ +TBool CLANLinkCommon::ReadMACSettings() +{ + TBuf8 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;indexUpdateMACAddr(); + } + + // check that the macaddress has been passed and is not 0; + return CheckMac(iMacAddr); // wrong. +} + + +TUint CLANLinkCommon::Mtu() const +{ + if(iEtherType==ELLCEthernet) + { + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L("MTU - value for LLC frames")); + return KEtherMaxFrame; + } + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L("MTU - default setting")); + return KDefaultMtuSetting; +} + +/** +The CLANLinkCommon::ConstructL performs all the memory allocating initialisations. It's +iContainer is allocated, using NewL; its iPktDriverFactories is created using its +iContainer->CreateL. A dynamic array of 16 iBearers are created. +@param TDesC Unused +*/ +EXPORT_C void CLANLinkCommon::ConstructL() +{ + __FLOG_STATIC(KEther802LogTag1,KEthLogTag2, _L("Ethint started")); + + // Initialise class members that do not need to be read from the database + iBearers = new (ELeave) CLanxBearerPtrArray(16); + iOnlyThisBearer = NULL; + + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L("Reading Ethint settings")); + ReadEthintSettingsL(); + +#ifdef TCPDUMP_LOGGING + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L("Libpcap format logging enabled")); + iLogger = CEthLog::NewL(); + iLogger->DumpTcpDumpFileHeader(); +#endif // TCPDUMP_LOGGING +} + +/** +Destructor. If there are any iPktDrvFactories, these are deleted first, by closing each Factory's +RLibrary iLib handle and then deleting the object. Then all the bearers are deleted . Finally, +the packet driver, the logical device driver and the physical device driver are freed and then +the packet driver is deleted. +*/ +EXPORT_C CLANLinkCommon::~CLANLinkCommon() +{ +#ifdef TCPDUMP_LOGGING + delete iLogger; +#endif // TCPDUMP_LOGGING + + delete iPktDrv; + if(iPktDrvOwner != NULL ) // iPktDrvOwner may not be created if leave occurs while loading the driver. + { + iPktDrvOwner->Close(); + } + ASSERT(0 == iBearers->Count()); + delete iBearers; + + LOG_NODE_DESTROY(KEthLogTag2, CLANLinkCommon); +} + +/** +Checks the descriptor for a valid (non-zero) MAC address. +@param aMacAddr A reference to a the descriptor containing the new MAC +@return ETrue if the MAC address was non-zero, EFalse otherwise. +*/ +TBool CLANLinkCommon::CheckMac(TDes8& aMacAddr) +{ + for (TUint i=0;i<=5;i++) + { + if (aMacAddr[i] != 0) + return ETrue; + } + return EFalse; +} + +/** +This method is intended for use when a device does not have the correct MAC address when ARP is started +(e.g. IRLAN). It must be called by the packet driver as soon as an interface address is available. +It should be called before the packet driver sends LinkLayerUp to nifman,otherwise packets could +be sent with an invalid hardware address. +*/ +EXPORT_C void CLANLinkCommon::FoundMACAddrL() +{ + iValidMacAddr = ReadMACSettings(); +} + +/** +Link Layer Up +Called by the packet driver when it is happy +@internalTechnology +*/ +EXPORT_C void CLANLinkCommon::LinkLayerUp() +{ + //some drivers have a valid MAC only after negotiation finishes + iValidMacAddr = ReadMACSettings(); + PostDataClientStartedMessage(); + + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L ("CLANLinkCommon::LinkLayerUp()")); + + /** + 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. */ +#ifndef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + if (LinkProvision().ConfigDaemonName().Length() == 0) + { +#endif + +#ifndef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + } +#endif + + TUint bearerLim = iBearers->Count(); + for(TUint index=0;indexStartSending((CProtocolBase*)this); + } +} + +EXPORT_C void CLANLinkCommon::LinkLayerDown(TInt aError, TAction aAction) // Notify the Protocol that the line is down +/** +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 +@internalTechnology +*/ + { + // If a stop was requested from the SCpr then this LinkLayerDown() + // was expected. This also means the SCpr has already been sent a + // TCFDataClient::TStopped 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) + { + + PostFlowGoingDownMessage(aError, (aAction == EReconnect) ? MNifIfNotify::EReconnect : MNifIfNotify::EDisconnect); + iPktDrv->StopInterface(); + iMMState = EStopped; + } + } + +/** +Given the RMBufChain &aPdu, which contains a PktInfo at the start, Convert the PktInfo into +an ether frame header. The source and dest address is already assumed to be filled, i.e. +multi-cast or whatever. aPdu is returned modified. +@param aPdu Contains a PktInfo. +@param aType The Ether type for the packet, +@return An error code, KErrNone if the Ethernet header could be prepended, or KErrGeneral + if it could not. +*/ +TInt CLANLinkCommon::EtherFrame(RMBufChain &aPdu, TUint16 aType) +{ + TInt ret; + //To start with, we need a buffer for the ethernet header, + //and the packet info. + + //Create an ether header + RMBufChain ethHdr; + TUint etherHeaderSize = (iEtherType==EStandardEthernet) ? + KEtherHeaderSize : KEtherLLCHeaderSize; + TRAP(ret, ethHdr.AllocL(etherHeaderSize)); + if (ret != KErrNone) + { + return ret; + } + TEtherLLCFrame *hdrBuf=(TEtherLLCFrame*)ethHdr.First()->Buffer(); + + //Get the packet info: + RMBufPktInfo* info = RMBufPacket::PeekInfoInChain(aPdu); + + // Fill in the dest, src Mac addresses: + hdrBuf->SetDestAddr(info->iDstAddr); + hdrBuf->SetSrcAddr(iMacAddr); + switch(iEtherType) + { + case EStandardEthernet: + BigEndian::Put16((TUint8*)&hdrBuf->iTypeLen,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->iTypeLen,static_cast(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. + TUint dummyLength=aPdu.Length(); // At this point, info becomes invalid. + aPdu.TrimStart(dummyLength-info->iLength); + //Finally, add the saved packet buffer to the mac header + aPdu.Prepend(ethHdr); + return KErrNone; +} + +/** +FrameSend frames the aPdu packet, giving it a type field defined by aType and then sends it via +the packet driver's Send method, returning its return value. If there is an error framing the +packet, the packet is dropped and KErrGeneral is returned. +@param aPdu The Packet to be sent (actually an RMBufPkt). +@param aProtocol A pointer to the protocol which sent the packet (ignored) +@param aType The Type field in the Ethernet header when framing. For iEtherFrame== EStandardEthernet, + this is stored in the iType field, for ELLCEthernet, this is stored in the + iTypeHi:iTypeLo fields. +@return 0 Tells the higher layer to send no more data else + 1 Tells higher layer that it can send more data +*/ +TInt CLANLinkCommon::FrameSend(RMBufChain& aPdu,TAny* /*aProtocol*/, 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. + + // Caller Flow controls off if the return to this method is <= 0 + if(EtherFrame(aPdu,aType)==KErrNone) + { + // Dump it to the log in pcap format +#ifdef TCPDUMP_LOGGING + //Find absolute time now + TTime timeNow; + timeNow.HomeTime(); + + iLogger->DumpFrame(timeNow,aPdu); +#endif + + return iPktDrv->Send(aPdu); + } + else + { // drop the packet and return an error - incorrectly formatted. + // which error though? + aPdu.Free(); + } + return KErrGeneral; // Should be a better error code though. +} + + +/** +GetProtocolType extracts protocol header information from an ethernet packet and is called +when processing a packet. +@param aPdu An Ethernet packet (actually, it is really an RMBufPkt with a packed + info, not an RMBufChain) +@param aEtherType The Ether type for the packet, which is the type field for the packet, + for example: KIPFrameType (=0x800) or KIP6FrameType (0x8dd). Note: + GetProtocolType makes no restrictions on valid EtherTypes, since + this is handled by the bearers. +@param aPayloadPtr A pointer to the beginning of the actual payload after the Ethernet + header (or the Ethernet LLC header). +@param aEtherHeaderSize The size of the Ethernet header, either the standard ethernet header + size (KEtherHeaderSize==14), or the LLC header size (KEtherLLCHeaderSize= standard+8). +@return An error code, KErrNone, if a valid procol type could be extracted, or KErrNotSupported otherwise. +*/ +TInt CLANLinkCommon::GetProtocolType(RMBufChain& aPdu, + TUint16& aEtherType, TUint8*& aPayloadPtr, + TUint& aEtherHeaderSize) const +{ + RMBuf* chnptr=aPdu.First(); // Start of received packet + // Start of actual packet data (Ethernet II) + TEtherFrame *etherFrame=(TEtherFrame*)(chnptr->Next()->Ptr()); + + if ((aEtherType=etherFrame->GetType())>=1536) + { // Standard Ethernet type + __ASSERT_DEBUG(chnptr->Next()->Length() >= KEtherHeaderSize, Panic(EIeee802AddrBadMBuf)); + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L ("CLANLinkCommon::GetProtocolType () Got Ethernet-II-type frame")); + + if (chnptr->Next()->Length() == KEtherHeaderSize) + { + aPayloadPtr = chnptr->Next()->Ptr(); + } + else + { + aPayloadPtr = etherFrame->iData; + } + aEtherHeaderSize=KEtherHeaderSize; + } + else // It's an LLC Ethernet frame (802.3) + { + if(chnptr->Next()->Length() >= KEtherLLCHeaderSize) + { + TEtherLLCFrame *etherLLCFrame = (TEtherLLCFrame*)etherFrame; + if(etherLLCFrame->iDSAP==KLLC_SNAP_DSAP && + etherLLCFrame->iSSAP==KLLC_SNAP_SSAP && + etherLLCFrame->iCtrl==KLLC_SNAP_CTRL) + { // Valid LLC-SNAP Frame. + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L ("CLANLinkCommon::GetProtocolType () Got 802.3-type frame, with LLC and SNAP headers")); + aEtherType=etherLLCFrame->GetType(); // Standard Ethernet type. + aPayloadPtr=etherLLCFrame->iData; + aEtherHeaderSize=KEtherLLCHeaderSize; + } + else + { + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L ("CLANLinkCommon::GetProtocolType () Got what initially looked like a 802.3-type frame, but no SNAP header")); + aEtherType=0; + aPayloadPtr=0; + aEtherHeaderSize=0; + return KErrNotSupported; + } + } + else + { + return KErrCorrupt; + } + } + return KErrNone; +} + +/** +Process processes a packet received from the packet driver. +@param aPdu The Packet to be sent (actually an RMBufPkt). +@param aLLC Unclear. +*/ +EXPORT_C void CLANLinkCommon::Process(RMBufChain& aPdu, TAny* /*aLLC*/) +{ + TUint16 etherCode; + TUint8* etherPtr; + TUint etherHeaderSize; + TBool packetProcessed=EFalse; + TInt ret=GetProtocolType(aPdu,etherCode,etherPtr,etherHeaderSize); + if (ret==KErrNone) + { // It's an ethernet packet of some kind. + + // Dump it to the log in pcap format +#ifdef TCPDUMP_LOGGING + //Find absolute time now + TTime timeNow; + timeNow.HomeTime(); + + RMBufPacket& pkt = (RMBufPacket&)aPdu; + pkt.Unpack(); + iLogger->DumpFrame(timeNow,aPdu); + pkt.Pack(); +#endif + + TUint bearerLim = iBearers->Count(); + for(TUint index=0;indexWantsProtocol(etherCode,etherPtr)) + { + RMBufPacket& pkt = (RMBufPacket&)aPdu; + pkt.Unpack(); + pkt.TrimStart(etherHeaderSize); + pkt.Pack(); + bearer->Process(aPdu, (TAny*)(TUint32)etherCode); // process expects ether type, but fixed function definition... + packetProcessed=ETrue; + } + } + } + } + if (ret!=KErrNone || !packetProcessed) + { + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L ("CLANLinkCommon::Process() - dropping packet - unrecognised type")); + aPdu.Free(); // Something strange about the packet - bin it + } +} + +/** +Implementation of pure virtual from CLANLinkBase for use by the packet driver. +Resume Sending is a notification call into NIF from the lower layer telling the NIF that a +previous sending congestion situation has been cleared and it can accept more downstack data. +NIF subsequently calls all the bearers' StartSending() methods directly. +*/ +EXPORT_C void CLANLinkCommon::ResumeSending() +{ + TUint bearerLim = iBearers->Count(); + for(TUint index=0;indexStartSending((CProtocolBase*)this); + } +} + +/** + +*/ +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) +{ + // Emulate reading of following parameters only: + // LAN_BEARER\LAN_BEARER_LDD_FILENAME + // LAN_BEARER\LAN_BEARER_LDD_NAME + // LAN_BEARER\LAN_BEARER_PDD_FILENAME + // LAN_BEARER\LAN_BEARER_PDD_NAME + + _LIT(KLanBearer, "LANBearer\\"); + const TInt KLanBearerTokenSize = 10; + + TPtrC field(aField.Left(KLanBearerTokenSize)); // "LANBearer" + + if (field.Compare(KLanBearer()) == 0) + { + _LIT(KLanBearerLddFilename, "LDDFilename"); + _LIT(KLanBearerLddName, "LDDName"); + _LIT(KLanBearerPddFilename, "PDDFilename"); + _LIT(KLanBearerPddName, "PDDName"); + + field.Set(aField.Mid(KLanBearerTokenSize)); // skip "LANBearer\\" + if (field.CompareF(KLanBearerLddFilename) == 0) + { + aValue.Copy(LinkProvision().LddFilename()); + } + else + if (field.CompareF(KLanBearerLddName) == 0) + { + aValue.Copy(LinkProvision().LddName()); + } + else + if (field.CompareF(KLanBearerPddFilename) == 0) + { + aValue.Copy(LinkProvision().PddFilename()); + } + else + if (field.CompareF(KLanBearerPddName) == 0) + { + aValue.Copy(LinkProvision().PddName()); + } + else + { + return KErrNotSupported; + } + return KErrNone; + } + else + { + 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::NifEvent(TNetworkAdaptorEventType /*aEventType*/, TUint /*aEvent*/, const TDesC8& /*aEventData*/, TAny* /*aSource*/) +{ +} + + +/** +Load a factory and check the Uid etc +function always opens factory CObject if successful +*/ +CPktDrvFactory* CLANLinkCommon::DoCreateDriverFactoryL(TUid aUid2,const TDesC& aFilename) +{ + TParse parse; + User::LeaveIfError(parse.Set(aFilename,0,0)); + + CPktDrvFactory* f=0; + + TAutoClose lib; + User::LeaveIfError(lib.iObj.Load(aFilename)); + lib.PushL(); + // The Uid check + if(lib.iObj.Type()[1]!=aUid2) + User::Leave(KErrBadLibraryEntryPoint); + + TPktDrvFactoryNewL libEntry=(TPktDrvFactoryNewL)lib.iObj.Lookup(1); + if (libEntry==NULL) + User::Leave(KErrNoMemory); + + f =(*libEntry)(); // Opens CObject (can leave) + + CleanupStack::PushL(f); + f->Install(lib.iObj); // Transfers the library object if successful + + // Can pop the library now - auto close will have no effect because handle is null + CleanupStack::Pop(); + lib.Pop(); + + return f; +} + + +// ====================================================================================== +// +// from MFlowBinderControl + +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. +*/ + { + 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(); + + // Must have provisioning information to operate + ASSERT(iLanLinkProvision); + iBearers->AppendL(bearer); + ProvisionBearerConfigL(aName); + CleanupStack::Pop(); + return bearer; + } + +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) +*/ + { + 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; + } + +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) +*/ + + { + 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 +// + +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. +*/ + { + 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; + } + +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. +*/ + { + 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; + } + +// ===================================================================================== +// +// Messages::ANode + +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. +*/ + { + CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage); + if (TEBase::ERealmId == aMessage.MessageId().Realm()) + { + switch (aMessage.MessageId().MessageId()) + { + case TEBase::TError::EId : + SubConnectionError(static_cast(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(aMessage).iConfig); + break; + case TCFDataClient::TStop::EId : + StopFlow(static_cast(aMessage).iValue); + break; + case TCFDataClient::TBindTo::EId : + { + TCFDataClient::TBindTo& bindToReq = message_cast(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(aMessage); + if(msg.iValue < KVendorSpecificNotificationStart) + { + User::Leave(KErrNotSupported); + } + else + { + User::LeaveIfError((iPktDrv) ? iPktDrv->Notification( + static_cast(msg.iValue), NULL) : KErrNotSupported); + } + } + break; + default: + ASSERT(EFalse); + }; //endswitch + } + else // (message and realm not recognised within this domain) + { + ASSERT(EFalse); + } + } + +// +// Methods for handling incoming SCPR messages +// + +void CLANLinkCommon::StartFlowL() + { + 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 TCFDataClient::TStart. + User::Leave(iSavedError); + } + + iValidMacAddr = ReadMACSettings(); + + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L("Starting Interface")); + iMMState = EStarting; + User::LeaveIfError(iPktDrv->StartInterface()); + } + + +void CLANLinkCommon::CancelStartFlow() + { + if (iMMState == EStarting) + { + iStopRequested = ETrue; + + iPktDrv->StopInterface(); + PostFlowDownMessage(KErrCancel); + } + } + +void CLANLinkCommon::StopFlow(TInt aError) + { + iStopRequested = ETrue; + iMMState = EStopping; + + iPktDrv->StopInterface(); + PostFlowDownMessage(aError); + } + +void CLANLinkCommon::SubConnectionGoingDown() + { + } + +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: + - TLanLinkProvision must be present. It is added by the EtherMCPr and populated from CommsDat. A pointer to it + is stored in iLanLinkProvision. + - 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 TCFDataClient::TStart message is + subsequently received, a TError message can be sent in response (there is no response to TProvisionConfig message). +*/ + +void CLANLinkCommon::ProvisionConfig(const RMetaExtensionContainerC& aConfigData) + { + __FLOG_STATIC(KEther802LogTag1,KEthLogTag2,_L("CLANLinkCommon:\tProvisionConfig message received")); + + AccessPointConfig().Close(); + AccessPointConfig().Open(aConfigData); + + ASSERT(iLanLinkProvision == NULL); // Should only happen once + + iLanLinkProvision = static_cast(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TLanLinkProvision::EUid, TLanLinkProvision::ETypeId))); + if (iLanLinkProvision == NULL) + { + __FLOG_STATIC(KEther802LogTag1,KEthLogTag2,_L("CLANLinkCommon:\tProvisionConfig() - no Ethernet Link configuration")); + iSavedError = KErrCorrupt; + return; + } + + iLanIp4Provision = static_cast(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TLanIp4Provision::EUid, TLanIp4Provision::ETypeId))); + if (iLanIp4Provision == NULL) + { + __FLOG_STATIC(KEther802LogTag1,KEthLogTag2,_L("CLANLinkCommon:\tProvisionConfig() - no IP4 configuration")); + } + + iLanIp6Provision = static_cast(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TLanIp6Provision::EUid, TLanIp6Provision::ETypeId))); + if (iLanIp6Provision == NULL) + { + __FLOG_STATIC(KEther802LogTag1,KEthLogTag2,_L("CLANLinkCommon:\tProvisionConfig() - no IP6 config 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; + } + } + + +void CLANLinkCommon::ProvisionConfigL() + { + // Provision Bearers + if (iBearers->Count()) + { + ProvisionBearerConfigL(KDescIp()); + ProvisionBearerConfigL(KDescIp6()); + } + + __FLOG_STATIC(KEther802LogTag1, KEthLogTag2, _L("Loading packet driver")); + LoadPacketDriverL(); + } + +void CLANLinkCommon::Destroy() + { + ASSERT(iMMState==EStopped); + DeleteThisFlow(); + } + +// Utility functions + +void CLANLinkCommon::ProvisionBearerConfigL(const TDesC8& aName) + { + 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 + } + } + } + } + +void CLANLinkCommon::PostProgressMessage(TInt aStage, TInt aError) + { + //Be careful when sending TStateChange message as RNodeChannelInterface will override the activity id + iSubConnectionProvider.RNodeInterface::PostMessage(Id(), TCFMessage::TStateChange(TStateChange( aStage, aError)).CRef()); + } + +void CLANLinkCommon::PostFlowDownMessage(TInt aError) + { + if (iMMState == EStopping) + { + iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStopped(aError).CRef()); + } + else if (iMMState == EStarting) + { + iLastRequestOriginator.ReplyTo(Id(), TEBase::TError(TCFDataClient::TStart::Id(), aError).CRef()); + } + else if (iMMState == EStarted) + { + iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError).CRef()); + } + iMMState = EStopped; + } + +void CLANLinkCommon::PostFlowGoingDownMessage(TInt aError, MNifIfNotify::TAction aAction) + { + // TDataClientGoneDown only makes sense if the flow was actually started + ASSERT(iMMState == EStarted); + iMMState = EStopped; + iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError, aAction).CRef()); + } + +void CLANLinkCommon::PostDataClientStartedMessage() + { + iMMState = EStarted; + iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStarted().CRef()); + } + +void CLANLinkCommon::MaybePostDataClientIdle() + { + if (iBearers->Count() == 0) + { + iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef()); + } + } + + +/** +Sets the BigEndian 32-bit value at iDstAddr to aDestAddr +Support methods for TEtherLLCFrame. +Note: These Methods should really go in a file for themselves. +@param aDest The destination IP address. +*/ +void TEtherLLCFrame::SetDestAddr( TDesC8& aDest) +{ + // copied a word at a time, remember BigEndian portability. + for(TUint ix=0; ix<3; ix++) + { + BigEndian::Put16((TUint8*)&iDestAddr[ix],(TUint16)(((aDest[ix*2]<<8)|aDest[ix*2+1])&0xffff)); + } +} + +/** +Sets the BigEndian 32-bit value at iSrcAddr to aSrcAddr. +@param aSrc The source IP address. +*/ +void TEtherLLCFrame::SetSrcAddr(TDesC8& aSrc) +{ + for(TUint ix=0; ix<3; ix++) + { + BigEndian::Put16((TUint8*)&iSrcAddr[ix],(TUint16)(((aSrc[ix*2]<<8)|aSrc[ix*2+1])&0xffff)); + } +} + +/** +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. +@param aOUI Byte order. +*/ +void TEtherLLCFrame::SetOUI(TUint32 aOUI) +{ + //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); +} + +const TLanLinkProvision& CLANLinkCommon::LinkProvision() + { + return *iLanLinkProvision; + } + +void CLANLinkCommon::SetAllowedBearer(CLanxBearer* aBearer) + { + iOnlyThisBearer = aBearer; + } + TBool CLANLinkCommon::BearerIsActive(CLanxBearer* aBearer) + { + if (!iOnlyThisBearer || + aBearer == iOnlyThisBearer) + { + return ETrue; + } + return EFalse; + } +