diff -r 000000000000 -r af10295192d8 tcpiputils/dhcp/src/DHCPIP6Control.cpp --- /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 +#include "netcfgextndhcpmsg.h" +#include +#include +#include +#include +#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 ) + 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 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(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(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(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(&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(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(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;iGetItemLength(); + 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(findNode->Ptr()); + ++numOfOpcodes; + //Append the opcode information to the buffer + buffer->Des().Append(reinterpret_cast(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(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(const_cast(aDes->Ptr())); + + HBufC8* buf = NULL; + DHCPv6::CDHCPMessageHeaderIP6 msg(buf); + CleanupClosePushL(msg); + TPtr8 ptr(const_cast(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length()); + msg.iRecord.ParseL(ptr); + + DHCPv6::COptionList* optionList = &(msg.GetOptions()); + + CDHCPOptionSipServerAddrs* sipServerAddrs = + static_cast(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(const_cast(aDes->Ptr())); + + HBufC8* buf = NULL; + DHCPv6::CDHCPMessageHeaderIP6 msg(buf); + CleanupClosePushL(msg); + TPtr8 ptr(const_cast(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length()); + msg.iRecord.ParseL(ptr); + + DHCPv6::COptionList* optionList = &(msg.GetOptions()); + + CDHCPOptionSipServerDomains* sipServerDomains = + static_cast(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(const_cast(aDes->Ptr())); + + HBufC8* buf = NULL; + DHCPv6::CDHCPMessageHeaderIP6 msg(buf); + CleanupClosePushL(msg); + TPtr8 ptr(const_cast(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length()); + msg.iRecord.ParseL(ptr); + + DHCPv6::COptionList* optionList = &(msg.GetOptions()); + + CDHCPOptionDomainSearchList* domainsearchlistoption = + static_cast(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(const_cast(aDes->Ptr())); + + HBufC8* buf = NULL; + DHCPv6::CDHCPMessageHeaderIP6 msg(buf); + CleanupClosePushL(msg); + TPtr8 ptr(const_cast(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length()); + msg.iRecord.ParseL(ptr); + + DHCPv6::COptionList* optionList = &(msg.GetOptions()); + + CDHCPOptionDNSServers* dnsServerAddrsoption = + static_cast(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