FPS 0.0.3

Flow processing system (under construction).
use n::packet::*;
use n::ip;

extract_field!(extract_vtf, ipv6, 4, vtf);
fill_field!(fill_vtf, ipv6, 4, vtf);

extract_field!(extract_source, ipv6, 16, source);
fill_field!(fill_source, ipv6, 16, source);

extract_field!(extract_destination, ipv6, 16, destination);
fill_field!(fill_destination, ipv6, 16, destination);

alias_protocol!(extract_total_length, ipv6, ip, total_length);
alias_protocol!(fill_total_length, ipv6, ip, total_length);
alias_protocol!(extract_total_length_u16, ipv6, ip, total_length, total_length_u16);
alias_protocol!(apply_total_length, ipv6, ip, total_length, total_length_u16);

alias_protocol!(extract_hop_limit, ipv6, ip, hop_limit);
alias_protocol!(fill_hop_limit, ipv6, ip, hop_limit);
alias_protocol!(extract_hop_limit_u8, ipv6, ip, hop_limit, hop_limit_u8);
alias_protocol!(apply_hop_limit, ipv6, ip, hop_limit, hop_limit_u8);

alias_protocol!(extract_protocol, ipv6, ip, protocol);
alias_protocol!(fill_protocol, ipv6, ip, protocol);
alias_protocol!(extract_protocol_u8, ipv6, ip, protocol, protocol_u8);
alias_protocol!(apply_protocol, ipv6, ip, protocol, protocol_u8);

#[millefeuille]
pub fn extract_source_u64(packet: Packet) -> Packet {
    let mut packet = packet;
    let first_8;
    let later_8;
    {
        let field = packet.context.get_field("ipv6::source");
        first_8 = field.read_u64(0);
        later_8 = field.read_u64(8);
    }
    packet.context.set_u64("ipv6::source0_u64", first_8);
    packet.context.set_u64("ipv6::source1_u64", later_8);
    packet
}

#[millefeuille]
pub fn extract_destination_u64(packet: Packet) -> Packet {
    let mut packet = packet;
    let first_8;
    let later_8;
    {
        let field = packet.context.get_field("ipv6::destination");
        first_8 = field.read_u64(0);
        later_8 = field.read_u64(8);
    }
    packet.context.set_u64("ipv6::destination0_u64", first_8);
    packet.context.set_u64("ipv6::destination1_u64", later_8);
    packet
}

#[millefeuille]
pub fn apply_source(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv6::source");
    let value0 = packet.context.get_u64("ipv6::source0_u64");
    let value1 = packet.context.get_u64("ipv6::source1_u64");
    field.write_u64(0, value0);
    field.write_u64(8, value1);
    packet.context.set_field("ipv6::source", field);
    packet
}

#[millefeuille]
pub fn apply_destination(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv6::destination");
    let value0 = packet.context.get_u64("ipv6::destination0_u64");
    let value1 = packet.context.get_u64("ipv6::destination1_u64");
    field.write_u64(0, value0);
    field.write_u64(8, value1);
    packet.context.set_field("ipv6::destination", field);
    packet
}

#[millefeuille]
pub fn extract_version_u8(packet: Packet) -> Packet {
    let mut packet = packet;
    let vtf;
    {
        let field = packet.context.get_field("ipv6::vtf");
        vtf = field.read_u8(0);
    }
    packet.context.set_u8("ipv6::version_u8", (vtf >> 4) & 0x0F);
    packet
}

#[millefeuille]
pub fn apply_version(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv6::vtf");
    let value = packet.context.get_u8("ipv6::version_u8");
    let value = value << 4;
    let value = value | (field.read_u8(0) & 0x0F);
    field.write_u8(0, value);
    packet.context.set_field("ipv6::vtf", field);
    packet
}

#[millefeuille]
pub fn extract_dscp_u8(packet: Packet) -> Packet {
    let mut packet = packet;
    let vtf;
    {
        let field = packet.context.get_field("ipv6::vtf");
        vtf = field.read_u16(0);
    }
    let dscp_ecn = ((vtf >> 4) & 0xFF) as u8;
    packet.context.set_u8("ipv6::dscp_u8", (dscp_ecn >> 2) & 0x3F);
    packet.context.set_alias("ip::dscp_u8", "ipv6::dscp_u8");
    packet
}

pub fn apply_dscp(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv6::vtf");
    let value = packet.context.get_u8("ipv6::dscp_u8");
    let value = value << 2;
    let value = (value as u16) << 4;
    let value = value | (field.read_u16(0) & 0xF03F);
    field.write_u16(0, value);
    packet.context.set_field("ipv6::vtf", field);
    packet
}

#[millefeuille]
pub fn extract_ecn_u8(packet: Packet) -> Packet {
    let mut packet = packet;
    let vtf;
    {
        let field = packet.context.get_field("ipv6::vtf");
        vtf = field.read_u16(0);
    }
    let dscp_ecn = ((vtf >> 4) & 0xFF) as u8;
    packet.context.set_u8("ipv6::ecn_u8", dscp_ecn & 0x03);
    packet.context.set_alias("ip::ecn_u8", "ipv6::ecn_u8");
    packet
}

