summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorluwenpeng <[email protected]>2023-09-21 14:52:05 +0800
committerluwenpeng <[email protected]>2023-09-21 14:52:05 +0800
commit1582aaa3a8cf6b70329ae6d8a248120c34d52669 (patch)
treef42c1b8b6d3dcf0f683ea227e155a78cd1628492 /src
parentae80f71eba09d4381bb070d87bcd2aa6173166c6 (diff)
[feature] Support PPTP Decode
Diffstat (limited to 'src')
-rw-r--r--src/main.rs3
-rw-r--r--src/packet/error.rs3
-rw-r--r--src/packet/packet.rs224
-rw-r--r--src/protocol/mod.rs3
-rw-r--r--src/protocol/pptp.rs770
5 files changed, 1001 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs
index 154a6fe..2efb827 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -63,6 +63,9 @@ fn trigger_packet_event(
Encapsulation::L2tp(_, _) => {
// TODO
}
+ Encapsulation::Pptp(_, _) => {
+ // TODO
+ }
}
}
}
diff --git a/src/packet/error.rs b/src/packet/error.rs
index a9e39a1..b9ca7cf 100644
--- a/src/packet/error.rs
+++ b/src/packet/error.rs
@@ -36,6 +36,8 @@ pub enum PacketError {
IncompleteL2tpHeader,
UnsupportL2tpVersion,
+
+ IncompletePptpHeader,
}
impl core::fmt::Display for PacketError {
@@ -69,6 +71,7 @@ impl core::fmt::Display for PacketError {
PacketError::UnsupportGtpVersion => write!(f, "Unsupport GTP Version"),
PacketError::IncompleteL2tpHeader => write!(f, "Incomplete L2TP Header"),
PacketError::UnsupportL2tpVersion => write!(f, "Unsupport L2TP Version"),
+ PacketError::IncompletePptpHeader => write!(f, "Incomplete PPTP Header"),
}
}
}
diff --git a/src/packet/packet.rs b/src/packet/packet.rs
index cc9e2d7..13140be 100644
--- a/src/packet/packet.rs
+++ b/src/packet/packet.rs
@@ -14,6 +14,7 @@ use crate::protocol::l2tp::L2tpHeader;
use crate::protocol::l2tp::L2tpType;
use crate::protocol::mpls::MplsHeader;
use crate::protocol::mpls::PwEthHeader;
+use crate::protocol::pptp::PptpHeader;
use crate::protocol::tcp::TcpHeader;
use crate::protocol::udp::UdpHeader;
use crate::protocol::vlan::VlanHeader;
@@ -39,6 +40,7 @@ pub enum Encapsulation<'a> {
Gtpv1(Gtpv1Header, &'a [u8]),
L2tp(L2tpHeader, &'a [u8]),
+ Pptp(PptpHeader, &'a [u8]),
}
#[derive(Debug)]
@@ -479,13 +481,23 @@ fn handle_tcp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packet
if let Ok((payload, header)) = result {
dbg!(&header);
+ let source_port = header.source_port;
+ let dest_port = header.dest_port;
packet
.encapsulation
.push(Encapsulation::Tcp(header, payload));
// TODO TCP Reassembly
- return Ok(());
+ if payload.len() == 0 {
+ return Ok(());
+ }
+
+ match (source_port, dest_port) {
+ // PPTP
+ (1723, _) | (_, 1723) => handle_pptp(packet, payload),
+ _ => Ok(()),
+ }
} else {
return Err(PacketError::IncompleteTcpHeader);
}
@@ -646,6 +658,21 @@ fn handle_gre<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), Packet
}
}
+fn handle_pptp<'a>(packet: &mut Packet<'a>, input: &'a [u8]) -> Result<(), PacketError> {
+ let result = PptpHeader::decode(input);
+ if let Ok((payload, header)) = result {
+ dbg!(&header);
+
+ packet
+ .encapsulation
+ .push(Encapsulation::Pptp(header, payload));
+
+ return Ok(());
+ } else {
+ return Err(PacketError::IncompletePptpHeader);
+ }
+}
+
fn handle_l3<'a>(
packet: &mut Packet<'a>,
input: &'a [u8],
@@ -705,6 +732,9 @@ mod tests {
use crate::protocol::ipv6::Ipv6Header;
use crate::protocol::mpls::MplsHeader;
use crate::protocol::mpls::PwEthHeader;
+ use crate::protocol::pptp::PptpControlMessageType;
+ use crate::protocol::pptp::PptpHeader;
+ use crate::protocol::pptp::PptpMessageType;
use crate::protocol::tcp::TcpHeader;
use crate::protocol::tcp::TcpOption;
use crate::protocol::udp::UdpHeader;
@@ -3006,4 +3036,196 @@ mod tests {
// assert_eq!(1, 0);
}
+
+ #[test]
+ fn test_packet_handle_eth_ipv4_tcp_pptp() {
+ /*
+ * Frame 11: 78 bytes on wire (624 bits), 78 bytes captured (624 bits)
+ * Encapsulation type: Ethernet (1)
+ * Arrival Time: Jul 20, 2016 10:34:53.718678000 CST
+ * [Time shift for this packet: 0.000000000 seconds]
+ * Epoch Time: 1468982093.718678000 seconds
+ * [Time delta from previous captured frame: 0.015937000 seconds]
+ * [Time delta from previous displayed frame: 0.000000000 seconds]
+ * [Time since reference or first frame: 0.074252000 seconds]
+ * Frame Number: 11
+ * Frame Length: 78 bytes (624 bits)
+ * Capture Length: 78 bytes (624 bits)
+ * [Frame is marked: False]
+ * [Frame is ignored: False]
+ * [Protocols in frame: eth:ethertype:ip:tcp:pptp]
+ * [Coloring Rule Name: TCP]
+ * [Coloring Rule String: tcp]
+ * Ethernet II, Src: LCFCHeFe_43:38:37 (28:d2:44:43:38:37), Dst: c0:00:14:8c:00:00 (c0:00:14:8c:00:00)
+ * Destination: c0:00:14:8c:00:00 (c0:00:14:8c:00:00)
+ * Address: c0:00:14:8c:00:00 (c0:00:14:8c:00:00)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Source: LCFCHeFe_43:38:37 (28:d2:44:43:38:37)
+ * Address: LCFCHeFe_43:38:37 (28:d2:44:43:38:37)
+ * .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
+ * .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
+ * Type: IPv4 (0x0800)
+ * Internet Protocol Version 4, Src: 172.16.0.100, Dst: 172.16.0.254
+ * 0100 .... = Version: 4
+ * .... 0101 = Header Length: 20 bytes (5)
+ * Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
+ * 0000 00.. = Differentiated Services Codepoint: Default (0)
+ * .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
+ * Total Length: 64
+ * Identification: 0x0a28 (2600)
+ * 010. .... = Flags: 0x2, Don't fragment
+ * 0... .... = Reserved bit: Not set
+ * .1.. .... = Don't fragment: Set
+ * ..0. .... = More fragments: Not set
+ * ...0 0000 0000 0000 = Fragment Offset: 0
+ * Time to Live: 128
+ * Protocol: TCP (6)
+ * Header Checksum: 0x970d [correct]
+ * [Header checksum status: Good]
+ * [Calculated Checksum: 0x970d]
+ * Source Address: 172.16.0.100
+ * Destination Address: 172.16.0.254
+ * Transmission Control Protocol, Src Port: 50112, Dst Port: 1723, Seq: 325, Ack: 189, Len: 24
+ * Source Port: 50112
+ * Destination Port: 1723
+ * [Stream index: 0]
+ * [Conversation completeness: Complete, WITH_DATA (63)]
+ * [TCP Segment Len: 24]
+ * Sequence Number: 325 (relative sequence number)
+ * Sequence Number (raw): 2945311102
+ * [Next Sequence Number: 349 (relative sequence number)]
+ * Acknowledgment Number: 189 (relative ack number)
+ * Acknowledgment number (raw): 3263707926
+ * 0101 .... = Header Length: 20 bytes (5)
+ * Flags: 0x018 (PSH, ACK)
+ * 000. .... .... = Reserved: Not set
+ * ...0 .... .... = Accurate ECN: Not set
+ * .... 0... .... = Congestion Window Reduced: Not set
+ * .... .0.. .... = ECN-Echo: Not set
+ * .... ..0. .... = Urgent: Not set
+ * .... ...1 .... = Acknowledgment: Set
+ * .... .... 1... = Push: Set
+ * .... .... .0.. = Reset: Not set
+ * .... .... ..0. = Syn: Not set
+ * .... .... ...0 = Fin: Not set
+ * [TCP Flags: ·······AP···]
+ * Window: 65332
+ * [Calculated window size: 65332]
+ * [Window size scaling factor: -2 (no window scaling used)]
+ * Checksum: 0xa732 [correct]
+ * [Checksum Status: Good]
+ * [Calculated Checksum: 0xa732]
+ * Urgent Pointer: 0
+ * [Timestamps]
+ * [Time since first frame in this TCP stream: 0.058594000 seconds]
+ * [Time since previous frame in this TCP stream: 0.015937000 seconds]
+ * [SEQ/ACK analysis]
+ * [This is an ACK to the segment in frame: 10]
+ * [The RTT to ACK the segment was: 0.015937000 seconds]
+ * [iRTT: 0.011036000 seconds]
+ * [Bytes in flight: 24]
+ * [Bytes sent since last PSH flag: 24]
+ * TCP payload (24 bytes)
+ * Point-to-Point Tunnelling Protocol
+ * Length: 24
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Set-Link-Info (15)
+ * Reserved: 0000
+ * Peer Call ID: 3
+ * Reserved: 0000
+ * Send ACCM: 0xffffffff
+ * Receive ACCM: 0xffffffff
+ *
+ */
+
+ let bytes = [
+ 0xc0, 0x00, 0x14, 0x8c, 0x00, 0x00, 0x28, 0xd2, 0x44, 0x43, 0x38, 0x37, 0x08, 0x00,
+ 0x45, 0x00, 0x00, 0x40, 0x0a, 0x28, 0x40, 0x00, 0x80, 0x06, 0x97, 0x0d, 0xac, 0x10,
+ 0x00, 0x64, 0xac, 0x10, 0x00, 0xfe, 0xc3, 0xc0, 0x06, 0xbb, 0xaf, 0x8d, 0xe1, 0x7e,
+ 0xc2, 0x88, 0x3b, 0x16, 0x50, 0x18, 0xff, 0x34, 0xa7, 0x32, 0x00, 0x00, 0x00, 0x18,
+ 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ ];
+
+ let mut packet = Packet::new(&bytes, bytes.len() as u32);
+ let result = packet.handle();
+ assert_eq!(result.is_ok(), true);
+
+ assert_eq!(packet.encapsulation.len(), 4);
+ assert_eq!(
+ packet.encapsulation[0],
+ Encapsulation::Eth(
+ EthernetFrame {
+ source_mac: MacAddress([0x28, 0xd2, 0x44, 0x43, 0x38, 0x37]),
+ dest_mac: MacAddress([0xc0, 0x00, 0x14, 0x8c, 0x00, 0x00]),
+ ether_type: EtherType::IPv4,
+ },
+ &bytes[14..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[1],
+ Encapsulation::Ipv4(
+ Ipv4Header {
+ version: 4,
+ ihl: 20,
+ tos: 0x00,
+ length: 64,
+ id: 0x0a28,
+ flags: 0x2,
+ frag_offset: 0,
+ ttl: 128,
+ protocol: IPProtocol::TCP,
+ checksum: 0x970d,
+ source_address: Ipv4Addr::new(172, 16, 0, 100),
+ dest_address: Ipv4Addr::new(172, 16, 0, 254),
+ },
+ &bytes[34..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[2],
+ Encapsulation::Tcp(
+ TcpHeader {
+ source_port: 50112,
+ dest_port: 1723,
+ seq_num: 2945311102,
+ ack_num: 3263707926,
+ data_offset: 20,
+ reserved: 0,
+ flag_urg: false,
+ flag_ack: true,
+ flag_psh: true,
+ flag_rst: false,
+ flag_syn: false,
+ flag_fin: false,
+ window: 65332,
+ checksum: 0xa732,
+ urgent_ptr: 0,
+ options: None,
+ },
+ &bytes[54..]
+ )
+ );
+ assert_eq!(
+ packet.encapsulation[3],
+ Encapsulation::Pptp(
+ PptpHeader {
+ length: 24,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::SetLinkInfo,
+ reserved0: 0,
+ payload: vec![
+ 0x00, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ ],
+ },
+ &bytes[78..]
+ )
+ );
+
+ // assert_eq!(1, 0);
+ }
}
diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs
index 4f82280..1f02684 100644
--- a/src/protocol/mod.rs
+++ b/src/protocol/mod.rs
@@ -14,4 +14,5 @@ pub mod mpls;
pub mod gtpv1;
pub mod l2tp;
pub mod grev0;
-pub mod grev1; \ No newline at end of file
+pub mod grev1;
+pub mod pptp; \ No newline at end of file
diff --git a/src/protocol/pptp.rs b/src/protocol/pptp.rs
new file mode 100644
index 0000000..3c4f80a
--- /dev/null
+++ b/src/protocol/pptp.rs
@@ -0,0 +1,770 @@
+use crate::protocol::codec::Decode;
+use nom::bytes;
+use nom::number;
+use nom::Err;
+use nom::IResult;
+use nom::Needed;
+
+/******************************************************************************
+ * Struct
+ ******************************************************************************/
+
+/*
+ * https://datatracker.ietf.org/doc/html/rfc2637#section-1.4
+ *
+ * Each PPTP Control Connection message begins with an 8 octet fixed
+ * header portion. This fixed header contains the following: the total
+ * length of the message, the PPTP Message Type indicator, and a "Magic
+ * Cookie".
+ *
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Length | PPTP Message Type |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Magic Cookie |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+// https://wwwdisc.chimica.unipd.it/luigino.feltre/pubblica/unix/winnt_doc/pppt/understanding_pptp.html
+// https://datatracker.ietf.org/doc/html/rfc2637
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum PptpMessageType {
+ ControlMessage,
+ ManagementMessage,
+ UnknownMessage(u16),
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum PptpControlMessageType {
+ StartControlConnectionRequest,
+ StartControlConnectionReply,
+ StopControlConnectionRequest,
+ StopControlConnectionReply,
+ EchoRequest,
+ EchoReply,
+ OutgoingCallRequest,
+ OutgoingCallReply,
+ IncomingCallRequest,
+ IncomingCallReply,
+ IncomingCallConnected,
+ CallClearRequest,
+ CallDisconnectNotify,
+ WanErrorNotify,
+ SetLinkInfo,
+ Unknown(u16),
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct PptpHeader {
+ pub length: u16,
+ pub message_type: PptpMessageType,
+ pub magic_cookie: u32, // The Magic Cookie is always sent as the constant 0x1A2B3C4D
+ pub control_message_type: PptpControlMessageType,
+ pub reserved0: u16,
+ pub payload: Vec<u8>,
+}
+
+/******************************************************************************
+ * API
+ ******************************************************************************/
+
+impl From<u16> for PptpMessageType {
+ fn from(value: u16) -> Self {
+ match value {
+ 1 => PptpMessageType::ControlMessage,
+ 2 => PptpMessageType::ManagementMessage,
+ other => PptpMessageType::UnknownMessage(other),
+ }
+ }
+}
+
+impl From<u16> for PptpControlMessageType {
+ fn from(value: u16) -> Self {
+ match value {
+ 1 => PptpControlMessageType::StartControlConnectionRequest,
+ 2 => PptpControlMessageType::StartControlConnectionReply,
+ 3 => PptpControlMessageType::StopControlConnectionRequest,
+ 4 => PptpControlMessageType::StopControlConnectionReply,
+ 5 => PptpControlMessageType::EchoRequest,
+ 6 => PptpControlMessageType::EchoReply,
+ 7 => PptpControlMessageType::OutgoingCallRequest,
+ 8 => PptpControlMessageType::OutgoingCallReply,
+ 9 => PptpControlMessageType::IncomingCallRequest,
+ 10 => PptpControlMessageType::IncomingCallReply,
+ 11 => PptpControlMessageType::IncomingCallConnected,
+ 12 => PptpControlMessageType::CallClearRequest,
+ 13 => PptpControlMessageType::CallDisconnectNotify,
+ 14 => PptpControlMessageType::WanErrorNotify,
+ 15 => PptpControlMessageType::SetLinkInfo,
+ other => PptpControlMessageType::Unknown(other),
+ }
+ }
+}
+
+impl Decode for PptpHeader {
+ type Iterm = PptpHeader;
+ fn decode(input: &[u8]) -> IResult<&[u8], PptpHeader> {
+ let (input, length) = number::streaming::be_u16(input)?;
+ let (input, message_type) = number::streaming::be_u16(input)?;
+ let (input, magic_cookie) = number::streaming::be_u32(input)?;
+ let (input, control_message_type) = number::streaming::be_u16(input)?;
+ let (input, reserved0) = number::streaming::be_u16(input)?;
+
+ let need = length - 12;
+ let left = input.len() as u16;
+ let (input, payload) = match left >= need {
+ true => bytes::streaming::take(need)(input).map(|(i, l)| (i, l.to_vec()))?,
+ false => return Err(Err::Incomplete(Needed::new(need.into()))),
+ };
+
+ let header = PptpHeader {
+ length,
+ message_type: message_type.into(),
+ magic_cookie,
+ control_message_type: control_message_type.into(),
+ reserved0,
+ payload,
+ };
+
+ Ok((input, header))
+ }
+}
+
+/******************************************************************************
+ * TEST
+ ******************************************************************************/
+
+#[cfg(test)]
+mod tests {
+ use super::PptpControlMessageType;
+ use super::PptpHeader;
+ use super::PptpMessageType;
+ use crate::protocol::codec::Decode;
+ const LAST_SLICE: &'static [u8] = &[0xff];
+
+ #[test]
+ // Control Message Type: Start-Control-Connection-Request (1)
+ fn pptp_header_decode1() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 156
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Start-Control-Connection-Request (1)
+ * Reserved: 0000
+ * Protocol version: 1.0
+ * Reserved: 0000
+ * Framing Capabilities: Asynchronous Framing supported (1)
+ * Bearer Capabilities: Analog access supported (1)
+ * Maximum Channels: 0
+ * Firmware Revision: 0
+ * Host Name:
+ * Vendor Name: Microsoft
+ */
+
+ let bytes = [
+ 0x00, 0x9c, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+ 0x6f, 0x66, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 156,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::StartControlConnectionRequest,
+ reserved0: 0,
+ payload: vec![
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x63, 0x72,
+ 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ ],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Start-Control-Connection-Reply (2)
+ fn pptp_header_decode2() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 156
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Start-Control-Connection-Reply (2)
+ * Reserved: 0000
+ * Protocol version: 1.0
+ * Result Code: Successful channel establishment (1)
+ * Error Code: None (0)
+ * Framing Capabilities: Either Framing supported (3)
+ * Bearer Capabilities: Either access supported (3)
+ * Maximum Channels: 0
+ * Firmware Revision: 4608
+ * Host Name: R1
+ * Vendor Name: Cisco Systems, Inc.
+ */
+
+ let bytes = [
+ 0x00, 0x9c, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x12, 0x00,
+ 0x52, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x69, 0x73, 0x63, 0x6f, 0x20,
+ 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 156,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::StartControlConnectionReply,
+ reserved0: 0,
+ payload: vec![
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x12, 0x00, 0x52, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x69, 0x73, 0x63,
+ 0x6f, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2c, 0x20, 0x49, 0x6e, 0x63,
+ 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ ],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Stop-Control-Connection-Request (3)
+ fn pptp_header_decode3() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 16
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Stop-Control-Connection-Request (3)
+ * Reserved: 0000
+ * Reason: Unknown (0)
+ * Reserved: 00
+ * Reserved: 0000
+ */
+
+ let bytes = [
+ 0x00, 0x10, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 16,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::StopControlConnectionRequest,
+ reserved0: 0,
+ payload: vec![0x00, 0x00, 0x00, 0x00],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Stop-Control-Connection-Reply (4)
+ fn pptp_header_decode4() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 16
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Stop-Control-Connection-Reply (4)
+ * Reserved: 0000
+ * Result Code: OK (1)
+ * Error Code: None (0)
+ * Reserved: 0000
+ */
+
+ let bytes = [
+ 0x00, 0x10, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 16,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::StopControlConnectionReply,
+ reserved0: 0,
+ payload: vec![0x01, 0x00, 0x00, 0x00],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Echo-Request (5)
+ fn pptp_header_decode5() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 16
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Echo-Request (5)
+ * Reserved: 0000
+ * Identifier: 83886080
+ */
+
+ let bytes = [
+ 0x00, 0x10, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00,
+ 0x00, 0x00, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 16,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::EchoRequest,
+ reserved0: 0,
+ payload: vec![0x05, 0x00, 0x00, 0x00],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Echo-Reply (6)
+ fn pptp_header_decode6() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 20
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Echo-Reply (6)
+ * Reserved: 0000
+ * Identifier: 67108864
+ * Result Code: OK (1)
+ * Error Code: None (0)
+ * Reserved: 0000
+ */
+
+ let bytes = [
+ 0x00, 0x14, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x06, 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 20,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::EchoReply,
+ reserved0: 0,
+ payload: vec![0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Outgoing-Call-Request (7)
+ fn pptp_header_decode7() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 168
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Outgoing-Call-Request (7)
+ * Reserved: 0000
+ * Call ID: 32020
+ * Call Serial Number: 12
+ * Minimum BPS: 300
+ * Maximum BPS: 100000000
+ * Bearer Type: Either access supported (3)
+ * Framing Type: Either Framing supported (3)
+ * Packet Receive Window Size: 64
+ * Packet Processing Delay: 0
+ * Phone Number Length: 0
+ * Reserved: 0000
+ * Phone Number:
+ * Subaddress:
+ */
+
+ let bytes = [
+ 0x00, 0xa8, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x07, 0x00, 0x00, 0x7d, 0x14,
+ 0x00, 0x0c, 0x00, 0x00, 0x01, 0x2c, 0x05, 0xf5, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 168,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::OutgoingCallRequest,
+ reserved0: 0,
+ payload: vec![
+ 0x7d, 0x14, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x2c, 0x05, 0xf5, 0xe1, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ ],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Outgoing-Call-Reply (8)
+ fn pptp_header_decode8() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 32
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Outgoing-Call-Reply (8)
+ * Reserved: 0000
+ * Call ID: 3
+ * Peer Call ID: 32020
+ * Result Code: Connected (1)
+ * Error Code: None (0)
+ * Cause Code: 0
+ * Connect Speed: 64000
+ * Packet Receive Window Size: 16
+ * Packet Processing Delay: 0
+ * Physical Channel ID: 0
+ */
+
+ let bytes = [
+ 0x00, 0x20, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03,
+ 0x7d, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 32,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::OutgoingCallReply,
+ reserved0: 0,
+ payload: vec![
+ 0x00, 0x03, 0x7d, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Incoming-Call-Request (9)
+ fn pptp_header_decode9() {
+ /*
+ * TODO
+ */
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Incoming-Call-Reply (10)
+ fn pptp_header_decode10() {
+ /*
+ * TODO
+ */
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Incoming-Call-Connected (11)
+ fn pptp_header_decode11() {
+ /*
+ * TODO
+ */
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Call-Clear-Request (12)
+ fn pptp_header_decode12() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 16
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Call-Clear-Request (12)
+ * Reserved: 0000
+ * Call ID: 32020
+ * Reserved: 0000
+ */
+
+ let bytes = [
+ 0x00, 0x10, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x0c, 0x00, 0x00, 0x7d, 0x14,
+ 0x00, 0x00, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 16,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::CallClearRequest,
+ reserved0: 0,
+ payload: vec![0x7d, 0x14, 0x00, 0x00],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Call-Disconnect-Notify (13)
+ fn pptp_header_decode13() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 148
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Call-Disconnect-Notify (13)
+ * Reserved: 0000
+ * Call ID: 3
+ * Result Code: Lost Carrier (1)
+ * Error Code: None (0)
+ * Cause Code: 65535
+ * Reserved: 0000
+ * Call Statistics:
+ */
+
+ let bytes = [
+ 0x00, 0x94, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03,
+ 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 148,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::CallDisconnectNotify,
+ reserved0: 0,
+ payload: vec![
+ 0x00, 0x03, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Wan-Error-Notify (14)
+ fn pptp_header_decode14() {
+ /*
+ * TODO
+ */
+
+ // assert_eq!(1, 0);
+ }
+
+ #[test]
+ // Control Message Type: Set-Link-Info (15)
+ fn pptp_header_decode15() {
+ /*
+ * Point-to-Point Tunnelling Protocol
+ * Length: 24
+ * Message type: Control Message (1)
+ * Magic Cookie: 0x1a2b3c4d (correct)
+ * Control Message Type: Set-Link-Info (15)
+ * Reserved: 0000
+ * Peer Call ID: 3
+ * Reserved: 0000
+ * Send ACCM: 0xffffffff
+ * Receive ACCM: 0xffffffff
+ */
+
+ let bytes = [
+ 0x00, 0x18, 0x00, 0x01, 0x1a, 0x2b, 0x3c, 0x4d, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Payload */
+ ];
+
+ let expectation = PptpHeader {
+ length: 24,
+ message_type: PptpMessageType::ControlMessage,
+ magic_cookie: 0x1a2b3c4d,
+ control_message_type: PptpControlMessageType::SetLinkInfo,
+ reserved0: 0,
+ payload: vec![
+ 0x00, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ ],
+ };
+
+ assert_eq!(PptpHeader::decode(&bytes), Ok((LAST_SLICE, expectation)));
+
+ // example
+ let result = PptpHeader::decode(&bytes);
+ if let Ok((payload, header)) = result {
+ println!("return: {:?}, payload: {}", header, payload.len());
+ } else {
+ println!("return: Incomplete data");
+ }
+
+ // assert_eq!(1, 0);
+ }
+}