datacommsserver/esockserver/ssock/ss_sapshim.cpp
changeset 0 dfb7c4ff071f
child 2 dee179edb159
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/ssock/ss_sapshim.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,2098 @@
+// 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:
+//
+
+/**
+ @file SS_SAPSHIM.CPP
+*/
+
+#define SYMBIAN_NETWORKING_UPS
+#include "ss_sapshim.h"
+
+#include <ss_std.h>
+#include <ss_glob.h>
+#include <comms-infras/ss_roles.h>
+#include <comms-infras/ss_log.h>
+#include <comms-infras/ss_subconnprov.h>
+#include <comms-infras/ss_connprov.h>
+#include <ss_protprov.h>
+#include <ss_sock.h>
+#include <comms-infras/ss_protflow.h>
+#include <in_sock.h> // KAfInet
+#include <elements/nm_messages_child.h>
+#include <elements/nm_messages_peer.h>
+
+#include <comms-infras/nifif.h>
+#include <comms-infras/nifif_internal.h>
+
+#include <addressupdate.h>
+
+#include <comms-infras/ss_nodemessages_dataclient.h>
+#include <comms-infras/ss_nodemessages_flow.h>
+#include <comms-infras/ss_nodemessages_ipmessages.h>
+#include <comms-infras/ss_nodemessages_internal_esock.h>
+
+#include "ss_protopt.h"
+
+#ifdef SYMBIAN_NETWORKING_UPS
+#include <comms-infras/ss_upsaccesspointconfigext.h>
+#include <comms-infras/upsmessages.h>
+
+
+#ifdef _DEBUG
+// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
+// (if it could happen through user error then you should give it an explicit, documented, category + code)
+_LIT(KSpecAssert_ESockSSocksspshm, "ESockSSocksspshm");
+#endif
+
+_LIT_SECURITY_POLICY_C1(KPolicyNetworkServices, ECapabilityNetworkServices);
+#endif
+
+using namespace ESock;
+using namespace Messages;
+using namespace MeshMachine;
+using namespace Factories;
+
+//CHostResolver specific functions this is to remove once we have app layer protocols
+//***************************************************************************************
+//also loo for iHostResolverNotify
+MLowerControl* CTransportFlowShim::GetControlL(const TDesC8& /*aProtocol*/)
+    {
+    return this;
+    }
+
+TInt CTransportFlowShim::Control(TUint aLevel, TUint aName, TDes8& aOption)
+    {
+    return iLowerControl ? iLowerControl->Control(aLevel, aName, aOption) : KErrNotReady;
+    }
+
+MLowerDataSender* CTransportFlowShim::BindL(const TDesC8& /*aProtocol*/, MUpperDataReceiver* aReceiver, MUpperControl* aControl)
+    {
+    if (aReceiver || iProvider || IsBoundToSession())
+        {
+        User::Leave(KErrInUse);
+        }
+    iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TActive().CRef());
+    iHostResolverNotify = aControl;
+    return this;
+    }
+
+void CTransportFlowShim::Unbind( MUpperDataReceiver* /*aReceiver*/, MUpperControl* aControl)
+    {
+    (void)aControl;
+    __ASSERT_DEBUG(aControl == iHostResolverNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 1));
+    __ASSERT_DEBUG(iDCIdle <= EClientsPresent, User::Panic(KSpecAssert_ESockSSocksspshm, 2));
+    iDCIdle = EIdle;
+    iHostResolverNotify = NULL;
+    if(iSubConnectionProvider.IsOpen())	// legacy flows have no control side
+    	{
+    	ProcessDCIdleState();
+    	}
+    }
+
+MLowerDataSender::TSendResult CTransportFlowShim::Send(RMBufChain& /*aData*/)
+    {
+    __ASSERT_DEBUG(iHostResolverNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 3));
+
+    TBuf8<sizeof(TConnectionInfo)> buf;
+    if (Control(KSOLProvider, static_cast<TUint>(KSoConnectionInfo), buf) == KErrNone)
+        {
+        iHostResolverNotify->StartSending();
+        }
+    else if (!iLowerControl)
+        {
+#ifdef SYMBIAN_NETWORKING_UPS
+		TInt result = SetupForNoBearerOnSend();
+		if (result != KErrNone)
+			{
+			return TSendResult(result);
+			}
+#endif
+		__ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 4));	// legacy flows have no control side, so must never get here
+        PostNoBearer();
+        }
+
+    return MLowerDataSender::ESendAccepted;
+    }
+//***************************************************************************************
+//End of CHostResolver specific functions also look for iHostResolverNotify to find the rest
+
+#ifndef SYMBIAN_NETWORKING_UPS
+
+//
+// Not used with UPS support - CUpsTransportFlowShim::NewL() used instead.
+//
+
+CTransportFlowShim* CTransportFlowShim::NewL(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConn, CProtocolIntfBase* aProtocolIntf)
+	{
+	return new (ELeave) CTransportFlowShim(aFactory, aSubConn, aProtocolIntf);
+	}
+
+#endif
+
+CTransportFlowShim::CTransportFlowShim(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConn, CProtocolIntfBase* aProtocolIntf)
+: CNetworkFlow(aFactory, aSubConn, aProtocolIntf), iFlowParams(TFlowParams(NULL, NULL, KUndefinedProtocol, NULL, NULL))
+	{
+    LOG_NODE_CREATE(KESockFlowTag, CTransportFlowShim)
+	}
+
+
+void CTransportFlowShim::SetSSP(CServProviderBase& aSSP)
+	{
+	__ASSERT_DEBUG(iProvider == NULL, User::Panic(KSpecAssert_ESockSSocksspshm, 5));
+	iProvider = &aSSP;
+	iProvider->SetNotify(this);
+	}
+
+CTransportFlowShim::~CTransportFlowShim()
+	{
+	// Remove ourselves from any listening control session's accept queue.
+	if(iListenerControlNotify)
+		{
+		iListenerControlNotify->DisconnectFromListener(*this);
+		}
+
+	if(!iDetaching)
+		{
+		delete iProvider;
+		iProvider = NULL;
+		}
+
+	Messages::TEBase::TError err(TEBase::TNull::Id(), KErrBindersInvalid);
+    SubConnectionError(err, EErrorAllOperations);
+
+    LOG_NODE_DESTROY(KESockFlowTag, CTransportFlowShim)
+	}
+
+void CTransportFlowShim::SetSockType(TUint aSockType)
+	{
+	if (iProvider)
+		{
+		iProvider->SetSockType(aSockType);
+		}
+	}
+
+MSessionControl* CTransportFlowShim::GetControlL(TInt aSessionType,MSessionControlNotify& aSessionControlNotify)
+    {
+    CNetworkFlow::GetControlL(aSessionType,aSessionControlNotify);
+    SetSockType(aSessionType);
+	return this;
+    }
+
+MSessionData* CTransportFlowShim::BindL(MSessionDataNotify& aNotify)
+    {
+	LOG( ESockLog::Printf(_L8("CTransportFlowShim %08x:\tBindL(aNotify 0x%08x)"), this, &aNotify) );
+
+	// The flow shim now manages custody and loading of the protocol involved.
+	// However in the case of host resolvers, until ported for the same behaviour, protocol loading is still managed by the socket.
+	if(iFlowParams.iFlowLoadsProtocol)
+		{
+		CProtocolRef * protocolReference = ProtocolManager::FindProtocolL(
+			iFlowParams.iAddrFamily,
+			iFlowParams.iSocketType,
+			iFlowParams.iProtocol);
+
+        if (protocolReference->GetFlag() & CProtocolRef::EThreePlaneCommsBased)
+            {
+            // Three plane comms protos should not be seen here. If an RSocket is opened with a supported
+            // protocol and it happens to be 3PC this point will be reached. In the case of RTP some
+            // special processing is performed (in the SCPR) in order to sort out the mess and ensure that
+            // a UDP/TCP flow is requested instead.
+            User::Leave(KErrProtocolNotReady);
+            }
+
+        // Check if the protocol is supported over sockets
+        if (!(protocolReference->Info().iServiceTypeInfo & ESocketSupport))
+            {
+            User::Leave(KErrNotSupported);
+            }
+
+        // Have the protocol loaded if not already the case and confirm it has socket support
+        protocolReference->LoadAndBindL();
+
+        __ASSERT_DEBUG(iProtocolReference == NULL, User::Panic(KSpecAssert_ESockSSocksspshm, 6));
+        iProtocolReference = protocolReference;
+
+        // Have the protocol added to the list of protocols for the session it is associated with
+        CSockSessionProxy* sessionProxy = reinterpret_cast<CSockSessionProxy*>(iFlowParams.iSessionProxy);
+        if(sessionProxy != NULL)
+            {
+            sessionProxy->AddProtocolL(iProtocolReference->Protocol());
+            }
+
+        // Fetch a new SAP from the protocol for this flow
+        if (iProvider == NULL)
+            {
+            iProvider = iProtocolReference->Protocol()->NewSAPL(iFlowParams.iSocketType);
+
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+            // Set the options iterating the RArray variable
+            SetProtocolOptions();
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+    
+            if (iProvider)
+                {
+                iProvider->SetNotify(this);
+                }
+            }
+		}
+    
+    // Now perform the binding proper
+    if (!iProvider)
+        {
+        User::Leave(KErrNotSupported);
+        }
+        
+    __ASSERT_DEBUG(!iHostResolverNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 8));
+    CNetworkFlow::BindL(aNotify);
+    iProvider->SetNotify(this);
+
+	return this;
+    }
+
+void CTransportFlowShim::Unbind()
+    {
+	LOG( ESockLog::Printf(_L8("CTransportFlowShim %08x:\tUnbind()"), this) );
+
+	// Infant mortality case in which binding never completed,
+	if(iFlowParams.iProtocol == KUndefinedProtocol)
+		{
+		delete this;
+		return;
+		}
+
+	// Legacy support for host resolvers
+	if(iHostResolverNotify)
+		{
+		__ASSERT_DEBUG(!iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 9));	// can't have both HR & SAP
+
+		LOG( ESockLog::Printf(_L8("CTransportFlowShim %08x:\tUnbind(): iBearerExpected %d"), this, iBearerExpected) );
+		if (!iBearerExpected)
+			{
+			delete this;
+			}
+		else
+			{
+			iDeleteUponBearerReception = ETrue;
+			iHostResolverNotify = NULL;
+			}
+		return;
+		}
+
+	if (iProvider)
+		{
+		iProvider->SetNotify(NULL);
+
+		if (!iDetaching)
+			{
+			delete iProvider;
+			iProvider = NULL;
+			}
+		}
+
+#ifdef SYMBIAN_NETWORKING_UPS
+	// Hook for derived classes to do cleanup before unbind occurs
+	PreUnbind();
+#endif
+
+	CNetworkFlow::Unbind();
+    }
+
+ESock::CSubConnectionFlowBase& CTransportFlowShim::CloneFlowL()
+    {
+    __ASSERT_DEBUG(iProtocolIntf, User::Panic(KSpecAssert_ESockSSocksspshm, 10));
+    TDefaultFlowFactoryQuery query (iProtocolIntf->ControlProviderId(), iSubConnectionProvider.RecipientId());
+	ESock::CSubConnectionFlowBase& flow = static_cast<ESock::CSubConnectionFlowBase&>(*(Factory().CreateObjectL(query)));
+	// Legacy flows lack a control provider
+	if(iSubConnectionProvider.IsOpen())
+		{
+		TCFPeer::TJoinRequest msg(flow.Id(), TClientType(TCFClientType::EData, TCFClientType::EActive));
+		iSubConnectionProvider.PostMessage(Id(), msg);
+		}
+	return flow;
+    }
+
+void CTransportFlowShim::Start()
+	/**
+	Start a service provider.
+	*/
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 11));
+	iProvider->Start();
+	}
+
+void CTransportFlowShim::LocalName(TSockAddr& anAddr) const
+/** Gets the local name (address) of the socket service provider entity. The format
+of the data in the TSockAddr object is defined by individual protocols.
+
+The local address is the address of the local machine plus a local port number.
+Generally only the port number is important, unless you have two IP interfaces,
+for example.
+
+@param anAddr The address to be filled in */
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 12));
+	iProvider->LocalName(anAddr);
+	}
+
+void CTransportFlowShim::SetLocalName(TSockAddr& anAddr)
+/** Sets the local name (address) of the socket service provider entity. The format
+of the data in the TSockAddr object is defined by individual protocols.
+
+@param anAddr The address */
+	{
+	CNetworkFlow::SetLocalName(anAddr);
+	PostDataClientRouted();
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 65));
+	TInt err = iProvider->SetLocalName(anAddr);
+	if (err != KErrNone)
+		{
+		// Post TError to self, which will result in SubConnectionError to
+		// be called in the TError handling. Have to fake that the message is
+		// coming from iSubConnectionProvider otherwise ReceivedL will leave.
+		RClientInterface::OpenPostMessageClose(iSubConnectionProvider.RecipientId(), Id(), TEBase::TError(err).CRef());
+		return;
+		}
+
+	SetLocalNameProcess();
+	}
+
+void CTransportFlowShim::SetLocalNameProcess()
+	{
+	TBool bearerSent = EFalse;
+	if(iFlowParams.iFlowRequestType != TFlowParams::EImplicit)
+		{
+		// For explicit sockets, TNoBearer will be sent out if it has not already
+		// been done so. This was introduced for PREQ2279, as it is necessary
+		// to lock this SAP to an interface for incoming sockets. Once locked,
+		// this ensures that any incoming packets are only accepted over the locked down
+		// interface and no other interfaces. To lock the interface down the
+		// NoBearer sequence is executed. This change will also now apply to
+		// outgoing explicit sockets. The change for outgoing explicit sockets is
+		// that the NoBearer sequence is started here instead of when receiving
+		// a NoBearer upcall from the protocol.
+
+		// Attempt to send out TNoBearer.
+		if (DoNoBearer())
+		    {
+		    // TNoBearer was sent out.
+			bearerSent = ETrue;
+		    }
+		}
+
+	if (!bearerSent)
+		{
+		// No Bearer was already sent out earlier, or this is an implicit socket.
+		iSessionControlNotify->SetLocalNameComplete();
+		}
+	}
+
+
+TBool CTransportFlowShim::DoNoBearer()
+/**
+Do the actual no Bearer call.
+@return ETrue if the NoBearer post was actually done, EFalse otherwise
+*/
+	{
+	TInt ret = EFalse;
+	if(!iIsStopped)
+		{ // Prevent sending NoBearer if DataClientStop was received
+		if (LockToConnectionInfo() != KErrNone)
+		    {
+	        __ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 66));
+			PostNoBearer();
+			ret = ETrue;
+		    }
+		iUseBearerErrors = EFalse;
+		ClearDataClientRoutedGuard();
+		}
+	return ret;
+	}
+
+
+
+void CTransportFlowShim::RemName(TSockAddr& anAddr) const
+/** Gets the remote name (address) of the socket service provider entity. The format
+of the data in the TSockAddr object is defined by individual protocols.
+
+A remote address is either the address you're sending data to (non connection-oriented
+sockets)* or the remote end of the connection. It is the address of the remote
+machine (your peer in the network) plus a port number.
+
+@note RemName is only meaningful if the socket server client has called Connect()
+to set up a default address for SendTo(). This function will only be called
+on the protocol if this is the case.
+
+@param anAddr The address to be filled in */
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 14));
+	iProvider->RemName(anAddr);
+	}
+
+TInt CTransportFlowShim::SetRemName(TSockAddr& anAddr)
+/** Sets the remote name (address) of the socket service provider entity. The format
+of the data in the TSockAddr object is defined by individual protocols.
+
+@param anAddr The address
+@return Returns KErrNone if the remote name is correctly set or, if this is
+not the case, an informative error number. */
+	{
+	CNetworkFlow::SetRemName(anAddr);
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 15));
+	return iProvider->SetRemName(anAddr);
+	}
+
+TInt CTransportFlowShim::GetOption(TUint aLevel, TUint aName, TDes8& anOption) const
+/** Gets some protocol specific option when called by the socket server on behalf of a
+client. A protocol may pass the request down a protocol	stack (to protocols it is bound
+to) using the GetOption() function of CProtocolBase.
+
+@param aLevel Option level.
+@param aName Option name.
+@param anOption Option data.
+@return System wide error code.
+*/
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 16));
+	return iProvider->GetOption(aLevel, aName, anOption);
+	}
+
+void CTransportFlowShim::Ioctl(TUint aLevel, TUint aName, TDes8* anOption)
+/** Performs some protocol specific IO control.
+
+@note If this function is called erroneously, the protocol should call Error() on the
+socket. If an Ioctl call is already outstanding, the client will be panicked with the
+value ETwoIoctls.
+
+@param aLevel Option level.
+@param aName Option name.
+@param anOption Option data.
+*/
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 17));
+	iProvider->Ioctl(aLevel, aName, anOption);
+	}
+
+void CTransportFlowShim::CancelIoctl(TUint aLevel, TUint aName)
+/** Cancels an outstanding Ioctl call. You are guaranteed only to have one outstanding
+at once.
+
+@param aLevel IOCTL level.
+@param aName IOCTL name.
+*/
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 18));
+	iProvider->CancelIoctl(aLevel, aName);
+	}
+
+TInt CTransportFlowShim::SetOption(TUint aLevel, TUint aName, const TDesC8 &anOption)
+/** Sets some protocol specific option when called by the socket server on behalf of a
+client. A protocol may pass the request down a protocol	stack (to protocols it is bound
+to) using the SetOption() function	of CProtocolBase.
+
+@param aLevel Option level.
+@param aName Option name.
+@param anOption Option data.
+@return System wide error code.
+*/
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 19));
+	return iProvider->SetOption(aLevel, aName, anOption);
+	}
+
+void CTransportFlowShim::ActiveOpen()
+/** Initiates a connection operation - this means that it tells the protocol to
+attempt to connect to a peer. It is called by the socket server in response
+to a connect request from a client.
+
+This version of the function has user data in the connection frame.
+
+Only ever called on connection-oriented sockets. Such a socket
+should always have both the local address and the remote address specified
+before this function is called. If this is not the case then the protocol
+should panic.
+
+When a connection has completed, the protocol should call ConnectComplete()
+on its TNotify. If an error occurs during connection the protocol should not
+call ConnectComplete() at all; instead it should call Error().
+*/
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 20));
+	iProvider->ActiveOpen();
+	}
+
+void CTransportFlowShim::ActiveOpen(const TDesC8& aConnectionData)
+/** Initiates a connection operation - this means that it tells the protocol to
+attempt to connect to a peer. It is called by the socket server in response
+to a connect request from a client.
+
+This version of the function has user data in the connection frame.
+
+Only ever called on connection-oriented sockets. Such a socket
+should always have both the local address and the remote address specified
+before this function is called. If this is not the case then the protocol
+should panic.
+
+When a connection has completed, the protocol should call ConnectComplete()
+on its TNotify. If an error occurs during connection the protocol should not
+call ConnectComplete() at all; instead it should call Error().
+
+@param aConnectionData If the protocol supports user specified connection
+data, then it will be held in this buffer. */
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 21));
+	iProvider->ActiveOpen(aConnectionData);
+	}
+
+TInt CTransportFlowShim::PassiveOpen(TUint aQueueSize)
+/** Tells the protocol to start waiting for an incoming connection request on this
+socket (i.e. port). It is called by the socket server in response to a listen
+request from a client.
+
+Only ever called on connection-oriented sockets. Such a socket
+should always have both the local address and the remote address specified
+before this function is called. If this is not the case, then the protocol
+should panic.
+
+The aQue parameter is the number of sockets which can be waiting for an outstanding
+Start after calling ConnectComplete(). The protocol should keep a count of
+sockets in this state - incrementing a variable in ConnectComplete(), and
+decrementing it in Start().
+
+When a connection has completed, the protocol should call ConnectComplete()
+on its TNotify. If an error occurs during connection the protocol should not
+call ConnectComplete() at all; instead it should call Error().
+
+@param aQueSize Size of connect queue.
+*/
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 22));
+	return iProvider->PassiveOpen(aQueueSize);
+	}
+
+TInt CTransportFlowShim::PassiveOpen(TUint aQueueSize, const TDesC8& aConnectionData)
+/** Tells the protocol to start waiting for an incoming connection request on this
+socket (i.e. port). It is called by the socket server in response to a listen
+request from a client.
+
+This version of the function has user data in the connection frame.
+
+Only ever called on connection-oriented sockets. Such a socket
+should always have both the local address and the remote address specified
+before this function is called. If this is not the case then the protocol
+should panic.
+
+The aQue parameter is the number of sockets which can be waiting for an outstanding
+Start after calling ConnectComplete(). The protocol should keep a count of
+sockets in this state - incrementing a variable in ConnectComplete(), and
+decrementing it in Start().
+
+When a connection has completed the protocol should call ConnectComplete()
+on its TNotify. If an error occurs during connection the protocol should not
+call ConnectComplete() at all; instead it should call Error().
+
+@param aQueueSize size of connect queue
+@param aConnectionData if the protocol supports user specified connection data
+then it will be held in this buffer. */
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 23));
+	return iProvider->PassiveOpen(aQueueSize, aConnectionData);
+	}
+
+void CTransportFlowShim::Shutdown(MSessionControl::TCloseType aOption)
+/** Terminates a connection (or closes a non connection-oriented socket down).
+
+The value of the option argument specifies the type of processing which will
+be required of the protocol after this function is called.
+
+Normally, when the socket server has called Shutdown() for a socket, it will
+wait for the socket to call CanClose() before destroying the CServProviderBase
+object. However, if the option argument is EImmediate, the CServProviderBase
+will be destroyed as soon as Shutdown() returns.
+
+@param option The shutdown type. */
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 24));
+	if (aOption == MSessionControl::EImmediate)
+		{
+		iShuttingDown = ETrue;
+		}
+
+	// It is possible for the provider to be null if an error occurs immediatly
+	// after socket creation before the flow is bound and the provider is received
+	// from the protocol.
+	if(iProvider)
+		{
+		iProvider->Shutdown(CServProviderBase::TCloseType(aOption));
+		}
+	}
+
+void CTransportFlowShim::Shutdown(MSessionControl::TCloseType aOption, const TDesC8& aDisconnectionData)
+/** Terminates a connection (or closes a non connection-oriented socket down).
+
+The value of the option argument specifies the type of processing which will
+be required of the protocol after this function is called.
+
+Normally, when the socket server has called Shutdown() for a socket, it will
+wait for the socket to call CanClose() before destroying the CServProviderBase
+object. However, if the option argument is EImmediate, the CServProviderBase
+will be destroyed as soon as Shutdown() returns.
+
+@param option The shutdown type.
+@param aDisconnectionData If the protocol supports disconnect data, any such
+data required will be held in this buffer. */
+	{
+	// It is possible for the provider to be null if an error occurs immediatly
+	// after socket creation before the flow is bound and the provider is received
+	// from the protocol.
+	if(iProvider)
+		{
+		iProvider->Shutdown(CServProviderBase::TCloseType(aOption), aDisconnectionData);
+		}
+	}
+
+void CTransportFlowShim::AutoBind()
+/** Specifies that the protocol should choose a local address for the service access
+point itself. */
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 25));
+	iProvider->AutoBind();
+	SetLocalNameProcess();
+
+	}
+
+TUint CTransportFlowShim::Write(const TDesC8& aDesc, TUint aOptions, TSockAddr* anAddr)
+/** Sends data onto the network via the protocol.
+
+Connection-oriented sockets must be in a connected state (that is ConnectComplete() has
+been called on their MSocketNotify before Write() is called).
+
+The socket server keeps track of how much data is waiting and then tries to send it all
+until the protocol tells it to hold off by returning 0 (datagram sockets) or 'less than
+all data consumed' (stream sockets) to Write(). The protocol should call CanSend() when it
+is ready to send more data.
+
+anAddr is the address to write the data to.	Connection oriented sockets always use the
+default value.
+
+@param aDesc The data to be sent.
+@param aOptions Protocol specific options.
+@param anAddr Address to write the data to.
+
+@returns For stream-oriented protocols the return value is the number of bytes actually written.
+If this is less than the length of the descriptor then the protocol should call CanSend()
+when it is ready to send more data. For datagram-oriented protocols, the write should return
+either 0 if the write cannot be completed, or the length of the descriptor if the write succeeds -
+no other values are valid. If the Write() must return 0, then it should call CanSend() when it is
+ready to send more data. If the Write() fails due to some error, then it should call Error() with
+an informative error number.
+*/
+	{
+	CNetworkFlow::Write( aDesc, aOptions, anAddr);
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 26));
+	return iProvider->Write(aDesc, aOptions, anAddr);
+	}
+
+TInt CTransportFlowShim::Write(RMBufChain& aData, TUint aOptions, TSockAddr* anAddr)
+/** Sends data onto the network via the protocol.
+
+Connection-oriented sockets must be in a connected state (that is ConnectComplete() has
+been called on their MSocketNotify before Write() is called).
+
+The socket server keeps track of how much data is waiting and then tries to send it all
+until the protocol tells it to hold off by returning 0 (datagram sockets) or 'less than
+all data consumed' (stream sockets) to Write(). The protocol should call CanSend() when it
+is ready to send more data.
+
+anAddr is the address to write the data to.	Connection oriented sockets always use the
+default value.
+
+@param aData The data to be sent.
+@param aOptions Protocol specific options.
+@param anAddr Address to write the data to.
+
+@returns For stream-oriented protocols the return value is the number of bytes actually written.
+If this is less than the length of the descriptor then the protocol should call CanSend()
+when it is ready to send more data. For datagram-oriented protocols, the write should return
+either 0 if the write cannot be completed, or the length of the descriptor if the write succeeds -
+no other values are valid. If the Write() must return 0, then it should call CanSend() when it is
+ready to send more data. If the Write() fails due to some error, then it should call Error() with
+an informative error number.
+*/
+	{
+	CNetworkFlow::Write(aData, aOptions, anAddr);
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 27));
+	return iProvider->Write(aData, aOptions, anAddr);
+	}
+
+void CTransportFlowShim::GetData(TDes8& aDesc, TUint aOptions, TSockAddr* anAddr)
+/** Gets data which the protocol has indicated is waiting in its buffers using the NewData
+up-call on the MSocketNotify.
+
+GetData() will only ever be called for as much data as the protocol has specified it can process
+using the NewData up-call.
+
+For stream oriented protocols GetData() should fill the descriptor with data from the stream. On
+a datagram protocol GetData() should copy one datagram into the descriptor and set the length of
+the descriptor. If a full datagram will not fit into the supplied descriptor, the overflow should
+be discarded.
+
+anAddr should be filled in by the protocol with the address of where the data came from.
+
+@param aDesc  The buffer for data.
+@param aOptions Protocol specific options.
+@param anAddr Address where the data came from.
+*/
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 28));
+	iProvider->GetData(aDesc, aOptions, anAddr);
+	}
+
+TInt CTransportFlowShim::GetData(RMBufChain& aData, TUint aLength, TUint aOptions, TSockAddr* anAddr)
+/** Gets data which the protocol has indicated is waiting in its buffers using the NewData
+up-call on the MSocketNotify.
+
+GetData() will only ever be called for as much data as the protocol has specified it can process
+using the NewData up-call.
+
+For stream oriented protocols GetData() should fill the descriptor with data from the stream. On
+a datagram protocol GetData() should copy one datagram into the descriptor and set the length of
+the descriptor. If a full datagram will not fit into the supplied descriptor, the overflow should
+be discarded.
+
+anAddr should be filled in by the protocol with the address of where the data came from.
+
+@param aDesc  The buffer for data.
+@param aOptions Protocol specific options.
+@param anAddr Address where the data came from.
+*/
+	{
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 29));
+	return iProvider->GetData(aData, aLength, aOptions, anAddr);
+	}
+
+TInt CTransportFlowShim::SecurityCheck(MProvdSecurityChecker* aChecker)
+/**
+Ask the SAP provider to perform a security policy check on the client process (default implementation).
+*/
+	{
+	// ********************************************************************
+	// NOTE: KErrNone for now, but this should be changed to KErrNotSupported to
+	// turn on strict checking and fail PRTs that have not been secured.
+	// ********************************************************************
+
+	__ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 30));
+	return iProvider->SecurityCheck(aChecker);
+	}
+
+void CTransportFlowShim::NewData(TUint aCount)
+	{
+	__ASSERT_DEBUG(iSessionDataNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 31));
+	iSessionDataNotify->NewData(aCount);
+	}
+
+void CTransportFlowShim::CanSend()
+	{
+	__ASSERT_DEBUG(iSessionDataNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 32));
+	iSessionDataNotify->CanSend();
+	}
+
+void CTransportFlowShim::ConnectComplete()
+	{
+	__ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 33));
+	iSessionControlNotify->ConnectComplete();
+	}
+
+void CTransportFlowShim::ConnectComplete(const TDesC8& aConnectData)
+	{
+	__ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 34));
+	iSessionControlNotify->ConnectComplete(aConnectData);
+	}
+
+CTransportFlowShim* CTransportFlowShim::CloneNSetSAP(CServProviderBase& aSSP)
+    {
+	//Here we can afford to create a flow directly since we know sub-connection
+	//+ protocols & flow plug-is've been already loaded while opening listenning socket
+	//this is the only case when flow joins without being created from control side
+	CTransportFlowShim* shimFlow = NULL;
+	TRAPD(ret,shimFlow = factoryobject_cast<CTransportFlowShim>(&CloneFlowL()));
+	if (ret != KErrNone)
+		{
+		Error(ret,MSessionControlNotify::EErrorCompleteConnect);
+		}
+	else
+	    {
+        __ASSERT_DEBUG(shimFlow, User::Panic(KSpecAssert_ESockSSocksspshm, 35)); //otherwise we shouldn't be here
+       	shimFlow->SetSSP(aSSP);
+       	shimFlow->iFlowParams = iFlowParams;
+	    }
+	return shimFlow;
+    }
+
+void CTransportFlowShim::ConnectComplete(CServProviderBase& aSSP)
+	{
+	CTransportFlowShim* shimFlow;
+	if ((shimFlow = CloneNSetSAP(aSSP)) != NULL)
+		{
+		__ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 36));
+
+		// Store a pointer to the listening control session in case we need to unbind before
+		// the passively opened socket is accepted.
+		shimFlow->iListenerControlNotify = iSessionControlNotify;
+
+		iSessionControlNotify->ConnectComplete(*shimFlow);
+		}
+	}
+
+void CTransportFlowShim::ConnectComplete(CServProviderBase& aSSP,const TDesC8& aConnectData)
+	{
+//	CTransportFlowShim* shim = NULL;
+//	TRAPD(ret, shim = CTransportFlowShim::NewL(aSSP, NULL, iProtocolId));
+
+	CTransportFlowShim* shimFlow;
+    if ((shimFlow = CloneNSetSAP(aSSP)) != NULL)
+		{
+		__ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 37));
+		iSessionControlNotify->ConnectComplete(*shimFlow, aConnectData);
+		}
+	}
+
+void CTransportFlowShim::CanClose(MSocketNotify::TDelete aDelete)
+	{
+	LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tCanClose() aDelete %d"), this, aDelete) );
+
+	if(iSessionControlNotify)
+		{
+		iDetaching = aDelete == MSocketNotify::EDetach;
+		iSessionControlNotify->CanClose(MSessionControlNotify::TDelete(aDelete));
+        if(aDelete==MSocketNotify::EDetach)
+            {
+            iProvider = NULL;
+            }
+		}
+	else
+		{
+		LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tCanClose() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+		// No control above us - likely cause is that we're the result of a passive open that
+		// hasn't yet been accepted.
+		Unbind();
+		}
+	}
+
+void CTransportFlowShim::CanClose(const TDesC8& aDisconnectData,MSocketNotify::TDelete aDelete)
+	{
+	LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tCanClose() aDisconnectData %08x, aDelete %d"), this, aDisconnectData.Ptr(), aDelete) );
+
+	if(iSessionControlNotify)
+		{
+        iDetaching = aDelete == MSocketNotify::EDetach;
+		iSessionControlNotify->CanClose(aDisconnectData, MSessionControlNotify::TDelete(aDelete));
+		if(aDelete==MSocketNotify::EDetach)
+			{
+			iProvider = NULL;
+			}
+		}
+	else
+		{
+		LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tCanClose() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+		// No control above us - likely cause is that we're the result of a passive open that
+		// hasn't yet been accepted.
+		Unbind();
+		}
+	}
+
+void CTransportFlowShim::Error(TInt anError, TUint anOperationMask)
+	{
+	LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tError() anError %d, anOperationMask %d"), this, anError, anOperationMask) );
+
+	NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=Error(%d)"),
+			this, static_cast<Messages::ANode*>(this), static_cast<Messages::ANode*>(this), anError) )
+
+	if(iSessionControlNotify)
+		{
+		if (iSessionControlNotify->Error(anError, anOperationMask) != KErrNone)
+	    	{
+	    	if (iLowerFlow)
+	    		{
+	    		iLowerFlow->Unbind(NULL,NULL);
+	    		iLowerFlow = NULL;
+	    		}
+	        iLowerControl = NULL;
+	    	}
+		}
+	else
+		{
+		LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tError() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+		// No control above us - likely cause is that we're the result of a passive open that
+		// hasn't yet been accepted.
+		iDetaching = MSocketNotify::EDetach;
+		Unbind();
+		}
+	}
+
+void CTransportFlowShim::Disconnect(void)
+	{
+	LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tDisconnect()"), this) );
+
+	if(iSessionControlNotify)
+		{
+		iSessionControlNotify->Disconnect();
+		}
+	else
+		{
+		LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tDisconnect() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+		// No control above us - likely cause is that we're the result of a passive open that
+		// hasn't yet been accepted.
+		iDetaching = MSocketNotify::EDetach;
+		Unbind();
+		}
+	}
+
+void CTransportFlowShim::Disconnect(TDesC8& aDisconnectData)
+	{
+	LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tDisconnect() aDisconnectData %08x"), this, aDisconnectData.Ptr()) );
+
+	if(iSessionControlNotify)
+		{
+		iSessionControlNotify->Disconnect(aDisconnectData);
+		}
+	else
+		{
+		LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tDisconnect() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+		// No control above us - likely cause is that we're the result of a passive open that
+		// hasn't yet been accepted.
+		iDetaching = MSocketNotify::EDetach;
+		Unbind();
+		}
+	}
+
+void CTransportFlowShim::IoctlComplete(TDesC8 *aBuf)
+	{
+	__ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 38));
+	iSessionControlNotify->IoctlComplete(aBuf);
+	}
+
+void CTransportFlowShim::NoBearer(const TDesC8& aConnectionParams)
+/**
+Upcall from protocol indicating no underlying bearer for the socket.
+@param aConnectionParams Additional connection parameters from the stack, in the form of a
+human readable string.  Initially, the required protocols (e.g. "protocol=ip").
+*/
+	{
+	// *** NOTE ***
+	// overridden by CUpsTransportFlowShim::NoBearer() for UPS support
+
+	(void)aConnectionParams;
+	LOG( ESockLog::ConnectionInfoPrintf(aConnectionParams, _L("CTransportFlowShim %08x:\tNoBearer()"), this) );
+
+	DoNoBearer(); // Do not care if actually posted, so no need to check return value
+
+	}
+
+void CTransportFlowShim::Bearer(const TDesC8& aConnectionInfo)
+	{
+	//we might need to translate the aConnectionInfo into "our" conn info format
+	LOG( ESockLog::ConnectionInfoPrintf(aConnectionInfo, _L("CTransportFlowShim %08x:\tBearer()"), this) );
+
+#if defined(SYMBIAN_TRACE_ENABLE)
+	const TSoIfConnectionInfo *info = REINTERPRET_CAST(const TSoIfConnectionInfo*, aConnectionInfo.Ptr());
+	NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=Bearer(Iap %d, Network %d)"),
+			this, static_cast<Messages::ANode*>(this), static_cast<Messages::ANode*>(this), info->iIAPId, info->iNetworkId) )
+#endif
+
+	if (TConnectionInfo::IsLocalBearer(aConnectionInfo))
+		{
+		return;
+		}
+
+	iUseBearerErrors = ETrue;
+	LocalName(iLocalAddress);
+	iLocalAddressSet = ETrue;
+	RemName(iRemoteAddress);
+	iRemoteAddressSet = ETrue;
+	__ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 41));	// legacy flows have no control side; should never get here
+
+	PostDataClientRouted();
+	}
+
+TInt CTransportFlowShim::LockToConnectionInfo()
+	{
+	//bind provider with the selected connection
+	// Note that the following SetOption() can result in an upcall into
+	// CTransportFlowShim::Bearer() in the same stack frame.
+    TPckgBuf<TConnectionInfo> info;
+    if (Control(KSOLProvider, static_cast<TUint>(KSoConnectionInfo), info) == KErrNone)
+		{
+		LOG(ESockLog::Printf(_L("CTransportFlowShim %08x:\tLockToConnectionInfo() Iap %d, Network %d"), this, info().iIapId, info().iNetId));
+		NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=LockToConnectionInfo(Iap %d, Network %d)"),
+				this, static_cast<Messages::ANode*>(this), static_cast<Messages::ANode*>(this), info().iIapId, info().iNetId) )
+
+		TPckg<TSoIfConnectionInfo> ifInfo(iIfInfo);
+	    ifInfo().iIAPId = info().iIapId;
+    	ifInfo().iNetworkId = info().iNetId;
+		iProvider->SetOption(KSOLProvider, static_cast<TUint>(KSoConnectionInfo), ifInfo);
+		return KErrNone;
+		}
+    else
+    	{
+    	LOG(ESockLog::Printf(_L("CTransportFlowShim %08x:\tLockToConnectionInfo()"), this));
+    	return KErrNotFound;
+    	}
+	}
+
+void CTransportFlowShim::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
+    {
+    if (aMessage.IsMessage<TCFDataClient::TBindTo>() && !NoBearerGuard())
+    	{
+    	//TODO PROD RZ
+    	//This needs investigating and fixing. There are two cases for why is this needed here:
+    	//(1) Bearer mobility is the only scenario for unsolicited TBindTo
+    	//(hence checking the guard above). CTransportFlowShim cannot just migrate to the new, as the
+    	//socket above it needs to be rebound. mobility_761220:
+    	//  (1) opens and starts a connection
+    	//  (2) opens a socket against
+    	//  (3) sendreceive UDP data and expects (packet colouring) that data to go via IAP4.
+    	//  (4) migrates to another bearer (IAP5)
+    	//  (5) uses the same socket (without rebinding) to sendreceive data and expects
+    	//    the data to go via IAP4 again (despite migrating).
+    	//Talk to Ivan Kelly to find out if this is a requirement on the socket (stays connected
+    	//over the old until rebound) or is this a wrong test case.
+    	//If the former, ipscpr will need changing not to propagate TBindTo to its flows if they
+    	//don't ask.
+    	//(2) Rejoing this flow. During rejoin scenario, it's the new owner obtains its new
+    	//dataclient ('this') before ('this') dataclient knowing. The rejoin procedure is make
+    	//before break, hence it tries to apply the new owner, during which time the new
+    	//owner starts and hence attempts to TBindTo his new child. The child hates it
+    	//as it arrives from an unknown node. The rejoin protocol needs rethinking.
+		RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete(KErrNone).CRef());
+    	return;
+    	}
+    CNetworkFlow::ReceivedL(aSender, aRecipient, aMessage);
+#ifdef SYMBIAN_NETWORKING_UPS
+	// Allow derived classes to process received messages.
+	//
+	// Rationale for ProcessReceivedL() virtual:
+	// The existing idiom whereby we call CNetworkFlow::ReceivedL() up front is awkward.
+	// If we move that call into the derived class, the derived class can do its
+	// specialised processing and then decide to call this base class method for any
+	// remaining more general processing.  In this case, the ProcessReceivedL() would
+	// not be required.  However, CTransportFlowShim will then become unusable if
+	// instantiated on its own because the call to CNetworkFlow::ReceivedL() is not present.
+    TInt ret = ProcessReceivedL(aMessage);
+    if (ret == KErrNone || ret != KErrNotSupported)
+    	{
+    	return;	// PREQ1116 Productisation: RE-WORK ProcessReceivedL().  Perhaps return TBool indicating whether message processed.  Leave if a "real" error.  Extra arguments?
+    	}
+#endif
+
+   	if ( aMessage.IsMessage<TEBase::TError>() )
+   		{
+		SubConnectionError(static_cast<TEBase::TError&>(aMessage));
+		}
+   	else if (aMessage.IsMessage<TEBase::TCancel>())
+   		{
+   		// TCancel can be received as a result of a Connect() being cancelled on the socket and a
+   		// TBindToComplete() with an error being sent to the PRBindTo activity on our control provider.
+   		}
+   	else if (TEChild::ERealmId == aMessage.MessageId().Realm())
+		{
+		switch (aMessage.MessageId().MessageId())
+			{
+		case TEChild::TDestroy::EId :
+			Destroy();
+			break;
+		default:
+			//TODO - logging
+			//LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+			__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 42)); //For debug configurations
+			User::Leave(KErrNotSupported); //For release configurations
+			}
+		}
+	else if (TCFDataClient::ERealmId == aMessage.MessageId().Realm())
+		{
+		switch (aMessage.MessageId().MessageId())
+			{
+		case TCFDataClient::TStart::EId :
+			StartFlowL(aSender);
+			break;
+		case TCFDataClient::TStop::EId :
+			StopFlow(static_cast<TCFDataClient::TStop&>(aMessage));
+			break;
+		case TCFDataClient::TProvisionConfig::EId :
+
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+			//Store the provision config message,
+			//to store the Provision config message
+            StoreProvision(static_cast<TCFDataClient::TProvisionConfig&>(aMessage));
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+
+			break;
+		case TCFDataClient::TCommitBindTo::EId :
+			/*TODO RZ PROD- mustn't just ignore TCommitBindTo - must implement*/
+			break;
+		case TCFDataClient::TBindTo::EId :
+			{
+			TCFDataClient::TBindTo& bindToMsg(static_cast<TCFDataClient::TBindTo&>(aMessage));
+			TRAPD(err,BindToL(bindToMsg));
+			// Ensure that TBindToComplete message gets sent before TIdle so that it gets to the destination
+			// before destroy processing.
+			RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete(err).CRef());
+			ProcessDCIdleState();	// in case we were waiting to send idle
+			//If we have received TDataClientStart before (when we did not yet have a bearer),
+			//we complete the start here as well
+			if (err != KErrNone)
+				{
+				//If we have received TDataClientStart before (when we did not yet have a bearer),
+				//we complete the start here as well
+				if (iStartRequest.IsOpen())
+					{
+					CompleteStart(err);
+					}
+               iBearerExpected = ETrue;
+				}
+			else
+		    	{
+				// If we get a TBindTo message then the TNoBearer request has succeeded
+				// and we can inform the client.
+		    	if (iSessionControlNotify)
+		    		{
+		    		iSessionControlNotify->SetLocalNameComplete();
+		    		}
+		        }
+		    break;
+			}
+		default:
+			//TODO - logging
+			//LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+			__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 43)); //For debug configurations
+			User::Leave(KErrNotSupported); //For release configurations
+			}
+		}
+	else if (TCFFlow::ERealmId == aMessage.MessageId().Realm())
+		{
+		switch (aMessage.MessageId().MessageId())
+			{
+		case TCFFlow::TRejoin::EId :
+			Rejoin(static_cast<TCFFlow::TRejoin&>(aMessage));
+			break;
+		default:
+			//TODO - logging
+			//LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+			__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 44)); //For debug configurations
+			User::Leave(KErrNotSupported); //For release configurations
+			}
+		}
+	else if (TCFInternalEsock::ERealmId == aMessage.MessageId().Realm())
+		{
+		switch (aMessage.MessageId().MessageId())
+			{
+	    case TCFInternalEsock::TFlowProvision::EId :
+			iFlowParams = (static_cast<TCFInternalEsock::TFlowProvision&>(aMessage)).iFlowParams;
+			break;
+		default:
+			//TODO - logging
+			//LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+			__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 45)); //For debug configurations
+			User::Leave(KErrNotSupported); //For release configurations
+			}
+		}
+
+//This is the case of Modulation change for a bearer.
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+	else if (TCFMessage::ERealmId == aMessage.MessageId().Realm())
+		{
+		switch (aMessage.MessageId().MessageId())
+			{
+		case TCFMessage::TTransportNotification::EId :
+          	//In case of modulation change,
+			//extract the value from this message,
+			//pass it to the shim to set the options for socket.
+	   		SetProtocolOptions();
+			break;
+        default:
+        	//TODO : Logging for error message
+        	__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 46)); //For debug configurations
+			User::Leave(KErrNotSupported); //For release configurations
+			}
+		}
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+
+	else if ( aMessage.IsMessage<TCFPeer::TJoinComplete>() )
+		{;}
+	else if ( aMessage.IsMessage<TCFControlProvider::TBearer>() )
+		{
+		//If we have received TDataClientStart before (when we did not yet have a bearer),
+		//we complete the start here as well
+		if (iStartRequest.IsOpen())
+			{
+			CompleteStart(KErrNone);
+			}
+		LOG( ESockLog::Printf(_L8("CTransportFlowShim %08x:\tReceivedL(): TBearer: iDeleteUponBearerReception %d"), this, iDeleteUponBearerReception) );
+
+		ClearNoBearerGuard();
+		ProcessDCIdleState();
+		NoBearerCompletion();		// may delete this !
+		}
+	else
+		{
+		//TODO - logging
+		//LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+    	__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 47)); //For debug configurations
+    	User::Leave(KErrNotSupported); //For release configurations
+		}
+    }
+
+void CTransportFlowShim::NoBearerCompletion()
+	{
+	iBearerExpected = EFalse;
+	if (iDeleteUponBearerReception)
+		{
+		delete this;
+		}
+	}
+
+const TNodeId& CTransportFlowShim::NodeId() const
+	{
+	return Id();
+	}
+
+void CTransportFlowShim::CompleteStart(TInt aError)
+	{
+	if (aError==KErrNone)
+		{
+		iStartRequest.ReplyTo(Id(), TCFDataClient::TStarted().CRef());
+		iIsStarted = ETrue;
+		iIsStopped = EFalse;
+		}
+	else
+		{
+		iStartRequest.ReplyTo(Id(), TEBase::TError(TCFDataClient::TStart::Id(),aError).CRef());
+		}
+	iStartRequest.Close();
+	}
+
+void CTransportFlowShim::SubConnectionError(const TEBase::TError& errorMsg, TUint anOperationMask)
+	{
+	LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tSubConnectionError() errorMsg.iValue %d, anOperationMask %d"), this, errorMsg.iValue, anOperationMask) );
+
+	if (errorMsg.iMsgId == TCFControlProvider::TNoBearer::Id())
+		{
+		LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tSubConnectionError() - clearing no-bearer guard"), this) );
+		ClearNoBearerGuard();
+#ifdef SYMBIAN_NETWORKING_UPS
+		ProcessDCIdleState();
+#endif
+		NoBearerCompletion();
+		}
+
+	if (IsBoundToSession())
+	    {
+		LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tSubConnectionError() - calling Error() function"), this) );
+    	Error(errorMsg.iValue, anOperationMask);
+	    }
+	else if (iHostResolverNotify)
+	    {
+		LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tSubConnectionError() - passing to host resolver's Error() function"), this) );
+	    iHostResolverNotify->Error(errorMsg.iValue);
+	    }
+	}
+
+void CTransportFlowShim::BindToL(TCFDataClient::TBindTo& aBindTo)
+/**
+Request from control side (at network layer) to indicate that the SubConnection is
+up and running and that we should bind to a Flow below.
+
+@param aLowerFlow Flow below to bind to.
+*/
+	{
+	//provisioning message must come before bindto in case we didn't get it after we've joined
+	//the sub-connection
+
+	NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=BindToL"),
+			this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node()) )
+
+	if (iShuttingDown)
+		{
+		User::Leave(KErrCancel);
+		return;
+		}
+
+	CNetworkFlow::BindToL(aBindTo);
+	if (iLowerFlow && IsBoundToSession())
+		{
+		LockToConnectionInfo();
+		LocalName(iLocalAddress);
+		iLocalAddressSet = ETrue;
+		RemName(iRemoteAddress);
+		iRemoteAddressSet = ETrue;
+		__ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 48));	// legacy flows have no control side; should never get here
+		}
+	else if (iHostResolverNotify)
+	    {//workaroud to indicate to CHostResolver we've got connection info
+	    if (aBindTo.iNodeId.Ptr())
+	        {
+    	    iHostResolverNotify->StartSending();
+	        }
+	    else
+	        {
+            iHostResolverNotify->Error(KErrDisconnected);
+	        }
+	    }
+
+
+
+	}
+
+
+void CTransportFlowShim::Rejoin(const TCFFlow::TRejoin& aRejoinMessage)
+    {
+	LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tRejoin()"), this ));
+	iSubConnectionProvider.Close();
+	iSubConnectionProvider.Open(TNodeCtxId(0, aRejoinMessage.iNodeId));
+    //If already bound there's a potential need to rebind.
+    //As the new control provider for the flow - if different than
+    //the current, rebind.
+    if (iLowerFlow)
+        {
+        PostNoBearer();
+        }
+    }
+
+void CTransportFlowShim::StartFlowL(const TRuntimeCtxId& aSender)
+	{
+	__ASSERT_DEBUG(!iIsStarted, User::Panic(KSpecAssert_ESockSSocksspshm, 49));
+	__ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 50));	// legacy flows have no control side; should never get here
+
+	//We will wait for it and complete the start after we have received it
+	User::LeaveIfError(iStartRequest.Open(iSubConnectionProvider, aSender));
+
+	if (iDCIdle != EClientsPresent)
+		{
+		iStartRequest.ReplyTo(Id(), TEBase::TError(TCFDataClient::TStart::Id(), KErrNotReady).CRef());
+		iStartRequest.Close();
+		return;
+		}
+
+	if (iLowerFlow)
+		{
+		iStartRequest.ReplyTo(Id(), TCFDataClient::TStarted().CRef());
+		iStartRequest.Close();
+		iIsStarted = ETrue;
+		iIsStopped = EFalse;
+		return;
+		}
+
+	//We need a bearer
+		PostNoBearer(); //Ask for bearer if not requested already
+
+	}
+
+void CTransportFlowShim::StopFlow(TCFDataClient::TStop& aMessage)
+	{
+	__ASSERT_DEBUG(iIsStarted, User::Panic(KSpecAssert_ESockSSocksspshm, 51)); //Must be started now
+	__ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 52));	// legacy flows have no control side; should never get here
+
+	// We need to error the socket if the lower protocol stack is not going to do this.  Once a
+	// Bearer() upcall has been received, the lower protocol will call Error() if the connection
+	// goes down.  Before this point, the lower protocol will not call Error(), so StopFlow() calls
+	// from the SCPR are used to error the socket (if the interface start fails).
+	//
+	// The main scenario is the TCP/IP stack as lower protocol which will only call Error() once it
+	// has attached a flow to a route (and hence an interface) which, in turn, only occurs once the
+	// interface is up and data has been sent over the socket.  Note that opening an RSocket on an
+	// RConnection but not transferring any data will not cause the TCP/IP stack to attach the flow
+	// to the route and hence not call Error() if the interface comes down.
+
+	if (IsBoundToSession() && !iUseBearerErrors)
+	    {
+    	Error(aMessage.iValue, EErrorAllOperations);
+	    }
+
+	if (iLowerFlow)
+		{
+		iLowerFlow->Unbind(NULL,NULL);
+		iLowerFlow = NULL;
+		}
+	iLowerControl = NULL;
+
+	iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStopped(aMessage.iValue).CRef());
+	iIsStarted = EFalse;
+	iIsStopped = ETrue;
+	}
+
+void CTransportFlowShim::InitDestroy()
+	{
+    __ASSERT_DEBUG(iDCIdle <= EClientsPresent, User::Panic(KSpecAssert_ESockSSocksspshm, 53));
+    iDCIdle = EIdle;
+
+    if(iSubConnectionProvider.IsOpen())	// legacy flows have no control side
+    	{
+    	ProcessDCIdleState();
+    	}
+	else
+		{
+		DeleteThisFlow();
+		}
+	}
+
+void CTransportFlowShim::Destroy()
+	{
+	DeleteThisFlow();
+	}
+
+void CTransportFlowShim::PostNoBearer()
+	{
+	if (!NoBearerGuard())
+		{
+		iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TNoBearer().CRef());
+		SetNoBearerGuard();
+		}
+	}
+
+void CTransportFlowShim::PostDataClientRouted()
+	{
+ 	if (iLocalAddressSet && iRemoteAddressSet
+	&& iRemoteAddress.Family() != KAFUnspec && !iDataClientRoutedGuard)
+		{
+		iSubConnectionProvider.PostMessage(
+			Id(),
+			TCFIPMessages::TDataClientRouted(
+				TAddrUpdate(
+					iLocalAddress,
+					iRemoteAddress,
+					iFlowParams.iProtocol,
+					iIfInfo.iIAPId)
+				).CRef()
+			);
+		iDataClientRoutedGuard = ETrue;
+		}
+	}
+
+void CTransportFlowShim::ClearDataClientRoutedGuard()
+	{
+	iDataClientRoutedGuard = EFalse;
+	}
+
+
+/*
+Store the provision information passed from the Control side.
+@param TProvisionConfig Message recd.
+*/
+void CTransportFlowShim::StoreProvision(TCFDataClient::TProvisionConfig& aMessage)
+	{
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+	//find access point inforamtion from the message
+	iAccessPointConfig.Close();
+	iAccessPointConfig.Open(aMessage.iConfig);
+	//Find extension appended at NetMcpr and store it
+	//Presently will extract CSAPSetOpt window extensions
+	ExtractSetOptExtensions();
+#else
+	(void)aMessage;
+#endif
+	}
+/*
+Extract extensions appended to TProvisionConfig specific to IPTransport.
+*/
+void CTransportFlowShim::ExtractSetOptExtensions()
+	{
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+	//Extract TCP receive window specific provisionconfig extension.
+	iProtocolOptions = static_cast< const CSAPSetOpt*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CSAPSetOpt::EUid,CSAPSetOpt::ETypeId)));
+#endif
+	}
+
+#ifdef SYMBIAN_NETWORKING_UPS
+
+TBool CTransportFlowShim::ActivityRunning()
+/**
+Determine whether we are in the middle of a NoBearer activity.
+
+In other words, we are waiting for a response from a previously transmitted TNoBearer.
+
+@return ETrue if in the middle of one of this activity, else EFalse.
+*/
+	{
+	return NoBearerGuard();
+	}
+
+//
+// Default implementations of CTransportFlowShim virtuals.
+//
+
+TInt CTransportFlowShim::SetupForNoBearerOnSend()
+	{
+	return KErrNotSupported;
+	}
+
+void CTransportFlowShim::PreUnbind()
+	{
+	}
+
+TInt CTransportFlowShim::ProcessReceivedL(TSignatureBase& /*aCFMessage*/)
+	{
+	return KErrNotSupported;
+	}
+
+//
+// CUpsTransportFlowShim methods
+//
+// This class contains User Prompt Service (UPS) specific functionality.
+//
+
+CUpsTransportFlowShim* CUpsTransportFlowShim::NewL(CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConn, CProtocolIntfBase* aProtocolIntf)
+/**
+Create a new CUpsTransportFlowShim instanace.
+
+Note: this method replaces CTransportFlowShim::NewL() in UPS builds.
+*/
+	{
+	return new (ELeave) CUpsTransportFlowShim(aFactory, aSubConn, aProtocolIntf);
+	}
+
+TInt CUpsTransportFlowShim::SetupForNoBearerOnSend()
+/**
+Called just before a TNoBearer message is posted for Host Resolver processing.
+
+Perform the Platform Security capability check and populate the UPS Access Point Config (APC) extension.
+
+@return KErrNone or a system wide error code.
+*/
+	{
+	// For UPS, the capability check has been moved from the provider SAP to here so that
+	// the capability check result is available at the time of the NoBearer message being sent.
+	__ASSERT_DEBUG(iSecurityChecker, User::Panic(KSpecAssert_ESockSSocksspshm, 54));
+	TInt result = iSecurityChecker->CheckPolicy(KPolicyNetworkServices, "UpsTransportFlowShim (SetupForNoBearerOnSend)");
+
+	// At this point, result can contain:
+	//
+	// KErrNone					Capability check passed.
+	// KErrPermissionDenied		Capability check failed.
+	// KErrCompletion			Special error code that instructs us not to perform any UPS check.
+	//							This is a means for upper layers to disable UPS checking in circumstances
+	//							where the UPS check will be catered for by a higher layer.
+	if (result != KErrCompletion)
+		{
+		if (UpsEnabled())
+			{
+			// UPS enabled - fill in the APC structure associated with TNoBearer message
+			PopulateUpsExtension(result);
+			}
+		else
+			{
+			// UPS disabled - fall back to the Platform Security check
+			if (result != KErrNone)
+				{
+				return TSendResult(result);
+				}
+			}
+		}
+	return KErrNone;
+	}
+
+void CUpsTransportFlowShim::PreUnbind()
+/**
+Called just before an unbind happens.
+
+Ensure that we cancel any running activities.
+
+(there are no activities on the data side in the formal sense - the term is used
+to describe NoBearer processing happening locally).
+*/
+	{
+	if (ActivityRunning())
+		{
+		// @TODO PREQ1116 - should we be able to have a NoBearer and a PolicyCheckRequest pending
+		// at the same time ?  Should we prevent it?
+
+		// Cancel any pending NoBearer activity.  This has become necessary because the UPS authorisation
+		// can cause the NoBearer activity to be pending for an indefinate period of time.  When the
+		// cancel reaches the MCpr, the UPS authorisation will be cancelled and a TError will eventually
+		// be received and processed in SubConnectionError().
+		iSubConnectionProvider.PostMessage(Id(), Messages::TEBase::TCancel().CRef());
+		}
+	}
+
+TInt CUpsTransportFlowShim::SetOption(TUint aLevel, TUint aName, const TDesC8 &anOption)
+/**
+Process SetOption() requests from upper layer
+*/
+	{
+	if (aLevel == KSOLProvider)
+		{
+		if (aName == KSoOwnerInfo)
+			{
+			// Upper layer communicating process and thread id of client opening subsession.
+			__ASSERT_DEBUG(anOption.Size() == sizeof(TSoOwnerInfo), User::Panic(KSpecAssert_ESockSSocksspshm, 55));
+
+			const TSoOwnerInfo* soOwnerInfoPtr = reinterpret_cast <const TSoOwnerInfo*> (anOption.Ptr());
+			__ASSERT_DEBUG(soOwnerInfoPtr, User::Panic(KSpecAssert_ESockSSocksspshm, 56));
+
+			iThreadId  = soOwnerInfoPtr->iThreadId;
+			iProcessId = soOwnerInfoPtr->iProcessId;
+			}
+		else
+		if (aName == KSoSetPlatSecApi)
+			{
+			// Upper layer communicating an 'M' class instance that can be used for retrieving
+			// process and thread id of client performing current operation.
+			__ASSERT_DEBUG(anOption.Size() == sizeof(const MPlatsecApiExt*), User::Panic(KSpecAssert_ESockSSocksspshm, 57));
+			iPlatsecIf = *reinterpret_cast <const MPlatsecApiExt* const *> (anOption.Ptr());
+			}
+
+		if (IsHostResolver())
+			{
+			// For Host Resolvers, the SetOption() is only for us to store the thread and process id,
+			// so we are complete.  There is no iProvider in this case to propagate the call to.
+			__ASSERT_DEBUG(Provider() == NULL, User::Panic(KSpecAssert_ESockSSocksspshm, 58));
+			return KErrNone;
+			}
+		}
+
+	return CTransportFlowShim::SetOption(aLevel, aName, anOption);
+	}
+
+TInt CUpsTransportFlowShim::SecurityCheck(MProvdSecurityChecker* aChecker)
+/**
+Called from upper layer to ask the SAP provider to perform a security policy check
+on the client process.
+
+@param aChecker Security checker class instance
+@return KErrNone or a system wide error code
+*/
+	{
+	// Save away the security checker class so that we can perform capability checking
+	// here instead of in the TCP/IP stack.
+	//
+	// Note: iSecurityChecker can get overwritten as a result of ProtocolManager::TransferSocketL(),
+	// so don't ASSERT(iSecurityChecker == NULL).
+	iSecurityChecker = aChecker;
+
+	if (Provider())
+		{
+		// Sockets
+		__ASSERT_DEBUG(!IsHostResolver(), User::Panic(KSpecAssert_ESockSSocksspshm, 59));
+		return Provider()->SecurityCheck(aChecker);
+		}
+	else
+		{
+		// Host Resolvers
+		__ASSERT_DEBUG(IsHostResolver(), User::Panic(KSpecAssert_ESockSSocksspshm, 60));
+		return KErrNone;
+		}
+	}
+
+void CUpsTransportFlowShim::GetProcessAndThreadId(TProcessId& aProcessId, TThreadId& aThreadId) const
+/**
+Retrieve the process and thread id corresponding to the current Socket/Host Resolver request.
+
+The iProcessId and iThreadId variables contain the ids at the time of subsession open, which
+is not necessarily the same as the ids of the client performing the actual request.  The
+call to iPlatsecIf->GetProcessAndThreadId() will actually go to the layer above for processing
+and retrieve the ids associated with the current pending request.
+
+@param aProcessId variable receiving process id (out)
+@param aThreadId variable receiveing thread id (out)
+@return KErrNone, else a system wide error code.
+*/
+	{
+	TInt err = KErrGeneral;
+	if (iPlatsecIf)
+		{
+		err = iPlatsecIf->GetProcessAndThreadId(aProcessId, aThreadId);
+		}
+
+	if (err != KErrNone)
+		{
+		aProcessId = iProcessId;
+		aThreadId = iThreadId;
+		}
+	}
+
+void CUpsTransportFlowShim::NoBearer(const TDesC8& aConnectionParams)
+/**
+Upcall from protocol indicating no underlying bearer for the socket.
+@param aConnectionParams Additional connection parameters from the stack, in the form of a
+human readable string.  Initially, the required protocols (e.g. "protocol=ip").
+
+This method overrides CTransportFlowShim::NoBearer() for UPS specific handling.
+*/
+	{
+	(void)aConnectionParams;
+	LOG( ESockLog::Printf(_L8("CUpsTransportFlowShim %08x:\tNoBearer(%S)"), this, &aConnectionParams) );
+
+	// Perform the Platform Security check (moved from the Provider SAP to here in order to
+	// obtain the platsec result as part of UPS processing).
+
+	TInt result = iSecurityChecker->CheckPolicy(KPolicyNetworkServices, "TransportFlowShim (NoBearer)");
+
+	NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=NoBearer(%S)"),
+			this, static_cast<Messages::ANode*>(this), static_cast<Messages::ANode*>(this), &aConnectionParams) )
+
+	// At this point, result can contain:
+	//
+	// KErrNone					Capability check passed.
+	// KErrPermissionDenied		Capability check failed.
+	// KErrCompletion			Special error code that instructs us not to perform any UPS check.
+	//							This is a means for upper layers to disable UPS checking in circumstances
+	//							where the UPS check will be catered for by a higher layer.
+
+	TBool disableUpsCheck = (result == KErrCompletion);
+	if (!disableUpsCheck && !UpsEnabled())
+		{
+		// UPS disabled - fall back to the Platform Security check
+		if (result != KErrNone)
+			{
+			Error(result, MSocketNotify::EErrorSend | MSocketNotify::EErrorConnect);
+			return;
+			}
+		}
+
+	if(!IsStopped())
+		{ // Prevent sending NoBearer if DataClientStop was received
+		ParseNoBearerParams(aConnectionParams);
+		if (iIsScoped)
+		    {
+		    if (!disableUpsCheck && UpsEnabled())
+		        {
+	            // Do not perform standard NoBearer() processing for "gratuitous" NoBearer() calls.  The
+	            // TCP/IP stack already has enough scope information to select an interface, but this
+	            // probably will be different from the "default" implicit interface that the control side will
+	            // select.  The consequence is that the TransportFlowShim could end up being associated with the
+	            // wrong SCpr.  Note that this is not a problem introduced by UPS functionality - it exists in
+	            // the Networking Subsystem anyway.  The "Bearer()-only" cases in pre-UPS code do not result in
+	            // the TCP/IP stack generating a NoBearer() (just a Bearer()), so the TransportFlowShim never
+	            // gets associated with any SCpr.  We are just replicating this behaviour for UPS functionality,
+	            // by performing a TPolicyCheckRequest sequence for the sake of UPS checking, but otherwise the
+	            // behaviour mirrors what is already present (i.e. does nothing else).
+	            PostPolicyCheckRequest(result);
+		        }
+            else
+                {
+                // If no UPS handling is required, tell the TCP/IP stack that it can go ahead and route the flow.
+				IssueScopedNoBearerResponse();
+                }
+		    }
+		else
+		if (LockToConnectionInfo() != KErrNone)
+		    {
+			__ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 61));	// legacy flows have no control side; should never get here
+			// If UPS is enabled, fill in the APC structure to accompany the TNoBearer
+			// Do this even if disableUpsCheck is set so that the APC will contain KErrCompletion.
+			if (UpsEnabled())
+				{
+				PopulateUpsExtension(result);
+				}
+	        PostNoBearer();
+		    }
+		ClearUseBearerErrors();
+		ClearDataClientRoutedGuard();
+		}
+	else
+	    {
+	    // Return an error on an attempt to issue a SendTo() on an explicit socket (datagram) whose corresponding
+	    // connection has gone down (BR2639).  Note that the use of KErrDisconnected should NOT be documented -
+	    // in future, we may wish to return the same error as the connection itself experienced.
+	    Error(KErrDisconnected, MSessionControlNotify::EErrorSend);
+	    }
+	}
+
+void CUpsTransportFlowShim::PopulateUpsExtension(TInt aPolicyCheckResult) const
+/**
+Populate the UPS Access Point Config structure with the required information in preparation for
+a TNoBearer message to be transmitted.
+
+@param aPolicyCheckResult result of Platform Security check
+*/
+	{
+	__ASSERT_DEBUG(iUpsExtension, User::Panic(KSpecAssert_ESockSSocksspshm, 62));
+	iUpsExtension->SetPolicyCheckResult(aPolicyCheckResult);
+
+	TProcessId processId;
+	TThreadId threadId;
+	GetProcessAndThreadId(processId, threadId);
+
+	iUpsExtension->SetProcessId(processId);
+	iUpsExtension->SetThreadId(threadId);
+
+	if (IsHostResolver())
+		{
+		// Null destination name for Host Resolvers.
+		iUpsExtension->ResetDestinationAddr();
+		iUpsExtension->SetDestinationAddrType(ETNone);
+		}
+	else
+		{
+		// @TODO PREQ1116 - something better than this cast?  For example, argument to
+		// SetDestinationAddr() could become a "const TDesC8&" perhaps (without worrying about
+		// error checking) ?
+		iUpsExtension->SetDestinationAddr(static_cast<TUpsDestinationAddr>(iRemoteAddress));
+		iUpsExtension->SetDestinationAddrType(ETSockAddress);
+		}
+	}
+
+
+void CUpsTransportFlowShim::PostPolicyCheckRequest(TInt aPolicyCheckResult)
+/**
+Post a TPolicyCheckRequest message to the SCpr
+
+@param aPolicyCheckResult result of Platform Security check
+*/
+	{
+	if (!PolicyCheckRequestPending())
+		{
+		__ASSERT_DEBUG(UpsEnabled(), User::Panic(KSpecAssert_ESockSSocksspshm, 63));	// UPS should not be "short circuited" off
+
+		TProcessId processId;
+		TThreadId threadId;
+		GetProcessAndThreadId(processId, threadId);
+
+		const TPolicyCheckRequestParams params(processId, threadId, aPolicyCheckResult, static_cast<TUpsDestinationAddr>(iRemoteAddress), ETSockAddress);
+		iSubConnectionProvider.PostMessage(Id(), UpsMessage::TPolicyCheckRequest(params).CRef());
+		SetPolicyCheckRequestPending(ETrue);
+		}
+	}
+
+void CUpsTransportFlowShim::ProcessPolicyCheckResponse(const UpsMessage::TPolicyCheckResponse& aResponse)
+/**
+Process a TPolicyCheckResponse from the SCpr.
+
+If UPS authorisation was granted, prod the TCP/IP stack into re-attaching the flow (based on the original
+scope id in the socket address).
+
+@param aResponse TPolicyCheckResponse message
+*/
+	{
+	SetPolicyCheckRequestPending(EFalse);
+
+	if (iDCIdle == EIdle)
+		{
+		ProcessDCIdleState();
+		}
+	else
+		{
+		if (aResponse.iValue == KErrNone)
+			{
+			if (iIsScoped)
+				{
+				// If socket address already has a scope id, do not tell the stack to use our
+				// idea of NetworkId.  If we do, our idea of the NetworkId could be a mismatch
+				// with the existing scope id, and we could end up with an SCPR which represents a
+				// different interface from the one that the TCP/IP stack has chosen based on the scope
+				// id.  Use the special KNetworkIdFromAddress value for NetworkId which the TCP/IP stack
+				// recognises as meaning "attempt to attach the flow to a route, but determine the
+				// NetworkId from the socket address, as you've already indicated in the NoBearer()
+				// that you have enough information to do so".
+				//
+				// This code has become necessary due to the UPS support, which forces the
+				// TCP/IP stack to issue NoBearer() calls in circumstances where it never used to
+				// before, to give an opportunity to perform UPS authorisation.
+				IssueScopedNoBearerResponse();
+				}
+			}
+		else
+			{
+			Error(aResponse.iValue, MSocketNotify::EErrorSend | MSocketNotify::EErrorConnect);
+			}
+		}
+	}
+
+void CUpsTransportFlowShim::IssueScopedNoBearerResponse()
+/**
+After a gratuitous NoBearer() upcall has been issued to us (to allow a chance for UPS checking to occur before
+a flow is routed), issue the response to the TCP/IP stack indicating that it can now route the flow and continue.
+ */
+    {
+    TSoIfConnectionInfo info;
+    TPckg<TSoIfConnectionInfo> ifInfo(info);
+    info.iIAPId = 0;
+    info.iNetworkId = KNetworkIdFromAddress;
+    __ASSERT_DEBUG(Provider(), User::Panic(KSpecAssert_ESockSSocksspshm, 64));
+    SetIfInfo(info);
+    Provider()->SetOption(KSOLProvider, static_cast<TUint>(KSoConnectionInfo), ifInfo);
+    }
+
+void CUpsTransportFlowShim::ParseNoBearerParams(const TDesC8& aConnectionParams)
+/**
+Parse the descriptor passed in NoBearer() upcall.
+
+Main raison d'etre for this routine is to check whether the "scoped" string was
+part of the descriptor contents (indicating a "gratuitous" NoBearer()).
+
+@param aConnectionParams Argument passed in NoBearer() upcall from lower layer.
+*/
+	{
+	_LIT8(KScoped, "scoped");
+	if (aConnectionParams.Find(KScoped()) != KErrNotFound)
+		{
+		// "scoped" string signifies a "gratuitous" NoBearer().  The flow could have been routed
+		// without a NoBearer() (i.e. it was scoped enough to route it), but the NoBearer() was
+		// generated anyway so that ESock could perform UPS checking before routing it.
+		iIsScoped = ETrue;
+		}
+	else
+		{
+		iIsScoped = EFalse;
+		}
+	}
+
+TInt CUpsTransportFlowShim::ProcessReceivedL(TSignatureBase& aCFMessage)
+/*
+Process any SCpr messages specific to UPS functionality.
+
+Called from base class (CTransportFlowShim) before it attempts to process the incoming message.
+
+@param aCFMessage Message from SCpr
+@return KErrNone if we have handled the incoming message and no more processing is necessary,
+KErrNotSupported if have not handled the incoming message, else a system wide error code.
+*/
+    {
+	// Check for special UPS messages.
+	if (UpsMessage::ERealmId == aCFMessage.MessageId().Realm())
+		{
+        switch (aCFMessage.MessageId().MessageId())
+		  {
+		case UpsMessage::TPolicyCheckResponse::EId :
+			{
+			// Support for UPS
+			const UpsMessage::TPolicyCheckResponse& policyCheckResponseMsg = static_cast<UpsMessage::TPolicyCheckResponse&>(aCFMessage);
+			ProcessPolicyCheckResponse(policyCheckResponseMsg);
+			return KErrNone;
+			}
+		  }
+		}
+	else
+	if (TCFDataClient::ERealmId == aCFMessage.MessageId().Realm())
+		{
+		switch (aCFMessage.MessageId().MessageId())
+		  {
+		case TCFDataClient::TProvisionConfig::EId :
+			{
+           	// Get a pointer to the UPS Access Point Config structure.  If not present, then UPS is
+           	// disabled ("short circuited") and iUpsExtension remains set to NULL.
+           	const  TCFDataClient::TProvisionConfig& provisionMsg = static_cast<TCFDataClient::TProvisionConfig&>(aCFMessage);
+           	
+           	iAccessPointConfig.Close();
+           	iAccessPointConfig.Open(provisionMsg.iConfig);
+           	
+			const Meta::SMetaData* const extension = AccessPointConfig().FindExtension(
+			        STypeId::CreateSTypeId(CUPSAccessPointConfigExt::EUPSAccessPointConfigUid, CUPSAccessPointConfigExt::ETypeId));
+			if (extension)
+				{
+				iUpsExtension = const_cast<CUPSAccessPointConfigExt*> (static_cast<const CUPSAccessPointConfigExt*>(extension));
+				}
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+			//
+			//Store the provision config message,
+			//to store the Provision config message
+			//which will have TCP Receive window sizes.
+            StoreProvision(static_cast<TCFDataClient::TProvisionConfig&>(aCFMessage));
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+
+			return KErrNone;
+	       	}
+		  }
+		}
+	return KErrNotSupported;
+	}
+
+void CUpsTransportFlowShim::SubConnectionError(const Messages::TEBase::TError& aErrorMsg, TUint anOperationMask)
+/**
+Handle errors from SCpr
+
+@param aErrorMsg The incoming TError message
+@param anOperationMask Pending operations to be error'd.
+*/
+	{
+	if (aErrorMsg.iMsgId == UpsMessage::TPolicyCheckRequest::Id())
+		{
+		// Previously sent TPolicyCheckRequest failed.
+		SetPolicyCheckRequestPending(EFalse);
+		ProcessDCIdleState();
+		}
+
+	CTransportFlowShim::SubConnectionError(aErrorMsg, anOperationMask);
+	}
+
+TBool CUpsTransportFlowShim::ActivityRunning()
+/**
+Determine whether we are in the middle of NoBearer or PolicyCheckRequest processing.
+
+In other words, we are waiting for a response from a previously transmitted TNoBearer
+or TPolicyCheckRequest.
+
+@return ETrue if in the middle of one of this activity, else EFalse.
+*/
+	{
+	return PolicyCheckRequestPending() || CTransportFlowShim::ActivityRunning();
+	}
+
+#endif //f_NETWORKING_UPS
+
+
+
+//Register the class variable
+START_ATTRIBUTE_TABLE(CSAPSetOpt,CSAPSetOpt::EUid, CSAPSetOpt::ETypeId)
+END_ATTRIBUTE_TABLE()
+
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+//Set the protocol options
+void CTransportFlowShim::SetProtocolOptions()
+	{
+	if(iProvider && iProtocolOptions)
+		{
+		for(TInt iter = 0; iter < iProtocolOptions->iOption.Count(); iter++)
+			{
+   	    	TPtr8 optionDesProtOptVal( (TUint8*)&(iProtocolOptions->iOption[iter].iOptionValue), sizeof(TUint), sizeof(TUint) );
+			iProvider->SetOption(iProtocolOptions->iOption[iter].iOptionName,iProtocolOptions->iOption[iter].iOptionLevel, optionDesProtOptVal);
+			}
+		}
+	}
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+
+EXPORT_C CSAPSetOpt::CSAPSetOpt()
+	{
+	}
+
+CSAPSetOpt::~CSAPSetOpt()
+	{
+	//Free the RArray resources.
+	iOption.Close();
+	}
+
+//Add the option to the RArray variable
+EXPORT_C void CSAPSetOpt::AddProtocolOptionL(TUint aOptionName, TUint aOptionLevel, TUint aOptionValue)
+	{
+	TProtocolOption opt;
+	opt.iOptionName = aOptionName;
+	opt.iOptionLevel = aOptionLevel;
+	opt.iOptionValue = aOptionValue;
+	iOption.AppendL(opt);
+	}
+
+//Update the value for an option
+EXPORT_C void CSAPSetOpt::UpdateProtocolOption(TUint aOptionName, TUint aOptionLevel, TUint aOptionValue)
+	{
+	for(TInt i = 0; i < iOption.Count(); i++)
+		if((iOption[i].iOptionName == aOptionName) && (iOption[i].iOptionLevel == aOptionLevel))
+			iOption[i].iOptionValue = aOptionValue;
+	}
+
+
+