//-----------------------------------------------------------------------------
// File:  ip_options.hh
// Date: Mon May  5 12:52:10 PDT 2003
// Author: Norman Franke
//
// Description:
//
// IP options construction
//
// ----------------------------------------------------------------------------
//
//    Copyright 2003. The Regents of the University of California.
//    All rights reserved.
//
//    This work was produced at the University of California, Lawrence Livermore
//    National Laboratory (UC LLNL) under contract no. W-7405-ENG-48 (Contract
//    48) between the U.S. Department of Energy (DOE) and The Regents of the
//    University of California (University) for the operation of UC LLNL.
//    Copyright is reserved to the University for purposes of controlled
//    dissemination, commercialization through formal licensing, or other
//    disposition under terms of Contract 48; DOE policies, regulations and
//    orders; and U.S. statutes. The rights of the Federal Government are
//    reserved under Contract 48 subject to the restrictions agreed upon by the
//    DOE and University as allowed under DOE Acquisition Letter 91-7.
//
//    DISCLAIMER
//    This software was prepared as an account of work sponsored by an
//    agency of the United States Government. Neither the United States
//    Government nor the University of California nor any of their employees,
//    makes any warranty, express or implied, or assumes any liability or
//    responsibility for the accuracy, completeness, or usefulness of any
//    information, apparatus, product, or process disclosed, or represents that
//    its use would not infringe protectedly-owned rights. Reference herein to any
//    specific commercial products, process, or service by trade name, trademark,
//    manufacturer, or otherwise, does not necessarily constitute or imply its
//    endorsement, recommendation, or favoring by the United States Government or
//    the University of California. The views and opinions of authors expressed
//    herein do not necessarily those of the United States Government or the
//    University of California, and shall not be used for advertising or product
//    endorsement purposes.
//
//-----------------------------------------------------------------------------

#ifndef IP_OPTIONS_HH
#define IP_OPTIONS_HH

#include "pacman/ip_transport.hh"

namespace pacman
{

struct ip_ts_block
{
    uint32_t ip;
    uint32_t ts;
}__attribute__ ((__packed__));

// Forward declaration.
struct ip_opt;

// Base class so we can specialize on the size.
template<typename O, uint8_t F> struct ip_options_;
template<typename O>
struct ip_options_<O, 0> : public ip_options_base
{
    O options;
}__attribute__ ((__packed__));

template<typename O, uint8_t F = 0>
struct ip_options_ : public ip_options_<O, 0>
{
    filler<F> filler;
}__attribute__ ((__packed__));


//-----------------------------------------------------------------------------
// Use this if adding options to a ip header.
template <typename O>
struct ip_options : public ip_options_<O, ((4-sizeof(O)) % 4) % 4 >
{
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------


// Base classes.
struct ip_opt {
    static const uint8_t COPY_FLAG = 0x80;
    static const uint8_t CLASS_1 = 0x20;
    static const uint8_t CLASS_2 = 0x40;
    static const uint8_t CLASS_3 = 0x60;

    static const uint8_t END = 0;
    static const uint8_t NOP = 1;
    static const uint8_t LOOSE_SRC_RTE = COPY_FLAG | 2;
    static const uint8_t TIMESTAMP = CLASS_2 | 4;
    static const uint8_t RECORD_RTE = 7;
    static const uint8_t STREAM_ID = COPY_FLAG | 8;
    static const uint8_t STRICT_SRC_RTE = COPY_FLAG | 9;
    static const uint8_t MTU_PROBE = 11;
    static const uint8_t MTU_REPLY = 12;
    static const uint8_t TRACEROUTE = CLASS_2 | 18;
    static const uint8_t ROUTER_ALERT = COPY_FLAG | 20;

