tcpiputils/dhcp/src/DHCPIP4StateMachine.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:33:58 +0100
branchRCL_3
changeset 58 8d540f55e491
parent 57 abbed5a4b42a
child 75 c1029e558ef5
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201035 Kit: 201035

// 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 IP4 statemachine helper functions
// 
//

/**
 @file DHCPIP4StateMachine.cpp
 @internalTechnology
*/
#include <babitflags.h>
#include <e32math.h>
#include "DHCPIP4States.h"
#include "DHCPServer.h"
#ifndef SYMBIAN_COMMS_REPOSITORY
#include <commdb.h>
#else
#include <metadatabase.h>
#include <commsdattypesv1_1.h>
#endif

#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
#include "dhcphwaddrmanager.h"
#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
using namespace DHCPv4;
#ifdef SYMBIAN_COMMS_REPOSITORY
using namespace CommsDat;
#endif

#ifdef SYMBIAN_NETWORKING_DHCPSERVER
const TUint16 KBroadCastFlagMask = 0x8000;
#endif

CDHCPIP4StateMachine::~CDHCPIP4StateMachine()
/**
  * Destructor of the If base class
  *
  * @internalTechnology
  *
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::~CDHCPIP4StateMachine")));
	}
	
#ifndef SYMBIAN_NETWORKING_DHCPSERVER
CDHCPIP4StateMachine* CDHCPIP4StateMachine::NewL(RSocketServ& aEsock, RConnection& aConnection, const TName& aInterfaceName)
/**
  * Creates a new instance of this class
  *
  * @internalTechnology
  *
  */
	{
	CDHCPIP4StateMachine* stateMachine = new (ELeave) CDHCPIP4StateMachine(aEsock, aConnection, aInterfaceName);
	CleanupStack::PushL(stateMachine);
	stateMachine->ConstructL();
	CleanupStack::Pop(stateMachine);
	return stateMachine;
	}
#endif // SYMBIAN_NETWORKING_DHCPSERVER

void CDHCPIP4StateMachine::ConstructL()
/**
  * Creates socket and connections for the object
  *
  *
  *	@internalTechnology
  *
  */
	{
   CDHCPStateMachine::ConstructL();

	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ConstructL")));
	if (iConfig)
	    {
		// Parse dhcp.ini for additional options to be requested with server
		// and append the option codes to the parameter request list
        TRAP_IGNORE(AppendMultipleExtraOptionsParamL());
	    }

  	ReAllocL(KDhcpMaxMsgSizeIP4);
  	iDhcpMessage = new(ELeave)CDHCPMessageHeaderIP4(iFragment);
	iMessageSender = new(ELeave)CMessageSender(this,iSocket,&iTaskStartedAt,KAfInet);

	}

void CDHCPIP4StateMachine::StartInitL(MStateMachineNotify* aStateMachineNotify, EInitialisationContext /*aInitialisationContext*/, TInt /*aUserTimeOut*/)
/**
  * StartInitL
  *
  * This function is called to start the init state machine
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::StartInitL")));
	ASSERT(!iFirstState);
	
	iFirstState = new(ELeave) CDHCPIP4Init(*this);
	CDHCPState* select = new(ELeave) CDHCPIP4Select(*this);
	iFirstState->SetNext( select );
	CDHCPState* request = new(ELeave) CDHCPIP4Request(*this);
	select->SetNext( request );
	request->SetNext( new(ELeave) CDHCPIP4WaitForDAD(*this) );

	CDHCPStateMachine::Start(aStateMachineNotify);
	}

void CDHCPIP4StateMachine::StartInformL(MStateMachineNotify* aStateMachineNotify, TBool /*aStaticAddress*/)
/**
  * StartIniformL
  *
  * This function is called to start the inform static address state machine
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::StartInformL")));
	ASSERT(!iFirstState);

	iFirstState = new(ELeave) CDHCPIP4Inform(*this);
	CDHCPState* request = new(ELeave) CDHCPIP4Request(*this);
   iFirstState->SetNext( request );
   request->SetNext( new(ELeave) CDHCPIP4WaitForDAD(*this) );
	
	CDHCPStateMachine::Start(aStateMachineNotify);
	iCfgInfoOnly = ETrue;
	}

#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
void CDHCPIP4StateMachine::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("CDHCPIP4StateMachine::StartInformL Dynamic Inform Request")));
	ASSERT(!iFirstState);

	iFirstState = new(ELeave) CDHCPIP4Inform(*this);
	CDHCPState* request = new(ELeave) CDHCPIP4Request(*this);
	iFirstState->SetNext( request );
	CDHCPStateMachine::Start(aStateMachineNotify);

	}
#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
void CDHCPIP4StateMachine::StartRebootL(MStateMachineNotify* aStateMachineNotify)
/**
  * StartRebootL
  *
  * This function is called to start the reboot request state machine
  * used when trying to start using a previously assigned address still
  * with valid lease.
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::StartRebootL")));
	ASSERT(!iFirstState);

   iFirstState = new(ELeave) CDHCPIP4Reboot(*this);
	CDHCPState* request = new(ELeave) CDHCPIP4Request(*this);
   iFirstState->SetNext( request );
   request->SetNext( new(ELeave) CDHCPIP4WaitForDAD(*this) );

	CDHCPStateMachine::Start(aStateMachineNotify);
	}

void CDHCPIP4StateMachine::StartRenewL(MStateMachineNotify* aStateMachineNotify,TInt /*aUserTimeOut*/)
/**
  * StartRenewL
  *
  * This function is called to start the renew of lease state machine
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::StartRenew")));
	ASSERT(!iFirstState);

  	iFirstState = new(ELeave) CDHCPIP4Renew(*this);
   iFirstState->SetNext( new(ELeave) CDHCPIP4WaitForDAD(*this) );

   CDHCPStateMachine::Start(aStateMachineNotify);
	}

void CDHCPIP4StateMachine::StartRebindL(MStateMachineNotify* aStateMachineNotify)
/**
  * StartRebindL
  *
  * This function is called to start the rebind state machine
  *
  * @internalTechnology
  */	
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::StartRebindL")));
	ASSERT(!iFirstState);
	
	iFirstState = new(ELeave) CDHCPIP4Rebind(*this);
   iFirstState->SetNext( new(ELeave) CDHCPIP4WaitForDAD(*this) );

	CDHCPStateMachine::Start(aStateMachineNotify);
	}

void CDHCPIP4StateMachine::StartDeclineL(MStateMachineNotify* aStateMachineNotify)
/**
  * StartDeclineL
  *
  * This function is called to start the decline state machine
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::StartDeclineL")));
	ASSERT(!iFirstState);
	
	iFirstState = new(ELeave) CDHCPIP4Decline(*this);
	
	CDHCPStateMachine::Start(aStateMachineNotify);
	}

void CDHCPIP4StateMachine::StartReleaseL(MStateMachineNotify* aStateMachineNotify)
/**
  * StartReleaseL
  *
  * This function is called to start the release state machine
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::StartReleaseL")));
	ASSERT(!iFirstState);
	
	iFirstState = new(ELeave) CDHCPIP4Release(*this);
	//iFirstState->SetNext( new(ELeave) CDHCPRemoveConfiguredAddress(*this));
	
	CDHCPStateMachine::Start(aStateMachineNotify);
	}

CDHCPState* CDHCPIP4StateMachine::ReceiveL(TRequestStatus* aStatus)
/**
  * Posts receive from on socket
  *
  * @note The iDHCPServerAddr in param 2 of the socket receivefrom
  * is written into by the socket to say where the received message
  * came from.
  * @internalTechnology
  *
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::Receive")));
	
	DhcpMessage()->InitialiseL();
  	iIncomingMsgDataPtr.Set(iDhcpMessage->Message().Des());
   ASSERT( iReceiving == EFalse );
 	iReceiving = ETrue;
	iSocket.RecvFrom(iIncomingMsgDataPtr, iDHCPServerAddr, 0, *aStatus);
   return static_cast<CDHCPState*>(iActiveEvent);
	}

#ifdef SYMBIAN_NETWORKING_DHCPSERVER
#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
CDHCPIP4StateMachine* CDHCPIP4StateMachine::NewL(RSocketServ& aEsock, RConnection& aConnection, const TName& aInterfaceName,  CDhcpHwAddrManager* aDhcpHwAddrManager, TBool aDHCPServerImpl)
#else
CDHCPIP4StateMachine* CDHCPIP4StateMachine::NewL(RSocketServ& aEsock, RConnection& aConnection, const TName& aInterfaceName,TBool aDHCPServerImpl)
#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
/**
  * Creates a new instance of this class
  *
  * @internalTechnology
  *
  */
	{
#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
	CDHCPIP4StateMachine* stateMachine = new (ELeave) CDHCPIP4StateMachine(aEsock, aConnection, aInterfaceName, aDhcpHwAddrManager, aDHCPServerImpl);
#else
	CDHCPIP4StateMachine* stateMachine = new (ELeave) CDHCPIP4StateMachine(aEsock, aConnection, aInterfaceName,aDHCPServerImpl);
#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION	
	CleanupStack::PushL(stateMachine);
	stateMachine->ConstructL();
	CleanupStack::Pop(stateMachine);
	return stateMachine;
	}

