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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
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);
if let Ok((payload, header)) = result {
println!("return: {:?}, payload: {}", header, payload.len());
} else {
println!("return: Incomplete data");
}
}
}
|