diff options
Diffstat (limited to 'src/protocol/ppp.rs')
| -rw-r--r-- | src/protocol/ppp.rs | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/src/protocol/ppp.rs b/src/protocol/ppp.rs new file mode 100644 index 0000000..97fa0e5 --- /dev/null +++ b/src/protocol/ppp.rs @@ -0,0 +1,120 @@ +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, Eq)] +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(Clone, Debug, PartialEq, Eq)] +pub struct PPPHeader { + pub address: u8, + pub control: u8, + pub protocol: PPPProtocol, +} + +/****************************************************************************** + * API + ******************************************************************************/ + +impl From<u16> 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)?; + + Ok((input, protocol.into())) + } +} + +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); + } +} |
