tcpiputils/dhcp/src/DHCPIP6IA.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dhcp/src/DHCPIP6IA.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,368 @@
+// 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 DHCPIP6 Identity Association classes
+// 
+//
+
+/**
+ @file DHCPIP6IA.cpp
+ @internalTechnology
+*/
+
+#include "DHCPIP6IA.h"
+#include "DHCP_Std.h"
+#include "DHCPServer.h"
+#include <comms-infras/metatypearray.h>
+
+#ifdef _DEBUG
+#include <e32property.h>
+#endif
+
+using namespace DHCPv6;
+
+COptionNode* CDHCPOptionIA_TA::NewL()
+	{ 
+	return new(ELeave)CDHCPOptionIA_TA();
+	}
+
+COptionNode* CDHCPOptionIA_NA::NewL()
+	{
+	return new(ELeave)CDHCPOptionIA_NA();
+	}
+
+CDHCPOptionIAAddress::~CDHCPOptionIAAddress()
+    {
+    iNext = NULL; //prevent the base from deleting its members
+    }
+
+TInt CDHCPOptionIAAddress::GetAddressOptionL( TPtr8& aPtr, SIPAddressInfo& aAddressInfo )
+    {
+    if ( aPtr.Length() <= KOptionHeaderLength || 
+		 TBigEndian::GetValue( aPtr.Ptr() + KOptionCodeOffset, KOptionCodeLen ) != EIaAddr )
+        {
+        return KErrNotFound;
+        }
+    ParseL( aPtr );
+    aPtr.Set( GetBodyDes() );
+    iRecord.ParseL( aPtr );
+
+	// Must ensure IP6 address is word aligned! So declare it locally
+	TIp6Addr ip6addr;
+	Mem::Copy(&ip6addr,iAddress.GetBodyPtr(),KIp6AddressLength);
+	  
+	aAddressInfo.iAddress.SetAddress( ip6addr );
+	aAddressInfo.iPreferredLifeTime = iPreferredLifeTime.GetBigEndian();
+	aAddressInfo.iValidLifeTime = iValidLifeTime.GetBigEndian();
+	CDHCPOptionStatusCode* pStatus = static_cast<CDHCPOptionStatusCode*>(GetOptions().FindOption( EStatusCode ));
+	aAddressInfo.iStatusCode = pStatus ? pStatus->GetStatusCode() : ESuccess;
+
+    return KErrNone;
+    }
+
+
+TInt CDHCPOptionIAAddress::AddAddressOptionL( TPtr8& aPtr, SIPAddressInfo& aAddressInfo, TStatusCodes aStatusCodeToSend )
+   {
+	InitialiseL(aPtr);
+	CDHCPOptionStatusCode* option = NULL;
+	if(aStatusCodeToSend != EStatusUnknown)
+		{
+		option = static_cast<CDHCPOptionStatusCode*>(iOptions.AddNodeL(EStatusCode, KDHCPOptionStatusCodeLength));
+		}
+	iRecord.InitialiseL(aPtr);
+	Header().SetInitialValue(KDHCPOptionIAAddressWithStatusCodeLength - KOptionHeaderLength);
+	SetLength();
+
+	SetOpCode(static_cast<TUint>(EIaAddr));
+	TIp6Addr* ip6addr = reinterpret_cast<TIp6Addr*>(iAddress.GetBodyPtr() );
+
+    //-- carefully copy one object to another. See function description
+    ObjectByteCopy(ip6addr, &aAddressInfo.iAddress.Ip6Address());
+
+	iPreferredLifeTime.SetBigEndian( aAddressInfo.iPreferredLifeTime );
+	iValidLifeTime.SetBigEndian( aAddressInfo.iValidLifeTime );
+	if(option)
+		{
+		option->SetOpCode(static_cast<TUint>(EStatusCode));
+		option->SetStatusCode(aStatusCodeToSend);
+		}
+
+	return KErrNone;
+	}
+
+TPtr8 CDHCPOptionIA_TA::GetOptionsDes() const
+    {
+    TPtr8 ptr(GetBodyDes());
+    TInt len = ptr.Length() - KDHCPOptionIA_NATInitLength;
+    return TPtr8( const_cast<TUint8*>(ptr.Ptr()) + KDHCPOptionIA_IAIDLength, len, len );
+    }
+
+TPtr8 CDHCPOptionIA_NA::GetOptionsDes() const
+    {
+    TPtr8 ptr(GetBodyDes());
+    TInt len = ptr.Length() - KDHCPOptionIA_NATInitLength;
+    return TPtr8( const_cast<TUint8*>(ptr.Ptr()) + KDHCPOptionIA_NATInitLength, len, len );
+    }
+
+START_ATTRIBUTE_TABLE( SIdentityAssociationConfigInfo, KDHCPv6Persinstence, 0 )
+	REGISTER_ATTRIBUTE( SIdentityAssociationConfigInfo, iIAID, TMetaNumber )
+	REGISTER_ATTRIBUTE( SIdentityAssociationConfigInfo, iAddressInfo, TMetaArray<SIPAddressInfo> )
+END_ATTRIBUTE_TABLE()
+
+void SIdentityAssociationConfigInfo::Reset()
+        {
+        TDhcpRnd rnd;
+        iIAID = rnd.Rnd( KDHCPv6IA_NANumberSpaceMin, KDHCPv6IA_NANumberSpaceMax );
+        iAddressInfo.Reset();
+        }
+
+void SIdentityAssociationConfigInfo::SetAddressStatus( TInt aIndex, TStatusCodes aStatusCode )
+   {
+	if ( aIndex == KAddrIndexAll )
+		{
+		TInt count = iAddressInfo.Count();
+		for(TInt addrInfoIdx=0;addrInfoIdx<count;addrInfoIdx++)
+			{
+			iAddressInfo[addrInfoIdx].iStatusCode = aStatusCode;
+			}
+		}
+	else
+		{
+		iAddressInfo[aIndex].iStatusCode = aStatusCode;
+		}
+   }
+
+TInt SIdentityAssociationConfigInfo::AddressInfo( TInt aIndex, TStatusCodes aStatusCode ) const
+	{
+	TInt count = iAddressInfo.Count();
+	for(TInt addrInfoIdx=aIndex;addrInfoIdx<count;addrInfoIdx++)
+		{
+		if ( (iAddressInfo[addrInfoIdx].iStatusCode & EStatusUnknown) == aStatusCode )
+			{
+			return addrInfoIdx + 1;
+			}
+		}
+	return KErrNotFound;
+	}
+
+TInt SIdentityAssociationConfigInfo::AddAddressesL( CDHCPOptionIA& aDHCPOptionIA, TMessageType aMessageType )
+        {
+        TInt addrInfoIdx = 0;
+        TStatusCodes	statusCode = EStatusUnknown;
+        TStatusCodes	statusCodeToSend = EStatusUnknown;
+        TInt remove = 0;
+
+        switch(aMessageType)
+                {
+                case ESolicit:
+                        break;
+                case ERequest:
+                        statusCode = EMarkToRequest;
+                        break;
+                case EConfirm:
+                case ERenew:
+                case ERebind:
+                        statusCode = ESuccess;
+                        statusCodeToSend = ESuccess;
+                        break;
+                case ERelease:
+                        statusCode = EMarkForRelease;
+                        statusCodeToSend = ESuccess;
+                        remove = 1;
+                        break;
+                case EDecline:
+                        statusCode = EMarkForDecline;
+                        statusCodeToSend = ENoBinding;
+                        remove = 1;
+                        break;
+                default:
+                        break;
+                }
+        //make a room for address options
+        TInt len = aDHCPOptionIA.GetLength();
+        TInt newlen = len + (KDHCPOptionIAAddressWithStatusCodeLength * iAddressInfo.Count());
+    //see DhcpIP6Msg.h comment !!!!BEWARE as to how the msg buffer allocation is handled
+    //so far
+        CDHCPOptionIAAddress* optionIaAddress = CDHCPOptionIAAddress::NewL();
+        CleanupStack::PushL( optionIaAddress );
+        TPtr8 ptr( aDHCPOptionIA.GetBodyPtr(), len, newlen );
+        ptr.SetLength( len );
+
+        while ( (addrInfoIdx = AddressInfo( addrInfoIdx, statusCode )) != KErrNotFound )
+                {
+                SIPAddressInfo& addressInfo = iAddressInfo[addrInfoIdx - 1];
+                optionIaAddress->AddAddressOptionL( ptr, addressInfo, statusCodeToSend );
+                if ( remove )
+                        {
+                        iAddressInfo.Remove( --addrInfoIdx );
+                        }
+                }
+        //write the IA option len into the msg buffer
+    aDHCPOptionIA.Header().SetInitialValue( ptr.Length() );
+    aDHCPOptionIA.SetLength();
+        CleanupStack::PopAndDestroy();
+        return ptr.Length() - len; //return te length of what we've just put in (address options)
+        }
+
+void SIdentityAssociationConfigInfo::ExtractAddressesL( CDHCPOptionIA& aDHCPOptionIA, TUint32 aRebindTimeSpan )
+        {
+        CDHCPOptionIAAddress* optionIaAddress = CDHCPOptionIAAddress::NewL();
+        CleanupStack::PushL( optionIaAddress );
+
+        TPtr8 ptr( aDHCPOptionIA.GetOptionsDes() );
+        SIPAddressInfo addressInfoNew;
+
+        while (optionIaAddress->GetAddressOptionL( ptr, addressInfoNew ) == KErrNone)
+                {
+                iAddressInfo.AppendL( addressInfoNew );
+                }
+        CleanupStack::PopAndDestroy();
+
+        //check validity and remove what's not needed
+        for(TInt addrInfoIdx=0;addrInfoIdx<iAddressInfo.Count();addrInfoIdx++)
+                {
+                SIPAddressInfo& addressInfo = iAddressInfo[addrInfoIdx];
+/*the RFC3315 doesn't explicitly say this but since it says:
+[At time T2(our aRebindTimeSpan) for an IA the client initiates a Rebind/Reply message exchange
+with any available server. The message exchange is terminated when the valid lifetimes of all
+the addresses assigned to the IA expire]
+the following check seems like a good idea*/
+                if ( addressInfo.iPreferredLifeTime > addressInfo.iValidLifeTime ||
+                        aRebindTimeSpan > addressInfo.iValidLifeTime ||
+                        addressInfo.iStatusCode != ESuccess )
+                        {
+                        addressInfo.iStatusCode = EMarkForDecline;
+                        }
+                }
+        }
+
+START_ATTRIBUTE_TABLE( SIdentityAssociationConfigInfoNA, KDHCPv6Persinstence, 0 )
+	REGISTER_ATTRIBUTE( SIdentityAssociationConfigInfoNA, iT1, TMetaNumber )
+	REGISTER_ATTRIBUTE( SIdentityAssociationConfigInfoNA, iT2, TMetaNumber )
+END_ATTRIBUTE_TABLE_BASE(SIdentityAssociationConfigInfo,KDHCPv6PersinstenceId.iUid)
+
+void SIdentityAssociationConfigInfoNA::ExtractIAOptionInfoL( CDHCPOptionIA_NA& aDHCPOptionIA )
+	{
+	iT1 = aDHCPOptionIA.GetT1();
+	iT2 = aDHCPOptionIA.GetT2();
+	ExtractAddressesL( aDHCPOptionIA, iT2 );
+   }
+
+void TInterfaceConfigInfo::AppendIAOptionsL(CDHCPMessageHeaderIP6& aMessage, TMessageType aMessageType)
+     {
+     CDHCPOptionIA_NA* pIA_NA = static_cast<CDHCPOptionIA_NA*>(aMessage.AddOptionL(EIaNa, KDHCPOptionIA_NATInitLength));
+     pIA_NA->SetIAID(iSIdentityAssociationConfigInfoNA.IaId());
+     // indicate no preference for T1 and T2
+     pIA_NA->SetT1(KIA_NoTimePreference);
+     pIA_NA->SetT2(KIA_NoTimePreference);
+     switch(aMessageType)
+             {
+             case ESolicit:
+                     break;
+             case EConfirm:
+             case ERenew:
+             case ERebind:
+                     pIA_NA->SetT1(iSIdentityAssociationConfigInfoNA.iT1);
+                     pIA_NA->SetT2(iSIdentityAssociationConfigInfoNA.iT2);
+                     //fall through
+             case ERequest:
+             case ERelease:
+             case EDecline:
+					 {
+                     TInt addrOptLen = iSIdentityAssociationConfigInfoNA.AddAddressesL(*pIA_NA,aMessageType);
+                     TPtr8 msg = aMessage.Message().Des();
+                     msg.SetLength( msg.Length() + addrOptLen);
+                     break;
+					 }
+             default:
+                     User::Leave(KErrNotSupported);
+             }
+
+   }
+
+void TInterfaceConfigInfo::ParseIAOptionsL(CDHCPMessageHeaderIP6& aMessage)
+        {
+        // Find an NA option
+        CDHCPOptionIA_NA* optionIa = static_cast<CDHCPOptionIA_NA*>(aMessage.GetOptions().FindOption(EIaNa));
+        if (!optionIa || optionIa->GetT1() > optionIa->GetT2())
+                {//nothing to do the fact that we don't have any address is picked up when the address is being
+                //congfigured
+                return;
+                }
+        if ( aMessage.GetMessageType() == EReply )
+            {
+            iSIdentityAssociationConfigInfoNA.ResetAddressInfos();
+            iSIdentityAssociationConfigInfoNA.ExtractIAOptionInfoL( *optionIa );
+            }
+        }
+
+void TInterfaceConfigInfo::CheckForUnicast( CDHCPMessageHeaderIP6& aMessage )
+        {
+        COptionNode* pNode = aMessage.GetOptions().FindOption(EUnicast);
+        if ( pNode )
+                {
+                iUseUnicast = ETrue;
+
+				// Must ensure IP6 address is word aligned! So declare it locally
+               	TIp6Addr ip6addr;
+				Mem::Copy(&ip6addr,pNode->GetBodyPtr(),KIp6AddressLength);  
+
+                iServerAddress.SetAddress( ip6addr );
+                }
+        }
+
+void TInterfaceConfigInfo::GetServerAddress( TInetAddr& aAddress )	// to send/receive data
+        {
+        __CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("TInterfaceConfigInfo::GetServerAddress unicast %d"), iUseUnicast));
+        if ( iUseUnicast )
+                {
+                aAddress = iServerAddress;
+                }
+        else
+                {
+                aAddress.SetAddress( KDHCPv6RelayAgentsNServers );
+                }
+#ifdef _DEBUG
+		// Simulate initialisation, renewal or rebind failure by using the wrong port.
+		if( ( CDHCPServer::DebugFlags() & KDHCP_FailDiscover ) || ( CDHCPServer::DebugFlags() & KDHCP_FailRenew ) || ( CDHCPServer::DebugFlags() & KDHCP_FailRebind ) )
+			{
+			aAddress.SetPort(KDhcpv6WrongDestPort);
+			}
+		else
+			{
+			TInt destPort;
+			RProperty::Get(KMyPropertyCat, KMyPropertyDestPortv6, destPort);
+			aAddress.SetPort(destPort);
+			}
+#else
+        aAddress.SetPort(KDhcpv6DestPort);
+#endif
+        }
+
+/**
+  * Creates one IAID for TA(SIdentityAssociationConfigInfoTA) and
+  * one for NA(SIdentityAssociationConfigInfoNA) in case they don't exist yet
+  * (restored after reboot, sleep,....)
+  *
+  * @see SIdentityAssociationConfigInfoTA, SIdentityAssociationConfigInfoNA
+  * @internalTechnology
+  */
+void DHCPv6::TInterfaceConfigInfo::Reset()
+        {
+        ResetUseUnicast();
+        //iSIdentityAssociationConfigInfoTA.iIAID = rnd.Rnd( KDHCPv6IA_TANumberSpaceMin, KDHCPv6IA_TANumberSpaceMax );
+        iSIdentityAssociationConfigInfoNA.Reset();
+        
+		// Clear the DHCP server address now that we no longer have a lease.
+        iServerAddress.SetAddress( KInet6AddrNone );
+        }