diff -r 000000000000 -r af10295192d8 tcpiputils/dhcp/src/DHCPIP6StateMachine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcpiputils/dhcp/src/DHCPIP6StateMachine.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,1065 @@ +// 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 statemachine helper functions +// +// + +/** + @file DHCPIP6StateMachine.cpp + @internalTechnology +*/ + +#include "DHCPIP6States.h" +#include "DhcpIP6MsgRcvr.h" +#include "DHCPServer.h" + +#ifdef _DEBUG +#include +#endif + +using namespace DHCPv6; + +CDHCPIP6StateMachine::~CDHCPIP6StateMachine() +/** + * Destructor of the If base class + * + * @internalTechnology + * + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::~CDHCPIP6StateMachine"))); + delete iMessageReader; + iServerId.Close(); + } + +#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION +CDHCPIP6StateMachine* CDHCPIP6StateMachine::NewL(RSocketServ& aEsock, RConnection& aConnection, const TName& aInterfaceName, CDhcpHwAddrManager* aDhcpHwAddrManager) +/** + * Creates a new instance of this class + * + * @internalTechnology + * + */ + { + CDHCPIP6StateMachine* stateMachine = new (ELeave) CDHCPIP6StateMachine(aEsock, aConnection, aInterfaceName, aDhcpHwAddrManager); + CleanupStack::PushL(stateMachine); + stateMachine->ConstructL(); + CleanupStack::Pop(stateMachine); + return stateMachine; + } +#else +CDHCPIP6StateMachine* CDHCPIP6StateMachine::NewL(RSocketServ& aEsock, RConnection& aConnection, const TName& aInterfaceName) +/** + * Creates a new instance of this class + * + * @internalTechnology + * + */ + { + CDHCPIP6StateMachine* stateMachine = new (ELeave) CDHCPIP6StateMachine(aEsock, aConnection, aInterfaceName); + CleanupStack::PushL(stateMachine); + stateMachine->ConstructL(); + CleanupStack::Pop(stateMachine); + return stateMachine; + } +#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION +void CDHCPIP6StateMachine::ConstructL() +/** + * Creates socket and connections for the object + * + * + * @internalTechnology + * + */ + { + CDHCPStateMachine::ConstructL(); + + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::ConstructL"))); + + ReAllocL(KDhcpInitMsgSizeIP6); + iDhcpMessage = new(ELeave)CDHCPMessageHeaderIP6(iFragment); + iMessageReader = new(ELeave)CDhcpIP6MessageReader( *this ); + iMessageSender = new(ELeave)CDHCPIP6MessageSender(this,iSocket,&iTaskStartedAt,KAfInet6); + } + +void CDHCPIP6StateMachine::GetServerAddress( TInetAddr& aAddress ) +{ + iInterfaceConfigInfo.GetServerAddress( aAddress ); +} + +void CDHCPIP6StateMachine::SetCurrentAddress(const TInetAddr& aCurrentAddress, const TInetAddr& /*aSubnetMask*/) + { + CDHCPStateMachine::SetCurrentAddress( aCurrentAddress ); + } + +void CDHCPIP6StateMachine::StartInitL(MStateMachineNotify* aStateMachineNotify, EInitialisationContext aInitialisationContext, TInt aUserTimeOut ) +/** + * StartInitL + * + * This function is called to start the IP address solicitation state machine + * we don't support rapid commit option for now + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::StartSolicitationL"))); + ASSERT(!iFirstState);//the states should be deleted by now or we are starting off + + SetIdle( EFalse ); + iInterfaceConfigInfo.Reset(); + +#ifdef SYMBIAN_ESOCK_V3 + if ( aInitialisationContext == CDHCPStateMachine::EFirstCall ) + { + iFirstState = new(ELeave) CDHCPIP6ListenToNeighbor(*this); + } + else +#else + (void)aInitialisationContext; +#endif + { + iFirstState = new(ELeave) CDHCPIP6Solicit(*this, aUserTimeOut); + CDHCPState* state1 = new(ELeave)CDHCPIP6Select(*this); + iFirstState->SetNext( state1 ); + CDHCPState* state2 = new(ELeave) CDHCPIP6Request(*this); + state1->SetNext( state2 ); + state2->SetNext( new(ELeave) CDHCPIP6WaitForDAD(*this) ); + + if (iStartInitCalls == CDHCPStateMachine::EFirstCall) + { + //This is the first time we're going to wait for a DCHP server. + //If there is no server it we will complete the client after one attempt + iStartInitCalls = aInitialisationContext; + static_cast(state1)->SetMaxRetryCount(1); + } + else + { + //We never found a DCHP server the first time, but this time try harder. + static_cast(state1)->SetMaxRetryCount(INT_MAX); + } + } + + CDHCPStateMachine::Start(aStateMachineNotify); + } +#ifdef SYMBIAN_TCPIPDHCP_UPDATE +void CDHCPIP6StateMachine::StartInformL(MStateMachineNotify* aStateMachineNotify) +/** + * This function is called to send inform message if options are not + * found in iValidMsg buffer + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::StartInformL Dynamic Inform Request"))); + ASSERT(!iFirstState); + iFirstState = new(ELeave) CDHCPIP6InformRequest(*this); + CDHCPState* request = new(ELeave) CDHCPIP6Request(*this); + iFirstState->SetNext( request ); + CDHCPStateMachine::Start(aStateMachineNotify); + } +#endif //SYMBIAN_TCPIPDHCP_UPDATE +void CDHCPIP6StateMachine::StartInformL(MStateMachineNotify* aStateMachineNotify, TBool /*aStaticAddress*/) +/** + * StartInformL + * + * This function is called to start the inform for state-less configuration + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::EInformRequest"))); + ASSERT(!iFirstState); //the states should be deleted by now or we are starting off + + if (!iServerId.Length()) + { + iInterfaceConfigInfo.Reset(); + } + + iFirstState = new(ELeave) CDHCPIP6InformRequest(*this); + CDHCPState* state1 = new(ELeave) CDHCPIP6Request(*this); + iFirstState->SetNext( state1 ); + //static address is set but no wait for DAD here + + CDHCPStateMachine::Start(aStateMachineNotify); + iCfgInfoOnly = ETrue; + } + +#ifdef SYMBIAN_NETWORKING_DHCPSERVER + +void CDHCPIP6StateMachine::CreateOfferMsgL() + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateOfferMsgL"))); + } + +void CDHCPIP6StateMachine::HandleRequestMsgL()//CreateRequestResponseMsgL() + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateRequestResponseMsgL"))); + } + +void CDHCPIP6StateMachine::HandleInformMsgL() + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::HandleInformMsgL"))); + } + +void CDHCPIP6StateMachine::PrepareToSendServerMsgL( CDHCPStateMachine::EAddressType /*aEAddressType*/) +/** + * PrepareToSendL + * + * This function is called to set the correct destination address + * for messages before they are sent. + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::PrepareToSendL"))); + DhcpMessage()->Dump(); + iMessageSender->Cancel(); + } + +void CDHCPIP6StateMachine::CloseNSendServerMsgL(TRequestStatus& /*aStatus*/, CDHCPStateMachine::EAddressType /*aEAddressType*/) + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CloseNSendServerMsgL"))); + } + +CDHCPState* CDHCPIP6StateMachine::ReceiveOnPort67L( TRequestStatus* aStatus ) + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::ReceiveOn67"))); + + iDhcpMessage->InitialiseL(); + iMessageReader->SetNext( iActiveEvent ); + ASSERT( iReceiving == EFalse ); + iReceiving = ETrue; + return static_cast(iMessageReader->ProcessL( *aStatus )); + } + +void CDHCPIP6StateMachine::InitialiseServerSocketL() + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::InitialiseServerSocketL"))); + } + +#endif // SYMBIAN_NETWORKING_DHCPSERVER + +void CDHCPIP6StateMachine::StartRebootL(MStateMachineNotify* aStateMachineNotify) +/** + * StartRebootL + * + * This function is called to start the confirm request state machine + * used when trying to start using a previously assigned address still + * with valid lease. + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::StartConfirmL"))); + ASSERT(!iFirstState);//the states should be deleted by now or we are starting off + + iFirstState = new(ELeave) CDHCPIP6Confirm(*this); + CDHCPState* state1 = new(ELeave) CDHCPIP6Request(*this); + iFirstState->SetNext( state1 ); + state1->SetNext( new(ELeave) CDHCPIP6WaitForDAD(*this) ); + + CDHCPStateMachine::Start(aStateMachineNotify); + } + +void CDHCPIP6StateMachine::StartRenewL(MStateMachineNotify* aStateMachineNotify,TInt aUserTimeOut) + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::StartRenewL"))); + ASSERT(!iFirstState); + + iUserRebindTimeout = aUserTimeOut; + iFirstState = new(ELeave) CDHCPIP6Renew(*this,aUserTimeOut); + iFirstState->SetNext( new(ELeave) CDHCPIP6WaitForDAD(*this) ); + + CDHCPStateMachine::Start(aStateMachineNotify); + } + +void CDHCPIP6StateMachine::StartRebindL(MStateMachineNotify* aStateMachineNotify) +/** + * StartRebindL + * + * This function is called to start the rebind state machine + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::StartRebindL"))); + ASSERT(!iFirstState);//the states should be deleted by now or we are starting off + + iFirstState = new(ELeave) CDHCPIP6Rebind(*this,iUserRebindTimeout); + iFirstState->SetNext( new(ELeave) CDHCPIP6WaitForDAD(*this) ); + + CDHCPStateMachine::Start(aStateMachineNotify); + } + +void CDHCPIP6StateMachine::StartReconfigureL(MStateMachineNotify* aStateMachineNotify) +/** + * StartReconfigureL + * + * This function is called to initialise waiting for the server reconfigure message. + * The task ends once a valid reconfigure messageg's been received + * + * @internalTechnology + */ +{ + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::StartReconfigureL"))); + + ASSERT(!iFirstState);//the states should be deleted by now or we are starting off + + iXid.SetXid( 0 ); + iFirstState = new(ELeave) CDHCPIP6Reconfigure(*this); + + CDHCPStateMachine::Start(aStateMachineNotify); +} + +void CDHCPIP6StateMachine::StartDeclineL(MStateMachineNotify* aStateMachineNotify) +/** + * StartDeclineL + * + * This function is called to start the decline task + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::StartDeclineL"))); + ASSERT(!iFirstState);//the states should be deleted by now or we are starting off + + if ( iInterfaceConfigInfo.AnyAddressToDecline() ) + { + iFirstState = new(ELeave) CDHCPIP6Decline(*this); + iFirstState->SetNext( new CDHCPIP6ReplyNoBinding(*this) ); + } + CDHCPStateMachine::Start(aStateMachineNotify); + } + +void CDHCPIP6StateMachine::StartReleaseL(MStateMachineNotify* aStateMachineNotify) +/** + * StartReleaseL + * + * This function is called to start the release state machine + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::StartReleaseL"))); + ASSERT(!iFirstState);//the states should be deleted by now or we are starting off + + iFirstState = new(ELeave) CDHCPIP6Release(*this); + iFirstState->SetNext( new(ELeave)CDHCPIP6ReplyNoBinding(*this) ); + + CDHCPStateMachine::Start(aStateMachineNotify); + } + +void CDHCPIP6StateMachine::PrepareToSendL( CDHCPStateMachine::EAddressType /*aEAddressType*/ ) +/** + * PrepareToSendL + * + * This function is called to set the correct destination address + * for messages before they are sent. + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::PrepareToSendL"))); + DhcpMessage()->Dump(); + iMessageSender->Cancel(); + } + +void CDHCPIP6StateMachine::CloseNSendMsgL(TRequestStatus& /*aStatus*/, CDHCPStateMachine::EAddressType aEAddressType) +/** + * Handles sending of packets for this object + * + * @internalTechnology + * + */ + { + CDHCPStateMachine::CloseNSendMsgL(0,KInfinity,aEAddressType); //IPv6 calculates its own delay and retry values..so KInfinity is ignored + } + +void CDHCPIP6StateMachine::CancelMessageReceiver() + {//doesn't cancel statemachine only the reader state + if ( IsActive() && iReceiving ) + { + ASSERT( !iErrorEvent ); + CStateMachine::Cancel(KErrNone);//waits for the cancel to complete + iActiveEvent = iMessageReader->Next(); + iReceiving = EFalse; + //restart the state machine + CStateMachine::Start(NULL, NULL, iStateMachineNotify); + } + } + +CDHCPState* CDHCPIP6StateMachine::ReceiveL(TRequestStatus* aStatus) +/** + * Starts iMessageReader state + * + * @internalTechnology + * + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::Receive"))); + + iDhcpMessage->InitialiseL(); + iMessageReader->SetNext( iActiveEvent ); + ASSERT( iReceiving == EFalse ); + iReceiving = ETrue; + return static_cast(iMessageReader->ProcessL( *aStatus )); + } + +void CDHCPIP6StateMachine::OnCompletion() +{ + if (LastError() == KErrEof && iReceiving) + {//end of datagram while reading a message => not an error => restart state machine + iActiveEvent = iMessageReader->Next(); + + CStateMachine::Start(NULL, NULL, iStateMachineNotify); //sets last error to KErrNone + } + else + { + CDHCPStateMachine::OnCompletion(); + } +} + +void CDHCPIP6StateMachine::AssembleClientIDsL() +/** + * Sets the client id - hardware address and type pair + * + * + */ + { + /*client id and the way we generate it + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 3 | hardware type (16 bits) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . link-layer address (variable length) . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + FetchHWAddress(); + + TUint htype = 0; + if(iHardwareAddr.Family() != KAFUnspec) + { + iClientId.CreateL(KDuidTypeLen + KDuidHardwareTypeLen + iHardwareAddr.Length() - KHwAddrOffset); + htype = iHardwareAddr.Family(); // should this be Port() ? + } + else + { + // This means we're on a point-to-point link (i.e. one with no hardware addressing). + // We'll make client id look like an ethernet/mac address combo to reduce the chance of stupid servers getting upset + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, + _L8("CDHCPIP6StateMachine::AssembleClientIDsL - no hardware address (suggesting point-to-point)" + " so generating a random 6 byte client id"))); + iClientId.CreateL(KDuidTypeLen + KDuidHardwareTypeLen + KDuidEthMacAddrSize); + htype = 1; // fake up as Ethernet + } + + TBigEndian::SetValue(const_cast(iClientId.Ptr()), KDuidTypeLen, KDuidLLTypeCode); + TBigEndian::SetValue(const_cast(iClientId.Ptr()) + KDuidTypeLen, KDuidHardwareTypeLen, htype); + iClientId.SetLength(KDuidTypeLen + KDuidHardwareTypeLen); + + if(iHardwareAddr.Family()!=KAFUnspec) + { + iClientId.Append(iHardwareAddr.Mid(KHwAddrOffset, iHardwareAddr.Length() - KHwAddrOffset)); + } + else + { + // Note: if you increase the number of bytes appended here, then be sure to + // increase the size passed to iClientId.CreateL() above. + TUint32 data = Math::Random(); + iClientId.Append(TPckgC(data)); + iClientId.Append(TPckgC(data)); + } + } + +TUint CDHCPIP6StateMachine::GetMessageType() const +/** + * Parses the message and returns the message type from the DHCP message + * i.e. whether the message is an advertise. reply, reconfigure + * + * @internalTechnology + */ + { + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + if ( v6Msg->Parse(iXid,iClientId,iServerId) == KErrNone ) + { + v6Msg->Dump(); + return v6Msg->GetMessageType(); + } + return EUnknown; + } + +void CDHCPIP6StateMachine::SetMessageHeaderL( TMessageType aMsgType ) +/** + * Sets the message header + * + * @internalTechnology + */ + { + iXid.Init6(); //generate random transaction Id + iTaskStartedAt.HomeTime(); // set time stamp to now + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + v6Msg->InitialiseL(); + v6Msg->SetXid(iXid.Xid()); + v6Msg->SetMessageType(static_cast(aMsgType)); + + // +++++++++++++++++++++++ Elapsed Time +++++++++++++++++++++++++++++++++++++++++/ + //EElapsedTime option MUST be the first option in the option part of the message + //see CDHCPIP6MessageSender::SendingContinues fn + v6Msg->AddOptionL(EElapsedTime, KElapsedTimeOptionLen)->SetBigEndian( 0 ); + // +++++++++++++++++++++++ Client Id +++++++++++++++++++++++++++++++++++++++++/ + v6Msg->AddOptionL(EClientId, iClientId.Length())->GetBodyDes().Copy(iClientId); + // +++++++++++++++++++++++ Server ID +++++++++++++++++++++++++++++++++++++++++/ + //included only when it exists + if ( iServerId.Length() ) + { + v6Msg->AddOptionL(EServerId, iServerId.Length())->GetBodyDes().Copy(iServerId); + } + } + +void CDHCPIP6StateMachine::CreateDiscoverMsgL() +/** + * Puts the specifics of the solicit message into + * the message buffer + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateDiscoverMsgL"))); + + iServerId.Close(); + //initiate message header + SetMessageHeaderL(ESolicit); + + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + + // +++++++++++++++++++++++ IA_NA/TA options+++++++++++++++++++++++++++++++++++/ + iInterfaceConfigInfo.AppendIAOptionsL(*v6Msg, ESolicit); + + // +++++++++++++++++++++++ reconfiguration accept ++++++++++++++++++++++++++++/ +#if defined(DHCP_RECONFIGURE_NO_AUTHENTICATION) + v6Msg->AddOptionL(EReconfAccept, 0); +#endif + + // +++++++++++++++++++++++ append requested options list +++++++++++++++++++++/ + static_cast(v6Msg->AddOptionL( EOro, KDHCPOptionRequestLen ))->AppendRequestedOptions(); + } + +void CDHCPIP6StateMachine::CreateOfferAcceptanceRequestMsgL() +/** + * Puts the specifics of the request + * message into the message buffer + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateOfferAcceptanceRequestMsgL"))); + + SetMessageHeaderL( ERequest ); + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + + // +++++++++++++++++++++++ IA_NA/TA options+++++++++++++++++++++++++++++++++++/ + iInterfaceConfigInfo.AppendIAOptionsL( *v6Msg, ERequest ); + // +++++++++++++++++++++++ reconfiguration accept ++++++++++++++++++++++++++++/ +#if defined(DHCP_RECONFIGURE_NO_AUTHENTICATION) + v6Msg->AddOptionL(EReconfAccept, 0); +#endif + // +++++++++++++++++++++++ append requested options list +++++++++++++++++++++/ + static_cast(v6Msg->AddOptionL( EOro, KDHCPOptionRequestLen ))->AppendRequestedOptions(); + + } + +void CDHCPIP6StateMachine::CreateRebootRequestMsgL() +/** + * Puts the specifics of a confirm specific after reboot or other means of + * changing the interface into the message buffer + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateRebootRequestMsgL"))); + + iServerId.Close(); + SetMessageHeaderL( EConfirm ); + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + + // +++++++++++++++++++++++ IA_NA/TA options+++++++++++++++++++++++++++++++++++/ + iInterfaceConfigInfo.AppendIAOptionsL( *v6Msg, EConfirm ); + // +++++++++++++++++++++++ IA_TA +++++++++++++++++++++++++++++++++++++++++++++/ + //iInterfaceConfigInfo.Init6ialiseNA_Option( *v6Msg->AddOptionL( EIaTa, KDHCPOptionIA_TATInitLength ) ); + // +++++++++++++++++++++++ append requested options list +++++++++++++++++++++/ + static_cast(v6Msg->AddOptionL( EOro, KDHCPOptionRequestLen ))->AppendRequestedOptions(); + + } + +void CDHCPIP6StateMachine::CreateInformMsgL() +/** + * Puts the specifics of an inform-request message + * into the message buffer + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateInformMsgL"))); + + SetMessageHeaderL( EInformationRequest ); + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); +#ifdef SYMBIAN_TCPIPDHCP_UPDATE + //This is used for multiple parameter option request + if (iSavedExtraParameters.Ptr()) + { + TUint8 requestedOptions[KDHCPOptionRequestLen] = {0,EServerId, 0,EIaNa, 0,ESipServerD, 0,ESipServerA, + 0,EDNSServers, 0,EDomainList}; + + TPtr8 ptr(requestedOptions, KDHCPOptionRequestLen, KDHCPOptionRequestLen ); + + RBuf8 appendOpCodeList; + appendOpCodeList.CreateL(ptr); + TInt oplength = appendOpCodeList.Length(); + //get the no of opcode to be fetched + TInt optLen= iSavedExtraParameters.Length(); + //Reallocate the opcodelist with the new opcodes(example if the client requests + //for 2options in the multiple opcode then the new memory will be allocated for 2 opcodes(2*2= 4 as it is 16bit)) + appendOpCodeList.ReAllocL(KDHCPOptionRequestLen+(optLen*2)); + for (TUint8 i=1;i<=optLen;i++) + { + //append null at the begining of the opcode always + appendOpCodeList.Append(TChar::EAlphaGroup); + //get the opcode number and append at the end + TPtr8 ptrs= iSavedExtraParameters.RightTPtr(i); + appendOpCodeList.Append(ptrs.Ptr(),1); + } + //add the required opcodes in the addoption + static_cast(v6Msg->AddOptionL(EOro, appendOpCodeList.Length()))->GetBodyDes().Copy(appendOpCodeList); + appendOpCodeList.Close(); + } +#endif //SYMBIAN_TCPIPDHCP_UPDATE + // +++++++++++++++++++++++ append requested options list +++++++++++++++++++++/ + static_cast(v6Msg->AddOptionL( EOro, KDHCPOptionRequestLen ))->AppendRequestedOptions(); + } + +void CDHCPIP6StateMachine::CreateRenewRequestMsgL() +/** + * Puts the specifics of the renew message + * into the mesage buffer + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateRenewRequestMsgL"))); + + SetMessageHeaderL( ERenew ); + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + + // +++++++++++++++++++++++ IA_NA/TA options+++++++++++++++++++++++++++++++++++/ + iInterfaceConfigInfo.AppendIAOptionsL( *v6Msg, ERenew ); + // +++++++++++++++++++++++ IA_TA +++++++++++++++++++++++++++++++++++++++++++++/ + //iInterfaceConfigInfo.Init6ialiseNA_Option( *v6Msg->AddOptionL( EIaTa, KDHCPOptionIA_TATInitLength ) ); + // +++++++++++++++++++++++ append requested options list +++++++++++++++++++++/ + + static_cast(v6Msg->AddOptionL( EOro, KDHCPOptionRequestLen ))->AppendRequestedOptions(); + } + +void CDHCPIP6StateMachine::CreateRebindRequestMsgL() +/** + * Puts the specifics of the rebind message + * into the message buffer + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateRebindRequestMsgL"))); + + SetMessageHeaderL( ERebind ); + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + + iInterfaceConfigInfo.ResetUseUnicast(); + + // +++++++++++++++++++++++ IA_NA/TA options+++++++++++++++++++++++++++++++++++/ + iInterfaceConfigInfo.AppendIAOptionsL( *v6Msg, ERebind ); + // +++++++++++++++++++++++ IA_TA +++++++++++++++++++++++++++++++++++++++++++++/ + //iInterfaceConfigInfo.Init6ialiseNA_Option( *v6Msg->AddOptionL( EIaTa, KDHCPOptionIA_TATInitLength ) ); + // +++++++++++++++++++++++ append requested options list +++++++++++++++++++++/ + static_cast(v6Msg->AddOptionL( EOro, KDHCPOptionRequestLen ))->AppendRequestedOptions(); + } + +void CDHCPIP6StateMachine::CreateReleaseMsgL() +/** + * Puts the specifics of the release message + * into the message buffer + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateReleaseMsgL"))); + + SetMessageHeaderL( DHCPv6::ERelease ); + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + + iInterfaceConfigInfo.SetAddressStatus( DHCPv6::KAddrIndexAll, DHCPv6::EMarkForRelease ); + + // +++++++++++++++++++++++ IA_NA/TA options+++++++++++++++++++++++++++++++++++/ + iInterfaceConfigInfo.AppendIAOptionsL( *v6Msg, DHCPv6::ERelease ); + + RemoveConfiguredAddress(); + } + +void CDHCPIP6StateMachine::CreateDeclineMsgL() +/** + * Puts the specifics of the decline message + * into the message buffer + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::CreateDeclineMsgL"))); + + SetMessageHeaderL( EDecline ); + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + + // +++++++++++++++++++++++ IA_NA/TA options+++++++++++++++++++++++++++++++++++/ + iInterfaceConfigInfo.AppendIAOptionsL( *v6Msg, EDecline ); + + } + +void CDHCPIP6StateMachine::HandleOfferL() +/** + * Handles the selected advertisement from a dhcp server, providing + * an offer of configuration parameters + * + * @see CDHCPIP6Select + * @internalTechnology + * + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::HandleOffer"))); + + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + //remember the address of the server and check for unicast option + iInterfaceConfigInfo.CheckForUnicast( *v6Msg ); + } + +CDHCPState* CDHCPIP6StateMachine::HandleReplyL( TRequestStatus* aStatus ) +/** + * Called after Request, Confirm, Renew, Rebind or + * Information-request message + * + * @internalTechnology + * + */ +{ + iReceiving = EFalse; + + CDHCPState* state = NULL; + + if ( GetMessageType() != EReply ) + { + return ReceiveL(aStatus); + } + + switch ( DhcpMessage()->GetStatusCode() ) + { + case ESuccess: + HandleAckL(); + User::RequestComplete(aStatus, KErrNone); + state = static_cast(iActiveEvent->Next()); + + // No need to notify server status - the TCP/IP6 stack will + // move straight to the address assigned state when we call + // ConfigureL... + + break; + + case EUnspecFail: + case ENoAddrsAvail: + case ENoBinding: + case ENotOnLink: + User::RequestComplete(aStatus, KErrAccessDenied); + + state = NULL; + break; + + case EUseMulticast: + { + iInterfaceConfigInfo.ResetUseUnicast(); + //return to the previous state and use multicast + CAsynchEvent* p = iFirstState; + while ( p->Next() != iActiveEvent ) + { + p = p->Next(); + } + state =static_cast(p); + } + break; + + + default: + state = ReceiveL(aStatus); + break; + + };// switch + + + return state; +} + +void CDHCPIP6StateMachine::HandleAckL() +/** + * Handles a succesfull reply from a dhcp server, storing + * configuration parameters and a committed ip address. + * Checks status code for IA(s) and IP address options and leaves + * with KErrAccessDenied if no address is avaiable. + * + * @internalTechnology + * + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::HandleAck"))); + + CDHCPMessageHeaderIP6* v6Msg = DhcpMessage(); + //get addresses out of IA options + iInterfaceConfigInfo.ParseIAOptionsL(*v6Msg); + //check unicast option & server address + iInterfaceConfigInfo.CheckForUnicast(*v6Msg); + + //check name servers from msg options + if( iNameServerAddressesFromServer ) + { + CDHCPOptionDNSServers* pServers = static_cast(v6Msg->GetOptions().FindOption( EDNSServers )); + if ( pServers ) + { + pServers->GetDomainNameServer( 0, iNameServer1 ); + pServers->GetDomainNameServer( 1, iNameServer2 ); + } + } + //get a host name somehow? + //still draft only draft-ietf-dhc-dhcpv6-fqdn-00.txt with option-code OPTION_CLIENT_FQDN (TBD) + + #ifdef _LOG + TBuf<39> addrStr; + + interfaceInfo.iAddress.Output( addrStr ); + + __CFLOG_1( KLogSubSysDHCP, KLogCode, _L( "DHCP client address is %S" ), &addrStr ); + #endif + + ConfigureInterfaceL( 0 ); + } + +void CDHCPIP6StateMachine::ConfigureInterfaceL( TInt aPos ) +/** + * Set the interface IP address and other params + * into the TCP/IP6 stack. + * Picks next valid address starting from given possition + * + * What we set depends on the setup + * in commDB for the service. If ipAddressFromServer + * is true then we set the ip address that has + * been assigned by DHCP, along with the netmask and gateway. + * If ipAddressFromServer is false, then we set the static ip + * address as long as it has been okayed by the DHCP server after + * we have sent an inform. We will then set the netmask and gateway + * choosing from those in commDB if they have been given values, or + * those returned in the DHCP Server ACK if a zero address is in commDB + * The same principle applies to DNS Server addresses. + * + * @param aPos possition to start in the address list + * @see SIdentityAssociationConfigInfo + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::ConfigureInterfaceL - Cancel Message Sender - aPos %d"), aPos)); + iMessageSender->Cancel(); + + if (!IsGettingCfgInfoOnly()) + { + const SIPAddressInfo* info = iInterfaceConfigInfo.GetValidAddressInfo( aPos ); + if ( !info ) + {//no more addresses to configure + User::Leave( KErrNotFound ); + } + //the values already checked on TInterfaceConfigInfo::ParseIAOptionsL + iRenewalTimeT1 = iInterfaceConfigInfo.RenewTime(); + iRebindTimeT2 = iInterfaceConfigInfo.RebindTime(); + iLeaseTime = info->iValidLifeTime; + + // This block caters for the following 2 cases: + // 1. Server sent 0 lease time, meaning "forever". This behaviour wasn't defined in the + // original RFC but many servers work this way so we need to support it. + // 2. Server sent extremely large lease time (e.g. 0xffffffff as specified in RFC). + // As TTimeIntervalSeconds has a maximum of 0x7fffffff, we must enforce this maximum. + // + if ( iLeaseTime == 0 || iLeaseTime > KReallyLongLease ) + { + iLeaseTime = KReallyLongLease; // 68 years should be long enough + } + + if ( (iRenewalTimeT1 == iRebindTimeT2) || (iRenewalTimeT1==0 && iRebindTimeT2==0) ) + { + // may have only been provided with a lease time... + // we need time to renew the lease before it runs out + // so we'd better set some times from the overall lease time + TUint32 temp = iLeaseTime/4; + iRenewalTimeT1=iLeaseTime/2; + iRebindTimeT2=iRenewalTimeT1+temp; + } + else if (iRenewalTimeT1iAddress.Ip6Address() ); + } + else if ( aPos != 0 ) + {//no more addresses to configure only one statically configured address + User::Leave( KErrNotFound ); + } + + TSoInet6InterfaceInfo interfaceInfo; + //fill interfaceInfo current address is iCurrentAddress + interfaceInfo.iHwAddr = iHardwareAddr; + interfaceInfo.iAddress = iCurrentAddress; +// interfaceInfo.iNetMask = iSubnetMask; + interfaceInfo.iDefGate = iDefGateway; + if (iNameServerAddressesFromServer) + { + interfaceInfo.iNameSer1 = iNameServer1; + interfaceInfo.iNameSer2 = iNameServer2; + } + else + { + //We need to set the family to KAFUnspec to ensure that the Stack does not overwrite the existing address + interfaceInfo.iNameSer1.SetFamily(KAFUnspec); + interfaceInfo.iNameSer2.SetFamily(KAFUnspec); + } + interfaceInfo.iName = iInterfaceName; + interfaceInfo.iMtu = 0; + interfaceInfo.iSpeedMetric = 0; + interfaceInfo.iFeatures = 0; // zero value better than junk value + + interfaceInfo.iState = EIfUp; + + interfaceInfo.iDelete = EFalse; + interfaceInfo.iAlias = EFalse; + interfaceInfo.iDoId = ETrue; + interfaceInfo.iDoState = ETrue; + interfaceInfo.iDoAnycast = EFalse; + interfaceInfo.iDoProxy = EFalse; + interfaceInfo.iDoPrefix = EFalse; + + CDHCPStateMachine::ConfigureInterfaceL( interfaceInfo ); + } + +void CDHCPIP6StateMachine::InitialiseSocketL() +/** + * Sets up socket, by opening one associated with the connection + * and sets the interface to use for traffic + * + * @internalTechnology + * + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::InitialiseSocketL"))); + + iSocket.Close(); + + User::LeaveIfError(iSocket.Open(iEsock, KAfInet, KSockDatagram, KProtocolInetUdp, iConnection)); + User::LeaveIfError(iSocket.SetOpt(KSoReuseAddr, KSolInetIp, 1)); +#ifdef _DEBUG + TInt destPort; + RProperty::Get(KMyPropertyCat, KMyPropertyDestPortv6, destPort); + User::LeaveIfError(iSocket.SetLocalPort(destPort - 1)); +#else + User::LeaveIfError(iSocket.SetLocalPort(KDhcpv6SrcPort)); +#endif + TPckgBuf query; + query().iName = iInterfaceName; + User::LeaveIfError(iSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query)); + User::LeaveIfError(iSocket.SetOpt(KSoInterfaceIndex, KSolInetIp, query().iIndex)); + User::LeaveIfError(iSocket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl)); + // make socket invisable for interface counting + User::LeaveIfError(iSocket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0)); + } + +void CDHCPIP6StateMachine::RemoveConfiguredAddress(const TInetAddr* /* aInetAddr*/) +/** + * This function can be called as a result of DAD failing + * or the lease expiring! It removes the address from the interface + * inside the TCP/IP6 stack as the address cannot continue to be used. + * + * @see "Implementation of IPv4/IPv6 Basic Socket API for Symbian OS" + * document for explanation of TSoInet6InterfaceInfo and its use + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::RemoveConfiguredAddress"))); + + TSoInet6InterfaceInfo interfaceInfo; + interfaceInfo.iHwAddr = iHardwareAddr; + interfaceInfo.iAddress = iCurrentAddress; + interfaceInfo.iName = iInterfaceName; + interfaceInfo.iDelete = ETrue; + interfaceInfo.iAlias = EFalse; + interfaceInfo.iDoId = ETrue; + interfaceInfo.iState = EIfUp; + interfaceInfo.iDoState = ETrue; + interfaceInfo.iDoAnycast = EFalse; + // zero value better than junk value + interfaceInfo.iMtu = 0; + interfaceInfo.iSpeedMetric = 0; + interfaceInfo.iFeatures = 0; + CDHCPStateMachine::RemoveConfiguredAddress( interfaceInfo ); + iInterfaceConfigInfo.Reset(); + } + +void CDHCPIP6StateMachine::AssignAddresses( TInetAddr& aDest, const TInetAddr& aSrc ) const + { + aDest = aSrc; + +#ifdef _DEBUG + // Simulate initialisation, renewal or rebind failure by using the wrong port. + if( ( CDHCPServer::DebugFlags() & KDHCP_FailDiscover ) || ( CDHCPServer::DebugFlags() & KDHCP_FailRenew ) || ( CDHCPServer::DebugFlags() & KDHCP_FailRebind ) ) + { + aDest.SetPort(KDhcpv6WrongSrcPort); + } + else + { + TInt destPort; + RProperty::Get(KMyPropertyCat, KMyPropertyDestPortv6, destPort); + aDest.SetPort(destPort - 1); + } +#else + aDest.SetPort(KDhcpv6SrcPort); +#endif + } + +void CDHCPIP6StateMachine::BindSocketForUnicastL() +/** + * Initialises socket in case it hasn't already been initialised + * + * @internalTechnology + */ + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6StateMachine::BindSocketForRenewL"))); + UpdateHistory(CDHCPState::EBindToSource); + if (!iSocket.SubSessionHandle()) + { + InitialiseSocketL(); + } + }