tcpiputils/dhcp/src/DHCPControl.cpp
changeset 0 af10295192d8
child 61 2fc972553898
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dhcp/src/DHCPControl.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,1290 @@
+// 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 the DHCP control plain
+// 
+//
+
+/**
+ @file DHCPControl.cpp
+ @internalTechnology
+*/
+
+#include "DHCPControl.h"
+#include "DHCPStates.h"
+#include "DHCPStateMachine.h"
+#include "DHCPConfigListener.h"
+#include "DNSUpdateIf.h"
+#include "DHCPDb.h"
+#include "DHCPMsg.h"
+#include "NetCfgExtDhcpControl.h"
+#include <nifman.h>
+#include <comms-infras/es_config.h>
+#ifdef _DEBUG
+#include "DHCPServer.h"
+#endif
+
+#include "DHCPStatesDebug.h"
+
+#ifdef SYMBIAN_NETWORKING_PLATSEC
+#include <comms-infras/rconfigdaemonmess.h>
+#else
+#include <comms-infras\cs_daemonmess.h>
+#endif
+
+#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#include "dhcphwaddrmanager.h"
+const TInt KEightBit = 8;
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <nifman_internal.h>
+#endif
+
+
+CDHCPControl::~CDHCPControl()
+	{
+  	CompleteClientMessage( KErrCancel ); // complete all. must be before the rest to avoid deadlock with ESOCK
+	delete iDhcpStateMachine;
+	delete iTimer;
+	iConnection.Close();
+	delete iDhcpDb;
+	iValidMsg.Close();
+	delete iDhcpConfigListener;
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+	delete iDNSRawOption;
+#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+	delete iDhcpHwAddrManager;
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#endif 	// SYMBIAN_NETWORKING_DHCPSERVER	
+	}
+
+//_LIT(KIp6Interface1,"ipcp6");
+//_LIT(KIp6Interface2,"eth6");
+
+void CDHCPControl::FindInterfaceNameL(const TConnectionInfo& aInfo, TInt aFamily)
+/**
+  * Finds the interface name by querying
+  * the connection for the name
+  *
+  * @internalTechnology
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::FindInterfaceName")));
+
+	TConnectionInfoBuf connInfo = aInfo;
+	// store IAP for later so we can access CommDB
+	iDhcpDb->iIapId = connInfo().iIapId;
+	User::LeaveIfError(iConnection.Open(iEsock));
+	User::LeaveIfError(iConnection.Attach(connInfo, RConnection::EAttachTypeMonitor));
+	TInt err = KErrNotFound;	// to ensure we can check that we found connection info
+	
+	TPckgBuf<TConnInterfaceName> name;
+	name().iIndex=1;
+	//this is somethig unheard of in OO environment that we cannot get hold of a simple object relations
+	//forced to do this horrible stuff
+	RSocket socket;
+	User::LeaveIfError(socket.Open(iEsock, KAfInet, KSockDatagram, KProtocolInetUdp,iConnection));
+	// make socket invisible for interface counting
+	User::LeaveIfError(socket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0));
+	
+	CleanupClosePushL( socket );
+	TPckgBuf<TSoInet6InterfaceInfo> info;
+	while ( err == KErrNotFound && iConnection.Control(KCOLProvider, KConnGetInterfaceName, name) == KErrNone )
+		{
+		TSoInet6InterfaceInfo& q = info();
+		User::LeaveIfError(socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl, 0));
+		do
+			{
+			User::LeaveIfError(socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info));
+			}
+		while ( q.iName != name().iName );
+		
+		if ( q.iState == EIfUp &&
+			q.iAddress.Family() == KAfInet6 && !q.iAddress.IsV4Mapped() )
+			{
+			if ( (TUint)aFamily == KAfInet6 )
+				{
+				err = KErrNone;
+				}
+			}
+		else if ( (TUint)aFamily == KAfInet )
+			{
+			err = KErrNone;
+			}
+#if 0
+			switch (aFamily)
+			{
+			case KAfInet6:
+				if ( name().iName.FindF( KIp6Interface1 ) != KErrNotFound ||
+					name().iName.FindF( KIp6Interface2 ) != KErrNotFound )
+					{
+					err = KErrNone;
+					}
+				break;
+			case KAfInet:
+				if ( name().iName.FindF( KIp6Interface1 ) == KErrNotFound &&
+					name().iName.FindF( KIp6Interface2 ) == KErrNotFound )
+					{
+					err = KErrNone;
+					}
+				break;
+			};
+#endif
+			name().iIndex++;
+		}
+	User::LeaveIfError(err);	// make sure we found something useful
+	CleanupStack::PopAndDestroy( 1 ); //socket
+	iInterfaceName = name().iName;
+	}
+
+void CDHCPControl::Cancel()
+{
+   CompleteClientMessage( KErrCancel ); //cancel all. must be before the rest to avoid deadlock with ESOCK
+    if(iDhcpStateMachine)
+        {
+        iDhcpStateMachine->Cancel();
+        }
+   
+   iInitStartedByRenew = EFalse;
+}
+
+TBool CDHCPControl::CompleteClientMessage(TInt aError, TInt aFunctionToCancel)
+/** 
+  * If necessary then complete client.
+  *   If complete is performed, true is returned
+  */
+	{
+	if (iMessage &&
+		 !iMessage->IsNull() &&
+		  ( aFunctionToCancel == -1 || aFunctionToCancel == iMessage->Function() || EConfigDaemonDeregister == iMessage->Function() ) )
+		{
+		iMessage->Complete(aError);
+		iMessage = NULL;
+		return ETrue;
+		}
+	return EFalse;
+	}
+	
+
+
+void CDHCPControl::BindingFinishedL()
+   {
+   //cancel any pending timer
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::BindingFinishedL")));
+	iTimer->Cancel();
+	UpdateDns(iDhcpStateMachine->iHostName, iDhcpStateMachine->iDomainName);
+	iDhcpStateMachine->iStartedAquisitionAt.HomeTime(); //remember acquisition time
+	
+	/** A compromise til we have implemented the "lifetime" option (#42) for
+	  *  stateless configuration mode - if iRenewalTimeT1 hasn't been read (because we
+	  *   didn't read IA information), we don't attempt a renew later.
+	  *    This prevents entry to the renew functionality which acts as though we are
+	  *     in stateful mode (attempting a full renew / rebind / re-lease)
+	  */
+	if(iDhcpStateMachine->iRenewalTimeT1)
+		{
+		//Start renewal timer
+		iTimer->After(static_cast<TTimeIntervalSeconds>(iDhcpStateMachine->iRenewalTimeT1), *this);
+		}
+	SaveMessageBufferForLaterReference();
+	ServiceAnyOutstandingIoctlL();
+	CompleteClientConfigureMessage(KErrNone);
+	DHCP_DEBUG_PUBLISH_READY(DHCPDebug::EReady);
+	}
+ 
+ 
+void CDHCPControl::ServiceAnyOutstandingIoctlL()
+	{
+	if(iMessage && !iMessage->IsNull() && (iMessage->Function() == EConfigDaemonIoctl || iMessage->Function() == EConfigDaemonDeregister))
+		{
+		TInt err = KErrNone;
+		
+		// Run the request again, this time service it (because iMessage is set).  We need
+		// to check to make sure the IOCTL is not a renew which has caused a reinitialisation
+		// - we don't want to restart the IOCTL!.
+		if( ( ( iState != EInitInProgress ) && ( iState != EInformInProgress ) ) || !iInitStartedByRenew )
+			{
+			TRAP(err,HandleClientRequestL(*iMessage));
+			}
+		iInitStartedByRenew = EFalse;
+		
+		CompleteClientIoctlMessage(err);
+		}
+	}
+
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER	
+void CDHCPControl::ServiceAnyOutstandingServerIoctlL()
+	{
+	if(iMessage && !iMessage->IsNull() && iMessage->Function() == EConfigDaemonIoctl)
+		{
+		// run the request again, this time service it (because iMessage is set)
+		TRAPD(err,HandleClientRequestL(*iMessage));
+		CompleteServerIoctlMessage(err);
+		}
+	}
+#endif // SYMBIAN_NETWORKING_DHCPSERVER			
+	
+void CDHCPControl::SaveMessageBufferForLaterReference()
+	{
+	//save the msg buffer in case user wants to retrieve any info
+	TPtr8 messageBuf = iDhcpStateMachine->Message()->Message().Des();
+	TInt len = messageBuf.Length();
+	TInt err = KErrNone;
+	
+	if ( iValidMsg.MaxLength() < len )
+			{
+			//we cannot use any other buffer (e.g ~CMessageSender one) unfortunately since the
+			//message options are valid over potential renew/rebind initalised manualy, by
+			//timeout or reconfigure.
+			iValidMsg.Close();
+			err = iValidMsg.Create(len);
+			}
+		//if we cannot create the iValidMsg then, well, bad luck
+		if ( err == KErrNone )
+			{
+			iValidMsg.Copy(messageBuf); 
+			}
+		else
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::SaveMessageBufferForLaterReference Error %d: couldn't store received message"),err));
+			}
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+		if (iDhcpStateMachine->iDhcpInformAckPending && iMessage)
+			{
+			TRAPD(err,InformCompleteRequestHandlerL());
+			CompleteClientIoctlMessage(err);
+			iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+			}	
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+	if(iDHCPServerImpl)
+		{
+		if(iDNSRawOption)
+			{
+			TPtr8 ptr = iDNSRawOption->Des();
+			HandleSetRawOptionCodeL(&ptr);
+			}
+		}
+#endif // 	SYMBIAN_NETWORKING_DHCPSERVER
+	}
+   
+   
+TBool CDHCPControl::OnCompletion( CStateMachine* aStateMachine )
+/**
+  * OnCompletion function
+  *
+  * if this method returns ETrue then aStateMachine deletes itself.
+  * In this case it does not ever return ETrue.
+  * Called upon completion or when suspended.
+  *
+  * @see CStateMachine::iSuspendRequest comment
+  * @internalTechnology
+  */
+	{
+	TRAPD(err, TaskCompleteL(aStateMachine->LastError()));
+	if (err != KErrNone)
+		{
+		// complete the client if this release was prompted by them
+		if(CompleteClientConfigureMessage(err))
+			{
+			// i.e. only if client is waiting for a configure action (not ioctl)
+
+			if(err != KErrNoMemory )
+				{
+				// by doing this we will make sockets get errored as there is no src addr
+				iDhcpStateMachine->RemoveConfiguredAddress();
+				iValidMsg.Close();
+				}
+			}
+		}
+	return EFalse; //Always!!!
+	}
+
+void CDHCPControl::SaveAndHandleClientRequestL(const RMessage2& aMessage,TUint aOptionName,TInt aValue )
+	{
+	TInt deferRequest=0;
+	
+	deferRequest = CDHCPControl::HandleClientRequestL(aOptionName,aValue);
+	
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::SaveAndHandleClientRequestL")));
+		
+	iMessage = &aMessage;
+	if( !deferRequest )
+		{
+		CompleteClientIoctlMessage(KErrNone);
+		}
+	else
+ 		{
+ 		if (deferRequest < KErrNone )
+ 			{
+ 			//return the err Value and  complete immediately
+			CompleteClientIoctlMessage(deferRequest);
+			}
+		}
+	}
+	
+
+void CDHCPControl::HandleClientRequestL(const RMessage2& aMessage)
+/**
+  * Receives client requests from RConnection.
+  * 
+  * This is the base implementation that is called
+  * to service client requests.  It handles the 
+  * reading and writing of data into the message
+  * and passes control to the derived implementation
+  * to provide the correct info, then completes the message
+  * when done.  If there is an error the message
+  * is completed by the session.
+  *
+  * DEFERRING:
+  *
+  * When the request is first made, and it's possible to defer the request.
+  *  This is done by setting iMessage to the message.
+  *
+  * @internalTechnology
+  */
+	{
+	if (aMessage.Function() == EConfigDaemonDeregister)
+		{
+		iDhcpDaemonDeregister = ETrue;
+		SaveAndHandleClientRequestL(aMessage,KConnAddrRelease);	
+		return;	
+		}
+	
+	if(aMessage.Function() != EConfigDaemonIoctl ||
+	   iMessage != 0 && iMessage != &aMessage)
+		{
+		User::Leave(KErrUnknown);
+		}
+	
+	TUint optionName = aMessage.Int1();
+	TInt length      = aMessage.Int3();
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+	TInt desLength= aMessage.GetDesLength(2);
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+
+#if _DEBUG
+    if(optionName & KDhcpInterfaceDbgIoctl)
+    	{
+    	HandleInterfaceDebugL(aMessage);
+    	}
+	else
+#endif
+	if (length>0)
+		{
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER			
+			//Only below commands are supported by DHCP server implementation.
+			//Any other commands are not supported.
+			if(iDHCPServerImpl)
+				{
+#ifndef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+				if(optionName != KConnSetDhcpRawOptionData )
+#else
+				if((optionName != KConnSetDhcpRawOptionData ) && (optionName != KConnDhcpSetHwAddressParams))
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+					{
+					CompleteClientIoctlMessage(KErrNotSupported);
+					}
+				}
+#endif // SYMBIAN_NETWORKING_DHCPSERVER	
+		
+		if(optionName == KConnAddrRenew)
+			{
+			//processing renew with user defined timeout
+			
+			TInt secValue;
+			TPckg<TInt> val(secValue);
+			aMessage.ReadL(2, val,0);
+
+			SaveAndHandleClientRequestL(aMessage, optionName,secValue);	
+			}
+		else
+			{
+			HBufC8* buffer = HBufC8::NewMaxLC(length);
+			TPtr8 ptr = buffer->Des();
+			aMessage.ReadL(2, ptr);
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+			ptr.SetLength(desLength);
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+			
+			TInt deferRequest =  HandleClientRequestL(optionName, &ptr);
+
+			iMessage = &aMessage;
+			if( !deferRequest )
+				{
+				// request was serviced.. complete immediately
+				aMessage.WriteL(2, ptr);
+				CompleteClientIoctlMessage(KErrNone);
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+				iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS					
+				}
+			else
+				{
+				if (deferRequest < KErrNone)
+					{
+					//return the err Value and  complete immediately
+					CompleteClientIoctlMessage(deferRequest);
+					}
+				}	
+			CleanupStack::PopAndDestroy(buffer);
+			}
+		}
+	else
+		{
+		SaveAndHandleClientRequestL(aMessage,optionName);
+		}
+	}
+
+void CDHCPControl::HandleInterfaceDebugL(const RMessage2& aMessage)
+/**
+  * Receives client requests for Debug on this interface.
+  * 
+  * @internalTechnology
+  */
+	{
+#ifdef _DEBUG
+//-- perform debug control from the client side.
+//-- Enabled for debug builds only.
+	TUint optionName = aMessage.Int1();
+	TInt length      = aMessage.Int3();
+    TInt nResult     = KErrNone;
+
+    if(optionName & KDhcpInterfaceDbgIoctl)
+    	{
+        
+        TPckgBuf<TInt> ctlParamBuf;
+        TInt ctlParam = 0;
+        
+        //-- read IOCTL parameter if appropriate
+        if(optionName & KConnReadUserDataBit)
+            {
+            //-- the parameter should be TUint as it is a debug control parameter
+            if(length != static_cast<TInt>(sizeof(TUint)))
+    			{
+        		nResult = KErrArgument; //-- wrong parameter type
+        		}
+        	else
+        		{
+            	aMessage.ReadL(2, ctlParamBuf);
+				ctlParam = ctlParamBuf();
+				}
+			}
+		
+		if(nResult == KErrNone)
+		{
+	        //-- perform IOCTL functon
+	        switch(optionName)
+	        	{
+	            case KDHCP_GetPubSubMonitorHandle:    
+
+	                //-- easy handle.. state machine pointer.
+	                ctlParam = (TInt)iDhcpStateMachine;
+
+	                nResult = KErrNone;
+	            	break;
+
+	            default:
+	                nResult = KErrArgument; //-- wrong function
+	       	 	}//switch
+
+			//-- write IOCTL result if appropriate
+			if(optionName & KConnWriteUserDataBit)
+				{
+				ctlParamBuf() = ctlParam;
+				aMessage.WriteL(2,ctlParamBuf);
+				}
+			
+    	}
+		
+        aMessage.Complete(nResult);
+    	}
+#else
+	aMessage.Complete(KErrNotSupported);
+#endif
+	}
+
+
+
+void CDHCPControl::ConfigureL(const TConnectionInfo& /*aInfo*/, const RMessage2* aMessage)
+/**
+  * Open and attach to the RConnection
+  *
+  * @internalTechnology
+  */
+	{
+	// This ConfigureL is called at the start of the derived class ConfigureL.
+
+	iMessage = aMessage;
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::ConfigureL")));
+	
+	delete iDhcpStateMachine;
+	iDhcpStateMachine = NULL;
+	delete iDhcpDb;
+	iDhcpDb = NULL;
+	
+	delete iTimer;
+	iTimer = NULL;
+	iTimer = CExpireTimer::NewL();
+	}
+
+void CDHCPControl::ConfigureL( TBool aStaticAddress )
+	{
+	// This ConfigureL is called at the end of the derived class ConfigureL.
+	// We create the listener here as by now the interface name should be set.
+	// Also, this is before the state m/c is started so we are already
+	// registered for linklocal events.
+	if (!iDhcpConfigListener)
+		{
+		// we will continue normal processing if we fail on construction in any way
+		TRAP_IGNORE(iDhcpConfigListener = CDHCPConfigListener::NewL(iInterfaceName, *this));
+		}
+
+	// if we have ipAddrFromServer = EFalse in commDB then we have read the static address 
+	// and must therefore inform of static ipaddress to the dhcp server. The ReadCommDbL
+	// returns the value of the ipAddrFromServer field
+	//iConfigType = EConfigNoIPAddress;
+	if ((aStaticAddress) || iConfigType == EConfigNoIPAddress)
+		{
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER			
+		if(iDHCPServerImpl) 
+			{
+			iDhcpStateMachine->iSvrState = ESvrBinding;
+			CompleteClientConfigureMessage(KErrNone);
+			}
+		else 
+			{
+#endif // SYMBIAN_NETWORKING_DHCPSERVER		
+		// We must find out if any information critical to connection start completion is not yet known..
+		if(InformNegotiationIsRequiredForConnectionStartCompletion())
+			{
+			// .. if that's the case we must try to find it by DHCP before we complete the connection start.
+			iDhcpStateMachine->StartInformL(this,aStaticAddress);
+			iState = EInformInProgress;
+			}
+		else
+			{
+			// .. otherwise we can defer negotiations til a client specifically needs to access an option
+			//  (e.g. SIP server address)
+			iState = EDeferredInform;
+			CompleteClientConfigureMessage(KErrNone);
+			}
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER			
+			}
+#endif // SYMBIAN_NETWORKING_DHCPSERVER					
+		}
+	else
+		{
+		TTime timeNow;
+ 		timeNow.HomeTime();
+	   	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Lease expires at: %Ld. Time now: %Ld"),iDhcpDb->iLeaseExpiresAt.Int64(),timeNow.Int64()));
+ 		if (iDhcpDb->iLeaseExpiresAt>timeNow)
+			{	
+#ifdef _DEBUG
+			if (CDHCPServer::DebugFlags() & KDHCP_ForceDiscovery)
+				{
+				iDhcpStateMachine->StartInitL(this, iConfigType == EConfigIPAddress ? CDHCPStateMachine::ESubsequentCalls : CDHCPStateMachine::EFirstCall);
+				iState = EInitInProgress;
+				}
+			else 
+				{
+				iDhcpStateMachine->StartRebootL(this);
+				iState = EInitInProgress;
+				}
+#else
+			iDhcpStateMachine->StartRebootL(this);
+			iState = EInitInProgress;
+#endif
+			}
+		else 
+			{
+			// lease has already expired or we didn't have one...
+			// so we must do discovery but can request the known ip address if there is one...
+			iDhcpStateMachine->StartInitL(this, iConfigType == EConfigIPAddress ? CDHCPStateMachine::ESubsequentCalls : CDHCPStateMachine::EFirstCall);
+			iState = EInitInProgress;
+			}
+		}
+
+	DHCP_DEBUG_PUBLISH_READY(DHCPDebug::ENotReady);
+	}
+
+
+TBool CDHCPControl::InformNegotiationIsRequiredForConnectionStartCompletion(void) const
+	{
+	// We assume that we already know that we don't need to use DHCP to find an ip address
+	//  This is reasonable as this method shouldn't be called from a discover/request control path.
+	
+	// Check if it's DHCP's job to find DNS addresses..
+	if(iDhcpStateMachine->iNameServerAddressesFromServer &&
+	   ! iDhcpStateMachine->DoesInterfaceKnowAnyDNSServers() )
+		{
+		iDhcpStateMachine->SetFastTimeoutDuringInform();
+		return ETrue;
+		}
+	
+	return EFalse;
+	}
+
+TBool CDHCPControl::ShouldInformAfterFailedInit(void)
+	{
+	return EFalse;
+	}
+
+void CDHCPControl::TimerExpired()
+/**
+  * Called by the timer to signal that the timer has expired
+  *
+  * @internalTechnology
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::TimerExpired()")));
+
+	switch (iState)
+		{
+		case EInitialised:
+     	case EReconfigureInProgress://this enum should really be changed in derived class
+                                  //to EInitialised in case 
+                                  //!iDhcpStateMachine->IsGettingCfgInfoOnly() so we could assert but....
+			//This is renew timeout. Start renew process and rebind timeout.
+        {
+    
+	    	iDhcpStateMachine->Cancel();
+	    	iDhcpStateMachine->iMaxRetryCount = 3; 
+			TRAPD(err, iDhcpStateMachine->StartRenewL(this,0));  //If server doesn't respond after 3 attempts, a rebind is initiated..Pls not Ipv6 calculates its own retry values
+			if (err != KErrNone)
+				{
+				//This might happen only due to lack of memory. Retry after timeout.
+				iTimer->After(TTimeIntervalSeconds(KFailTimeOut), *this);
+				return;	
+				}
+			iState = ERenewInProgress;
+   			iTimer->After(TTimeIntervalSeconds(iDhcpStateMachine->iRebindTimeT2 - iDhcpStateMachine->iRenewalTimeT1 + 1), *this);
+			break;
+        }
+		case ERenewInProgress:
+			//This is rebind timeout. Start rebind process and final lease timeout.
+        {
+        	iDhcpStateMachine->Cancel();
+			TRAPD(err, iDhcpStateMachine->StartRebindL(this));  //If server doesn't respond after 3 attempts, dhcp moves on to the INIT state..Pls not Ipv6 calculates its own retry values
+			if (err != KErrNone)
+				{
+				//This might happen only due to lack of memory. Retry after timeout.
+				iTimer->After(TTimeIntervalSeconds(KFailTimeOut), *this);
+				return;	
+				}
+			//Rebind timeout
+			iTimer->After(TTimeIntervalSeconds(iDhcpStateMachine->iLeaseTime - iDhcpStateMachine->iRebindTimeT2 + 1), *this);
+			iState = ERebindInProgress;
+			iDhcpStateMachine->iTaskStartedAt = 0;
+			break;
+        }
+		case ERebindInProgress:
+			//This is lease timeout. 
+			//Remove configured address (from TCPIP6 stack) and start discovery process.
+        {
+			iDhcpStateMachine->RemoveConfiguredAddress();
+         	iDhcpStateMachine->Cancel();
+         	iValidMsg.Close();
+         	iDhcpStateMachine->iMaxRetryCount = 2;
+         	TRAPD(err, iDhcpStateMachine->StartInitL(this,CDHCPStateMachine::ESubsequentCalls));
+			if (err != KErrNone)
+				{
+				//This might happen only due to lack of memory. Retry after timeout.
+				iTimer->After(TTimeIntervalSeconds(KFailTimeOut), *this);
+				return;
+				}
+			iState = EInitInProgress;
+			break;
+        }
+		default:
+			_LIT(KDhcpPanicReason, "Timer expired in unexpected state");
+			User::Panic(KDhcpPanicReason, KErrNotSupported);
+		}
+	}
+
+void CDHCPControl::TaskCompleteL(TInt aError)
+/**
+  * Signals the end of a task
+  * and decides what we should do when
+  *
+  * @internalTechnology
+  */
+	{
+	// cancel possibly working message sender & socket activity and delete current states
+	iDhcpStateMachine->Cancel();
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, 
+		         _L8("CDHCPControl::TaskCompleteL (%d) with error = %d") ,
+		         iState, aError));
+	if ( aError == KErrServerTerminated )
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, 
+		         _L8("CDHCPControl::TaskCompleteL server terminated => complete client request & going to idle")));
+		iState = EEnd;
+		CompleteClientConfigureMessage(aError);
+		CompleteClientIoctlMessage(aError);
+		return;
+		}
+	switch (iState)
+		{
+		case EInitInProgress:
+			if (KErrTimedOut == aError)
+				{
+				// Listen for Link Local address.
+				// DHCP server is timed out so we unblock our client.
+				if (iDhcpConfigListener && iDhcpConfigListener->HaveLinkLocal())
+					{
+					CompleteClientConfigureMessage(KErrNone);
+					// don't complete any outstanding ioctl yet..
+					}
+				}
+
+			if (iDhcpStateMachine->Idle())
+				{
+				ServiceAnyOutstandingIoctlL();
+				CompleteClientConfigureMessage(KErrNone);
+				iState = EEnd;
+				return;
+				}
+
+			if (iDhcpStateMachine->CompleteClientRequest())	// 'O' flag true in RA
+				{
+				CompleteClientConfigureMessage(KErrNone);
+				iDhcpStateMachine->SetCompleteClientRequestFalse();
+				iDhcpStateMachine->StartInformL(this, EFalse);
+				return;
+				}
+
+			if (KErrNone != aError)
+				{
+				iDhcpStateMachine->SetLastError(aError);
+				if (iDhcpStateMachine->History() & CDHCPState::EBinding)
+					{
+					// ARP failed, duplicate address found so cannot use assigned one. Send DHCPDECLINE.
+					// After decline task being finished, we will complete client request with error.
+					iDhcpStateMachine->iMaxRetryCount = 3; 
+					iDhcpStateMachine->StartDeclineL(this);
+					iState = EDeclineInProgress;
+
+					return;
+					}
+				//We received either NACK or not any DHCP server replied. Retry it.
+				if(ShouldInformAfterFailedInit())
+					{
+					__CFLOG_VAR((KLogSubSysDHCP, KLogCode, 
+					         _L8("CDHCPControl::TaskCompleteL starting Inform because Init failed...")));
+					iDhcpStateMachine->StartInformL(this, /*aStaticAddress=*/ ETrue);
+					iState = EInformInProgress;
+					}
+				else
+					{
+					__CFLOG_VAR((KLogSubSysDHCP, KLogCode, 
+					         _L8("CDHCPControl::TaskCompleteL restarting Init because Init failed...")));					
+					iDhcpStateMachine->iMaxRetryCount = 2;         
+					iDhcpStateMachine->StartInitL(this,CDHCPStateMachine::ESubsequentCalls);
+					}
+
+				return;
+				}
+
+			// we're bound
+         	BindingFinishedL();
+			iState = EInitialised;
+			break;
+
+		case ERenewInProgress:
+			if (KErrNone != aError)
+				{
+				//Complete client request with error if there is any
+				CompleteClientConfigureMessage(aError); //unlikely
+				CompleteClientIoctlMessage(aError);
+				//Renew process has failed.
+				return;
+				}
+
+			// we're bound
+         	BindingFinishedL();
+			iState = EInitialised;
+			break;
+
+		case ERebindInProgress:
+			if (KErrNone != aError)
+				{
+				//Complete client request with error if there is any
+				CompleteClientConfigureMessage(aError); //unlikely
+				CompleteClientIoctlMessage(aError);
+				//Renew process has failed. We wait for rebind timer (which is already running)
+				//to expire to start rebind process.
+				return;
+				}
+
+			// we're bound
+			iTimer->Cancel();
+         	BindingFinishedL();
+			iState = EInitialised;
+			break;
+
+		case EDeclineInProgress:
+			//Decline message has been sent. Retry discovery.
+			CompleteClientConfigureMessage(aError);
+			iDhcpStateMachine->StartInitL(this,CDHCPStateMachine::ESubsequentCalls);
+			iState = EInitInProgress;
+			break;
+
+		case EReleaseInProgress:
+			if (! iDhcpDaemonDeregister)  
+				{
+				iDhcpStateMachine->RemoveConfiguredAddress();
+				iDhcpDaemonDeregister = EFalse;
+				}
+			ServiceAnyOutstandingIoctlL();
+			CompleteClientConfigureMessage(KErrNone);
+			iState = EEnd;
+			break;
+		case EInformInProgress:
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+			if ( aError == KErrTimedOut && iDhcpStateMachine->iDhcpInformAckPending)
+				{
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, 
+		         _L8("CDHCPControl::Inforrm Request TaskCompleteL requests timed out => complete client request & going to idle")));
+				iState = EEnd;
+				TRAPD(err,InformCompleteRequestHandlerL());
+				CompleteClientIoctlMessage(err);
+				CompleteClientConfigureMessage(err);
+				return;
+				}
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS		
+			SaveMessageBufferForLaterReference();
+			ServiceAnyOutstandingIoctlL();
+			CompleteClientConfigureMessage(KErrNone);
+			DHCP_DEBUG_PUBLISH_READY(DHCPDebug::EReady);
+			iState = EEnd;
+			break;
+		default:
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::TaskCompleteL not supported state %d"),iState));
+			User::Leave(KErrNotSupported);
+		}
+
+	}
+
+TInt CDHCPControl::HandleClientRequestL(TUint aName, TDes8* aDes)
+/**
+  * Handles client requests made through RConnection.
+  *
+  * Clients can obtain the ip address,
+  * the dhcp server ip address, the remaining lease time
+  * and also renewing and releasing the lease. Any data from
+  * any option can also be returned as raw data using the GetDhcpRawOptionData
+  * request.
+  *
+  * returns True if request could not be serviced immediately (so should be
+  *  deferred then serviced later)
+  *
+  * @internalTechnology
+  */
+	{
+	TTime time;
+	time.HomeTime();
+	TTimeIntervalSeconds secs;
+	
+	// currently all below options should block client til DHCP negotiation has finished.
+	//   We'll service them properly after that.
+	//
+	// when requests are needed which return immediately, more complex logic will be required
+	//  to decide whether to block client or service immediately.
+	//
+	// This is only here because it's a decision that should be made here rather than in the calling function
+	//
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::HandleClientRequestL state: %d"),iState));
+	if ( !iMessage && iValidMsg.Length()==0 && iState == EDeferredInform )
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::HandleClientRequestL -> deferred inform now triggering...")));
+		iDhcpStateMachine->StartInformL(this, /*aStaticAddress=*/ ETrue);
+		iState = EInformInProgress;
+
+		return ETrue;
+		}
+
+	if ( !iMessage && iValidMsg.Length()==0 && iState == EInitInProgress )
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::HandleClientRequestL EInitInProgress...")));
+
+		return ETrue;
+		}
+	
+	// We're not ready to service any of the following ioctls if for some reason we
+	// haven't stored the reply from DHCP (e.g. because we timed out waiting for INFORM response)
+	//
+	// This is more appropriate than letting the sub-handlers throw something less meaningful
+	//
+	if (iValidMsg.Length() == 0)
+		{
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER			
+		if(!iDHCPServerImpl)
+			{
+#endif // 	SYMBIAN_NETWORKING_DHCPSERVER		
+		User::Leave(KErrNotReady);
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER					
+			}
+		else
+			{
+#ifndef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+			if(aName != KConnSetDhcpRawOptionData && aName != KConnGetDhcpRawOptionData)
+#else
+			if(aName != KConnSetDhcpRawOptionData && aName != KConnGetDhcpRawOptionData && aName != KConnDhcpSetHwAddressParams)
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+				{
+				User::Leave(KErrNotReady);
+				}
+			}
+		
+#endif // SYMBIAN_NETWORKING_DHCPSERVER			
+		}
+	
+	if (iDhcpStateMachine)
+		{
+		switch (aName)
+			{
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER			
+			case KConnSetDhcpRawOptionData:
+					{
+					HandleSetRawOptionCodeL(aDes);					
+					}
+				break;
+#endif // SYMBIAN_NETWORKING_DHCPSERVER				
+			case KConnGetCurrentAddr:
+				{
+				if (aDes->Length() < static_cast<TInt>(sizeof(TConnectionAddress)))
+					{
+					User::Leave(KErrArgument);
+					}
+				TConnectionAddress* ptr = (TConnectionAddress*)aDes->Ptr();
+				
+
+				TInetAddr* addrPtr = new (&(ptr->iAddr))TInetAddr(iDhcpStateMachine->iCurrentAddress);
+//				ptr->iAddr is just some memory in aDes. There is no guarantee that it will be a
+//				valid TInetAddr (or even a valid TDes) so what we do here is just run a constructor
+//				on this already valid memory block and we are now guaranteed to have a valid 
+//				TInetAddr - NO MEMORY IS ACTUALLY ALLOCATED BY NEW HERE - see base code for more 
+//				details
+
+				break;
+				}
+			case KConnGetServerAddr:
+				{
+				if (aDes->Length() < static_cast<TInt>(sizeof(TConnectionAddress)))
+					{
+					User::Leave(KErrArgument);
+					}
+				TConnectionAddress* ptr = (TConnectionAddress*)aDes->Ptr();
+				TInetAddr* addrPtr = new(&(ptr->iAddr))TInetAddr;
+//				ptr->iAddr is just some memory in aDes. There is nno guarantee that it will be a
+//				valid TInetAddr (or even a valid TDes) so what we do here is just run a constructor
+//				on this already valid memory block and we are now guaranteed to have a valid 
+//				TInetAddr - NO MEMORY IS ACTUALLY ALLOCATED BY NEW HERE - see base code for more 
+//				details
+	
+				iDhcpStateMachine->GetServerAddress( *addrPtr );
+				break;
+				}
+			case KConnGetAddrLeaseTimeRemain:
+				{
+			    if (!iDhcpStateMachine->IsGettingCfgInfoOnly())
+					{
+					time.SecondsFrom(iDhcpStateMachine->iStartedAquisitionAt, secs);
+					
+					if (aDes->Length()!=static_cast<TInt>(sizeof(TConnectionLeaseInfo)))
+						{
+						User::Leave(KErrArgument);
+						}
+					(*(TConnectionLeaseInfo*)aDes->Ptr()).iSecondsRemaining = iDhcpStateMachine->iLeaseTime-secs.Int();
+					}
+				break;
+				}
+			case KConnGetDhcpRawOptionData:
+			    //-- DHCP option data format is absolutely different for ip4 and ip6 versions.
+			    //-- so, handle this request separately in CDHCPIP4Control and CDHCPIP6Control
+			    HandleGetRawOptionDataL(aDes);
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS				
+			    if (iDhcpStateMachine->iDhcpInformAckPending)
+			    	{
+			    	return ETrue;
+			    	}
+#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS					
+			    
+			    break;
+			
+			// SIP server/gateway ?? Which?
+			case KConnGetSipServerAddr:
+				/*
+					Different methods of obtaining the SIP server addresses
+					are specified for IPv4 vs. IPv6.
+					
+					RFC3361 - Dynamic Host Configuration Protocol (DHCP-for-IPv4) 
+							  Option for Session Initiation Protocol (SIP) Servers							  
+							  ! - Not currently implemented
+					
+					RFC3319 - Dynamic Host Configuration Protocol (DHCPv6) Options
+							  for Session Initiation Protocol (SIP) Servers 							
+				*/
+				
+				HandleGetSipServerAddrL(aDes);
+				
+				break;
+		
+			case KConnGetSipServerDomain:
+				
+				HandleGetSipServerDomainL(aDes);
+				break;
+#ifdef SYMBIAN_TCPIPDHCP_UPDATE			
+			case KConnGetDomainSearchList:
+				/*
+				Extract the list of domain names during name resolution
+				Refer : RFC3646 - Dynamic Host Configuration Protocol (DHCPv6) Options
+				for Domain Search List option(option 24)							
+				*/		
+				HandleGetDomainSearchListL(aDes);
+				break;	
+				
+			case KConnGetDNSServerList:
+				/*
+				Extract the list of IPv6 address of DNS recursive name server
+				Refer : RFC3646 - DNS Recursive Name Server option(option code 23)							
+				*/		
+				HandleGetDNSServerListL(aDes);
+				break;	
+#endif // SYMBIAN_TCPIPDHCP_UPDATE				
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS				
+			case KConnGetDhcpHdrSname:
+				{
+				/*
+				Extract the server hostname 
+				**/
+				GetDhcpHdrSnameL(*aDes);
+				break;
+				}
+				
+			case KConnGetDhcpHdrSiaddr:
+				{
+				/*
+				Extract the server IPAddress 
+				**/
+				GetDhcpHdrSiaddrL(*aDes);
+				break;
+				}
+				
+		
+			case KConnGetTftpServerAddr:
+				{
+				/*
+				Extract the TFTP Server Address
+				**/	
+				HandleGetTftpServerAddrL(*aDes);
+				if (iDhcpStateMachine->iDhcpInformAckPending)
+			    	{
+			    	return ETrue;
+			    	}
+			    break;	
+				}
+			
+			case KConnGetTftpServerName:
+				{
+				/*
+				Extract Tftp Server Name
+				**/
+				HandleGetTftpServerNameL(*aDes);
+				if (iDhcpStateMachine->iDhcpInformAckPending)
+			    	{
+			    	return ETrue;
+			    	}
+				break;
+				}
+
+			case KConnDhcpGetMultipleParams :
+				{
+				HandleGetMultipleParamsL(*aDes);
+				if (iDhcpStateMachine->iDhcpInformAckPending) //all options found ..copy the message 
+					{
+					return  ETrue; //make DHCPINFORM
+					}
+				break;
+				}
+#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION	
+			case KConnDhcpSetHwAddressParams:
+				{
+					//Extract the Hardware address from the received descriptor and preserve it for future reference.
+					Uint64 hwAddress = 0;
+					TInt length = aDes->Length();
+					if(length > KHwAddrLength)
+						{
+						// Leave the routine if the hwAddress length is not of the standard
+						User::Leave(KErrArgument);
+						}
+					__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("IOCTL Inserting the MAC address")));
+					for(TInt index = 0; index < length; index++)
+						{
+						hwAddress <<= KEightBit;
+						hwAddress += (*aDes)[index];
+						__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("%x "), (*aDes)[index]));
+						}
+					iDhcpHwAddrManager->Insert(hwAddress);
+				}
+	        	break;
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS					
+				
+			default:
+				User::Leave(KErrNotSupported);
+			}
+		}
+		
+		return EFalse; // request was serviced
+	}
+
+
+TInt CDHCPControl::HandleClientRequestL(TUint aName, TInt aValue)
+	{
+/**
+  * Handles client requests made through RConnection
+  * are handled here.  Currently aValue is used to set the 
+  * user defined renew timeout
+  * @internalTechnology
+  */
+  	TBool deferAllowed = !iMessage;
+  	TInt  deferred = EFalse;
+  
+  	if (iDhcpStateMachine)
+		{
+	   switch (aName)
+		   {
+		   case KConnAddrRelease:
+			   if (deferAllowed && !iDhcpStateMachine->IsGettingCfgInfoOnly())
+				   {
+				   iTimer->Cancel();
+				   iDhcpStateMachine->Cancel();
+				   iDhcpStateMachine->iMaxRetryCount = 3;
+				   iValidMsg.Close();
+				   
+				   // Check to see if we need to ask the DHCP server to release the address
+				   // or if we have not yet acquired an address and should cancel any operation
+				   // in progress.
+				   if( ( iState == EInitialised ) || ( iState == EReconfigureInProgress ) )
+				       {
+					   iDhcpStateMachine->StartReleaseL( this );
+					   iState = EReleaseInProgress;
+					   deferred = ETrue;
+				       }
+				   else
+				   	   {
+					   iState = EEnd;
+
+					   // Listen for Link Local address.
+					   // Assignment process has been cancelled so we unblock our client.
+					   if (iDhcpConfigListener && iDhcpConfigListener->HaveLinkLocal())
+					       {
+					  	   CompleteClientConfigureMessage(KErrNone);
+						   }
+					   }
+				   }
+			   if (iDhcpStateMachine->IsGettingCfgInfoOnly())
+		       		{
+		       		deferred = KErrNotSupported;
+		       		}
+               break;
+           case KConnAddrRenew:
+	           if (deferAllowed && !iDhcpStateMachine->IsGettingCfgInfoOnly())
+		           {
+		           iTimer->Cancel();
+		           iDhcpStateMachine->Cancel();
+			       iDhcpStateMachine->iMaxRetryCount = 3; //If server doesn't respond after 3 attempts, a rebind is initiated..Pls not Ipv6 calculates its own retry values
+
+				   // Check to see if we need to ask the DHCP server to renew the address
+				   // or if we have not yet acquired an address and should start
+				   // initialisation again (i.e., the lease has been released).
+				   if( ( iState == EInitInProgress ) || ( iState == EReleaseInProgress ) || ( iState == EEnd ) )
+					   {
+			           iDhcpStateMachine->StartInitL(this,iConfigType == EConfigIPAddress ? CDHCPStateMachine::ESubsequentCalls : CDHCPStateMachine::EFirstCall,aValue);
+			           iState = EInitInProgress;
+			           iInitStartedByRenew = ETrue;
+					   }
+				   else
+				       {
+			           iDhcpStateMachine->StartRenewL(this,aValue);
+			           iState = ERenewInProgress;
+				       }
+				   
+				   deferred = ETrue;
+		           }
+		        if (iDhcpStateMachine->IsGettingCfgInfoOnly())
+		       		{
+		       		deferred = KErrNotSupported;
+		       		} 
+		       break;
+		   default:
+			   User::Leave(KErrNotSupported);
+		   }
+		}
+	else
+		{
+		// ConfigureL must have left before it could create a state machine
+		// object, doing this is the only safe way to stop dereferencing
+		// a possibly null pointer.
+		User::Leave(KErrAbort);
+		}
+		
+	return deferred;
+	}
+	
+TInt CDHCPControl::HandleClientRequestL(TUint aName)
+/**
+  * Handles client requests made through RConnection
+  * are handled here.  These are obtaining the ip address,
+  * the dhcp server ip address, the remaining lease time
+  * and also renewing and releasing the lease
+  *
+  * @internalTechnology
+  */
+	{
+	return CDHCPControl::HandleClientRequestL(aName,0);
+	}
+
+void CDHCPControl::UpdateDns(TDesC8* aHostName, TDesC8* aDomainName)
+/**
+  * UpdateDNS function
+  *
+  * Poke the DNS update dll to perform its
+  * dynamic dns update. However, this is DHCP
+  * and we can't handle failure cases for DNS 
+  * so we ignore any errors as it's not our job
+  *
+  * @internalTechnology
+  */
+	{
+	__UHEAP_MARK;
+    CDnsUpdateIf* pUpdate = NULL;
+	TRAPD(ret,pUpdate = CDnsUpdateIf::NewL();
+			  pUpdate->Update(iInterfaceName, aHostName, aDomainName));
+	if (ret!=KErrNone)
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPControl::UpdateDns error: %d"),ret));
+		}
+	delete pUpdate;
+	REComSession::FinalClose();
+	__UHEAP_MARKEND;
+	}
+
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+void  CDHCPControl::HandleSetRawOptionCodeL(TDes8* /*aDes*/)
+	{
+	}
+#endif // SYMBIAN_NETWORKING_DHCPSERVER	
+