pub fn apply_ecn(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv6::vtf");
    let value = packet.context.get_u8("ipv6::ecn_u8");
    let value = value & 0x03;
    let value = (value as u16) << 4;
    let value = value | (field.read_u16(0) & 0xFFCF);
    field.write_u16(0, value);
    packet.context.set_field("ipv6::vtf", field);
    packet
}

#[millefeuille]
pub fn extract_flow_u32(packet: Packet) -> Packet {
    let mut packet = packet;
    let vtf;
    {
        let field = packet.context.get_field("ipv6::vtf");
        vtf = field.read_u32(0);
    }
    packet.context.set_u32("ipv6::flow_u32", vtf & 0x000FFFFF);
    packet
}

pub fn apply_flow(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv6::vtf");
    let value = packet.context.get_u32("ipv6::flow_u32");
    let value = value & 0x000FFFFF;
    let value = value | (field.read_u32(0) & 0xFFF00000);
    field.write_u32(0, value);
    packet.context.set_field("ipv6::vtf", field);
    packet
}

#[millefeuille]
pub fn prepare_pseudo_header_u16(packet: Packet) -> Packet {
    let mut sum: u32;
    let ipv6_body;
    {
        let ipv6_src = packet.context.get_field("ipv6::source");
        let ipv6_dst = packet.context.get_field("ipv6::destination");
        let ipv6_proto = packet.context.get_field("ipv6::protocol").read_u8(0);
        let ipv6_hlen = packet.context.get_u32("ipv6::header_length_u32");
        let ipv6_tlen = packet.context.get_u32("ipv6::total_length_u32");

        ipv6_body = ipv6_tlen - ipv6_hlen;
        sum = (ipv6_body & 0x0000FFFF) + (ipv6_body >> 16);
        sum = sum + ipv6_proto as u32;
        sum = sum + ipv6_src.ones_complement_sum_u16(ipv6_src.len()) as u32;
        sum = sum + ipv6_dst.ones_complement_sum_u16(ipv6_dst.len()) as u32;

        while (sum & 0xFFFF0000) > 0 {
            sum = (sum >> 16) + (sum & 0x0000FFFF);
        }
    }
    let mut packet = packet;
    packet.context.set_u16("ipv6::pseudo_csum_u16", sum as u16);
    packet.context.set_alias("ip::pseudo_csum_u16", "ipv6::pseudo_csum_u16");
    packet.context.set_u32("ipv6::payload_length_u32", ipv6_body);
    packet.context.set_alias("ip::payload_length_u32", "ipv6::payload_length_u32");
    packet
}

#[millefeuille]
pub fn has_more_options(packet: Packet) -> Packet {

    let has_next = match packet.context.get_field("ip::protocol").read_u8(0) {
        0x00 |
        0x2B |
        0x2C |
        0x3C |
        0x33 |
        0x32 => true,
        _ => false,
    };
    let mut packet = packet;
    packet.context.set_bool_released("ipv6::more_options_bool", has_next);

    packet
}

#[millefeuille]
pub fn prepare_option_parsing(packet: Packet) -> Packet {
    let mut packet = packet;
    let ipv6_hlen = match packet.context.get_u32_released("ipv6::header_length_u32") {
        Some(x) => x,
        _ => 0, //ipv6 hlen does not include default header
    };
    let ipv6_tlen = match packet.context.get_u32_released("ipv6::total_length_u32") {
        Some(x) => x,
        _ => packet.context.get_field("ipv6::total_length").read_u16(0) as u32,
    };
    packet.context.set_u32_released("ipv6::header_length_u32", ipv6_hlen);
    packet.context.set_u32_released("ipv6::total_length_u32", ipv6_tlen);

    packet
}

#[millefeuille]
pub fn extract_current_option(packet: Packet) -> Packet {
    let ipv6_hlen = packet.context.get_u32("ipv6::header_length_u32");

    let (packet, next_header) = packet.right_packet(1);
    let (packet, ext_len) = packet.right_packet(1);
    let ext_len = ext_len.read_u8(0) << 3; //8 octets
    let mut packet = packet.right_strip(6);
    packet.context.set_field_released("ipv6::protocol", next_header);
    packet.context.set_u32_released("ipv6::header_length_u32", ipv6_hlen + 8 + ext_len as u32);
    packet.right_strip(ext_len as usize)
}

#[millefeuille]
pub fn extract(packet: Packet) -> Packet {
    let packet = extract_vtf(packet);
    let packet = extract_total_length(packet);
    let packet = extract_protocol(packet);
    let packet = extract_hop_limit(packet);
    let packet = extract_source(packet);
    let packet = extract_destination(packet);
    let packet = prepare_option_parsing(packet);

    let mut packet = packet;
    loop {
        packet = has_more_options(packet);
        if !packet.context.get_bool("ipv6::more_options_bool") {
            break;
        }
        packet = extract_current_option(packet);
    }

    packet = prepare_pseudo_header_u16(packet);

    packet
}

#[millefeuille]
pub fn fill(packet: Packet) -> Packet {
    let packet = fill_destination(packet);
    let packet = fill_source(packet);
    let packet = fill_hop_limit(packet);
    let packet = fill_protocol(packet);
    let packet = fill_total_length(packet);
    let packet = fill_vtf(packet);

    packet
}