FPS 0.0.3

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

extract_field!(extract_vhl, ipv4, 1, vhl);
fill_field!(fill_vhl, ipv4, 1, vhl);

extract_field!(extract_dscp_ecn, ipv4, 1, dscp_ecn);
fill_field!(fill_dscp_ecn, ipv4, 1, dscp_ecn);

extract_field!(extract_identification, ipv4, 2, identification);
fill_field!(fill_identification, ipv4, 2, identification);
extract_field_value!(extract_identification_u16, ipv4, identification, u16);
apply_field_value!(apply_identification, ipv4, identification, u16);

extract_field!(extract_fragment, ipv4, 2, fragment);
fill_field!(fill_fragment, ipv4, 2, fragment);

extract_field!(extract_header_checksum, ipv4, 2, header_checksum);
fill_field!(fill_header_checksum, ipv4, 2, header_checksum);
extract_field_value!(extract_header_checksum_u16, ipv4, header_checksum, u16);
apply_field_value!(apply_header_checksum, ipv4, header_checksum, u16);

extract_field!(extract_source, ipv4, 4, source);
fill_field!(fill_source, ipv4, 4, source);
extract_field_value!(extract_source_u32, ipv4, source, u32);
apply_field_value!(apply_source, ipv4, source, u32);

extract_field!(extract_destination, ipv4, 4, destination);
fill_field!(fill_destination, ipv4, 4, destination);
extract_field_value!(extract_destination_u32, ipv4, destination, u32);
apply_field_value!(apply_destination, ipv4, destination, u32);

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

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

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

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

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

#[millefeuille]
pub fn extract_header_length_u8(packet: Packet) -> Packet {
    let mut packet = packet;
    let ihl;
    {
        let field = packet.context.get_field("ipv4::vhl");
        ihl = field.read_u8(0);
    }
    packet.context.set_u8("ipv4::header_length_u8", (ihl & 0x0F) << 2);
    packet
}

#[millefeuille]
pub fn apply_header_length(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv4::vhl");
    let value = packet.context.get_u8("ipv4::header_length_u8");
    let value = value >> 2;
    let value = value | (field.read_u8(0) & 0xF0);
    field.write_u8(0, value);
    packet.context.set_field("ipv4::vhl", field);
    packet
}

#[millefeuille]
pub fn extract_dscp_u8(packet: Packet) -> Packet {
    let mut packet = packet;
    let dscp_ecn;
    {
        let field = packet.context.get_field("ipv4::dscp_ecn");
        dscp_ecn = field.read_u8(0);
    }
    packet.context.set_u8("ipv4::dscp_u8", (dscp_ecn >> 2) & 0x3F);
    packet.context.set_alias("ip::dscp_u8", "ipv4::dscp_u8");
    packet
}

#[millefeuille]
pub fn apply_dscp(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv4::dscp_ecn");
    let value = packet.context.get_u8("ipv4::dscp_u8");
    let value = value << 2;
    let value = value | (field.read_u8(0) & 0x03);
    field.write_u8(0, value);
    packet.context.set_field("ipv4::dscp_ecn", field);
    packet
}

#[millefeuille]
pub fn extract_ecn_u8(packet: Packet) -> Packet {
    let mut packet = packet;
    let dscp_ecn;
    {
        let field = packet.context.get_field("ipv4::dscp_ecn");
        dscp_ecn = field.read_u8(0);
    }
    packet.context.set_u8("ipv4::ecn_u8", dscp_ecn & 0x03);
    packet.context.set_alias("ip::ecn_u8", "ipv4::ecn_u8");
    packet
}

#[millefeuille]
pub fn apply_ecn(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv4::dscp_ecn");
    let value = packet.context.get_u8("ipv4::ecn_u8");
    let value = value & 0x03;
    let value = value | (field.read_u8(0) & 0x3F);
    field.write_u8(0, value);
    packet.context.set_field("ipv4::dscp_ecn", field);
    packet
}

#[millefeuille]
pub fn extract_fragment_flag_u8(packet: Packet) -> Packet {
    let mut packet = packet;
    let fragment;
    {
        let field = packet.context.get_field("ipv4::fragment");
        fragment = field.read_u8(0);
    }
    packet.context.set_u8("ipv4::fragment_flag_u8", (fragment >> 5) & 0x03);
    packet
}

#[millefeuille]
pub fn apply_fragment_flag(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv4::fragment");
    let value = packet.context.get_u8("ipv4::fragment_flag_u8");
    let value = value << 5;
    let value = value | (field.read_u8(0) & 0x1F);
    field.write_u8(0, value);
    packet.context.set_field("ipv4::fragment", field);
    packet
}

