diff -r 000000000000 -r af10295192d8 tcpiputils/dhcp/src/DHCPIP6Msg.cpp --- /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(&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(&(*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(iRecord.iFirst); + TInt counter = 0; + while (nodeCursor) + { + if ( nodeCursor->OpCode() == aOpCode && ++counter > aPos ) + { + aPos = counter; + return nodeCursor; + } + nodeCursor = static_cast(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(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(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(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(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