TUint8 CDHCPIP4StateMachine::GetClientMessageTypeL() const
/**
  * Returns the message type from the DHCP message
  * i.e. whether the message is an offer, ack, nak...
  *
  * @internalTechnology 
  */
	{
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	v4Msg->ParseClientMsgL();
	v4Msg->Dump();	

	return v4Msg->iOptions.GetMessageType();
	}

	
CDHCPState* CDHCPIP4StateMachine::ReceiveOnPort67L(TRequestStatus* aStatus)
/**
  * Posts receive from on socket
  *
  * @note The iDHCPClientAddr in param 2 of the socket receivefrom
  * is written into by the socket to say where the received message
  * came from.
  * @internalTechnology
  *
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ReceiveOnPort67L")));
	
	DhcpMessage()->InitialiseL();
  	iIncomingMsgDataPtr.Set(iDhcpMessage->Message().Des());
	ASSERT( iReceiving == EFalse );
 	iReceiving = ETrue;
	iSvrSocket.RecvFrom(iIncomingMsgDataPtr, iDHCPClientAddr, 0, *aStatus);
	return static_cast<CDHCPState*>(iActiveEvent);
	}
	
void CDHCPIP4StateMachine::PrepareToSendServerMsgL( CDHCPStateMachine::EAddressType aEAddressType)
/**
  * PrepareToSendServerMsgL
  *
  * This function is called to set the correct destination address
  * for messages before they are sent.
  *
  * @internalTechnology
  */	
	{
	// nothing is done with iClientId in server implementation
	// but it is passed to reuse the existing function.
	DhcpMessage()->FinishL(iClientId); 
	DhcpMessage()->Dump();
	if (aEAddressType==EUnicast)
		{
		if(iBroadCastFlag)
			{
			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::SetDestination - broadcast")));
			iDHCPClientAddr.SetV4MappedAddress(KInetAddrBroadcast);		
			}
		else
			{
			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::SetDestination - unicast")));
			iDHCPClientAddr.SetV4MappedAddress(iYiaddr);// client ip address
			}
		}
	else
		{
		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::SetDestination - broadcast")));
		iDHCPClientAddr.SetV4MappedAddress(KInetAddrBroadcast);	
		}

// While DHCP server listens on a custom port, the server message for client
// needs to be the custom server port + 1 and not the default client port (i.e., 68)
#ifdef _DEBUG
	iDHCPClientAddr.SetPort(GetDestPort()+1);
#else
	iDHCPClientAddr.SetPort(KDhcpClientPort);
#endif
	}
	
void CDHCPIP4StateMachine::GetClientAddress( TInetAddr& aAddress )
/**
  * GetClientAddress
  *
  * Gets the assigned client address
  *
  * @internalTechnology	
*/
	{
	aAddress = iDHCPClientAddr;
	}

TUint32 CDHCPIP4StateMachine::GenerateClientIPAddress()
/**
  * GenerateClientIPAddress
  *
  * Generate valid IP address to be offered to the client
  *
  *@internalTechnology	
*/
	{
	// get the server IP address	
	TUint32 serverAddr = iCurrentAddress.Address();
	TUint32 hostId = (serverAddr & ~KInetAddrNetMaskC) + 1;
	if (hostId >= 255)
	 {
	 hostId = 1;
	 }
	return (serverAddr & KInetAddrNetMaskC) | hostId;
	}
	
void CDHCPIP4StateMachine::SetMessageHeaderAsServerL( TDHCPv4MessageType aMsgType )
/**
  * SetMessageHeaderAsServerL
  *
  * Fills in the DHCP header information to be sent to the client
  *
  * @internalTechnology
  */
	{
	TTime now;
	TTimeIntervalSeconds secs;
	now.HomeTime();	
	(void)now.SecondsFrom(iTaskStartedAt, secs);

	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	v4Msg->InitialiseL();
	v4Msg->SetSecs(static_cast<TUint16>(secs.Int()));	// time field is 16 bits, time elapsed will be less than 16 bits, hence no data loss
	v4Msg->SetXid(iXid.Xid());
	// set to indicate we are using DHCP server implementation
	v4Msg->iDHCPServerImpl = ETrue; 
	v4Msg->SetCIAddr(iCiaddr);
	// +++++++++++++++++++++ Message Type (1 byte) ++++++++++++++++++++++++++++++++/
	v4Msg->AddOptionL(EDHCPMessageType, 1)->SetBigEndian(aMsgType);
	
	switch(aMsgType)
		{
		case EDHCPOffer:
		case EDHCPAck:
			// ++++++++Subnet mask, Router and Server IP set with server address ++++++++++/			
			v4Msg->AddOptionL(EDHCPSubnetMask,KIp4AddrByteLength)->SetBigEndian(KInetAddrNetMaskC); // 255.255.255.0
			v4Msg->AddOptionL(EDHCPRouter,KIp4AddrByteLength)->SetBigEndian(iCurrentAddress.Address());
			v4Msg->AddOptionL(EDHCPServerID,KIp4AddrByteLength)->SetBigEndian(iCurrentAddress.Address());	
			break;

		case EDHCPNak:
			// ++++++++Server IP set with server address ++++++++++/
			v4Msg->AddOptionL(EDHCPServerID,KIp4AddrByteLength)->SetBigEndian(iCurrentAddress.Address());	
			break;
		}
	
	TUint8 htype,hlen;
	//  fill in something "traditional" so as not to upset a stupid server.
	//  This is a best guess based on lack of specs in this area
	htype = 1; // ethernet
	hlen = 6; // mac address length
	v4Msg->SetCHAddr(iClientHWAddr);

	v4Msg->SetHeader(EDHCPBootReply,  htype /*hardware addr type*/,  hlen /*hardware addr length*/,  0 /*hops*/);
	v4Msg->SetFlags(iFlag);
#ifdef _DEBUG
	if (CDHCPServer::DebugFlags() & KDHCP_RequestIP4BroadcastOffer)
		{
		v4Msg->SetFlags(0x8000); // force broadcast
		}
#endif
	}
			
#endif // SYMBIAN_NETWORKING_DHCPSERVER

void CDHCPIP4StateMachine::PrepareToSendL( CDHCPStateMachine::EAddressType aEAddressType )
/**
  * PrepareToSendL
  *
  * This function is called to set the correct destination address
  * for messages before they are sent.
  *
  * @internalTechnology
  */	
	{
#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
	if (iDhcpInformAckPending)
		{
		DhcpMessage()->FinishL(iClientId,&iSavedExtraParameters);
		}
	else
		{
#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
	// From tb92 and later, including iSavedExtraParameters for FinishL()
	// as SYMBIAN_NETWORKING_DHCP_MSG_HEADERS is expected to be always ON
	DhcpMessage()->FinishL(iClientId,&iSavedExtraParameters);
#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
		}	
#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
	DhcpMessage()->Dump();
	if (aEAddressType==EUnicast)
		{
		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::SetDestination - unicast")));
		iDHCPServerAddr.SetV4MappedAddress(iServerAddress);
		}
	else
		{
		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::SetDestination - broadcast")));
		iDHCPServerAddr.SetV4MappedAddress(KInetAddrBroadcast);	
		}
#ifndef _DEBUG
	iDHCPServerAddr.SetPort(KDhcpDestPort);
#else
	// Simulate initialisation, renewal or rebind failure by using the wrong port.
	if( ( CDHCPServer::DebugFlags() & KDHCP_FailDiscover ) || ( CDHCPServer::DebugFlags() & KDHCP_FailRenew ) || ( CDHCPServer::DebugFlags() & KDHCP_FailRebind ) )
		{
		iDHCPServerAddr.SetPort(KDhcpWrongDestPort);
		}
	else
		{
		iDHCPServerAddr.SetPort(GetDestPort());
		}
#endif
	}


