use crate::protocol::codec::Decode; use nom::number; use nom::IResult; /****************************************************************************** * Struct ******************************************************************************/ // https://www.iana.org/assignments/ppp-numbers/ppp-numbers.xhtml #[derive(Clone, Copy, Debug, PartialEq)] pub enum PPPProtocol { PAD, // Padding Protocol IPv4, // Internet Protocol version 4 (IPv4) IPv6, // Internet Protocol version 6 (IPv6) IPCP, // Internet Protocol Control Protocol (IPCP) CCP, // Compression Control Protocol (CCP) LCP, // Link Control Protocol (LCP) PAP, // Password Authentication Protocol (PAP) CHAP, // Challenge Handshake Authentication Protocol (CHAP) Other(u16), } // https://www.rfc-editor.org/rfc/rfc1661.html #[derive(Debug, PartialEq)] pub struct PPPHeader { pub address: u8, pub control: u8, pub protocol: PPPProtocol, } /****************************************************************************** * API ******************************************************************************/ impl From for PPPProtocol { fn from(raw: u16) -> Self { match raw { 0x0001 => PPPProtocol::PAD, 0x0021 => PPPProtocol::IPv4, 0x0057 => PPPProtocol::IPv6, 0x8021 => PPPProtocol::IPCP, 0x80FD => PPPProtocol::CCP, 0xC021 => PPPProtocol::LCP, 0xC023 => PPPProtocol::PAP, 0xC223 => PPPProtocol::CHAP, other => PPPProtocol::Other(other), } } } impl Decode for PPPProtocol { type Iterm = PPPProtocol; fn decode(input: &[u8]) -> IResult<&[u8], PPPProtocol> { let (input, protocol) = number::streaming::be_u16(input).map(|(i, l)| (i, l.into()))?; Ok((input, protocol)) } } impl Decode for PPPHeader { type Iterm = PPPHeader; fn decode(input: &[u8]) -> IResult<&[u8], PPPHeader> { let (input, address) = number::streaming::be_u8(input)?; let (input, control) = number::streaming::be_u8(input)?; let (input, protocol) = PPPProtocol::decode(input)?; Ok(( input, PPPHeader { address, control, protocol, }, )) } } /****************************************************************************** * TEST ******************************************************************************/ #[cfg(test)] mod tests { use super::PPPHeader; use super::PPPProtocol; use crate::protocol::codec::Decode; const LAST_SLICE: &'static [u8] = &[0xff]; #[test] fn ppp_header_decode() { /* * Point-to-Point Protocol * Address: 0xff * Control: 0x03 * Protocol: Link Control Protocol (0xc021) */ let bytes = [0xff, 0x03, 0xc0, 0x21, 0xff /* Payload */]; let expectation = PPPHeader { address: 0xff, control: 0x03, protocol: PPPProtocol::LCP, }; assert_eq!(PPPHeader::decode(&bytes), Ok((LAST_SLICE, expectation))); // example let result = PPPHeader::decode(&bytes); match result { Ok((payload, header)) => { println!("OK: {:?}, payload: {}", header, payload.len()); } Err(e) => { println!("ERR: {:?}", e); } } // assert_eq!(1, 0); } }