diff -r 000000000000 -r af10295192d8 tcpiputils/dhcp/src/DHCPIP6States.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcpiputils/dhcp/src/DHCPIP6States.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,530 @@ +// 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 DHCPv4 States representing each interface +// +// + +/** + @file DHCPIP6States.cpp + @internalTechnology +*/ + +#include "DHCPIP6States.h" +#include "DhcpIP6Msg.h" +#include "DHCPIP6MsgSender.h" + +#include "DHCPServer.h" +#include "DHCPStatesDebug.h" + +using namespace DHCPv6; + +#ifdef SYMBIAN_ESOCK_V3 +CDHCPIP6ListenToNeighbor::~CDHCPIP6ListenToNeighbor() + { + if ( iNetSubscribe ) + { + iEvent.Cancel(*iNetSubscribe); + } + } + + + + + +CAsynchEvent* CDHCPIP6ListenToNeighbor::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6ListenToNeighbor); + //(static_cast(this)->*iHandler)(); + CDHCPIP6StateMachine& stmachine = DHCPIPv6(); + //set us as an error event as well so that we catch the leave and can deregister if needed + stmachine.SetErrorEvent( this ); + stmachine.CancelTimer(); + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6ListenToNeighbor::ProcessL err %d"), stmachine.LastError())); + if ( iErr == KErrNone ) + { + iErr = stmachine.LastError(); + if ( iErr == KErrNone || (iQuery && iQuery->iHandle) ) + {//we can get here only when we want to subscribe or unsubscribe + SubscribeL( stmachine.InterfaceName(), IPEvent::EMFlagReceived, iEvent ); + } + } + if ( iErr == KErrNone && iQuery && iQuery->iHandle ) + {//start timer in case we never get the signal + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6ListenToNeighbor::ProcessL wait signal StartTimer"))); + + + // The 14 second timeout comes from the 3x4 seconds the IP stack waits for RouterAdvs once it's sent out + // its 3 RouterSols ... plus a bit for processing. Search for iRtrSolicitationInterval in tcpip/src/iface.cpp + stmachine.StartTimer( TTimeIntervalSeconds(14)/*seconds*/, *this ); + + aStatus = KRequestPending; + stmachine.SetAsyncCancelHandler(this); + } + else + {//we're deregistered => start statemachine based on 'M' flag value + ASSERT( this == DHCPIPv6().iFirstState ); + CleanupStack::PushL(this); + stmachine.iFirstState = NULL; + stmachine.SetErrorEvent( NULL ); + + if (iErr == KErrTimedOut) + { + TimerExpired(); + } + else + { + // RA received + if ( iMFlag ) + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("MFlag true. - Proceeding with Stateful"))); + stmachine.StartInitL( NULL, CDHCPStateMachine::ESubsequentCalls ); + } + else + { + if( iOFlag ) + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("MFlag false, OFlag True - stateful autoconfiguration to get non-IPv6-address information"))); + CompleteClientAndStartInform(); // complete client, as 'O' flag set - stateful autoconfiguration to get non-IPv6-address information + } + else + { + BecomeIdle(); // 'M' and 'O' flags are false + } + } + } + CleanupStack::PopAndDestroy(this); + return stmachine.iFirstState; + } + stmachine.SetLastError( KErrNone ); //ignore the error + return this; + } + +/*static*/ +void CDHCPIP6ListenToNeighbor::SignalHandlerFn( TAny* aThis, const Meta::SMetaData* aData ) + { + //Router Advt received, decide upon 'M' and 'O' flags + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6ListenToNeighbor::SignalHandlerFn()"))); + CDHCPIP6ListenToNeighbor* inst = reinterpret_cast(aThis); + CDHCPIP6StateMachine& stmachine = inst->DHCPIPv6(); + inst->iMFlag = static_cast(aData)->GetMFlag(); + inst->iOFlag = static_cast(aData)->GetOFlag(); + stmachine.CancelTimer(); + TRequestStatus* p = &stmachine.iStatus; + User::RequestComplete( p, KErrNone ); + stmachine.SetAsyncCancelHandler(NULL); + } + +void CDHCPIP6ListenToNeighbor::Cancel() + { + CDHCPIP6StateMachine& stmachine = DHCPIPv6(); + stmachine.CancelTimer(); + TRequestStatus* p = &stmachine.iStatus; + User::RequestComplete( p, KErrCancel ); + stmachine.SetAsyncCancelHandler(NULL); + } + + +void CDHCPIP6ListenToNeighbor::BecomeIdle() + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6ListenToNeighbor::BecomeIdle()"))); + CDHCPIP6StateMachine& stmachine = DHCPIPv6(); + TRequestStatus* p = &stmachine.iStatus; + stmachine.SetIdle( ETrue ); + User::RequestComplete( p, KErrNone ); + stmachine.SetAsyncCancelHandler(NULL); + } + +void CDHCPIP6ListenToNeighbor::CompleteClientAndStartInform() + { + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6ListenToNeighbor::CompleteClientAndStartInform()"))); + CDHCPIP6StateMachine& stmachine = DHCPIPv6(); + TRequestStatus* p = &stmachine.iStatus; + stmachine.SetCompleteClientRequestTrue(); + User::RequestComplete( p, KErrNone ); + stmachine.SetAsyncCancelHandler(NULL); + } + + +void CDHCPIP6ListenToNeighbor::TimerExpired() + { + //start state-ful config since no signal received + __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP6ListenToNeighbor::TimerExpired()"))); + CDHCPIP6StateMachine& stmachine = DHCPIPv6(); + TRequestStatus* p = &stmachine.iStatus; + User::RequestComplete( p, KErrTimedOut ); + stmachine.SetAsyncCancelHandler(NULL); + } +#endif +/** our selection criteria so far + * - the first advertise msg received or the one with the highest + * preference value + * + * some smarter selection criteria for server advertisements: + * - Within a group of Advertise messages with the same server + * preference value, a client MAY select those servers whose + * Advertise messages advertise information of interest to the + * client. For example, the client may choose a server that returned + * an advertisement with configuration options of interest to the + * client. + * + * - The client MAY choose a less-preferred server if that server has a + * better set of advertised parameters, such as the available + * addresses advertised in IAs. +*/ +CAsynchEvent* CDHCPIP6Solicit::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6Solicit); + CDHCPIP6MessageSender* pSender = DHCPIPv6().MessageSender(); + //ask for a signal after the first RT elapses + pSender->SetMaxRetryCount( 1 ); + pSender->SetMaxRetryTimeout( DHCPv6::KSolMaxRt ); + TInt n = KIP6MaxSecs; + if( iUserDefinedTimeout != 0 ) + { + n = iUserDefinedTimeout; + } + pSender->SetMaxRetryDuration( n ); + pSender->SetInitialRetryTimeout( DHCPv6::KSolTimeout ); + pSender->SetFirstSendDelay( DHCPv6::KSolMaxDelay ); + //here we know that select follows after solicit + pSender->SetListener(static_cast(iNext)); + return CDHCPAddressAcquisition::ProcessL( aStatus ); + } + +void CDHCPIP6Select::SetMaxRetryCount(TInt aMaxRetryCount) + { + iMaxRetryCount = aMaxRetryCount; + } + +const TInt KAdvertOverridePref = 255; +CAsynchEvent* CDHCPIP6Select::ProcessL(TRequestStatus& aStatus) + {//called when a message's been received or state's changed for us + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6Select); + CDHCPIP6StateMachine& rDHCP = DHCPIPv6(); + CDHCPIP6MessageSender* pSender = rDHCP.MessageSender(); + CDHCPMessageHeaderIP6* v6Msg = rDHCP.DhcpMessage(); + if(rDHCP.iReceiving || iDone) + { // we're waiting to receive data from the socket + /* + collect advertisements so long we are waiting for the first retransmition timeout. + Keep the first one and check the others for + preference option with a pref value of 255. If the client receives an Advertise message + that does not include a Preference option with a preference value of 255, the + client continues to wait until the first RT elapses + if pSender->Notifier() != this than the first RT's elapsed => we're happy + with any message that is a valid advertisement + */ + rDHCP.iReceiving = EFalse; + if(rDHCP.GetMessageType() == DHCPv6::EAdvertise) + { + /* + examine the message and make decision based on the aforementioned + selection criteria + */ + DHCPv6::COptionNode* option = v6Msg->GetOptions().FindOption(DHCPv6::EPreference); + TInt serverPreference; + if (option) + { + serverPreference = option->GetBigEndian(); + } + else + { + serverPreference = 0; + } + if(pSender->EventListener() != this || iDone || serverPreference == KAdvertOverridePref) + { + // We're not interested in further notifications + pSender->SetListener( &rDHCP ); + + // Set-up sender, consume selected advertisement & initiate request + // message + pSender->SetMaxRetryCount(DHCPv6::KReqMaxRc); + pSender->SetMaxRetryTimeout(DHCPv6::KReqMaxRt); + pSender->SetMaxRetryDuration(KIP6MaxSecs); + pSender->SetInitialRetryTimeout(DHCPv6::KReqTimeout); + pSender->SetFirstSendDelay(0); + + if ( !iDone/*see CDHCPIP6Select::MSReportError*/ && iSelectedMessage.Length() ) + { + // Copy the selected message back the max length must be enough since we've read + //iSelectedMessage into the v6Msg buffer + v6Msg->Message().Des().Copy(iSelectedMessage); + } + + return CDHCPSelect::ProcessL(aStatus); + } + else + { // Work out if this advertisment's better for us + + if(serverPreference > iBestServerPreference ) + { + iBestServerPreference = serverPreference; + + // Store a copy away for later + TInt ret= iSelectedMessage.ReAlloc(v6Msg->Message().Length()); + if (ret == KErrNone) + iSelectedMessage.Copy(v6Msg->Message()); + else + User::LeaveIfError(ret); + } + } + } + } + + // wait for a message (next or the first) + return rDHCP.ReceiveL(&aStatus); + } + +/* + This method is called when the retransmission timer expires. +*/ +TInt CDHCPIP6Select::MSReportError(TInt aError) + {//called when the first RT's expired + CDHCPIP6StateMachine& rDHCP = DHCPIPv6(); + CDHCPIP6MessageSender* pSender = rDHCP.MessageSender(); + if(aError == KErrTimedOut) + { + /* + the first RT's elapsed so check the collected messages + if we have one (the first one) we're done if not we start the sender again + */ + + if (iBestServerPreference != -1) + { + pSender->Cancel(); + iDone = ETrue; + rDHCP.CancelMessageReceiver(); + + // Copy the selected message back the max length must be enough since we've read + //iSelectedMessage into the v6Msg buffer + rDHCP.DhcpMessage()->Message().Des().Copy(iSelectedMessage); + + return aError; + } + else + { + // We're not interested in further notifications + pSender->SetListener(&rDHCP); + pSender->SetMaxRetryCount(iMaxRetryCount); + + return KErrNone; // Causes the sender to continue + } + } + + // Something else's gone wrong => report it up + pSender->SetListener(&rDHCP); + + return rDHCP.MSReportError(aError); + } + +CDHCPIP6Select::~CDHCPIP6Select() + { + iSelectedMessage.Close(); + } + +CAsynchEvent* CDHCPIP6InformRequest::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6InformRequest); + CDHCPIP6MessageSender* pSender = DHCPIPv6().MessageSender(); + pSender->SetMaxRetryCount( INT_MAX ); + pSender->SetMaxRetryTimeout( DHCPv6::KInfMaxRt ); + pSender->SetMaxRetryDuration( KIP6MaxSecs ); + pSender->SetInitialRetryTimeout( DHCPv6::KInfTimeout ); + pSender->SetFirstSendDelay( DHCPv6::KInfMaxDelay ); + return CDHCPInformationConfig::ProcessL( aStatus ); + } + +CAsynchEvent* CDHCPIP6Release::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6Release); + CDHCPIP6MessageSender* pSender = DHCPIPv6().MessageSender(); + pSender->SetMaxRetryCount( DHCPv6::KRelMaxRc ); + pSender->SetMaxRetryTimeout( KIP6MaxSecs ); + pSender->SetMaxRetryDuration( KIP6MaxSecs ); + pSender->SetInitialRetryTimeout( DHCPv6::KRelTimeout ); + pSender->SetFirstSendDelay( 0 ); + CDHCPRelease::ProcessL( aStatus ); //this fn doesn't actually complete status for v6 + iStateMachine->SetActiveEvent( iNext ); //to shift the state after the receiver is ready + return DHCPIPv6().ReceiveL( &aStatus ); + } + +CAsynchEvent* CDHCPIP6Decline::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6Decline); + CDHCPIP6MessageSender* pSender = DHCPIPv6().MessageSender(); + pSender->SetMaxRetryCount( DHCPv6::KDecMaxRc ); + pSender->SetMaxRetryTimeout( KIP6MaxSecs ); + pSender->SetMaxRetryDuration( KIP6MaxSecs ); + pSender->SetInitialRetryTimeout( DHCPv6::KDecTimeout ); + pSender->SetFirstSendDelay( 0 ); + CDHCPDecline::ProcessL( aStatus ); //this fn doesn't actually complete status for v6 + iStateMachine->SetActiveEvent( iNext ); //to shift the state after the receiver is ready + return DHCPIPv6().ReceiveL( &aStatus ); + } + +CDHCPState* CDHCPIP6ReplyNoBinding::ProcessAckNakL(TRequestStatus* aStatus) + { + CDHCPIP6StateMachine& rDHCP = DHCPIPv6(); + if ( rDHCP.GetMessageType() == DHCPv6::EReply ) + { + rDHCP.CancelMessageSender(); + rDHCP.iReceiving = EFalse; + User::RequestComplete(aStatus, KErrNone); + return static_cast(iNext); + } + return rDHCP.ReceiveL( aStatus ); + } + +CAsynchEvent* CDHCPIP6Confirm::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6Confirm); + CDHCPIP6MessageSender* pSender = DHCPIPv6().MessageSender(); + pSender->SetMaxRetryCount( INT_MAX ); + pSender->SetMaxRetryTimeout( DHCPv6::KCnfMaxRt ); + pSender->SetMaxRetryDuration( DHCPv6::KCnfMaxRd ); + pSender->SetInitialRetryTimeout( DHCPv6::KCnfTimeout ); + pSender->SetFirstSendDelay( DHCPv6::KCnfMaxDelay ); + return CDHCPRebootConfirm::ProcessL( aStatus ); + } + +#if 0 +CAsynchEvent* CDHCPIP6WaitForDAD::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6WaitForDAD); + CDHCPIP6StateMachine& rDHCP = DHCPIPv6(); + rDHCP.StartTimer(KOneSecond*20, *this); // 20 secs timer in case there's no response from IPNotifier. + if (iAddressIndex == 1 && !CSubscribeChannel::ListenL(aStatus,event,rDHCP.C32Root())) + { + return this; + } + else + { + //read channel data and if success then attempt to bind to verify the result + + if ( rDHCP.ConfigureInterface( iAddressIndex++ ) ) + {//set the next address as iCurrentAddress + //and listen for DAD + CSubscribeChannel::ListenL(aStatus,event,rDHCP.C32Root()); + return this; + } + } + return iNext; + } +#else +CAsynchEvent* CDHCPIP6WaitForDAD::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6WaitForDAD); + CDHCPIP6StateMachine& rDHCP = DHCPIPv6(); + if (iAddressIndex == 0) + {//start the first wait + iAddressIndex++; + CDHCPWaitForDADBind::ProcessL( aStatus ); + return this; + } + else if ( iErr != KErrNone ) + {//Mark the iAddressIndex as invalid and attempt to bind the next one + rDHCP.iInterfaceConfigInfo.SetAddressStatus( iAddressIndex -1, DHCPv6::EMarkForDecline ); + rDHCP.ConfigureInterfaceL( iAddressIndex++ ); + //listen for DAD + CDHCPWaitForDADBind::ProcessL( aStatus ); + return this; + } + else + {//Mark all but iAddressIndex as invalid + } + TRequestStatus* p = &aStatus; + User::RequestComplete(p, iErr); + return iNext; + } + +void CDHCPIP6WaitForDAD::TimerExpired() + { + CDHCPWaitForDADBind::TimerExpired(); + CDHCPStateMachine& rDHCP = Dhcp(); + if ( !rDHCP.TimerActive() ) + { + //finish either => bound or not => bouncwe back to CDHCPIP6WaitForDAD::ProcessL + TRequestStatus* p = &iStateMachine->iStatus; + User::RequestComplete(p, KErrNone); //proceed back to the process function + rDHCP.SetAsyncCancelHandler(NULL); + } + } +#endif + +CAsynchEvent* CDHCPIP6Renew::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6Renew); + CDHCPIP6StateMachine& rDHCP = DHCPIPv6(); + CDHCPIP6MessageSender* pSender = rDHCP.MessageSender(); + pSender->SetMaxRetryCount( INT_MAX ); + pSender->SetMaxRetryTimeout( DHCPv6::KRenMaxRt ); + TInt n = rDHCP.iRebindTimeT2 - rDHCP.iRenewalTimeT1; + if(iUserDefinedTimeout) + { + n = iUserDefinedTimeout; + } + else if ( n <= 0 ) + { + n = 2; //2 seconds + } + pSender->SetMaxRetryDuration( n ); + pSender->SetInitialRetryTimeout( DHCPv6::KRenTimeout ); + pSender->SetFirstSendDelay( 0 ); + return CDHCPRenew::ProcessL( aStatus ); + } + +CAsynchEvent* CDHCPIP6Rebind::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6Rebind); + CDHCPIP6StateMachine& rDHCP = DHCPIPv6(); + CDHCPIP6MessageSender* pSender = rDHCP.MessageSender(); + pSender->SetMaxRetryCount( INT_MAX ); + pSender->SetMaxRetryTimeout( DHCPv6::KRebMaxRt ); + TInt n = rDHCP.iLeaseTime - rDHCP.iRebindTimeT2; + if(iUserDefinedTimeout) + { + n = iUserDefinedTimeout; + } + else if ( n <= 0 ) + { + n = 2; //2 seconds + } + pSender->SetMaxRetryDuration( n ); + pSender->SetInitialRetryTimeout( DHCPv6::KRebTimeout ); + pSender->SetFirstSendDelay( 0 ); + return CDHCPRebind::ProcessL( aStatus ); + } + +CAsynchEvent* CDHCPIP6Reconfigure::ProcessL(TRequestStatus& aStatus) + { + DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EDHCPIP6Reconfigure); + CDHCPIP6StateMachine& rDHCP = DHCPIPv6(); + if (!rDHCP.iReceiving) + { + rDHCP.InitialiseSocketL(); + } + return CDHCPRequest::ProcessL(aStatus); + } + +CDHCPState* CDHCPIP6Reconfigure::ProcessAckNakL(TRequestStatus* aStatus) + {//check for reconfigure reply msg + CDHCPIP6StateMachine& rDHCP = DHCPIPv6(); + if ( rDHCP.GetMessageType() == DHCPv6::EReconfigure ) + { + rDHCP.iReceiving = EFalse; + User::RequestComplete(aStatus, KErrNone); + return static_cast(iNext); + } + return rDHCP.ReceiveL( aStatus ); + }