void CDHCPIP4StateMachine::AssembleClientIDsL()
/**
  * Sets the client id - this just has to be a cookie for the server to use for indexing.
  * 
  *   On an addressed link (e.g. ethernet), hardware address type/value pair is a good combo to use
  *      as it mirrors a few other popular implementations..
  */
	{
    FetchHWAddress();

    iClientId.CreateL(KMaxSockAddrSize);
    iClientId.SetLength(1);		// set length to 1 byte

	if(iHardwareAddr.Family()!=KAFUnspec)
		{
		// we're on a link with hardware addressing e.g. ethernet
		__CFLOG_VAR((KLogSubSysDHCP, KLogCode,
						_L8("CDHCPIP4StateMachine::AssembleClientIDsL - hardware address type=%d, length=%d"),
						iHardwareAddr.Port(), iHardwareAddr.Length() - KHwAddrOffset));

		iClientId[0] = static_cast<TUint8>(iHardwareAddr.Port());	// fill in the hwAddrType
	    iClientId.Append(iHardwareAddr.Mid(KHwAddrOffset, iHardwareAddr.Length() - KHwAddrOffset));
		}
	else // family was unspecified meaning no hardware address
    	{
    	// 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("CDHCPIP4StateMachine::AssembleClientIDsL - no hardware address (suggesting point-to-point)"
						     " so generating a random 4 byte client id")));
		iClientId[0] = static_cast<TUint8>(1);	// force hwAddrType to look like ethernet
    	TUint32 data = Math::Random();
		iClientId.Append(TPckgC<TUint32>(data));
		iClientId.Append(TPckgC<TUint16>(data));
    	}
	}


void CDHCPIP4StateMachine::GetServerAddress( TInetAddr& aAddress )
{
	aAddress = iDHCPServerAddr;
}


void CDHCPIP4StateMachine::SetCurrentAddress(const TInetAddr& aCurrentAddress, const TInetAddr& aSubnetMask)
/**
  * The SetCurrentAddress function
  *
  * Stores ip address and subnet mask and assembles the broadcast address
  *
  * @internalTechnology
  */
	{
	iCurrentAddress = aCurrentAddress;
	iSubnetMask = aSubnetMask;
	TInetAddr broadcast;
	broadcast.SubNetBroadcast(iCurrentAddress, iSubnetMask);
	iBroadcastAddress = broadcast.Address();
	}

void CDHCPIP4StateMachine::SetMessageHeaderL( TDHCPv4MessageType aMsgType )
/**
  * Puts a standard header into the message
  *
  * @internalTechnology
  */
	{
	TTime now;
	TTimeIntervalSeconds secs;
	now.HomeTime();	
	(void)now.SecondsFrom(iTaskStartedAt, secs);

	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	v4Msg->InitialiseL();
	v4Msg->SetSecs(static_cast<TUint16>(secs.Int()));	// time field is 16 bits, time elapsed will be less than 16 bits, hence no data loss
	v4Msg->SetXid(iXid.Xid());

	TUint8 htype,hlen;
	if(iHardwareAddr.Family()!=KAFUnspec)
		{
		// we have link layer addressing so fill in the blanks..
		htype = static_cast<TUint8>(iHardwareAddr.Port()); // hwAddr type (hidden in port field)...there won't be any loss of data
		hlen = static_cast<TUint8>(iHardwareAddr.Length()-KHwAddrOffset); // length won't be too long that we lose data. Data starts 8 bytes in, thats why length is minus an offset(8)
		v4Msg->SetCHAddr(iHardwareAddr);
		}
	else
		{
		// We have no link layer addressing so fill in something "traditional" so as not to upset a stupid server.
		//  This is a best guess based on lack of specs in this area
		htype = 1; // ethernet
		hlen = 6; // mac address length
		}

	v4Msg->SetHeader(EDHCPBootRequest,  htype /*hardware addr type*/,  hlen /*hardware addr length*/,  0 /*hops*/);
	v4Msg->SetFlags(0x0000);
#ifdef _DEBUG
	if (CDHCPServer::DebugFlags() & KDHCP_RequestIP4BroadcastOffer)
		{
		v4Msg->SetFlags(0x8000); // force broadcast
		}
#endif
	// +++++++++++++++++++++ Message Type (1 byte) ++++++++++++++++++++++++++++++++/
	v4Msg->AddOptionL(EDHCPMessageType, 1)->SetBigEndian(aMsgType);
	}




TUint8 CDHCPIP4StateMachine::GetMessageTypeL() const
/**
  * Returns the message type from the DHCP message
  * i.e. whether the message is an offer, ack, nak...
  *
  * @internalTechnology 
  */
	{
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	v4Msg->ParseL();
	v4Msg->Dump();	
	
	return v4Msg->iOptions.GetMessageType();
	}

TBool CDHCPIP4StateMachine::CheckXid() const
/**
  * Checks xid of incoming packet against that of last message sent
  * must be called after GetMessageType so that message has been parsed!
  *
  * @internalTechnology
  */
	{
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	// check the Xid matches the xid we put in the discover
	if (v4Msg->GetXid()!=iXid.Xid())
		{
		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::GetMessageTypeL - non-matching xid")));
		return EFalse;	// does not match so we are not interested in this message
		}
	return ETrue;
	}

void CDHCPIP4StateMachine::CreateDiscoverMsgL()
/**
  * Puts the specifics of the discover message into
  * the message buffer
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateDiscoverMsgL")));
	
	if(iTaskStartedAt == 0)
		{
		// set time stamp to now
		iTaskStartedAt.HomeTime();
		iMessageSender->SetTaskStartedTime(iTaskStartedAt);
		}
	iXid.SetXid(static_cast<TUint32>(iXid.Rnd(0,KMaxTInt)));
	SetMessageHeaderL(EDHCPDiscover);

	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	
	// +++++++++++++++++++++ requested IP address +++++++++++++++++++++++++++++++++/
	TInetAddr unspAddr;  //creates unspecified address
	// now check to see if a previous address exists in CommDB with an existing lease
	if (!iCurrentAddress.Match(unspAddr))
		{
		// if we have a known address (perhaps from an expired lease) then request it
		// an address is 4 bytes long
		v4Msg->AddOptionL(EDHCPRequestedIPAddr, KIp4AddrByteLength)->SetBigEndian(iCurrentAddress.Address());
		}
	// XXX: Add hostname to discover (maybe request), update device hostname
	// if offered value differs - repeat for IPv6
	
	// +++++++++++++++++++++ FQDN update request ++++++++++++++++++++++++++++++++++/
	CreateFqdnUpdateRequestL();
	}

void CDHCPIP4StateMachine::CreateOfferAcceptanceRequestMsgL()
/**
  * Puts the specifics of the offer acceptance request
  * message into the message buffer
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateOfferAcceptanceRequestMsgL")));
	
	SetMessageHeaderL(EDHCPRequest);
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	
	// +++++++++++++++++++++ requested IP address +++++++++++++++++++++++++++++++++/
	v4Msg->AddOptionL(EDHCPRequestedIPAddr, KIp4AddrByteLength)->SetBigEndian(iCurrentAddress.Address());
	
	// +++++++++++++++++++++ server ID ++++++++++++++++++++++++++++++++++++++++++++/
	v4Msg->AddOptionL(EDHCPServerID, KIp4AddrByteLength)->SetBigEndian(iDHCPServerID.Address());
	
	// +++++++++++++++++++++ FQDN update request ++++++++++++++++++++++++++++++++++/
	CreateFqdnUpdateRequestL();	
	}


void CDHCPIP4StateMachine::CreateRebootRequestMsgL()
/**
  * Puts the specifics of a reboot request message
  * into the message buffer 
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateRebootRequestMsgL")));
	
	iTaskStartedAt.HomeTime();	// set time stamp to now
	iMessageSender->SetTaskStartedTime(iTaskStartedAt);
	iXid.SetXid(static_cast<TUint32>(iXid.Rnd(0,KMaxTInt)));
	SetMessageHeaderL(EDHCPRequest);

	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	
	// +++++++++++++++++++++ requested IP address +++++++++++++++++++++++++++++++++/
	v4Msg->AddOptionL(EDHCPRequestedIPAddr, KIp4AddrByteLength)->SetBigEndian(iCurrentAddress.Address());
	}


void CDHCPIP4StateMachine::CreateInformMsgL()
/**
  * Puts the specifics of an inform message
  * into the message buffer
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateInformMsgL")));
	 
	iXid.SetXid(static_cast<TUint32>(iXid.Rnd(0,KMaxTInt)));
	iTaskStartedAt.HomeTime();	// set time stamp to now
	SetMessageHeaderL(EDHCPInform);

	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	v4Msg->SetCIAddr(iCurrentAddress.Address());
	//v4Msg->SetFlags(0);		// indicates that the response should be unicast back
	
	}

void CDHCPIP4StateMachine::CreateRenewRequestMsgL()
/**
  * Puts the specifics of the renew message
  * into the mesage buffer
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateRenewRequestMsgL")));
	
	 if(iTaskStartedAt != 0)
		{
		iTaskStartedAt.HomeTime();
		iMessageSender->SetTaskStartedTime(iTaskStartedAt);
		}
	SetMessageHeaderL(EDHCPRequest);

	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	v4Msg->SetCIAddr(iCurrentAddress.Address());
	v4Msg->SetFlags(0);		// indicates that the response should be unicast back
	}	

void CDHCPIP4StateMachine::CreateRebindRequestMsgL()
/**
  * Puts the specifics of the rebind message
  * into the mesage buffer which happened to be the same as the renew message
  *
  * @internalTechnology
  */
   {
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateRebindRequestMsgL")));
   CDHCPIP4StateMachine::CreateRenewRequestMsgL(); //to avoid virtual call generation
   }

