// 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:
// DHCPv6 Identity Association - holds config info associated with IAID
// IAID (Identity Association Id) is generated by client at least one per interface 
// (DUID DHCP Unique IDentifier)
// 
//

/**
 @file DHCPIP6IA.h
*/

#ifndef DHCPIP6IA_H
#define DHCPIP6IA_H

#include <e32base.h>
#include "DhcpIP6Msg.h"
#include <comms-infras/metadata.h>

class CDHCPIP6Control;
class CDHCPIP6StateMachine;

namespace DHCPv6
{

const TInt KDHCPOptionIA_IAIDLength = 4; //(4 bytes)

/*
      Identity Association for Non-temporary Addresses Option
       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |          OPTION_IA_NA         |          option-len           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                        IAID (4 octets)                        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                              T1                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                              T2                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      .                         IA_NA-options                         .
      .                                                               .
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      option-code          OPTION_IA_NA (3).

      option-len           12 + length of IA_NA-options field.

      IAID                 The unique identifier for this IA_NA; the
                           IAID must be unique among the identifiers for
                           all of this client's IA_NAs.  The number
                           space for IA_NA IAIDs is separate from the
                           number space for IA_TA IAIDs.

      T1                   The time at which the client contacts the
                           server from which the addresses in the IA_NA
                           were obtained to extend the lifetimes of the
                           addresses assigned to the IA_NA; T1 is a
                           time duration relative to the current time
                           expressed in units of seconds.

      T2                   The time at which the client contacts any
                           available server to extend the lifetimes of
                           the addresses assigned to the IA_NA; T2 is a
                           time duration relative to the current time
                           expressed in units of seconds.

      IA_NA-options        Options associated with this IA_NA.

Identity Association for Temporary Addresses Option doesn't have T1 and T2 fields
*/
class CDHCPOptionIA : public COptionNode
/**
  * Option associated with DUID identifying one set of config parameters
  * associated with a DHCP interface Id (DUID).
  * Part common for NA_IA & TA_IA
  *
  * @internalTechnology
  */
	{

public:
	CDHCPOptionIA() :
		COptionNode(NULL)
		{
		}

    virtual TPtr8 GetOptionsDes() const = 0;
    
	TUint32 GetIAID() const; 
	void SetIAID(const TUint32 aIAID);
	};

inline TUint32 CDHCPOptionIA::GetIAID() const
    {
    __ASSERT_DEBUG(GetLength() >= KDHCPOptionIA_IAIDLength, User::Panic(KDhcpv6, KErrBadDescriptor));
    return TBigEndian::GetValue(iPtr8 + KOptionHeaderLength, KDHCPOptionIA_IAIDLength);
    }

inline void CDHCPOptionIA::SetIAID(const TUint32 aIAID)
    {
   __ASSERT_DEBUG( GetLength() >= KDHCPOptionIA_IAIDLength, User::Panic( KDhcpv6, KErrBadDescriptor ) );
	TBigEndian::SetValue(iPtr8 + KOptionHeaderLength, KDHCPOptionIA_IAIDLength, aIAID);
    }

//no options involved in the init length of IA_TA option
const TInt KDHCPOptionIA_TATInitLength = KDHCPOptionIA_IAIDLength;

class CDHCPOptionIA_TA : public CDHCPOptionIA
/**
  * Option associated with DUID identifying one set of config parameters
  * associated with a DHCP interface Id (DUID).
  * Part specific to TA_IA
  *
  * @internalTechnology
  */
	{

public:
	CDHCPOptionIA_TA() :
		CDHCPOptionIA()
		{
		}

    static COptionNode* NewL();

    virtual TPtr8 GetOptionsDes() const;
	};

const TInt KDHCPOptionIA_NAT1Length = 4; //(4 bytes)
const TInt KDHCPOptionIA_NAT2Length = 4; //(4 bytes)
//no options involved in the init length
const TInt KDHCPOptionIA_NATInitLength = KDHCPOptionIA_NAT1Length + KDHCPOptionIA_NAT2Length + KDHCPOptionIA_IAIDLength;

const TInt KIA_NoTimePreference = 0x00;

class CDHCPOptionIA_NA : public CDHCPOptionIA
/**
  * Option associated with DUID identifying one set of config parameters
  * associated with a DHCP interface Id (DUID)
  * Part specific to IA_NA
  *
  * @internalTechnology
  */
	{

public:
	CDHCPOptionIA_NA() :
		CDHCPOptionIA()
		{
		}

	static COptionNode* NewL();


    virtual TPtr8 GetOptionsDes() const;

	TUint32 GetT1() const; 
	void SetT1(TUint32 aT1);
	TUint32 GetT2() const; 
	void SetT2(TUint32 aT1);
	};


inline TUint32 CDHCPOptionIA_NA::GetT1() const
    {
//    __ASSERT_DEBUG(GetLength() >= KDHCPOptionStatusCodeLength, User::Panic(KDhcpv6, KErrBadDescriptor));
    return TBigEndian::GetValue(iPtr8 + KOptionHeaderLength + KDHCPOptionIA_IAIDLength, KDHCPOptionIA_NAT1Length);
    }

inline void CDHCPOptionIA_NA::SetT1(TUint32 aT1)
    {
//    __ASSERT_DEBUG(GetLength() >= KDHCPOptionStatusCodeLength, User::Panic(KDhcpv6, KErrBadDescriptor));
    TBigEndian::SetValue(iPtr8 + KOptionHeaderLength + KDHCPOptionIA_IAIDLength, KDHCPOptionIA_NAT1Length, aT1);
    }    


inline TUint32 CDHCPOptionIA_NA::GetT2() const
    {
//    __ASSERT_DEBUG(GetLength() >= KDHCPOptionStatusCodeLength, User::Panic(KDhcpv6, KErrBadDescriptor));
    return TBigEndian::GetValue(iPtr8 + KOptionHeaderLength + KDHCPOptionIA_IAIDLength + KDHCPOptionIA_NAT1Length, 
        KDHCPOptionIA_NAT2Length);
    }

inline void CDHCPOptionIA_NA::SetT2(TUint32 aT2)
    {
//    __ASSERT_DEBUG(GetLength() >= KDHCPOptionStatusCodeLength, User::Panic(KDhcpv6, KErrBadDescriptor));
    TBigEndian::SetValue(iPtr8 + KOptionHeaderLength + KDHCPOptionIA_IAIDLength + KDHCPOptionIA_NAT1Length, 
        KDHCPOptionIA_NAT2Length, aT2);
    }    


const TInt KDHCPOptionAddressPrefLifeTimeLength = 4; //(4 bytes)
const TInt KDHCPOptionAddressValidLifeTimeLength = 4; //(4 bytes)
/*
      IA Address Option
       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |          OPTION_IAADDR        |          option-len           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      |                         IPv6 address                          |
      |                                                               |
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                      preferred-lifetime                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                        valid-lifetime                         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      .                                                               .
      .                        IAaddr-options                         .
      .                                                               .
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      option-code   OPTION_IAADDR (5).

      option-len    24 + length of IAaddr-options field.

      IPv6 address  An IPv6 address.

      preferred-lifetime The preferred lifetime for the IPv6 address in
                    the option, expressed in units of seconds.

      valid-lifetime The valid lifetime for the IPv6 address in the
                    option, expressed in units of seconds.

      IAaddr-options Options associated with this address.
*/

const TInt KDHCPOptionIAAddressLength = KOptionHeaderLength + KIp6AddressLength + KDHCPOptionAddressPrefLifeTimeLength + KDHCPOptionAddressValidLifeTimeLength;
const TInt KDHCPOptionIAAddressWithStatusCodeLength = KDHCPOptionIAAddressLength + KOptionHeaderLength + KDHCPOptionStatusCodeLength;

struct SIPAddressInfo;

class CDHCPOptionIAAddress : public COptionNode
/**
  * Option associated with IAID (IA option) carrying address config info
  *
  * @internalTechnology
  */
	{

public:
   CDHCPOptionIAAddress() :
		COptionNode( &iAddress ),
		iAddress( &iPreferredLifeTime, KIp6AddressLength ),
		iPreferredLifeTime( &iValidLifeTime, KDHCPOptionAddressPrefLifeTimeLength ),
		iValidLifeTime(&iOptions, KDHCPOptionAddressValidLifeTimeLength ),
		iOptions(NULL)
      {
		iRecord.iFirst = &iAddress;
      }
        
    virtual ~CDHCPOptionIAAddress();    

	static CDHCPOptionIAAddress* NewL() 
		 { 
		 return new(ELeave)CDHCPOptionIAAddress(); 
		 }

	TInt GetAddressOptionL(TPtr8& aPtr, SIPAddressInfo& aAddressInfo);
	TInt AddAddressOptionL(TPtr8& aPtr, SIPAddressInfo& aAddressInfo, TStatusCodes aStatusCodeToSend);

	inline COptionList& GetOptions() { return iOptions; }
	

public:
	CConstItem iAddress;
	CConstItem iPreferredLifeTime;
	CConstItem iValidLifeTime;
	
protected:
	COptionList iOptions;
    };
    
    
    
const TInt KAddrIndexAll = -1;

//persistent data
struct SIPAddressInfo
/**
  * Contains IPv6 address info associated with the particular IAID
  *
  * @internalTechnology
  */
	{
	  SIPAddressInfo() :
		iPreferredLifeTime( KIA_NoTimePreference ),
		iValidLifeTime( KIA_NoTimePreference ),
		iStatusCode( ESuccess )
		{
		}
	TInetAddr iAddress;
	TUint32 iPreferredLifeTime; //renew of the address via unicast (renew)
	TUint32 iValidLifeTime; //renew address via multicast (rebind)
	TInt	iStatusCode;
	};

struct SIdentityAssociationConfigInfo : public Meta::SMetaData
/**
  * Contains config info associated with one IAID. The first address of the first IA option
  * in the server's reply message is stored in CDHCPStateMachine::iCurrentAddress variable
  * so as KConnGetCurrentAddr Ioctl command works for IP4 & IP6
  *
  * @see SIdentityAssociationConfigInfoTA, SIdentityAssociationConfigInfoNA
  * @internalTechnology
  */
	{
	SIdentityAssociationConfigInfo() : iIAID(0)
		{
		}
		
	~SIdentityAssociationConfigInfo() //non-virtual since never accessed via base class
		{
		iAddressInfo.Close();
		}

	void Reset();
	void ResetAddressInfos();
	TUint32 IaId() const;
	TInt AddressInfo( TInt aIndex, TStatusCodes aStatusCode ) const;
	TInt AddAddressesL( CDHCPOptionIA& aDHCPOptionIA, TMessageType aMessageType );
	void ExtractAddressesL( CDHCPOptionIA& aDHCPOptionIA, TUint32 aRebindTimeSpan );

	const SIPAddressInfo* GetValidAddressInfo( TInt& aPos ) const;

	void SetAddressStatus( TInt aIndex, TStatusCodes aStatusCode );

protected:
	TUint32 iIAID;    //Identity Association ID
	RArray<SIPAddressInfo> iAddressInfo;

public:
	DATA_VTABLE
	};

inline void SIdentityAssociationConfigInfo::ResetAddressInfos()
	{
	iAddressInfo.Reset();
	}

inline TUint32 SIdentityAssociationConfigInfo::IaId() const
	{
	return iIAID;
	}

inline const SIPAddressInfo* SIdentityAssociationConfigInfo::GetValidAddressInfo( TInt& aPos ) const
	{
	return ( aPos = AddressInfo( aPos, ESuccess )) != KErrNotFound ? &iAddressInfo[aPos - 1] : NULL;
	}

struct SIdentityAssociationConfigInfoTA : public SIdentityAssociationConfigInfo
/**
  * Contains config info associated with one IAID for Temporary Addresses
  *
  * @see SIPAddressInfo
  * @internalTechnology
  */
   {
	TUint32 iLifeTime; //the longest life time from associated addresses
   };

struct SIdentityAssociationConfigInfoNA : public SIdentityAssociationConfigInfo
/**
  * Contains config info associated with one IAID for Non-temporary Addresses
  *
  * @see SIPAddressInfo
  * @internalTechnology
  */
   {
   TUint32 iT1;    //renew of the IA via unicast
   TUint32 iT2;    //rebind of the IA via multicast to all servers and rely agents

   void ExtractIAOptionInfoL( CDHCPOptionIA_NA& aDHCPOptionIA );

public:
	DATA_VTABLE
   };

class TInterfaceConfigInfo
/**
  * Contains all IAIDs associated with the interface identified by DUID
  * By having iSIdentityAssociationConfigInfoTA and iSIdentityAssociationConfigInfoNA members
  * we confined ourselves to one NAID and one TAID for the moment. There could be an array of these.
  *
  * @see SIdentityAssociationConfigInfo
  * @see SIdentityAssociationConfigInfoTA
  * @see SIdentityAssociationConfigInfoNA
  * @internalTechnology
  */
   {
friend class CDHCPIP6Control;
friend class CDHCPIP6StateMachine;

public:
	void Reset();
	void AppendIAOptionsL( CDHCPMessageHeaderIP6& aMessage, TMessageType aMessageType );
	void ParseIAOptionsL( CDHCPMessageHeaderIP6& aMessage );

	void ResetUseUnicast();	
	void CheckForUnicast( CDHCPMessageHeaderIP6& aMessage );
	void GetServerAddress( TInetAddr& aAddress );	// to send/receive data
	
	TBool AnyAddressToDecline() const;
	void SetAddressStatus( TInt aIndex, TStatusCodes aStatusCode );

	const SIPAddressInfo* GetValidAddressInfo( TInt& aPos ) const;

	TUint32 RenewTime() const;
	TUint32 RebindTime() const;

protected:
   TBool iUseUnicast; //ETrue if the server's sent a unicast option
	TInetAddr iServerAddress;	// to store the address of the DHCP Server we are dealing with

public:
//not used yet   SIdentityAssociationConfigInfoTA iSIdentityAssociationConfigInfoTA;
   SIdentityAssociationConfigInfoNA iSIdentityAssociationConfigInfoNA;   
   };
   
//if we ever what to work with more than one IA we need to add mechanism how to make one an active one
inline TUint32 TInterfaceConfigInfo::RenewTime() const
	{
	return iSIdentityAssociationConfigInfoNA.iT1;
	}

inline TUint32 TInterfaceConfigInfo::RebindTime() const
	{
	return iSIdentityAssociationConfigInfoNA.iT2;
	}

inline void TInterfaceConfigInfo::SetAddressStatus( TInt aIndex, TStatusCodes aStatusCode )
	{
	iSIdentityAssociationConfigInfoNA.SetAddressStatus(aIndex, aStatusCode);
	}

inline void TInterfaceConfigInfo::ResetUseUnicast()
	{
	iUseUnicast = EFalse;
	}

inline TBool TInterfaceConfigInfo::AnyAddressToDecline() const
	{
	TInt dummy = 0;
	return iSIdentityAssociationConfigInfoNA.AddressInfo( dummy, EMarkForDecline ) != KErrNotFound;
	}

inline const SIPAddressInfo* TInterfaceConfigInfo::GetValidAddressInfo( TInt& aPos ) const
	{
	return iSIdentityAssociationConfigInfoNA.GetValidAddressInfo(aPos);
	}

}//DHCPv6 namespace

#endif