    uint8_t opt;
}__attribute__ ((__packed__));

// Base class for non-trivial tags.
struct ip_opt_len : public ip_opt {
    uint8_t len;
}__attribute__ ((__packed__));


//-----------------------------------------------------------------------------
// Terminator (not needed if there is no extra non-options data in the ip header.)
template <typename T> struct ip_end;
template <>
struct ip_end<empty> : public ip_opt
{
    ip_end() { opt=END; }
}__attribute__ ((__packed__));
template <typename T = empty>
struct ip_end : public ip_end<empty>
{
    T data;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// NOP
template <typename T> struct ip_nop;
template<>
struct ip_nop<empty> : public ip_opt
{
    ip_nop() { opt=NOP; }
}__attribute__ ((__packed__));
template<typename T = empty>
struct ip_nop : public ip_nop<empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Loose Source Route
template <uint8_t N, typename T> struct ip_lsr;
template<uint8_t N>
struct ip_lsr<N, empty> : public ip_opt_len
{
    uint8_t ptr;
    uint32_t routes[N];
    ip_lsr() { ptr = 0; opt=LOOSE_SRC_RTE; len=3+sizeof(routes); memset(&routes, 0, sizeof(routes)); }
}__attribute__ ((__packed__));
template<uint8_t N, typename T = empty>
struct ip_lsr : public ip_lsr<N, empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Timestamp
template <uint8_t N, typename T> struct ip_ts;
template<uint8_t N>
struct ip_ts<N, empty> : public ip_opt_len
{
    uint8_t ptr;
    uint8_t over_flag;
    ip_ts_block routes[N];
    ip_ts() { ptr = 0; over_flag = 0; opt=TIMESTAMP; len=4+sizeof(routes); memset(&routes, 0, sizeof(routes)); }
}__attribute__ ((__packed__));
template<uint8_t N, typename T = empty>
struct ip_ts : public ip_ts<N, empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Record Route
template <uint8_t N, typename T> struct ip_rr;
template<uint8_t N>
struct ip_rr<N, empty> : public ip_opt_len
{
    uint8_t ptr;
    uint32_t routes[N];
    ip_rr() { ptr = 0; opt=RECORD_RTE; len=3+sizeof(routes); memset(&routes, 0, sizeof(routes)); }
}__attribute__ ((__packed__));
template<uint8_t N, typename T = empty>
struct ip_rr : public ip_rr<N, empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Stream ID
template <typename T> struct ip_sid;
template<>
struct ip_sid<empty> : public ip_opt_len
{
    uint16_t sid;
    ip_sid() { opt=STREAM_ID; len=4; sid = 0; }
}__attribute__ ((__packed__));
template<typename T = empty>
struct ip_sid : public ip_sid<empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Strict Source Route
template <uint8_t N, typename T> struct ip_ssr;
template<uint8_t N>
struct ip_ssr<N, empty> : public ip_opt_len
{
    uint8_t ptr;
    uint32_t routes[N];
    ip_ssr() { ptr = 0; opt=STRICT_SRC_RTE; len=3+sizeof(routes); memset(&routes, 0, sizeof(routes)); }
}__attribute__ ((__packed__));
template<uint8_t N, typename T = empty>
struct ip_ssr : public ip_ssr<N, empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// MTU Probe
template <typename T> struct ip_mp;
template<>
struct ip_mp<empty> : public ip_opt_len
{
    uint16_t mtu;
    ip_mp() { opt=MTU_PROBE; len=4; mtu = 0; }
}__attribute__ ((__packed__));
template<typename T = empty>
struct ip_mp : public ip_mp<empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------}

//-----------------------------------------------------------------------------
// MTU Reply
template <typename T> struct ip_mr;
template<>
struct ip_mr<empty> : public ip_opt_len
{
    uint16_t mtu;
    ip_mr() { opt=MTU_REPLY; len=4; mtu = 0; }
}__attribute__ ((__packed__));
template<typename T = empty>
struct ip_mr : public ip_mr<empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Traceroute
template <typename T> struct ip_tr;
template<>
struct ip_tr<empty> : public ip_opt_len
{
    uint16_t id;
    uint16_t out_hop;
    uint16_t ret_hop;
    uint32_t ip;
    ip_tr() { opt=MTU_REPLY; len=12; id = out_hop = ret_hop = 0; ip = 0; }
}__attribute__ ((__packed__));
template<typename T = empty>
struct ip_tr : public ip_tr<empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Router Alert
template <typename T> struct ip_ra;
template<>
struct ip_ra<empty> : public ip_opt_len
{
    uint16_t value;
    ip_ra() { opt=MTU_REPLY; len=4; value = 0; }
}__attribute__ ((__packed__));
template<typename T = empty>
struct ip_ra : public ip_ra<empty>
{
    T next;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

} // -- namespace pacman

#endif  //-- IP_OPTIONS_HH
