tcpiputils/dhcp/src/DHCPIP6Control.cpp
changeset 0 af10295192d8
child 37 052078dda061
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dhcp/src/DHCPIP6Control.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,709 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Implements the DHCP IP6 highest level control plain
+// 
+//
+
+/**
+ @file DHCPIP6Control.cpp
+ @internalTechnology
+*/
+
+#include "DHCPIP6Control.h"
+#include "DHCPIP6States.h"
+#include "DHCPServer.h"
+#include "DHCPDb.h"
+#include "NetCfgExtDhcpControl.h"
+#include "DhcpIP6Msg.h"
+#include "ExpireTimer.h"
+#include "DomainNameDecoder.h"
+#include <comms-infras/es_config.h>
+#include "netcfgextndhcpmsg.h"
+#include <nifman.h>
+#include <f32file.h>
+#include <comms-infras/metatype.h>
+#include <comms-infras/metadata.h>
+#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#include "dhcphwaddrmanager.h"
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+using namespace DHCPv6;
+
+struct TDHCPv6Persistent : public Meta::SMetaData
+{
+	TDHCPv6Persistent( SIdentityAssociationConfigInfoNA& aIdentityAssociationConfigInfoNA ) :
+		iIdentityAssociationConfigInfoNA( &aIdentityAssociationConfigInfoNA )
+		{
+		iTaskStartedAt.HomeTime();
+		}
+	TTime iTaskStartedAt;
+	SIdentityAssociationConfigInfoNA* iIdentityAssociationConfigInfoNA;
+
+	DATA_VTABLE
+};
+
+START_ATTRIBUTE_TABLE( TDHCPv6Persistent, KDHCPv6Persinstence, KDHCPv6PersinstenceId )
+	REGISTER_ATTRIBUTE( TDHCPv6Persistent, iIdentityAssociationConfigInfoNA, TMetaObjectPtr<SIdentityAssociationConfigInfoNA> )
+	REGISTER_ATTRIBUTE( TDHCPv6Persistent, iTaskStartedAt, TMetaTime )
+END_ATTRIBUTE_TABLE()
+
+
+CDHCPIP6Control::~CDHCPIP6Control()
+	{
+	}
+
+void CDHCPIP6Control::ConfigureL(const TConnectionInfo& aInfo, const RMessage2* aMessage)
+/**
+  * Open and attach to the RConnection
+  *
+  * @internalTechnology
+  */
+	{
+   CDHCPControl::ConfigureL( aInfo, aMessage );
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::ConfigureL")));
+	
+	iDhcpDb = new (ELeave) CDHCPDb( TPtrC( SERVICE_IP6_DNS_ADDR_FROM_SERVER ),
+													TPtrC( SERVICE_IP6_NAME_SERVER1 ),
+													TPtrC( SERVICE_IP6_NAME_SERVER2 )); //for both version for the time being see the class TDHCPIP4Db comments
+	TRAPD( err, FindInterfaceNameL(aInfo,KAfInet6) );
+	if( err == KErrNone )
+		{
+		TBuf8<KMaxName> tempBuf;
+		tempBuf.Copy( iInterfaceName );
+		__CFLOG_1(KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::ConfigureL - FindInterfaceNameL found \"%S\""), &tempBuf);
+		}
+	else
+		{
+		__CFLOG_1(KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::ConfigureL - FindInterfaceNameL failed with error %d"), err);
+		User::Leave( err );
+		}
+#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+	iDhcpHwAddrManager = CDhcpHwAddrManager::NewL();
+	iDhcpStateMachine = CDHCPIP6StateMachine::NewL(iEsock, iConnection, iInterfaceName,iDhcpHwAddrManager);
+#else
+	iDhcpStateMachine = CDHCPIP6StateMachine::NewL(iEsock, iConnection, iInterfaceName);
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+	
+	CDHCPIP6StateMachine* sm6 = static_cast<CDHCPIP6StateMachine*>(iDhcpStateMachine);
+ 	TDHCPv6Persistent pers(sm6->iInterfaceConfigInfo.iSIdentityAssociationConfigInfoNA);
+	TBool bStaticAddress = !iDhcpDb->ReadL(*iDhcpStateMachine, pers);
+	//initialise relevant data
+	TInt pos = 0;
+	const SIPAddressInfo* info = pers.iIdentityAssociationConfigInfoNA->GetValidAddressInfo( pos );
+	TTimeIntervalSeconds seconds = info ? static_cast<TInt>(info->iValidLifeTime) : 0 ;
+	iDhcpDb->iLeaseExpiresAt = pers.iTaskStartedAt + seconds;
+	//the rest of the data we'll get back in reply msg
+	CDHCPControl::ConfigureL(bStaticAddress);	
+	}
+
+void CDHCPIP6Control::BindingFinishedL()
+ 	{
+	CDHCPControl::BindingFinishedL();
+	//see case EDeclineInitialisedInProgress as to how the persistent
+	//data is written
+  	}
+
+void CDHCPIP6Control::TaskCompleteL(TInt aError)
+/**
+  * Signals the end of a task
+  * and decides what we should do when
+  *
+  * @internalTechnology
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, 
+				 _L8("CDHCPIP6Control::TaskCompleteL (%d) with error = %d") ,
+				 iState, aError));
+
+	DhcpStateMachine()->Cancel();
+	TState prevState = iState;
+	switch (iState)
+		{
+		case EDeclineInitialisedInProgress:
+			{
+			TDHCPv6Persistent pers(DhcpStateMachine()->iInterfaceConfigInfo.iSIdentityAssociationConfigInfoNA);
+			//get relevant data from statemachine
+			pers.iTaskStartedAt = DhcpStateMachine()->iStartedAquisitionAt;
+			TRAPD( ret, iDhcpDb->WriteL(*iDhcpStateMachine, pers) );
+			if (ret!=KErrNone)
+				{
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::TaskCompleteL error: %d"),ret));
+				}
+			iState = EInitialised;
+			break;
+			}
+		case EReconfigureInProgress:
+			//in the case the following fn leave we've run out of memory => we will not respond
+			//to the reconfigure message. However we can still use our address(es) and wait
+			//for renew timer to expire
+			if ( aError == KErrNone )
+				{
+				CDHCPMessageHeaderIP6* v6Msg = DhcpStateMachine()->DhcpMessage();
+				COptionNode* pNode = v6Msg->GetOptions().FindOption( EReconfMsg );
+				if (pNode)
+					{
+					TInt nCode = pNode->GetBigEndian();
+					switch ( nCode )
+						{
+						case EReconfigureInformRequest:
+							DhcpStateMachine()->StartInformL( this, EFalse /*static address is either already set or not used*/ );
+							iState = EInformInProgress;
+							//cancel the renew timer (if any) after succesfully starting the above tasks
+							iTimer->Cancel();
+							break;
+						case EReconfigureRenew:
+							DhcpStateMachine()->StartRenewL( this,0 );
+							iState = ERenewInProgress;
+							//cancel the renew timer (if any) after succesfully starting the above tasks
+							iTimer->Cancel();
+							break;
+						default:
+							// keep restarting reconfigure
+							DhcpStateMachine()->StartReconfigureL( this );
+						}
+					}
+				else
+					{
+					// keep restarting reconfigure
+					DhcpStateMachine()->StartReconfigureL( this );
+					}
+			}
+			else
+				{
+				//keep restarting reconfigure until a valid reconfigure arrives or
+				//renew timer expires or interface goes down
+				DhcpStateMachine()->StartReconfigureL( this );
+				}
+			break;
+		case ERebindInProgress:
+		case EInitInProgress:
+			iTimer->Cancel();
+
+			if ( aError != KErrNone )
+				{//decline all
+				DhcpStateMachine()->iInterfaceConfigInfo.SetAddressStatus( KAddrIndexAll, EMarkForDecline );
+				}
+			iState = EInitInProgress; //take the same action as for EInitInProgress
+			CDHCPControl::TaskCompleteL(aError);
+			break;
+		case ERenewInProgress:
+			iTimer->Cancel();
+			if (KErrNone != aError)
+				{
+				//Renew process has failed => start rebind
+				DhcpStateMachine()->StartRebindL( this );
+				iState = ERebindInProgress;
+				break;
+				}
+			//fall through if no error
+		default:
+			{
+			CDHCPControl::TaskCompleteL(aError);
+			}
+		};
+	//if the statemachine history indicates CDHCPState::EBinding and aError==KErrNone we have to check whether to
+	//decline any addresses that haven't been verified by the stack as valid ones. If so we initiate decline
+	//to decline the invalid addresses. In case at least one address is valid we go to reconfigure state after the decline.
+	//=> amend UML and doc accordingly.
+	if (DhcpStateMachine()->History() & CDHCPState::EBinding && aError == KErrNone )
+		{//see CDHCPIP6StateMachine::StartDeclineL
+		DhcpStateMachine()->StartDeclineL( this );
+		iState = EDeclineInitialisedInProgress;
+		//not changing CDHCPIP6Control state we are initialised and timer is running
+		}
+	else if ( iState == EInitialised || (iState == EEnd && prevState == EInformInProgress))
+		{//we don't want this to leave
+#if defined(DHCP_RECONFIGURE_NO_AUTHENTICATION)
+		//we don't support reconfigure until we've sorted out authentication
+		TRAPD(ret, DhcpStateMachine()->StartReconfigureL( this ));
+		if (ret!=KErrNone)
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::TaskCompleteL error: %d"),ret));
+			}
+		iState = EReconfigureInProgress;
+#endif
+		}
+	}
+
+
+TInt CDHCPIP6Control::HandleClientRequestL(TUint aName, TInt aValue)
+	{
+	TBool deferAllowed = !iMessage;
+	
+	if (iDhcpStateMachine)
+		{
+	   	switch (aName)
+			{
+			case KConnAddrRenew:
+				if (deferAllowed && iDhcpStateMachine->IsGettingCfgInfoOnly())
+					{
+					iTimer->Cancel();
+					iDhcpStateMachine->Cancel();
+					iDhcpStateMachine->StartInformL(this,EFalse);
+					iState = EInformInProgress;
+					return ETrue;
+					}
+				break;
+			default:
+				break;
+			}
+		}
+	return CDHCPControl::HandleClientRequestL(aName,aValue);		
+	}
+	
+	
+TInt CDHCPIP6Control::HandleClientRequestL(TUint aName)
+	{
+	return CDHCPIP6Control::HandleClientRequestL(aName,0);
+	}
+
+void CDHCPIP6Control::GetRawOptionDataL(TUint aOpCode, TPtr8& aPtr )
+	{
+	HBufC8* buf = NULL;
+	DHCPv6::CDHCPMessageHeaderIP6 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr( const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length() );
+	msg.iRecord.ParseL(ptr); //no check necessary
+    DHCPv6::COptionNode* pOption = msg.GetOptions().FindOption(aOpCode);
+    if (!pOption)
+      {
+#ifdef SYMBIAN_TCPIPDHCP_UPDATE
+      // The option is not found try to get the option through DHCP INFORM message 
+      //by calling RequestInformOrCompleteCallL
+      CleanupStack::PopAndDestroy();
+	  TUint opcode = aOpCode;
+	  TPtr8 optPtr(reinterpret_cast<TUint8*>(&opcode),1,1);
+	  return(RequestInformOrCompleteCallL(optPtr));
+#else	  
+	  User::Leave(KErrNotFound);  
+#endif //SYMBIAN_TCPIPDHCP_UPDATE	  
+      }
+    ptr.Set(pOption->GetBodyDes());
+    if (ptr.Length() > aPtr.MaxLength())
+      {
+      User::Leave(KErrOverflow);
+      }
+    aPtr.Copy(ptr);
+    CleanupStack::PopAndDestroy();
+	}
+
+/**
+    Get raw option data (IP6 version).
+    @param  pointer to the buffer descriptor for getting option data
+*/
+void CDHCPIP6Control::HandleGetRawOptionDataL(TDes8* aDes)
+	{
+	TDhcp6RawOptionDataPckg pckg(*aDes);
+		
+	TUint16 opCode = pckg.OpCode();
+	TPtr8 buf(pckg.Buf());
+
+	GetRawOptionDataL(opCode, buf);
+	pckg.SetBufLengthL(buf.Length());
+	}
+
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+void CDHCPIP6Control::GetDhcpHdrSiaddrL(TDes8& /*aNxtAddress*/)
+	{
+	//presently empty implementation.
+	//PREQ 1647& 1648 implmentation is only for IPv4
+	}
+	
+void CDHCPIP6Control::GetDhcpHdrSnameL(TDes8& /*aHdrSvrName*/)
+	{
+	//presently empty implementation.
+	//PREQ 1647& 1648 implmentation is only for IPv4
+	}
+void CDHCPIP6Control::HandleGetTftpServerNameL(TDes8& /*aDes*/)
+	{
+	//presently empty implementation.
+	//PREQ 1647& 1648 implmentation is only for IPv4
+	}
+void CDHCPIP6Control::HandleGetTftpServerAddrL(TDes8& /*aDes*/)
+	{
+	//presently empty implementation.
+	//PREQ 1647& 1648 implmentation is only for IPv4
+	}
+#endif
+#ifdef SYMBIAN_TCPIPDHCP_UPDATE
+void CDHCPIP6Control::RequestInformOrCompleteCallL(TDes8& 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);
+			}
+		//Cancel if there is any outstanding request(DHCP reconfigure will cancelled)
+		iDhcpStateMachine->Cancel();
+		static_cast<CDHCPIP6StateMachine*>(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);	
+		}
+	}
+#endif //SYMBIAN_TCPIPDHCP_UPDATE
+
+#ifdef SYMBIAN_TCPIPDHCP_UPDATE 
+void CDHCPIP6Control::HandleGetMultipleParamsL(TDes8& aDes)
+#else
+void CDHCPIP6Control::HandleGetMultipleParamsL(TDes8& /*aDes */)
+#endif //SYMBIAN_TCPIPDHCP_UPDATE
+/**
+  * This function will be called when the application want to retrieve multiple 
+  * options from the server by using option ORO(option 6) 
+  *
+  * @see RFC 3315 sec 22.7
+  * @internalTechnology
+  */
+	{
+#ifdef SYMBIAN_TCPIPDHCP_UPDATE	
+	HBufC8 *saveBuf=NULL, *buffer=NULL;
+	TUint16 *headerPtr;
+	TInt numOfOpcodes=0;
+	TInt totalLength=0,opcodeLength=aDes.Length();
+	TInt maxLength=aDes.MaxLength();
+	TUint16 opcode;
+	TBool allFound=ETrue;
+	
+	DHCPv6::CDHCPMessageHeaderIP6 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
+		
+		DHCPv6::COptionNode* findNode = msgSaved.GetOptions().FindOption(opcode);
+		if (findNode )
+			{
+			//get the opcode length
+			TInt bufLength=findNode->GetItemLength();
+			totalLength+=bufLength;
+			//The opcode buffer length is greater than maximum length through overflow error
+			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 = reinterpret_cast<TUint16*>(findNode->Ptr()); 
+			++numOfOpcodes;
+			//Append the opcode information to the buffer
+			buffer->Des().Append(reinterpret_cast<const TUint8*>(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 || totalLength<=0)
+			{
+			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
+		{
+		//If the option is not found then trigger the information request
+		TPtr8 opcodePtr(const_cast<TUint8*>(aDes.Ptr()),opcodeLength);
+		opcodePtr.SetLength(opcodeLength);
+		RequestInformOrCompleteCallL(opcodePtr);	
+		}	
+	
+	if (buffer)
+		{
+		CleanupStack::PopAndDestroy(buffer);
+		}
+
+	CleanupStack::PopAndDestroy(&msgSaved);
+#endif //SYMBIAN_TCPIPDHCP_UPDATE
+	}
+
+TInt CDHCPIP6Control::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
+  */
+	{
+#ifdef SYMBIAN_TCPIPDHCP_UPDATE
+	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;
+			}
+
+	default:
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("InformCompleteRequestHandlerL : default unhandled optino Name")));
+		break;	
+	
+		}
+		iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+		CleanupStack::PopAndDestroy(buff);
+		return KErrNone;
+#else
+		return EFalse;
+#endif //SYMBIAN_TCPIPDHCP_UPDATE
+	}
+void CDHCPIP6Control::HandleGetSipServerAddrL(TDes8* aDes)
+	{	
+	SSipServerAddr* sipServerAddr = 
+		reinterpret_cast<SSipServerAddr*>(const_cast<TUint8*>(aDes->Ptr()));
+
+	HBufC8* buf = NULL;
+	DHCPv6::CDHCPMessageHeaderIP6 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(ptr);
+
+	DHCPv6::COptionList* optionList = &(msg.GetOptions());
+	
+	CDHCPOptionSipServerAddrs* sipServerAddrs = 
+		static_cast<CDHCPOptionSipServerAddrs*>(optionList->FindOption(ESipServerA));
+	
+	TBool ret = EFalse;
+
+	if(sipServerAddrs)
+		{
+		ret = sipServerAddrs->GetSipServerAddr(sipServerAddr->index, 
+			sipServerAddr->address);
+		}
+
+	User::LeaveIfError(ret ? KErrNone : KErrNotFound);
+	CleanupStack::PopAndDestroy();
+	}
+
+void CDHCPIP6Control::HandleGetSipServerDomainL(TDes8* aDes)
+	{	
+	SSipServerDomain* sipServerDomain = 
+		reinterpret_cast<SSipServerDomain*>(const_cast<TUint8*>(aDes->Ptr()));
+
+	HBufC8* buf = NULL;
+	DHCPv6::CDHCPMessageHeaderIP6 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(ptr);
+
+	DHCPv6::COptionList* optionList = &(msg.GetOptions());
+	
+	CDHCPOptionSipServerDomains* sipServerDomains = 
+		static_cast<CDHCPOptionSipServerDomains*>(optionList->FindOption(ESipServerD));
+
+	if(sipServerDomains)
+		{
+		CDomainNameCodec* domainNameDecoder = new(ELeave) CDomainNameCodec();
+		CleanupStack::PushL(domainNameDecoder);
+		TPtr8 ptr = sipServerDomains->GetBodyDes();
+		domainNameDecoder->DecodeL(ptr);
+
+		if(sipServerDomain->index < (TInt)domainNameDecoder->NumDomainNames())
+			{
+			TDomainName domainName = (*domainNameDecoder)[sipServerDomain->index];
+			sipServerDomain->domainName.Copy(domainName);
+			}
+		else
+			{
+			User::Leave(KErrNotFound);
+			}
+			
+		CleanupStack::PopAndDestroy();
+		}
+	else
+		{
+		User::Leave(KErrNotFound);
+		}
+		
+	CleanupStack::PopAndDestroy();
+	}
+#ifdef SYMBIAN_TCPIPDHCP_UPDATE
+void CDHCPIP6Control::HandleGetDomainSearchListL(TDes8* aDes)
+/**
+  * This function will be called when the application want to retrieve the 
+  * list of Domain names from the DomainSearchList option (option 24)by using 
+  * KConnGetDomainSearchList variable.
+  *
+  * @see RFC 3646,
+  * @internalTechnology
+  */
+	{
+	SDomainSearchList* domainsearchlist = 
+			reinterpret_cast<SDomainSearchList*>(const_cast<TUint8*>(aDes->Ptr()));
+
+	HBufC8* buf = NULL;
+	DHCPv6::CDHCPMessageHeaderIP6 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(ptr);
+
+	DHCPv6::COptionList* optionList = &(msg.GetOptions());
+	
+	CDHCPOptionDomainSearchList* domainsearchlistoption = 
+		static_cast<CDHCPOptionDomainSearchList*>(optionList->FindOption(EDomainList));
+		
+	if(domainsearchlistoption)
+		{
+		if(domainsearchlist->index >= 0)
+			{
+			CDomainNameCodec* domainNameDecoder = new(ELeave) CDomainNameCodec();
+			CleanupStack::PushL(domainNameDecoder);
+			TPtr8 ptr = domainsearchlistoption->GetBodyDes();
+			domainNameDecoder->DecodeL(ptr);
+		
+			if(domainsearchlist->index < (TInt)domainNameDecoder->NumDomainNames())
+				{
+				TDomainName domainName = (*domainNameDecoder)[domainsearchlist->index];
+				domainsearchlist->domainname.Copy(domainName);
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::HandleGetDomainSearchListL -index = %d  domain name  = \"%S\" "), domainsearchlist->index,&(domainsearchlist->domainname)));
+				}
+			else
+				{
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::HandleGetDomainSearchListL: Client tried to fetch an out-of-range domain names %d (I only know about %d)"), domainsearchlist->index , (TInt)domainNameDecoder->NumDomainNames()));
+				User::Leave(KErrNotFound);
+				}
+			
+			CleanupStack::PopAndDestroy(domainNameDecoder);
+			}
+		else
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::HandleGetDomainSearchListL: index is  not >=0 %d "), domainsearchlist->index));
+			User::Leave(KErrNotFound);
+			}
+		}
+	else
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::HandleGetDomainSearchListL option is not found ")));
+		User::Leave(KErrNotFound);
+		}
+	
+	CleanupStack::PopAndDestroy(&msg);
+	}
+
+void CDHCPIP6Control::HandleGetDNSServerListL(TDes8* aDes)
+/**
+  * This function will be called when the application want to retrieve the 
+  * list of IPV6 addresses of DNS recursive name server from the
+  * DNS Recursive Name Server option (option 23)by using 
+  * KConnGetDNSServerList variable.
+  *
+  * @see RFC 3646,
+  * @internalTechnology
+  */	
+	{
+	SDNSServerAddr* dnsServerAddr = 
+			reinterpret_cast<SDNSServerAddr*>(const_cast<TUint8*>(aDes->Ptr()));
+
+	HBufC8* buf = NULL;
+	DHCPv6::CDHCPMessageHeaderIP6 msg(buf);
+	CleanupClosePushL(msg);
+	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+	msg.iRecord.ParseL(ptr);
+
+	DHCPv6::COptionList* optionList = &(msg.GetOptions());
+	
+	CDHCPOptionDNSServers* dnsServerAddrsoption = 
+		static_cast<CDHCPOptionDNSServers*>(optionList->FindOption(EDNSServers));
+	
+	TInt ret = KErrNone;
+	if(dnsServerAddrsoption)
+		{
+		if(dnsServerAddr->index >=0)
+			{
+			ret = dnsServerAddrsoption->GetDomainNameServer(dnsServerAddr->index, 
+				dnsServerAddr->addres);
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::HandleGetDNSServerListL -index = %d  DNS server address = \"%S\" "), ret,&(dnsServerAddr->addres)));
+			}
+		else
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::HandleGetDNSServerListL -index is out of range ")));
+			ret = KErrNotFound;
+			}
+		}
+	else
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6Control::HandleGetDNSServerListL option is not found ")));
+		ret = KErrNotFound;	
+		}
+	
+	User::LeaveIfError(ret);
+	CleanupStack::PopAndDestroy(&msg);
+	
+	}
+#endif //SYMBIAN_TCPIPDHCP_UPDATE