networkcontrol/ipnetworklayer/src/nif.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkcontrol/ipnetworklayer/src/nif.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,473 @@
+// 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:
+// CNifIfBase and CProtocolBase shim layer functionality
+// 
+//
+
+/**
+ @file nif.cpp
+*/
+
+#include <e32base.h>
+#include <networking/qos_if.h>
+#include <nifmbuf.h>
+#include <es_prot_internal.h>
+#include <comms-infras/ss_subconnflow.h>
+#include <comms-infras/ss_protflow.h>
+
+#include "in_sock.h"
+#include "in_iface.h"
+#include "in6_if.h"
+
+#include "flow.h"
+#include "nif.h"
+#include "notify.h"
+#include "panic.h"
+#include "ItfInfoConfigExt.h"
+
+#include "nif4.h"		// for CIPShimIfBase::NewL()
+#include "nif6.h"		// for CIPShimIfBase::NewL()
+
+#include "IPProtoDeMux.h"
+
+#include "../addressinfohook/inc/hookaddrinfo.h"
+
+
+using namespace ESock;
+
+//
+// CIPShimIfBase methods
+//
+
+CIPShimIfBase* CIPShimIfBase::NewL(const TDesC8& aProtocol, CIPShimProtocolIntf *aIntf)
+	{
+	CIPShimIfBase* intf = NULL;
+
+	if (aProtocol.CompareF(KProtocolIp()) == 0)
+		{
+		intf = CIPShimIfBase4::NewL(aProtocol);
+		}
+	else
+	if (aProtocol.CompareF(KProtocolIp6()) == 0)
+		{
+		intf = CIPShimIfBase6::NewL(aProtocol);
+		}
+	else
+		{
+		// only support "ip" and "ip6" protocol names
+		User::Leave(KErrArgument);
+		}
+	intf->SetProtocolIntf(aIntf);
+	
+	return intf;
+	}
+
+
+CIPShimIfBase::CIPShimIfBase(const TDesC8& aProtocolName)
+	: CNifIfBase(), iBinderReady(EFalse), iProtIntf(NULL)
+/**
+CIPShimIfBase constructor
+*/
+	{
+	__CFLOG_2(KIPProtoTag1, KIPProtoTag2, _L8("CIPShimIfBase %08x:\tCIPShimIfBase(aProtocolName '%S')"), this, &aProtocolName);
+	iProtocolName.Copy(aProtocolName);
+	}
+
+CIPShimIfBase::~CIPShimIfBase()
+	{
+	__CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\t~CIPShimIfBase()"), this);
+	delete iShimNotify;
+
+	for (TInt i = 0; i < iProtoBinders.Count(); i++)
+		{
+		iProtoBinders[i]->Unbind();
+		}
+		
+	iProtoBinders.Close();
+
+/*	ASSERT(iProtIntf);
+	iProtIntf->NifDisappearing(this);*/
+	
+	/*
+	 * it's not legal to assume that this pointer isn't NULL. There can be
+	 * OOM conditions in the constructor (which doesn't follow the official
+	 * 2 way constructions [in nif4 or nif6]) which can cause not to initialize
+	 * this pointer.
+	 */
+	if (iProtIntf)
+		{
+		iProtIntf->NifDisappearing(this);
+		}
+	}
+
+void CIPShimIfBase::ConstructL()
+	{
+	iShimNotify = CIPShimNotify::NewL(this);
+	// Setup the CNifIfBase::iNotify for the benefit of the TCP/IP stack to call us
+	iNotify = static_cast<MNifIfNotify*>(iShimNotify);	
+	}
+
+void CIPShimIfBase::StartL()
+	{
+	if (iUpperProtocol)
+		{
+		return;
+		}
+		
+	TBuf<KMaxProtocolNameSize> protocolName;
+	protocolName.Copy(iProtocolName);
+	__CFLOG_2(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tStartL(): FindAndLoadProtocolL('%S')"), this, &protocolName);    	
+	iUpperProtocol = SocketServExt::FindAndLoadProtocolL(protocolName);
+	iUpperProtocol->Open();
+	
+	
+	// Retrieve the MNifIfUser derived object from the upper protocol
+
+	TNifIfUser ifuser;
+	TInt err = iUpperProtocol->GetOption(KNifOptLevel, KNifOptGetNifIfUser, ifuser, 0);
+
+	if (err == KErrNone)
+		{
+		iNifUser = ifuser();
+
+		// Inform the upper protocol of our CNifIfBase derived interface.
+		// (the second argument does not appear to be used in current SymbianOS, so pass 0).
+		__CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tStartL(): IfUserNewInterfaceL()"), this);    	
+
+		CleanupClosePushL(*iUpperProtocol);
+		iNifUser->IfUserNewInterfaceL(this, 0);	// Note: increments CNifIfBase reference
+		CleanupStack::Pop();
+
+		// Cleanup Note: if you ever add a leaving function after IfUserNewInterfaceL() above,
+		// then you'll need to arrange for CleanupSignalNewInterface() to be called here (it is pushed
+		// onto the cleanup stack later as there are no subsequent leaving functions in this routine.
+
+		iNifUser->IfUserOpenNetworkLayer();				// Note: increments protocol reference count
+		}
+	else
+		{
+		__CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimIfBase %08x:\tStartL(): Error %d issuing KNifOptGetNifIfUser to protocol"), this, err));
+		User::Leave(err);
+		}
+	}
+
+void CIPShimIfBase::BindToL(CIPProtoBinder* aIPProtoBinder)
+	{
+	aIPProtoBinder->BindL(this);
+	iProtoBinders.AppendL(aIPProtoBinder);
+	}
+
+void CIPShimIfBase::UnbindFrom(CIPProtoBinder* aIPProtoBinder)
+	{
+	TInt index = iProtoBinders.Find(aIPProtoBinder);
+
+	// shouldn't try to unbind from a binder we're not bound to
+	ASSERT(index >= 0);
+	iProtoBinders.Remove(index);
+	aIPProtoBinder->Unbind();
+	}
+
+//-=========================================
+// MUpperDataReceiver methods
+//-=========================================        
+void CIPShimIfBase::Process(RMBufChain& aData)
+	{
+	iUpperProtocol->Process(aData, reinterpret_cast<CProtocolBase*>(this));
+	}
+
+//-=========================================
+// MUpperControl methods
+//-=========================================        
+void CIPShimIfBase::StartSending()
+	{
+	if (!iBinderReady)
+		{
+		// Get config info (for first time)
+		__CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tStartSending() (first time)"), this);
+		GetConfigFirstTime();
+		iBinderReady = ETrue;
+		}
+
+	if (iUpperProtocol)
+		{
+		// Call StartSending(...) in the context of "downstream path ready for first time"
+		__CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tStartSending()"), this);
+		iUpperProtocol->StartSending(reinterpret_cast<CProtocolBase*>(this));
+		}
+	}
+	
+void CIPShimIfBase::Error(TInt anError)
+	{
+	iProtoBinders[0]->Error(anError);
+	}
+
+#ifdef _DEBUG
+void CIPShimIfBase::BindL(TAny* aId)
+#else
+void CIPShimIfBase::BindL(TAny* /*aId*/)
+#endif
+/**
+Called from upper protocol to pass its CProtocolBase pointer
+*/
+	{
+	//[401TODO] RZ: Is this assumption safe?
+	ASSERT(iUpperProtocol == aId);
+	
+	if (iBinderReady && iUpperProtocol)
+		{
+		__CFLOG_2(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tBindL(%08x)"), this, aId);
+		iUpperProtocol->StartSending(reinterpret_cast<CProtocolBase*>(this));
+		}
+	}
+
+void CIPShimIfBase::CleanupInterface(TInt aError)
+	{
+	__CFLOG_2(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %x:\tCleanupInterface(%d)"), this, aError);    	
+	iUpperProtocol->Close();
+	iUpperProtocol = NULL;
+	
+	if(iInterfaceNameRecorded && iProtoBinders.Count())
+		{
+        XInterfaceNames* itfNames = static_cast<XInterfaceNames*>(
+			const_cast<Meta::SMetaData*>(iProtoBinders[0]->Flow().AccessPointConfig().FindExtension(XInterfaceNames::TypeId())));
+		itfNames->RemoveInterfaceName(this);
+		}
+
+	// IfUserInterfaceDown may delete this object, so create a stack variable for the NifIfUser
+	// so CloseNetworkLayer can be called on it.
+	MNifIfUser* nifUser = iNifUser; 
+	nifUser->IfUserInterfaceDown(aError, this);  	// Note: decrements CNifIfBase reference
+	nifUser->IfUserCloseNetworkLayer();				// Note: decrements protocol reference count
+	}
+
+void CIPShimIfBase::RemoveInterfaceName(CIPProtoBinder* aBinder)
+	{
+	ASSERT(aBinder);
+	
+	if(iInterfaceNameRecorded)
+		{
+        XInterfaceNames* itfNames = static_cast<XInterfaceNames*>(
+			const_cast<Meta::SMetaData*>(aBinder->Flow().AccessPointConfig().FindExtension(XInterfaceNames::TypeId())));
+		itfNames->RemoveInterfaceName(this);
+		}
+	}
+
+
+void CIPShimIfBase::Release(TInt aError)
+	{
+	/* CleanupInterface will delete the interface when it is done if refcount is 0 (it will decrement it itself).
+	   If iRefCount 0 when release is called, Start must never have been
+	   called on this nif.  */
+	if (iProtoBinders.Count())
+		{
+		return;	//can't go away if we still have binders
+		}
+	   
+	if (iRefCount == 0)
+		{
+		delete this;
+		}
+	else
+		{
+		CleanupInterface(aError);
+		}
+	}
+
+TInt CIPShimIfBase::State()
+	{
+	return EIfDown;
+	}
+
+TInt CIPShimIfBase::ServiceHwAddrControl(TDes8& aOption)
+/**
+Service KSoIfHardwareAddr calls from upper protocol
+*/
+	{
+	ASSERT(aOption.Length() == sizeof(TSoIfHardwareAddr));
+	if (iProtoBinders.Count())
+		{
+		//[401TODO] RZ: we're probably need fixed array to avoid index changing
+		return iProtoBinders[0]->Control(KSOLInterface, KSoIfHardwareAddr, aOption);		
+		}
+	else
+		{
+		__CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tServiceHwAddrControl(): no binders"), this);
+		return KErrNotReady;
+		}
+	}
+
+TInt CIPShimIfBase::ServiceConnInfo(TDes8& aOption)
+/**
+Service KSoIfGetConnectionInfo calls from upper protocol
+*/
+	{
+	ASSERT(aOption.Length() == sizeof(TSoIfConnectionInfo));
+	TUint8* ptr = const_cast<TUint8*>(aOption.Ptr());
+	TSoIfConnectionInfo& returnedInfo = reinterpret_cast<TSoIfConnectionInfo&>(*ptr);
+
+	returnedInfo.iIAPId = iConnectionInfo.iIapId;
+	returnedInfo.iNetworkId = iConnectionInfo.iNetId;
+
+	return KErrNone;
+	}
+
+TInt CIPShimIfBase::Control(TUint aLevel, TUint aName, TDes8& aOption, TAny* aSource)
+	{
+	__CFLOG_3(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tControl(aLevel 0x%x, aName 0x%x)"), this, aLevel, aName);
+	if (aLevel == KSOLInterface)
+		{
+		switch (aName)
+			{
+		case KSoIfInfo:
+			/* FALLTHROUGH */
+		case KSoIfInfo6:
+			return ServiceInfoControl(aOption, aName);
+
+		case KSoIfConfig:
+			return ServiceConfigControl(aOption);
+
+		case KSoIfHardwareAddr:
+			return ServiceHwAddrControl(aOption);
+
+		case KSoIfGetConnectionInfo:
+			return ServiceConnInfo(aOption);			
+		case 0x734:
+			iHookAddressInfo = (CHookAddressInfo*)aSource;
+			return KErrNone;
+		default:
+			break;
+			}
+		}
+		
+	if (iProtoBinders.Count())
+		{
+		//[401TODO] RZ: we're probably need fixed array to avoid index changing
+		return iProtoBinders[0]->Control(aLevel, aName, aOption);
+		}
+	return KErrNotReady;	
+	}
+
+void CIPShimIfBase::Info(TNifIfInfo& aInfo) const
+	{
+	// Fill in the TNifIfInfo::iName field, which is used by TCP/IP
+	if (iProtoBinders.Count())
+		{
+		//[401TODO] RZ: we're probably need fixed array to avoid index changing
+		iProtoBinders[0]->GetName(aInfo.iName);
+
+		if(!iInterfaceNameRecorded)
+			{
+			XInterfaceNames* itfNames = static_cast<XInterfaceNames*>(
+				const_cast<Meta::SMetaData*>(iProtoBinders[0]->Flow().AccessPointConfig().FindExtension(XInterfaceNames::TypeId())));
+			itfNames->AddInterfaceNameL(this, aInfo.iName);
+			iInterfaceNameRecorded = ETrue;
+			}
+		}	
+
+	//[401TODO] DL: get rid of magic number
+	aInfo.iVersion = TVersion(78,96,12453);
+
+	}
+
+TInt CIPShimIfBase::Send(RMBufChain& aPdu, TAny* /*aSource*/)
+/**
+Called from upper protocol to send a data packet.
+
+@param aPdu packet to send
+@param aSource unused
+@return 0 if upper protocol should block until receipt of StartSending(), else 1.
+*/
+	{
+	// demultiplex packets into the approriate senders
+	const RMBufPktInfo* info = RMBufPacket::PeekInfoInChain(aPdu);
+	CIPProtoBinder *binder = reinterpret_cast<CIPProtoBinder*>(info->iDstAddr.Port());
+	
+    //[401TODO] This check is there purely because of GuQoS interoperability
+    //i.e.: GuQoS colloring packets for the Flow below IPShim. Get rid of
+    //this if statement along with GuQoS.
+	if (iProtoBinders.Count() == 1 || binder == NULL)
+    	{
+    	return iProtoBinders[0]->Send(aPdu);
+    	}
+    else
+        {
+        return binder->Send(aPdu);
+        }
+	}
+
+TInt CIPShimIfBase::Notification(TAgentToNifEventType /*aEvent*/, void * /*aInfo*/)
+/**
+*/
+	{
+	return KErrNotSupported;
+	}
+
+void CIPShimIfBase::SetConnectionInfo(const TConnectionInfo& aConnectionInfo)
+/**
+Called from the Flow to provision the connection info to us.
+*/
+	{
+	iConnectionInfo = aConnectionInfo;
+	}
+
+const TConnectionInfo& CIPShimIfBase::ConnectionInfo()
+/**
+Called from the Flow to provision the connection info to us.
+*/
+	{
+	return iConnectionInfo;
+	}
+
+const TDesC8& CIPShimIfBase::ProtocolName()
+/**
+Return the associated protocol name.
+*/
+	{
+	ASSERT(iProtocolName.Length());
+	return iProtocolName;
+	}
+
+	
+void CIPShimIfBase::AddIpAddrInfoL(CIPProtoBinder* aBinder, CSubConIPAddressInfoParamSet::TSubConIPAddressInfo& aAddrInfo)
+	{
+	ASSERT(iHookAddressInfo);
+	iHookAddressInfo->AddL(aBinder, aAddrInfo);
+	}
+
+void CIPShimIfBase::RemoveIpAddrInfo(CIPProtoBinder* aBinder, CSubConIPAddressInfoParamSet::TSubConIPAddressInfo& aAddrInfo)
+	{
+	ASSERT(iHookAddressInfo);
+    iHookAddressInfo->Remove(aBinder, aAddrInfo);	    
+	}
+
+void CIPShimIfBase::RemoveIpAddrInfo(CIPProtoBinder* aBinder)
+	{
+	if (iHookAddressInfo)
+    	{
+	    iHookAddressInfo->Remove(aBinder);
+    	}
+	}
+
+
+CIPShimSubConnectionFlow& CIPShimIfBase::Flow()
+	{
+	ASSERT(iProtoBinders.Count() > 0);
+	return iProtoBinders[0]->Flow();
+	}
+	
+CIPShimProtocolIntf* CIPShimIfBase::ProtcolIntf()
+	{
+	ASSERT(iProtIntf);
+	return iProtIntf;
+	}