diff -r 000000000000 -r dfb7c4ff071f commsfwutils/commsbufs/reference/loopback_bearer/src/binder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commsfwutils/commsbufs/reference/loopback_bearer/src/binder.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,1117 @@ +/* +* Copyright (c) 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: +* +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "var.h" +#include "binder.h" +#include "provision.h" + +#ifdef SYMBIAN_ZERO_COPY_NETWORKING +#include +#include +#include +#else +#include +#endif + +using namespace ESock; + +#ifdef _DEBUG +_LIT8(KNif,"Legacy"); +_LIT8(KBinder4,"Binder4"); +_LIT8(KBinder6,"Binder6"); +#endif + +// +// CLegacyLoopbackBinder4 // +// + +CLegacyLoopbackBinder4::CLegacyLoopbackBinder4(CLegacyLoopbackSubConnectionFlow& aLegacyLoopbackSubConnectionFlow) : iLegacyLoopbackSubConnectionFlow(aLegacyLoopbackSubConnectionFlow) + { + __FLOG_OPEN(KNif, KBinder4); + // generate my local ip address (ip4) - vals potentially will be overwritten by any derived classes + iLocalAddressBase = KLegacyLoopbackLocalAddressBase; // also used later in control method + + TUint32 id = ((TUint32)this) % 255; + // Avoid the reserved address (least significant byte KLegacyLoopbackReservedHostId) that + // is never to be allocated as a local address. + if (id == KLegacyLoopbackReservedHostId) + { + ++id; + } + iLocalAddress = iLocalAddressBase + id; + __FLOG_3(_L8("CLegacyLoopbackBinder4 %08x:\tCLegacyLoopbackBinder4(CLegacyLoopbackSubConnectionFlow& %08x): iLocalAddress %08x"), this, &aLegacyLoopbackSubConnectionFlow, iLocalAddress); +} + +CLegacyLoopbackBinder4::~CLegacyLoopbackBinder4() +/** +Destroys 'this' +*/ + { + if (iTestSubscriber) + { + iTestSubscriber->Cancel(); + } + delete iTestSubscriber; + delete iDrvReceiver; + delete iDrvSender; + __FLOG_1(_L8("CLegacyLoopbackBinder4 %08x:\t~CLegacyLoopbackBinder4()"), this); + ASSERT(iUpperControl == NULL); + ASSERT(iUpperReceiver == NULL); + ASSERT(!iErrorOneShot.IsActive()); + RDebug::Printf("closing driver\n"); + iDrv.Close(); + __FLOG_CLOSE; + } + +CLegacyLoopbackBinder4* CLegacyLoopbackBinder4::NewL(CLegacyLoopbackSubConnectionFlow& aLegacyLoopbackSubConnectionFlow) + { + CLegacyLoopbackBinder4* self = new (ELeave) CLegacyLoopbackBinder4(aLegacyLoopbackSubConnectionFlow); + CleanupStack::PushL(self); + + const TProviderInfo& providerInfo = static_cast( + aLegacyLoopbackSubConnectionFlow.AccessPointConfig().FindExtensionL( + STypeId::CreateSTypeId(TProviderInfoExt::EUid, TProviderInfoExt::ETypeId))).iProviderInfo; + TInt ap = providerInfo.APId(); + if(CLegacyLoopbackFlowTestingSubscriber::ShouldRun(ap)) + { + ASSERT(self->iTestSubscriber==NULL); + self->iTestSubscriber = CLegacyLoopbackFlowTestingSubscriber::NewL(aLegacyLoopbackSubConnectionFlow, ap); + } + + // The send and receive paths each have an AO + self->iDrvReceiver = new(ELeave) CDrvReceiver(CActive::EPriorityHigh); + self->iDrvSender = new(ELeave) CDrvSender(CActive::EPriorityHigh); + + CleanupStack::Pop(self); + return self; + } + +void CLegacyLoopbackBinder4::LogPacketDetails(TInet6HeaderIP4* aIp4, const TDesC8& aCaption) + { + static_cast(aIp4); + static_cast(aCaption); + +#if defined __FLOG_ACTIVE + TBuf8 log; + TInet6HeaderUDP* udp = NULL; + TInet6HeaderTCP* tcp = NULL; + TBuf8<10> prot; + TBuf8<40> length; + TInt srcPort = -1; + TInt dstPort = -1; + if(aIp4->Protocol() == KProtocolInetUdp) + { + udp = (TInet6HeaderUDP*) aIp4->EndPtr(); + prot = _L8("UDP"); + length.Format(_L8("payload %d"), udp->Length()); + srcPort = udp->SrcPort(); + dstPort = udp->DstPort(); + } + else if(aIp4->Protocol() == KProtocolInetTcp) + { + tcp = (TInet6HeaderTCP*) aIp4->EndPtr(); + prot = _L8("TCP"); + length.Format(_L8("payload %d"), aIp4->TotalLength() - aIp4->HeaderLength() - tcp->HeaderLength()); + srcPort = tcp->SrcPort(); + dstPort = tcp->DstPort(); + } + else + { + prot.Format(_L8("%d"), aIp4->Protocol()); + length.Format(_L8("tot_len %d"), aIp4->TotalLength()); + } + TDes8IgnoreOverflow overflow; + log.AppendFormat(_L8("%S %S %S src %08x:%d, dst %08x:%d"), &overflow, &aCaption, &prot, &length, + aIp4->SrcAddr(), srcPort, aIp4->DstAddr(), dstPort); + __FLOG(log); +#endif + } + +void CLegacyLoopbackBinder4::UpdateHeaders(TInet6HeaderIP4* aIp4, TInet6HeaderUDP* aUdp) +/** +Update the IPv4 and UDP headers to allow the packet to be looped back. +*/ +{ + __FLOG_STMT( LogPacketDetails(aIp4, _L8("CLegacyLoopbackBinder4:\tUpdateHeaders(...): ")) ); + + // swap over the destination and source addresses + TUint32 temp; + temp = aIp4->SrcAddr(); + aIp4->SetSrcAddr(aIp4->DstAddr()); + aIp4->SetDstAddr(temp); + + // swap over the destination and source ports + if (aUdp) + { + TUint tempPort; + tempPort = aUdp->DstPort(); + aUdp->SetDstPort(aUdp->SrcPort()); + aUdp->SetSrcPort(tempPort); + } + + // NB: don't need to recalculate any checksums since luckily IP sums don't detect transposition + __FLOG_4(_L("CLegacyLoopbackBinder4:\tUpdateHeaders(...): became src %08x:%d, dst %08x:%d"), + aIp4->SrcAddr(), aUdp? (TInt)aUdp->SrcPort(): -1, (TInt)aIp4->DstAddr(), aUdp? (TInt)aUdp->DstPort(): -1); +} + +MLowerDataSender::TSendResult CLegacyLoopbackBinder4::Send(RMBufChain& aData) +/** +Entry point for receiving IPv4 outgoing data + +@param aData MBuf chain containing data to send +@return an indication of whether the upper layer should block. +*/ + { + RMBufPacket& pkt = static_cast(aData); + + pkt.Unpack(); + TInet6HeaderIP4* ip4 = (TInet6HeaderIP4*) pkt.First()->Ptr(); + __FLOG_STMT( LogPacketDetails(ip4, _L8("CLegacyLoopbackBinder4:\tSend(...): ")) ); + + if (ip4->Protocol() == KProtocolInetUdp || ip4->Protocol() == KProtocolInetTcp) + { + // get the "udp" header as well - cheating & relying upon UDP & TCP being in same place + TInet6HeaderUDP* udp = (TInet6HeaderUDP*) ip4->EndPtr(); + + // use the source or destination port number to decide whether or not to pass it through the loopback driver + // very weak this; dynamic ports could overlap. Really should do this for all packets and + // fix any impacted test code + TUint srcPort = udp->SrcPort(); + TUint dstPort = udp->DstPort(); + + if(dstPort >= KDriverReflectionRangeStartPort && dstPort <= KDriverReflectionRangeEndPort || + srcPort >= KDriverReflectionRangeStartPort && srcPort <= KDriverReflectionRangeEndPort) + { + if(!iLoopbackLoadAttempted) + { + iLoopbackLoadAttempted = ETrue; + TInt r = User::LoadPhysicalDevice(KLegacyLoopbackPddFileName); + RDebug::Printf("Loading PDD - %d\n", r); + if(r == KErrNone || r == KErrAlreadyExists) + { + r = User::LoadLogicalDevice(KLegacyLoopbackLddFileName); + RDebug::Printf("Loading LDD - %d\n", r); + if(r == KErrNone || r == KErrAlreadyExists) + { + r = iDrv.Open(); + RDebug::Printf("Opening driver - %d\n", r); + if(r == KErrNone) + { + // Prime the pathways + iDrvReceiver->Start(this, iDrv); + iDrvSender->Start(this, iDrv); + } + } + } + } + if(iDrv.Handle()) + { + // Swap the ports, because the receipt path also unconditionally swaps them (probably + // some test needs this + // ugh! should use a queue here when the write is still busy + udp->SetDstPort(srcPort); + udp->SetSrcPort(dstPort); + + __FLOG_4(_L("CLegacyLoopbackBinder4:\tSend(...): passing packet to driver as src %08x:%d, dst %08x:%d"), + ip4->SrcAddr(), dstPort, ip4->DstAddr(), srcPort); + + iDrvSender->QueueForSend(pkt); + return ESendAccepted; + } + } + else if(dstPort >= KBearerReflectionRangeStartPort && dstPort <= KBearerReflectionRangeEndPort || + srcPort >= KBearerReflectionRangeStartPort && srcPort <= KBearerReflectionRangeEndPort) + { + // Swap the ports, because the receipt path also unconditionally swaps them (probably + // some test needs this + udp->SetDstPort(srcPort); + udp->SetSrcPort(dstPort); + } + } + + // Loop the data straight back into the TCP/IP stack + pkt.Pack(); + ProcessPacket(aData); + return ESendAccepted; + } + + +MLowerDataSender* CLegacyLoopbackBinder4::Bind(MUpperDataReceiver& aUpperReceiver, MUpperControl& aUpperControl) +/** +Return the MLowerDataSender instance (CLegacyLoopbackBinder4) that we +previously allocated. +*/ + { + __FLOG_3(_L8("CLegacyLoopbackBinder4 %08x:\tBind(aUpperReceiver %08x, aUpperControl %08x)"), this, &aUpperReceiver, &aUpperControl); + iUpperReceiver = &aUpperReceiver; + iUpperControl = &aUpperControl; + + // Signal upper layer that we are ready + BinderReady(); + + return this; + } + +void CLegacyLoopbackBinder4::Unbind(MUpperDataReceiver& aUpperReceiver, MUpperControl& aUpperControl) +/** +Forget our association with upper layer. +*/ + { + static_cast(aUpperReceiver); + static_cast(aUpperControl); + __FLOG_1(_L8("CLegacyLoopbackBinder4 %08x:\tUnbind()"), this); + ASSERT(&aUpperReceiver == iUpperReceiver); + ASSERT(&aUpperControl == iUpperControl); + iUpperReceiver = NULL; + iUpperControl = NULL; + } + +void CLegacyLoopbackBinder4::BinderReady() +/** +Signal upper layer that we are ready +*/ + { + __FLOG_1(_L8("CLegacyLoopbackBinder4 %08x:\tBinderReady()"), this); + + iUpperControl->StartSending(); + } + +void CLegacyLoopbackBinder4::ProcessPacket(RMBufChain& aPdu) +/** +Process incoming data +*/ + { + // this received data has already been looped back... + // get the ip header from the RMBufChain + TInet6HeaderIP4* ip4 = (TInet6HeaderIP4*) aPdu.First()->Next()->Ptr(); + + if (ip4->Protocol() != KProtocolInetUdp && ip4->Protocol() != KProtocolInetTcp) + { + //Non UDP traffic goes here! + __FLOG_3(_L("CLegacyLoopbackBinder4 %08x:\tProcessPacket(): IPv4 length %d, protocol %d"), this, ip4->TotalLength(), ip4->Protocol()); + + UpdateHeaders(ip4, NULL); + // now process it (pass up the stack) + iUpperReceiver->Process(aPdu); + return; + } + + // get the udp header as well - assume only udp traffic here + __FLOG_STMT( LogPacketDetails(ip4, _L8("CLegacyLoopbackBinder4:\tProcessPacket(...): ")) ); + + TInet6HeaderUDP* udp = (TInet6HeaderUDP*) ip4->EndPtr(); + + // depending on the contents, pass it on up thru the stack + // or maybe do something else + + // use the destination port number to decide whether or not the payload is a command + TUint dstPort = udp->DstPort(); + if (KLegacyLoopbackCmdPort == dstPort) + { + // let's use the first payload byte as the command byte + switch (*(udp->EndPtr())) + { + case KForceDisconnect: + __FLOG(_L("KForceDisconnect command")); + // do some action + Flow()->Progress(KLinkLayerClosed, KErrCommsLineFail); + + Flow()->FlowDown(KErrCommsLineFail, MNifIfNotify::EDisconnect); + + // no return code so all we can do is respond with what we got + UpdateHeaders(ip4, udp); + iUpperReceiver->Process(aPdu); + break; + + case KForceReconnect: + __FLOG(_L("KForceReconnect command")); + // do some action + Flow()->Progress(KLinkLayerClosed, KErrCommsLineFail); + + Flow()->FlowDown(KErrCommsLineFail, MNifIfNotify::EReconnect); + + // no return code so all we can do is respond with what we got + UpdateHeaders(ip4, udp); + iUpperReceiver->Process(aPdu); + break; + + case KSendNotification: + __FLOG(_L("KSendNotification command")); + //let's write the result in the next byte of the reply + if (Flow()->AgentProvision()->IsDialIn() == KErrNotSupported) + udp->EndPtr()[1] = (unsigned char) KErrNone; + else + udp->EndPtr()[1] = (unsigned char) KErrGeneral; // this will lose it's sign :-( + + UpdateHeaders(ip4, udp); + iUpperReceiver->Process(aPdu); + break; + + case KForceFinishedSelection: + __FLOG(_L("KForceFinishedSelection command")); + // force subConn into KFinishedSelection State + Flow()->Progress(KFinishedSelection, KErrNone); + UpdateHeaders(ip4, udp); + aPdu.Free(); + break; + + case KForceBinderError: + __FLOG(_L("KForceBinderError command")); + // We cannot signal an error whilst in the middle of a send in the TCP/IP stack, + // as the act of signalling the error will eventually result in the CNifIfBase binder + // being destructed by the TCP/IP stack whilst we're in the middle of using it. + // Consequently, we would panic on exit from this routine. So make the call + // via an asynchronous callback. + if (!iErrorOneShot.IsActive()) + { + iErrorOneShot.Schedule(iUpperControl); + } + aPdu.Free(); + break; + + case KColourDataByLinkTierAccessPointId: + { + const TProviderInfoExt* providerInfo = static_cast( + iLegacyLoopbackSubConnectionFlow.AccessPointConfig().FindExtension( + STypeId::CreateSTypeId(TProviderInfoExt::EUid, TProviderInfoExt::ETypeId))); + ASSERT(providerInfo); // Should always be present + + // We are going to simply add the access point id to the command byte + // A test client can then validate that the socket is connected on the expected access point + __FLOG(_L("KColourDataByAccessPointId command")); + *(udp->EndPtr()) += static_cast(providerInfo->iProviderInfo.APId()); + + // Update the udp headers and forward on + UpdateHeaders(ip4, udp); + iUpperReceiver->Process(aPdu); + } + break; + + default: + __FLOG(_L("Unknown command - ignoring it")); + aPdu.Free(); + // unknown command, just ignore this packet??? + } + } + else + { + __FLOG(_L("Standard echo packet")); + if (iTestSubscriber && !iTestSubscriber->IsEnabled()) + { + __FLOG(_L("Bearer not available. Packet dropped.")); + aPdu.Free(); + return; + } + + // just echo the packet back to the original sender + // update the headers (addresses, checksums etc) + UpdateHeaders(ip4, udp); + // now process it (pass up the stack) + iUpperReceiver->Process(aPdu); + } + } + +TInt CLegacyLoopbackBinder4::GetConfig(TBinderConfig& aConfig) +/** +Return IPv4 configuration information. + +Called from upper layer. + +@param aConfig structure to populate with IPv4 configuration +*/ + { + TBinderConfig4* config = TBinderConfig::Cast(aConfig); + + if(config == NULL) + { + return KErrNotSupported; + } + + // Setup config + config->iInfo.iFeatures = KIfCanBroadcast | KIfCanMulticast; + config->iInfo.iMtu = KLoopbackBearerMTU; + config->iInfo.iRMtu = KLoopbackBearerMTU; + config->iInfo.iSpeedMetric = 0; + + config->iFamily = KAfInet6; + + TUint32 address; + const TInt KPort = 65; + + config->iFamily = KAfInet; + + __FLOG_2(_L8("CLegacyLoopbackBinder4 %08x:\tGetConfig(): iLocalAddress %08x"), this, iLocalAddress); + + config->iAddress.SetAddress(iLocalAddress); + config->iAddress.SetPort(KPort); + + // network mask + config->iNetMask.SetAddress(KInetAddrNetMaskC); // 255.255.255.0 + config->iNetMask.SetPort(KPort); + + // broadcast address + address = iLocalAddressBase + KBroadcastAddressSuffix; + config->iBrdAddr.SetAddress(address); + config->iBrdAddr.SetPort(KPort); + + // default gateway + address = iLocalAddressBase + KDefaultGatewayAddressSuffix; + config->iDefGate.SetAddress(address); + config->iDefGate.SetPort(KPort); + + // primary DNS, just make same as default gateway + config->iNameSer1.SetAddress(address); + config->iNameSer1.SetPort(KPort); + + // secondary DNS + address = iLocalAddressBase + KSecondaryDnsAddressSuffix; + config->iNameSer2.SetAddress(address); + config->iNameSer2.SetPort(KPort); + + return KErrNone; + } + +TInt CLegacyLoopbackBinder4::Control(TUint aLevel, TUint aName, TDes8& aOption) +/** +Called from upper layer for special control functionality. +*/ + { + (void) aLevel; + (void) aName; + (void) aOption; + __FLOG_3(_L("CLegacyLoopbackBinder4 %08x:\tControl(aLevel %x, aName %x)"), this, aLevel, aName); + return KErrNotSupported; + } + +TInt CLegacyLoopbackBinder4::GetName(TDes& aName) +/** +Called from upper layer to retrieve the binder name. + +@param aName populated with name +@return KErrNone on success, else a system wide error code. +*/ + { + // This name matches the NIF-based DummyNif to match any potential + // test code expectations on the name. + aName.Format(_L("legacy_loopback[0x%08x]"), this); + + __FLOG_2(_L("CLegacyLoopbackBinder4 %08x:\tGetName(): %S"), this, &aName); + + return KErrNone; + } + +TInt CLegacyLoopbackBinder4::BlockFlow(MLowerControl::TBlockOption /*aOption*/) + { + __FLOG_1(_L8("CLegacyLoopbackBinder4 %08x:\tBlockFlow()"), this); + + return KErrNotSupported; + } + +TBool CLegacyLoopbackBinder4::MatchesUpperControl(ESock::MUpperControl* aUpperControl) const +/** +Utility function that returns whether this binder is associated with the +MUpperControl object passed as argument. + +@param aUpperControl upper layer to match against +@return ETrue on a match else EFalse. +*/ + { + return aUpperControl == iUpperControl; + } + + +CLegacyLoopbackBinder4::CDrvSender::CDrvSender(TInt aPriority) +: CActive(aPriority) + { + CActiveScheduler::Add(this); + __FLOG_OPEN(KNif, KBinder4); + } + +CLegacyLoopbackBinder4::CDrvSender::~CDrvSender() + { + Cancel(); + do + { + iSendPkt.Free(); + } + while(iSendQueue.Remove(iSendPkt)); + __FLOG_CLOSE; + } + +void CLegacyLoopbackBinder4::CDrvSender::Start(CLegacyLoopbackBinder4* aBinder, RLegacyLoopbackDriver aDrv) + { + iBinder = aBinder; + iDrv = aDrv; + } + +void CLegacyLoopbackBinder4::CDrvSender::RunL() + { + // Finished with the buffer just sent + iSendPkt.Free(); + + // Send the next packet waiting + SendPacket(); + } + +void CLegacyLoopbackBinder4::CDrvSender::DoCancel() + { + iDrv.SendDataCancel(); + } + +void CLegacyLoopbackBinder4::CDrvSender::SendPacket() + { + // Fetch packet to send + TBool havePktToSend = iSendQueue.Remove(iSendPkt); + + if(havePktToSend) + { + RMBuf* sendBuffer = NULL; + + // If the packet is composed of more than one buffer then we log this and abandon the packet + if(iSendPkt.NumBufs() > 1) + { + __FLOG_VA((_L8("Warning: packet %d bytes %d buffers"), iSendPkt.Length(), iSendPkt.NumBufs() )); + iManyBufCount++; + + // Copy out to a single buffer + sendBuffer = RMBuf::Alloc(KLoopbackBearerMTU, iBinder->iAllocator); + if(sendBuffer) + { + sendBuffer->SetLength(0); + RMBuf* currentBuf = iSendPkt.First(); + while(currentBuf) + { + TPtr8 srcData(currentBuf->Ptr(), currentBuf->Length(), currentBuf->Length()); + sendBuffer->Append(srcData); + currentBuf = currentBuf->Next(); + } + } + iSendPkt.Free(); + RMBufChain sendChain(sendBuffer); + iSendPkt.Assign(sendChain); + } + else + { + iOneBufCount++; + sendBuffer = iSendPkt.First(); + } + + // Send the buffer + if(sendBuffer) + { + TInt length(sendBuffer->Length()); + TPtr8 txPtr(sendBuffer->Ptr(), length, length); + iDrv.SendData(iStatus, txPtr); + SetActive(); + } + } + } + +void CLegacyLoopbackBinder4::CDrvSender::QueueForSend(RMBufPacket& aPkt) + { + aPkt.FreeInfo(); + iSendQueue.Append(aPkt); + if(!IsActive()) + { + SendPacket(); + } + } + +CLegacyLoopbackBinder4::CDrvReceiver::CDrvReceiver(TInt aPriority) +: CActive(aPriority), + iRxPtr(NULL, 0) + { + CActiveScheduler::Add(this); + iPond = TCommsBufPondTLSOp::Get(); + } + +CLegacyLoopbackBinder4::CDrvReceiver::~CDrvReceiver() + { + Cancel(); + } + +void CLegacyLoopbackBinder4::CDrvReceiver::Start(CLegacyLoopbackBinder4* aBinder, RLegacyLoopbackDriver aDrv) + { + iBinder = aBinder; + iDrv = aDrv; + RequestReceipt(); + } + +void CLegacyLoopbackBinder4::CDrvReceiver::RequestReceipt() + { + ASSERT(iPkt.IsEmpty()); + RMBuf* buf = RMBuf::Alloc(RLegacyLoopbackDriver::KLoopbackMTU); + if(buf) + { + RMBufQ q(buf); + TRAPD(ret, iPkt.CreateL(q)); // need non-leaving overload! + if(ret == KErrNone) + { + iPkt.Pack(); + iRxPtr.Set(buf->Ptr(), 0, buf->Size()); + } + else + { + // In a real version we could still strive to use the buf, even without the header + // But someday we'll be free of having the packet info as the magic extra buffer + // on the front & instead pass a concrete type in tandem: type safety & an end to + // all this pushing & popping + buf->Free(); + buf = NULL; + } + } + if(!buf) + { + // No pre-built packet; copy through descriptor + iRxPtr.Set(iDesBuf.MidTPtr(0)); + } + + // Request the next received packet from the driver + iDrv.ReceiveData(iStatus, iRxPtr); + SetActive(); + } + +void CLegacyLoopbackBinder4::CDrvReceiver::RunL() + { + TInt ret; + if(iPkt.IsEmpty()) + { + TRAP(ret, iPkt.CreateL(iDesBuf)); // need non-leaving overload! + if(ret == KErrNone) + { + iPkt.Pack(); + } + } + else + { + ret = KErrNone; + } + if(ret == KErrNone) + { + iBinder->ProcessPacket(iPkt); + ASSERT(iPkt.IsEmpty()); + } + RequestReceipt(); + } + +void CLegacyLoopbackBinder4::CDrvReceiver::DoCancel() + { + iDrv.ReceiveDataCancel(); + } + + +// ================================================================================= +// +// CLegacyLoopbackBinder6 + +CLegacyLoopbackBinder6::CLegacyLoopbackBinder6(CLegacyLoopbackSubConnectionFlow& aLegacyLoopbackSubConnectionFlow) : iLegacyLoopbackSubConnectionFlow(aLegacyLoopbackSubConnectionFlow) + { + __FLOG_OPEN(KNif, KBinder6); + __FLOG_2(_L8("CLegacyLoopbackBinder6 %08x:\tCLegacyLoopbackBinder6(CLegacyLoopbackSubConnectionFlow& %08x)"), this, &aLegacyLoopbackSubConnectionFlow); + } + +CLegacyLoopbackBinder6::~CLegacyLoopbackBinder6() +/** +Destroys 'this' +*/ + { + __FLOG(_L8("CLegacyLoopbackBinder6:\t~CLegacyLoopbackBinder6()")); + __FLOG_CLOSE; + } + +CLegacyLoopbackBinder6* CLegacyLoopbackBinder6::NewL(CLegacyLoopbackSubConnectionFlow& aLegacyLoopbackSubConnectionFlow) + { + return new (ELeave) CLegacyLoopbackBinder6(aLegacyLoopbackSubConnectionFlow); + } + +void CLegacyLoopbackBinder6::UpdateHeaders(TInet6HeaderIP* aIp6, TInet6HeaderUDP* /*aUdp*/) + { + // swap over the destination and source addresses + TIp6Addr temp; + temp = aIp6->SrcAddr(); + aIp6->SetSrcAddr(aIp6->DstAddr()); + aIp6->SetDstAddr(temp); + } + +MLowerDataSender::TSendResult CLegacyLoopbackBinder6::Send(RMBufChain& aData) +/** +Send IPv6 data + +Note: not clear that this is properly supported or used. + +@param aData data to send +*/ + { + __FLOG(_L8("CLegacyLoopbackBinder6:\tSend()")); + + // Loop the data straight back into the TCP/IP stack + ProcessPacket(aData); + return ESendAccepted; + } + +MLowerDataSender* CLegacyLoopbackBinder6::Bind(MUpperDataReceiver& aUpperReceiver, MUpperControl& aUpperControl) + { + __FLOG_2(_L8("CLegacyLoopbackBinder6:\tBind(MUpperDataReceiver %08x, MUpperControl %08x)"), &aUpperReceiver, &aUpperControl); + + iUpperReceiver = &aUpperReceiver; + iUpperControl = &aUpperControl; + + // Signal upper layer that we are ready + BinderReady(); + + return this; + } + +void CLegacyLoopbackBinder6::BinderReady() +/** +Signal to upper layer that we are ready +*/ + { + __FLOG(_L8("CLegacyLoopbackBinder6:\tBinderReady()")); + + iUpperControl->StartSending(); + } + +void CLegacyLoopbackBinder6::ProcessPacket(RMBufChain& aPdu) +/** +Process incoming IPv6 packets. + +Note: not clear that this is properly supported or used. + +@param aPdu incoming data packet +*/ + { + __FLOG(_L8("CLegacyLoopbackBinder6:\tProcessPacket()")); + + // this received data has already been looped back... + // get the ip header from the RMBufChain + TInet6HeaderIP* ip6 = (TInet6HeaderIP*) aPdu.First()->Next()->Ptr(); + TInet6HeaderUDP* udp = NULL; + + if ((TUint)ip6->NextHeader() == KProtocolInetUdp) + { + // get the udp header as well - assume only udp traffic here + udp = (TInet6HeaderUDP*) ip6->EndPtr(); + + __FLOG_3(_L("CLegacyLoopbackBinder6:\tProcessPacket(...): UDP length %d, src port %d, dst port %d"), + udp->Length(), udp->SrcPort(), udp->DstPort()); + + // depending on the contents, pass it on up thru the stack + // or maybe do something else + + // use the destination port number to decide whether or not the payload is a command + TUint dstPort = udp->DstPort(); + if (KLegacyLoopbackCmdPort == dstPort) + { + // let's use the first payload byte as the command byte + switch (*(udp->EndPtr())) + { + case KForceDisconnect: + __FLOG(_L("KForceDisconnect command")); + // do some action + Flow()->Progress(KLinkLayerClosed, KErrCommsLineFail); + + Flow()->FlowDown(KErrCommsLineFail, MNifIfNotify::EDisconnect); + + // no return code so all we can do is respond with what we got + UpdateHeaders(ip6, udp); + iUpperReceiver->Process(aPdu); + break; + + case KForceReconnect: + __FLOG(_L("KForceReconnect command")); + // do some action + Flow()->Progress(KLinkLayerClosed, KErrCommsLineFail); + + //cause.iReserved=MNifIfNotify::EReconnect; + Flow()->FlowDown(KErrCommsLineFail); + + // no return code so all we can do is respond with what we got + UpdateHeaders(ip6, udp); + iUpperReceiver->Process(aPdu); + break; + + case KSendNotification: + __FLOG(_L("KSendNotification command")); + //let's write the result in the next byte of the reply + if (Flow()->AgentProvision()->IsDialIn() == KErrNotSupported) + udp->EndPtr()[1] = (unsigned char) KErrNone; + else + udp->EndPtr()[1] = (unsigned char) KErrGeneral; // this will lose it's sign :-( + + UpdateHeaders(ip6, udp); + iUpperReceiver->Process(aPdu); + break; + + + default: + __FLOG(_L("Unknown command - ignoring it")); + break; + // unknown command, just ignore this packet??? + } + return; + } + + } + else + { + __FLOG_2(_L("CLegacyLoopbackBinder6:\tProcessPacket(...): IPv6 length %d, next header %d"), + ip6->PayloadLength(), ip6->NextHeader()); + } + + // just echo the packet back to the original sender + + // update the headers (addresses, checksums etc). If "udp" is non-NULL, then + // the UDP ports will be updated as well. + UpdateHeaders(ip6, udp); + // now process it (pass up the stack) + iUpperReceiver->Process(aPdu); + } + +void CLegacyLoopbackBinder6::Unbind(MUpperDataReceiver& aUpperReceiver, MUpperControl& aUpperControl) + { + static_cast(aUpperReceiver); + static_cast(aUpperControl); + __FLOG(_L8("CLegacyLoopbackBinder6:\tUnbind()")); + + ASSERT(&aUpperReceiver == iUpperReceiver); + ASSERT(&aUpperControl == iUpperControl); + iUpperReceiver = NULL; + iUpperControl = NULL; + } + +TInt CLegacyLoopbackBinder6::GetName(TDes& aName) +/** +Called from upper layer to retrieve the binder name. + +@param aName populated with name +@return KErrNone on success, else a system wide error code. +*/ + { + __FLOG(_L8("CLegacyLoopbackBinder6:\tGetName()")); + + // This name matches the NIF-based DummyNif to match any potential + // test code expectations on the name. + aName.Format(_L("legacy_loopback6[0x%08x]"), this); + + return KErrNone; + } + +TInt CLegacyLoopbackBinder6::BlockFlow(MLowerControl::TBlockOption /*aOption*/) + { + __FLOG(_L8("CLegacyLoopbackBinder6:\tBlockFlow()")); + + return KErrNotSupported; + } + +void CLegacyLoopbackBinder6::StaticDnsConfiguration(TBinderConfig6& aConfig) + { + __FLOG(_L8("CLegacyLoopbackBinder6:\tStaticDnsConfiguration()")); + + const TLegacyLoopbackIp6Provision* ip6Provision = Flow()->Ip6Provision(); + + if (!ip6Provision->Ip6DNSAddrFromServer()) + { + aConfig.iNameSer1.SetAddress(ip6Provision->Ip6NameServer1()); + aConfig.iNameSer2.SetAddress(ip6Provision->Ip6NameServer2()); + } + else + { + // Ensure that static DNS addresses are set as unspecified, + // so they are not used in Control(KSoIfConfig). + aConfig.iNameSer1.SetAddress(KInet6AddrNone); + aConfig.iNameSer2.SetAddress(KInet6AddrNone); + } + } + +TInt CLegacyLoopbackBinder6::GetConfig(TBinderConfig& aConfig) +/** +Return IPv6 configuration information. + +Called from upper layer. + +@param aConfig structure to populate with IPv6 configuration +*/ + { + TBinderConfig6* config = TBinderConfig::Cast(aConfig); + + if(config == NULL) + { + return KErrNotSupported; + } + + // Setup config + config->iInfo.iFeatures = KIfCanBroadcast | KIfCanMulticast;; + config->iInfo.iMtu = KLoopbackBearerMTU; + config->iInfo.iRMtu = KLoopbackBearerMTU; + config->iInfo.iSpeedMetric = 0; + + // Setup addresses + + config->iFamily = KAfInet6; + + // Local ID + + TInt addr64 = 0x80; + TE64Addr localAddr(addr64); + TEui64Addr* id = (TEui64Addr*) &config->iLocalId; + + id->Init(); + id->SetAddress(localAddr); + + // Remote ID + addr64 = 0x81; + TE64Addr remoteAddr(addr64); + id = (TEui64Addr*) &config->iRemoteId; + + id->Init(); + id->SetAddress(remoteAddr); + + // Setup static DNS address if required + StaticDnsConfiguration(*config); + + return KErrNone; + } + +TInt CLegacyLoopbackBinder6::Control(TUint aLevel, TUint aName, TDes8& aOption) + { + (void) aLevel; + (void) aName; + (void) aOption; + __FLOG_2(_L("CLegacyLoopbackBinder6:\tControl(aLevel %x, aName %x, ...)"), aLevel, aName); + return KErrNotSupported; + } + +// +// Utilities +// + +TBool CLegacyLoopbackBinder6::MatchesUpperControl(ESock::MUpperControl* aUpperControl) const +/** +Utility function that returns whether this binder is associated with the +MUpperControl object passed as argument. + +@param aUpperControl upper layer to match against +@return ETrue on a match else EFalse. +*/ + { + return aUpperControl == iUpperControl; + } + +// +// Async error callback +// +// Used to schedule asynchronous signalling of a binder error to upper flow in circumstances +// where a direct call is not possible (e.g. in the middle of a TCP/IP send as the binder +// may disappear underneath the TCP/IP stack). + +CLegacyLoopbackErrorOneShot::CLegacyLoopbackErrorOneShot() + : CAsyncOneShot(EPriorityStandard) + { + } + +void CLegacyLoopbackErrorOneShot::Schedule(MUpperControl* aUpperControl) + { + iUpperControl = aUpperControl; + Call(); + } + +void CLegacyLoopbackErrorOneShot::RunL() + { + iUpperControl->Error(KErrCommsLineFail); + } + + +CLegacyLoopbackFlowTestingSubscriber::CLegacyLoopbackFlowTestingSubscriber(CLegacyLoopbackSubConnectionFlow& aFlow, TUint aApId) + : CActive(0), + iFlow(aFlow), + iApId(aApId) + { + } + +/*static*/ TBool CLegacyLoopbackFlowTestingSubscriber::ShouldRun(TUint aApId) + { + RProperty property; + TInt result = property.Attach(KLegacyLoopbackTestingPubSubUid, aApId); + if(result == KErrNone) + { + TInt propertyValue; + result = property.Get(propertyValue); + if(result == KErrNone) + { + return ETrue; + } + } + return EFalse; + } + +void CLegacyLoopbackFlowTestingSubscriber::ConstructL() + { + CActiveScheduler::Add(this); +// __DECLARE_NAME(_S("CAvailabilityTestingSubscriber")); + + TInt result = iProperty.Attach(KLegacyLoopbackTestingPubSubUid, iApId); + ASSERT(result == KErrNone); + + RunL(); + } + +void CLegacyLoopbackFlowTestingSubscriber::RunL() + { + // .. and repeat.. + iProperty.Subscribe(iStatus); + + TInt publishedValue; + TInt result = iProperty.Get(publishedValue); + ASSERT(result == KErrNone); + + TAvailabilityStatus av(publishedValue); + if (av.Score()) + { + iIsEnabled = ETrue; + iFlow.iDisableStart = EFalse; + } + else + { + iIsEnabled = EFalse; + iFlow.iDisableStart = ETrue; + } + + SetActive(); + } + +void CLegacyLoopbackFlowTestingSubscriber::DoCancel() + { + iProperty.Cancel(); + } + +/*virtual*/ CLegacyLoopbackFlowTestingSubscriber::~CLegacyLoopbackFlowTestingSubscriber() + { + this->Cancel(); // object must be stoppable by descruction due to cleanup restrictions + iProperty.Close(); + } + + +