tcpiputils/dhcp/src/DHCPIP6StateMachine.cpp
changeset 0 af10295192d8
child 20 7e41d162e158
--- /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 <e32property.h>
+#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<CDHCPIP6Select*>(state1)->SetMaxRetryCount(1);
+			}
+		else
+			{
+			//We never found a DCHP server the first time, but this time try harder.
+			static_cast<CDHCPIP6Select*>(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<CDHCPState*>(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<CDHCPState*>(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<TUint8*>(iClientId.Ptr()), KDuidTypeLen, KDuidLLTypeCode);	
+	TBigEndian::SetValue(const_cast<TUint8*>(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<TUint32>(data));
+		iClientId.Append(TPckgC<TUint16>(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<TUint8>(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<CDHCPOptionRequestOption*>(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<CDHCPOptionRequestOption*>(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<CDHCPOptionRequestOption*>(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<CDHCPOptionRequestOption*>(v6Msg->AddOptionL(EOro, appendOpCodeList.Length()))->GetBodyDes().Copy(appendOpCodeList);
+		appendOpCodeList.Close();
+		}
+#endif //SYMBIAN_TCPIPDHCP_UPDATE		
+	// +++++++++++++++++++++++ append requested options list +++++++++++++++++++++/
+   static_cast<CDHCPOptionRequestOption*>(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<CDHCPOptionRequestOption*>(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<CDHCPOptionRequestOption*>(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<CDHCPState*>(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<CDHCPState*>(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<CDHCPOptionDNSServers*>(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 (iRenewalTimeT1<iRebindTimeT2 && iRebindTimeT2<iLeaseTime && iRenewalTimeT1<iLeaseTime)
+            {
+            // do nothing as we have got the valid values we were expecting
+            }
+        else
+            {
+            User::Leave(KErrArgument);
+            }   
+		
+		iCurrentAddress.SetAddress( info->iAddress.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<TSoInetIfQuery> 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();
+        }
+	}