networkprotocols/ipeventnotifier/src/ipeventnotifier.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkprotocols/ipeventnotifier/src/ipeventnotifier.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,796 @@
+// Copyright (c) 2004-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 ipeventnotifier.cpp
+ @internalComponent
+*/
+
+
+#include <in_chk.h>
+#include <icmp6_hdr.h>
+#include <in_sock.h>
+#include <in_bind.h>
+#include "in6_opt.h"
+
+#include "ipeventnotifier.h"
+#include "HookLog.h"
+#include <networking/ipeventtypes.h>
+#include "ipeventnotifierinterface.h"
+#include "ipeventlistener.h"
+#include <comms-infras/idquerynetmsg.h>
+#include "DHCPUnicastTranslator.h"
+
+
+CIPEventNotifier* CIPEventNotifier::NewL()
+	{
+	CIPEventNotifier* self = new(ELeave) CIPEventNotifier();
+	CleanupStack::PushL(self);
+
+	self->ConstructL();
+
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+
+void CIPEventNotifier::ConstructL()
+	{
+	/**
+	 * Create the address/interface listener.
+	 */
+	iIPEventListener = new (ELeave) CIPEventListener(*this);
+	}
+
+
+CIPEventNotifier::CIPEventNotifier()
+	{
+	}
+
+
+
+CIPEventNotifier::~CIPEventNotifier()
+	{
+	iInterfaces.ResetAndDestroy();
+
+	delete iIPEventListener;
+	
+	delete iDHCPUnicastTranslator;
+	}
+
+
+
+void CIPEventNotifier::BindL(CProtocolBase* aProtocol, TUint aId)
+	{
+	// Do sanity checks
+	//
+	if ((aId != KProtocolInet6Ip) || (aProtocol == this))
+		{
+		User::Leave(KErrArgument);
+		}
+
+	TUint ourId;
+		{
+		TServerProtocolDesc info;
+		Identify(&info);
+		ourId = info.iProtocol;
+		}
+
+	if (aId == ourId)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	if ( iProtocolIPv6 != NULL )
+		{
+		if ( iProtocolIPv6 == aProtocol )
+			{
+			// We don't need to bind to the same protocol twice.
+			//
+			return;
+			}
+		else
+			{
+			// We don't want to bind to a different protocol either...
+			//
+			User::Leave(KErrAlreadyExists);
+			}
+		}
+
+	iProtocolIPv6 = (CProtocolInet6Binder*) aProtocol;
+
+	// Get a pointer to the event service.
+	//
+	ObtainEventService();
+
+	// Must always register hooks on startup, til the required
+	//  initial values have been received.
+	//
+	RegisterHooksL();
+	
+	// Create cache of interfaces known to IP stack
+	//
+	AddKnownInterfacesL();
+
+	/**
+	 * Create owned hook to allow unicast DHCP packets to pass.
+	 * Notice we are bypassing the standard mechanism for including
+	 *  another protocol hook (esk files), and are directly creating
+	 *  it here as it is needed for the same lifetime as IPEN itself.
+	 */
+	if (iDHCPUnicastTranslator == NULL)
+		{
+		iDHCPUnicastTranslator = new (ELeave) CDHCPUnicastTranslator(*iProtocolIPv6);
+		}
+	// connect the hook to the stack..
+	iProtocolIPv6->BindL(iDHCPUnicastTranslator, BindForwardHook());
+	
+	}
+
+
+
+void CIPEventNotifier::Unbind(CProtocolBase* aProtocol, TUint /* aId */)
+	{
+	if (iProtocolIPv6 != aProtocol)
+		{
+		return;
+		}
+
+	iProtocolIPv6->Unbind(iDHCPUnicastTranslator, 0);
+
+	UnregisterHooks();
+
+	iProtocolIPv6 = 0;
+	iEventService = 0;
+	}
+	
+
+
+TInt CIPEventNotifier::GetOption(TUint aLevel, TUint aName,TDes8& aOption,CProtocolBase* aSourceProtocol)
+/**
+ * Performs one of the following actions, depending on the option name:
+ *
+ * KHandleAttach: Sets up IPEN to catch and publish events on the interface named in aOption.
+ *                  Session handle TUint (the pubsub address key) returned in first 4 bytes of aOption buffer.
+ *
+ * KHandleRelease: Tells IPEN to stop catching and publishing events to the given session handle
+ *                   Handle passed in as TUint in first 4 bytes of aOption buffer.
+ *
+ * @param aLevel: should be KSolInetIp for this protocol
+ * @param aName: see above
+ * @param aOption: in/out, dependent on option name. See above
+ * @return error status
+ *
+ */
+	{
+	(void) aLevel;
+	(void) aSourceProtocol;
+
+	TInt retVal = KErrNotSupported;
+		
+	switch (aName)
+		{
+		case NetMessages::KHandleAttach:
+		    {
+			TName buf;
+			buf.Copy( aOption );
+			TUint *out_handlenum = (TUint *)aOption.Ptr();
+			TRAPD(retval, *out_handlenum = OpenSessionL(buf));
+			return retval;
+			}
+
+		case NetMessages::KHandleRelease:
+			{
+			TUint *in_handle = (TUint *)aOption.Ptr();
+			TInt ret = CloseSession(*in_handle);
+			*in_handle = 0;
+			return ret;
+		    }
+			
+	    default:
+	        break;
+		}
+
+	return retVal ;
+	}
+
+
+
+TUint CIPEventNotifier::OpenSessionL(const TDesC& aIfName)
+/**
+  * Sets up IPEN to catch and publish events on the interface named by aIfName.
+  *                  Session handle TUint (the pubsub address key) is returned.
+  *
+  * @internalTechnology
+  */
+	{
+	// The IP stack's first interface, a dummy, has an empty name string.
+	// Therefore an empty string to open against would match this dummy
+	//  interface! So we should report failure if a naughty client is trying to
+	//  monitor events on an interface with an empty name string.
+	//
+	if(aIfName == KNullDesC)
+		{
+		LOG(
+			_LIT(KHookNotifyStr,"ERROR: client attempted to monitor interface with empty name");
+			HookLog::Printf( KHookNotifyStr );
+			)
+		User::Leave(KErrBadName);
+		}
+	
+	TInt ifPos = FindPositionOfInterfaceByName(aIfName);
+
+	CIPEventNotifierInterface* iface = 0;
+
+	if(ifPos == KErrNotFound)
+		{
+		AddKnownInterfacesL();
+		ifPos = FindPositionOfInterfaceByName(aIfName);
+		User::LeaveIfError(ifPos);
+		}
+	
+	iface = iInterfaces[ifPos];
+	
+	if( AnyClientsCurrentlyInterested() == false )
+		{
+		RegisterHooksL();
+		}
+		
+	__ASSERT_ALWAYS(iface , User::Leave(KErrCorrupt));
+	iface->IncreaseRefCount();
+	
+	PublishLastKnownStates(iface);
+
+	LOG(
+		_LIT(KHookNotifyStr2,"CIPEventNotifier::OpenSessionL - now monitoring interface %S (pos #%d)");
+		HookLog::Printf(KHookNotifyStr2,&aIfName,ifPos);
+		)
+		
+	return iface->GetInterfaceIndex(); // later we might create a session id and map it to i/f #
+	}
+
+	
+TInt CIPEventNotifier::CloseSession(TUint aHandle)
+	{
+	TInt acIfPos = FindPositionOfInterface(aHandle);
+
+	if(acIfPos == KErrNotFound)
+		{
+		return KErrNotFound;
+		}
+
+	CIPEventNotifierInterface* acIf = iInterfaces[acIfPos];
+
+	acIf->DecreaseRefCount();
+	
+	// shouldn't be more closes than news! naughty client.
+	__ASSERT_ALWAYS((acIf->GetRefCount() >= 0), User::Panic(_L("IPEN:CloseSession"),1));
+	
+	LOG(
+		_LIT(KHookNotifyStr2,"CIPEventNotifier::CloseSession handle %d (pos #%d)");
+		HookLog::Printf(KHookNotifyStr2,aHandle,acIfPos);
+		)	
+	
+	if( AnyClientsCurrentlyInterested() == false )
+		{
+		UnregisterHooks();
+		}
+
+	return KErrNone;
+	}
+
+
+
+void CIPEventNotifier::AddInterfaceL(TUint32 aIfIndex, const TDesC& aIfName)
+	{
+	CIPEventNotifierInterface* newActIf = new (ELeave)CIPEventNotifierInterface(aIfIndex, aIfName);
+	CleanupStack::PushL( newActIf );
+	iInterfaces.AppendL(newActIf);
+	CleanupStack::Pop( newActIf );
+	}
+
+
+
+void CIPEventNotifier::AddKnownInterfacesL()
+    {
+    TUint   bufsize = 2048;
+    HBufC8 *buffer = 0;
+    TInt exceed;
+    buffer = GetBuffer(buffer, bufsize);
+    User::LeaveIfNull(buffer);
+    TPtr8 bufdes = buffer->Des();
+    
+	do
+		{
+	    //-- get list of network interfaces
+	    // if exceed>0, all interface could not fit into the buffer.
+	    // In that case allocate a bigger buffer and retry.
+	    // There should be no reason for this while loop to take more than 2 rounds.
+	    bufdes.Set(buffer->Des());
+	    exceed = iProtocolIPv6->GetOption(KSolInetIfQuery, KSoInetInterfaceInfo, bufdes);
+	    if(exceed > 0)
+	        {
+	        bufsize += exceed * sizeof(TInetInterfaceInfo);
+	        buffer = GetBuffer(buffer, bufsize);
+	        User::LeaveIfNull(buffer);
+	        }
+	    } while (exceed > 0);
+    
+    TOverlayArray<TInetInterfaceInfo> infoIface(bufdes);
+    
+    TInt idx;
+    for(idx=0; idx < infoIface.Length(); ++idx)
+        {
+        TInetInterfaceInfo& iface = infoIface[idx];
+
+		if(FindPositionOfInterface(iface.iIndex) == KErrNotFound)
+			{
+			LOG(
+		        TBuf<2048> tmpBuf;
+	        	tmpBuf.Format(_L("Detected new i/f: index:%d, name: "),iface.iIndex);
+		        tmpBuf.Append(iface.iName);
+		        tmpBuf.AppendFormat(_L(", state:%d, SMti:%d, RMtu:%d, SpeedMetric:%d, feat:%d,"),
+		        			iface.iState,iface.iSMtu,iface.iRMtu,iface.iSpeedMetric,iface.iFeatures/*,iface.iHwAddr*/);
+		        HookLog::Printf(tmpBuf);
+	        	)
+
+			TRAP_IGNORE(AddInterfaceL(iface.iIndex,iface.iName));
+			}
+        }
+	LOG(LogKnownInterfaces());
+	delete buffer;
+    }
+
+
+HBufC8* CIPEventNotifier::GetBuffer(HBufC8* apBuf, TInt aBufLenRequired)
+    {
+    HBufC8* pBufResult = NULL;
+    
+    if(aBufLenRequired <= 0 ) 
+        return NULL; //-- invalid argument
+    
+    if(!apBuf)
+        {//-- the buffer is not allocated at all, try allocate it
+        pBufResult = HBufC8::New(aBufLenRequired);
+        }
+    else
+        {//-- the buffer is already allocated. Check its size and try to reallocate if
+        //-- required size is bigger than existing. Otherwise do nothing.   
+        
+        if(apBuf->Des().MaxSize() >= aBufLenRequired)
+            pBufResult = apBuf; //-- do nothing, existing buffer is big enough
+        else
+            {  //-- delete and allocate new buffer to avoid data copying
+            delete apBuf;
+            pBufResult = HBufC8::New(aBufLenRequired);
+            }
+        }
+    
+    return pBufResult;
+    }
+
+
+TInt CIPEventNotifier::FindPositionOfInterface(TUint32 aIfIndex) const
+	{
+	TInt i;
+	for( i=0 ; i<iInterfaces.Count() /*inline call*/ ; ++i )
+		{
+		if(iInterfaces[i]->GetInterfaceIndex() == aIfIndex)
+			{
+			return i;
+			}
+		}
+	return KErrNotFound;
+	}
+
+
+
+TInt CIPEventNotifier::FindPositionOfInterfaceByName(const TDesC& aIfName) const
+	{
+	TInt i;
+	for( i=0 ; i<iInterfaces.Count() ; ++i )
+		{
+		if(iInterfaces[i]->GetInterfaceName() == aIfName)
+			{
+			return i;
+			}
+		}
+
+	return KErrNotFound;
+	}
+
+
+CIPEventNotifierInterface* CIPEventNotifier::GetInterfaceWithIndexL(TInt aIpIfIndex)
+	{
+		TInt aIfPos;
+		aIfPos = FindPositionOfInterface(aIpIfIndex);
+		if(aIfPos < 0)
+			{
+			LOG (
+				_LIT(KHookNotifyStr,"ERROR: couldn't find interface %d. err %d");
+				HookLog::Printf( KHookNotifyStr,aIpIfIndex, aIfPos);
+				)
+			User::Leave(aIfPos);
+			}
+		
+		return iInterfaces[aIfPos];
+	}
+
+
+TBool CIPEventNotifier::AnyClientsCurrentlyInterested(void) const
+	{
+#ifdef ALWAYS_PUBLISH_IP_EVENTS
+	return true;
+#else
+	TInt i;
+	for( i=0 ; i<iInterfaces.Count() ; ++i )
+		{
+		if(iInterfaces[i]->GetRefCount() != 0       ||
+		   iInterfaces[i]->iMFlagReceived == 0         ||
+		   iInterfaces[i]->iLinklocalAddressKnown == 0   )
+		   		// (We must always listen until we've received the M flag and a LL addr.
+		   		//  This is because DHCP must have access to these events, even if it hasn't started yet.)
+			{
+			return true;
+			}
+		}
+	return false;
+#endif
+	}
+
+
+TBool CIPEventNotifier::ShouldPublishEvent(TUint aInterfaceIndex)
+	{
+	TInt aIfPos;
+	aIfPos = FindPositionOfInterface(aInterfaceIndex);
+	if(aIfPos == KErrNotFound)
+		{
+		LOG ( HookLog::Printf(_L("UNEXPECTED: Interface %d not yet known. Trying to find it"),aInterfaceIndex); )
+		TRAP_IGNORE(AddKnownInterfacesL())
+		aIfPos = FindPositionOfInterface(aInterfaceIndex);
+		if(aIfPos == KErrNotFound)
+			{
+			LOG ( HookLog::Printf(_L("VERY UNEXPECTED: Couldn't add interface %d"),aInterfaceIndex); )
+			return EFalse;
+			}
+		aIfPos = FindPositionOfInterface(aInterfaceIndex);
+		}
+	
+#ifdef ALWAYS_PUBLISH_IP_EVENTS
+    return ETrue;
+#else
+	CIPEventNotifierInterface* aIf = iInterfaces[aIfPos];
+	// if the M flag / LL addr has not yet been received we should try to catch it
+	return( (aIf->iMFlagReceived == 0)  ||
+	        (aIf->iLinklocalAddressKnown == 0)  ||
+	        (aIf->GetRefCount() > 0)      );
+	    
+#endif
+	}
+
+
+void CIPEventNotifier::InterfaceDetached(const TDesC & aName, CNifIfBase *aIf)
+	{
+	(void)aIf;
+	TInt pos = FindPositionOfInterfaceByName(aName);
+	LOG(
+		_LIT(KHookNotifyStr,"CIPEventNotifier::InterfaceDetached %S ptr=%08x [pos %d of %d interfaces]");
+		HookLog::Printf(KHookNotifyStr,&aName,aIf,pos,iInterfaces.Count());
+		)	
+	if(pos != KErrNotFound)
+		{
+		CIPEventNotifierInterface* notIf = iInterfaces[pos];
+		delete notIf;
+		iInterfaces.Remove(pos);
+		}
+	LOG(LogKnownInterfaces());
+	}
+	
+#ifdef _DEBUG
+void CIPEventNotifier::LogKnownInterfaces()
+	{
+	LOG(
+		_LIT(KHookNotifyHeader,"Dumping iInterfaces:");
+		HookLog::Printf(KHookNotifyHeader);
+		)
+			
+	for(TInt i=0 ; i<iInterfaces.Count() ; ++i )
+		{
+		LOG(
+			_LIT(KHookNotifyStr,"\tPos %d: %S, stack's index %d");
+			TName name = iInterfaces[i]->GetInterfaceName();
+			TUint32 idx = iInterfaces[i]->GetInterfaceIndex();
+			HookLog::Printf(KHookNotifyStr, i, &name, idx);
+			)	
+		}
+	}
+#endif	
+
+
+void CIPEventNotifier::RegisterHooksL(void)
+/**
+ * Registers the hook to catch IP stack events
+ */
+	{
+	if(!(iProtocolIPv6 && iEventService && iIPEventListener))
+		{
+		User::Leave(KErrNotReady);
+		}
+
+	// bind to IP for incoming packets
+	iProtocolIPv6->BindL((CProtocolBase*)this, BindHookAll());
+
+
+	// Register our listener class with the event service. We're interested in:
+	//
+	// i.  address events
+	//     for determining when DAD has completed and when link-local addresses have been assigned
+	//     to an interface.
+	// ii. interface events to allow the notifier to associate interface names with the stack's
+	//     internal indices.
+	//
+	iEventService->RegisterListener(iIPEventListener, EClassAddress);
+	iEventService->RegisterListener(iIPEventListener, EClassInterface);
+	}
+
+
+	
+void CIPEventNotifier::UnregisterHooks(void)
+/**
+ * Detaches this hook from the running of the stack.
+ *  This is so IPEN doesn't slow down the stack while it isn't
+ *   needed by any clients.
+ *
+ *  e.g. without this mechanism, every incoming packet would pass through
+ *   CIPEventNotifier::ApplyL pointlessly.
+ *
+ */
+	{
+	if(!(iProtocolIPv6 && iEventService && iIPEventListener))
+		{
+		return;
+		}
+
+	// If IPv6 exists, unbind the hook. Covers both in/out hooks (I hope)
+	iProtocolIPv6->Unbind(this);
+
+	// Unregister the address/interface listener.
+	iEventService->RemoveListener(iIPEventListener);
+	}
+
+	
+
+void CIPEventNotifier::FillIdentification(TServerProtocolDesc& anEntry)
+/**
+ * Fills in an existing protocol description structure with details of this protocol.
+ *
+ * @param aProtocolDesc: reference to the structure to be filled in
+ */
+	{
+	anEntry.iName=_S("ipen");
+	anEntry.iAddrFamily=KAfInet; //KAfExain;
+	anEntry.iSockType=KSockDatagram;
+	anEntry.iProtocol=KProtocolId;
+	anEntry.iVersion=TVersion(1, 0, 0);
+	anEntry.iByteOrder=EBigEndian;
+	anEntry.iServiceInfo=KSIDatagram | KSIConnectionLess;
+	anEntry.iNamingServices=0;
+	anEntry.iSecurity=KSocketNoSecurity;
+	anEntry.iMessageSize=0xffff;
+	anEntry.iServiceTypeInfo=0; // 1 for ability to create sockets
+	anEntry.iNumSockets=KUnlimitedSockets;
+	}
+
+
+void CIPEventNotifier::Identify(TServerProtocolDesc* aProtocolDesc) const
+/**
+ * Fills in an existing protocol description structure with details of this protocol.
+ *
+ * @param aProtocolDesc: pointer to the structure to be filled in
+ */
+	{
+	FillIdentification(*aProtocolDesc);
+	}
+
+
+TInt CIPEventNotifier::DefineProperty(Meta::SMetaData& aEvent, TUint aHandle)
+	{
+	TSecurityPolicy readPol(TSecurityPolicy::EAlwaysPass);
+	_LIT_SECURE_ID(ipeventsid,0x102045B9);
+	_LIT_SECURITY_POLICY_S0(writePol,ipeventsid);
+
+	TInt err = iPublisher.Define(TUid::Uid(aEvent.GetTypeId().iType), aHandle,
+						RProperty::EByteArray/*, readPol, writePol*/);
+						
+	// Does not matter if property has already been defined - we ignore the error.
+	if( err == KErrAlreadyExists )
+		{
+		err = KErrNone;
+		}
+		
+	return err;
+	}
+
+
+void CIPEventNotifier::PublishToHandle(TUint aHandle, Meta::SMetaData& aData)
+	{
+	TBuf8<RProperty::KMaxPropertySize> buf;
+
+	TInt res =  aData.Store(buf);
+	if(res != KErrNone)
+		{
+		LOG(HookLog::Printf( _L("IPEN can't store: %d"), res));
+		return;
+		}
+
+	TPtrC8 toSet = buf;
+	res = iPublisher.Set(TUid::Uid(aData.GetTypeId().iType), aHandle, toSet);
+	if(res != KErrNone)
+		{
+		LOG(HookLog::Printf( _L("IPEN can't publish: %d"), res));
+		}
+	}
+
+
+
+/**
+ * Incoming packet
+ */
+TInt CIPEventNotifier::ApplyL(RMBufHookPacket& aPacket, RMBufRecvInfo& aInfo)
+	{
+
+	LOG	(
+		_LIT(KHookNotifyStr,"CIPEventNotifier::ApplyL hit with protocol: %d");
+		HookLog::Printf( KHookNotifyStr , aInfo.iProtocol );
+		)
+
+	if(aInfo.iProtocol == static_cast<TInt>(KProtocolInet6Icmp) &&  // quickest first
+		ShouldPublishEvent(aInfo.iInterfaceIndex) )
+		{
+
+		LOG	(
+			_LIT(KHookNotifyStr," ICMPv6 packet detected");
+			HookLog::Printf( KHookNotifyStr );
+			)
+
+		/**
+		 * Could switch on ICMP type here, in case the hook needs to catch
+		 *   other ICMP packet types..
+		 */
+		TInet6Checksum<TInet6HeaderICMP_RouterAdv> icmp(aPacket,aInfo.iOffset);
+
+		if(icmp.iHdr)
+			{
+			if (icmp.iHdr->Type() == KInet6ICMP_RouterAdv &&
+				icmp.VerifyChecksum( aPacket,
+							  aInfo.iProtocol == static_cast<TInt>(KProtocolInet6Icmp) ? &aInfo : NULL,
+							  aInfo.iOffset) )
+				{
+				TBool mflag = (icmp.iHdr->M() ? ETrue : EFalse) ;
+				TBool oflag = (icmp.iHdr->O() ? ETrue : EFalse) ;
+
+				LOG	(
+					_LIT(KHookNotifyStr," IP EVENT on if# %d: Publishing M flag: %d");
+					HookLog::Printf( KHookNotifyStr, aInfo.iInterfaceIndex, mflag );
+					_LIT(KHookOFlagNotifyStr," IP EVENT on if# %d: Publishing O flag: %d");
+					HookLog::Printf( KHookOFlagNotifyStr, aInfo.iInterfaceIndex, oflag );
+					)
+
+				TRAPD(err, PublishMFlagL(aInfo.iInterfaceIndex, mflag, oflag));
+				if(err!=KErrNone)
+					{
+					LOG	(
+					_LIT(KLogStr, "Can't publish M and O flags message! Err %d\n");
+					HookLog::Printf(KLogStr, err);
+					)
+					}
+				}
+			}
+
+		}
+			
+	return KIp6Hook_PASS;   // ensure we don't affect the control flow
+	}
+
+
+
+void CIPEventNotifier::ObtainEventService()
+	{
+	MInterfaceManager* ifacer = iProtocolIPv6->NetworkService()->Interfacer();
+
+	TRAPD(err, iEventService = IMPORT_API_L (ifacer, MEventService));
+	if (err != KErrNone)
+		{
+		LOG	(
+			_LIT(KHookNotifyStr, "MEventService not available (%d). Some features may be missing\n");
+			HookLog::Printf(KHookNotifyStr, err);
+			)
+		}
+	}
+
+
+
+
+void CIPEventNotifier::PublishMFlagL(TInt aIpIfIndex, TBool aMflag, TBool aOflag)
+	{
+	CIPEventNotifierInterface* iface = GetInterfaceWithIndexL(aIpIfIndex);
+
+	if(iface)
+		{
+		if(iface->iMFlagReceived == 0)
+			{
+			iface->iMFlagReceived = CMFlagReceived::NewL();
+			User::LeaveIfError(DefineProperty(*(iface->iMFlagReceived), aIpIfIndex));
+			}
+		
+		iface->iMFlagReceived->SetMFlag(aMflag);
+		iface->iMFlagReceived->SetOFlag(aOflag);
+		PublishToHandle(aIpIfIndex, *(iface->iMFlagReceived));
+		}
+	}
+
+		
+void CIPEventNotifier::PublishIPReadyL(TInt aIpIfIndex, const TInetAddr& tmpInetAddr, TBool addressValid)
+	{
+	CIPEventNotifierInterface* iface = GetInterfaceWithIndexL(aIpIfIndex);
+
+	if(iface)
+		{
+		if(iface->iIPReady == 0)
+			{
+			iface->iIPReady = CIPReady::NewL();			
+			User::LeaveIfError(DefineProperty(*(iface->iIPReady), aIpIfIndex));
+			}
+		
+		iface->iIPReady->SetIPAddress(tmpInetAddr);
+		iface->iIPReady->SetAddressValid(addressValid);
+		PublishToHandle(aIpIfIndex, *(iface->iIPReady));
+		}
+	}
+
+void CIPEventNotifier::PublishLinklocalAddressKnownL(TInt aIpIfIndex, const TInetAddr& tmpInetAddr)
+	{
+	CIPEventNotifierInterface* iface = GetInterfaceWithIndexL(aIpIfIndex);
+
+	if(iface)
+		{
+		if(iface->iLinklocalAddressKnown == 0)
+			{
+			iface->iLinklocalAddressKnown = CLinklocalAddressKnown::NewL();
+			User::LeaveIfError(DefineProperty(*(iface->iLinklocalAddressKnown), aIpIfIndex));
+			}			
+		iface->iLinklocalAddressKnown->SetIPAddress(tmpInetAddr);
+		PublishToHandle(aIpIfIndex, *(iface->iLinklocalAddressKnown));
+		}
+	}
+
+
+void CIPEventNotifier::PublishLastKnownStates(CIPEventNotifierInterface* aIface)
+{
+	TUint32 ifIdx = aIface->GetInterfaceIndex();
+	
+	// For each message from which we need state, not just events
+	//  i.e. everything that might happen before DHCP starts and registers
+	//
+	if(aIface->iMFlagReceived)
+		{
+		PublishToHandle(ifIdx, *(aIface->iMFlagReceived));
+		}
+	if(aIface->iLinklocalAddressKnown)
+		{
+		PublishToHandle(ifIdx, *(aIface->iLinklocalAddressKnown));
+		}
+}