diff -r 000000000000 -r af10295192d8 tcpiputils/dhcp/src/DHCPIP4StateMachine.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tcpiputils/dhcp/src/DHCPIP4StateMachine.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,1878 @@ +// 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 +#include +#include "DHCPIP4States.h" +#include "DHCPServer.h" +#ifndef SYMBIAN_COMMS_REPOSITORY +#include +#else +#include +#include +#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"))); + + 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(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(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(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 + DhcpMessage()->FinishL(iClientId); +#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(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(1); // force hwAddrType to look like ethernet + TUint32 data = Math::Random(); + iClientId.Append(TPckgC(data)); + iClientId.Append(TPckgC(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(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(iHardwareAddr.Port()); // hwAddr type (hidden in port field)...there won't be any loss of data + hlen = static_cast(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(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(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(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(¶mReqValue,(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(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 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(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 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 (iRenewalTimeT1iOptions.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 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)); + + TSoInet6InterfaceInfo interfaceInfo; + + CDHCPMessageHeaderIP4* v4Msg = DhcpMessage(); + + 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; + + 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(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(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(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(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 +#endif // SYMBIAN_NETWORKING_DHCPSERVER