linklayercontrol/networkinterfacemgr/netcfgext/src/netcfgextnbase.cpp
changeset 0 af10295192d8
child 5 1422c6cd3f0c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linklayercontrol/networkinterfacemgr/netcfgext/src/netcfgextnbase.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,842 @@
+// Copyright (c) 2003-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:
+// Implements generic base for NIFMAN side of configuration daemon
+// 
+//
+
+/**
+ @file NIFConfigurationControl.cpp
+ @internalTechnology
+*/
+
+#include "networkconfigextensionbase.h"
+#include <comms-infras/nifif.h>
+#include <comms-infras/ca_startserver.h>
+#include <cdbcols.h>
+#include <comms-infras/commsdebugutility.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_NifManNetCfgExtn, "NifManNetCfgExtn");
+#endif
+
+_LIT(KIAPId, "IAP\\Id");
+_LIT(KIAPNetwork, "IAP\\IAPNetwork");
+
+
+/**
+   ADeletionNotifier
+*/
+ADeletionNotifier::~ADeletionNotifier()
+	{
+	iDeletionListener->NotifyDeletionL(this);
+	}
+
+/**
+   ADeferredDeletion
+*/	
+void ADeferredDeletion::ListenForObjectDeletionL(ADeletionNotifier */*aDelete*/)
+	{
+	iDeletionObjectCount++;
+	}
+
+EXPORT_C void ADeferredDeletion::DeleteThis()
+	{
+	iDeleteWhenAllObjectsDeleted = ETrue;
+	if (iDeletionObjectCount == 0)
+		{
+		delete this;
+		}
+	}
+
+EXPORT_C void ADeferredDeletion::NotifyDeletionL(ADeletionNotifier */*aDelete*/)
+	{
+	iDeletionObjectCount--;
+	if (iDeleteWhenAllObjectsDeleted && iDeletionObjectCount == 0)
+		{
+		DeleteThis();
+		}
+	}
+
+NONSHARABLE_CLASS(CAsynchDaemonCancel) : public CActive, public ADeletionNotifier
+{
+public:
+   CAsynchDaemonCancel(ADeferredDeletion* aDeletionListener) :
+	   CActive(EPriorityStandard), ADeletionNotifier(aDeletionListener)
+	   {
+	   }
+
+   void AsyncDelete();
+
+   void CancelControl(RConfigDaemon& aConfigDaemon, TBool aDeleteOnCompletion);
+   void CancelControl(RConfigDaemon& aConfigDaemon, TInt aOpMask, TBool aDeleteOnCompletion);
+
+protected:
+	virtual void RunL();
+	virtual void DoCancel();
+
+protected:
+	TBool iDeleteOnCompletion;
+	};
+
+NONSHARABLE_CLASS(CNifDaemonProgress) : public CActive, public ADeletionNotifier, public ADeferredDeletion
+/**
+ * Active object class used by CNetworkConfigExtensionBase to maintain a persistent 
+ * ProgressNotification call against the daemon. Delete this object only using the 
+ * AsyncDelete method.
+ *
+ * @internalComponent
+ */
+	{
+public:
+	static CNifDaemonProgress* NewL(RConfigDaemon& aConfigDaemon, CNetworkConfigExtensionBase* aProgressDest, ADeferredDeletion* aDeletionListener);
+	void ProgressNotification();
+   	void AsyncDelete();
+	void DeleteThis();
+   	void CancelControl();
+
+protected:
+	void RunL();
+	void DoCancel();
+
+	// This is protectde so that you MUST use AsyncDelete.
+	virtual ~CNifDaemonProgress() {};
+	
+private:
+
+  	void ConstructL();
+   	CNifDaemonProgress(RConfigDaemon& aConfigDaemon, CNetworkConfigExtensionBase* aProgressDest, ADeferredDeletion* aDeletionListener);
+	/** Reference to the configuration daemon interface. */
+   	RConfigDaemon& iConfigDaemon;
+	/** Used to asynchrounously cancel any outstanding request on iConfigDaemon so that esock is never blocked. */
+   	CAsynchDaemonCancel* iAsynchDaemonCancel;
+	/** The target for progress notifications. */
+   	CNetworkConfigExtensionBase* iProgressDest;
+	/** Stores the progress notification. */
+   	TDaemonProgressBuf iProgressBuf;
+	/** If ETrue, the object should delete itself when the outstanding request completes. */
+	TBool iDeleteOnCompletion;
+	};
+
+void CAsynchDaemonCancel::AsyncDelete()
+/**
+ * Delete the instance of CAsynchDaemonCancel safely.
+ * 
+ * @internalComponent
+ */
+	{
+	if (IsActive())
+		iDeleteOnCompletion = ETrue;
+	else
+		delete this;
+	}
+
+void CAsynchDaemonCancel::DoCancel()
+   {//nothing to do
+   }
+
+void CAsynchDaemonCancel::CancelControl(RConfigDaemon& aConfigDaemon, TBool aDeleteOnCompletion)
+   {
+      if (!IsActive())
+         {
+         __ASSERT_DEBUG(!IsAdded(), User::Panic(KSpecAssert_NifManNetCfgExtn, 1));	
+         CActiveScheduler::Add(this);
+         aConfigDaemon.Cancel(iStatus);
+         SetActive();
+         }
+      iDeleteOnCompletion = aDeleteOnCompletion;
+   }
+
+void CAsynchDaemonCancel::CancelControl(RConfigDaemon& aConfigDaemon, TInt aOpMask, TBool aDeleteOnCompletion)
+/**
+ * CancelControl - Asynchronously cancels the last server request according to aOpMask.
+ *
+ * @internalComponent
+ */
+   {
+      if (!IsActive())
+         {
+         __ASSERT_DEBUG(!IsAdded(), User::Panic(KSpecAssert_NifManNetCfgExtn, 2));
+         CActiveScheduler::Add(this);
+         aConfigDaemon.Cancel(aOpMask,iStatus);
+         SetActive();
+         }
+      iDeleteOnCompletion = aDeleteOnCompletion;
+   }
+   
+void CAsynchDaemonCancel::RunL()
+  	{
+	   if ( iDeleteOnCompletion )
+		   {
+		   delete this;
+		   }
+	   else
+		   {
+		   Deque();
+		   }
+  	}
+  	
+CNifDaemonProgress* CNifDaemonProgress::NewL(RConfigDaemon& aConfigDaemon, CNetworkConfigExtensionBase* aProgressDest, ADeferredDeletion* aDeletionListener)
+/**
+ * Standard NewL for CNifDaemonProgress.
+ * 
+ * @internalComponent
+ *
+ * @param aConfigDaemon	Daemon client to be used.
+ * @param aProgressDest	Destination for progress notifications.
+ * @leave KErrNoMemory if there is insufficient heap.
+ */
+   {
+	   CNifDaemonProgress* pDaemonProgress = new(ELeave)CNifDaemonProgress(aConfigDaemon, aProgressDest, aDeletionListener);
+   CleanupStack::PushL(pDaemonProgress);
+   pDaemonProgress->ConstructL();
+   CleanupStack::Pop(pDaemonProgress);
+   return pDaemonProgress;
+   }
+
+void CNifDaemonProgress::DeleteThis()
+	{
+	if (iAsynchDaemonCancel)
+		{
+		iAsynchDaemonCancel->AsyncDelete();
+		iAsynchDaemonCancel = NULL;
+		}
+	ADeferredDeletion::DeleteThis();
+	}
+
+void CNifDaemonProgress::ConstructL()
+/**
+ * Standard ConstructL for CNifDaemonProgress.
+ * 
+ * @internalComponent
+ *
+ * @leave KErrNoMemory if there is insufficient heap.
+ */
+   {
+   iAsynchDaemonCancel = new(ELeave)CAsynchDaemonCancel(this);
+   }
+
+CNifDaemonProgress::CNifDaemonProgress(
+	RConfigDaemon& aConfigDaemon, 
+	CNetworkConfigExtensionBase* aProgressDest,
+	ADeferredDeletion* aDeletionListener) :
+	CActive(EPriorityStandard),
+	ADeletionNotifier(aDeletionListener),
+   	iConfigDaemon(aConfigDaemon),
+   	iAsynchDaemonCancel(NULL),
+   	iProgressDest(aProgressDest),
+   	iDeleteOnCompletion(EFalse)
+/**
+ * Construct the progress active object. Adds the active object to the scheduler and 
+ * issues the asynchronous call.
+ * 
+ * @internalComponent
+ *
+ * @param aConfigDaemon	Daemon client to be used.
+ * @param aProgressDest	Destination for progress notifications.
+ */
+    {
+    CActiveScheduler::Add(this);
+    ProgressNotification();       
+    }  	
+  	
+void CNifDaemonProgress::ProgressNotification()
+/**
+ * Issues the asynchronous progress notification request.
+ * 
+ * @internalComponent
+ */
+	{
+	iConfigDaemon.ProgressNotification(iProgressBuf, iStatus);
+	SetActive();
+	}
+  	
+void CNifDaemonProgress::RunL()
+/**
+ * Indicates that a progress notification was received. 
+ * The progress info will be found in iProgressBuf.
+ * 
+ * @internalComponent
+ */
+	{
+	if (iDeleteOnCompletion)
+		{
+		// if iDeleteOnCompletion is true, we are to delete ourselves
+	  	__FLOG_STATIC0(KLogSubSysNifman, KLogTagCsDaemon, _L("CNifDaemonProgress::RunL - Deleting ourselves."));	
+		DeleteThis();
+		}
+	else if (iStatus.Int() == KErrNone)
+		{
+		// We successfully got a progress notification. Pass it
+		// on the the target and re-issue the request.
+	  	__FLOG_STATIC1(KLogSubSysNifman, KLogTagCsDaemon, _L("CNifDaemonProgress::RunL - Successfully received progress notification %d. Re-issuing request."),iProgressBuf().iStage);	
+		iProgressDest->DoOnDaemonProgress(iProgressBuf().iStage, iProgressBuf().iError);
+		ProgressNotification();	
+		}
+	else if (iStatus.Int() == KErrNotReady)
+		{
+		// The daemon is starting-up. Re-issue the request.
+		__FLOG_STATIC0(KLogSubSysNifman, KLogTagCsDaemon, _L("CNifDaemonProgress::RunL - Progress notification. Waiting for server to start."));
+		ProgressNotification();	
+		}
+	else
+		{
+		// We failed to get a progress notification.
+		// The daemon either does not support this request,
+		// has exited or has died. Do not issue another request. 
+		// We'll get into a tight loop if we do.
+	  	__FLOG_STATIC1(KLogSubSysNifman, KLogTagCsDaemon, _L("CNifDaemonProgress::RunL - Failed to get progress notification from daemon. The error was %d"),iStatus.Int());	
+	  	}
+  	}
+
+void CNifDaemonProgress::AsyncDelete()
+/**
+ * Cancels any outstanding progress notification and optionally 
+ * the instance of CNifDaemonProgress asynchronously to avoid
+ * potential deadlock in Esock.
+ *
+ * @internalComponent
+ */	
+	{
+   	if (IsActive())
+    	{
+	  	__FLOG_STATIC0(KLogSubSysNifman, KLogTagCsDaemon, _L("CNifDaemonProgress::AsyncDelete - Waiting for CancelControl to complete"));	
+       	iDeleteOnCompletion = ETrue;
+       	CancelControl();
+       	}
+ 	else
+    	{
+		DeleteThis();
+       	}
+	}
+
+void CNifDaemonProgress::CancelControl()
+/**
+ * Cancels any outstanding progress asynchronously to avoid
+ * potential deadlock in Esock.
+ *
+ * @internalComponent
+ */
+	{
+	if (IsActive())
+		{
+		iAsynchDaemonCancel->CancelControl(iConfigDaemon, KConfigDaemonOpMaskProgress, iDeleteOnCompletion);
+		if (iDeleteOnCompletion)
+			iAsynchDaemonCancel = NULL;
+		}
+	}
+
+void CNifDaemonProgress::DoCancel()
+/**
+ * Standard active object DoCancel.
+ * 
+ * @internalComponent
+ */
+	{
+	// DoCancel() is only used by Cancel(), which is can not be 
+	// used as it will block the ESOCK thread.
+	__ASSERT_DEBUG(0, User::Panic(KSpecAssert_NifManNetCfgExtn, 3)); 
+	}
+
+CNetworkConfigExtensionBase* CNetworkConfigExtensionBase::NewL( TAny* aMNifIfNotify )
+   {
+   MNifIfNotify* nifIfNotify = reinterpret_cast<MNifIfNotify*>(aMNifIfNotify);
+   CNetworkConfigExtensionBase* pDaemon = new(ELeave)CNetworkConfigExtensionBase( *nifIfNotify );
+	CleanupStack::PushL(pDaemon);
+   pDaemon->ConstructL();
+	CleanupStack::Pop(pDaemon);
+   return pDaemon;
+   }
+
+EXPORT_C void CNetworkConfigExtensionBase::ConstructL()
+   {
+   __FLOG_STATIC0(KLogSubSysNifman, KLogTagCsDaemon, _L("CNetworkConfigExtensionBase::ConstructL"));
+   iAsynchDaemonCancel = new(ELeave)CAsynchDaemonCancel(this);
+   }
+
+EXPORT_C void CNetworkConfigExtensionBase::ConfigureNetworkL()
+/**
+ConfigureNetworkL - starts a daemon and issues configuration request
+@internalTechnology
+@version 0.02
+**/
+	{
+  	__FLOG_STATIC0(KLogSubSysNifman, KLogTagCsDaemon, _L("CNetworkConfigExtensionBase::ConfigureNetworkL"));	
+	//it could access directly CNifAgentRef::ConnectionInfo but i don't want the class be 
+	//CNifAgentRef dependent
+   	__ASSERT_DEBUG(iMessage.IsNull(), User::Panic(KSpecAssert_NifManNetCfgExtn, 4));
+	
+	User::LeaveIfError(iNifIfNotify->ReadInt(KIAPId(), iConnectionInfoBuf().iIapId));
+	User::LeaveIfError(iNifIfNotify->ReadInt(KIAPNetwork(), iConnectionInfoBuf().iNetId));
+   	//this is the same read as in CNifConfigurationControl::NewL we do the read rather than storing the
+   	//server name since the db access should really provide an efficient access to the settings
+   	//already selected by NETCON
+	TBuf<KCommsDbSvrMaxFieldLength> serverName;		/*100 bytes if unicode*/
+	User::LeaveIfError(iNifIfNotify->ReadDes(TPtrC(SERVICE_CONFIG_DAEMON_NAME), serverName));
+	// safe to pass stack var here, as its copied down the track...
+
+	// For security reasons, ensure that the server name has the "!" prefix - only protected
+	// servers should be involved with Network Configuration.
+	
+	_LIT(KExclamationMark, "!");
+	if (serverName.Left(1).Compare(KExclamationMark()) != 0)
+		serverName.Insert(0,KExclamationMark());
+	
+	__ASSERT_DEBUG(!ipStartServer, User::Panic(KSpecAssert_NifManNetCfgExtn, 5));
+	DoOnGenericProgress(KConfigDaemonLoading, KErrNone);
+	ipStartServer = new(ELeave)CStartServer(iConfigDaemon, iConfigDaemon.Version(), 10);
+	ipStartServer->Connect(serverName, iStatus);
+	SetActive();
+	}
+
+EXPORT_C void CNetworkConfigExtensionBase::LinkLayerDown()	
+/**
+ * Generates an EConfigDaemonLinkLayerDown request. Used to inform the
+ * daemon that link-layer renegotiation has started.
+ * 
+ * @internalComponent
+ */
+	{
+	if (iSuccessfullyCreatedDaemon)
+		iConfigDaemon.LinkLayerDown();
+	}
+
+EXPORT_C void CNetworkConfigExtensionBase::LinkLayerUp()	
+/**
+ * Generates an EConfigDaemonLinkLayerUp request. Used to inform the
+ * daemon that link-layer renegotiation has completed.
+ * 
+ * @internalComponent
+ */
+	{
+	if (iSuccessfullyCreatedDaemon)
+		iConfigDaemon.LinkLayerUp();
+	}
+
+EXPORT_C void CNetworkConfigExtensionBase::Deregister(
+	TInt aCause)	
+/**
+ * Generates a deregistration request.
+ * 
+ * @internalComponent
+ *
+ * @param aCause Specifies what caused the deregistration request (idle timer or Stop call)
+ */
+	{
+	if (IsActive())
+		{
+		// if a deregistration request isn't queued up, queue one up
+		if (!iDeregisterOnCompletionOfRequest)
+			{
+			iDeregisterOnCompletionOfRequest = ETrue;
+			iDeregistrationCauseCode = aCause;
+			}
+		}
+	else if (!iSuccessfullyCreatedDaemon)
+		{
+		// note that there is no longer a queued deregistration
+		// request
+		iDeregisterOnCompletionOfRequest = EFalse;
+		// fake the behaviour of the daemon and report 
+		// KErrNotFound to be compatible with the previous
+		// behaviour expected by the DHCP tests - KErrNotFound
+		// as in the daemon "was not found"
+		DoOnGenericProgress(KConfigDaemonStartingDeregistration, KErrNone);
+		DoOnGenericProgress(KConfigDaemonFinishedDeregistrationStop, KErrNotFound);		
+		}
+	else
+		{
+		// note that there is no longer a queued deregistration
+		// request
+		iDeregisterOnCompletionOfRequest = EFalse;
+		// progress notification before the operation
+		DoOnGenericProgress(KConfigDaemonStartingDeregistration, KErrNone);
+		// ask the daemon to deregister
+		iConfigDaemon.Deregister(aCause, &iDesDeregActionStatus, iStatus);
+		SetActive();
+		}    	
+	}
+
+EXPORT_C void CNetworkConfigExtensionBase::SendIoctlMessageL(const ESock::RLegacyResponseMsg& aMessage)
+/**
+* SendIoctlMessageL forwards Ioctl request to the daemon and activates the AO to wait for response
+* 
+@internalTechnology
+@version 0.02
+@param aMessage[in] a message to be processed (it's the caller's resposibility to forward just Ioctl
+*                   messages)
+**/
+	{
+   	__FLOG_STATIC0(KLogSubSysNifman, KLogTagCsDaemon, _L("CNetworkConfigExtensionBase::SendIoctlMessageL"));	
+	if (static_cast<TUint>(aMessage.Int0()) != KCOLConfiguration)
+		{
+		User::Leave(KErrNotSupported);
+		}
+   	else
+		{
+		if (!IsActive())
+			{
+			TDes8* ptr = NULL;
+			// may not always have a buffer to read...
+			if (aMessage.Ptr2())
+				{
+
+            	delete iIoBuf;
+            	iIoBuf = NULL;
+            	TInt maxLength = aMessage.GetDesMaxLengthL(2);
+				iIoBuf=HBufC8::NewMaxL(maxLength);
+				iIoPtr.Set(iIoBuf->Des());
+				aMessage.ReadL(2, iIoPtr);
+				
+				TInt length = aMessage.GetDesLength(2);
+				if (length<1) //length could be -ve due to error return from GetDesLength
+					{
+					iIoPtr.SetLength(maxLength);
+					}
+				else
+					{
+					iIoPtr.SetLength(length);
+					}
+				ptr = &iIoPtr;
+				}
+			//store msg after ReadDescriptorL which could leave
+			iMessage = aMessage;
+			iConfigDaemon.Ioctl(aMessage.Int0(), aMessage.Int1(), iStatus, ptr);
+			SetActive();      
+			}
+		else
+			{
+			User::Leave(KErrInUse);
+			}
+		}
+	}
+	
+EXPORT_C void CNetworkConfigExtensionBase::AsyncDelete()
+/**
+Provide a clever method for deletion and 
+asynchronously cancelling any outstanding event
+so as to avoid any problems of deadlock
+**/	
+	{
+	if (IsActive()) //are we waiting?
+    	{
+       	//yes
+		// complete any blocked client message immediately - no sense in keeping them hanging on and in a session close 
+		// case the dealer may race us to this
+		if (!iMessage.IsNull())
+			{
+			iMessage.Complete(KErrCancel);
+			}
+       	iDeleteOnCompletion = ETrue;
+       	CancelControl();
+       	// Zero our reference to the NIFMAN CNifAgentRef as it can be destroyed
+       	// ahead of us (this problem manifests itself during cycles of connection
+       	// start immediately followed by connection stop).
+       	iNifIfNotify = NULL;
+       	}
+ 	else
+    	{
+		DeleteThis();
+       	}
+	}
+
+EXPORT_C void CNetworkConfigExtensionBase::CancelControl()
+/**
+ CancelControl - cancels request asynchronously to avoid deadlock
+ @internalAll
+ @version 0.01
+**/
+	{
+	if (IsActive()) //are we waiting?
+		{
+		//yes
+		if (ipStartServer)
+			{
+			ipStartServer->Cancel(); //it'll set an error code to KErrCancel meaning that 
+         //the requests will complete with KErrCancel
+			}
+		else
+			{
+			if(iLastGenericProgressStage != KConfigDaemonStartingDeregistration)
+				{
+				iAsynchDaemonCancel->CancelControl(iConfigDaemon, iDeleteOnCompletion);
+				if ( iDeleteOnCompletion )
+					{
+					iAsynchDaemonCancel = NULL;
+					}
+				}
+			}
+		//the RunL method will be called on the original request cancellation
+		}
+	}
+
+EXPORT_C void CNetworkConfigExtensionBase::DoCancel()
+/**
+DoCancel - cancels current request
+@internalTechnology
+@version 0.01
+@see CActive::DoCancel
+**/
+	{
+  	__ASSERT_DEBUG(0, User::Panic(KSpecAssert_NifManNetCfgExtn, 6)); //we shouldn't ever get here, would block NIFMAN/ESOCK thread
+	}
+
+EXPORT_C void CNetworkConfigExtensionBase::RunL()
+/**
+RunL - called when request completes
+@internalTechnology
+@version 0.03
+@see CActive::RunL
+**/
+	{
+  	//__FLOG_STATIC0(KLogSubSysNifman, KLogTagCsDaemon, _L("CNetworkConfigExtensionBase::RunL"));	
+  	
+	if (iDeleteOnCompletion)
+		{
+		// if iDeleteOnCompletion is true, we are to delete ourselves
+		
+		// if there was an outstanding IOCTL request, complete the message
+		if (!iMessage.IsNull())
+			{
+			// client request completion
+			const TAny* ptr = iMessage.Ptr2();
+			if (ptr)
+				{
+				__ASSERT_DEBUG(iIoBuf, User::Panic(KSpecAssert_NifManNetCfgExtn, 7));
+				iMessage.WriteL(2, *iIoBuf);
+				delete iIoBuf; //no longer needed
+				iIoBuf = NULL;
+				}
+			iMessage.Complete(iStatus.Int());
+			}
+
+      	__ASSERT_DEBUG(!ipStartServer || !ipStartServer->IsActive(), User::Panic(KSpecAssert_NifManNetCfgExtn, 8));
+		delete ipStartServer; //no needed any more
+		ipStartServer = NULL;
+		DeleteThis();
+		// *********************************************
+		// CAREFUL... don't do anything after this point
+		// because this object has been deleted
+		// *********************************************		
+		}
+	else if (ipStartServer)
+		{
+		// the daemon server was created (or the creation failed)
+		
+		// if ipStartServer is not null, then the server has just been
+		// started
+		delete ipStartServer; //no needed any more
+		ipStartServer = NULL;
+		if (iStatus.Int() == KErrNone)
+			{
+			// record the fact that the daemon was successfully 
+			// launched
+			iSuccessfullyCreatedDaemon = ETrue;
+			// signal that the daemon was loaded successfully		
+			DoOnGenericProgress(KConfigDaemonLoaded, KErrNone);
+			// create progress instance - this registers for daemon progress notifications
+ 		 	iDaemonProgress = CNifDaemonProgress::NewL(iConfigDaemon, this, this);
+			// signal before the Configure method is called		
+			DoOnGenericProgress(KConfigDaemonStartingRegistration, KErrNone);
+			//complete connection
+			iConfigDaemon.Configure(iConnectionInfoBuf, iStatus);
+			SetActive();
+			//wait for the Configure to complete
+			}
+		else
+			{
+			//we're done with en error
+			iNifIfNotify->IfProgress(KLinkLayerOpen, iStatus.Int());
+			}
+		}
+	else if (!iMessage.IsNull())
+		{
+		// the ioctl request completed
+		
+		// complete the message
+		const TAny* ptr = iMessage.Ptr2();
+		if (ptr)
+			{
+			__ASSERT_DEBUG(iIoBuf, User::Panic(KSpecAssert_NifManNetCfgExtn, 9));
+			iMessage.WriteL(2, *iIoBuf);
+			delete iIoBuf; //no longer needed
+			iIoBuf = NULL;
+			}
+		iMessage.Complete(iStatus.Int());
+		
+ 		// start to deregister if we happen to have one queued
+ 		if (iDeregisterOnCompletionOfRequest)
+ 			Deregister(iDeregistrationCauseCode);
+		}
+	else if (iLastGenericProgressStage == KConfigDaemonStartingRegistration)
+		{
+		// the configure call completed
+		
+		// signal the completed Configure call
+		DoOnGenericProgress(KConfigDaemonFinishedRegistration, iStatus.Int());
+		//no user request => must be configuration completion => signal it up
+		 iNifIfNotify->IfProgress(KLinkLayerOpen, iStatus.Int());
+ 		// start to deregister if we happen to have one queued
+ 		if (iDeregisterOnCompletionOfRequest)
+ 			Deregister(iDeregistrationCauseCode);
+		}
+	else if (iLastGenericProgressStage == KConfigDaemonStartingDeregistration)
+		{
+		// the deregistration request completed
+		
+		// if any error occurred, we should assume stop
+		// is the desired result
+		if (iStatus.Int() != KErrNone)
+			iDeregActionStatus = EConfigDaemonDeregisterActionStop;
+		// if the daemon doesn't support deregistration,
+		// we act as if everything succeeded
+		if (iStatus.Int() == KErrNotSupported)
+			iStatus = KErrNone;
+		// handle the result
+		switch (iDeregActionStatus)
+			{
+		case EConfigDaemonDeregisterActionStop:
+			// progress notification - note that this specific
+			// notification will delete this object
+			DoOnGenericProgress(KConfigDaemonFinishedDeregistrationStop, iStatus.Int());		
+			// *****************************************************
+			// CAREFUL... don't do anything after this point because 
+			// this object has been deleted as a result of this
+			// progress notification
+			// *****************************************************
+			break;
+		case EConfigDaemonDeregisterActionPreserve:
+			// progress notification
+			DoOnGenericProgress(KConfigDaemonFinishedDeregistrationPreserve, iStatus.Int());		
+	 		// start to deregister if we happen to have one queued
+	 		if (iDeregisterOnCompletionOfRequest)
+	 			Deregister(iDeregistrationCauseCode);
+			break;
+		default:
+			User::Leave(KErrNotSupported);
+			break;
+			}			
+		}
+	else
+		{
+		// should never get here.
+		__ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_NifManNetCfgExtn, 10));
+		}
+	// ********************************************
+	// CAREFUL... consider the possible deletion of
+	// this object in the code above before adding
+	// anything down here
+	// ********************************************			
+	}
+	
+EXPORT_C TInt CNetworkConfigExtensionBase::RunError(TInt aError)
+	{//see CNetworkConfigExtensionBase::RunL the only case it can leave is when iMessage is valid
+   	if (!iMessage.IsNull())
+		{
+		iMessage.Complete(aError);
+		}
+   	return KErrNone;
+	}	
+
+EXPORT_C void CNetworkConfigExtensionBase::DeleteThis()
+	{
+	// delete safely the progress request    
+	if (iDaemonProgress)
+		{
+		iDaemonProgress->AsyncDelete();
+		iDaemonProgress = NULL;
+		}
+
+	// delete safely the cancel request
+   	if (iAsynchDaemonCancel)
+   		{
+   		iAsynchDaemonCancel->AsyncDelete();
+   		iAsynchDaemonCancel = NULL;
+   		}
+
+	ADeferredDeletion::DeleteThis();
+/*	iDeleteWhenAllObjectsDeleted = ETrue;
+	if (iDeletionObjectCount == 0)
+		{
+		delete this;
+		}*/
+	}
+
+EXPORT_C CNetworkConfigExtensionBase::~CNetworkConfigExtensionBase()
+/**
+~CNetworkConfigExtensionBase - destructor
+@internalTechnology
+@version 0.02
+**/
+	{
+	// complete any outstanding messages
+	if (!iMessage.IsNull())
+		{
+		//client request completion - no point to write any data back to client here
+		iMessage.Complete(KErrCancel);
+		}
+   	__ASSERT_DEBUG(!ipStartServer, User::Panic(KSpecAssert_NifManNetCfgExtn, 11));
+
+	// unload the daemon		
+    DoOnGenericProgress(KConfigDaemonUnloading, KErrNone);
+   	iConfigDaemon.Close();
+    DoOnGenericProgress(KConfigDaemonUnloaded, KErrNone);
+       		
+   	delete iIoBuf;
+	}	
+
+EXPORT_C void CNetworkConfigExtensionBase::EventNotification(TNetworkAdaptorEventType /*aEventType*/, TUint /*aEvent*/, const TDesC8& /*aEventData*/, TAny* /*aSource*/)
+/**
+ Notification - does nothing. Needs to be implemented by deriving class to achieve functionality.
+ @internalTechnology
+ @version 0.01
+**/
+	{}
+	
+void CNetworkConfigExtensionBase::DoOnDaemonProgress(TInt aStage, TInt aError)
+/**
+ * Called by CNifDaemonProgress when it receives a progress notification. 
+ * Passes the notification to CNifAgentRef.
+ * 
+ * @internalComponent
+ * 
+ * @param aStage Progress stage reported by the daemon
+ * @param aError Error code associated with the stage
+ */
+	{
+	if (iNifIfNotify)				// see comment in AsyncDelete()
+		{
+		iNifIfNotify->IfProgress(aStage, aError);
+		}
+	}
+
+void CNetworkConfigExtensionBase::DoOnGenericProgress(TInt aStage, TInt aError)
+/**
+ * Called to generate the cs_daemon generic progress notifications.
+ * 
+ * @internalComponent
+ * 
+ * @param aStage Generic progress stage
+ * @param aError Error code associated with the stage
+ */
+	{
+	iLastGenericProgressStage = aStage;
+	if (iNifIfNotify)				// see comment in AsyncDelete()
+		{
+		iNifIfNotify->IfProgress(aStage, aError);
+		}
+	}
+