summaryrefslogtreecommitdiff
path: root/src/protocol/pptp.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/protocol/pptp.rs')
-rw-r--r--src/protocol/pptp.rs770
1 files changed, 770 insertions, 0 deletions
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);
+ }
+}