ppp_packet/
ipv4.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 IPCP options.
6
7use crate::records::options::{OptionsImpl, OptionsImplLayout, OptionsSerializerImpl};
8use byteorder::{ByteOrder, NetworkEndian};
9
10/// An IPCP 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 compression protocol desired, and any additional data as determined by the
16    /// particular protocol.
17    IpCompressionProtocol(u16, Vec<u8>),
18    /// The desired local address of the sender.
19    IpAddress(u32),
20}
21
22/// Implementation of the IPCP control options parsing and serialization.
23pub struct ControlOptionsImpl;
24
25impl ControlOptionsImpl {
26    const TYPE_IP_COMPRESSION_PROTOCOL: u8 = 2;
27    const TYPE_IP_ADDRESS: u8 = 3;
28}
29
30impl OptionsImplLayout for ControlOptionsImpl {
31    type Error = ();
32    const END_OF_OPTIONS: Option<u8> = None;
33    const NOP: Option<u8> = None;
34}
35
36impl<'a> OptionsImpl<'a> for ControlOptionsImpl {
37    type Option = ControlOption;
38
39    fn parse(kind: u8, data: &[u8]) -> Result<Option<ControlOption>, ()> {
40        match kind {
41            Self::TYPE_IP_COMPRESSION_PROTOCOL => {
42                if data.len() >= 2 {
43                    Ok(Some(ControlOption::IpCompressionProtocol(
44                        NetworkEndian::read_u16(&data),
45                        data[2..].to_vec(),
46                    )))
47                } else {
48                    Err(())
49                }
50            }
51            Self::TYPE_IP_ADDRESS => {
52                if data.len() == 4 {
53                    Ok(Some(ControlOption::IpAddress(NetworkEndian::read_u32(&data))))
54                } else {
55                    Err(())
56                }
57            }
58            unrecognized => Ok(Some(ControlOption::Unrecognized(unrecognized, data[..].to_vec()))),
59        }
60    }
61}
62
63impl<'a> OptionsSerializerImpl<'a> for ControlOptionsImpl {
64    type Option = ControlOption;
65
66    fn get_option_length(option: &Self::Option) -> usize {
67        match option {
68            ControlOption::Unrecognized(_, data) => data.len(),
69            ControlOption::IpCompressionProtocol(_, data) => 2 + data.len(),
70            ControlOption::IpAddress(_) => 4,
71        }
72    }
73
74    fn get_option_kind(option: &Self::Option) -> u8 {
75        match option {
76            ControlOption::Unrecognized(kind, _) => *kind,
77            ControlOption::IpCompressionProtocol(_, _) => Self::TYPE_IP_COMPRESSION_PROTOCOL,
78            ControlOption::IpAddress(_) => Self::TYPE_IP_ADDRESS,
79        }
80    }
81
82    fn serialize(data: &mut [u8], option: &Self::Option) {
83        match option {
84            ControlOption::Unrecognized(_, unrecognized_data) => {
85                data.copy_from_slice(&unrecognized_data);
86            }
87            ControlOption::IpCompressionProtocol(protocol, protocol_data) => {
88                NetworkEndian::write_u16(data, *protocol);
89                data[2..].copy_from_slice(&protocol_data);
90            }
91            ControlOption::IpAddress(address) => NetworkEndian::write_u32(data, *address),
92        }
93    }
94}