//-----------------------------------------------------------------------------
// File:  ip.hh 
// Date:  Fri Mar 21 15:21:38 PST 2003 
// Author: Martin Casado, Norman Franke
//
// Description:
//
// IPv4 packet w/ header
//
// -----------------------------------------------
// |version|  ihl  |  TOS      | total length    |
// ----------------------------------------------
// |    identification         |flags|frag offset|
// -----------------------------------------------
// |      TTL      |  Protocol | Header Checksum |
// -----------------------------------------------
// |           source IP address                 |
// -----------------------------------------------
// |        destination IP address               |
// -----------------------------------------------
// |         .... options and padding ...        |
// ...............................................
//
//
// Q: Why break encapsulation by having ip know about ip_transport?
// A: because the transport checksum requires the packet with the IP
//   header :-(
//
// ----------------------------------------------------------------------------
//
//    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 represent those of the United States
//    Government or the University of California, and shall not be used for
//    advertising or product endorsement purposes.
//
//-----------------------------------------------------------------------------

#ifndef IP_HH
#define IP_HH

#include "static_type_inference.hh"
#include "ethernet.hh"
#include "ipaddr.hh"

#include "ip_options.hh"

namespace pacman
{

template <typename O, typename T> struct ip;    

//-----------------------------------------------------------------------------
struct ip_base : public ether_type, public arp_protocol
{

    // -- Conform to model of ARP_protocol
    static const uint8_t ARPTYPE = ethernet<>::IP; 

    // -- Conform to model of Ethernet_type
    static const uint16_t ETHTYPE = ethernet<>::IP;

    // ------------------------------------------------------------------------
    // STATIC CONST
    // ------------------------------------------------------------------------

    static const uint16_t ADDRLEN = sizeof(ipaddr);
    static const uint8_t  VERSION = 4;

    static const uint16_t MAXPACKET = 65535;

    // Our default values
    static const uint8_t DEFPROTO = 0;

    // Internet implementation parameters
    static const uint8_t MAXTTL  = 255;
    static const uint8_t DEFTTL  = 64;  // default TTL, RFC 1340
    static const uint8_t FRAGTTL = 60;  // time to live for frags
    static const uint8_t TTLDEC  = 1;   // subtracted when forwarding

    // IP protocols
    static const uint8_t ICMP = 1;
    static const uint8_t IGMP = 2;
    static const uint8_t GGP  = 3;
    static const uint8_t IP   = 4;
    static const uint8_t ST   = 4;
    static const uint8_t TCP  = 6;
    static const uint8_t UDP  = 17;

    // TOS
    static const uint8_t TOS_MIN_DELAY = 0x10;
    static const uint8_t TOS_MAX_THROUGHPUT = 0x08;
    static const uint8_t TOS_MAX_RELIABILITY = 0x04;
    static const uint8_t TOS_MIN_MONETARY_COST = 0x02;

    // FLAGS
    static const uint8_t NO_FRAGMENT = 0x2;
    static const uint8_t MORE_FRAGMENTS = 0x1;

    // ------------------------------------------------------------------------
    // Typedefs
    // ------------------------------------------------------------------------

    typedef ipaddr            AddrType;

    // ------------------------------------------------------------------------
    // ------------------------------------------------------------------------
    
    template <typename O, typename T>
    static uint16_t cksum(ip<O, T>& in);
    
    static uint16_t cksum_impl(void *, size_t);

    protected:

    template <typename O, typename T>
    static void init(ip<O, T>& );

}__attribute__ ((__packed__)); // -- struct ip_base
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <typename O, typename T> struct ip;

template <>
struct ip<empty, empty> : public ip_base
{
    // -- useful, very useful
    typedef empty PayloadType;

#if __BYTE_ORDER == __LITTLE_ENDIAN
    uint16_t ihl:4;
    uint16_t version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
    uint16_t version:4;
    uint16_t ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
    uint8_t   tos;
    uint16_t  tot_len;
    uint16_t  id;
    uint16_t  frag_off;
    uint8_t   ttl;
    uint8_t   protocol;
    uint16_t  check;
    AddrType  saddr;
    AddrType  daddr;

    ip()
    { init(*this); }

}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <typename T>
struct ip<empty, T> : public ip <empty, empty> 
{
    // -- useful, very useful
    typedef T PayloadType;