void CDHCPIP4StateMachine::CreateReleaseMsgL()
/**
  * Puts the specifics of the release message
  * into the message buffer
  * 
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateReleaseMsgL")));

	SetMessageHeaderL(EDHCPReleaseMsg);
	
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	v4Msg->SetCIAddr(iCurrentAddress.Address());
	v4Msg->SetFlags(0);		// probably don't need to set...as there is no respsonse...
	
	// +++++++++++++++++++++ server ID ++++++++++++++++++++++++++++++++++++++++++++/
	v4Msg->AddOptionL(EDHCPServerID, KIp4AddrByteLength)->SetBigEndian(iDHCPServerID.Address());
	//remove the configured address ater Completion of the Release Message
	}

void CDHCPIP4StateMachine::CreateDeclineMsgL()
/**
  * Puts the specifics of the decline message
  * into the message buffer
  *
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateDeclineMsgL")));
	
	SetMessageHeaderL(EDHCPDecline);

	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	
	// +++++++++++++++++++++ server ID ++++++++++++++++++++++++++++++++++++++++++++/
	v4Msg->AddOptionL(EDHCPServerID, KIp4AddrByteLength)->SetBigEndian(iDHCPServerID.Address());
	
	// +++++++++++++++++++++ requested IP address +++++++++++++++++++++++++++++++++/
	v4Msg->AddOptionL(EDHCPRequestedIPAddr, KIp4AddrByteLength)->SetBigEndian(iCurrentAddress.Address());
	RemoveConfiguredAddress();
	iRetryDhcpIpCount++;
	}

#ifdef SYMBIAN_NETWORKING_DHCPSERVER
void CDHCPIP4StateMachine::CreateOfferMsgL()
/**
  *  CreateOfferMsgL
  *
  * Puts the specifics of the Offer message into the message buffer
  * 
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateOfferMsgL")));

	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	iXid.SetXid(v4Msg->GetXid());
	iTaskStartedAt.HomeTime();
	// remember the client hardware address from message for later use
	v4Msg->GetCHAddr(iClientHWAddr);
	
	// check if the broadcast flag is set for this client then we sent broadcast message to it
	TUint16 flags  = v4Msg->GetFlags();
	if(flags & KBroadCastFlagMask)
		iBroadCastFlag = ETrue;

	// Create DHCPOFFER message
	iFlag = 0x8000;			
	SetMessageHeaderAsServerL(EDHCPOffer);	
	
	// generate the client IP addres that is to be offered to the client
	TUint32 offeredAddress = GenerateClientIPAddress();
	
	if(iSvrState == ESvrWaitForAnyDHCPMsgs)
		{
		if(iInformClientAddr.Address())
			v4Msg->SetYIAddr(iInformClientAddr.Address());
		else
			v4Msg->SetYIAddr(offeredAddress);
		}
	else
		{
		v4Msg->SetYIAddr(offeredAddress);
		}	
	SetClientIdentified(EFalse);	
	AddMessageOptionsL();
	}

void CDHCPIP4StateMachine::HandleInformMsgL()
/**
  *  HandleInformMsgL
  *
  * Handles DHCPInform message and sends DHCPAck
  * 
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateResponseMsgL")));
	
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	
	iXid.SetXid(v4Msg->GetXid());
	iTaskStartedAt.HomeTime();
	
	v4Msg->GetCHAddr(iClientHWAddr);
	
	iCiaddr = v4Msg->GetCIAddr();
	iYiaddr = v4Msg->GetYIAddr();
	iFlag = 0x0000;	
	
	SetMessageHeaderAsServerL(EDHCPAck);	
	iYiaddr = iCiaddr;
	}

void CDHCPIP4StateMachine::CheckClientParamListL()
	{
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	// check for the Parameter request list option code
	DHCPv4::COptionNode* pOption = v4Msg->iOptions.FindOption(EDHCPParameterReqList);
	
	if(pOption)
		{
		TUint8* headerPtr = pOption->Ptr();	
		
		// const TUint8 KParamReqTypeOffset = 0; never used
		const TUint8 KParamReqLengthOffset = 1;
				
		//  TUint encoding = headerPtr[KParamReqTypeOffset];   never used
		TUint length = headerPtr[KParamReqLengthOffset]; // n octets
	
		TUint8* bodyPtr = pOption->GetBodyPtr();
		
		TUint paramReqAddrOffset;
		TUint8 paramReqValue;
		
		for(TInt i=1; i <= length; i++)
			{
			// read the requested parameter list 
			paramReqAddrOffset = 1 * i;	
			Mem::Copy(&paramReqValue,(bodyPtr + paramReqAddrOffset),1);  
			
			AddParamRequestOptionL(paramReqValue);
			}
		}
	}

void CDHCPIP4StateMachine::AddParamRequestOptionL(TUint8 aParamReqValue)
	{
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	// default values determined to be used widely are provided by the DHCP server
	// for these requested parameters
	
	// few of the widely requested options are provided, remainning options are ignored
	switch(aParamReqValue)	
		{
	case EDHCPRouter:
		v4Msg->AddOptionL(EDHCPRouter, KIp4AddrByteLength)->SetBigEndian(iCurrentAddress.Address());	
		break;
	case EDHCPBroadcastAddr:
		v4Msg->AddOptionL(EDHCPBroadcastAddr, KIp4AddrByteLength)->SetBigEndian(KInetAddrBroadcast);	
		break;	
	case EDHCPServerID:
		v4Msg->AddOptionL(EDHCPServerID,KIp4AddrByteLength)->SetBigEndian(iCurrentAddress.Address());	
		break;
	case EDHCPSubnetMask:
		v4Msg->AddOptionL(EDHCPSubnetMask,KIp4AddrByteLength)->SetBigEndian(KInetAddrNetMaskC); 
		break;	
	case EDHCPEnd:
		v4Msg->AddOptionL(EDHCPEnd, 0);
		break;
		}
	}

void CDHCPIP4StateMachine::HandleRequestMsgL()
/**
  * CreateRequestResponseMsgL
  *
  * Creates DHCPACK or DHCPNAK in response to DHCPREQUEST (Renew, Rebind and Init-Reboot)
  * 
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::CreateRequestResponseMsgL")));
	
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	
	iXid.SetXid(v4Msg->GetXid());
	iTaskStartedAt.HomeTime();
	
	v4Msg->GetCHAddr(iClientHWAddr);

	iCiaddr = v4Msg->GetCIAddr();
	
	// check if the broadcast flag is set for this client then we sent broadcast message to it
	TUint16 flags  = v4Msg->GetFlags();
	if(flags & KBroadCastFlagMask)
		iBroadCastFlag = ETrue;
	 
	TUint32 offeredAddress = GetIPAddressToOffer();
		
	// Check the requested parameter list from client and provide them
	CheckClientParamListL();
	
	TInetAddr reqIPAddress ;
	reqIPAddress.SetAddress(v4Msg->iOptions.GetRequestedIPAddress());
				
	//Check if the message contains the Requested IPAddress 
	if(reqIPAddress.Address())
		{
		//Compare the requested IP Address with the generated offered IP Address.
		// If same as the offered IP Address,then send DHCPACK
		if(reqIPAddress.Address() == offeredAddress)
			{
			iFlag = 0x8000;			
			SetMessageHeaderAsServerL(EDHCPAck);
			iYiaddr = offeredAddress;
			v4Msg->SetYIAddr(iYiaddr);
			AddMessageOptionsL();
			}
		else
			{
			// cannot provide requested IP address
			iFlag = 0x8000;
			SetMessageHeaderAsServerL(EDHCPNak);
			}
		}
	else				
		{
		// No Requested IP address when DHCPRequest is received during
		// Renewal and Rebind of IPAddress
		iFlag = 0x0000;
		SetMessageHeaderAsServerL(EDHCPAck);
		iYiaddr = iCiaddr;
		v4Msg->SetYIAddr(iYiaddr);
		AddMessageOptionsL();
	   	}
	}

TUint32 CDHCPIP4StateMachine::GetIPAddressToOffer()
	{
	TUint32 offeredAddress;
	// check if we ever offered any client which was statically configured
	// and we responded to DHCPINFORM from it
	// We offer the same IP address to any second client so that if the first client
	// existed then the second client fails with DAD
	if(iSvrState == ESvrWaitForAnyDHCPMsgs)
		{
		if(iInformClientAddr.Address())
			offeredAddress = iInformClientAddr.Address();
		else 
			offeredAddress = GenerateClientIPAddress();
		}
	else
		{
		// Generate a valid IP address which can be offered to the client 
		offeredAddress = GenerateClientIPAddress();
		}
#ifdef SYMBIAN_DNS_PROXY	
	iOfferedAddress = offeredAddress;
#endif
	return offeredAddress;	
	}

void CDHCPIP4StateMachine::AddMessageOptionsL()
/**
  * AddMessageOptionsL
  *
  * Adds Lease Time,Renew Time and Rebind Time options
  * 
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::AddMessageOptionsL")));
	
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();

// Providing support for handling custom lease time being set for DHCP server
// in DEBUG builds using RProperty API's
	TInt defLeaseTime;
#ifdef _DEBUG
	RProperty::Get(KMyPropertyCat, KMyDefaultLeaseTime, defLeaseTime);
#else
	defLeaseTime = KDefaultLeaseTime;
#endif
	// +++++++++++++++++ Default Fixed Lease Time - 6 hours ++++++++++++++++++++++++++++++++++++++++/
	v4Msg->AddOptionL(EDHCPLeaseTime, KIp4AddrByteLength)->SetBigEndian(defLeaseTime);
	// +++++++++++++++++ Renewal Time (T1) - 50% of Lease time ++++++++++++++++++++++++++++++++++++++++/				
	v4Msg->AddOptionL(EDHCPRenewalT1,KIp4AddrByteLength)->SetBigEndian(defLeaseTime/2);
	// +++++++++++++++++ Rebind Time (T2) - 75% of Lease time ++++++++++++++++++++++++++++++++++++++++/				
	v4Msg->AddOptionL(EDHCPRebindT2,KIp4AddrByteLength)->SetBigEndian(defLeaseTime/2+defLeaseTime/4);
	// These are the options which the client might ask later
	// Simplified DHCP server is not capable of generating values for these option codes
	// They will be set later using Ioctl() call
	v4Msg->AddOptionL(EDHCPNameServer,KIp4AddrByteLength);		
	v4Msg->AddOptionL(EDHCPSIPServers,KIp4AddrByteLength);		
		
	if(!iDNSInformation)
		{
		v4Msg->AddOptionL(EDHCPDomainNameServer,KIp4AddrByteLength);
		
#ifdef SYMBIAN_DNS_PROXY
		if(iProxyDnsSrvAddr.Address())		
		   v4Msg->AddOptionL(EDHCPDomainNameServer,KIp4AddrByteLength)->SetBigEndian(iProxyDnsSrvAddr.Address());
		if(iProxyDomainName.Length())
		   v4Msg->AddOptionL(EDHCPDomainName, iProxyDomainName.Length())->GetBodyDes().Copy(iProxyDomainName);
#endif
		}
	else
		{
		// point to the option code value in the raw option buffer
		TPtr8 dnsPtr(const_cast<TUint8*>(iDNSInformation->Ptr()), iDNSInformation->Length(), iDNSInformation->Length());
		dnsPtr.Set((TUint8*)(dnsPtr.Ptr()+1),dnsPtr.Length()-1,dnsPtr.MaxLength()-1);
	
		v4Msg->AddOptionL(EDHCPDomainNameServer,dnsPtr.Length())->GetBodyDes().Copy(dnsPtr);
		}
	}

#endif // SYMBIAN_NETWORKING_DHCPSERVER
	
TInt CDHCPIP4StateMachine::CreateIPv4LinkLocal()
/**
  * Notifies the TCP/IP6 stack whenever the assignment process fails
  * so that a link local may be created.
  * 
  *
  * @internalTechnology
  */
	{
	__CFLOG( KLogSubSysDHCP, KLogCode, _L8( "CDHCPIP4StateMachine::CreateIPv4LinkLocal" ) );

	iSocket.Close();	
	
	TInt err = iSocket.Open(iEsock, KAfInet, KSockDatagram, KProtocolInetUdp, iConnection);
	
	if( err == KErrNone )
		{
		// make socket invisible for interface counting
		(void)iSocket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0);

		TPckgBuf<TSoInet6InterfaceInfo> configInfo;

		configInfo().iHwAddr = iHardwareAddr;
		configInfo().iName = iInterfaceName;
		configInfo().iDelete = EFalse;
		configInfo().iAlias = EFalse;
		configInfo().iDoId = EFalse;
		configInfo().iState = EIfUp;
		configInfo().iDoState = ETrue;
		
		// zero value better than junk value
		configInfo().iMtu = 0;
		configInfo().iSpeedMetric = 0;
		configInfo().iFeatures = 0; 

		err = iSocket.SetOpt( KSoInetCreateIPv4LLOnInterface, KSolInetIfCtrl, configInfo );
		}
		
	return err;
	}

