--- /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