//-----------------------------------------------------------------------------
// File:  ethernet.hh
// Date:  Mon May 06 22:40:56 PDT 2002 
// Author: Martin Casado
//
// Description:
//
// Provide a fuzzy c++ interface for handeling ethernet packets
//
// ----------------------------------------------------------------------------
//
//    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 ETHERNET_HH__
#define ETHERNET_HH__

#include <iostream>

#include "static_type_inference.hh"
#include "ethernetaddr.hh"
#include "checksum.hh"

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

namespace pacman
{

template <typename T> struct ethernet;    

//-----------------------------------------------------------------------------
struct ethernet_base : public arp_protocol
{
    //-------------------------------------------------------------------------
    //-------------------------------------------------------------------------
    
    typedef  ethernetaddr         AddrType;

    static const unsigned int ADDRLEN =   AddrType::LEN;
    
    // -- arp<_>::ETHER = 1, we don't use this because including arp.hh
    //    gives us a circular include ... C++ is so lame ... lame lame lame
    //    bleh .. /mc
    static const uint16_t ARPTYPE = htons_<1>::val;

    static const uint16_t DEFTYPE = 0;

    //-------------------------------------------------------------------------
    // from net/ethernet.h
    //
    // #define ETHERTYPE_PUP           0x0200          /* Xerox PUP */
    // #define ETHERTYPE_IP            0x0800          /* IP */
    // #define ETHERTYPE_ARP           0x0806          /* Address resolution */
    // #define ETHERTYPE_REVARP        0x8035          /* Reverse ARP */
    //-------------------------------------------------------------------------

    static const uint16_t PUP    = htons_<0x0200>::val; 
    static const uint16_t IP     = htons_<0x0800>::val; 
    static const uint16_t ARP    = htons_<0x0806>::val; 
    static const uint16_t REVARP = htons_<0x8035>::val; 

    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    
    protected:

    template <typename T>
    static void init(ethernet<T>& );

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

//-----------------------------------------------------------------------------
template <>
struct ethernet<empty> : public ethernet_base
{
    typedef empty PayloadType;

    ethernetaddr  dhost;    // destination ethernet address 
    ethernetaddr  shost;    // source ethernet address 
    uint16_t      type;     // packet type ID 

    ethernet()
    { init(*this); }

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

//-----------------------------------------------------------------------------
template <typename T = uint8_t[1500]>
struct ethernet : public ethernet<empty>
{
    typedef T PayloadType;

    T             data;     // payload

    ethernet()
    { init(*this); }

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

//-----------------------------------------------------------------------------
template <typename T>
inline
void 
ethernet_base::init(ethernet<T>& in)
{
    in.type = get_ether_type<T, ethernet_base::DEFTYPE>::val;
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <class T> 
struct ether_csum
{
    static void func(T& in)
    {  checksum(in.data); }
};
template <> 
struct ether_csum <ethernet<empty> >
{
    static void func(ethernet<empty>& in)
    {  }
};
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
template <class T>
struct which_csum <ethernet<T> >
{
    typedef ether_csum<ethernet<T> > Type; 
};
//-----------------------------------------------------------------------------

} // -- namespace pacman

#endif  // ETHERNET_HH__
