tcpiputils/dhcp/src/DHCPIP6Msg.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dhcp/src/DHCPIP6Msg.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,473 @@
+// 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 Message format
+// 
+//
+
+/**
+ @file DHCPIP6Msg.cpp
+ @internalTechnology
+*/
+
+#include "DHCPIP6IA.h"
+#include "DHCPAuthentication.h"
+#include "DHCP_Std.h"
+
+using namespace DHCPv6;
+
+COptionNode::~COptionNode()
+	{
+	delete iNext;
+	}
+
+COptionNode* COptionNode::NewL()
+	{
+	return new(ELeave)COptionNode(NULL);
+	}
+
+COptionNode* CDHCPOptionAny::NewL()
+	{
+	return new(ELeave)CDHCPOptionAny(NULL);
+	}
+
+COptionNode* CDHCPOptionStatusCode::NewL()
+	{
+	return new(ELeave)CDHCPOptionStatusCode();
+	}
+
+COptionNode* CDHCPOptionRequestOption::NewL()
+	{
+	return new(ELeave)CDHCPOptionRequestOption();
+	}
+
+struct SOptionHeader
+	{
+	TInt iCode;
+#ifdef __FLOG_ACTIVE
+	const TText8* iName;
+#endif
+	};
+
+#ifdef __FLOG_ACTIVE
+const TInt KNumberOfSupportedOptions = 23;
+const SOptionHeader KOptions[KNumberOfSupportedOptions + 1]= 
+	{   //iCode,                     iName
+		{EClientId,          _S8( "EClientId" )},
+		{EServerId,          _S8( "EServerId" )},
+		{EIaNa,              _S8( "EIaNa" )},
+		{EIaTa,              _S8( "EIaTa" )},
+		{EIaAddr,            _S8( "EIaAddr" )},
+		{EOro,               _S8( "EOro" )},
+		{EPreference,        _S8( "EPreference" )},
+		{EElapsedTime,       _S8( "EElapsedTime" )},
+		{ERelayMsg,          _S8( "ERelayMsg" )},
+		{EAuthentication,    _S8( "EAuthentication" )},
+		{EUnicast,           _S8( "EUnicast" )},
+		{EStatusCode,        _S8( "EStatusCode" )},
+		{ERapidCommit,       _S8( "ERapidCommit" )},
+		{EUserClass,         _S8( "EUserClass" )},
+		{EVendorClass,       _S8( "EVendorClass" )},
+		{EVendorOpts,        _S8( "EVendorOpts" )},
+		{EInterfaceId,       _S8( "EInterfaceId" )},
+		{EReconfMsg,         _S8( "EReconfMsg" )},
+		{EReconfAccept,      _S8( "EReconfAccept" )},
+		{ESipServerD,        _S8( "ESipServerD" )},
+		{ESipServerA,        _S8( "ESipServerA" )},
+		{EDNSServers,        _S8( "EDNSServers" )},
+		{EDomainList,        _S8( "EDomainList" )},
+		{0,                          _S8( "EUnknown" )}
+	};
+
+void COptionNode::Dump(const TDesC& aTag, const TDesC& aFile)
+	{
+	RFileLogger f;
+	if (f.Connect() == KErrNone)
+		{
+		f.CreateLog(aTag, aFile, EFileLoggingModeAppend);
+		TInt i = 0;
+      TInt nCode = OpCode();
+		while (KOptions[i].iCode != nCode && ++i < KNumberOfSupportedOptions){/*do nothing*/}
+		
+		f.WriteFormat(_L8("Option Code: %s, length: %d"), KOptions[i].iName, nCode);
+		if (GetItemLength() > KOptionHeaderLength)
+			{
+			f.HexDump(NULL, NULL, GetBodyPtr(), GetLength());
+			}
+		f.CloseLog();
+		f.Close();
+		}
+	}
+#endif
+
+//simple static const mapping option id to the handling class constructor
+//to simplify parsing
+namespace DHCPv6
+{
+typedef COptionNode* (*TOptionCostructor)();
+
+
+struct SMapOptionNumberToOption
+{
+   TUint iOption;
+   TOptionCostructor iNewL;
+};
+
+static const SMapOptionNumberToOption mapOptionNumberToOption[] = {
+    {EIaNa                  , CDHCPOptionIA_NA::NewL},       //Identity Association for Non-temporary Addresses 
+    {EIaTa                  , CDHCPOptionIA_TA::NewL},          //Identity Association for Temporary Addresses
+    {EOro                   , CDHCPOptionRequestOption::NewL},//Option Request - identify a list of options in a message
+    {EAuthentication        , CDHCPOptionAuthentication::NewL},
+    {EDNSServers		    , CDHCPOptionDNSServers::NewL},
+    {ESipServerA			, CDHCPOptionSipServerAddrs::NewL},    	
+    {EOptionAny             , COptionNode::NewL}
+	};
+//the rest of the options uses CDHCPOptionAny::NewL
+
+}//namespace DHCPv6
+
+void COptionList::ParseL(TPtr8& aDes8)
+/**
+  * Parse message to set pointers into descriptor buffer
+  * at locations of each option supplied in a response msg
+  *
+  * @internalTechnology
+  */
+	{
+	ASSERT(!iRecord.iFirst);
+	
+    COptionNode** ppNode = reinterpret_cast<COptionNode**>(&iRecord.iFirst);
+	
+	while(aDes8.Length())
+        {
+        User::LeaveIfError(aDes8.Length() < KOptionHeaderLength ? KErrBadDescriptor : KErrNone);
+
+        TUint nOptCode = TBigEndian::GetValue(aDes8.Ptr(), KOptionLengthOffset);
+
+		*ppNode = CreateNodeL(nOptCode);
+		(*ppNode)->ParseL(aDes8);
+		
+		ppNode = reinterpret_cast<COptionNode**>(&(*ppNode)->iNext);
+		}
+	}
+
+TUint32 COptionList::GetL( TInt aIndex, TUint aOpCode ) const
+/**
+  * Return a value from the message in big endian format
+  *
+  * @internalTechnology
+  */
+	{
+	COptionNode* pNode = FindOption(aOpCode);
+   if ( !pNode || pNode->GetLength() < aIndex * K32bitNumberOctets + K32bitNumberOctets )
+      {
+      User::Leave( KErrNotFound );
+      }
+   return TBigEndian::GetValue( pNode->Ptr() + aIndex * K32bitNumberOctets, K32bitNumberOctets );
+	}
+
+COptionNode* COptionList::CreateNodeL( TUint aOpCode )
+   {
+   TInt n = 0;
+   while ( mapOptionNumberToOption[n].iOption != aOpCode && 
+      mapOptionNumberToOption[n].iOption != EOptionAny )
+      {
+      n++;
+      };
+	return (*mapOptionNumberToOption[n].iNewL)();
+   }
+
+COptionNode* COptionList::AddNodeL(TOptionCodes aOpCode, TInt aInitialLength)
+/**
+  * Create a new node for an option in the message
+  *
+  * @internalTechnology
+  */
+   {
+   COptionNode* pNode = CreateNodeL(aOpCode);
+   AddNode(pNode);
+   pNode->Header().SetInitialValue(aInitialLength);
+   return pNode;
+   }
+
+COptionNode* COptionList::FindOption(TUint aOpCode, TInt& aPos) const
+	{
+	COptionNode* nodeCursor = static_cast<COptionNode*>(iRecord.iFirst);
+	TInt counter = 0;
+	while (nodeCursor)
+		{
+		if ( nodeCursor->OpCode() == aOpCode && ++counter > aPos )
+			{
+			aPos = counter;
+			return nodeCursor;
+			}
+		nodeCursor = static_cast<COptionNode*>(nodeCursor->iNext);
+		}
+	return NULL;
+	}
+
+TUint32 CDHCPOptionStatusCode::GetStatusCode() const
+    {
+    __ASSERT_DEBUG( GetLength() >= KDHCPOptionStatusCodeLength, User::Panic( KDhcpv6, KErrBadDescriptor ) );
+    return TBigEndian::GetValue(iPtr8 + KOptionHeaderLength, KDHCPOptionStatusCodeLength);
+    }
+
+void CDHCPOptionStatusCode::SetStatusCode( TUint32 aStatusCode )
+    {
+   __ASSERT_DEBUG( GetLength() >= KDHCPOptionStatusCodeLength, User::Panic( KDhcpv6, KErrBadDescriptor ) );
+	TBigEndian::SetValue(iPtr8 + KOptionHeaderLength, KDHCPOptionStatusCodeLength, aStatusCode);
+    }
+
+void CDHCPOptionDNSServers::ParseL(TPtr8& aDes8)
+	{
+	COptionNode::ParseL(aDes8);
+	
+	TPtr8 ptr(GetBodyDes());
+	
+	User::LeaveIfError(ptr.Length() % KIp6AddressLength ? KErrBadDescriptor : KErrNone);
+	}
+
+TBool CDHCPOptionDNSServers::GetDomainNameServer( TInt aIndex, TInetAddr& addr )
+	{
+	TInt pos = aIndex * KIp6AddressLength;
+	TBool ret = GetLength() >= pos + KIp6AddressLength;
+	if ( ret )
+		{
+		// Must ensure IP6 address is word aligned! So declare it locally
+		TIp6Addr ip6addr;
+		Mem::Copy(&ip6addr,GetBodyPtr() + pos,KIp6AddressLength);
+		
+		addr.SetAddress(ip6addr);
+		}
+	return ret;
+	}
+	
+void CDHCPOptionSipServerAddrs::ParseL(TPtr8& aDes8)
+	{
+	COptionNode::ParseL(aDes8);
+	
+	TPtr8 ptr(GetBodyDes());
+	
+	User::LeaveIfError(ptr.Length() % KIp6AddressLength ? KErrBadDescriptor : KErrNone);
+	}
+
+TBool CDHCPOptionSipServerAddrs::GetSipServerAddr(TInt aIndex, TInetAddr& addr)
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPOptionSipServerAddrs::GetSipServerAddr index = %d"),aIndex));
+	TInt pos = aIndex * KIp6AddressLength;
+	TInt len = GetLength();
+	TBool ret = len >= pos + KIp6AddressLength;
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("pos = %d, len = %d, ret = %d"), pos, len, ret));
+
+	if (ret)
+		{
+		// Must ensure IP6 address is word aligned! So declare it locally
+		TIp6Addr ip6addr;
+		Mem::Copy(&ip6addr,GetBodyPtr() + pos,KIp6AddressLength);  
+
+		addr.SetAddress(ip6addr);
+		}
+	return ret;
+	}
+
+
+void CDHCPOptionSipServerDomains::ParseL(TPtr8& aDes8)
+	{
+	COptionNode::ParseL(aDes8);
+	}
+
+TBool CDHCPOptionSipServerDomains::GetSipServerDomains(TInt aIndex, THostName& aName)
+	{
+	TInt domainIdx = 0;
+	TUint8* pChar = const_cast<TUint8*>(GetBodyDes().Ptr());
+	TUint labelLength = 0;
+	
+	// Walk the list of domain names
+	while(*pChar++ != NULL && domainIdx != aIndex)
+		{
+		labelLength = *(pChar - 1);
+		*(pChar - 1) = '.';
+		
+		TBuf8<0x100> tmp;
+		tmp.Copy(pChar, labelLength);
+		aName.Copy(tmp);
+
+		pChar += labelLength;
+		}
+	
+	return EFalse;
+	}
+
+//---------------------------------
+void CDHCPOptionRequestOption::AppendRequestedOptions()
+   {
+	// the array is in network byte order(big-endian) already => could be used as a descriptor
+	// authentication option and IA for temporary addresses not involved so far
+	TUint8 requestedOptions[KDHCPOptionRequestLen] = {0,EServerId, 0,EIaNa, 0,ESipServerD, 0,ESipServerA,
+														0,EDNSServers, 0,EDomainList};
+
+
+	TPtr8 ptr(requestedOptions, KDHCPOptionRequestLen, KDHCPOptionRequestLen );
+	GetBodyDes().Copy(ptr);
+   }
+
+CDHCPMessageHeaderIP6::~CDHCPMessageHeaderIP6()
+	{
+	Close();
+	}
+
+COptionNode* CDHCPMessageHeaderIP6::AddOptionL(TOptionCodes aOpCode, TInt aLength)
+/**
+  * First stage of adding an option to the message. Calls AddNode to create space
+  * for message.
+  *
+  * @param aOpCode The opcode of the options to be added
+  * @param aLength The length of the option data
+  * @return COptionNode* The pointer to the option in the message
+  *
+  * @internalTechnology
+  */
+	{
+	COptionNode* pNode = iOptions.AddNodeL(aOpCode, aLength);
+	TPtr8 ptr = iMsg->Des();
+	pNode->iRecord.InitialiseL(ptr);
+	pNode->SetOpCode(static_cast<TUint>(aOpCode));
+	return pNode;
+	}
+	
+TInt CDHCPMessageHeaderIP6::Parse(const TDhcpRnd& aXid, const TDesC8& aClientId, RBuf8& aServerId)
+/**
+  * When a response is received to a message
+  * this function will unpack the response by creating
+  * option objects which can be easily used to retrieve 
+  * the values returned in these options.  Providing 
+  * this functionality hides the nasty descriptor operations. 
+  *
+  * Each option class has a pointer set to the start point
+  * of their data in the response message.
+  *
+  * There is no need to explicitly unpack the mandatory fields
+  * of the DHCP message that has been returned.  Accessor functions
+  * simply extract the data sraight out of the decsriptor.
+  *
+  * @internalTechnology
+  */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPMessageHeaderIP6::Parse")));
+	
+	iOptions.RemoveAllNodes();
+	TPtr8 ptr = iMsg->Des();
+	TRAPD(ret,iRecord.ParseL(ptr););
+	
+   if ( ret == KErrNone )
+		{
+		/* Reject the message if:
+		 * 
+		 * 1) Not an Advertise, Reply, or potentially a Reconfigure message. 
+		 * 2) The server or client ID values are nonexistent
+		 * 3) The client ID being advertised does not match ours
+		 * 4) Bad status code
+		 */
+	   if (GetXid()!=aXid.Xid())
+		   {
+		   __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPMessageHeaderIP6::Parse - non-matching xid")));
+		   return KErrBadDescriptor;	// does not match so we are not interested in this message
+		   }
+      CDHCPOptionStatusCode* pStatus = static_cast<CDHCPOptionStatusCode*>(iOptions.FindOption( EStatusCode ));
+      TInt code = pStatus ? pStatus->GetStatusCode() : ESuccess;
+		if (code != ESuccess )
+		   {
+		   __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPMessageHeaderIP6::Parse - status code %d"), code));
+		   return KErrBadDescriptor;	// bad status code so we are not interested in this message
+		   }
+      TUint8 nType = GetMessageType();
+      COptionNode* pServerId = iOptions.FindOption( EServerId );
+      COptionNode* pClientId = iOptions.FindOption( EClientId );
+		switch(nType)
+			{
+			case EAdvertise:
+				if(pClientId == NULL || pServerId == NULL)
+					{
+					__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPMessageHeaderIP6::Parse - invalid message type %d or options"), nType));
+					return KErrBadDescriptor;
+					}
+					break;			
+			case EReply:
+#if defined(DHCP_RECONFIGURE_NO_AUTHENTICATION)
+			case EReconfigure:
+#endif				
+				if (pClientId == NULL || pServerId == NULL || 
+				    (aServerId.Length() && pServerId->GetBodyDes() != aServerId))
+					{
+					__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPMessageHeaderIP6::Parse - invalid message type %d or options"), nType));
+					return KErrBadDescriptor;
+					}
+				if ( nType == EReconfigure && !iOptions.FindOption( EReconfMsg ) )
+				    {
+					__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPMessageHeaderIP6::Parse - Reconfigure msg with no reconfigure option")));
+					return KErrBadDescriptor;
+				    }
+				break;
+			 default:
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPMessageHeaderIP6::Parse - invalid message type %d or options"), nType));
+				return KErrBadDescriptor;
+			}
+
+		if(pClientId->GetBodyDes() != aClientId)
+			{
+			__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPMessageHeaderIP6::Parse - ClientIds don't match")));
+			return KErrBadDescriptor;
+			}
+		if ( !aServerId.Length() )
+		    {
+            aServerId.Close();
+            TRAP(ret, aServerId.CreateL( pServerId->GetBodyDes() ));
+		    }
+      }
+   return ret;
+	}
+
+#ifdef SYMBIAN_TCPIPDHCP_UPDATE
+void CDHCPOptionDomainSearchList::ParseL(TPtr8& aDes8)
+	{
+	COptionNode::ParseL(aDes8);
+	}
+
+TBool CDHCPOptionDomainSearchList::GetDomainSearchList(TInt aIndex, THostName& aName)
+	{
+	TInt domainIdx = 0;
+	TUint8* pChar = const_cast<TUint8*>(GetBodyDes().Ptr());
+	TUint labelLength = 0;
+	TBuf8<0x100> tmp;
+	
+	if(*pChar)
+		{
+		// Walk the list of domain names
+		while(*pChar++ != NULL && domainIdx != aIndex)
+			{
+			labelLength = *(pChar - 1);
+			*(pChar - 1) = '.';
+				
+			tmp.Copy(pChar, labelLength);
+			aName.Copy(tmp);
+
+			pChar += labelLength;
+			}
+		return EFalse;
+		}
+	else
+		{
+		return ETrue;
+		}
+	}
+#endif //SYMBIAN_TCPIPDHCP_UPDATE