void CDHCPIP4StateMachine::HandleOfferL()
/**
  * Handles an offer from a dhcp server, providing
  * an offer of configuration parameters
  *
  * @internalTechnology
  *
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::HandleOffer")));
	
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	// at this stage just the offered ip address is set into the current address for efficiency
	iCurrentAddress.SetAddress(v4Msg->GetYIAddr());	
	
	TUint32 addr = v4Msg->iOptions.GetServerId();
	if ( !addr )
		User::Leave(KErrNotFound);
	iDHCPServerID.SetAddress(addr);
	}

CDHCPState* CDHCPIP4StateMachine::HandleReplyL( TRequestStatus* aStatus )
{
	iReceiving = EFalse;
	
	TInt err = KErrNone;

	if (CheckXid())
		{
		switch (GetMessageTypeL())
			{
			case EDHCPAck:
#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS 	
				if (!iDhcpInformAckPending)
				{
#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS	
				HandleAckL();
#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS 					
				}
#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS	

				break;
			case EDHCPNak:
				err = KErrAccessDenied;

				break;
			default:
				return ReceiveL(aStatus);
			}
		}
	else
		{
		return ReceiveL(aStatus);
		}
		
	User::RequestComplete(aStatus, err);
	
	if( err == KErrNone )
	{
		return static_cast<CDHCPState*>(iActiveEvent->Next());
	}
	
	return NULL;
}

void CDHCPIP4StateMachine::HandleAckL()
/**
  * Handles an acknowledgement from a dhcp server, storing
  * configuration parameters and a committed ip address
  *
  * @internalTechnology
  *
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::HandleAck")));
	
	if(iRetryDhcpIpCount >= KDHCPv4MaxRetryCount)
 	{
	TPckgBuf<TSoInetInterfaceInfo> opt;
	TInetAddr addr;
	while (iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, opt) == KErrNone)
		{
	  	if (opt().iName == InterfaceName())
			{
		  	addr = opt().iAddress;
		  	if (addr.IsLinkLocal() && addr.IsV4Compat() )
		  		{
		  		RemoveConfiguredAddress(&addr);
		  		break;
		  		}
		  	}
		}
	}
	ConfigureInterfaceL();

	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	if (!IsUsingStaticAddress())
		{
		iRenewalTimeT1 = v4Msg->iOptions.GetRenewalTime();
		iRebindTimeT2 = v4Msg->iOptions.GetRebindTime();
		iLeaseTime = v4Msg->iOptions.GetLeaseTime();
		
		#ifdef _LOG
			TBuf<39> addrStr;
			
			TInetAddr( v4Msg->GetYIAddr(), 0 ).Output( addrStr );
			
			__CFLOG_1( KLogSubSysDHCP, KLogCode, _L( "DHCP server assigned client IP address %S" ), &addrStr );
		#endif
		
#ifdef _DEBUG
		if (CDHCPServer::DebugFlags() & KDHCP_SetShortLease)
			{
			iLeaseTime = KDHCP_ShortLeaseLeaseTime;
			iRenewalTimeT1 = KDHCP_ShortLeaseRenewTime;
			iRebindTimeT2 = KDHCP_ShortLeaseRebindTime;
			CDHCPServer::DebugFlags() &= ~( KDHCP_SetShortLease | KDHCP_SetShortRetryTimeOut );	// we only want this to have an affect the first time...
			}
#endif
		// -- Infinite leases -- INC078424 --
		//
		// 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)
			{
			// 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
			
			__CFLOG_VAR((KLogSubSysDHCP, KLogCode,
				_L8("Invalid Renew/Rebind times received: (RenewT1: %d, RebindT2: %d, Lease: %d)"),
						iRenewalTimeT1, iRebindTimeT2, iLeaseTime));
						
			TUint32 temp = iLeaseTime/4;
			iRenewalTimeT1=iLeaseTime/2;
			iRebindTimeT2=iRenewalTimeT1+temp;		
			
			__CFLOG_VAR((KLogSubSysDHCP, KLogCode,
				_L8("New Renew/Rebind Time calculated: (RenewT1: %d, RebindT2: %d)"),
						iRenewalTimeT1, iRebindTimeT2));	
						
			}
		else if (iRenewalTimeT1<iRebindTimeT2 && iRebindTimeT2<iLeaseTime)
			{
			// do nothing as we have got the valid values we were expecting
			__CFLOG_VAR((KLogSubSysDHCP, KLogCode,
				_L8("Times received from server: (RenewT1: %d, RebindT2: %d, lease: %d)"),
						iRenewalTimeT1, iRebindTimeT2, iLeaseTime));
			}
		else
			{
			__CFLOG_VAR((KLogSubSysDHCP, KLogCode,
					_L8("HandleAckL Error: invalid times received from server (RenewT1: %d, RebindT2: %d, lease: %d)"),
							iRenewalTimeT1, iRebindTimeT2, iLeaseTime));
			User::Leave(KErrArgument);
			}	
		
		}

	delete iHostName;
	delete iDomainName;
	iHostName = NULL;
	iDomainName = NULL;

	v4Msg->iOptions.CopyHostNameL(iHostName);
	v4Msg->iOptions.CopyDomainNameL(iDomainName);
	}

#ifdef _DEBUG
TInt CDHCPIP4StateMachine::GetDestPort()
	{
	TInt destPort;
	User::LeaveIfError(RProperty::Get(KMyPropertyCat, KMyPropertyDestPortv4, destPort));
	return destPort;
	}
#endif

void CDHCPIP4StateMachine::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("CDHCPIP4StateMachine::InitialiseSocketL")));
	
	iSocket.Close();
	
	User::LeaveIfError(iSocket.Open(iEsock, KAfInet, KSockDatagram, KProtocolInetUdp, iConnection));
	User::LeaveIfError(iSocket.SetOpt(KSoReuseAddr, KSolInetIp, 1));
#ifndef _DEBUG
	User::LeaveIfError(iSocket.SetLocalPort(KDhcpSrcPort));
#else
	User::LeaveIfError(iSocket.SetLocalPort(GetDestPort() + 1));
#endif
    TInetAddr existingGlobalAddr = this->GetInterfaceGlobalAddress();
    if( existingGlobalAddr.IsUnspecified() || existingGlobalAddr.IsLinkLocal() )
    	{
    	User::LeaveIfError(iSocket.SetOpt(KSoNoSourceAddressSelect, KSolInetIp, 1));
    	}
	// make socket invisible for interface counting
	User::LeaveIfError(iSocket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0));
	
	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));
	// loopback of broadcast/multicast packets to the stack is disabled
	User::LeaveIfError(iSocket.SetOpt(KSoIp6MulticastLoop, KSolInetIp, 0));
	}

void CDHCPIP4StateMachine::RemoveConfiguredAddress(const TInetAddr * aAddr)
/**
  * 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("CDHCPIP4StateMachine::RemoveConfiguredAddress")));
	
	TSoInet6InterfaceInfo interfaceInfo;
	interfaceInfo.iHwAddr = iHardwareAddr;
	if(aAddr)
		{
		interfaceInfo.iAddress.SetV4MappedAddress(aAddr->Address());
		interfaceInfo.iState = EIfDown;
		}
	else
		{
		interfaceInfo.iAddress.SetV4MappedAddress(iCurrentAddress.Address());
		interfaceInfo.iState = EIfUp;	
		}
	interfaceInfo.iDefGate.SetV4MappedAddress(iDefGateway.Address());
	interfaceInfo.iName = iInterfaceName;
	interfaceInfo.iDelete = ETrue;
	interfaceInfo.iAlias = EFalse;
	interfaceInfo.iDoId = ETrue;
	
	interfaceInfo.iDoState = ETrue;
	interfaceInfo.iDoAnycast = EFalse;
	
	// zero value better than junk value
	interfaceInfo.iMtu = 0;
	interfaceInfo.iSpeedMetric = 0;
	interfaceInfo.iFeatures = 0; 
    CDHCPStateMachine::RemoveConfiguredAddress( interfaceInfo );
    
	// Clear the DHCP server address now that we no longer have a lease.
    iDHCPServerAddr.SetAddress( KInet6AddrNone );
    //clear the client address & lease time
   	iCurrentAddress = TInetAddr();
   	iLeaseTime = 0;

	}

void CDHCPIP4StateMachine::AssignAddresses( TInetAddr& aDest, const TInetAddr& aSrc ) const
{
	aDest.SetFamily(KAfInet);
	aDest.SetAddress(aSrc.Address());
#ifdef SYMBIAN_NETWORKING_DHCPSERVER
	if(iServerImpl)
		{
// The DHCP server can listen on custom ports
// Supported only on DEBUG builds
#ifdef _DEBUG
		aDest.SetPort(GetDestPort());
#else
		aDest.SetPort(KDhcpServerPort);
#endif
		}
	else
#endif // SYMBIAN_NETWORKING_DHCPSERVER	
#ifndef _DEBUG
	aDest.SetPort(KDhcpSrcPort);
#else
	{
	// 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(KDhcpWrongSrcPort);
		}
	else
		{
		aDest.SetPort(GetDestPort() + 1);
		}
	}
#endif
	
}

void CDHCPIP4StateMachine::BindSocketForUnicastL()
/**
  * Open a new socket and bind it to the configured source address
  * ready for a unicast renew message
  *
  * @internalTechnology
  */
	{
    __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::BindSocketForRenewL")));
    iSocket.Close();	// destroy the old socket

    UpdateHistory(CDHCPState::EBindToSource);
    // Start a new one.
    User::LeaveIfError(iSocket.Open(iEsock, KAfInet, KSockDatagram, KProtocolInetUdp, iConnection));
	User::LeaveIfError(iSocket.SetOpt(KSoReuseAddr, KSolInetIp, 1));
    TInetAddr bindTo;
    AssignAddresses( bindTo, iCurrentAddress );

    User::LeaveIfError(iSocket.Bind(bindTo));

	// So we can still receive packets from naughty servers who send broadcasts back to 
	//  unicast requests, we do this:
	User::LeaveIfError(iSocket.SetOpt(KSoNoSourceAddressSelect, KSolInetIp, 1));
	User::LeaveIfError(iSocket.SetOpt(KSoUdpAddressSet, KSolInetUdp, 0));
	// make socket invisable for interface counting
	User::LeaveIfError(iSocket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0));
	}

