--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dhcp/src/DHCPIP4Control.cpp Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,891 @@
+// Copyright (c) 2003-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 control plain
+//
+//
+
+/**
+ @file DHCPIP4Control.cpp
+ @internalTechnology
+*/
+
+#include "DHCPIP4Control.h"
+#include "DHCPIP4States.h"
+#include "DHCPIP4Msg.h"
+#include "DHCPServer.h"
+#include "DHCPConfigListener.h"
+#include "DHCPDb.h"
+#include "ExpireTimer.h"
+#include "NetCfgExtDhcpControl.h"
+#include "DomainNameDecoder.h"
+#include <nifman.h>
+#include <comms-infras/es_config.h>
+#include "netcfgextndhcpmsg.h"
+#include <f32file.h>
+#include <comms-infras/metatype.h>
+#include <comms-infras/metadata.h>
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+#include "DHCPIP4Msg.h"
+#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#include "dhcphwaddrmanager.h"
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+using namespace DHCPv4;
+#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+
+struct TDHCPv4Persistent : public Meta::SMetaData
+{
+ TDHCPv4Persistent() :
+ iTaskStartedAt( 0 ),
+ iCurrentAddress(KInetAddrNone,KInetPortNone),
+ iLeaseTime(0)
+ {
+ }
+
+ TTime iTaskStartedAt;
+ TInetAddr iCurrentAddress;
+ TUint32 iLeaseTime;
+
+ DATA_VTABLE
+};
+
+START_ATTRIBUTE_TABLE( TDHCPv4Persistent, KDHCPv4Persinstence, KDHCPv4PersinstenceId )
+ REGISTER_ATTRIBUTE( TDHCPv4Persistent, iTaskStartedAt, TMetaTime )
+ REGISTER_ATTRIBUTE( TDHCPv4Persistent, iCurrentAddress, TMeta<TInetAddr> )
+ REGISTER_ATTRIBUTE( TDHCPv4Persistent, iLeaseTime, TMetaNumber )
+END_ATTRIBUTE_TABLE()
+
+CDHCPIP4Control::~CDHCPIP4Control()
+ {
+ }
+
+void CDHCPIP4Control::ConfigureL(const TConnectionInfo& aInfo, const RMessage2* aMessage)
+/**
+ * Open and attach to the RConnection
+ *
+ * @internalTechnology
+ */
+ {
+ CDHCPControl::ConfigureL( aInfo, aMessage );
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4Control::ConfigureL")));
+
+ iDhcpDb = new (ELeave) CDHCPDb( TPtrC( SERVICE_IP_DNS_ADDR_FROM_SERVER ),
+ TPtrC( SERVICE_IP_NAME_SERVER1 ),
+ TPtrC( SERVICE_IP_NAME_SERVER2 )); //for both version for the time being see the class TDHCPIP4Db coments
+ FindInterfaceNameL(aInfo,KAfInet);
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+#ifndef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+ iDhcpStateMachine = CDHCPIP4StateMachine::NewL(iEsock, iConnection, iInterfaceName,iDHCPServerImpl);
+#else
+ iDhcpHwAddrManager = CDhcpHwAddrManager::NewL();
+ iDhcpStateMachine = CDHCPIP4StateMachine::NewL(iEsock, iConnection, iInterfaceName,iDhcpHwAddrManager, iDHCPServerImpl);
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#else
+ iDhcpStateMachine = CDHCPIP4StateMachine::NewL(iEsock, iConnection, iInterfaceName);
+#endif // SYMBIAN_NETWORKING_DHCPSERVER
+ TDHCPv4Persistent pers;
+ iStaticAddress = !iDhcpDb->ReadL(*iDhcpStateMachine, pers);
+
+
+ //initialise relevant data
+ TTimeIntervalSeconds seconds = static_cast<TInt>(pers.iLeaseTime);
+ iDhcpDb->iLeaseExpiresAt = pers.iTaskStartedAt + seconds;
+ DhcpStateMachine()->iLeaseTime = pers.iLeaseTime;
+ iDhcpStateMachine->SetCurrentAddress( pers.iCurrentAddress );
+ DhcpStateMachine()->iMaxRetryCount = 2; //Max retry count for the first run is set to 2
+
+
+ TInetAddr existingGlobalAddr = iDhcpStateMachine->GetInterfaceGlobalAddress();
+
+ if( ! existingGlobalAddr.IsUnspecified() )
+ {
+ // there was an existing address on the interface, regardless of commsdat preference..
+ // so force inform.
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Interface already has global address. Forcing inform mode.")));
+ iDhcpStateMachine->SetCurrentAddress( existingGlobalAddr );
+ iStaticAddress = ETrue;
+ }
+ else
+ {
+ if(iStaticAddress)
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Interface has a static address from commsdat. Proceeding in inform mode.")));
+ }
+ else
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Interface has no global address yet. Proceeding in discover mode.")));
+ }
+ }
+
+ CDHCPControl::ConfigureL(iStaticAddress);
+ }
+
+void CDHCPIP4Control::Cancel()
+ {
+ iClientShouldCompleteWhenLinkLocalCreated = EFalse;
+
+ // Call the base class.
+ CDHCPControl::Cancel();
+ }
+
+void CDHCPIP4Control::BindingFinishedL()
+ {
+ CDHCPControl::BindingFinishedL();
+ TDHCPv4Persistent pers;
+ //get relevant data from statemachine
+ pers.iTaskStartedAt = DhcpStateMachine()->iStartedAquisitionAt;
+ pers.iCurrentAddress = DhcpStateMachine()->iCurrentAddress;
+ pers.iLeaseTime = DhcpStateMachine()->iLeaseTime;
+ TRAPD( ret, iDhcpDb->WriteL(*iDhcpStateMachine, pers) );
+ if (ret!=KErrNone)
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4Control::BindingFinishedL error: %d"),ret));
+ }
+ }
+
+void CDHCPIP4Control::TimerExpired()
+/**
+ * Called by the timer to signal that the timer has expired
+ *
+ * @internalTechnology
+ */
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4Control::TimerExpired()")));
+
+ CDHCPControl::TimerExpired();
+
+ // In response to the rebind operation timing out, try to create
+ // a link local to allow local addressing (may not be supported
+ // by current interface's IPv4 link local option). We cannot
+ // create the link local earlier (e.g., after a renew attempt
+ // times-out) because the link local will not be usable until
+ // the DHCP assigned address has been removed (randomly
+ // generated addresses are prioritised below non-randomly
+ // generated addresses during selection in the TCP/IP stack).
+ if( ( iState == EInitInProgress ) && iDhcpConfigListener && !iDhcpConfigListener->HaveLinkLocal() )
+ {
+ DhcpStateMachine()->CreateIPv4LinkLocal();
+ }
+ }
+
+TInt CDHCPIP4Control::HandleClientRequestL(TUint aName, TInt aValue)
+/**
+ * Handles client requests made through RConnection
+ * are handled here. Currently its for renewing the lease time
+ * where client passes in a required timeout
+ * @see CDHCPControl::HandleClientRequestL
+ *
+ * @internalTechnology
+ */
+ {
+ TBool deferAllowed = !iMessage;
+ TBool defer = EFalse;
+
+ defer = CDHCPControl::HandleClientRequestL(aName, aValue);
+
+ if (aName == KConnAddrRenew && iState == ERenewInProgress && deferAllowed)
+ {//Rebind timeout
+ TTimeIntervalSeconds timeOut;
+ if(aValue > 0)
+ {
+ timeOut = aValue;
+ }
+ else
+ {
+ timeOut = (DhcpStateMachine()->iRebindTimeT2 - DhcpStateMachine()->iRenewalTimeT1 + 1);
+ }
+ iTimer->After(timeOut, *this);
+ defer = ETrue;
+ }
+
+ return defer;
+ }
+
+TInt CDHCPIP4Control::HandleClientRequestL(TUint aName)
+/**
+ * Handles client requests specific for IP4
+ *
+ * @see CDHCPControl::HandleClientRequestL
+ * @internalTechnology
+ */
+ {
+ return CDHCPIP4Control::HandleClientRequestL(aName,0);
+ }
+
+/**
+ Get raw option data (IP4 version).
+ @param pointer to the buffer descriptor for getting option data
+*/
+void CDHCPIP4Control::HandleGetRawOptionDataL(TDes8* aDes)
+{
+ TDhcp4RawOptionDataPckg pckg(*aDes);
+
+ TUint8 opCode = pckg.OpCode();
+ TPtr8 buf(pckg.Buf());
+ GetRawOptionDataL(opCode, buf);
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+ if (!iDhcpStateMachine->iDhcpInformAckPending)
+ {
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+ pckg.SetBufLengthL(buf.Length());
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+ }
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+}
+
+void CDHCPIP4Control::TaskCompleteL( TInt aError )
+/**
+ * TaskCompleteL function
+ *
+ * if this method returns ETrue then aStateMachine deletes itself.
+ * In this case it does not ever return ETrue.
+ * Called upon completion or when suspended.
+ *
+ * @see CStateMachine::iSuspendRequest comment
+ * @internalTechnology
+ */
+ {
+ // In response to the initialisation operation timing out,
+ // try to create a link local to allow local addressing (may
+ // not be supported by current interface's IPv4 link local
+ // option).
+ if( ( aError == KErrTimedOut ) &&
+ ( iState == EInitInProgress ) &&
+ !iStaticAddress &&
+ iDhcpConfigListener &&
+ !iDhcpConfigListener->HaveLinkLocal() )
+ {
+ if( DhcpStateMachine()->CreateIPv4LinkLocal() == KErrNone )
+ {
+ iClientShouldCompleteWhenLinkLocalCreated = ETrue;
+ //Link Local Address has been taken & return here itself
+ CDHCPControl::TaskCompleteL(aError);
+ return;
+ }
+ }
+ if((DhcpStateMachine()->iRetryDhcpIpCount >= KDHCPv4MaxRetryCount) && iState == EDeclineInProgress )
+ {
+ if( DhcpStateMachine()->CreateIPv4LinkLocal() == KErrNone )
+ {
+ iClientShouldCompleteWhenLinkLocalCreated = ETrue;
+ //Link Local Address has been taken & return here itself
+ CDHCPControl::TaskCompleteL(KErrNone);
+ return;
+ }
+
+ }
+ // Call the base class.
+ CDHCPControl::TaskCompleteL( aError );
+ }
+
+void CDHCPIP4Control::LinkLocalCreated()
+/**
+ * LinkLocalCreated function
+ *
+ * If iClientShouldCompleteWhenLinkLocalCreated is ETrue we need to complete the
+ * client messages as the link local has been created and the interface is now
+ * ready for use.
+ *
+ * @internalTechnology
+ */
+ {
+ if( iClientShouldCompleteWhenLinkLocalCreated )
+ {
+ iClientShouldCompleteWhenLinkLocalCreated = EFalse;
+
+ CompleteClientConfigureMessage(KErrNone);
+ // don't complete any outstanding ioctl yet..
+ }
+ }
+
+void CDHCPIP4Control::GetRawOptionDataL(TUint aOpCode, TPtr8& aPtr)
+ {
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+ if(iValidMsg.Length()==0 && iDHCPServerImpl)
+ {
+ GetRawOptionDataFromDNSBufL(aPtr);
+ return;
+ }
+#endif // SYMBIAN_NETWORKING_DHCPSERVER
+ HBufC8* buf = NULL;
+ DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+ CleanupClosePushL(msg);
+ TPtr8 ptr( const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length() );
+ msg.iRecord.ParseL(ptr); //no check necessary
+ DHCPv4::COptionNode* pOption = msg.iOptions.FindOption(static_cast<TUint8>(aOpCode));
+ if (!pOption)
+ {
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+ CleanupStack::PopAndDestroy();
+ TUint8 tempOpt=aOpCode;
+ TPtr8 optPtr(&tempOpt,1,1);
+ return(RequestInformOrCompleteCallL(optPtr));
+#else
+ User::Leave(KErrNotFound);
+#endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+ }
+ ptr.Set(pOption->GetBodyDes());
+ if (ptr.Length() > aPtr.MaxLength())
+ {
+ User::Leave(KErrOverflow);
+ }
+ aPtr.Copy(ptr);
+ CleanupStack::PopAndDestroy();
+ }
+
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+
+void CDHCPIP4Control::GetRawOptionDataFromDNSBufL(TPtr8& aPtr)
+ {
+ if(iValidMsg.Length() == 0)
+ {
+ if (iDNSRawOption->Des().Length() > aPtr.MaxLength())
+ {
+ User::Leave(KErrOverflow);
+ }
+ aPtr.Copy(iDNSRawOption->Des());
+ }
+ }
+
+void CDHCPIP4Control::HandleSetRawOptionCodeL(TDes8* aDes)
+ {
+ if(iValidMsg.Length() == 0)
+ {
+ iDNSRawOption = HBufC8::NewL(aDes->Length());
+ iDNSRawOption->Des() = *aDes;
+ }
+ else
+ {
+ SetRawOptionCodeL(aDes);
+ }
+ }
+
+void CDHCPIP4Control::SetRawOptionCodeL(TDes8* aDes)
+ {
+ HBufC8* buf = NULL;
+ DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+ CleanupClosePushL(msg);
+ TPtr8 ptr( const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length() );
+ msg.iRecord.ParseL(ptr); //no check necessary
+
+ TDhcp4RawOptionDataPckg pckg(*aDes);
+ DHCPv4::TDHCPOptionCodes opcode = static_cast<DHCPv4::TDHCPOptionCodes>(pckg.OpCode());
+
+ DHCPv4::COptionNode* pOption = msg.iOptions.FindOption(opcode);
+ if (!pOption)
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ TPtr8 ptr2(reinterpret_cast<TUint8*>(aDes),aDes->Length());
+
+ pOption->SetBody(ptr2);
+ CleanupStack::PopAndDestroy(); // msg
+ }
+#endif // SYMBIAN_NETWORKING_DHCPSERVER
+
+void CDHCPIP4Control::HandleGetSipServerAddrL(TDes8* aDes)
+ {
+ if (aDes->Length() < static_cast<TInt>(sizeof(SSipServerAddr)))
+ {
+ User::Leave(KErrArgument);
+ }
+
+ SSipServerAddr* sipServerAddr =
+ reinterpret_cast<SSipServerAddr*>(const_cast<TUint8*>(aDes->Ptr()));
+
+ HBufC8* buf = NULL;
+ DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+ CleanupClosePushL(msg);
+ TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+ msg.iRecord.ParseL(ptr);
+ DHCPv4::COptionNode* sipServerOption = msg.iOptions.FindOption(DHCPv4::EDHCPSIPServers);
+
+ if(sipServerOption)
+ {
+ TUint8* headerPtr = sipServerOption->Ptr();
+
+ TUint encoding = headerPtr[DHCPv4::KDhcpSipEncodingOffset];
+ TUint length = headerPtr[DHCPv4::KDhcpSipLengthOffset];
+
+ if(encoding != DHCPv4::KDhcpSipEncodingAddresses)
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerAddrL: Client trying to fetch a SIP address when only a SIP domain is known")));
+ User::Leave( KErrNotFound );
+ }
+ if((TUint)sipServerAddr->index >= (length / KIp4AddrByteLength))
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerAddrL: Client tried to fetch an out-of-range SIP address %d (I only know about %d)"),(TUint)sipServerAddr->index, (length / KIp4AddrByteLength)));
+ User::Leave( KErrNotFound );
+ }
+
+ TUint addrOffset = sipServerAddr->index * KIp4AddrByteLength;
+
+ TUint8* bodyPtr = sipServerOption->GetBodyPtr();
+ TUint32 copiedValue;
+ // Grab ip address from option body at given offset, +1 used to skip the encoding boolean used for sip
+ Mem::Copy(&copiedValue,(bodyPtr + addrOffset+1),4);
+ // swap around ip address as in BigEndian form
+ copiedValue = ByteOrder::Swap32(copiedValue);
+ sipServerAddr->address.SetAddress(copiedValue);
+ }
+ else
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerAddrL: Client tried to fetch a SIP option but none has (yet) been received")));
+ User::Leave(KErrNotFound);
+ }
+ CleanupStack::PopAndDestroy();
+ }
+
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+void CDHCPIP4Control::GetDhcpHdrSiaddrL(TDes8& aNxtAddress)
+/**
+ * The GetDhcpHdrSiaddr function
+ *
+ * Fetches the Siaddr
+ *
+ * @param aNxtAddress Next server IPAddress fetched from the DHCP Server
+ * @internalTechnology
+ */
+ {
+ if (aNxtAddress.Length() < static_cast<TInt>(sizeof(TConnectionAddress)))
+ {
+ User::Leave(KErrArgument);
+ }
+ TConnectionAddress* ptr = (TConnectionAddress*)aNxtAddress.Ptr();
+ TInetAddr* addrPtr = new(&(ptr->iAddr))TInetAddr;
+ //ptr->iAddr is just some memory in aDes. There is no guarantee that it will be a
+ //valid TInetAddr (or even a valid TDes) so what we do here is just run a constructor
+ //on this already valid memory block and we are now guaranteed to have a valid
+ //TInetAddr - NO MEMORY IS ACTUALLY ALLOCATED BY NEW HERE - see base code for more
+ //details
+
+ //Parse the iValidMsg
+ HBufC8* buf = NULL;
+ DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+ CleanupClosePushL(msg);
+ TPtr8 msgPtr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+ msg.iRecord.ParseL(msgPtr);
+
+ //Extract the server address
+ addrPtr->SetAddress(msg.GetSIAddr());
+
+ CleanupStack::PopAndDestroy();
+ }
+
+void CDHCPIP4Control::GetDhcpHdrSnameL(TDes8& aHdrSvrName)
+/**
+ * The GetDhcpHdrSname function
+ *
+ * Fetches the Sname
+ *
+ * @param aHdrSvrName Next server name fetched from the DHCP Server.
+ * @internalTechnology
+ */
+ {
+ HBufC8* buf = NULL;
+ DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+ CleanupClosePushL(msg);
+ TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+ msg.iRecord.ParseL(ptr);
+ if (msg.GetSName().Length() > aHdrSvrName.MaxLength())
+ {
+ User::Leave(KErrOverflow);
+ }
+ aHdrSvrName=msg.GetSName();
+ //SetLength otherwise received string length will be 64 by default, truncate to end of string.
+ aHdrSvrName.SetLength(aHdrSvrName.Locate('\0'));
+
+ CleanupStack::PopAndDestroy(&msg);
+ }
+
+void CDHCPIP4Control::HandleGetTftpServerAddrL(TDes8& aDes)
+/**
+ * The HandleGetTftpServerAddrL function
+ *
+ * Fetches the Tftp Server Address
+ * @param aDes Buffer returned contains a list of ip addresses each of 4 bytes.
+ *
+ * @internalTechnology
+ */
+ {
+ if (aDes.Length() < static_cast<TInt>(sizeof(STftpServerAddr)))
+ {
+ User::Leave(KErrArgument);
+ }
+
+ STftpServerAddr* tftpServerAddr =
+ reinterpret_cast<STftpServerAddr*>(const_cast<TUint8*>(aDes.Ptr()));
+
+ HBufC8* buf = NULL;
+ DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+ CleanupClosePushL(msg);
+ TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+ msg.iRecord.ParseL(ptr);
+ DHCPv4::COptionNode* tftpServerOption = msg.iOptions.FindOption(DHCPv4::EDHCPTftpServers);
+ if(tftpServerOption)
+ {
+
+ TUint8 len=tftpServerOption->GetItemLength()-2;//subtract 2 bytes becz length include message opcode and message opcode length
+
+ TUint addrOffset = tftpServerAddr->index * KIp4AddrByteLength;
+
+ if (addrOffset>len)
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetTftpServerAddrL: Client tried to fetch a invalid index of Tftp Address which is not present")));
+ iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+ User::Leave(KErrNotFound);
+
+ }
+
+ TUint8* bodyPtr = tftpServerOption->GetBodyPtr();
+
+ TUint32 copiedValue;
+ // Grab ip address from option body at given offset.
+ Mem::Copy(&copiedValue,(bodyPtr + addrOffset),4);
+ // swap around ip address as in BigEndian form/ copiedValue = ByteOrder::Swap32(copiedValue);
+ copiedValue = ByteOrder::Swap32(copiedValue);
+ tftpServerAddr->address.SetAddress(copiedValue);
+ }
+ else //check inform to be made or not..or return
+ {
+ CleanupStack::PopAndDestroy(); //pop buffer ..we are going to return immediately
+ TUint8 opt=DHCPv4::EDHCPTftpServers;
+ TPtr8 optPtr(&opt,1,1);
+ return(RequestInformOrCompleteCallL(optPtr));
+ }
+ iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+ CleanupStack::PopAndDestroy();
+
+}
+
+void CDHCPIP4Control::HandleGetTftpServerNameL(TDes8& aTftpSvrName)
+/**
+ * The HandleGetTftpServerName function
+ *
+ * Fetches the Tftp Server Name
+ *
+ * @param aTftpSvrName Tftp Server Name fetched from the DHCP Server.
+ * @internalTechnology
+ */
+ {
+ HBufC8* buf = NULL;
+ DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+ CleanupClosePushL(msg);
+ TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+ msg.iRecord.ParseL(ptr);
+ DHCPv4::COptionNode* tftpOption = msg.iOptions.FindOption(DHCPv4::EDHCPTftpServerName);
+ if(tftpOption)
+ {
+ if (aTftpSvrName.MaxLength()<tftpOption->GetItemLength())
+ {
+ iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+ User::Leave(KErrOverflow);
+ }
+ else
+ {
+ aTftpSvrName.Copy(tftpOption->GetBodyDes());
+ }
+ }
+ else
+ {
+ //To check if DHCP Sname Option is overloaded
+ tftpOption = msg.iOptions.FindOption(DHCPv4::EDHCPOptionOverload);
+ if(tftpOption)
+ {
+ if( msg.iOptions.GetOptionOverload() == DHCPv4::EDHCPSname)
+ {
+ GetDhcpHdrSnameL(aTftpSvrName);
+ }
+ }
+ else//now issue Inform Request for option 66 or return now..
+ {
+ CleanupStack::PopAndDestroy(); //pop buffer ..we are going to return immediately
+ TUint8 opt=DHCPv4::EDHCPTftpServerName;
+ TPtr8 optPtr(&opt,1,1);
+ return(RequestInformOrCompleteCallL(optPtr));
+ }
+ }
+ iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+ CleanupStack::PopAndDestroy();
+ }
+
+void CDHCPIP4Control::RequestInformOrCompleteCallL(TPtr8& aOpcodePtr)
+/**
+ * The RequestInformOrCompleteCallL function
+ *
+ * Checks DHCPINFORM message should be sent or not
+ * @param aOpcodePtr pointer to the opcode list to be updated in iSavedExtraParameters
+ * @internalTechnology
+ */
+ {
+
+ if (!iDhcpStateMachine->iDhcpInformAckPending)
+ {
+ if (!iDhcpStateMachine->iSavedExtraParameters.Length())
+ {
+ iDhcpStateMachine->iSavedExtraParameters.CreateL(aOpcodePtr);
+ }
+ else
+ {
+ iDhcpStateMachine->iSavedExtraParameters.ReAllocL(iDhcpStateMachine->iSavedExtraParameters.Length()+aOpcodePtr.Length());
+ iDhcpStateMachine->iSavedExtraParameters.Append(aOpcodePtr);
+ }
+
+ static_cast<CDHCPIP4StateMachine*>(iDhcpStateMachine)->StartInformL( this );
+ iDhcpStateMachine->iDhcpInformAckPending=ETrue;
+ iState = EInformInProgress;
+ }
+ else
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8(" RequestInformOrCompleteCallL::Client tried to fetch a option but none has (yet) been received")));
+ iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+ User::Leave(KErrNotFound);
+ }
+ }
+
+
+
+void CDHCPIP4Control::HandleGetMultipleParamsL(TDes8& aDes)
+/**
+ * The HandleGetMultipleParamsL function
+ *
+ * Fetches the required raw option parameter buffer.
+ * Buffer contains list of parameter options followed by msg opcode, len, data..
+ * If any of the parameters are not found, DHCPINFORM message will be sent.
+ * Filled Returned Buffer is as shown in fig..
+ * @code
+ * -----------------------------------------------------
+ * |No of | |Data | | |Data | |
+ * |OpCode|OP1 |length1|Data1 | OP2 |Length2|Data2 |
+ * | | | | | | | |
+ * -----------------------------------------------------
+ * @endcode
+ * @param aDes Pointer to the buffer descriptor for getting option data
+ * @internalTechnology
+ */
+ {
+ HBufC8 *saveBuf=NULL, *buffer=NULL;
+ TUint8 *headerPtr;
+ TInt numOfOpcodes=0;
+ TInt totalLength=0,opcodeLength=aDes.Length();
+ TInt maxLength=aDes.MaxLength();
+ TUint8 opcode;
+ TBool allFound=ETrue;
+
+ DHCPv4::CDHCPMessageHeaderIP4 msgSaved(saveBuf);
+ TPtr8 savedPtr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+ CleanupClosePushL(msgSaved);
+ msgSaved.iRecord.ParseL(savedPtr);
+
+
+ //The below for loop checks all the required opcode data is present or not
+ //The message opcode data is not present in the iValidMsg buffer,the corresponding
+ //opcodes are stored in iCurrentParameters for sending it in DHCPINFORM message
+ for(TInt i=0;i<opcodeLength;i++)
+ {
+ opcode=*(aDes.Ptr()+i); //search required opcode is present or not, one by one
+ DHCPv4::COptionNode* findNode = msgSaved.iOptions.FindOption(opcode);
+ if (findNode )
+ {
+ TInt bufLength=findNode->GetItemLength();
+ totalLength+=bufLength;
+ if ((totalLength+1) > maxLength)
+ {
+ totalLength-=bufLength;
+ continue; //current buffer is too big..so hope next buffer is small
+ }
+ if (!buffer)
+ {
+ buffer=HBufC8::NewLC(totalLength + 1);//+1 is extra byte to store number of opcodes
+ buffer->Des().Append(KNoChar);
+ }
+ else
+ {
+ buffer=buffer->ReAllocL(totalLength + 1);
+ CleanupStack::Pop();//buffer as ptr address has changed
+ CleanupStack::PushL(buffer);
+ }
+ headerPtr = findNode->Ptr();
+ ++numOfOpcodes;
+ buffer->Des().Append(headerPtr,bufLength);
+ }
+ else
+ {
+ //If atleast one opcode, among the requested, is not found then request through
+ //DHCP INFORM message by calling RequestInformOrCompleteCallL
+ allFound=EFalse;
+ }
+ }
+
+ if (allFound ) //everything is present..just return call now itself..
+ {
+ if ((totalLength + 1) > maxLength)
+ {
+ User::Leave(KErrOverflow);
+ }
+ if(buffer) // buffer would be NULL only when aDes.Length = 0 which is a rare scenario. But still check it to avoid NULL pointer dereference.
+ {
+ aDes.Copy(buffer->Ptr(), buffer->Length());
+ TBuf8<1> dummy;
+ dummy.FillZ(1);
+ dummy[0]=numOfOpcodes;
+ aDes.Replace(0,1,dummy);//update number of opcodes collected
+ }
+ }
+ else
+ {
+ TPtr8 opcodePtr(const_cast<TUint8*>(aDes.Ptr()),opcodeLength);
+ opcodePtr.SetLength(opcodeLength);
+ RequestInformOrCompleteCallL(opcodePtr);
+ }
+
+ if (buffer)
+ {
+ CleanupStack::PopAndDestroy(buffer);
+ }
+
+ CleanupStack::PopAndDestroy(&msgSaved);
+
+ }
+
+
+TInt CDHCPIP4Control::InformCompleteRequestHandlerL()
+/**
+ * The InformCompleteRequestHandlerL function
+ *
+ * The function will be called after the DHCPACK message is received, and
+ * iValidMsg buffer has been updated.
+ * Looks for the requested options present or not and appropriately calls
+ * the function handlers
+ *
+ * @return KErrNone if the required data option is found else corresponding error code.
+ * @internalTechnology
+ */
+ {
+
+ TUint optionName = iMessage->Int1();
+ TInt length = iMessage->Int3();
+
+ HBufC8 *buff=HBufC8::NewMaxLC(length) ;
+ TPtr8 ptr(buff->Des());
+ iMessage->ReadL(2, ptr);
+
+
+ switch(optionName)
+ {
+ case KConnGetDhcpRawOptionData:
+ {
+ HandleGetRawOptionDataL(&ptr);
+ iMessage->WriteL(2,ptr);
+ break;
+ }
+
+ case KConnDhcpGetMultipleParams :
+ {
+ HandleGetMultipleParamsL(ptr);
+ iMessage->WriteL(2,ptr);
+ break;
+ }
+
+ case KConnGetTftpServerAddr:
+ {
+ HandleGetTftpServerAddrL(ptr);
+ iMessage->WriteL(2,ptr);
+ break;
+ }
+
+ case KConnGetTftpServerName:
+ {
+ HandleGetTftpServerNameL(ptr);
+ iMessage->WriteL(2,ptr);
+ break;
+ }
+
+ default:
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("InformCompleteRequestHandlerL : default unhandled optino Name")));
+ break;
+
+ }
+ iDhcpStateMachine->iDhcpInformAckPending=EFalse;
+ CleanupStack::PopAndDestroy(buff);
+ return KErrNone;
+
+ }
+#endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+
+
+void CDHCPIP4Control::HandleGetSipServerDomainL(TDes8* aDes)
+ {
+ if (aDes->Length() < static_cast<TInt>(sizeof(SSipServerDomain)))
+ {
+ User::Leave(KErrArgument);
+ }
+
+ SSipServerDomain* sipServerDomain =
+ reinterpret_cast<SSipServerDomain*>(const_cast<TUint8*>(aDes->Ptr()));
+
+ HBufC8* buf = NULL;
+ DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
+ CleanupClosePushL(msg);
+ TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
+ msg.iRecord.ParseL(ptr);
+ DHCPv4::COptionNode* sipServerOption = msg.iOptions.FindOption(DHCPv4::EDHCPSIPServers);
+
+ if(sipServerOption)
+ {
+ TUint8* headerPtr = sipServerOption->Ptr();
+
+ TUint encoding = headerPtr[DHCPv4::KDhcpSipEncodingOffset];
+
+ if(encoding != DHCPv4::KDhcpSipEncodingDomains)
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerDomainL: Client trying to fetch a SIP domain when only a SIP address is known")));
+ User::Leave( KErrNotFound );
+ }
+
+ CDomainNameCodec* domainNameDecoder = new(ELeave) CDomainNameCodec();
+ CleanupStack::PushL(domainNameDecoder);
+ TPtr8 ptr = sipServerOption->GetBodyDes();
+ ptr.Set((TUint8*)(ptr.Ptr()+1),ptr.Length()-1,ptr.MaxLength()-1);
+ domainNameDecoder->DecodeL(ptr);
+
+ if(sipServerDomain->index < (TInt)domainNameDecoder->NumDomainNames())
+ {
+ TDomainName domainName = (*domainNameDecoder)[sipServerDomain->index];
+ sipServerDomain->domainName.Copy(domainName);
+ }
+ else
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerDomainL: Client tried to fetch an out-of-range SIP domain %d (I only know about %d)"), sipServerDomain->index , (TInt)domainNameDecoder->NumDomainNames()));
+ User::Leave(KErrNotFound);
+ }
+
+ CleanupStack::PopAndDestroy();
+ }
+ else
+ {
+ __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerDomainL: Client tried to fetch a SIP option but none has (yet) been received")));
+ User::Leave(KErrNotFound);
+ }
+ CleanupStack::PopAndDestroy();
+ }
+
+
+
+TBool CDHCPIP4Control::ShouldInformAfterFailedInit(void)
+ {
+ // if has no global address, should not inform
+ return iDhcpStateMachine->GetInterfaceGlobalAddress().IsUnspecified() ? EFalse : ETrue ;
+ }
+