--- /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<TEvent*>(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<CDHCPIP6ListenToNeighbor*>(aThis);
+ CDHCPIP6StateMachine& stmachine = inst->DHCPIPv6();
+ inst->iMFlag = static_cast<const IPEvent::CMFlagReceived*>(aData)->GetMFlag();
+ inst->iOFlag = static_cast<const IPEvent::CMFlagReceived*>(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<CDHCPIP6Select*>(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<CDHCPState*>(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<CDHCPState*>(iNext);
+ }
+ return rDHCP.ReceiveL( aStatus );
+ }