void CDHCPIP4StateMachine::ConfigureInterfaceL()
/**
  * Set the interface IP address and other params
  * into the TCP/IP6 stack.
  *
  * 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.
  *
  * @internalTechnology
  */
	{

	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ConfigureInterfaceL - Cancel Message Sender")));
	iMessageSender->Cancel();

	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ConfigureInterfaceL - KSoNoSourceAddressSelect")));
	User::LeaveIfError(iSocket.SetOpt(KSoNoSourceAddressSelect, KSolInetIp, 0));

	// Using the new structure derived from TSoInet6InterfaceInfo
	// to be able to set domain search list for the interface
	TSoInetInterfaceInfoExtnDnsSuffix interfaceInfo;
	
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();


	// Read the optiond data buffer for option 119 and decrypt it
    HBufC8* domainSearchBuf(NULL);
    v4Msg->iOptions.CopyDomainSearchL(domainSearchBuf);
    if (domainSearchBuf)
    	{
		// Perform decryption only if option data has been returned by dhcp server
        SplitDomainSearchBufferL(domainSearchBuf);
        delete domainSearchBuf;
        domainSearchBuf = NULL;
    	}

	if (!IsUsingStaticAddress())
		{
		iCurrentAddress.SetAddress(v4Msg->GetYIAddr());
		iServerAddress = v4Msg->iOptions.GetServerId();
		
		TInetAddr nullAddr;  //creates unspecif. (null) address

		// we want to use CommDb settings if present
		// but those ifs aren't the solution for that as
		// these values will potentially fail for renegotiation
		// for now we should live with this, as there is no time
		// to change it.
		if (iSubnetMask.Match(nullAddr))
			{
			iSubnetMask.SetAddress(v4Msg->iOptions.GetSubnetMask());
			}

		if (iBroadcastAddress.Match(nullAddr))
			{
			iBroadcastAddress.SetV4MappedAddress(v4Msg->iOptions.GetBroadcastAddress());
			}
		
		if (iDefGateway.Match(nullAddr))
			{
			iDefGateway.SetV4MappedAddress(v4Msg->iOptions.GetRouterAddress());
			}		
		}

	if( iNameServerAddressesFromServer )
		{	
		TInt num = v4Msg->iOptions.NumberOfDomainServers();
		if (num>0)
			{
			iNameServer1.SetAddress(v4Msg->iOptions.GetDomainNameServer(0));
			if (num>1)
				{
				iNameServer2.SetAddress(v4Msg->iOptions.GetDomainNameServer(1));
				}
			}
		}

	
	interfaceInfo.iHwAddr = iHardwareAddr;
	interfaceInfo.iAddress.SetV4MappedAddress(iCurrentAddress.Address());
	interfaceInfo.iNetMask.SetAddress(iSubnetMask.Address());
	interfaceInfo.iBrdAddr.SetV4MappedAddress(iBroadcastAddress.Address());
	interfaceInfo.iDefGate.SetV4MappedAddress(iDefGateway.Address());
	if( iNameServerAddressesFromServer )
		{
		interfaceInfo.iNameSer1.SetV4MappedAddress(iNameServer1.Address());
		interfaceInfo.iNameSer2.SetV4MappedAddress(iNameServer2.Address());	
		}
	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;
	
	// Depending on number of domain suffix(es) received from the DHCP server,
	// we have to call CDHCPStateMachine::ConfigureInterfaceL multiple times
	TUint suffixCount = iSuffixList.Count();
	
	if (suffixCount > 0)
	    interfaceInfo.iDomainSuffix.Copy(iSuffixList[0]);

	// If there is no domain suffix available for updating the interface,
	// we end up calling ConfigureInterfaceL once
	CDHCPStateMachine::ConfigureInterfaceL( interfaceInfo );

	// Repeat ConfigureInterface call for each domain suffix returned from the server	
	for (TUint index = 1; index < suffixCount; index++)
	    {
	    interfaceInfo.iDomainSuffix.Copy(iSuffixList[index]);
        CDHCPStateMachine::ConfigureInterfaceL( interfaceInfo );
	    }
	}