    T data;

    ip()
    { init(*this); }

}__attribute__ ((__packed__)) ; // -- struct ip
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <typename O>
struct ip<ip_options<O>, empty> : public ip <empty, empty>
{
    // -- useful, very useful
    typedef empty PayloadType;

    ip_options<O> options;

    ip()
    { init(*this); }

}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <typename O, typename T>
struct ip<ip_options<O>, T> : public ip <empty, empty>
{
    // -- useful, very useful
    typedef T PayloadType;

    ip_options<O> options;
    T data;

    ip()
    { init(*this); }

}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <typename O, typename T>
struct ip : ip < ip_options<O>, T >
{
};
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <typename O, typename T>
inline
void 
ip_base::init(ip<O, T>& in)
{
    in.tos      = 0;
    in.tot_len  = htons_<sizeof(in)>::val;
    in.id       = 0;
    in.frag_off = 0;
    in.ttl      = ip_base::DEFTTL;
    in.protocol = get_ip_proto<T, ip_base::DEFPROTO>::val;
    in.check    = 0;
    in.saddr    = static_cast<uint32_t>(0);
    in.daddr    = static_cast<uint32_t>(0);
    in.version  = ip_base::VERSION;
    in.ihl      = hdr<ip<O, T> >::len/4;
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <typename O, typename T>
inline
uint16_t 
ip_base::cksum(ip<O, T>& in)
{
    uint16_t  ihl = (hdr<ip<O, T> >::len);
    return cksum_impl(&in, ihl);
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
inline
uint16_t 
ip_base::cksum_impl(void * in, size_t size)
{
    register size_t nleft = size;
    const u_short *w = (u_short *) in;
    register u_short answer;
    register int sum = 0;

    while (nleft > 1) {
        sum += *w++;
        nleft -= 2;
    }

    if (nleft == 1) {
        sum += htons(*(u_char *) w << 8);
    }

    sum = (sum >> 16) + (sum & 0xffff); // add high 16 to low 16
    sum += (sum >> 16); // add carry
    answer = ~sum;
    return answer;
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <class T> 
struct ip_csum
{
    static void func(T& in)
    {  
        in.check = ip_base::cksum(in);
        checksum(in.data); 
    }
};
template <> 
struct ip_csum <ip<empty, empty> >
{
    static void func(ip<empty,empty>& in)
    {  
        in.check = ip_base::cksum(in);
    }
};
template <class O> 
struct ip_csum <ip<O, empty> >
{
    static void func(ip<O, empty>& in)
    {  
        in.check = ip<O, empty>::cksum(in);
    }
};

template <class T> 
struct ip_csum_w_transport
{
    static void func(T& in)
    {  
        in.check = ip_base::cksum(in);
        in.data.check = ip_transport::cksum(in);
        checksum(in.data);
    }
};
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <class O, class T>
struct which_csum <ip<O, T> >
{
    typedef typename type_if_true_else <
                boost::is_base_and_derived<ip_transport, T>::value,
                ip_csum_w_transport<ip<O,T> >,
                ip_csum<ip<O, T> > >::Type Type;
};
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
typedef uint8_t mtu_t[1500];
typedef ip< empty, uint8_t[1500] > ip_mtu_t;
//-----------------------------------------------------------------------------

} // -- namespace pacman

//-----------------------------------------------------------------------------
//                        REFERENCE
//-----------------------------------------------------------------------------


// Value
//                             Protocol
//   0 IPv6 Hop-by-Hop Option.
//   1 ICMP, Internet Control Message Protocol.
//   2 IGMP, Internet Group Management Protocol.
//      RGMP, Router-port Group Management Protocol.
//   3 GGP, Gateway to Gateway Protocol.
//   4 IP in IP encapsulation.
//   5 ST, Internet Stream Protocol.
//   6 TCP, Transmission Control Protocol.
//   7 UCL, CBT.
//   8 EGP, Exterior Gateway Protocol.
//   9 IGRP.
//   10 BBN RCC Monitoring.
//   11 NVP, Network Voice Protocol.
//   12 PUP.
//   13 ARGUS.
//   14 EMCON, Emission Control Protocol.
//   15 XNET, Cross Net Debugger.
//   16 Chaos.
//   17 UDP, User Datagram Protocol.
//   18 TMux, Transport Multiplexing Protocol.
//   19 DCN Measurement Subsystems.
//   20 HMP, Host Monitoring Protocol.
//   21 Packet Radio Measurement.
//   22 XEROX NS IDP.
//   23 Trunk-1.
//   24 Trunk-2.
//   25 Leaf-1.
//   26 Leaf-2.
//   27 RDP, Reliable Data Protocol.
//   28 IRTP, Internet Reliable Transaction Protocol.
//   29 ISO Transport Protocol Class 4.
//   30 NETBLT, Network Block Transfer.
//   31 MFE Network Services Protocol.
//   32 MERIT Internodal Protocol.
//   33 Sequential Exchange Protocol.
//   34 Third Party Connect Protocol.
//   35 IDPR, Inter-Domain Policy Routing Protocol.
//   36 XTP, Xpress Transfer Protocol.
//   37 Datagram Delivery Protocol.
//   38 IDPR, Control Message Transport Protocol.
//   39 TP++ Transport Protocol.
//   40 IL Transport Protocol.
//   41 IPv6 over IPv4.
//   42 SDRP, Source Demand Routing Protocol.
//   43 IPv6 Routing header.
//   44 IPv6 Fragment header.
//   45 IDRP, Inter-Domain Routing Protocol.
//   46 RSVP, Reservation Protocol.
//   47 GRE, General Routing Encapsulation.
//   48 MHRP, Mobile Host Routing Protocol.
//   49 BNA.
//   50 ESP, Encapsulating Security Payload.
//   51 AH, Authentication Header.
//   52 Integrated Net Layer Security TUBA
//   53 IP with Encryption.
//   54 NARP, NBMA Address Resolution Protocol.
//   55 Minimal Encapsulation Protocol.
//   56 TLSP, Transport Layer Security Protocol using Kryptonet key management.
//   57 SKIP.
//   58 ICMPv6, Internet Control Message Protocol for IPv6.
//      MLD, Multicast Listener Discovery.
//   59 IPv6 No Next Header.
//   60 Destination Options for IPv6.
//   61 Any host internal protocol.
//   62 CFTP.
//   63 Any local network.
//   64 SATNET and Backroom EXPAK.
//   65 Kryptolan.
//   66 MIT Remote Virtual Disk Protocol.
//   67 Internet Pluribus Packet Core.
//   68 Any distributed file system.
//   69 SATNET Monitoring.
//   70 VISA Protocol.
//   71 Internet Packet Core Utility.
//   72 Computer Protocol Network Executive.
//   73 Computer Protocol Heart Beat.
//   74 Wang Span Network.
//   75 Packet Video Protocol.
//   76 Backroom SATNET Monitoring.
//   77 SUN ND PROTOCOL-Temporary.
//   78 WIDEBAND Monitoring.
//   79 WIDEBAND EXPAK.
//   80 ISO Internet Protocol.
//   81 VMTP, Versatile Message Transaction Protocol.
//   82 SECURE-VMTP
//   83 VINES.
//   84 TTP.
//   85 NSFNET-IGP.
//   86 Dissimilar Gateway Protocol.
//   87 TCF.
//   88 EIGRP.
//   89 OSPF, Open Shortest Path First Routing Protocol.
//      MOSPF, Multicast Open Shortest Path First.
//   90 Sprite RPC Protocol.
//   91 Locus Address Resolution Protocol.
//   92 MTP, Multicast Transport Protocol.
//   93 AX.25.
//   94 IP-within-IP Encapsulation Protocol.
//   95 Mobile Internetworking Control Protocol.
//   96 Semaphore Communications Sec. Pro.
//   97 Ethernet-within-IP Encapsulation.
//   98 Encapsulation Header.
//   99 Any private encryption scheme.
//   100 GMTP.
//   101 IFMP, Ipsilon Flow Management Protocol.
//   102 PNNI over IP.
//   103 PIM, Protocol Independent Multicast.
//   104 ARIS.
//   105 SCPS.
//   106 QNX.
//   107 Active Networks.
//   108 IPPCP, IP Payload Compression Protocol.
//   109 SNP, Sitara Networks Protocol.

#endif // -- IP_HH