#[millefeuille]
pub fn extract_fragment_offset_u16(packet: Packet) -> Packet {
    let mut packet = packet;
    let fragment;
    {
        let field = packet.context.get_field("ipv4::fragment");
        fragment = field.read_u16(0);
    }
    packet.context.set_u16("ipv4::fragment_offset_u16", ((fragment) & 0x1FFF) << 3);
    packet
}

#[millefeuille]
pub fn apply_fragment_offset(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv4::fragment");
    let value = packet.context.get_u16("ipv4::fragment_offset_u16");
    let value = value >> 3;
    let value = value | (field.read_u16(0) & 0xE000);
    field.write_u16(0, value);
    packet.context.set_field("ipv4::fragment", field);
    packet
}

#[millefeuille]
pub fn extract_option(packet: Packet) -> Packet {
    let ihl;
    {
        let field = packet.context.get_field("ipv4::vhl");
        ihl = field.read_u8(0) & 0x0F;
    }

    assert!(ihl >= 5);
    let option_bytes = ((ihl - 5) << 2) as usize;
    let (mut packet, field) = packet.right_packet(option_bytes);
    packet.context.set_field("ipv4::option", field);
    packet
}

#[millefeuille]
pub fn verify_header_checksum(packet: Packet) -> Packet {
    let mut packet = packet;
    let header_length;
    {
        header_length = (packet.read_u8(0) & 0xFF) << 2;
    }
    let result = packet.ones_complement_sum_u16(header_length as usize);
    packet.context.set_u16("ipv4::current_csum_u16", result);
    packet.context.set_bool("ipv4::correct_csum_bool",
                            (result == 0xFFFF) || (result == 0x0000));
    packet
}

#[millefeuille]
pub fn apply_current_checksum(packet: Packet) -> Packet {
    let mut packet = packet;
    let mut field = packet.context.take_field("ipv4::header_checksum");
    let current = packet.context.get_u16("ipv4::current_csum_u16");
    let csum = field.read_u16(0);
    let current = (!csum) as u32 + current as u32;
    let current = ((current >> 16) + (current & 0xFFFF)) as u16;
    field.write_u16(0, !current);
    packet.context.set_bool_released("ipv4::correct_csum_bool", true);
    packet.context.set_u16_released("ipv4::current_csum_u16", 0);
    packet.context.set_field("ipv4::header_checksum", field);
    
    packet
}

#[millefeuille]
pub fn prepare_pseudo_header_u16(packet: Packet) -> Packet {
    let mut sum: u32;
    let playload_len;
    {
        let ipv4_src = packet.context.get_field("ipv4::source");
        let ipv4_dst = packet.context.get_field("ipv4::destination");
        let ipv4_proto = packet.context.get_field("ipv4::protocol").read_u8(0);

        let ipv4_hlen;
        {
            let field = packet.context.get_field("ipv4::vhl");
            ipv4_hlen = field.read_u8(0);
        }
        let ipv4_hlen = (ipv4_hlen & 0x0F) << 2;
        let ipv4_tlen = packet.context.get_field("ipv4::total_length").read_u16(0);

        playload_len = (ipv4_tlen - (ipv4_hlen as u16)) as u32;
        sum = playload_len;
        sum = sum + (ipv4_proto as u16) as u32;
        sum = sum + ipv4_src.ones_complement_sum_u16(ipv4_src.len()) as u32;
        sum = sum + ipv4_dst.ones_complement_sum_u16(ipv4_dst.len()) as u32;

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

#[millefeuille]
pub fn extract(packet: Packet) -> Packet {
    let packet = verify_header_checksum(packet);
    let packet = extract_vhl(packet);
    let packet = extract_dscp_ecn(packet);
    let packet = extract_total_length(packet);
    let packet = extract_identification(packet);
    let packet = extract_fragment(packet);
    let packet = extract_hop_limit(packet);
    let packet = extract_protocol(packet);
    let packet = extract_header_checksum(packet);
    let packet = extract_source(packet);
    let packet = extract_destination(packet);
    let packet = extract_option(packet);
    let 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_header_checksum(packet);
    let packet = fill_protocol(packet);
    let packet = fill_hop_limit(packet);
    let packet = fill_fragment(packet);
    let packet = fill_identification(packet);
    let packet = fill_total_length(packet);
    let packet = fill_dscp_ecn(packet);
    let packet = fill_vhl(packet);

    packet
}