networkcontrol/ipnetworklayer/src/flow.cpp
changeset 0 af10295192d8
child 6 c64cefac6e99
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkcontrol/ipnetworklayer/src/flow.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,971 @@
+// Copyright (c) 2005-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:
+// IP Shim Flow Base class.
+// This class is derived from by the separate IP4 and IP6 shim flow classes.
+// 
+//
+
+/**
+ @file flow.cpp
+*/
+
+#include <e32std.h>
+#include <e32test.h>
+#include <ecom/ecom.h>
+#include <ecom/implementationproxy.h>
+#include <comms-infras/ss_metaconnprov.h>
+#include <comms-infras/ss_subconnflow.h>
+#include "flow.h"
+#include "nif.h"
+#include "panic.h"
+#include "ItfInfoConfigExt.h"
+#include "IPProtoMessages.h"	// TCFIPProtoMessage
+#include "IPProtoCPR.h"
+#include "idletimer.h"
+#include <networking/ipaddrinfoparams.h>
+#include "IPProtoDeMux.h"
+#include <comms-infras/ss_log.h>
+#include <es_prot_internal.h>
+
+using namespace Messages;
+using namespace MeshMachine;
+using namespace ESock;
+using namespace IpProtoCpr;
+//
+// CIPShimSubConnectionFlow
+//
+
+CIPShimSubConnectionFlow::CIPShimSubConnectionFlow(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf)
+: CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf), iCleanupError(KErrUnknown),
+  iAsyncBinderClose(*this)
+	{
+	LOG_NODE_CREATE(KIPProtoTag1, CIPShimSubConnectionFlow);
+	}
+
+CIPShimSubConnectionFlow::~CIPShimSubConnectionFlow()
+	{
+	ASSERT(iBinderList.Count() == 0);
+    iConnectionInfo.Close();
+	// iIntf doesn't need to be deleted explicitly, as it will be deleted
+	// when the last Close() is issued on it (i.e. either by us or by the TCP/IP
+	// stack).  At the time of writing, our call to Close() is the last one and
+	// will delete it.
+	LOG_NODE_DESTROY(KIPProtoTag1, CIPShimSubConnectionFlow);
+	}
+
+MFlowBinderControl* CIPShimSubConnectionFlow::DoGetBinderControlL()
+	{
+	return this;
+	}
+
+
+void CIPShimSubConnectionFlow::InitialiseDataMonitoringL(CIPShimIfBase* intf)
+	{
+	const TPacketActivity* packetActivity =
+		static_cast<const TPacketActivity*>(AccessPointConfig().FindExtension(TPacketActivity::TypeId()));
+	if (packetActivity)
+		{
+		intf->ShimNotify()->SetPacketActivityFlag(packetActivity->iPacketActivity);
+		}
+	else
+		{
+		__CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("Packet activity provisioning information missing")));
+    	User::Leave(KErrNotReady);
+		}
+
+	const TDataMonitoringConnProvisioningInfo* connProvisioningInfo =
+		static_cast<const TDataMonitoringConnProvisioningInfo*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TDataMonitoringConnProvisioningInfo::iUid, TDataMonitoringConnProvisioningInfo::iId)));
+
+	const TDataMonitoringSubConnProvisioningInfo* subConnProvisioningInfo =
+		static_cast<const TDataMonitoringSubConnProvisioningInfo*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(TDataMonitoringSubConnProvisioningInfo::iUid, TDataMonitoringSubConnProvisioningInfo::iId)));
+
+    if(connProvisioningInfo && subConnProvisioningInfo)
+    	{
+		intf->ShimNotify()->SetDataVolumePtrs(connProvisioningInfo->iDataVolumesPtr, subConnProvisioningInfo->iDataVolumesPtr);
+		intf->ShimNotify()->SetNotificationThresholdPtrs(connProvisioningInfo->iThresholdsPtr, subConnProvisioningInfo->iThresholdsPtr);
+    	}
+    else
+    	{
+		__CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("Data monitoring provisioning information missing")));
+    	User::Leave(KErrNotReady);
+    	}
+	}
+
+
+// ============================================================================
+//
+// from Messages::ANode
+
+void CIPShimSubConnectionFlow::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
+/**
+Receive function for incoming messages from SCPR.
+
+@param aCFMessage message from SCPR
+*/
+    {
+	CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage);
+	if(aMessage.IsMessage<TEBase::TCancel>())
+		{
+		if (iStarting )
+			{
+			StopFlow(KErrCancel);
+			}
+		}
+	else if(aMessage.IsMessage<TEChild::TDestroy>())
+		{
+		Destroy();
+		}
+	else if(aMessage.IsMessage<TCFDataClient::TBindTo>())
+		{
+		TCFDataClient::TBindTo& msg = message_cast<TCFDataClient::TBindTo>(aMessage);
+		BindToL(msg.iNodeId);
+		ASSERT(iSubConnectionProvider == aSender);
+		iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TBindToComplete().CRef());
+		}
+	else if(aMessage.IsMessage<TCFDataClient::TStart>())
+		{
+		StartFlowL();
+		}
+	else if(aMessage.IsMessage<TCFDataClient::TStop>())
+		{
+		StopFlow(static_cast<TCFDataClient::TStop&>(aMessage).iValue);
+		}
+	else if(aMessage.IsMessage<TCFDataClient::TProvisionConfig>())
+		{
+		iAccessPointConfig.Close();		
+		iAccessPointConfig.Open(static_cast<TCFDataClient::TProvisionConfig&>(aMessage).iConfig);
+		ProcessProvisionConfigL();
+		}
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+	else if(aMessage.IsMessage<TCFScpr::TSetParamsRequest>())
+		{
+		UpdateIpAddressInfoL(static_cast<TCFScpr::TSetParamsRequest&>(aMessage));
+		}
+#else
+	else if(aMessage.IsMessage<TCFScpr::TParamsRequest>())
+		{
+		UpdateIpAddressInfoL(static_cast<TCFScpr::TParamsRequest&>(aMessage));
+		}
+#endif // SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+	else
+		{
+		Panic(EUnexpectedSubConnectionMsg);
+		}
+    }
+
+
+//
+// Dispatch functions for messages from SCPR
+//
+
+__CFLOG_STMT
+(
+void LOG_ADDRESS(TSockAddr addr)
+	{
+	TBuf<KMaxSockAddrSize> buff;
+	TInetAddr iaddr(addr);
+	iaddr.Output(buff);
+
+	__CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L("CIPShimSubConnectionFlow::UpdateIpAddressInfoL %S %d"), &buff, addr.Port()));
+	}
+)
+
+//helper function
+CIPProtoBinder * FindBinderForProtocol(const TDesC8& proto, RPointerArray<CIPProtoBinder> &array)
+	{
+	TInt count= array.Count();
+	for (TInt i = 0; i < count; i++)
+		{
+		if (array[i]->ProtocolName().Compare(proto) == 0)
+			{
+			return array[i];
+			}
+		}
+	return 0;
+	}
+
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+void CIPShimSubConnectionFlow::UpdateIpAddressInfoL(TCFScpr::TSetParamsRequest& aParamReq)
+#else
+void CIPShimSubConnectionFlow::UpdateIpAddressInfoL(TCFScpr::TParamsRequest& aParamReq)
+#endif // SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+	{
+
+	//[401TODO] DL: deal with the granted also.
+	const RCFParameterFamilyBundleC& newParamBundle = aParamReq.iFamilyBundle;
+
+	CSubConIPAddressInfoParamSet* IPAddressInfoSet;
+	RParameterFamily family = newParamBundle.FindFamily(KSubConIPAddressInfoFamily);
+	if ( family.IsNull() )
+		{
+		 IPAddressInfoSet = NULL;
+		}
+    else
+    	{
+    	 IPAddressInfoSet = static_cast<CSubConIPAddressInfoParamSet*>
+		 	(family.FindParameterSet(
+		 			STypeId::CreateSTypeId(CSubConIPAddressInfoParamSet::EUid,
+				 		CSubConIPAddressInfoParamSet::ETypeId)
+						 ,RParameterFamily::ERequested));
+		}
+
+	if (IPAddressInfoSet)
+        {
+		TUint aParamSetNum = IPAddressInfoSet->GetParamNum();
+		/** TODO: It should be only one in the queue, so remove the loop */
+		for (TUint i=0; i<aParamSetNum; ++i)
+			{
+
+			CSubConIPAddressInfoParamSet::TSubConIPAddressInfo paramInfo(IPAddressInfoSet->GetParamInfoL(i));
+
+			//The only protocol we are going to deal with is TCP/IP
+			//as the flow association gets lost in when it goes through the current stack.
+			if (paramInfo.iCliDstAddr.Family() == KAfInet6 ||
+				paramInfo.iCliDstAddr.Family() == KAfInet)
+				{
+				__CFLOG_STMT(LOG_ADDRESS(paramInfo.iCliDstAddr);)
+				__CFLOG_STMT(LOG_ADDRESS(paramInfo.iCliSrcAddr);)
+
+				TInetAddr addr(paramInfo.iCliDstAddr);
+				TUint32 ipv4Addr = addr.Address();
+
+				if (iBinderList.Count())
+					{
+					CIPShimIfBase* nif = iBinderList[0]->iNif;
+					ASSERT(nif);
+					CIPProtoBinder *binder = 0;
+					if(ipv4Addr)
+						{
+						//find ip4 binder
+						binder = FindBinderForProtocol(KProtocolIp, iBinderList);
+						}
+					else
+						{
+						//find ip6 binder
+						binder = FindBinderForProtocol(KProtocolIp6, iBinderList);
+						}
+
+					if (IPAddressInfoSet->GetOperationCode() == CSubConIPAddressInfoParamSet::EDelete)
+						{
+						nif->RemoveIpAddrInfo(binder, paramInfo);
+						}
+					else
+						{
+						nif->AddIpAddrInfoL(binder, paramInfo);
+						}
+					}
+				}
+			}
+        }
+	}
+
+
+class TCleanupNifPair {
+public:
+	TCleanupNifPair(CIPShimIfBase* aNif) : iNif(aNif), iBinder(NULL) {}
+
+	void Cleanup();
+	static void CleanupReleaseNif(TAny* aThis);
+
+	CIPShimIfBase* iNif;
+	CIPProtoBinder* iBinder;
+	};
+
+void TCleanupNifPair::Cleanup()
+	{
+	ASSERT(iNif);
+
+	if (iBinder)
+		{
+		iNif->UnbindFrom(iBinder);
+		iBinder->UnbindFromLowerFlow();
+		}
+	iNif->Release(KErrAbort);
+	}
+
+void TCleanupNifPair::CleanupReleaseNif(TAny* aThis)
+	{
+	TCleanupNifPair* pair = static_cast<TCleanupNifPair*>(aThis);
+	pair->Cleanup();
+	}
+
+void CIPShimSubConnectionFlow::BindToL(const Messages::TNodeId& aCommsBinder)
+	{
+	// Assumption that TCommsBinder object contains pointer to Flow
+    if (aCommsBinder.IsNull())
+     	{
+     	User::Leave(KErrNotSupported);
+     	}
+
+	ANode& mcfNode = aCommsBinder.Node();
+#if !defined(__GCCXML__)
+	CSubConnectionFlowBase& flow = mcfnode_cast<CSubConnectionFlowBase>(mcfNode);
+#else
+	CSubConnectionFlowBase& flow = reinterpret_cast<CSubConnectionFlowBase&>(mcfNode);
+#endif
+
+	__CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimSubConnectionFlow %08x:\tBindToL(): flow 0x%08x, protocol list '%S'"),
+ 				this, &flow, &iProtocolList));
+
+	MFlowBinderControl* binderControl = flow.GetBinderControlL();
+	ASSERT(binderControl);
+
+	// Loop through all the protocols in the list and create binders for them
+	TPtrC8 protoList(iProtocolList);
+	TPtrC8 proto;
+	TInt pos = KErrNotFound;
+
+	do
+		{
+		pos = protoList.LocateF(',');
+		if (pos == KErrNotFound)
+			{
+			proto.Set(protoList);
+			}
+		else
+			{
+			proto.Set(protoList.Left(pos));
+			protoList.Set(protoList.Mid(pos + 1));
+			}
+
+		if (proto.Length() > 0)
+			{
+			CIPProtoBinder* protoBinder = CIPProtoBinder::NewL(*this, proto);
+			CleanupStack::PushL(protoBinder);
+
+			CIPShimIfBase* nif = ProtocolIntf()->FindOrCreateNifL(proto,
+				reinterpret_cast<const TConnectionInfo&>(*iConnectionInfo.Ptr()));
+			TCleanupNifPair cleanuppair(nif);
+			CleanupStack::PushL(TCleanupItem(TCleanupNifPair::CleanupReleaseNif, &cleanuppair));
+
+			__CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimSubConnectionFlow %08x:\tBindToL(): nif 0x%08x, binder 0x%08x"), this, nif, protoBinder));
+			nif->BindToL(protoBinder);
+			cleanuppair.iBinder = protoBinder;
+
+			protoBinder->BindToLowerFlowL(*binderControl);
+
+			iBinderList.AppendL(protoBinder);
+
+			CleanupStack::Pop(2);
+
+			InitialiseDataMonitoringL(nif);
+			}
+		}
+	while (pos != KErrNotFound);
+
+	NM_LOG((KIPProtoTag1, _L8("CIPShimSubConnectionFlow %08x:\tSynchronous call: From=%08x To=%08x Func=BindToL"), this, static_cast<Messages::ANode*>(this), &mcfNode));
+
+	TInt binderCount = iBinderList.Count();
+	for (TInt i = 0; i < binderCount; i++)
+		{
+		iBinderList[i]->StartL();
+		}
+	}
+
+
+
+void CIPShimSubConnectionFlow::StartFlowL()
+/**
+Message from SCPR to start.
+*/
+	{
+	ASSERT(!iStarting);
+
+	iStarting = ETrue;
+
+	PostDataClientStartedIfReady();
+	}
+
+void CIPShimSubConnectionFlow::StopFlow(TInt aError)
+/**
+Message from SCPR to stop.
+
+The aError reason code is stored to be passed to the TCP/IP stack via IfUserInterfaceDown().
+
+@param aError Reason code.
+*/
+	{
+	ASSERT(aError != KErrNone);
+	iStopCode = aError;
+
+	for(TInt i =0; i < iBinderList.Count(); i++)
+		{
+		MarkBinderForClosure(iBinderList[i]);
+		}
+	CloseMarkedBinders();
+
+	PostDataClientStoppedIfReady();
+	}
+
+
+
+void CIPShimSubConnectionFlow::ProcessProvisionConfigL()
+/**
+Message from SCPR providing configuration information.
+*/
+	{
+    const TItfInfoConfigExt* ext = static_cast<const TItfInfoConfigExt*>(AccessPointConfig().FindExtension(
+    		STypeId::CreateSTypeId(KIpProtoConfigExtUid, EItfInfoConfigExt)));
+    if (ext)
+        {
+        TInt err = SetConnectionInfo(ext->iConnectionInfo);
+		if (err == KErrNone)
+			{
+			err = SetProtocolList(ext->iProtocolList);
+			}
+        if (err != KErrNone)
+            {
+    	    User::Leave(err);
+            }
+	    }
+	}
+
+
+
+TInt CIPShimSubConnectionFlow::SetProtocolList(const TDesC8& aProtocolList)
+/**
+Save a pointer to the protocol list string in the provisioning information
+*/
+	{
+	if (aProtocolList.Length() > 0)
+		{
+		iProtocolList.Set(aProtocolList);
+		return KErrNone;
+		}
+	else
+		{
+		return KErrArgument;
+		}
+	}
+
+void CIPShimSubConnectionFlow::Destroy()
+/**
+Message from SCPR to self destruct.
+*/
+	{
+	// No-one should be bound to us from above if we are about to disappear.
+	ASSERT(iBindCallCount == 0);
+
+	MarkAllBindersForClosure();
+
+	if (iAsyncBinderClose.IsActive())
+		{
+		// Can't destroy ourselves whilst an asynchronous binder close is pending.
+		// Arrange for it to close all binders and initiate the destroy.
+		//
+		// Note that the async binder close may have been originally invoked with
+		// just a single binder marked for closure, and we are now marking them all
+		// for closure and requesting a destroy.  This is the main reason for using
+		// the "marked for closure" flag - to deal with events that require further
+		// binders to be closed whilst the async binder close is still pending.
+		iDestroyPending = ETrue;
+		}
+	else
+		{
+		// No async binder close pending - close binders and destroy ourselves here.
+		CloseMarkedBinders();
+		DeleteThisFlow();
+		}
+	}
+
+//
+// Utility functions for sending messages to SCPR
+//
+
+void CIPShimSubConnectionFlow::PostDataClientStartedIfReady()
+	{
+	if (iBinderReady && iStarting)
+    	{
+    	iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStarted().CRef());
+    	iStarting = EFalse;
+    	iStarted = ETrue;
+    	}
+	}
+
+void CIPShimSubConnectionFlow::PostDataClientStoppedIfReady()
+	{
+	if (iStopCode != KErrNone)
+    	{
+    	iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStopped(iStopCode).CRef());
+    	iStopCode = KErrNone;
+    	iStarted = EFalse;
+
+		MarkAllBindersForClosure();
+
+		if (!iAsyncBinderClose.IsActive())
+			{
+			// No async binder close pending - close binders
+			CloseMarkedBinders();
+			}
+       	}
+	}
+
+void CIPShimSubConnectionFlow::Error(TInt aError)
+	{
+    ASSERT(iStarted || iStarting);
+    ASSERT(iSubConnectionProvider.IsOpen());
+    if (iStarting)
+        {
+        iSubConnectionProvider.PostMessage(Id(), TEBase::TError(TCFDataClient::TStart::Id(), aError).CRef());
+        }
+    else
+        {
+        iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError, MNifIfNotify::EDisconnect).CRef());
+        }
+
+    iStopCode = aError;
+    iStarting = EFalse;
+    }
+
+MLowerControl* CIPShimSubConnectionFlow::GetControlL(const TDesC8& aProtocol)
+    {
+    if (aProtocol.Length())
+        {
+        User::Leave(KErrNotSupported);
+        }
+    return this;
+    }
+
+MLowerDataSender* CIPShimSubConnectionFlow::BindL(const TDesC8& /*aProtocol*/, MUpperDataReceiver* /*aReceiver*/, MUpperControl* /*aControl*/)
+    {
+    iBindCallCount++;
+    if (iBindCallCount == 1)
+    	{
+	    iSubConnectionProvider.RNodeInterface::PostMessage(Id(), TCFControlProvider::TActive().CRef());
+    	}
+    return NULL;
+    }
+
+void CIPShimSubConnectionFlow::Unbind( MUpperDataReceiver* /*aReceiver*/, MUpperControl* /*aControl*/)
+    {
+    iBindCallCount--;
+    if (iBindCallCount <= 0)
+    	{
+    	ASSERT(iBindCallCount == 0);
+	    PostClientIdleIfIdle();
+    	}
+    }
+
+CSubConnectionFlowBase* CIPShimSubConnectionFlow::Flow()
+    {
+    return this;
+    }
+
+void CIPShimSubConnectionFlow::OpenRoute()
+	{
+	// Post directly to cpr bypassing the scpr purely for efficiency
+	__CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimSubConnectionFlow %08x:\tOpenRoute()"), this);
+
+	RClientInterface::OpenPostMessageClose(Id(), TNodeCtxId(ECFActivityOpenCloseRoute, iProtocolIntf->ControlProviderId()),
+		TCFIPProtoMessage::TOpenCloseRoute(ETrue).CRef());
+	}
+
+
+void CIPShimSubConnectionFlow::CloseRoute()
+	{
+	// Post directly to cpr bypassing the scpr purely for efficiency
+	__CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimSubConnectionFlow %08x:\tCloseRoute()"), this);
+
+	RClientInterface::OpenPostMessageClose(Id(), TNodeCtxId(ECFActivityOpenCloseRoute, iProtocolIntf->ControlProviderId()),
+		TCFIPProtoMessage::TOpenCloseRoute(EFalse).CRef());
+	}
+
+void CIPShimSubConnectionFlow::PostClientIdleIfIdle()
+    {
+    if (iBindCallCount == 0)
+        {
+        iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
+        }
+    }
+
+
+TInt CIPShimSubConnectionFlow::Control(TUint aLevel, TUint aName, TDes8& aOption)
+    {
+    TInt err = KErrNotSupported;
+    
+    //It returns interface info alias TConnectionInfo in a form of an old fashioned descriptor
+    //for SetOption
+    if (aLevel == (TUint)KSOLProvider && aName == (TUint)KSoConnectionInfo)
+        {
+	    // Get the connection info from the config if it has not been stored yet in case the
+	    // CTransportFlowShim locks the connection info for a host resolver and calls StartSending()
+	    // on the host resolver before CIPShimSubConnectionFlow::ProcessProvisionConfigL() is called.
+	    // Otherwise, if ProcessProvisionConfigL() is not called in time the CTransportFlowShim will
+	    // lock to empty connection info.  ProcessProvisionConfigL() is called when the
+	    // CIPShimSubConnectionFlow receives the request to bind to the bearer SCPR which is not
+	    // synchronised in any way with the request to bind the CIPShimSubConnectionFlow to the
+	    // CTransportFlowShim which triggers the call to StartSending().  We still return
+	    // KErrNotReady when we are not bound so that a socket does not try to flow on too early
+	    // (this was causing failures in te_spudnetworkside).  A host resolver does not check the
+	    // error code when calling KSoConnectionInfo and simply uses the info if it's there anyway.
+	    //
+	    // See DEF128574.
+	   	if(iConnectionInfo.Length() == 0)
+	   		{
+			const TItfInfoConfigExt* ext = static_cast<const TItfInfoConfigExt*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(KIpProtoConfigExtUid, EItfInfoConfigExt)));
+			if (ext)
+			    {
+				aOption.Copy((const TUint8*)&ext->iConnectionInfo, sizeof(TConnectionInfo));
+		   		err = KErrNotReady;
+			    }
+	   		}
+	   	else
+	   		{
+	        if(iConnectionInfo.Length() == 0)
+	        	{
+	        	err = KErrNotReady;
+	        	}
+	        else
+	        	{
+		        aOption.Copy(iConnectionInfo);
+		   		err = KErrNone;
+	        	}
+	   		}
+        }
+    
+    return err;
+    }
+
+TInt CIPShimSubConnectionFlow::SetConnectionInfo(const TConnectionInfo& aInfo)
+	{
+	iConnectionInfo.Close();
+	TInt ret = iConnectionInfo.Create(sizeof(TConnectionInfo));
+	if (ret == KErrNone)
+	    {
+    	iConnectionInfo.Copy((TUint8*)&aInfo, sizeof(TConnectionInfo));
+	    }
+	return ret;
+	}
+
+void CIPShimSubConnectionFlow::BinderReady()
+/**
+Called from binder to indicate that it is ready.
+*/
+	{
+	iBinderReady = ETrue;
+	PostDataClientStartedIfReady();
+	}
+
+/**
+Called from lower binder to indicate an error that renders the binder unusable
+
+Ensure that the TCP/IP stack is notified and the binder closed down.
+
+@param aError error code
+@param aIf CIPShimIfBase object associated with the binder
+*/
+#ifdef _DEBUG
+void CIPShimSubConnectionFlow::BinderError(TInt aError, CIPProtoBinder* aBinder)
+#else
+void CIPShimSubConnectionFlow::BinderError(TInt /*aError*/, CIPProtoBinder* aBinder)
+#endif
+	{
+	__CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimSubConnectionFlow %08x:\tBinderError(%d)"), this, aError));
+
+	// NOTE:
+	// - We are currently in the stack frame of the lower binder as it makes the Error() upcall.
+	// - Calling CloseBinder() directly here will result in a recursive Unbind() and destructor
+	//   downcall back into the binder.  Consequently, schedule asynchronous closure of the binder
+	//   to ensure that the binder does not have the burden of dealing with this recursion.
+	// - Note that CloseBinder() will also Close() the CIPShimIfBase, which may cause it to be destructed
+	//   (if all other references on it are gone, in particular the TCP/IP stack)
+	MarkBinderForClosure(aBinder);
+	if (!iAsyncBinderClose.IsActive())
+		{
+		iAsyncBinderClose.Call();
+		}
+	}
+
+
+void CIPShimSubConnectionFlow::SendMessageToSubConnProvider(const Messages::TSignatureBase& aCFMessage)
+    {
+    iSubConnectionProvider.PostMessage(Id(), aCFMessage);
+    }
+
+const Messages::TNodeId& CIPShimSubConnectionFlow::GetCommsId()
+    {
+    return NodeId();
+    }
+
+
+// MIpDataMonitoringNotifications
+
+void CIPShimSubConnectionFlow::PostConnDataReceivedThresholdReached(TUint aVolume)
+	{
+	RClientInterface::OpenPostMessageClose(Id(), iProtocolIntf->ControlProviderId(),
+		TCFDataMonitoringNotification::TDataMonitoringNotification(EReceived, aVolume).CRef());
+	}
+
+void CIPShimSubConnectionFlow::PostConnDataSentThresholdReached(TUint aVolume)
+	{
+	RClientInterface::OpenPostMessageClose(Id(), iProtocolIntf->ControlProviderId(),
+		TCFDataMonitoringNotification::TDataMonitoringNotification(ESent, aVolume).CRef());
+	}
+
+void CIPShimSubConnectionFlow::PostSubConnDataReceivedThresholdReached(TUint aVolume)
+	{
+	iSubConnectionProvider.PostMessage(Id(),
+		TCFDataMonitoringNotification::TDataMonitoringNotification(EReceived, aVolume).CRef());
+	}
+
+void CIPShimSubConnectionFlow::PostSubConnDataSentThresholdReached(TUint aVolume)
+	{
+	iSubConnectionProvider.PostMessage(Id(),
+		TCFDataMonitoringNotification::TDataMonitoringNotification(ESent, aVolume).CRef());
+	}
+
+//
+// Asynchronous Binder Close routines
+//
+// Class used to asynchronously unbind/destroy a binder from outside of the binder's call stack.
+//
+
+CAsyncBinderClose::CAsyncBinderClose(CIPShimSubConnectionFlow& aFlow)
+  : CAsyncOneShot(EPriorityStandard), iFlow(aFlow)
+  	{
+  	}
+
+void CAsyncBinderClose::RunL()
+	{
+	iFlow.AsyncBinderClose();
+	}
+
+void CIPShimSubConnectionFlow::AsyncBinderClose()
+/**
+Main method of asynchronous binder close callback.
+*/
+	{
+	CloseMarkedBinders();
+	if (iDestroyPending)
+		{
+		// Deal with a pending Destroy() that happened whilst the asynchronous binder close was pending.
+		iDestroyPending = EFalse;
+		DeleteThisFlow();
+		}
+	}
+
+void CIPShimSubConnectionFlow::MarkAllBindersForClosure()
+/**
+Mark all binders for closure in the asynchronous binder close callback
+*/
+	{
+	for (TInt index = 0 ; index < iBinderList.Count() ; ++index)
+		{
+		MarkBinderForClosure(iBinderList[index]);
+		}
+	}
+
+void CIPShimSubConnectionFlow::MarkBinderForClosure(CIPProtoBinder* aBinder)
+	{
+	__CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimSubConnectionFlow %08x:\tMarkBinderForClosure(%08x)"), this, aBinder));
+	aBinder->iMarkedForClosure = ETrue;
+	}
+
+void CIPShimSubConnectionFlow::CloseMarkedBinders()
+	{
+	TInt count = iBinderList.Count();
+	TBool reset = count > 0 ? ETrue : EFalse;
+	for (TInt index = count -1  ; index >= 0; --index)
+		{
+		CIPProtoBinder* binder = iBinderList[index];
+		if (binder->iMarkedForClosure)
+			{
+			CIPShimIfBase *nif = binder->iNif;
+			if (nif) // nif may have unbound itself
+				{
+				nif->RemoveIpAddrInfo(binder);
+				// The removal of interface name has to be extracted from Release() and
+				// performed before UnbindFrom() as otherwise Release() would have no CIPProtoBinders
+				// to navigate up to the Flow, which is required to remove the interface name.
+				nif->RemoveInterfaceName(binder);
+				nif->UnbindFrom(binder);
+				nif->Release(iStopCode);
+				}
+			binder->UnbindFromLowerFlow();
+
+			iBinderList.Remove(index);
+			delete binder;
+			}
+		else
+			{
+			reset = EFalse;
+			}
+		}
+
+	if (reset)
+		{
+		// If we've closed all binders in the list, and the list is non-empty, then reset it.
+		iBinderList.Reset();
+		}
+	}
+
+// Utility functions
+
+GLDEF_C void Panic(TIPShimPanic aReason)
+	{
+	_LIT(KPanicCategory, "IPShim");
+
+	User::Panic(KPanicCategory(), aReason);
+	}
+
+// =================================================================================
+//
+// Flow Factory methods
+//
+
+CIPShimFlowFactory* CIPShimFlowFactory::NewL(TAny* aConstructionParameters)
+/**
+Constructs a Default SubConnection Flow Factory
+
+@param aConstructionParameters construction data passed by ECOM
+
+@returns pointer to a constructed factory
+*/
+	{
+	CIPShimFlowFactory* ptr = new (ELeave) CIPShimFlowFactory(TUid::Uid(KIPShimFlowImplUid), *(reinterpret_cast<CSubConnectionFlowFactoryContainer*>(aConstructionParameters)));
+	return ptr;
+	}
+
+CIPShimFlowFactory::~CIPShimFlowFactory()
+	{
+	}
+
+
+CIPShimFlowFactory::CIPShimFlowFactory(TUid aFactoryId, CSubConnectionFlowFactoryContainer& aParentContainer)
+	: CSubConnectionFlowFactoryBase(aFactoryId, aParentContainer)
+/**
+Default SubConnection Flow Factory Constructor
+
+@param aFactoryId ECOM Implementation Id
+@param aParentContainer Object Owner
+*/
+	{
+	}
+
+
+CSubConnectionFlowBase* CIPShimFlowFactory::DoCreateFlowL(ESock::CProtocolIntfBase* aProtocolIntf, TFactoryQueryBase& aQuery)
+	{
+	const TDefaultFlowFactoryQuery& query = static_cast<const TDefaultFlowFactoryQuery&>(aQuery);
+	return new (ELeave) CIPShimSubConnectionFlow(*this, query.iSCprId, aProtocolIntf);
+	}
+
+CProtocolIntfFactoryBase* CIPShimFlowFactory::CreateProtocolIntfFactoryL(CProtocolIntfFactoryContainer& aParentContainer)
+	{
+	CProtocolIntfFactoryBase* factory = CIPShimProtocolIntfFactory::NewL(TUid::Uid(KIPShimFlowImplUid),
+																		 aParentContainer);
+    return factory;
+	}
+
+CIPShimProtocolIntf::CIPShimProtocolIntf(CProtocolIntfFactoryBase& aFactory,const Messages::TNodeId& aCprId)
+	:CProtocolIntfBase(aFactory,aCprId)
+	{
+	}
+
+CIPShimProtocolIntf::~CIPShimProtocolIntf()
+	{
+	// if there is still a nif open, then one of the ipshimflows
+	// is not being cleaned up correctly
+	ASSERT(iNifs.Count() == 0);
+	iNifs.Close();
+	}
+
+void CIPShimProtocolIntf::DoFlowCreated(ESock::CSubConnectionFlowBase& /*aFlow*/)
+	{
+	// do nothing
+	}
+
+void CIPShimProtocolIntf::DoFlowBeingDeleted(ESock::CSubConnectionFlowBase& /*aFlow*/)
+	{
+	// do nothing
+	}
+
+CIPShimIfBase* CIPShimProtocolIntf::FindOrCreateNifL(const TDesC8& aProtocol, const TConnectionInfo& aConnectionInfo)
+	{
+	CIPShimIfBase* shim = NULL;
+
+	for (TInt i = 0; i < iNifs.Count(); i++)
+		{
+		if (iNifs[i]->ProtocolName().Compare(aProtocol) == 0)
+			{
+			shim = iNifs[i];
+			break;
+			}
+		}
+	if (shim == NULL)
+		{
+		shim = CIPShimIfBase::NewL(aProtocol, this);
+		
+		CleanupStack::PushL(shim);
+		iNifs.AppendL(shim);
+		CleanupStack::Pop(shim);
+		
+		shim->SetConnectionInfo(aConnectionInfo);
+		}
+
+	return shim;
+	}
+
+void CIPShimProtocolIntf::NifDisappearing(CIPShimIfBase* aNif)
+	{
+	TInt index = iNifs.Find(aNif);
+	// index can be KErrNotFound if there was an OOM whilst trying to append a CIPShimIfBase to iNifs.
+	ASSERT(index >= KErrNotFound);
+	if (index >= 0)
+		{
+		iNifs.Remove(index);
+		}
+	}
+
+//TNodeCtxId(ECFActivityOpenCloseRoute, ControlProviderId())
+void CIPShimProtocolIntf::OpenRoute()
+	{
+		// Post directly to cpr bypassing the scpr purely for efficiency
+	__CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimProtocolIntf %08x:\tOpenRoute()"), this);
+
+	RClientInterface::OpenPostMessageClose(ControlProviderId(), ControlProviderId(),
+		TCFIPProtoMessage::TOpenCloseRoute(ETrue).CRef());
+	}
+
+//TNodeCtxId(ECFActivityOpenCloseRoute, ControlProviderId())
+void CIPShimProtocolIntf::CloseRoute()
+	{
+	// Post directly to cpr bypassing the scpr purely for efficiency
+	__CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimProtocolIntf %08x:\tCloseRoute()"), this);
+
+	RClientInterface::OpenPostMessageClose(ControlProviderId(), ControlProviderId(),
+		TCFIPProtoMessage::TOpenCloseRoute(EFalse).CRef());
+	}
+
+
+CIPShimProtocolIntfFactory* CIPShimProtocolIntfFactory::NewL(TUid aFactoryId,
+															 ESock::CProtocolIntfFactoryContainer& aParentContainer)
+	{
+	CIPShimProtocolIntfFactory *fact = new(ELeave) CIPShimProtocolIntfFactory(aFactoryId, aParentContainer);
+	CleanupStack::PushL(fact);
+	fact->ConstructL();
+	CleanupStack::Pop(fact);
+	return fact;
+	}
+
+CProtocolIntfBase* CIPShimProtocolIntfFactory::DoCreateProtocolIntfL(TFactoryQueryBase& aQuery)
+	{
+	const TDefaultProtocolIntfFactoryQuery& query = static_cast<const TDefaultProtocolIntfFactoryQuery&>(aQuery);
+	return new(ELeave) CIPShimProtocolIntf(*this, query.iCprId);
+	}
+
+CIPShimProtocolIntfFactory::CIPShimProtocolIntfFactory(TUid aFactoryId,
+													   ESock::CProtocolIntfFactoryContainer& aParentContainer)
+	:CProtocolIntfFactoryBase(aFactoryId, aParentContainer)
+	{
+	}