void CDHCPIP4StateMachine::CreateFqdnUpdateRequestL()
	{	
#ifndef SYMBIAN_COMMS_REPOSITORY
	CCommsDatabase* commDb = CCommsDatabase::NewL();
	CleanupStack::PushL(commDb);
	
	CCommsDbTableView* tableView = commDb->OpenViewMatchingUintLC(TPtrC16(NETWORK), TPtrC16(COMMDB_ID), GetNetworkIdL());
	
	TDomainName hostName;
	if (tableView->GotoFirstRecord() == KErrNone)
		{
		tableView->ReadTextL(TPtrC16(HOST_NAME), hostName);
		}
#else
#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
	CMDBSession* session = CMDBSession::NewLC(KCDVersion1_2);
#else
	CMDBSession* session = CMDBSession::NewLC(KCDVersion1_1);
#endif

	// Reveal hidden or private IAP records if a licensee has chosen to protect a record
	// using one of these flags - the API to do this is public so internal components
	// have to support the use of such records.
	session->SetAttributeMask(ECDHidden | ECDPrivate);
	
	CCDNetworkRecord* networkRecord = static_cast<CCDNetworkRecord*>(CCDRecordBase::RecordFactoryL(KCDTIdNetworkRecord));;
	CleanupStack::PushL(networkRecord);
	networkRecord->SetRecordId(GetNetworkIdL());
  	networkRecord->LoadL(*session);

	TDomainName hostName;
	hostName.Copy(networkRecord->iHostName);
#endif
		
	if (hostName.Length() > 0)
		{
		CDnsUpdateOption* dnsUpdateOption = new(ELeave) CDnsUpdateOption();
		CleanupStack::PushL(dnsUpdateOption);
		
		dnsUpdateOption->SetFlag(CDnsUpdateOption::EDnsUpdateFlagE);
		dnsUpdateOption->SetFlag(CDnsUpdateOption::EDnsUpdateFlagS);
		dnsUpdateOption->SetDomainName(hostName);
		
		RBuf8 optionData;
		optionData.CleanupClosePushL();
		
		dnsUpdateOption->ToStringL(optionData);
		
		CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
		COptionNode* optionNode = 
			v4Msg->AddOptionL(EDHCPDNSUpdate, optionData.Length());
		
		optionNode->SetBody(optionData);
		
		CleanupStack::PopAndDestroy(&optionData);
		CleanupStack::PopAndDestroy(dnsUpdateOption);
		}	
	
#ifndef SYMBIAN_COMMS_REPOSITORY
	CleanupStack::PopAndDestroy(2, commDb);
#else
	CleanupStack::PopAndDestroy(2, session);
#endif
	}
	
#ifdef SYMBIAN_NETWORKING_DHCPSERVER	
void CDHCPIP4StateMachine::InitialiseServerSocketL()
/**
  * Sets up socket, by opening one associated with the connection
  * and sets the interface to use for traffic
  *%
  * @internalTechnology
  *
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::InitialiseServerSocket")));
	
	iSvrSocket.Close();
	
	User::LeaveIfError(iSvrSocket.Open(iEsock, KAfInet, KSockDatagram, KProtocolInetUdp, iConnection));
	User::LeaveIfError(iSvrSocket.SetOpt(KSoReuseAddr, KSolInetIp, 1));
	
// The DHCP server can listen on custom ports
// Supported only on DEBUG builds
#ifdef _DEBUG
	User::LeaveIfError(iSvrSocket.SetLocalPort(GetDestPort()));
#else
	User::LeaveIfError(iSvrSocket.SetLocalPort(KDhcpServerPort));
#endif
	}

	
void CDHCPIP4StateMachine::InitServerStateMachineL(MStateMachineNotify* aStateMachineNotify)
/**
  * Reset the lower state machine for DHCP server implementation.
  * Set the state machine to wait for client messages on port 67 and 
  * to handle the messages
  *
  * @internalTechnology
  */
	{
	ASSERT(!iFirstState);
	// after start up wait on port 67 for DHCP client msgs 
	iFirstState = new(ELeave) CDHCPIP4WaitForClientMsgs(*this);
	// handle the client messages
	CDHCPState* handleClientMsg = new(ELeave) CDHCPIP4HandleClientMsgs(*this);
	iFirstState->SetNext( handleClientMsg);
	
	CDHCPStateMachine::Start(aStateMachineNotify);
	}	

void CDHCPIP4StateMachine::InitServerBinding(MStateMachineNotify* aStateMachineNotify)
/**
  * 
  *
  * @internalTechnology
  */
	{
	ASSERT(!iFirstState);
	// binds the server with the static IP address from Comms database
	iFirstState = new(ELeave) CDHCPIP4BindServer(*this);

	CDHCPStateMachine::Start(aStateMachineNotify);
	}	


void CDHCPIP4StateMachine::ProcessDiscoverL()
/** Set the state machine to handle discover message using lower state machine
  * discover-> offer -> request -> ack
  *  
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ProcessDiscoverL()")));
	
	// the active state was to handle the client message - here Discover message
	CDHCPState* handleDiscoverMsg = static_cast<CDHCPState*>(iActiveEvent); 

#ifdef SYMBIAN_DNS_PROXY
	HBufC8*   hostName = HBufC8::NewLC(KMaxName);
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	v4Msg->iOptions.CopyHostNameL(hostName);
	iClientHostName.Copy(hostName->Des());
	CleanupStack::PopAndDestroy(hostName);
#endif // SYMBIAN_DNS_PROXY	
	
	CDHCPState* provideOffer = new(ELeave) CDHCPIP4ProvideOffer(*this);
    handleDiscoverMsg->SetNext( provideOffer );
    			
    CDHCPState* sendRequestResponse = new(ELeave) CDHCPIP4SendRequestResponse(*this);
    provideOffer->SetNext( sendRequestResponse );
    		
    iSvrSpecificState = ESvrDiscoverInProgress;
	}
	
void CDHCPIP4StateMachine::ProcessInformL()
/** Set the state machine to handle inform message using lower state machine
  * inform -> ack
  *  
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ProcessInformL()")));

#ifdef SYMBIAN_DNS_PROXY
	ReadDhcpMsgParamsL();
#endif // SYMBIAN_DNS_PROXY		
	
	CDHCPState* handleInformMsg = static_cast<CDHCPState*>(iActiveEvent); 
				
	CDHCPState* sendInformResponse = new(ELeave) CDHCPIP4SendInformResponse(*this);
	handleInformMsg->SetNext(sendInformResponse);
		    
	iSvrSpecificState = ESvrInformInProgress;
	}
    
void CDHCPIP4StateMachine::ProcessRequestL()
/** Set the state machine to handle Request message using lower state machine
  * Request -> Ack / Nak
  *  
  * @internalTechnology
  */
	{
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ProcessRequestL()")));
		
	CDHCPState* handleRequestMsg = static_cast<CDHCPState*>(iActiveEvent); 

	CDHCPState* sendRequestResponse = new(ELeave) CDHCPIP4SendRequestResponse(*this);
    handleRequestMsg->SetNext(sendRequestResponse);
		    
    iSvrSpecificState = ESvrRenewInProgress;
	}
			

void CDHCPIP4StateMachine::CheckClientMsgL()
	{
	switch(GetClientMessageTypeL())
		{
		case EDHCPDiscover:
			ProcessDiscoverL();
	    	break;
    	
		case EDHCPInform:
			if(iSvrState != ESvrWaitForAnyDHCPMsgs)
				{
				ProcessInformL();
				}
  			break;
  		
		case EDHCPRequest:
			ProcessRequestL();
			break;

		case EDHCPReleaseMsg:
#ifdef SYMBIAN_DNS_PROXY
			ReadDhcpMsgParamsL();
#endif // SYMBIAN_DNS_PROXY
			iSvrSpecificState = ESvrReleaseInProgress;
			break;

    	case EDHCPDecline:
#ifdef SYMBIAN_DNS_PROXY
			ReadDhcpMsgParamsL();
#endif // SYMBIAN_DNS_PROXY
    		iSvrSpecificState = ESvrDeclineInProgress;
			break;
		}
	}
	
