//-----------------------------------------------------------------------------
// File:  tcp.hh
// Date:  Fri Mar 21 23:27:04 PST 2003 
// Author: Martin Casado, Norman Franke
//
// Description:
//
// Tcp header creation
//
// Q? why make flags a template parameter?
// A: flags determine type ... 
//
// ----------------------------------------------------------------------------
//
//    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 TCP_HH
#define TCP_HH

#include "static_type_inference.hh"
#include "tcp_options.hh"
#include "ip.hh"

extern "C"
{
#include <stdint.h>
#include <assert.h>
}

namespace pacman
{

//-----------------------------------------------------------------------------
struct tcp_base : public ip_proto
{

    static const uint32_t NODELAY	 = 1; // Don't delay send to coalesce packets  
    static const uint32_t MAXSEG	 = 2; // Set maximum segment size  
    static const uint32_t CORK	     = 3; // Control sending of partial frames  
    static const uint32_t KEEPIDLE	 = 4; // Start keeplives after this period 
    static const uint32_t KEEPINTVL	 = 5; // Interval between keepalives 
    static const uint32_t KEEPCNT	 = 6; // Number of keepalives before death 
    static const uint32_t SYNCNT	 = 7; // Number of SYN retransmits 
    static const uint32_t LINGER2	 = 8; // Life time of orphaned FIN-WAIT-2 state 
    static const uint32_t INFO	     = 11; // Information about this connection. 
    static const uint32_t QUICKACK	 = 12; // Bock/reenable quick ACKs.  
    static const uint32_t DEFER_ACCEPT = 9;// Wake up listener only when data arrive 
    static const uint32_t WINDOW_CLAMP = 10; // Bound advertised window 

    static const uint32_t MSS = 512; 
    static const uint32_t MAXWIN = 65535; // largest value for unscaled window
    static const uint32_t MAX_WINSHIFT = 14; // maximum window shirt

    static const uint8_t IPPROTO = ip_base::TCP;
    static const uint8_t DEF_PORT = 0;

    static const uint8_t FIN  = 0x01;
    static const uint8_t SYN  = 0x02;
    static const uint8_t RST  = 0x04;
    static const uint8_t PUSH = 0x08;
    static const uint8_t ACK  = 0x10;
    static const uint8_t URG  = 0x20;

    protected:

    template <uint8_t flag, typename O, typename T>
    static void init(tcp_impl<flag, O, T>& );

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

//-----------------------------------------------------------------------------
struct tcp_impl_base : public tcp_base, public ip_transport
{
    uint16_t sport;		// source port 
    uint16_t dport;		// destination port 
    uint32_t seq;		// sequence number 
    uint32_t ack;		// acknowledgement number 
#  if __BYTE_ORDER == __LITTLE_ENDIAN
    uint8_t x2:4;		// (unused) 
    uint8_t off:4;		// data offset 
#  endif
#  if __BYTE_ORDER == __BIG_ENDIAN
    uint8_t off:4;		// data offset 
    uint8_t x2:4;		// (unused) 
#  endif
    uint8_t flags;
    uint16_t win;		// window 
    uint16_t check;		// checksum 
    uint16_t urp;		// urgent pointer 

	uint16_t len() { return ((uint16_t) off) * 4; };
};
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <uint8_t tflags, typename O, typename T> struct tcp_impl;

template <uint8_t tflags, typename O, typename T>
struct tcp_impl<tflags, tcp_options<O>, T> : public tcp_impl_base
{
    typedef T PayloadType;

    tcp_options<O> options;
    T data;

    tcp_impl()
    { init(*this); }

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

//-----------------------------------------------------------------------------
template <uint8_t tflags, typename T>
struct tcp_impl <tflags, empty, T> : public tcp_impl_base
{
    typedef empty PayloadType;

    T        data;

    tcp_impl()
    { init(*this); }

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

//-----------------------------------------------------------------------------
template <uint8_t tflags, typename O>
struct tcp_impl <tflags, tcp_options<O>, empty> : public tcp_impl_base
{
    typedef empty PayloadType;

    tcp_options<O> options;

    tcp_impl()
    { init(*this); }

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

//-----------------------------------------------------------------------------
template <uint8_t tflags>
struct tcp_impl <tflags, empty, empty>: public tcp_impl_base
{
    typedef empty PayloadType;

    tcp_impl()
    { init(*this); }

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

//-----------------------------------------------------------------------------
template <uint8_t tflags = 0, typename O = empty, typename T = empty>
struct tcp_impl
{
};
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <uint8_t F, typename O, typename T>
inline
void
tcp_base::init(tcp_impl<F, O, T>& in)
{
    in.sport = 0;
    in.dport = htons_<get_ip_port<T, tcp_base::DEF_PORT>::val>::val;
    in.seq   = 0;
    in.ack   = 0;
    in.off   = hdr<tcp_impl<F,O,T> >::len / 4;
    in.x2    = 0;
    in.flags = F;
    in.win   = 0;
    in.check = 0;
    in.urp   = 0;
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <typename O = empty, typename T = empty>
struct tcp: public tcp_impl<0, O, T>
{
}__attribute__ ((__packed__));

// TCP SYN
template <typename O, typename T > struct syn;
template <typename T>
struct syn<empty, T>: public tcp_impl<tcp_impl<>::SYN, empty, T>
{
    typedef T PayloadType;
}__attribute__ ((__packed__));
template <typename O = empty, typename T = empty>
struct syn: public tcp_impl<tcp_impl<>::SYN, O, T>
{
    typedef T PayloadType;
}__attribute__ ((__packed__));

// TCP FIN
template <typename O, typename T > struct fin;
template <typename T>
struct fin<empty, T>: public tcp_impl<tcp_impl<>::FIN, empty, T>
{
    typedef T PayloadType;
}__attribute__ ((__packed__));
template <typename O = empty, typename T = empty>
struct fin: public tcp_impl<tcp_impl<>::FIN, O, T>
{
    typedef T PayloadType;
}__attribute__ ((__packed__));

// TCP RST
template <typename O, typename T> struct rst;
template <typename T>
struct rst<empty, T>: public tcp_impl<tcp_impl<>::RST, empty, T>
{
    typedef T PayloadType;
}__attribute__ ((__packed__));
template <typename O = empty, typename T = empty>
struct rst: public tcp_impl<tcp_impl<>::RST, O, T>
{
    typedef T PayloadType;
}__attribute__ ((__packed__));

// TCP ACK
template <typename O = empty, typename T = empty> struct ack;
template <typename T>
struct ack<empty, T>: public tcp_impl<tcp_impl<>::ACK, empty, T>
{
    typedef T PayloadType;
}__attribute__ ((__packed__));
template <typename O, typename T>
struct ack: public tcp_impl<tcp_impl<>::ACK, O, T>
{
    typedef T PayloadType;
}__attribute__ ((__packed__));
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
typedef tcp< uint8_t[1500] > tcp_mtu_t;
//-----------------------------------------------------------------------------


} // -- namespace pacman


#endif  //-- TCP_HH
