use crate::protocol::codec::Decode; use crate::protocol::ethernet::EthType; use nom::bits; use nom::error::Error; use nom::number; use nom::sequence; use nom::IResult; /****************************************************************************** * Struct ******************************************************************************/ /* * Enhanced GRE header (Version 1) * * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |C|R|K|S|s|Recur|A| Flags | Ver | Protocol Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Key (HW) Payload Length | Key (LW) Call ID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Sequence Number (Optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Acknowledgment Number (Optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * https://datatracker.ietf.org/doc/html/rfc2637 */ #[derive(Debug, PartialEq)] pub struct GREv1Header { pub flag_checksum: bool, pub flag_routing: bool, pub flag_key: bool, pub flag_sequence: bool, pub flag_strictroute: bool, pub recursion_control: u8, pub flag_acknowledgment: bool, pub flags: u8, pub version: u8, pub protocol_type: EthType, pub key_payload_length: u16, pub key_call_id: u16, pub sequence_number: Option, pub acknowledgment_number: Option, } /****************************************************************************** * API ******************************************************************************/ impl Decode for GREv1Header { type Iterm = GREv1Header; fn decode(input: &[u8]) -> IResult<&[u8], GREv1Header> { let ( input, ( flag_checksum, flag_routing, flag_key, flag_sequence, flag_strictroute, recursion_control, flag_acknowledgment, flags, version, ), ): (&[u8], (u8, u8, u8, u8, u8, u8, u8, u8, u8)) = bits::bits::<_, _, Error<_>, _, _>(sequence::tuple(( bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(3u8), bits::streaming::take(1u8), bits::streaming::take(4u8), bits::streaming::take(3u8), )))(input)?; if version != 1 { return Err(nom::Err::Error(Error::new( input, nom::error::ErrorKind::Verify, ))); } let (input, protocol_type) = EthType::decode(input)?; let (input, key_payload_length) = number::streaming::be_u16(input)?; let (input, key_call_id) = number::streaming::be_u16(input)?; let (input, sequence_number) = match flag_sequence { 0 => (input, None), _ => number::streaming::be_u32(input).map(|(i, l)| (i, Some(l)))?, }; let (input, acknowledgment_number) = match flag_acknowledgment { 0 => (input, None), _ => number::streaming::be_u32(input).map(|(i, l)| (i, Some(l)))?, }; Ok(( input, GREv1Header { flag_checksum: flag_checksum == 1, flag_routing: flag_routing == 1, flag_key: flag_key == 1, flag_sequence: flag_sequence == 1, flag_strictroute: flag_strictroute == 1, recursion_control, flag_acknowledgment: flag_acknowledgment == 1, flags, version, protocol_type, key_payload_length, key_call_id, sequence_number, acknowledgment_number, }, )) } } /****************************************************************************** * TEST ******************************************************************************/ #[cfg(test)] mod tests { use super::GREv1Header; use crate::protocol::codec::Decode; use crate::protocol::ethernet::EthType; const LAST_SLICE: &'static [u8] = &[0xff]; #[test] fn grev1_header_decode() { /* * Generic Routing Encapsulation (PPP) * Flags and Version: 0x3081 * 0... .... .... .... = Checksum Bit: No * .0.. .... .... .... = Routing Bit: No * ..1. .... .... .... = Key Bit: Yes * ...1 .... .... .... = Sequence Number Bit: Yes * .... 0... .... .... = Strict Source Route Bit: No * .... .000 .... .... = Recursion control: 0 * .... .... 1... .... = Acknowledgment: Yes * .... .... .000 0... = Flags (Reserved): 0 * .... .... .... .001 = Version: Enhanced GRE (1) * Protocol Type: PPP (0x880b) * Payload Length: 103 * Call ID: 6016 * Sequence Number: 430001 * Acknowledgment Number: 539254 */ let bytes = [ 0x30, 0x81, 0x88, 0x0b, 0x00, 0x67, 0x17, 0x80, 0x00, 0x06, 0x8f, 0xb1, 0x00, 0x08, 0x3a, 0x76, 0xff, /* Payload */ ]; let expectation = GREv1Header { flag_checksum: false, flag_routing: false, flag_key: true, flag_sequence: true, flag_strictroute: false, recursion_control: 0, flag_acknowledgment: true, flags: 0, version: 1, protocol_type: EthType::PPP, key_payload_length: 103, key_call_id: 6016, sequence_number: Some(430001), acknowledgment_number: Some(539254), }; assert_eq!(GREv1Header::decode(&bytes), Ok((LAST_SLICE, expectation))); // example let result = GREv1Header::decode(&bytes); match result { Ok((payload, header)) => { println!("OK: {:?}, payload: {}", header, payload.len()); } Err(e) => { println!("ERR: {:?}", e); } } // assert_eq!(1, 0); } }