/*
 * Copyright (c) 2007-2008 Louis Pasteur University
 *
 * SPDX-License-Identifier: GPL-2.0-only
 *
 * Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
 */

#ifndef IPV6_HEADER_H
#define IPV6_HEADER_H

#include "ns3/header.h"
#include "ns3/ipv6-address.h"

namespace ns3
{

/**
 * @ingroup ipv6
 *
 * @brief Packet header for IPv6
 */
class Ipv6Header : public Header
{
  public:
    /**
     * @enum DscpType
     * @brief DiffServ Code Points
     * Code Points defined in
     * Assured Forwarding (AF) \RFC{2597}
     * Expedited Forwarding (EF) \RFC{2598}
     * Default and Class Selector (CS) \RFC{2474}
     */
    enum DscpType
    {
        DscpDefault = 0x00,

        // Prefixed with "DSCP" to avoid name clash (bug 1723)
        DSCP_CS1 = 0x08,  // octal 010
        DSCP_AF11 = 0x0A, // octal 012
        DSCP_AF12 = 0x0C, // octal 014
        DSCP_AF13 = 0x0E, // octal 016

        DSCP_CS2 = 0x10,  // octal 020
        DSCP_AF21 = 0x12, // octal 022
        DSCP_AF22 = 0x14, // octal 024
        DSCP_AF23 = 0x16, // octal 026

        DSCP_CS3 = 0x18,  // octal 030
        DSCP_AF31 = 0x1A, // octal 032
        DSCP_AF32 = 0x1C, // octal 034
        DSCP_AF33 = 0x1E, // octal 036

        DSCP_CS4 = 0x20,  // octal 040
        DSCP_AF41 = 0x22, // octal 042
        DSCP_AF42 = 0x24, // octal 044
        DSCP_AF43 = 0x26, // octal 046

        DSCP_CS5 = 0x28, // octal 050
        DSCP_EF = 0x2E,  // octal 056

        DSCP_CS6 = 0x30, // octal 060
        DSCP_CS7 = 0x38  // octal 070
    };

    /**
     * @enum NextHeader_e
     * @brief IPv6 next-header value
     */
    enum NextHeader_e
    {
        IPV6_EXT_HOP_BY_HOP = 0,
        IPV6_IPV4 = 4,
        IPV6_TCP = 6,
        IPV6_UDP = 17,
        IPV6_IPV6 = 41,
        IPV6_EXT_ROUTING = 43,
        IPV6_EXT_FRAGMENTATION = 44,
        IPV6_EXT_CONFIDENTIALITY = 50,
        IPV6_EXT_AUTHENTICATION = 51,
        IPV6_ICMPV6 = 58,
        IPV6_EXT_END = 59,
        IPV6_EXT_DESTINATION = 60,
        IPV6_SCTP = 135,
        IPV6_EXT_MOBILITY = 135,
        IPV6_UDP_LITE = 136,
    };

    /**
     * @brief Get the type identifier.
     * @return type identifier
     */
    static TypeId GetTypeId();

    /**
     * @brief Return the instance type identifier.
     * @return instance type ID
     */
    TypeId GetInstanceTypeId() const override;

    /**
     * @brief Constructor.
     */
    Ipv6Header();

    /**
     * @brief Set the "Traffic class" field.
     * @param traffic the 8-bit value
     */
    void SetTrafficClass(uint8_t traffic);

    /**
     * @brief Get the "Traffic class" field.
     * @return the traffic value
     */
    uint8_t GetTrafficClass() const;

    /**
     * @brief Set DSCP Field
     * @param dscp DSCP value
     */
    void SetDscp(DscpType dscp);

    /**
     * @returns the DSCP field of this packet.
     */
    DscpType GetDscp() const;

    /**
     * @param dscp the dscp
     * @returns std::string of DSCPType
     */
    std::string DscpTypeToString(DscpType dscp) const;

    /**
     * @enum EcnType
     * @brief ECN field bits
     */
    enum EcnType
    {
        // Prefixed with "ECN" to avoid name clash
        ECN_NotECT = 0x00,
        ECN_ECT1 = 0x01,
        ECN_ECT0 = 0x02,
        ECN_CE = 0x03
    };

    /**
     * @brief Set ECN field bits
     * @param ecn ECN field bits
     */
    void SetEcn(EcnType ecn);

    /**
     * @return the ECN field bits of this packet.
     */
    EcnType GetEcn() const;

    /**
     * @param ecn the ECNType
     * @return std::string of ECNType
     */
    std::string EcnTypeToString(EcnType ecn) const;

    /**
     * @brief Set the "Flow label" field.
     * @param flow the 20-bit value
     */
    void SetFlowLabel(uint32_t flow);

    /**
     * @brief Get the "Flow label" field.
     * @return the flow label value
     */
    uint32_t GetFlowLabel() const;

    /**
     * @brief Set the "Payload length" field.
     * @param len the length of the payload in bytes
     */
    void SetPayloadLength(uint16_t len);

    /**
     * @brief Get the "Payload length" field.
     * @return the payload length
     */
    uint16_t GetPayloadLength() const;

    /**
     * @brief Set the "Next header" field.
     * @param next the next header number
     */
    void SetNextHeader(uint8_t next);

    /**
     * @brief Get the next header.
     * @return the next header number
     */
    uint8_t GetNextHeader() const;

    /**
     * @brief Set the "Hop limit" field (TTL).
     * @param limit the 8-bit value
     */
    void SetHopLimit(uint8_t limit);

    /**
     * @brief Get the "Hop limit" field (TTL).
     * @return the hop limit value
     */
    uint8_t GetHopLimit() const;

    /**
     * @brief Set the "Source address" field.
     * @param src the source address
     */
    void SetSource(Ipv6Address src);

    /**
     * @brief Get the "Source address" field.
     * @return the source address
     */
    Ipv6Address GetSource() const;

    /**
     * @brief Set the "Destination address" field.
     * @param dst the destination address
     */
    void SetDestination(Ipv6Address dst);

    /**
     * @brief Get the "Destination address" field.
     * @return the destination address
     */
    Ipv6Address GetDestination() const;

    /**
     * @brief Print some information about the packet.
     * @param os output stream
     */
    void Print(std::ostream& os) const override;

    /**
     * @brief Get the serialized size of the packet.
     * @return size
     */
    uint32_t GetSerializedSize() const override;

    /**
     * @brief Serialize the packet.
     * @param start Buffer iterator
     */
    void Serialize(Buffer::Iterator start) const override;

    /**
     * @brief Deserialize the packet.
     * @param start Buffer iterator
     * @return size of the packet
     */
    uint32_t Deserialize(Buffer::Iterator start) override;

  private:
    /**
     * @brief The traffic class.
     */
    uint32_t m_trafficClass : 8;

    /**
     * @brief The flow label.
     * @note This is 20-bit value.
     */
    uint32_t m_flowLabel : 20;

    /**
     * @brief The payload length.
     */
    uint16_t m_payloadLength;

    /**
     * @brief The Next header number.
     */
    uint8_t m_nextHeader;

    /**
     * @brief The Hop limit value.
     */
    uint8_t m_hopLimit;

    /**
     * @brief The source address.
     */
    Ipv6Address m_sourceAddress;

    /**
     * @brief The destination address.
     */
    Ipv6Address m_destinationAddress;
};

} /* namespace ns3 */

#endif /* IPV6_HEADER_H */
