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