/* -*- P4_16 -*- */
#ifndef HEADERS_P4
#define HEADERS_P4

#include <core.p4>

/**************************************** NetPFGA    ****************************************/

/* already defined in sume_switch.p4 */
#ifndef _SUME_SWITCH_P4_
typedef bit<9>   port_t;
#endif

/**************************************** types    ****************************************/

typedef bit<48>  mac_addr_t;
typedef bit<32>  ipv4_addr_t;
typedef bit<128> ipv6_addr_t;

typedef bit<16>  mcast_t;
typedef bit<16>  task_t;
typedef bit<16>  table_t; /* to map debug messages - 16 bit to match shortenumfield */

/**************************************** constants ****************************************/

const bit<16> TABLE_NAT64       = 1;
const bit<16> TABLE_ICMP6       = 2;
const bit<16> TABLE_V6_NETWORKS = 3;
const bit<16> TABLE_NAT46       = 4;
const bit<16> TABLE_V4_NETWORKS = 5;
const bit<16> TABLE_ARP         = 6;
const bit<16> TABLE_ARP_EGRESS  = 7;
const bit<16> TABLE_ICMP        = 8;
const bit<16> TABLE_NAT64_TCP   = 9;
const bit<16> TABLE_NAT64_UDP   = 10;
const bit<16> TABLE_NAT64_ICMP6 = 11;
const bit<16> TABLE_NAT64_SESSION = 12;


const bit<16> TYPE_IPV4  = 0x0800;
const bit<16> TYPE_IPV6  = 0x86DD;
const bit<16> TYPE_CPU   = 0x4242;
const bit<16> TYPE_DEBUG = 0x2323;
const bit<16> TYPE_ARP   = 0x0806;


const bit<8>  PROTO_ICMP = 1;
const bit<8>  PROTO_TCP  = 6;
const bit<8>  PROTO_UDP  = 17;
const bit<8>  PROTO_ICMP6  = 58;

const bit<8>  TCP_SEQ_LEN = 4;

const bit<8>  ICMP6_ECHO_REQUEST = 128;
const bit<8>  ICMP6_ECHO_REPLY   = 129;
const bit<8>  ICMP6_NS           = 135;
const bit<8>  ICMP6_NA           = 136;

const bit<8>  ICMP_ECHO_REPLY    = 0;
const bit<8>  ICMP_ECHO_REQUEST  = 8;

const bit<16>  ARP_REQUEST        = 1;
const bit<16>  ARP_REPLY          = 2;

/* RFC4861, Section 4.6 */
const bit<8>  ICMP6_NDP_OPT_SOURCE_LL    = 1;
const bit<8>  ICMP6_NDP_OPT_TARGET_LL    = 2;
const bit<8>  ICMP6_NDP_OPT_PREFIX_INFO  = 3;
const bit<8>  ICMP6_NDP_OPT_REDIR_HEADER = 4;
const bit<8>  ICMP6_NDP_OPT_MTU          = 5;

/* Tasks from switch to controller - no RFC, internal */
const task_t TASK_ICMP6_NS       = 1;
const task_t TASK_ICMP6_GENERAL  = 2;
const task_t TASK_DEBUG          = 3;
const task_t TASK_ICMP6_REPLY    = 4;
const task_t TASK_CHECKSUM_ICMP6    = 5; /* data plane */
const task_t TASK_CHECKSUM_ICMP6_NA = 6; /* data plane */
const task_t TASK_CHECKSUM_ICMP     = 7; /* data plane */
const task_t TASK_NAT64_TCP_SESSION = 8; /* control plane */

/**************************************** header ****************************************/


/* 48+48+16 = 112 */
header ethernet_t {
    mac_addr_t dst_addr;
    mac_addr_t src_addr;
    bit<16>    ethertype;
}

header ipv4_t {
    bit<4>      version;
    bit<4>      ihl;
    bit<6>      diff_serv;
    bit<2>      ecn;
    bit<16>     totalLen;
    bit<16>     identification;
    bit<3>      flags;
    bit<13>     fragOffset;
    bit<8>      ttl;
    bit<8>      protocol;
    bit<16>     hdrChecksum;
    ipv4_addr_t src_addr;
    ipv4_addr_t dst_addr;
}

/*
https://en.wikipedia.org/wiki/IPv6_packet
64 + 256 = 320
*/
header ipv6_t {
    bit<4>      version;
    bit<8>      traffic_class;
    bit<20>     flow_label;
    bit<16>     payload_length;
    bit<8>      next_header;
    bit<8>      hop_limit;
    ipv6_addr_t src_addr;
    ipv6_addr_t dst_addr;
}

header tcp_t{
    bit<16> src_port;
    bit<16> dst_port;
    int<32> seqNo;
    int<32> ackNo;
    bit<4>  data_offset;
    bit<4>  res;
    bit<1>  cwr;
    bit<1>  ece;
    bit<1>  urg;
    bit<1>  ack;
    bit<1>  psh;
    bit<1>  rst;
    bit<1>  syn;
    bit<1>  fin;
    bit<16> window;
    bit<16> checksum;
    bit<16> urgentPtr;
}

header udp_t {
    bit<16> src_port;
    bit<16> dst_port;
    bit<16> payload_length;
    bit<16> checksum;
}

header icmp6_t {
    bit<8>  type;
    bit<8>  code;
    bit<16> checksum;
}

/*
 https://tools.ietf.org/html/rfc4861#section-4.4
*/
header icmp6_na_ns_t {
    bit<1>  router;
    bit<1>  solicitated;
    bit<1>  override;
    bit<29> reserved;
    ipv6_addr_t target_addr;
}

header icmp6_option_link_layer_addr_t {
    bit<8>     type;
    bit<8>     ll_length;
    mac_addr_t mac_addr;
}


header icmp_t {
    bit<8>  type;
    bit<8>  code;
    bit<16> checksum;
}

header arp_t {
    bit<16>     hw_type;
    bit<16>     protocol;
    bit<8>      hw_size;
    bit<8>      protocol_size;
    bit<16>     opcode;
    mac_addr_t  src_mac_addr;
    ipv4_addr_t src_ipv4_addr;
    mac_addr_t  dst_mac_addr;
    ipv4_addr_t dst_ipv4_addr;
}

header cpu_t {
    task_t task;
    bit<16> ingress_port;
    bit<16> ethertype;
    table_t table_id;
}

/**************************************** struct ****************************************/

struct headers {
    ethernet_t       ethernet;
    ipv4_t	         ipv4;
    ipv6_t	         ipv6;
    tcp_t	         tcp;
    udp_t	         udp;
    icmp_t           icmp;
    cpu_t            cpu;
    icmp6_t          icmp6;
    icmp6_na_ns_t    icmp6_na_ns;
    icmp6_option_link_layer_addr_t   icmp6_option_link_layer_addr;
    arp_t arp;
}


struct metadata {
    port_t ingress_port;
    task_t task;
    task_t switch_task;

    /* migrate tasks to bool */
    bit<1> chk_icmp6_na_ns;
    bit<1> chk_icmp6;
    bit<1> chk_icmp;
    bit<1> chk_ipv4;
    bit<1> chk_udp_v4;
    bit<1> chk_udp_v6;
    bit<1> chk_tcp_v4;
    bit<1> chk_tcp_v6;

    bit<16> length_without_ip_header;
    bit<32> cast_length;
    table_t table_id;
}

#endif