tcpiputils/dhcp/src/DHCPIP4Control.cpp
changeset 0 af10295192d8
child 37 052078dda061
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implements the DHCP IP4 control plain
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file DHCPIP4Control.cpp
       
    20  @internalTechnology
       
    21 */
       
    22 
       
    23 #include "DHCPIP4Control.h"
       
    24 #include "DHCPIP4States.h"
       
    25 #include "DHCPIP4Msg.h"
       
    26 #include "DHCPServer.h"
       
    27 #include "DHCPConfigListener.h"
       
    28 #include "DHCPDb.h"
       
    29 #include "ExpireTimer.h"
       
    30 #include "NetCfgExtDhcpControl.h"
       
    31 #include "DomainNameDecoder.h"
       
    32 #include <nifman.h>
       
    33 #include <comms-infras/es_config.h>
       
    34 #include "netcfgextndhcpmsg.h"
       
    35 #include <f32file.h>
       
    36 #include <comms-infras/metatype.h>
       
    37 #include <comms-infras/metadata.h>
       
    38 #ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
       
    39 #include "DHCPIP4Msg.h" 
       
    40 #ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
       
    41 #include "dhcphwaddrmanager.h"
       
    42 #endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
       
    43 using namespace DHCPv4;
       
    44 #endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS			
       
    45 
       
    46 struct TDHCPv4Persistent : public Meta::SMetaData
       
    47 {
       
    48 	TDHCPv4Persistent() : 
       
    49 		iTaskStartedAt( 0 ),
       
    50 		iCurrentAddress(KInetAddrNone,KInetPortNone),
       
    51 		iLeaseTime(0)
       
    52 		{
       
    53 		}
       
    54 
       
    55 	TTime iTaskStartedAt;
       
    56 	TInetAddr iCurrentAddress;
       
    57 	TUint32 iLeaseTime;
       
    58 
       
    59 	DATA_VTABLE
       
    60 };
       
    61 
       
    62 START_ATTRIBUTE_TABLE( TDHCPv4Persistent, KDHCPv4Persinstence, KDHCPv4PersinstenceId )
       
    63 	REGISTER_ATTRIBUTE( TDHCPv4Persistent, iTaskStartedAt, TMetaTime )
       
    64 	REGISTER_ATTRIBUTE( TDHCPv4Persistent, iCurrentAddress, TMeta<TInetAddr> )
       
    65 	REGISTER_ATTRIBUTE( TDHCPv4Persistent, iLeaseTime, TMetaNumber )
       
    66 END_ATTRIBUTE_TABLE()
       
    67 
       
    68 CDHCPIP4Control::~CDHCPIP4Control()
       
    69 	{
       
    70 	}
       
    71 
       
    72 void CDHCPIP4Control::ConfigureL(const TConnectionInfo& aInfo, const RMessage2* aMessage)
       
    73 /**
       
    74   * Open and attach to the RConnection
       
    75   *
       
    76   * @internalTechnology
       
    77   */
       
    78 	{
       
    79    CDHCPControl::ConfigureL( aInfo, aMessage );
       
    80 	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4Control::ConfigureL")));
       
    81 	
       
    82 	iDhcpDb = new (ELeave) CDHCPDb( TPtrC( SERVICE_IP_DNS_ADDR_FROM_SERVER ),
       
    83 													TPtrC( SERVICE_IP_NAME_SERVER1 ),
       
    84 													TPtrC( SERVICE_IP_NAME_SERVER2 )); //for both version for the time being see the class TDHCPIP4Db coments
       
    85 	FindInterfaceNameL(aInfo,KAfInet);
       
    86 #ifdef SYMBIAN_NETWORKING_DHCPSERVER
       
    87 #ifndef SYMBIAN_NETWORKING_ADDRESS_PROVISION
       
    88 	iDhcpStateMachine = CDHCPIP4StateMachine::NewL(iEsock, iConnection, iInterfaceName,iDHCPServerImpl);
       
    89 #else
       
    90 	iDhcpHwAddrManager = CDhcpHwAddrManager::NewL();
       
    91 	iDhcpStateMachine = CDHCPIP4StateMachine::NewL(iEsock, iConnection, iInterfaceName,iDhcpHwAddrManager, iDHCPServerImpl);
       
    92 #endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
       
    93 #else 
       
    94 	iDhcpStateMachine = CDHCPIP4StateMachine::NewL(iEsock, iConnection, iInterfaceName);
       
    95 #endif 	// SYMBIAN_NETWORKING_DHCPSERVER		
       
    96 	TDHCPv4Persistent pers;
       
    97 	iStaticAddress = !iDhcpDb->ReadL(*iDhcpStateMachine, pers);
       
    98 
       
    99 
       
   100 	//initialise relevant data
       
   101 	TTimeIntervalSeconds seconds = static_cast<TInt>(pers.iLeaseTime);
       
   102 	iDhcpDb->iLeaseExpiresAt = pers.iTaskStartedAt + seconds;
       
   103 	DhcpStateMachine()->iLeaseTime = pers.iLeaseTime;
       
   104 	iDhcpStateMachine->SetCurrentAddress( pers.iCurrentAddress );
       
   105 	DhcpStateMachine()->iMaxRetryCount = 2; //Max retry count for the first run is set to 2
       
   106 
       
   107 
       
   108 	TInetAddr existingGlobalAddr = iDhcpStateMachine->GetInterfaceGlobalAddress();
       
   109 
       
   110 	if( ! existingGlobalAddr.IsUnspecified() )
       
   111 		{
       
   112 		// there was an existing address on the interface, regardless of commsdat preference..
       
   113 		//  so force inform.
       
   114 		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Interface already has global address. Forcing inform mode.")));
       
   115 		iDhcpStateMachine->SetCurrentAddress( existingGlobalAddr );
       
   116 		iStaticAddress = ETrue;
       
   117 		}
       
   118 	else
       
   119 		{
       
   120 		if(iStaticAddress)
       
   121 			{
       
   122 			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Interface has a static address from commsdat. Proceeding in inform mode.")));
       
   123 			}
       
   124 		else
       
   125 			{
       
   126 			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Interface has no global address yet. Proceeding in discover mode.")));
       
   127 			}
       
   128 		}
       
   129 
       
   130 	CDHCPControl::ConfigureL(iStaticAddress);
       
   131 	}
       
   132 
       
   133 void CDHCPIP4Control::Cancel()
       
   134 	{
       
   135 	iClientShouldCompleteWhenLinkLocalCreated = EFalse;
       
   136 
       
   137 	// Call the base class.
       
   138 	CDHCPControl::Cancel();
       
   139    }
       
   140 
       
   141 void CDHCPIP4Control::BindingFinishedL()
       
   142 	{
       
   143 	CDHCPControl::BindingFinishedL();
       
   144 	TDHCPv4Persistent pers;
       
   145 	//get relevant data from statemachine
       
   146 	pers.iTaskStartedAt = DhcpStateMachine()->iStartedAquisitionAt;
       
   147 	pers.iCurrentAddress = DhcpStateMachine()->iCurrentAddress;
       
   148 	pers.iLeaseTime = DhcpStateMachine()->iLeaseTime;
       
   149 	TRAPD( ret, iDhcpDb->WriteL(*iDhcpStateMachine, pers) );
       
   150 	if (ret!=KErrNone)
       
   151 		{
       
   152 		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4Control::BindingFinishedL error: %d"),ret));
       
   153 		}
       
   154 	}
       
   155 
       
   156 void CDHCPIP4Control::TimerExpired()
       
   157 /**
       
   158   * Called by the timer to signal that the timer has expired
       
   159   *
       
   160   * @internalTechnology
       
   161   */
       
   162 	{
       
   163 	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPIP4Control::TimerExpired()")));
       
   164 
       
   165     CDHCPControl::TimerExpired();
       
   166 	
       
   167 	// In response to the rebind operation timing out, try to create
       
   168 	// a link local to allow local addressing (may not be supported
       
   169 	// by current interface's IPv4 link local option).  We cannot
       
   170 	// create the link local earlier (e.g., after a renew attempt
       
   171 	// times-out) because the link local will not be usable until
       
   172 	// the DHCP assigned address has been removed (randomly
       
   173 	// generated addresses are prioritised below non-randomly
       
   174 	// generated addresses during selection in the TCP/IP stack).
       
   175 	if( ( iState == EInitInProgress ) && iDhcpConfigListener && !iDhcpConfigListener->HaveLinkLocal() )
       
   176 		{
       
   177 		DhcpStateMachine()->CreateIPv4LinkLocal();
       
   178 		}
       
   179 	}
       
   180 
       
   181 TInt CDHCPIP4Control::HandleClientRequestL(TUint aName, TInt aValue)
       
   182 /**
       
   183   * Handles client requests made through RConnection
       
   184   * are handled here.  Currently its for renewing the lease time 
       
   185   * where client passes in a required timeout 
       
   186   * @see CDHCPControl::HandleClientRequestL
       
   187   *
       
   188   * @internalTechnology
       
   189   */
       
   190 	{
       
   191 	TBool deferAllowed = !iMessage;
       
   192 	TBool defer = EFalse;
       
   193 	
       
   194   	defer = CDHCPControl::HandleClientRequestL(aName, aValue);
       
   195 
       
   196 	if (aName == KConnAddrRenew && iState == ERenewInProgress && deferAllowed)
       
   197 		{//Rebind timeout
       
   198 		TTimeIntervalSeconds timeOut;
       
   199 		if(aValue > 0)
       
   200 			{
       
   201 			timeOut = aValue;
       
   202 			}
       
   203 		else
       
   204 			{
       
   205 			timeOut = (DhcpStateMachine()->iRebindTimeT2 - DhcpStateMachine()->iRenewalTimeT1 + 1);
       
   206 			}
       
   207       	iTimer->After(timeOut, *this);
       
   208       	defer = ETrue;
       
   209 		}
       
   210 	
       
   211 	return defer;
       
   212 	}	
       
   213 
       
   214 TInt CDHCPIP4Control::HandleClientRequestL(TUint aName)
       
   215 /**
       
   216   * Handles client requests specific for IP4
       
   217   *
       
   218   * @see CDHCPControl::HandleClientRequestL
       
   219   * @internalTechnology
       
   220   */
       
   221 	{
       
   222 	return CDHCPIP4Control::HandleClientRequestL(aName,0);
       
   223 	}
       
   224 
       
   225 /**
       
   226     Get raw option data (IP4 version).
       
   227     @param  pointer to the buffer descriptor for getting option data
       
   228 */
       
   229 void CDHCPIP4Control::HandleGetRawOptionDataL(TDes8* aDes)
       
   230 {
       
   231 	TDhcp4RawOptionDataPckg pckg(*aDes);
       
   232 		
       
   233 	TUint8 opCode = pckg.OpCode();
       
   234 	TPtr8 buf(pckg.Buf());
       
   235 	GetRawOptionDataL(opCode, buf);
       
   236 #ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
       
   237 	if (!iDhcpStateMachine->iDhcpInformAckPending)   
       
   238 		{
       
   239 #endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
       
   240 	pckg.SetBufLengthL(buf.Length());
       
   241 #ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
       
   242 		}
       
   243 #endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
       
   244 }
       
   245 
       
   246 void CDHCPIP4Control::TaskCompleteL( TInt aError )
       
   247 /**
       
   248   * TaskCompleteL function
       
   249   *
       
   250   * if this method returns ETrue then aStateMachine deletes itself.
       
   251   * In this case it does not ever return ETrue.
       
   252   * Called upon completion or when suspended.
       
   253   *
       
   254   * @see CStateMachine::iSuspendRequest comment
       
   255   * @internalTechnology
       
   256   */
       
   257 	{
       
   258 	// In response to the initialisation operation timing out,
       
   259 	// try to create a link local to allow local addressing (may
       
   260 	// not be supported by current interface's IPv4 link local
       
   261 	// option).
       
   262 	if( ( aError == KErrTimedOut ) &&
       
   263 		( iState == EInitInProgress ) &&
       
   264 		!iStaticAddress &&
       
   265 		iDhcpConfigListener &&
       
   266 		!iDhcpConfigListener->HaveLinkLocal() )
       
   267 		{
       
   268 		if( DhcpStateMachine()->CreateIPv4LinkLocal() == KErrNone )
       
   269 			{
       
   270 			iClientShouldCompleteWhenLinkLocalCreated = ETrue;
       
   271 			//Link Local Address has been taken & return here itself
       
   272 			CDHCPControl::TaskCompleteL(aError);
       
   273 			return;
       
   274 			}
       
   275 		}
       
   276 	if((DhcpStateMachine()->iRetryDhcpIpCount >= KDHCPv4MaxRetryCount) && iState == EDeclineInProgress )
       
   277 		{
       
   278 		if( DhcpStateMachine()->CreateIPv4LinkLocal() == KErrNone )
       
   279 			{
       
   280 			iClientShouldCompleteWhenLinkLocalCreated = ETrue;
       
   281 			//Link Local Address has been taken & return here itself
       
   282  			CDHCPControl::TaskCompleteL(KErrNone);
       
   283  			return;
       
   284 			}
       
   285 		
       
   286 		}
       
   287 	// Call the base class.
       
   288 	CDHCPControl::TaskCompleteL( aError );
       
   289 	}
       
   290 	
       
   291 void CDHCPIP4Control::LinkLocalCreated()
       
   292 /**
       
   293   * LinkLocalCreated function
       
   294   *
       
   295   * If iClientShouldCompleteWhenLinkLocalCreated is ETrue we need to complete the
       
   296   * client messages as the link local has been created and the interface is now
       
   297   * ready for use.
       
   298   *
       
   299   * @internalTechnology
       
   300   */
       
   301 	{
       
   302 	if( iClientShouldCompleteWhenLinkLocalCreated )
       
   303 		{
       
   304 		iClientShouldCompleteWhenLinkLocalCreated = EFalse;
       
   305 		
       
   306 		CompleteClientConfigureMessage(KErrNone);
       
   307 		// don't complete any outstanding ioctl yet..
       
   308 		}
       
   309 	}
       
   310 
       
   311 void CDHCPIP4Control::GetRawOptionDataL(TUint aOpCode, TPtr8& aPtr)
       
   312 	{
       
   313 #ifdef SYMBIAN_NETWORKING_DHCPSERVER
       
   314 	if(iValidMsg.Length()==0 && iDHCPServerImpl)
       
   315 		{
       
   316 		GetRawOptionDataFromDNSBufL(aPtr);
       
   317 		return;
       
   318 		}
       
   319 #endif // SYMBIAN_NETWORKING_DHCPSERVER
       
   320 	HBufC8* buf = NULL;
       
   321 	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
       
   322 	CleanupClosePushL(msg);
       
   323 	TPtr8 ptr( const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length() );
       
   324 	msg.iRecord.ParseL(ptr); //no check necessary
       
   325 	DHCPv4::COptionNode* pOption = msg.iOptions.FindOption(static_cast<TUint8>(aOpCode));
       
   326 	if (!pOption)
       
   327 		{
       
   328 #ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
       
   329 		CleanupStack::PopAndDestroy();
       
   330 		TUint8 tempOpt=aOpCode;
       
   331 		TPtr8 optPtr(&tempOpt,1,1);
       
   332 		return(RequestInformOrCompleteCallL(optPtr));
       
   333 #else
       
   334 		User::Leave(KErrNotFound);
       
   335 #endif // SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
       
   336 		}
       
   337 	ptr.Set(pOption->GetBodyDes());
       
   338 	if (ptr.Length() > aPtr.MaxLength())
       
   339 		{
       
   340 		User::Leave(KErrOverflow);
       
   341 		}
       
   342 	aPtr.Copy(ptr);
       
   343 	CleanupStack::PopAndDestroy();
       
   344 	}
       
   345 
       
   346 #ifdef SYMBIAN_NETWORKING_DHCPSERVER
       
   347 
       
   348 void CDHCPIP4Control::GetRawOptionDataFromDNSBufL(TPtr8& aPtr)
       
   349 	{
       
   350 	if(iValidMsg.Length() == 0)
       
   351 		{
       
   352 		if (iDNSRawOption->Des().Length() > aPtr.MaxLength())
       
   353 			{
       
   354 			User::Leave(KErrOverflow);
       
   355 			}
       
   356 		aPtr.Copy(iDNSRawOption->Des());
       
   357 		}
       
   358 	}
       
   359 
       
   360 void CDHCPIP4Control::HandleSetRawOptionCodeL(TDes8* aDes)
       
   361 	{
       
   362 	if(iValidMsg.Length() == 0)
       
   363 		{
       
   364 		iDNSRawOption = HBufC8::NewL(aDes->Length());
       
   365 		iDNSRawOption->Des() = *aDes;
       
   366 		}
       
   367 	else
       
   368 		{
       
   369 		SetRawOptionCodeL(aDes);	
       
   370 		}
       
   371 	}
       
   372 
       
   373 void CDHCPIP4Control::SetRawOptionCodeL(TDes8* aDes)
       
   374 	{
       
   375 	HBufC8* buf = NULL;
       
   376 	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
       
   377 	CleanupClosePushL(msg);
       
   378 	TPtr8 ptr( const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length() );
       
   379 	msg.iRecord.ParseL(ptr); //no check necessary
       
   380 	
       
   381 	TDhcp4RawOptionDataPckg pckg(*aDes);
       
   382 	DHCPv4::TDHCPOptionCodes opcode = static_cast<DHCPv4::TDHCPOptionCodes>(pckg.OpCode());
       
   383 	
       
   384 	DHCPv4::COptionNode* pOption = msg.iOptions.FindOption(opcode);
       
   385 	if (!pOption)
       
   386 		{
       
   387 		User::Leave(KErrNotFound);
       
   388 		}
       
   389 		
       
   390 	TPtr8 ptr2(reinterpret_cast<TUint8*>(aDes),aDes->Length());
       
   391 	
       
   392 	pOption->SetBody(ptr2);	
       
   393 	CleanupStack::PopAndDestroy(); // msg
       
   394 	}
       
   395 #endif // SYMBIAN_NETWORKING_DHCPSERVER
       
   396 
       
   397 void CDHCPIP4Control::HandleGetSipServerAddrL(TDes8* aDes)
       
   398 	{	
       
   399 	if (aDes->Length() < static_cast<TInt>(sizeof(SSipServerAddr)))
       
   400 		{
       
   401 		User::Leave(KErrArgument);
       
   402 		}
       
   403 
       
   404 	SSipServerAddr* sipServerAddr = 
       
   405 		reinterpret_cast<SSipServerAddr*>(const_cast<TUint8*>(aDes->Ptr()));
       
   406 
       
   407 	HBufC8* buf = NULL;
       
   408 	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
       
   409 	CleanupClosePushL(msg);
       
   410 	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
       
   411 	msg.iRecord.ParseL(ptr);
       
   412 	DHCPv4::COptionNode* sipServerOption = msg.iOptions.FindOption(DHCPv4::EDHCPSIPServers);
       
   413 
       
   414 	if(sipServerOption)
       
   415 		{
       
   416 		TUint8* headerPtr = sipServerOption->Ptr();		
       
   417 		
       
   418 		TUint encoding = headerPtr[DHCPv4::KDhcpSipEncodingOffset];
       
   419 		TUint length = headerPtr[DHCPv4::KDhcpSipLengthOffset];
       
   420 		
       
   421 		if(encoding != DHCPv4::KDhcpSipEncodingAddresses)
       
   422 			{
       
   423 			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerAddrL: Client trying to fetch a SIP address when only a SIP domain is known")));
       
   424 			User::Leave( KErrNotFound );
       
   425 			}
       
   426 		if((TUint)sipServerAddr->index >= (length / KIp4AddrByteLength))
       
   427 			{
       
   428 			__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)));
       
   429 			User::Leave( KErrNotFound );
       
   430 			}
       
   431 		
       
   432 		TUint addrOffset = sipServerAddr->index * KIp4AddrByteLength;
       
   433 		
       
   434 		TUint8* bodyPtr = sipServerOption->GetBodyPtr();
       
   435 		TUint32 copiedValue;
       
   436 		// Grab ip address from option body at given offset, +1 used to skip the encoding boolean used for sip
       
   437 		Mem::Copy(&copiedValue,(bodyPtr + addrOffset+1),4);  
       
   438 		// swap around ip address as in BigEndian form
       
   439 		copiedValue = ByteOrder::Swap32(copiedValue); 
       
   440 		sipServerAddr->address.SetAddress(copiedValue);   
       
   441 		}
       
   442 	else
       
   443 		{
       
   444 		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerAddrL: Client tried to fetch a SIP option but none has (yet) been received")));
       
   445 		User::Leave(KErrNotFound);
       
   446 		}	
       
   447 	CleanupStack::PopAndDestroy();
       
   448 	}
       
   449 
       
   450 #ifdef SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
       
   451 void CDHCPIP4Control::GetDhcpHdrSiaddrL(TDes8& aNxtAddress)
       
   452 /**
       
   453   * The GetDhcpHdrSiaddr function
       
   454   *
       
   455   * Fetches the Siaddr
       
   456   *
       
   457   * @param aNxtAddress Next server IPAddress fetched from the DHCP Server
       
   458   * @internalTechnology
       
   459   */
       
   460 	{
       
   461 	if (aNxtAddress.Length() < static_cast<TInt>(sizeof(TConnectionAddress)))
       
   462 		{
       
   463 		User::Leave(KErrArgument);
       
   464 		}
       
   465 	TConnectionAddress* ptr = (TConnectionAddress*)aNxtAddress.Ptr();
       
   466 	TInetAddr* addrPtr = new(&(ptr->iAddr))TInetAddr;	
       
   467 	//ptr->iAddr is just some memory in aDes. There is no guarantee that it will be a
       
   468 	//valid TInetAddr (or even a valid TDes) so what we do here is just run a constructor
       
   469 	//on this already valid memory block and we are now guaranteed to have a valid 
       
   470 	//TInetAddr - NO MEMORY IS ACTUALLY ALLOCATED BY NEW HERE - see base code for more 
       
   471 	//details	
       
   472 	
       
   473 	//Parse the iValidMsg
       
   474 	HBufC8* buf = NULL;
       
   475 	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
       
   476 	CleanupClosePushL(msg);
       
   477 	TPtr8 msgPtr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
       
   478 	msg.iRecord.ParseL(msgPtr);
       
   479 	
       
   480 	//Extract the server address
       
   481 	addrPtr->SetAddress(msg.GetSIAddr());
       
   482 	
       
   483 	CleanupStack::PopAndDestroy();
       
   484 	}
       
   485 
       
   486 void CDHCPIP4Control::GetDhcpHdrSnameL(TDes8& aHdrSvrName)
       
   487 /**
       
   488   * The GetDhcpHdrSname function
       
   489   *
       
   490   * Fetches the Sname
       
   491   *
       
   492   * @param aHdrSvrName Next server name fetched from the DHCP Server. 
       
   493   * @internalTechnology
       
   494   */
       
   495 	{
       
   496 	HBufC8* buf = NULL;
       
   497 	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
       
   498 	CleanupClosePushL(msg);
       
   499 	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
       
   500 	msg.iRecord.ParseL(ptr);
       
   501 	if (msg.GetSName().Length() > aHdrSvrName.MaxLength())
       
   502 	{
       
   503 		User::Leave(KErrOverflow);
       
   504 	}
       
   505 	aHdrSvrName=msg.GetSName();
       
   506 	//SetLength otherwise received string length will be 64 by default, truncate to end of string.
       
   507 	aHdrSvrName.SetLength(aHdrSvrName.Locate('\0'));
       
   508 
       
   509 	CleanupStack::PopAndDestroy(&msg);
       
   510 	}
       
   511 	
       
   512 void CDHCPIP4Control::HandleGetTftpServerAddrL(TDes8& aDes) 
       
   513 /**
       
   514   * The HandleGetTftpServerAddrL function
       
   515   *
       
   516   * Fetches the Tftp Server Address
       
   517   * @param aDes Buffer returned contains a list of ip addresses each of 4 bytes.
       
   518   *
       
   519   * @internalTechnology
       
   520   */
       
   521 	{
       
   522 	if (aDes.Length() < static_cast<TInt>(sizeof(STftpServerAddr)))
       
   523 		{
       
   524 		User::Leave(KErrArgument);
       
   525 		}
       
   526 
       
   527 	STftpServerAddr* tftpServerAddr = 
       
   528 		reinterpret_cast<STftpServerAddr*>(const_cast<TUint8*>(aDes.Ptr()));
       
   529 
       
   530 	HBufC8* buf = NULL;
       
   531 	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
       
   532 	CleanupClosePushL(msg);
       
   533 	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
       
   534 	msg.iRecord.ParseL(ptr);
       
   535 	DHCPv4::COptionNode* tftpServerOption = msg.iOptions.FindOption(DHCPv4::EDHCPTftpServers);
       
   536 	if(tftpServerOption)
       
   537 		{
       
   538 		
       
   539 		TUint8 len=tftpServerOption->GetItemLength()-2;//subtract 2 bytes becz length include message opcode and message opcode length 
       
   540 		
       
   541 		TUint addrOffset = tftpServerAddr->index * KIp4AddrByteLength;
       
   542 		
       
   543 		if (addrOffset>len)
       
   544 			{
       
   545 			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetTftpServerAddrL: Client tried to fetch a invalid index of Tftp Address which is not present")));
       
   546 			iDhcpStateMachine->iDhcpInformAckPending=EFalse;
       
   547 			User::Leave(KErrNotFound);	
       
   548 			
       
   549 			}
       
   550 		
       
   551 		TUint8* bodyPtr = tftpServerOption->GetBodyPtr();
       
   552 				
       
   553 		TUint32 copiedValue;
       
   554 		// Grab ip address from option body at given offset.
       
   555 		Mem::Copy(&copiedValue,(bodyPtr + addrOffset),4);  
       
   556 		// swap around ip address as in BigEndian form/		copiedValue = ByteOrder::Swap32(copiedValue); 
       
   557 		copiedValue = ByteOrder::Swap32(copiedValue); 
       
   558 		tftpServerAddr->address.SetAddress(copiedValue);   
       
   559 		}
       
   560 	else //check inform to be made or not..or return
       
   561 		{
       
   562 		CleanupStack::PopAndDestroy(); //pop buffer ..we are going to return immediately
       
   563 		TUint8 opt=DHCPv4::EDHCPTftpServers;
       
   564 		TPtr8 optPtr(&opt,1,1);
       
   565 		return(RequestInformOrCompleteCallL(optPtr));
       
   566 		}	
       
   567 	iDhcpStateMachine->iDhcpInformAckPending=EFalse;
       
   568 	CleanupStack::PopAndDestroy();
       
   569 	
       
   570 }
       
   571 
       
   572 void CDHCPIP4Control::HandleGetTftpServerNameL(TDes8& aTftpSvrName)
       
   573 /**
       
   574   * The HandleGetTftpServerName function
       
   575   *
       
   576   * Fetches the Tftp Server Name
       
   577   *
       
   578   * @param aTftpSvrName Tftp Server Name fetched from the DHCP Server.
       
   579   * @internalTechnology
       
   580   */
       
   581 	{
       
   582 	HBufC8* buf = NULL;
       
   583 	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
       
   584 	CleanupClosePushL(msg);
       
   585 	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
       
   586 	msg.iRecord.ParseL(ptr);
       
   587 	DHCPv4::COptionNode* tftpOption = msg.iOptions.FindOption(DHCPv4::EDHCPTftpServerName);
       
   588 	if(tftpOption)
       
   589 		{
       
   590 		if (aTftpSvrName.MaxLength()<tftpOption->GetItemLength())
       
   591 			{
       
   592 			iDhcpStateMachine->iDhcpInformAckPending=EFalse;
       
   593 			User::Leave(KErrOverflow);
       
   594 			}
       
   595 		else	
       
   596 			{
       
   597 			aTftpSvrName.Copy(tftpOption->GetBodyDes());
       
   598 			}
       
   599 		}
       
   600 	else 
       
   601 		{
       
   602 		//To check if DHCP Sname Option is overloaded
       
   603 		tftpOption = msg.iOptions.FindOption(DHCPv4::EDHCPOptionOverload);
       
   604 		if(tftpOption)
       
   605 			{
       
   606 			if(	msg.iOptions.GetOptionOverload() == DHCPv4::EDHCPSname)
       
   607 				{
       
   608 				GetDhcpHdrSnameL(aTftpSvrName);
       
   609 				}
       
   610 			}
       
   611 		else//now issue Inform Request for option 66 or return now..
       
   612 			{
       
   613 			CleanupStack::PopAndDestroy(); //pop buffer ..we are going to return immediately
       
   614 			TUint8 opt=DHCPv4::EDHCPTftpServerName;
       
   615 			TPtr8 optPtr(&opt,1,1);
       
   616 			return(RequestInformOrCompleteCallL(optPtr));
       
   617 			}
       
   618 		}
       
   619 		iDhcpStateMachine->iDhcpInformAckPending=EFalse;
       
   620 		CleanupStack::PopAndDestroy();	
       
   621 	}	
       
   622 
       
   623 void CDHCPIP4Control::RequestInformOrCompleteCallL(TPtr8& aOpcodePtr)	
       
   624 /**
       
   625   * The RequestInformOrCompleteCallL function
       
   626   *
       
   627   * Checks DHCPINFORM message should be sent or not
       
   628   * @param aOpcodePtr  pointer to the opcode list to be updated  in iSavedExtraParameters
       
   629   * @internalTechnology
       
   630   */
       
   631 	{
       
   632 
       
   633 	if (!iDhcpStateMachine->iDhcpInformAckPending)
       
   634 		{
       
   635 		if (!iDhcpStateMachine->iSavedExtraParameters.Length())
       
   636 			{
       
   637 			iDhcpStateMachine->iSavedExtraParameters.CreateL(aOpcodePtr);
       
   638 			}
       
   639 		else
       
   640 			{
       
   641 			iDhcpStateMachine->iSavedExtraParameters.ReAllocL(iDhcpStateMachine->iSavedExtraParameters.Length()+aOpcodePtr.Length());
       
   642 			iDhcpStateMachine->iSavedExtraParameters.Append(aOpcodePtr);
       
   643 			}	
       
   644 	
       
   645 			static_cast<CDHCPIP4StateMachine*>(iDhcpStateMachine)->StartInformL( this );
       
   646 			iDhcpStateMachine->iDhcpInformAckPending=ETrue;
       
   647   			iState = EInformInProgress;
       
   648 		}
       
   649 	else
       
   650 		{
       
   651 		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8(" RequestInformOrCompleteCallL::Client tried to fetch a  option but none has (yet) been received")));
       
   652 		iDhcpStateMachine->iDhcpInformAckPending=EFalse;
       
   653 		User::Leave(KErrNotFound);	
       
   654 		}
       
   655 	}
       
   656 	
       
   657 	
       
   658 
       
   659 void CDHCPIP4Control::HandleGetMultipleParamsL(TDes8& aDes)
       
   660 /**
       
   661   * The HandleGetMultipleParamsL function
       
   662   *
       
   663   * Fetches the required raw option parameter buffer.
       
   664   * Buffer contains list of parameter options followed by msg opcode, len, data..
       
   665   * If any of the parameters are not found, DHCPINFORM message will be sent.
       
   666   *	Filled Returned Buffer is as shown in fig..
       
   667   * @code
       
   668   *		  -----------------------------------------------------
       
   669   *		 |No of |      |Data   |      |       |Data   |        |
       
   670   *	 	 |OpCode|OP1   |length1|Data1 |  OP2  |Length2|Data2   |
       
   671   *		 |      |      |       |      |       |       |        |
       
   672   *		  ----------------------------------------------------- 
       
   673   * @endcode
       
   674   * @param aDes Pointer to the buffer descriptor for getting option data
       
   675   * @internalTechnology
       
   676   */
       
   677 	{
       
   678 	HBufC8 *saveBuf=NULL, *buffer=NULL;
       
   679 	TUint8 *headerPtr;
       
   680 	TInt numOfOpcodes=0;
       
   681 	TInt totalLength=0,opcodeLength=aDes.Length();
       
   682 	TInt maxLength=aDes.MaxLength();
       
   683 	TUint8 opcode;
       
   684 	TBool allFound=ETrue;
       
   685 	
       
   686 	DHCPv4::CDHCPMessageHeaderIP4 msgSaved(saveBuf);
       
   687 	TPtr8 savedPtr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
       
   688 	CleanupClosePushL(msgSaved);
       
   689 	msgSaved.iRecord.ParseL(savedPtr);
       
   690 
       
   691 
       
   692 	//The below for loop checks all the required opcode data is present or not
       
   693 	//The message opcode data is not present in the iValidMsg buffer,the corresponding 
       
   694 	//opcodes are stored in iCurrentParameters for sending it in DHCPINFORM message
       
   695 	for(TInt i=0;i<opcodeLength;i++)
       
   696 		{
       
   697 		opcode=*(aDes.Ptr()+i); //search required opcode is present or not, one by one
       
   698 		DHCPv4::COptionNode* findNode = msgSaved.iOptions.FindOption(opcode);
       
   699 		if (findNode )
       
   700 			{
       
   701 			TInt bufLength=findNode->GetItemLength();
       
   702 			totalLength+=bufLength;
       
   703 			if ((totalLength+1) > maxLength)
       
   704 				{
       
   705 				totalLength-=bufLength;
       
   706 				continue; //current buffer is too big..so hope next buffer is small
       
   707 				}
       
   708 			if (!buffer)
       
   709 				{
       
   710 				buffer=HBufC8::NewLC(totalLength + 1);//+1 is extra byte to store number of opcodes
       
   711 				buffer->Des().Append(KNoChar);
       
   712 				}
       
   713 			else
       
   714 				{
       
   715 				buffer=buffer->ReAllocL(totalLength + 1);
       
   716 				CleanupStack::Pop();//buffer as ptr address has changed
       
   717 		        CleanupStack::PushL(buffer);
       
   718 				}
       
   719 			headerPtr = findNode->Ptr(); 
       
   720 			++numOfOpcodes;
       
   721 			buffer->Des().Append(headerPtr,bufLength);
       
   722 			}
       
   723 		else
       
   724 			{
       
   725 			//If atleast one opcode, among the requested, is not found then request through 
       
   726 			//DHCP INFORM message by calling RequestInformOrCompleteCallL
       
   727 			allFound=EFalse;
       
   728 			}
       
   729 		}
       
   730 	
       
   731 	if (allFound ) //everything is present..just return call now itself..
       
   732 		{
       
   733 		if ((totalLength + 1) > maxLength)
       
   734 			{
       
   735 			User::Leave(KErrOverflow);
       
   736 			}
       
   737 		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.
       
   738 			{
       
   739 			aDes.Copy(buffer->Ptr(), buffer->Length());
       
   740 			TBuf8<1> dummy;
       
   741 			dummy.FillZ(1);
       
   742 			dummy[0]=numOfOpcodes;
       
   743 			aDes.Replace(0,1,dummy);//update number of opcodes collected
       
   744 			}
       
   745 		}
       
   746 	else
       
   747 		{
       
   748 		TPtr8 opcodePtr(const_cast<TUint8*>(aDes.Ptr()),opcodeLength);
       
   749 		opcodePtr.SetLength(opcodeLength);
       
   750 		RequestInformOrCompleteCallL(opcodePtr);	
       
   751 		}	
       
   752 	
       
   753 	if (buffer)
       
   754 		{
       
   755 		CleanupStack::PopAndDestroy(buffer);
       
   756 		}
       
   757 
       
   758 	CleanupStack::PopAndDestroy(&msgSaved);
       
   759 
       
   760 	}
       
   761 
       
   762 
       
   763 TInt CDHCPIP4Control::InformCompleteRequestHandlerL()
       
   764 /**
       
   765   * The InformCompleteRequestHandlerL function
       
   766   * 
       
   767   * The function will be called after the DHCPACK message is received, and 
       
   768   * iValidMsg buffer has been updated. 
       
   769   * Looks for the requested options present or not and appropriately calls 
       
   770   * the function handlers
       
   771   *
       
   772   * @return KErrNone if the required data option is found else corresponding error code.
       
   773   * @internalTechnology
       
   774   */
       
   775 	{
       
   776 
       
   777 	TUint optionName = iMessage->Int1();
       
   778 	TInt length      = iMessage->Int3();
       
   779 
       
   780 	HBufC8 *buff=HBufC8::NewMaxLC(length) ;
       
   781 	TPtr8 ptr(buff->Des());
       
   782 	iMessage->ReadL(2, ptr);
       
   783 
       
   784 	
       
   785 	switch(optionName)
       
   786 		{
       
   787 		case KConnGetDhcpRawOptionData:
       
   788 			{
       
   789 			HandleGetRawOptionDataL(&ptr);
       
   790 			iMessage->WriteL(2,ptr);
       
   791 			break;
       
   792 			}
       
   793 		
       
   794 		case KConnDhcpGetMultipleParams :
       
   795 			{
       
   796 			HandleGetMultipleParamsL(ptr);
       
   797 			iMessage->WriteL(2,ptr);
       
   798 			break;
       
   799 			}
       
   800 	
       
   801 		case KConnGetTftpServerAddr:
       
   802 			{
       
   803 			HandleGetTftpServerAddrL(ptr);
       
   804 			iMessage->WriteL(2,ptr);
       
   805 			break;
       
   806 			}
       
   807 		
       
   808 		case KConnGetTftpServerName:
       
   809 			{
       
   810 			HandleGetTftpServerNameL(ptr);
       
   811 			iMessage->WriteL(2,ptr);
       
   812 			break;
       
   813 			}
       
   814 		
       
   815 		default:
       
   816 			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("InformCompleteRequestHandlerL : default unhandled optino Name")));
       
   817 			break;	
       
   818 	
       
   819 		}
       
   820 	iDhcpStateMachine->iDhcpInformAckPending=EFalse;
       
   821 	CleanupStack::PopAndDestroy(buff);
       
   822 	return KErrNone;
       
   823 	 
       
   824 	}
       
   825 #endif//SYMBIAN_NETWORKING_DHCP_MSG_HEADERS
       
   826 
       
   827 
       
   828 void CDHCPIP4Control::HandleGetSipServerDomainL(TDes8* aDes)
       
   829 	{
       
   830 	if (aDes->Length() < static_cast<TInt>(sizeof(SSipServerDomain)))
       
   831 		{
       
   832 		User::Leave(KErrArgument);
       
   833 		}
       
   834 
       
   835 	SSipServerDomain* sipServerDomain = 
       
   836 		reinterpret_cast<SSipServerDomain*>(const_cast<TUint8*>(aDes->Ptr()));
       
   837 
       
   838 	HBufC8* buf = NULL;
       
   839 	DHCPv4::CDHCPMessageHeaderIP4 msg(buf);
       
   840 	CleanupClosePushL(msg);
       
   841 	TPtr8 ptr(const_cast<TUint8*>(iValidMsg.Ptr()), iValidMsg.Length(), iValidMsg.Length());
       
   842 	msg.iRecord.ParseL(ptr);
       
   843 	DHCPv4::COptionNode* sipServerOption = msg.iOptions.FindOption(DHCPv4::EDHCPSIPServers);
       
   844 
       
   845 	if(sipServerOption)
       
   846 		{
       
   847 		TUint8* headerPtr = sipServerOption->Ptr();
       
   848 		
       
   849 		TUint encoding = headerPtr[DHCPv4::KDhcpSipEncodingOffset];
       
   850 
       
   851 		if(encoding != DHCPv4::KDhcpSipEncodingDomains)
       
   852 			{
       
   853 			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerDomainL: Client trying to fetch a SIP domain when only a SIP address is known")));
       
   854 			User::Leave( KErrNotFound );
       
   855 			}
       
   856 
       
   857 		CDomainNameCodec* domainNameDecoder = new(ELeave) CDomainNameCodec();
       
   858 		CleanupStack::PushL(domainNameDecoder);
       
   859 		TPtr8 ptr = sipServerOption->GetBodyDes();
       
   860 		ptr.Set((TUint8*)(ptr.Ptr()+1),ptr.Length()-1,ptr.MaxLength()-1);
       
   861 		domainNameDecoder->DecodeL(ptr);
       
   862 
       
   863 		if(sipServerDomain->index < (TInt)domainNameDecoder->NumDomainNames())
       
   864 			{
       
   865 			TDomainName domainName = (*domainNameDecoder)[sipServerDomain->index];
       
   866 			sipServerDomain->domainName.Copy(domainName);
       
   867 			}
       
   868 		else
       
   869 			{
       
   870 			__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()));
       
   871 			User::Leave(KErrNotFound);
       
   872 			}
       
   873 
       
   874 		CleanupStack::PopAndDestroy();
       
   875 		}
       
   876 	else
       
   877 		{
       
   878 		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("HandleGetSipServerDomainL: Client tried to fetch a SIP option but none has (yet) been received")));
       
   879 		User::Leave(KErrNotFound);
       
   880 		}
       
   881 	CleanupStack::PopAndDestroy();
       
   882 	}
       
   883 
       
   884 
       
   885 
       
   886 TBool CDHCPIP4Control::ShouldInformAfterFailedInit(void)
       
   887 	{
       
   888 	// if has no global address, should not inform
       
   889 	return iDhcpStateMachine->GetInterfaceGlobalAddress().IsUnspecified() ? EFalse : ETrue ;
       
   890 	}
       
   891