summaryrefslogtreecommitdiff
path: root/src/protocol/vlan.rs
blob: 7f647800880cbfe0f3e328a3b04983b286159341 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use crate::protocol::codec::Decode;
use crate::protocol::ethernet::EtherType;
use nom::bits;
use nom::error::Error;
use nom::sequence;
use nom::IResult;

/******************************************************************************
 * Struct
 ******************************************************************************/

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct VlanHeader {
    // A 3 bit number which refers to the IEEE 802.1p class of service and maps to the frame priority level.
    pub priority_code_point: u8,
    // Indicate that the frame may be dropped under the presence of congestion.
    pub drop_eligible_indicator: bool,
    // 12 bits vland identifier.
    pub vlan_identifier: u16,
    // "Tag protocol identifier": Type id of content after this header. Refer to the "EtherType" for a list of possible supported values.
    pub ether_type: EtherType,
}

/******************************************************************************
 * API
 ******************************************************************************/

fn bit_decode(input: &[u8]) -> IResult<&[u8], (u8, u8, u16)> {
    bits::bits::<_, _, Error<_>, _, _>(sequence::tuple((
        bits::streaming::take(3u8),
        bits::streaming::take(1u8),
        bits::streaming::take(12u8),
    )))(input)
}

impl Decode for VlanHeader {
    type Iterm = VlanHeader;
    fn decode(input: &[u8]) -> IResult<&[u8], VlanHeader> {
        let (input, (priority_code_point, drop_eligible_indicator, vlan_identifier)) =
            bit_decode(input)?;
        let (input, ether_type) = EtherType::decode(input)?;
        Ok((
            input,
            VlanHeader {
                priority_code_point,
                drop_eligible_indicator: drop_eligible_indicator == 1,
                vlan_identifier,
                ether_type,
            },
        ))
    }
}

/******************************************************************************
 * TEST
 ******************************************************************************/

#[cfg(test)]
mod tests {
    use super::VlanHeader;
    use crate::protocol::codec::Decode;
    use crate::protocol::ethernet::EtherType;
    const LAST_SLICE: &'static [u8] = &[0xff];

    #[test]
    fn vlan_header_decode() {
        /*
         * 802.1Q Virtual LAN, PRI: 0, DEI: 0, ID: 32
         *     000. .... .... .... = Priority: Best Effort (default) (0)
         *     ...0 .... .... .... = DEI: Ineligible
         *     .... 0000 0010 0000 = ID: 32
         *     Type: IPv4 (0x0800)
         */
        let bytes = [0x00, 0x20, 0x08, 0x00, 0xff /* Payload */];

        let expectation = VlanHeader {
            priority_code_point: 0,
            drop_eligible_indicator: false,
            vlan_identifier: 32,
            ether_type: EtherType::IPv4,
        };

        assert_eq!(VlanHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));

        // example
        let result = VlanHeader::decode(&bytes);
        if let Ok((payload, header)) = result {
            println!("return: {:?}, payload: {}", header, payload.len());
        } else {
            println!("return: Incomplete data");
        }
    }
}