tcpiputils/dhcp/src/DHCPIP4Control.cpp
changeset 0 af10295192d8
child 37 052078dda061
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dhcp/src/DHCPIP4Control.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,891 @@
+// 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 IP4 control plain
+// 
+//
+
+/**
+ @file DHCPIP4Control.cpp
+ @internalTechnology
+*/
+
+#include "DHCPIP4Control.h"
+#include "DHCPIP4States.h"
+#include "DHCPIP4Msg.h"
+#include "DHCPServer.h"
+#include "DHCPConfigListener.h"
+#include "DHCPDb.h"
+#include "ExpireTimer.h"
+#include "NetCfgExtDhcpControl.h"
+#include "DomainNameDecoder.h"
+#include <nifman.h>
+#include <comms-infras/es_config.h>
+#include "netcfgextndhcpmsg.h"
+#include <f32file.h>
+#include <comms-infras/metatype.h>
+#include <comms-infras/metadata.h>
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+#include "DHCPIP4Msg.h" 
+#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#include "dhcphwaddrmanager.h"
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+using namespace DHCPv4;
+#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS			
+
+struct TDHCPv4Persistent : public Meta::SMetaData
+{
+	TDHCPv4Persistent() : 
+		iTaskStartedAt( 0 ),
+		iCurrentAddress(KInetAddrNone,KInetPortNone),
+		iLeaseTime(0)
+		{
+		}
+
+	TTime iTaskStartedAt;
+	TInetAddr iCurrentAddress;
+	TUint32 iLeaseTime;
+
+	DATA_VTABLE
+};
+
+START_ATTRIBUTE_TABLE( TDHCPv4Persistent, KDHCPv4Persinstence, KDHCPv4PersinstenceId )
+	REGISTER_ATTRIBUTE( TDHCPv4Persistent, iTaskStartedAt, TMetaTime )
+	REGISTER_ATTRIBUTE( TDHCPv4Persistent, iCurrentAddress, TMeta<TInetAddr> )
+	REGISTER_ATTRIBUTE( TDHCPv4Persistent, iLeaseTime, TMetaNumber )
+END_ATTRIBUTE_TABLE()
+
+CDHCPIP4Control::~CDHCPIP4Control()
+	{
+	}
+
+void CDHCPIP4Control::ConfigureL(const TConnectionInfo& aInfo, const RMessage2* aMessage)
+/**
+  * Open and attach to the RConnection
+  *
+  * @internalTechnology
+  */
+	{
+   CDHCPControl::ConfigureL( aInfo, aMessage );
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4Control::ConfigureL")));
+	
+	iDhcpDb = new (ELeave) CDHCPDb( TPtrC( SERVICE_IP_DNS_ADDR_FROM_SERVER ),
+													TPtrC( SERVICE_IP_NAME_SERVER1 ),
+													TPtrC( SERVICE_IP_NAME_SERVER2 )); //for both version for the time being see the class TDHCPIP4Db coments
+	FindInterfaceNameL(aInfo,KAfInet);
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+#ifndef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+	iDhcpStateMachine = CDHCPIP4StateMachine::NewL(iEsock, iConnection, iInterfaceName,iDHCPServerImpl);
+#else
+	iDhcpHwAddrManager = CDhcpHwAddrManager::NewL();
+	iDhcpStateMachine = CDHCPIP4StateMachine::NewL(iEsock, iConnection, iInterfaceName,iDhcpHwAddrManager, iDHCPServerImpl);
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#else 
+	iDhcpStateMachine = CDHCPIP4StateMachine::NewL(iEsock, iConnection, iInterfaceName);
+#endif 	// SYMBIAN_NETWORKING_DHCPSERVER		
+	TDHCPv4Persistent pers;
+	iStaticAddress = !iDhcpDb->ReadL(*iDhcpStateMachine, pers);
+
+
+	//initialise relevant data
+	TTimeIntervalSeconds seconds = static_cast<TInt>(pers.iLeaseTime);
+	iDhcpDb->iLeaseExpiresAt = pers.iTaskStartedAt + seconds;
+	DhcpStateMachine()->iLeaseTime = pers.iLeaseTime;
+	iDhcpStateMachine->SetCurrentAddress( pers.iCurrentAddress );
+	DhcpStateMachine()->iMaxRetryCount = 2; //Max retry count for the first run is set to 2
+
+
+	TInetAddr existingGlobalAddr = iDhcpStateMachine->GetInterfaceGlobalAddress();
+
+	if( ! existingGlobalAddr.IsUnspecified() )
+		{
+		// there was an existing address on the interface, regardless of commsdat preference..
+		//  so force inform.
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Interface already has global address. Forcing inform mode.")));
+		iDhcpStateMachine->SetCurrentAddress( existingGlobalAddr );
+		iStaticAddress = ETrue;
+		}
+	else
+		{
+		if(iStaticAddress)
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Interface has a static address from commsdat. Proceeding in inform mode.")));
+			}
+		else
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Interface has no global address yet. Proceeding in discover mode.")));
+			}
+		}
+
+	CDHCPControl::ConfigureL(iStaticAddress);
+	}
+
+void CDHCPIP4Control::Cancel()
+	{
+	iClientShouldCompleteWhenLinkLocalCreated = EFalse;
+
+	// Call the base class.
+	CDHCPControl::Cancel();
+   }
+
+void CDHCPIP4Control::BindingFinishedL()
+	{
+	CDHCPControl::BindingFinishedL();
+	TDHCPv4Persistent pers;
+	//get relevant data from statemachine
+	pers.iTaskStartedAt = DhcpStateMachine()->iStartedAquisitionAt;
+	pers.iCurrentAddress = DhcpStateMachine()->iCurrentAddress;
+	pers.iLeaseTime = DhcpStateMachine()->iLeaseTime;
+	TRAPD( ret, iDhcpDb->WriteL(*iDhcpStateMachine, pers) );
+	if (ret!=KErrNone)
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4Control::BindingFinishedL error: %d"),ret));
+		}
+	}
+
+void CDHCPIP4Control::TimerExpired()
+/**
+  * Called by the timer to signal that the timer has expired
+  *
+  * @internalTechnology
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4Control::TimerExpired()")));
+
+    CDHCPControl::TimerExpired();
+	
+	// In response to the rebind operation timing out, try to create
+	// a link local to allow local addressing (may not be supported
+	// by current interface's IPv4 link local option).  We cannot
+	// create the link local earlier (e.g., after a renew attempt
+	// times-out) because the link local will not be usable until
+	// the DHCP assigned address has been removed (randomly
+	// generated addresses are prioritised below non-randomly
+	// generated addresses during selection in the TCP/IP stack).
+	if( ( iState == EInitInProgress ) && iDhcpConfigListener && !iDhcpConfigListener->HaveLinkLocal() )
+		{
+		DhcpStateMachine()->CreateIPv4LinkLocal();
+		}
+	}
+
+TInt CDHCPIP4Control::HandleClientRequestL(TUint aName, TInt aValue)
+/**
+  * Handles client requests made through RConnection
+  * are handled here.  Currently its for renewing the lease time 
+  * where client passes in a required timeout 
+  * @see CDHCPControl::HandleClientRequestL
+  *
+  * @internalTechnology
+  */
+	{
+	TBool deferAllowed = !iMessage;
+	TBool defer = EFalse;
+	
+  	defer = CDHCPControl::HandleClientRequestL(aName, aValue);
+
+	if (aName == KConnAddrRenew && iState == ERenewInProgress && deferAllowed)
+		{//Rebind timeout
+		TTimeIntervalSeconds timeOut;
+		if(aValue > 0)
+			{
+			timeOut = aValue;
+			}
+		else
+			{
+			timeOut = (DhcpStateMachine()->iRebindTimeT2 - DhcpStateMachine()->iRenewalTimeT1 + 1);
+			}
+      	iTimer->After(timeOut, *this);
+      	defer = ETrue;
+		}
+	
+	return defer;
+	}	
+
+TInt CDHCPIP4Control::HandleClientRequestL(TUint aName)
+/**
+  * Handles client requests specific for IP4
+  *
+  * @see CDHCPControl::HandleClientRequestL
+  * @internalTechnology
+  */
+	{
+	return CDHCPIP4Control::HandleClientRequestL(aName,0);
+	}
+
+/**
+    Get raw option data (IP4 version).
+    @param  pointer to the buffer descriptor for getting option data
+*/
+void CDHCPIP4Control::HandleGetRawOptionDataL(TDes8* aDes)
+{
+	TDhcp4RawOptionDataPckg pckg(*aDes);
+		
+	TUint8 opCode = pckg.OpCode();
+	TPtr8 buf(pckg.Buf());
+	GetRawOptionDataL(opCode, buf);
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+	if (!iDhcpStateMachine->iDhcpInformAckPending)   
+		{
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+	pckg.SetBufLengthL(buf.Length());
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+		}
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+}
+
+void CDHCPIP4Control::TaskCompleteL( TInt aError )
+/**
+  * TaskCompleteL 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
+  */
+	{
+	// In response to the initialisation operation timing out,
+	// try to create a link local to allow local addressing (may
+	// not be supported by current interface's IPv4 link local
+	// option).
+	if( ( aError == KErrTimedOut ) &&
+		( iState == EInitInProgress ) &&
+		!iStaticAddress &&
+		iDhcpConfigListener &&
+		!iDhcpConfigListener->HaveLinkLocal() )
+		{
+		if( DhcpStateMachine()->CreateIPv4LinkLocal() == KErrNone )
+			{
+			iClientShouldCompleteWhenLinkLocalCreated = ETrue;
+			//Link Local Address has been taken & return here itself
+			CDHCPControl::TaskCompleteL(aError);
+			return;
+			}
+		}
+	if((DhcpStateMachine()->iRetryDhcpIpCount >= KDHCPv4MaxRetryCount) && iState == EDeclineInProgress )
+		{
+		if( DhcpStateMachine()->CreateIPv4LinkLocal() == KErrNone )
+			{
+			iClientShouldCompleteWhenLinkLocalCreated = ETrue;
+			//Link Local Address has been taken & return here itself
+ 			CDHCPControl::TaskCompleteL(KErrNone);
+ 			return;
+			}
+		
+		}
+	// Call the base class.
+	CDHCPControl::TaskCompleteL( aError );
+	}
+	
+void CDHCPIP4Control::LinkLocalCreated()
+/**
+  * LinkLocalCreated function
+  *
+  * If iClientShouldCompleteWhenLinkLocalCreated is ETrue we need to complete the
+  * client messages as the link local has been created and the interface is now
+  * ready for use.
+  *
+  * @internalTechnology
+  */
+	{
+	if( iClientShouldCompleteWhenLinkLocalCreated )
+		{
+		iClientShouldCompleteWhenLinkLocalCreated = EFalse;
+		
+		CompleteClientConfigureMessage(KErrNone);
+		// don't complete any outstanding ioctl yet..
+		}
+	}
+
+void CDHCPIP4Control::GetRawOptionDataL(TUint aOpCode, TPtr8& aPtr)
+	{
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+	if(iValidMsg.Length()==0 && iDHCPServerImpl)
+		{
+		GetRawOptionDataFromDNSBufL(aPtr);
+		return;
+		}
+#endif // SYMBIAN_NETWORKING_DHCPSERVER
+	HBufC8* buf = NULL;
+	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr( const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length() );
+	msg.iRecord.ParseL(ptr); //no check necessary
+	DHCPv4::COptionNode* pOption = msg.iOptions.FindOption(static_cast<TUint8>(aOpCode));
+	if (!pOption)
+		{
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+		CleanupStack::PopAndDestroy();
+		TUint8 tempOpt=aOpCode;
+		TPtr8 optPtr(&tempOpt,1,1);
+		return(RequestInformOrCompleteCallL(optPtr));
+#else
+		User::Leave(KErrNotFound);
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+		}
+	ptr.Set(pOption->GetBodyDes());
+	if (ptr.Length() > aPtr.MaxLength())
+		{
+		User::Leave(KErrOverflow);
+		}
+	aPtr.Copy(ptr);
+	CleanupStack::PopAndDestroy();
+	}
+
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+
+void CDHCPIP4Control::GetRawOptionDataFromDNSBufL(TPtr8& aPtr)
+	{
+	if(iValidMsg.Length() == 0)
+		{
+		if (iDNSRawOption->Des().Length() > aPtr.MaxLength())
+			{
+			User::Leave(KErrOverflow);
+			}
+		aPtr.Copy(iDNSRawOption->Des());
+		}
+	}
+
+void CDHCPIP4Control::HandleSetRawOptionCodeL(TDes8* aDes)
+	{
+	if(iValidMsg.Length() == 0)
+		{
+		iDNSRawOption = HBufC8::NewL(aDes->Length());
+		iDNSRawOption->Des() = *aDes;
+		}
+	else
+		{
+		SetRawOptionCodeL(aDes);	
+		}
+	}
+
+void CDHCPIP4Control::SetRawOptionCodeL(TDes8* aDes)
+	{
+	HBufC8* buf = NULL;
+	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr( const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length() );
+	msg.iRecord.ParseL(ptr); //no check necessary
+	
+	TDhcp4RawOptionDataPckg pckg(*aDes);
+	DHCPv4::TDHCPOptionCodes opcode = static_cast<DHCPv4::TDHCPOptionCodes>(pckg.OpCode());
+	
+	DHCPv4::COptionNode* pOption = msg.iOptions.FindOption(opcode);
+	if (!pOption)
+		{
+		User::Leave(KErrNotFound);
+		}
+		
+	TPtr8 ptr2(reinterpret_cast<TUint8*>(aDes),aDes->Length());
+	
+	pOption->SetBody(ptr2);	
+	CleanupStack::PopAndDestroy(); // msg
+	}
+#endif // SYMBIAN_NETWORKING_DHCPSERVER
+
+void CDHCPIP4Control::HandleGetSipServerAddrL(TDes8* aDes)
+	{	
+	if (aDes->Length() < static_cast<TInt>(sizeof(SSipServerAddr)))
+		{
+		User::Leave(KErrArgument);
+		}
+
+	SSipServerAddr* sipServerAddr = 
+		reinterpret_cast<SSipServerAddr*>(const_cast<TUint8*>(aDes->Ptr()));
+
+	HBufC8* buf = NULL;
+	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(ptr);
+	DHCPv4::COptionNode* sipServerOption = msg.iOptions.FindOption(DHCPv4::EDHCPSIPServers);
+
+	if(sipServerOption)
+		{
+		TUint8* headerPtr = sipServerOption->Ptr();		
+		
+		TUint encoding = headerPtr[DHCPv4::KDhcpSipEncodingOffset];
+		TUint length = headerPtr[DHCPv4::KDhcpSipLengthOffset];
+		
+		if(encoding != DHCPv4::KDhcpSipEncodingAddresses)
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerAddrL: Client trying to fetch a SIP address when only a SIP domain is known")));
+			User::Leave( KErrNotFound );
+			}
+		if((TUint)sipServerAddr->index >= (length / KIp4AddrByteLength))
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerAddrL: Client tried to fetch an out-of-range SIP address %d (I only know about %d)"),(TUint)sipServerAddr->index, (length / KIp4AddrByteLength)));
+			User::Leave( KErrNotFound );
+			}
+		
+		TUint addrOffset = sipServerAddr->index * KIp4AddrByteLength;
+		
+		TUint8* bodyPtr = sipServerOption->GetBodyPtr();
+		TUint32 copiedValue;
+		// Grab ip address from option body at given offset, +1 used to skip the encoding boolean used for sip
+		Mem::Copy(&copiedValue,(bodyPtr + addrOffset+1),4);  
+		// swap around ip address as in BigEndian form
+		copiedValue = ByteOrder::Swap32(copiedValue); 
+		sipServerAddr->address.SetAddress(copiedValue);   
+		}
+	else
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerAddrL: Client tried to fetch a SIP option but none has (yet) been received")));
+		User::Leave(KErrNotFound);
+		}	
+	CleanupStack::PopAndDestroy();
+	}
+
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+void CDHCPIP4Control::GetDhcpHdrSiaddrL(TDes8& aNxtAddress)
+/**
+  * The GetDhcpHdrSiaddr function
+  *
+  * Fetches the Siaddr
+  *
+  * @param aNxtAddress Next server IPAddress fetched from the DHCP Server
+  * @internalTechnology
+  */
+	{
+	if (aNxtAddress.Length() < static_cast<TInt>(sizeof(TConnectionAddress)))
+		{
+		User::Leave(KErrArgument);
+		}
+	TConnectionAddress* ptr = (TConnectionAddress*)aNxtAddress.Ptr();
+	TInetAddr* addrPtr = new(&(ptr->iAddr))TInetAddr;	
+	//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	
+	
+	//Parse the iValidMsg
+	HBufC8* buf = NULL;
+	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 msgPtr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(msgPtr);
+	
+	//Extract the server address
+	addrPtr->SetAddress(msg.GetSIAddr());
+	
+	CleanupStack::PopAndDestroy();
+	}
+
+void CDHCPIP4Control::GetDhcpHdrSnameL(TDes8& aHdrSvrName)
+/**
+  * The GetDhcpHdrSname function
+  *
+  * Fetches the Sname
+  *
+  * @param aHdrSvrName Next server name fetched from the DHCP Server. 
+  * @internalTechnology
+  */
+	{
+	HBufC8* buf = NULL;
+	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(ptr);
+	if (msg.GetSName().Length() > aHdrSvrName.MaxLength())
+	{
+		User::Leave(KErrOverflow);
+	}
+	aHdrSvrName=msg.GetSName();
+	//SetLength otherwise received string length will be 64 by default, truncate to end of string.
+	aHdrSvrName.SetLength(aHdrSvrName.Locate('\0'));
+
+	CleanupStack::PopAndDestroy(&msg);
+	}
+	
+void CDHCPIP4Control::HandleGetTftpServerAddrL(TDes8& aDes) 
+/**
+  * The HandleGetTftpServerAddrL function
+  *
+  * Fetches the Tftp Server Address
+  * @param aDes Buffer returned contains a list of ip addresses each of 4 bytes.
+  *
+  * @internalTechnology
+  */
+	{
+	if (aDes.Length() < static_cast<TInt>(sizeof(STftpServerAddr)))
+		{
+		User::Leave(KErrArgument);
+		}
+
+	STftpServerAddr* tftpServerAddr = 
+		reinterpret_cast<STftpServerAddr*>(const_cast<TUint8*>(aDes.Ptr()));
+
+	HBufC8* buf = NULL;
+	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(ptr);
+	DHCPv4::COptionNode* tftpServerOption = msg.iOptions.FindOption(DHCPv4::EDHCPTftpServers);
+	if(tftpServerOption)
+		{
+		
+		TUint8 len=tftpServerOption->GetItemLength()-2;//subtract 2 bytes becz length include message opcode and message opcode length 
+		
+		TUint addrOffset = tftpServerAddr->index * KIp4AddrByteLength;
+		
+		if (addrOffset>len)
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetTftpServerAddrL: Client tried to fetch a invalid index of Tftp Address which is not present")));
+			iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+			User::Leave(KErrNotFound);	
+			
+			}
+		
+		TUint8* bodyPtr = tftpServerOption->GetBodyPtr();
+				
+		TUint32 copiedValue;
+		// Grab ip address from option body at given offset.
+		Mem::Copy(&copiedValue,(bodyPtr + addrOffset),4);  
+		// swap around ip address as in BigEndian form/		copiedValue = ByteOrder::Swap32(copiedValue); 
+		copiedValue = ByteOrder::Swap32(copiedValue); 
+		tftpServerAddr->address.SetAddress(copiedValue);   
+		}
+	else //check inform to be made or not..or return
+		{
+		CleanupStack::PopAndDestroy(); //pop buffer ..we are going to return immediately
+		TUint8 opt=DHCPv4::EDHCPTftpServers;
+		TPtr8 optPtr(&opt,1,1);
+		return(RequestInformOrCompleteCallL(optPtr));
+		}	
+	iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+	CleanupStack::PopAndDestroy();
+	
+}
+
+void CDHCPIP4Control::HandleGetTftpServerNameL(TDes8& aTftpSvrName)
+/**
+  * The HandleGetTftpServerName function
+  *
+  * Fetches the Tftp Server Name
+  *
+  * @param aTftpSvrName Tftp Server Name fetched from the DHCP Server.
+  * @internalTechnology
+  */
+	{
+	HBufC8* buf = NULL;
+	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(ptr);
+	DHCPv4::COptionNode* tftpOption = msg.iOptions.FindOption(DHCPv4::EDHCPTftpServerName);
+	if(tftpOption)
+		{
+		if (aTftpSvrName.MaxLength()<tftpOption->GetItemLength())
+			{
+			iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+			User::Leave(KErrOverflow);
+			}
+		else	
+			{
+			aTftpSvrName.Copy(tftpOption->GetBodyDes());
+			}
+		}
+	else 
+		{
+		//To check if DHCP Sname Option is overloaded
+		tftpOption = msg.iOptions.FindOption(DHCPv4::EDHCPOptionOverload);
+		if(tftpOption)
+			{
+			if(	msg.iOptions.GetOptionOverload() == DHCPv4::EDHCPSname)
+				{
+				GetDhcpHdrSnameL(aTftpSvrName);
+				}
+			}
+		else//now issue Inform Request for option 66 or return now..
+			{
+			CleanupStack::PopAndDestroy(); //pop buffer ..we are going to return immediately
+			TUint8 opt=DHCPv4::EDHCPTftpServerName;
+			TPtr8 optPtr(&opt,1,1);
+			return(RequestInformOrCompleteCallL(optPtr));
+			}
+		}
+		iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+		CleanupStack::PopAndDestroy();	
+	}	
+
+void CDHCPIP4Control::RequestInformOrCompleteCallL(TPtr8& aOpcodePtr)	
+/**
+  * The RequestInformOrCompleteCallL function
+  *
+  * Checks DHCPINFORM message should be sent or not
+  * @param aOpcodePtr  pointer to the opcode list to be updated  in iSavedExtraParameters
+  * @internalTechnology
+  */
+	{
+
+	if (!iDhcpStateMachine->iDhcpInformAckPending)
+		{
+		if (!iDhcpStateMachine->iSavedExtraParameters.Length())
+			{
+			iDhcpStateMachine->iSavedExtraParameters.CreateL(aOpcodePtr);
+			}
+		else
+			{
+			iDhcpStateMachine->iSavedExtraParameters.ReAllocL(iDhcpStateMachine->iSavedExtraParameters.Length()+aOpcodePtr.Length());
+			iDhcpStateMachine->iSavedExtraParameters.Append(aOpcodePtr);
+			}	
+	
+			static_cast<CDHCPIP4StateMachine*>(iDhcpStateMachine)->StartInformL( this );
+			iDhcpStateMachine->iDhcpInformAckPending=ETrue;
+  			iState = EInformInProgress;
+		}
+	else
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8(" RequestInformOrCompleteCallL::Client tried to fetch a  option but none has (yet) been received")));
+		iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+		User::Leave(KErrNotFound);	
+		}
+	}
+	
+	
+
+void CDHCPIP4Control::HandleGetMultipleParamsL(TDes8& aDes)
+/**
+  * The HandleGetMultipleParamsL function
+  *
+  * Fetches the required raw option parameter buffer.
+  * Buffer contains list of parameter options followed by msg opcode, len, data..
+  * If any of the parameters are not found, DHCPINFORM message will be sent.
+  *	Filled Returned Buffer is as shown in fig..
+  * @code
+  *		  -----------------------------------------------------
+  *		 |No of |      |Data   |      |       |Data   |        |
+  *	 	 |OpCode|OP1   |length1|Data1 |  OP2  |Length2|Data2   |
+  *		 |      |      |       |      |       |       |        |
+  *		  ----------------------------------------------------- 
+  * @endcode
+  * @param aDes Pointer to the buffer descriptor for getting option data
+  * @internalTechnology
+  */
+	{
+	HBufC8 *saveBuf=NULL, *buffer=NULL;
+	TUint8 *headerPtr;
+	TInt numOfOpcodes=0;
+	TInt totalLength=0,opcodeLength=aDes.Length();
+	TInt maxLength=aDes.MaxLength();
+	TUint8 opcode;
+	TBool allFound=ETrue;
+	
+	DHCPv4::CDHCPMessageHeaderIP4 msgSaved(saveBuf);
+	TPtr8 savedPtr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	CleanupClosePushL(msgSaved);
+	msgSaved.iRecord.ParseL(savedPtr);
+
+
+	//The below for loop checks all the required opcode data is present or not
+	//The message opcode data is not present in the iValidMsg buffer,the corresponding 
+	//opcodes are stored in iCurrentParameters for sending it in DHCPINFORM message
+	for(TInt i=0;i<opcodeLength;i++)
+		{
+		opcode=*(aDes.Ptr()+i); //search required opcode is present or not, one by one
+		DHCPv4::COptionNode* findNode = msgSaved.iOptions.FindOption(opcode);
+		if (findNode )
+			{
+			TInt bufLength=findNode->GetItemLength();
+			totalLength+=bufLength;
+			if ((totalLength+1) > maxLength)
+				{
+				totalLength-=bufLength;
+				continue; //current buffer is too big..so hope next buffer is small
+				}
+			if (!buffer)
+				{
+				buffer=HBufC8::NewLC(totalLength + 1);//+1 is extra byte to store number of opcodes
+				buffer->Des().Append(KNoChar);
+				}
+			else
+				{
+				buffer=buffer->ReAllocL(totalLength + 1);
+				CleanupStack::Pop();//buffer as ptr address has changed
+		        CleanupStack::PushL(buffer);
+				}
+			headerPtr = findNode->Ptr(); 
+			++numOfOpcodes;
+			buffer->Des().Append(headerPtr,bufLength);
+			}
+		else
+			{
+			//If atleast one opcode, among the requested, is not found then request through 
+			//DHCP INFORM message by calling RequestInformOrCompleteCallL
+			allFound=EFalse;
+			}
+		}
+	
+	if (allFound ) //everything is present..just return call now itself..
+		{
+		if ((totalLength + 1) > maxLength)
+			{
+			User::Leave(KErrOverflow);
+			}
+		if(buffer) // buffer would be NULL only when aDes.Length = 0 which is a rare scenario. But still check it to avoid NULL pointer dereference.
+			{
+			aDes.Copy(buffer->Ptr(), buffer->Length());
+			TBuf8<1> dummy;
+			dummy.FillZ(1);
+			dummy[0]=numOfOpcodes;
+			aDes.Replace(0,1,dummy);//update number of opcodes collected
+			}
+		}
+	else
+		{
+		TPtr8 opcodePtr(const_cast<TUint8*>(aDes.Ptr()),opcodeLength);
+		opcodePtr.SetLength(opcodeLength);
+		RequestInformOrCompleteCallL(opcodePtr);	
+		}	
+	
+	if (buffer)
+		{
+		CleanupStack::PopAndDestroy(buffer);
+		}
+
+	CleanupStack::PopAndDestroy(&msgSaved);
+
+	}
+
+
+TInt CDHCPIP4Control::InformCompleteRequestHandlerL()
+/**
+  * The InformCompleteRequestHandlerL function
+  * 
+  * The function will be called after the DHCPACK message is received, and 
+  * iValidMsg buffer has been updated. 
+  * Looks for the requested options present or not and appropriately calls 
+  * the function handlers
+  *
+  * @return KErrNone if the required data option is found else corresponding error code.
+  * @internalTechnology
+  */
+	{
+
+	TUint optionName = iMessage->Int1();
+	TInt length      = iMessage->Int3();
+
+	HBufC8 *buff=HBufC8::NewMaxLC(length) ;
+	TPtr8 ptr(buff->Des());
+	iMessage->ReadL(2, ptr);
+
+	
+	switch(optionName)
+		{
+		case KConnGetDhcpRawOptionData:
+			{
+			HandleGetRawOptionDataL(&ptr);
+			iMessage->WriteL(2,ptr);
+			break;
+			}
+		
+		case KConnDhcpGetMultipleParams :
+			{
+			HandleGetMultipleParamsL(ptr);
+			iMessage->WriteL(2,ptr);
+			break;
+			}
+	
+		case KConnGetTftpServerAddr:
+			{
+			HandleGetTftpServerAddrL(ptr);
+			iMessage->WriteL(2,ptr);
+			break;
+			}
+		
+		case KConnGetTftpServerName:
+			{
+			HandleGetTftpServerNameL(ptr);
+			iMessage->WriteL(2,ptr);
+			break;
+			}
+		
+		default:
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("InformCompleteRequestHandlerL : default unhandled optino Name")));
+			break;	
+	
+		}
+	iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+	CleanupStack::PopAndDestroy(buff);
+	return KErrNone;
+	 
+	}
+#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+
+
+void CDHCPIP4Control::HandleGetSipServerDomainL(TDes8* aDes)
+	{
+	if (aDes->Length() < static_cast<TInt>(sizeof(SSipServerDomain)))
+		{
+		User::Leave(KErrArgument);
+		}
+
+	SSipServerDomain* sipServerDomain = 
+		reinterpret_cast<SSipServerDomain*>(const_cast<TUint8*>(aDes->Ptr()));
+
+	HBufC8* buf = NULL;
+	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(ptr);
+	DHCPv4::COptionNode* sipServerOption = msg.iOptions.FindOption(DHCPv4::EDHCPSIPServers);
+
+	if(sipServerOption)
+		{
+		TUint8* headerPtr = sipServerOption->Ptr();
+		
+		TUint encoding = headerPtr[DHCPv4::KDhcpSipEncodingOffset];
+
+		if(encoding != DHCPv4::KDhcpSipEncodingDomains)
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerDomainL: Client trying to fetch a SIP domain when only a SIP address is known")));
+			User::Leave( KErrNotFound );
+			}
+
+		CDomainNameCodec* domainNameDecoder = new(ELeave) CDomainNameCodec();
+		CleanupStack::PushL(domainNameDecoder);
+		TPtr8 ptr = sipServerOption->GetBodyDes();
+		ptr.Set((TUint8*)(ptr.Ptr()+1),ptr.Length()-1,ptr.MaxLength()-1);
+		domainNameDecoder->DecodeL(ptr);
+
+		if(sipServerDomain->index < (TInt)domainNameDecoder->NumDomainNames())
+			{
+			TDomainName domainName = (*domainNameDecoder)[sipServerDomain->index];
+			sipServerDomain->domainName.Copy(domainName);
+			}
+		else
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerDomainL: Client tried to fetch an out-of-range SIP domain %d (I only know about %d)"), sipServerDomain->index , (TInt)domainNameDecoder->NumDomainNames()));
+			User::Leave(KErrNotFound);
+			}
+
+		CleanupStack::PopAndDestroy();
+		}
+	else
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerDomainL: Client tried to fetch a SIP option but none has (yet) been received")));
+		User::Leave(KErrNotFound);
+		}
+	CleanupStack::PopAndDestroy();
+	}
+
+
+
+TBool CDHCPIP4Control::ShouldInformAfterFailedInit(void)
+	{
+	// if has no global address, should not inform
+	return iDhcpStateMachine->GetInterfaceGlobalAddress().IsUnspecified() ? EFalse : ETrue ;
+	}
+