tcpiputils/dhcp/src/DHCPStateMachine.cpp
changeset 0 af10295192d8
child 25 d15a50675083
child 27 4214adf9e0d3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dhcp/src/DHCPStateMachine.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,720 @@
+// 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 statemachine helper functions
+// 
+//
+
+/**
+ @file DHCPStateMachine.cpp
+ @internalTechnology
+*/
+
+#include "DHCPStates.h"
+#include "DHCPStatesDebug.h"
+#include "DHCPControl.h"
+#include "ExpireTimer.h"
+#include "DHCPMsg.h"
+#include <e32math.h>
+#include "DHCPServer.h"
+#include "in6_opt.h"
+#include "es_sock.h"
+
+CDHCPStateMachine::~CDHCPStateMachine()
+/**
+  * Destructor of the If base class
+  *
+  * @internalTechnology
+  *
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::~CDHCPStateMachine")));
+	Cancel();
+	delete iDhcpMessage;
+	delete iMessageSender;
+	delete iTimer;
+	delete iHostName;
+	delete iDomainName;
+#ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
+	iSavedExtraParameters.Close();
+#endif //SYMBIAN_NETWORKING_DHCP_MSG_HEADERS	
+	iClientId.Close();
+	iSocket.Close();
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER	
+	iSvrSocket.Close();
+	delete iDNSInformation;
+#endif // SYMBIAN_NETWORKING_DHCPSERVER	
+	}
+
+void CDHCPStateMachine::ConstructL()
+/**
+  * Creates socket and connections for the object
+  *
+  *
+  *	@internalTechnology
+  *
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::ConstructL")));
+	
+#ifdef _DEBUG
+	// let's set debug properties to something
+	//  so they can be read immediately..
+	CDHCPStateMachine* const & iStateMachine = this;
+	CDHCPStateMachine* const & iDhcpStateMachine = iStateMachine;
+	DHCP_DEBUG_PUBLISH_READY(DHCPDebug::ENotReady);
+	DHCP_DEBUG_PUBLISH_STATE(DHCPDebug::EStateUnknown);
+#endif
+
+	iTimer = CExpireTimer::NewL();
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER	
+	if(!iServerImpl) // Assemble client Ids only for DHCP client implementation
+		{
+#endif // SYMBIAN_NETWORKING_DHCPSERVER	
+	InitialiseSocketL();
+	AssembleClientIDsL();
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER	
+		}
+	else
+		InitialiseServerSocketL();
+#endif // SYMBIAN_NETWORKING_DHCPSERVER			
+	}
+
+void CDHCPStateMachine::Start(MStateMachineNotify* aStateMachineNotify)
+/**
+  * The Start function
+  *
+  * Starts the statemachine task
+  *
+  * @internalTechnology
+  */
+{
+   SetLastError( KErrNone );
+   iReceiving = EFalse;
+   iHistory = 0;
+	SetActiveEvent(iFirstState);
+	if ( !aStateMachineNotify )
+		{//no notifier specified => leave the current one unchanged
+		aStateMachineNotify = iStateMachineNotify;
+		}
+	CStateMachine::Start(NULL, NULL, aStateMachineNotify);
+}
+
+void CDHCPStateMachine::CloseNSendMsgL(TRequestStatus& aStatus, CDHCPStateMachine::EAddressType aEAddressType)
+/**
+  * Handles sending of packets for this object
+  *
+  * @internalTechnology
+  *
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::CloseNSendMsgL")));
+   	PrepareToSendL(aEAddressType);
+  	iMessageSender->Cancel();
+	
+	GetServerAddress(iSocketAddr);
+	AddScopeToAddrL(iSocketAddr);
+
+#ifdef _DEBUG
+	THostName addrDes;
+	iSocketAddr.Output(addrDes);	
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, 
+		_L("CDHCPStateMachine::CloseNSendMsgL - Sending message to %S%%%d"), &addrDes, iSocketAddr.Scope()));
+#endif
+
+	iSocket.SendTo(iDhcpMessage->Message(), iSocketAddr, 0, aStatus);
+	}
+
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+void CDHCPStateMachine::CloseNSendServerMsgL(TRequestStatus& aStatus, CDHCPStateMachine::EAddressType aEAddressType)
+/**
+  * Handles sending of packets for this object
+  *
+  * @internalTechnology
+  *
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::CloseNSendMsgL")));
+
+
+   	PrepareToSendServerMsgL(aEAddressType);
+  	iMessageSender->Cancel();
+
+	GetClientAddress(iSrvSocketAddr);
+	AddScopeToClientAddrL(iSrvSocketAddr);
+
+#ifdef _DEBUG
+	THostName addrDes;
+	iSrvSocketAddr.Output(addrDes);	
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, 
+		_L("CDHCPStateMachine::CloseNSendServerMsgL - Sending message to %S%%%d"), &addrDes, iSrvSocketAddr.Scope()));
+#endif
+
+	iSvrSocket.SendTo(iDhcpMessage->Message(), iSrvSocketAddr, 0, aStatus);
+	}
+	
+void CDHCPStateMachine::GetClientAddress( TInetAddr& /*aAddress*/ )
+/**
+  * GetClientAddress
+  *
+  * Null implementation
+  *
+  * @internalTechnology	
+*/
+	{
+	}	
+	
+#ifdef SYMBIAN_DNS_PROXY	
+TInetAddr CDHCPStateMachine::GetListenerAddress()
+	{
+	return iCurrentAddress;
+	}
+#endif
+		
+void CDHCPStateMachine::InitServerStateMachineL(MStateMachineNotify* /*aStateMachineNotify*/)
+/**
+  * InitServerStateMachineL
+  *
+  * Null implementation
+  *
+  * @internalTechnology
+  */
+	{
+	}	
+	
+void CDHCPStateMachine::InitServerBinding(MStateMachineNotify* /*aStateMachineNotify*/)		
+	{
+	
+	}
+	
+#endif // SYMBIAN_NETWORKING_DHCPSERVER
+
+void CDHCPStateMachine::CloseNSendMsgL(TTimeIntervalSeconds aSecs, TInt aMaxRetryCount, CDHCPStateMachine::EAddressType aEAddressType)
+/**
+  * Handles sending of packets for this object
+  *
+  * @internalTechnology
+  *
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::CloseNSendMsgL")));
+   	PrepareToSendL(aEAddressType);
+	iMessageSender->Cancel();
+	
+	TInetAddr addr;		
+	GetServerAddress( addr );
+	AddScopeToAddrL(addr);
+	
+#ifdef _DEBUG
+	THostName addrDes;
+	addr.Output(addrDes);	
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, 
+		_L("CDHCPStateMachine::CloseNSendMsgL - Sending message to %S%%%d"), &addrDes, addr.Scope()));
+#endif
+
+	if (FastTimeoutDuringInform())	// true only when InformNegotiationIsRequiredForConnectionStartCompletion is ETrue
+		{
+		iMessageSender->SendL(addr, iDhcpMessage->Message(), (aSecs.Int() * KMicrosecondsInSecs) / 14, aMaxRetryCount);
+		}
+	else
+		{
+		iMessageSender->SendL(addr, iDhcpMessage->Message(), aSecs.Int() * KMicrosecondsInSecs, aMaxRetryCount);	
+		}
+	}
+
+TInt CDHCPStateMachine::MSReportError(TInt aError)
+/**
+  * Report an error properly
+  *
+  * @internalTechnology
+  */
+	{
+	Cancel();
+
+	SetLastError(aError);
+	OnCompletion();
+
+	return aError;
+	}
+
+void CDHCPStateMachine::Cancel()
+/**
+  * Cancel the state machine's activities
+  *
+  * @internalTechnology
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::Cancel")));
+	CancelMessageSender();
+	iSocket.Close();
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER	
+	iSvrSocket.Close();
+#endif // SYMBIAN_NETWORKING_DHCPSERVER	
+	CancelTimer();
+	CStateMachine::Cancel(KErrNone);
+	delete iFirstState;
+	iFirstState = NULL;
+	iFastTimeout = EFalse;	// reset iFastTimeout
+	iMaxRetryCount = KInfinity;//reset
+	}
+
+void CDHCPStateMachine::DoCancel()
+/**
+  * Implements a default docancel for the connection object
+  *
+  * @internalTechnology
+  */
+	{
+	// we have to cancel send and recv independently as cancelAll()
+	// doesn't satisfy us, only supporting read, write, ioctl, connect,
+	// accept and shutdown...:-(
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::DoCancel")));
+	if (iSocket.SubSessionHandle())
+		{
+		// check that the socket is open
+		// and if it is then we need to cancel things on it
+		iSocket.CancelRecv();
+		}
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER		
+	if(iSvrSocket.SubSessionHandle())
+		{
+		iSvrSocket.CancelRecv();
+		}
+#endif // SYMBIAN_NETWORKING_DHCPSERVER		
+	/*	iAsyncCancelHandler is set by the DHCP State that assumes ownership of the 
+		RequestStatus object of CDHCPStateMachine 				 
+	*/
+	 if(iAsyncCancelHandler)
+		{
+		iAsyncCancelHandler->Cancel();
+		}
+	}
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+void CDHCPStateMachine::FetchServerAddressL()
+/**
+  * This function is used to get the server's address (interface address)
+  *
+  */
+	{
+	if(!iSvrSocket.SubSessionHandle())
+		InitialiseServerSocketL();
+	
+	TPckgBuf<TSoInetInterfaceInfo> opt;
+	while (iSvrSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, opt) == KErrNone)
+		{
+		if (opt().iName == iInterfaceName)
+			{
+			iCurrentAddress = opt().iAddress;
+			break;
+			}
+		}
+   }
+   
+void CDHCPStateMachine::SetDNSInformation(TDes8* aDNSInfo)	
+	{
+	delete iDNSInformation;
+	iDNSInformation = NULL;
+	
+	iDNSInformation = HBufC8::NewL(aDNSInfo->Length());
+	iDNSInformation->Des() = *aDNSInfo;
+	}   
+	
+TBool CDHCPStateMachine::CheckNetworkId()
+/**
+  * This function compares the NetworkIds of the client and server
+  *
+  */	
+	{
+	iInformClientAddr.SetV4MappedAddress(iCiaddr);
+
+	if ((iInformClientAddr.Address() & KInetAddrNetMaskC) == 
+			(iCurrentAddress.Address() & KInetAddrNetMaskC))		
+		{
+		return ETrue;		
+		}
+	else
+		{
+		return EFalse;
+		}	
+	}   
+#endif // SYMBIAN_NETWORKING_DHCPSERVER
+
+void CDHCPStateMachine::FetchHWAddress()
+/**
+  * Fetches hardware address from the interface
+  *
+  */
+	{
+	TPckgBuf<TSoInetInterfaceInfo> opt;
+	while (iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, opt) == KErrNone)
+		{
+		if (opt().iName == iInterfaceName)
+			{
+			iHardwareAddr = opt().iHwAddr;
+			if(iHardwareAddr.Length() <= KHwAddrOffset)
+				{
+				// the hardware address came back too short
+   		 		//  to be a valid TSockAddr.. so we'll treat it as an empty value
+				iHardwareAddr.SetFamily(KAFUnspec);
+				iHardwareAddr.SetLength(KHwAddrOffset);
+				}
+			break;
+			}
+		}
+   }
+
+
+void CDHCPStateMachine::StartTimer(TTimeIntervalSeconds aSeconds, MExpireTimer& aExpireTimer)
+/**
+  * Give the tcp/ip6 stack time to perform
+  * its gratuitous ARP...
+  *
+  * @internalTechnology
+  */
+	{
+	CancelTimer();
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::StartTimerL")));
+
+	iTimer->After(aSeconds, aExpireTimer);
+	}
+
+void CDHCPStateMachine::StartTimer( TTimeIntervalMicroSeconds32 aMicroSeconds, MExpireTimer& aExpireTimer)
+/**
+  * Give the tcp/ip6 stack time to perform
+  * its gratuitous ARP...
+  *
+  * @internalTechnology
+  */
+	{
+	CancelTimer();
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::StartTimerL")));
+
+	iTimer->After(aMicroSeconds, aExpireTimer);
+	}
+
+void CDHCPStateMachine::RemoveConfiguredAddress( const TSoInet6InterfaceInfo& aSoInet6InterfaceInfo )
+/**
+  * 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("CDHCPStateMachine::RemoveConfiguredAddress")));
+	
+	TPckgBuf<TSoInet6InterfaceInfo> configInfo(aSoInet6InterfaceInfo);
+	// not interested in error
+	// how could we attempt to handle it anyway?...keep trying??? i think not...
+	// ensure that we have a socket to write down	
+	iSocket.Close();	
+	(void)iSocket.Open(iEsock, KAfInet, KSockDatagram, KProtocolInetUdp, iConnection);
+	(void)iSocket.SetOpt(KSoInetConfigInterface, KSolInetIfCtrl, configInfo);	
+	// make socket invisible for interface counting
+	(void)iSocket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0);
+	}
+
+void CDHCPStateMachine::ConfigureInterfaceL( const TSoInet6InterfaceInfo& aInterfaceInfo )
+/**
+  * 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
+  */
+	{
+	
+	TPckgBuf<TSoInet6InterfaceInfo> configInfo(aInterfaceInfo);
+	
+
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::ConfigureInterfaceL - KSoInetConfigInterface")));
+	
+	User::LeaveIfError(iSocket.SetOpt(KSoInetConfigInterface, KSolInetIfCtrl, configInfo));
+	}
+
+TInt CDHCPStateMachine::BindToSource()
+/**
+  * Binds socket to newly assigned address for the interface
+  *
+  * @internalTechnology
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::BindToSourceL")));
+	iSocket.Close();	// destroy the old socket
+	
+	UpdateHistory(CDHCPState::EBindToSource);
+	// now start a new one.
+	// might be nice if we left here if the socket open fails...but nobody's perfect...
+   // PS: cannot leave here the failure doesn't mean exception here see the usage....
+	TInt err = iSocket.Open(iEsock, KAfInet, KSockDatagram, KProtocolInetUdp, iConnection);
+	// make socket invisable for interface counting
+	if (err == KErrNone)
+		{
+		err = iSocket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0);
+		}
+		
+    if (err == KErrNone)       //PDEF122482: Enabling the ReUseAddr option.
+	    {
+	    err = iSocket.SetOpt(KSoReuseAddr, KSolInetIp, 1);
+	    }			
+	
+	if (err == KErrNone)
+		{
+        TInetAddr bindTo;        
+        AssignAddresses( bindTo, iCurrentAddress ); 
+
+        err = iSocket.Bind(bindTo);
+        if (err==KErrNone)
+	        {
+	        // we are finished with this socket, 
+	        // release it so as not to hold esock open
+	        iSocket.Close();
+	        }
+		}
+	return err;
+	}
+
+
+TUint32 CDHCPStateMachine::GetNetworkIdL() const
+	{	
+	TUint32 networkId;
+	_LIT(KIapNetwork, "IAP\\IAPNetwork");
+	User::LeaveIfError(iConnection.GetIntSetting(KIapNetwork, networkId));
+	
+	return networkId;
+	}
+
+void CDHCPStateMachine::AddScopeToAddrL(TInetAddr& addr)
+	{
+	TPckgBuf<TSoInetIfQuery> queryBuf;
+	queryBuf().iName = iInterfaceName;		
+	User::LeaveIfError(iSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, queryBuf));
+	
+	const TUint s = addr.Ip6Address().Scope() - 1;
+
+	if (s < 16)
+		{
+		addr.SetScope(queryBuf().iZone[s]);
+		}
+	}
+
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+void CDHCPStateMachine::AddScopeToClientAddrL(TInetAddr& addr)
+	{
+	TPckgBuf<TSoInetIfQuery> queryBuf;
+	queryBuf().iName = iInterfaceName;		
+	User::LeaveIfError(iSvrSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, queryBuf));
+	
+	const TUint s = addr.Ip6Address().Scope() - 1;
+
+	if (s < 16)
+		{
+		addr.SetScope(queryBuf().iZone[s]);
+		}
+	}
+// Set when the DHCP server implementation is being used	
+void CDHCPStateMachine::SetServerState(TBool aServerImpl)	
+	{
+	iServerImpl = aServerImpl;
+	}
+	
+TInt CDHCPStateMachine::BindServerInterface()
+/**
+  * Binds socket to newly assigned address for the interface
+  *
+  * @internalTechnology
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPStateMachine::BindServerInterface")));
+	iSvrSocket.Close();	// destroy the old socket
+	
+	// now start a new one.
+	TInt err = iSvrSocket.Open(iEsock, KAfInet, KSockDatagram, KProtocolInetUdp, iConnection);
+	// make socket invisable for interface counting
+	if (err == KErrNone)
+		{
+		TInt err = iSvrSocket.SetOpt(KSoKeepInterfaceUp, KSolInetIp, 0);
+		}
+
+	if (err == KErrNone)
+		{
+        TInetAddr bindTo;        
+        AssignAddresses( bindTo, iCurrentAddress );
+        err = iSvrSocket.Bind(bindTo);
+		}
+	return err;
+	}
+
+	
+TInetAddr CDHCPStateMachine::GetInterfaceServerGlobalAddress()
+/**
+  * Are any of the addresses on the interface global addresses?
+  *  If so, DHCP might decide not to attempt to discover an address.
+  *
+  * Returns unspecified address if no global address present.
+  */
+	{
+	TPckgBuf<TSoInetInterfaceInfo> opt;
+	if (iSvrSocket.SubSessionHandle() == 0)
+		{
+		InitialiseServerSocketL();
+		}
+	iSvrSocket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
+	__CFLOG_STMT(TBuf<512> addrStr;);
+	while (iSvrSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, opt) == KErrNone)
+		{
+		if (opt().iName == iInterfaceName)
+			{
+			TInetAddr& addr = opt().iAddress;
+			__CFLOG_STMT(addr.Output(addrStr););
+			if ( ! addr.IsLinkLocal())
+				{
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L("Global address %S found on interface %S"),&addrStr,&iInterfaceName));
+				return addr;
+				}
+			else
+				{
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L("Linklocal address %S found on interface %S"),&addrStr,&iInterfaceName));
+				}
+			break;
+			}
+		}
+	return TInetAddr(); // unspecified
+	}
+
+
+
+		
+#endif // SYMBIAN_NETWORKING_DHCPSERVER
+	
+TInetAddr CDHCPStateMachine::GetInterfaceGlobalAddress()
+/**
+  * Are any of the addresses on the interface global addresses?
+  *  If so, DHCP might decide not to attempt to discover an address.
+  *
+  * Returns unspecified address if no global address present.
+  */
+	{
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER	
+	if(iServerImpl)
+		{
+		return GetInterfaceServerGlobalAddress();
+		}
+	else
+		{
+#endif // SYMBIAN_NETWORKING_DHCPSERVER	
+	
+	TPckgBuf<TSoInetInterfaceInfo> opt;
+	if (iSocket.SubSessionHandle() == 0)
+		{
+		InitialiseSocketL();
+		}
+	iSocket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
+	__CFLOG_STMT(TBuf<512> addrStr;);
+	while (iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, opt) == KErrNone)
+		{
+		if (opt().iName == iInterfaceName)
+			{
+			TInetAddr& addr = opt().iAddress;
+			__CFLOG_STMT(addr.Output(addrStr););
+			if ( ! addr.IsLinkLocal())
+				{
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L("Global address %S found on interface %S"),&addrStr,&iInterfaceName));
+				return addr;
+				}
+			else
+				{
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L("Linklocal address %S found on interface %S"),&addrStr,&iInterfaceName));
+				}
+			break;
+			}
+		}
+	return TInetAddr(); // unspecified
+	
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+		}
+#endif // SYMBIAN_NETWORKING_DHCPSERVER				
+	}
+
+
+TBool CDHCPStateMachine::DoesInterfaceKnowAnyDNSServers()
+/**
+  * Does the interface know of any DNS servers?
+  */
+	{
+	TPckgBuf<TSoInetInterfaceInfo> opt;
+	if (iSocket.SubSessionHandle() == 0)
+		{
+		InitialiseSocketL();
+		}
+	iSocket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
+	__CFLOG_STMT(TBuf<512> addrStr;);
+	while (iSocket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, opt) == KErrNone)
+		{
+		if (opt().iName == iInterfaceName)
+			{
+			TInetAddr& addr = opt().iNameSer1;
+			__CFLOG_STMT(addr.Output(addrStr););
+			if ( ! addr.IsUnspecified() )
+				{
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L("DNS server %S found on interface %S"),&addrStr,&iInterfaceName));
+				return ETrue;
+				}
+			else
+				{
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L("No DNS servers already set on interface %S (prior to DHCP)"),&iInterfaceName));
+				}
+			break;
+			}
+		}
+	return EFalse;
+	}
+
+
+
+
+TDhcpRnd::TDhcpRnd():iXid(0)
+/**
+  * Constructor for this little random number 
+  * class that creates us a random transaction id
+  *
+  * @internalTechnology
+  */
+	{
+	TTime now;
+	now.HomeTime();
+	iSeed = now.Int64();
+	}
+
+TInt TDhcpRnd::Rnd(TInt aMin, TInt aMax)
+/**
+  * Utility class function to generated a real
+  * random number
+  *
+  * @internalTechnology
+  */
+	{
+	return Math::Rand(iSeed)%(aMax-aMin+1)+aMin;
+	}