use crate::protocol::codec::Decode; use nom::bits; use nom::bytes; use nom::error::Error; use nom::number; use nom::sequence; use nom::IResult; /****************************************************************************** * Struct ******************************************************************************/ #[derive(Debug, PartialEq)] pub struct GTPv1Option { pub sequence_number: u16, // 16bit pub npdu_number: u8, // 8bit pub next_header_type: u8, // 8bit } #[derive(Debug, PartialEq)] pub struct GTPv1ExtensionHeader { pub length: u8, // 8bit (单位4字节,包括长度/内容/下一扩展消息头字段) pub contents: Vec, pub next_header_type: u8, // 8bit } #[derive(Debug, PartialEq)] pub struct GTPv1Header { pub version: u8, // 3bit 1: GTPv1 pub protocol_type: u8, // 1bit pub reserved: u8, // 1bit pub extension_header_flag: u8, // 1bit pub sequence_number_flag: u8, // 1bit pub npdu_number_flag: u8, // 1bit pub message_type: u8, // 8bit pub message_length: u16, // 16bit (单位为字节,不包括GTP头前8字节的必选字段) pub teid: u32, // 32bit // extension_header_flag/sequence_number_flag/npdu_number_flag任意一个取值为1时options字段才存在 pub options: Option, pub extensions: Vec, } /****************************************************************************** * API ******************************************************************************/ fn bit_decode(input: &[u8]) -> IResult<&[u8], (u8, u8, u8, u8, u8, u8)> { bits::bits::<_, _, Error<_>, _, _>(sequence::tuple(( bits::streaming::take(3u8), bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(1u8), bits::streaming::take(1u8), )))(input) } fn option_decode(input: &[u8]) -> IResult<&[u8], GTPv1Option> { let (input, sequence_number) = number::streaming::be_u16(input)?; let (input, npdu_number) = number::streaming::be_u8(input)?; let (input, next_header_type) = number::streaming::be_u8(input)?; Ok(( input, GTPv1Option { sequence_number, npdu_number, next_header_type, }, )) } fn extension_decode(input: &[u8]) -> IResult<&[u8], GTPv1ExtensionHeader> { let (input, length) = number::streaming::be_u8(input)?; if length * 4 < 2 { return Err(nom::Err::Incomplete(nom::Needed::new( (2 - length * 4).into(), ))); } let (input, contents) = bytes::streaming::take(length * 4 - 2)(input).map(|(i, l)| (i, l.to_vec()))?; let (input, next_header_type) = number::streaming::be_u8(input)?; Ok(( input, GTPv1ExtensionHeader { length, contents, next_header_type, }, )) } impl Decode for GTPv1Header { type Iterm = GTPv1Header; fn decode(input: &[u8]) -> IResult<&[u8], GTPv1Header> { let ( input, ( version, protocol_type, reserved, extension_header_flag, sequence_number_flag, npdu_number_flag, ), ) = bit_decode(input)?; match (version, protocol_type) { (1, 1) => (), (_, _) => { return Err(nom::Err::Error(Error::new( input, nom::error::ErrorKind::TagBits, ))) } } let (input, message_type) = number::streaming::be_u8(input)?; let (input, message_length) = number::streaming::be_u16(input)?; let (input, teid) = number::streaming::be_u32(input)?; // Optional word of GTP header, present if any of extension_header_flag, sequence_number_flag, npdu_number_flag is set let mut remain = input; let mut options = None; if extension_header_flag == 1 || sequence_number_flag == 1 || npdu_number_flag == 1 { let (left, _options) = option_decode(remain)?; remain = left; options = Some(_options); } let mut extensions = Vec::new(); let ref_options = &options; match ref_options { Some(ref _options) => { let mut next_header = _options.next_header_type; while next_header != 0 { let (left, extension) = extension_decode(remain)?; remain = left; next_header = extension.next_header_type; extensions.push(extension); } } None => (), } Ok(( remain, GTPv1Header { version, protocol_type, reserved, extension_header_flag, sequence_number_flag, npdu_number_flag, message_type, message_length, teid, options, extensions, }, )) } } /****************************************************************************** * TEST ******************************************************************************/ #[cfg(test)] mod tests { use super::GTPv1ExtensionHeader; use super::GTPv1Header; use crate::protocol::codec::Decode; const LAST_SLICE: &'static [u8] = &[0xff]; #[test] fn gtpv1_header_decode() { /* * GPRS Tunneling Protocol * Flags: 0x30 * 001. .... = Version: GTP release 99 version (1) * ...1 .... = Protocol type: GTP (1) * .... 0... = Reserved: 0 * .... .0.. = Is Next Extension Header present?: No * .... ..0. = Is Sequence Number present?: No * .... ...0 = Is N-PDU number present?: No * Message Type: T-PDU (0xff) * Length: 64 * TEID: 0x1f54d4b5 (525653173) */ let bytes = [ 0x30, 0xff, 0x00, 0x40, 0x1f, 0x54, 0xd4, 0xb5, 0xff, /* Payload */ ]; let expectation = GTPv1Header { version: 1, protocol_type: 1, reserved: 0, extension_header_flag: 0, sequence_number_flag: 0, npdu_number_flag: 0, message_type: 0xff, message_length: 64, teid: 525653173, options: None, extensions: vec![], }; assert_eq!(GTPv1Header::decode(&bytes), Ok((LAST_SLICE, expectation))); // example let result = GTPv1Header::decode(&bytes); match result { Ok((payload, header)) => { println!("OK: {:?}, payload: {}", header, payload.len()); } Err(e) => { println!("ERR: {:?}", e); } } // assert_eq!(1, 0); } #[test] fn gtpv1_extension_decode() { /* * GPRS Tunneling Protocol * Flags: 0x36 * 001. .... = Version: GTP release 99 version (1) * ...1 .... = Protocol type: GTP (1) * .... 0... = Reserved: 0 * .... .1.. = Is Next Extension Header present?: Yes * .... ..1. = Is Sequence Number present?: Yes * .... ...0 = Is N-PDU number present?: No * Message Type: T-PDU (0xff) * Length: 48 * TEID: 0x1c6596fc (476419836) * Sequence number: 0x6739 (26425) * Next extension header type: PDU Session container (0x85) * Extension header (PDU Session container) * Extension Header Length: 1 * PDU Session Container * 0001 .... = PDU Type: UL PDU SESSION INFORMATION (1) * .... 0000 = Spare: 0x0 * 00.. .... = Spare: 0x0 * ..00 0001 = QoS Flow Identifier (QFI): 1 * Next extension header type: No more extension headers (0x00) */ let bytes = [ 0x36, 0xff, 0x00, 0x30, 0x1c, 0x65, 0x96, 0xfc, 0x67, 0x39, 0x00, 0x85, 0x01, 0x10, 0x01, 0x00, 0xff, /* Payload */ ]; let expectation = GTPv1Header { version: 1, protocol_type: 1, reserved: 0, extension_header_flag: 1, sequence_number_flag: 1, npdu_number_flag: 0, message_type: 0xff, message_length: 48, teid: 476419836, options: Some(super::GTPv1Option { sequence_number: 26425, npdu_number: 0, next_header_type: 0x85, }), extensions: vec![GTPv1ExtensionHeader { length: 1, contents: vec![0x10, 0x01], next_header_type: 0x00, }], }; assert_eq!(GTPv1Header::decode(&bytes), Ok((LAST_SLICE, expectation))); // example let result = GTPv1Header::decode(&bytes); match result { Ok((payload, header)) => { println!("OK: {:?}, payload: {}", header, payload.len()); } Err(e) => { println!("ERR: {:?}", e); } } // assert_eq!(1, 0); } }