netlink_packet_route/neighbour_discovery_user_option/
message.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_utils::traits::{Emitable, Parseable};
4use std::convert::TryFrom as _;
5
6use super::buffer::{
7    NeighbourDiscoveryUserOptionMessageBuffer, NEIGHBOUR_DISCOVERY_USER_OPTION_HEADER_LEN,
8};
9use super::header::NeighbourDiscoveryUserOptionHeader;
10use super::nla::Nla;
11use super::NeighbourDiscoveryUserOptionError;
12
13#[derive(Debug, PartialEq, Eq, Clone)]
14#[non_exhaustive]
15pub struct NeighbourDiscoveryUserOptionMessage {
16    /// The header of the ND_USEROPT message.
17    pub header: NeighbourDiscoveryUserOptionHeader,
18
19    /// The body of the NDP option as it was on the wire.
20    pub option_body: Vec<u8>,
21
22    pub attributes: Vec<Nla>,
23}
24
25impl NeighbourDiscoveryUserOptionMessage {
26    pub fn new(
27        header: NeighbourDiscoveryUserOptionHeader,
28        option_body: Vec<u8>,
29        attributes: Vec<Nla>,
30    ) -> Self {
31        Self { header, option_body, attributes }
32    }
33}
34
35impl Emitable for NeighbourDiscoveryUserOptionMessage {
36    fn buffer_len(&self) -> usize {
37        NEIGHBOUR_DISCOVERY_USER_OPTION_HEADER_LEN
38            + self.option_body.len()
39            + self.attributes.as_slice().buffer_len()
40    }
41
42    fn emit(&self, buffer: &mut [u8]) {
43        let Self {
44            header: NeighbourDiscoveryUserOptionHeader { interface_index, icmp_type },
45            option_body,
46            attributes,
47        } = self;
48
49        let mut packet = NeighbourDiscoveryUserOptionMessageBuffer::new(buffer);
50
51        packet.set_address_family(icmp_type.family().into());
52
53        let payload = packet.payload_mut();
54        payload[..option_body.len()].copy_from_slice(&option_body[..]);
55        attributes.as_slice().emit(&mut payload[option_body.len()..]);
56
57        packet.set_options_length(
58            u16::try_from(option_body.len())
59                .expect("neighbor discovery options length doesn't fit in u16"),
60        );
61        packet.set_interface_index(*interface_index);
62
63        let (icmp_type, icmp_code) = icmp_type.into_type_and_code();
64        packet.set_icmp_type(icmp_type);
65        packet.set_icmp_code(icmp_code);
66    }
67}
68
69impl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourDiscoveryUserOptionMessageBuffer<&'a T>>
70    for NeighbourDiscoveryUserOptionMessage
71{
72    type Error = NeighbourDiscoveryUserOptionError;
73
74    fn parse(
75        buf: &NeighbourDiscoveryUserOptionMessageBuffer<&'a T>,
76    ) -> Result<Self, NeighbourDiscoveryUserOptionError> {
77        let header = NeighbourDiscoveryUserOptionHeader::parse(buf)
78            .map_err(NeighbourDiscoveryUserOptionError::InvalidHeader)?;
79
80        let mut nlas = Vec::new();
81        for nla_buf in buf.nlas() {
82            nlas.push(
83                Nla::parse(&nla_buf.map_err(NeighbourDiscoveryUserOptionError::InvalidNla)?)
84                    .map_err(NeighbourDiscoveryUserOptionError::InvalidNla)?,
85            );
86        }
87
88        Ok(NeighbourDiscoveryUserOptionMessage {
89            header,
90            option_body: buf.option_body().to_vec(),
91            attributes: nlas,
92        })
93    }
94}