#ifdef SYMBIAN_DNS_PROXY
void CDHCPIP4StateMachine::ReadDhcpMsgParamsL()
	{
	HBufC8*   hostName = HBufC8::NewLC(KMaxName);
	CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
	TUint32 staticAddr = v4Msg->GetCIAddr();
	iClientStaticAddr.SetAddress(staticAddr);
	v4Msg->iOptions.CopyHostNameL(hostName);
	iClientHostName.FillZ();
	iClientHostName.Copy(hostName->Des());
	CleanupStack::PopAndDestroy(hostName);
	}
#endif // SYMBIAN_DNS_PROXY
#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
TBool CDHCPIP4StateMachine::ClientHwAddrProvisioned()
	{
/** DHCP server server checks in which mode it has to offer the IP to clients.
  * 1. If no HW address is provisioned, don't provide IP to any client.
  * 2. Provide IP for any client if the DHCP server has already received the MAC as 0xFFFFFFFFFFFF through IOCTL call.
  * 3. Provide IP for only clients whose MAC address is provisioned using the IOCTL call.
  * 4. Reset the HW address list if DHCP server receives HW address as 0x000000000000
  *  
  * @internalTechnology
  * @return - ETrue if the client is eligible to get the IP, otherwise EFalse.
  */
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4StateMachine::ClientHwAddrProvisioned()")));
	if(iDhcpHwAddrManager->IsHwAddressProvisioned())
		{
		if(iDhcpHwAddrManager->IsAnyClientAllowed())
			{
			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("DHCP server assigns IP without MAC provisioning")));
				return ETrue;
			}
		else
			{
			Uint64 clientHwAddress = 0;
			TSockAddr hwAddr;
			CDHCPMessageHeaderIP4* v4Msg = DhcpMessage();
			v4Msg->GetCHAddr(hwAddr);
			TPtrC8 hwAddrPtr(hwAddr.Mid(KHwAddrOffset, KHwAddrLength));
			TInt index = 0;
			TInt length = hwAddrPtr.Length();
			//Convert buffer data to Uint64
			for(; index < length; index++)
				{
				clientHwAddress <<= 8;
				clientHwAddress += hwAddrPtr[index];
				}
			//Check the received MAC address is provisioned. If true provide the DHCP OFFER.
			//Otherwise go back to wait for any DHCP client messages state
			if(iDhcpHwAddrManager->Provisioned(clientHwAddress))
				{
				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Client Harware address provisioned")));
				return ETrue;
				}
			}
		}
	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Client Harware address not provisioned")));
	return EFalse;
	}
#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION

/**
  * @name AppendMultipleExtraOptionsParam
  *			Parses dhcp.ini for extra dhcp options and adds them to
  *  			the dhcp server's parameter request list
  *
  * @internalTechnology
  */
void CDHCPIP4StateMachine::AppendMultipleExtraOptionsParamL()
    {
    TBuf8<KOpCodeOutOfBounds> iniValue;
    User::LeaveIfError(IniRead(KDhcpExtraOptions, iniValue));
    
    TLex8 iniLex(iniValue);
    TChar ch;
    
    while((ch = iniLex.Get()) != 0)
        {
        TUint8 opCode(ch);
        TPtr8 opCodePtr(&opCode,1,1);
        
        if (!iSavedExtraParameters.Length())
            {
            iSavedExtraParameters.CreateL(opCodePtr);
            }
        else
            {
            iSavedExtraParameters.ReAllocL(iSavedExtraParameters.Length()+opCodePtr.Length());
            iSavedExtraParameters.Append(opCodePtr);
            }
        }
    }

/**
  * @name SplitDomainSearchBufferL
  *			Decrypt dhcp server option data response for option code 119
  *			and retrieve the domain search list for configuring the interface
  *
  * @internalTechnology
  */
void CDHCPIP4StateMachine::SplitDomainSearchBufferL(HBufC8* aDomainSearchBuf)
    {
	typedef TBuf8<KMaxDomainSuffixLength> THostName8;
	const TInt KMaxDomainSearchBufferLength = 4096;
	
	// Retrieve the total length of the option data content
    TPtr8 ptr(aDomainSearchBuf->Des());
    TInt totalLength = 0;
    totalLength = aDomainSearchBuf->Length();
    
	// Create a buffer of a length capable 
	// to hold domain search list from the option data
    TLex8 primaryLex;
    RBuf8 suffixList;
    suffixList.CreateL(KMaxDomainSearchBufferLength);
	
	// To overcome specific limitations of TLex
	// Converting all '0's to '@'s in the option data buffer
    TInt offset = 0;
    THostName8 tmpBuf;
    while((offset = ptr.Locate(0)) != KErrNotFound) 
        {
        tmpBuf.Append(ptr.MidTPtr(0, offset));
        tmpBuf.Append('@');
        if (ptr.Length() > (offset +1))
            ptr.Set(ptr.MidTPtr((offset+1)));
        else
            ptr.SetLength(0);
        }
    ptr.Set(tmpBuf.MidTPtr(0));
    primaryLex.Assign(ptr.Ptr());


	// Creating temporary objects for parsing the buffer
    THostName8 domainName;
    domainName.SetLength(0);
    TInt noOfDomainNames = 0;
    TChar ch;

    /* Start of decryption algorithm implementation for the option data buffer
	 * Synopsis 
	 * 		Option data contains domain suffixes seaparated by either a '@' or a two-octet compression pointer i.e. C004 (hex)
	 *		which points to offset 4 in the complete aggregated block of Domain Search Option data
	 *		where another validly encoded domain name can be found to complete the name
	 *		Each sub-domain in a domain name is defined by a digit representing number of characters following this digit
	 */
    for (TInt i=0; i<totalLength; i++)
        {
        ch = primaryLex.Peek();
        if (ch == 64) // if the character is a '@'
            {
			// Marks end of a domain name in the list
			// add the domainName constructed to a array and initialise it for next domain name parsing
			// Inc a counter to keep track of number of domain names retrieved
			// Maintain a continous list of the domain name as well for lookup during use of compression pointer
            suffixList.Append(ch);
            TBuf<KMaxDomainSuffixLength> domainName16;
            domainName16.Copy(domainName);
            iSuffixList.AppendL(domainName16);
            domainName.FillZ();
            domainName.SetLength(0);
            primaryLex.Inc();
            noOfDomainNames++;
            }
        else if (ch < 48) // if the character is a digit
            {
			// Marks '.' completing a sub-domain and defines the length
			// of the next sub-domain in the option data buffer
            if (domainName.Length() != 0)
                {
                suffixList.Append('.');
                domainName.Append('.');
                }
            TInt domainPartLength(ch);
            suffixList.Append(ptr.Mid(i+1,ch));
            domainName.Append(ptr.Mid(i+1,ch));

            TInt inc = (TInt)ch + 1;
            i+=(TInt)ch;
            primaryLex.Inc(inc);
            }
        else if (ch == 192) // if the character is a hex 0xC0
            {
			// Marks start of compression pointer
			// Looks up to the suffixList buffer created earlier that holds
			// the domain names read until now in contigous sequence
			// for extracting the remainder of the sub-domains to complete the domain name
            if (domainName.Length() != 0)
                {
                suffixList.Append('.');
                domainName.Append('.');
                }
            i++;
            primaryLex.Inc();
            ch = primaryLex.Peek();
            TInt refOffset(ch), actOffset=0;
            THostName compressedDomain;
            TPtr8 tmpPtr(suffixList.MidTPtr(0));
            TLex8 tmpLex(tmpPtr);
            TInt ind=0;
            for (; ind < tmpPtr.Length() && actOffset < refOffset; ind++)
                {
                TChar ch1 = tmpLex.Peek();
                if (ch1 != 46 && ch1 != 64)
                    actOffset++;
                tmpLex.Inc();
                }
            tmpPtr.Set(tmpPtr.MidTPtr(ind-1));
            tmpPtr.Set(tmpPtr.MidTPtr(0,tmpPtr.Locate('@')));
            suffixList.Append(tmpPtr);
            domainName.Append(tmpPtr);
            suffixList.Append('@');
            TBuf<KMaxDomainSuffixLength> domainName16;
            domainName16.Copy(domainName);
            iSuffixList.AppendL(domainName16);
            domainName.FillZ();
            domainName.SetLength(0);
            primaryLex.Inc();
            noOfDomainNames++;
            }
        else
        	{
			// Marks completion of the option data buffer
			// Free up memory allocated on the heap
	        suffixList.Close();
            return;
        	}
        }
	// End of decryption algorithm implementation for the option data buffer
    }

#endif // SYMBIAN_NETWORKING_DHCPSERVER