/* -*- P4_16 -*- */
#ifndef CHECKSUMS_P4
#define CHECKSUMS_P4

#include <core.p4>
#include <v1model.p4>
#include "headers.p4"

update_checksum_with_payload(meta.chk_icmp6 == 1,
	{
        hdr.ipv6.src_addr,         /* 128 */
		hdr.ipv6.dst_addr,         /* 128 */
        meta.cast_length,          /* 32 */
        24w0,                      /* 24 0's */
        PROTO_ICMP6,               /* 8 */
        hdr.icmp6.type,            /* 8 */
        hdr.icmp6.code             /* 8 */
    },
    hdr.icmp6.checksum,
    HashAlgorithm.csum16
);

/* checksumming for icmp6_na_ns_option */
update_checksum_with_payload(meta.chk_icmp6_na_ns == 1,
	{
        hdr.ipv6.src_addr,         /* 128 */
		hdr.ipv6.dst_addr,         /* 128 */
        meta.cast_length,          /* 32 */
        24w0,                      /* 24 0's */
        PROTO_ICMP6,               /* 8 */
        hdr.icmp6.type,            /* 8 */
        hdr.icmp6.code,            /* 8 */

        hdr.icmp6_na_ns.router,
        hdr.icmp6_na_ns.solicitated,
        hdr.icmp6_na_ns.override,
        hdr.icmp6_na_ns.reserved,
        hdr.icmp6_na_ns.target_addr,

        hdr.icmp6_option_link_layer_addr.type,
        hdr.icmp6_option_link_layer_addr.ll_length,
        hdr.icmp6_option_link_layer_addr.mac_addr
    },
    hdr.icmp6.checksum,
    HashAlgorithm.csum16
);

update_checksum_with_payload(meta.chk_icmp == 1,
	{
        hdr.icmp.type,
        hdr.icmp.code
    },
    hdr.icmp.checksum,
    HashAlgorithm.csum16
);

update_checksum(meta.chk_ipv4 == 1,
    {
        hdr.ipv4.version,
	    hdr.ipv4.ihl,
        hdr.ipv4.diff_serv,
        hdr.ipv4.ecn,
        hdr.ipv4.totalLen,
        hdr.ipv4.identification,
        hdr.ipv4.flags,
        hdr.ipv4.fragOffset,
        hdr.ipv4.ttl,
        hdr.ipv4.protocol,
        hdr.ipv4.src_addr,
        hdr.ipv4.dst_addr
    },
    hdr.ipv4.checksum,
    HashAlgorithm.csum16
);

update_checksum_with_payload(meta.chk_udp_v4 == 1,
    {
        hdr.ipv4.src_addr,
        hdr.ipv4.dst_addr,
        8w0,
        hdr.ipv4.protocol,
		meta.length_without_ip_header,

		// UDP header
        hdr.udp.src_port,
        hdr.udp.dst_port,
        hdr.udp.payload_length
    },
    hdr.udp.checksum,
    HashAlgorithm.csum16
);

update_checksum_with_payload(meta.chk_udp_v6 == 1,
    {
        hdr.ipv6.src_addr,               /* 128 */
        hdr.ipv6.dst_addr,               /* 128 */
		meta.length_without_ip_header,   /* 32 */
        24w0,                            /* 24 */
		hdr.ipv6.next_header,            /* 8 */
        /* total: 324 */

		// UDP header
        hdr.udp.src_port,                /* 16 */
        hdr.udp.dst_port,                /* 16 */
        hdr.udp.payload_length           /* 16 */
        /* all: 372 */

    },
    hdr.udp.checksum,
    HashAlgorithm.csum16
);

update_checksum_with_payload(meta.chk_tcp_v4 == 1,
	{
        hdr.ipv4.src_addr,
		hdr.ipv4.dst_addr,
		8w0,
		hdr.ipv4.protocol,
        meta.length_without_ip_header,

		// TCP header
		hdr.tcp.src_port,
		hdr.tcp.dst_port,
		hdr.tcp.seqNo,
		hdr.tcp.ackNo,
		hdr.tcp.data_offset,
		hdr.tcp.res,
		hdr.tcp.cwr,
		hdr.tcp.ece,
		hdr.tcp.urg,
		hdr.tcp.ack,
		hdr.tcp.psh,
		hdr.tcp.rst,
		hdr.tcp.syn,
		hdr.tcp.fin,
		hdr.tcp.window,
		hdr.tcp.urgentPtr
	},
	hdr.tcp.checksum,
	HashAlgorithm.csum16
);

update_checksum_with_payload(meta.chk_tcp_v6 == 1,
			{
        hdr.ipv6.src_addr,
		hdr.ipv6.dst_addr,
		meta.length_without_ip_header,
		24w0,
		hdr.ipv6.next_header,

		// TCP header
		hdr.tcp.src_port,
		hdr.tcp.dst_port,
		hdr.tcp.seqNo,
		hdr.tcp.ackNo,
		hdr.tcp.data_offset,
		hdr.tcp.res,
		hdr.tcp.cwr,
		hdr.tcp.ece,
		hdr.tcp.urg,
		hdr.tcp.ack,
		hdr.tcp.psh,
		hdr.tcp.rst,
		hdr.tcp.syn,
		hdr.tcp.fin,
		hdr.tcp.window,
		hdr.tcp.urgentPtr
	},
	hdr.tcp.checksum,
	HashAlgorithm.csum16);

#endif
