ppp_packet/
link.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Utilities for parsing and serializing LCP options.
6
7use crate::records::options::{OptionsImpl, OptionsImplLayout, OptionsSerializerImpl};
8use byteorder::{ByteOrder, NetworkEndian};
9
10/// An LCP control option.
11#[derive(Clone, Eq, Hash, PartialEq, Debug)]
12pub enum ControlOption {
13    /// Any sequence of bytes not recognized as a valid option.
14    Unrecognized(u8, Vec<u8>),
15    /// The maximum number of bytes in the Information and Padding fields of a PPP packet.
16    MaximumReceiveUnit(u16),
17    /// The authentication protocol desired, and any additional data as determined by the
18    /// particular protocol.
19    AuthenticationProtocol(u16, Vec<u8>),
20    /// The link quality monitoring protocol desired, and any additional data as determined by the
21    /// particular protocol.
22    QualityProtocol(u16, Vec<u8>),
23    /// A 32-bit number which is very likely to be unique on the link.
24    MagicNumber(u32),
25    /// Requests that the protocol field of PPP packets be compressed (if the sent protocol
26    /// supports compression).
27    ProtocolFieldCompression,
28    /// Requests that the address and control fields of the HDLC framing be compressed.
29    AddressControlFieldCompression,
30}
31
32/// Implementation of the LCP control options parsing and serialization.
33#[derive(Copy, Clone)]
34pub struct ControlOptionsImpl;
35
36impl ControlOptionsImpl {
37    const TYPE_MAXIMUM_RECEIVE_UNIT: u8 = 1;
38    const TYPE_AUTHENTICATION_PROTOCOL: u8 = 3;
39    const TYPE_QUALITY_PROTOCOL: u8 = 4;
40    const TYPE_MAGIC_NUMBER: u8 = 5;
41    const TYPE_PROTOCOL_FIELD_COMPRESSION: u8 = 7;
42    const TYPE_ADDRESS_CONTROL_FIELD_COMPRESSION: u8 = 8;
43}
44
45impl OptionsImplLayout for ControlOptionsImpl {
46    type Error = ();
47    const END_OF_OPTIONS: Option<u8> = None;
48    const NOP: Option<u8> = None;
49}
50
51impl<'a> OptionsImpl<'a> for ControlOptionsImpl {
52    type Option = ControlOption;
53
54    fn parse(kind: u8, data: &[u8]) -> Result<Option<ControlOption>, ()> {
55        match kind {
56            Self::TYPE_MAXIMUM_RECEIVE_UNIT => {
57                if data.len() == 2 {
58                    Ok(Some(ControlOption::MaximumReceiveUnit(NetworkEndian::read_u16(&data))))
59                } else {
60                    Err(())
61                }
62            }
63            Self::TYPE_AUTHENTICATION_PROTOCOL => {
64                if data.len() >= 2 {
65                    Ok(Some(ControlOption::AuthenticationProtocol(
66                        NetworkEndian::read_u16(&data),
67                        data[2..].to_vec(),
68                    )))
69                } else {
70                    Err(())
71                }
72            }
73            Self::TYPE_QUALITY_PROTOCOL => {
74                if data.len() >= 2 {
75                    Ok(Some(ControlOption::QualityProtocol(
76                        NetworkEndian::read_u16(&data),
77                        data[2..].to_vec(),
78                    )))
79                } else {
80                    Err(())
81                }
82            }
83            Self::TYPE_MAGIC_NUMBER => {
84                if data.len() == 4 {
85                    Ok(Some(ControlOption::MagicNumber(NetworkEndian::read_u32(&data))))
86                } else {
87                    Err(())
88                }
89            }
90            Self::TYPE_PROTOCOL_FIELD_COMPRESSION => {
91                if data.is_empty() {
92                    Ok(Some(ControlOption::ProtocolFieldCompression))
93                } else {
94                    Err(())
95                }
96            }
97            Self::TYPE_ADDRESS_CONTROL_FIELD_COMPRESSION => {
98                if data.is_empty() {
99                    Ok(Some(ControlOption::AddressControlFieldCompression))
100                } else {
101                    Err(())
102                }
103            }
104            unrecognized => Ok(Some(ControlOption::Unrecognized(unrecognized, data.to_vec()))),
105        }
106    }
107}
108
109impl<'a> OptionsSerializerImpl<'a> for ControlOptionsImpl {
110    type Option = ControlOption;
111
112    fn get_option_length(option: &Self::Option) -> usize {
113        match option {
114            ControlOption::Unrecognized(_, data) => data.len(),
115            ControlOption::MaximumReceiveUnit(_) => 2,
116            ControlOption::AuthenticationProtocol(_, data)
117            | ControlOption::QualityProtocol(_, data) => 2 + data.len(),
118            ControlOption::MagicNumber(_) => 4,
119            ControlOption::ProtocolFieldCompression
120            | ControlOption::AddressControlFieldCompression => 0,
121        }
122    }
123
124    fn get_option_kind(option: &Self::Option) -> u8 {
125        match option {
126            ControlOption::Unrecognized(kind, _) => *kind,
127            ControlOption::MaximumReceiveUnit(_) => Self::TYPE_MAXIMUM_RECEIVE_UNIT,
128            ControlOption::AuthenticationProtocol(_, _) => Self::TYPE_AUTHENTICATION_PROTOCOL,
129            ControlOption::QualityProtocol(_, _) => Self::TYPE_QUALITY_PROTOCOL,
130            ControlOption::MagicNumber(_) => Self::TYPE_MAGIC_NUMBER,
131            ControlOption::ProtocolFieldCompression => Self::TYPE_PROTOCOL_FIELD_COMPRESSION,
132            ControlOption::AddressControlFieldCompression => {
133                Self::TYPE_ADDRESS_CONTROL_FIELD_COMPRESSION
134            }
135        }
136    }
137
138    fn serialize(data: &mut [u8], option: &Self::Option) {
139        match option {
140            ControlOption::Unrecognized(_, unrecognized_data) => {
141                data.copy_from_slice(unrecognized_data);
142            }
143            ControlOption::MaximumReceiveUnit(mru) => NetworkEndian::write_u16(data, *mru),
144            ControlOption::AuthenticationProtocol(protocol, protocol_data)
145            | ControlOption::QualityProtocol(protocol, protocol_data) => {
146                NetworkEndian::write_u16(data, *protocol);
147                data[2..].copy_from_slice(protocol_data);
148            }
149            ControlOption::MagicNumber(magic) => NetworkEndian::write_u32(data, *magic),
150            ControlOption::ProtocolFieldCompression
151            | ControlOption::AddressControlFieldCompression => {}
152        }
153    }
154}