netlink_packet_route/rtnl/neighbour/
message.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4
5use crate::{
6    nlas::neighbour::Nla,
7    traits::{Emitable, Parseable},
8    DecodeError,
9    NeighbourHeader,
10    NeighbourMessageBuffer,
11};
12
13#[derive(Debug, PartialEq, Eq, Clone, Default)]
14pub struct NeighbourMessage {
15    pub header: NeighbourHeader,
16    pub nlas: Vec<Nla>,
17}
18
19impl Emitable for NeighbourMessage {
20    fn buffer_len(&self) -> usize {
21        self.header.buffer_len() + self.nlas.as_slice().buffer_len()
22    }
23
24    fn emit(&self, buffer: &mut [u8]) {
25        self.header.emit(buffer);
26        self.nlas
27            .as_slice()
28            .emit(&mut buffer[self.header.buffer_len()..]);
29    }
30}
31
32impl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourMessageBuffer<&'a T>> for NeighbourMessage {
33    fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
34        Ok(NeighbourMessage {
35            header: NeighbourHeader::parse(buf)
36                .context("failed to parse neighbour message header")?,
37            nlas: Vec::<Nla>::parse(buf).context("failed to parse neighbour message NLAs")?,
38        })
39    }
40}
41
42impl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourMessageBuffer<&'a T>> for Vec<Nla> {
43    fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
44        let mut nlas = vec![];
45        for nla_buf in buf.nlas() {
46            nlas.push(Nla::parse(&nla_buf?)?);
47        }
48        Ok(nlas)
49    }
50}
51
52#[cfg(test)]
53mod test {
54    use crate::{
55        constants::*,
56        traits::Emitable,
57        NeighbourHeader,
58        NeighbourMessage,
59        NeighbourMessageBuffer,
60    };
61
62    // 0020   0a 00 00 00 02 00 00 00 02 00 80 01 14 00 01 00
63    // 0030   2a 02 80 10 66 d5 00 00 f6 90 ea ff fe 00 2d 83
64    // 0040   0a 00 02 00 f4 90 ea 00 2d 83 00 00 08 00 04 00
65    // 0050   01 00 00 00 14 00 03 00 00 00 00 00 00 00 00 00
66    // 0060   00 00 00 00 02 00 00 00
67
68    #[rustfmt::skip]
69    static HEADER: [u8; 12] = [
70        0x0a, // interface family (inet6)
71        0xff, 0xff, 0xff, // padding
72        0x01, 0x00, 0x00, 0x00, // interface index = 1
73        0x02, 0x00, // state NUD_REACHABLE
74        0x80, // flags NTF_PROXY
75        0x01  // ntype
76
77        // nlas
78        // will add some once I've got them parsed out.
79    ];
80
81    #[test]
82    fn packet_header_read() {
83        let packet = NeighbourMessageBuffer::new(&HEADER[0..12]);
84        assert_eq!(packet.family(), AF_INET6 as u8);
85        assert_eq!(packet.ifindex(), 1);
86        assert_eq!(packet.state(), NUD_REACHABLE);
87        assert_eq!(packet.flags(), NTF_ROUTER);
88        assert_eq!(packet.ntype(), NDA_DST as u8);
89    }
90
91    #[test]
92    fn packet_header_build() {
93        let mut buf = vec![0xff; 12];
94        {
95            let mut packet = NeighbourMessageBuffer::new(&mut buf);
96            packet.set_family(AF_INET6 as u8);
97            packet.set_ifindex(1);
98            packet.set_state(NUD_REACHABLE);
99            packet.set_flags(NTF_ROUTER);
100            packet.set_ntype(NDA_DST as u8);
101        }
102        assert_eq!(&buf[..], &HEADER[0..12]);
103    }
104
105    #[test]
106    fn emit() {
107        let header = NeighbourHeader {
108            family: AF_INET6 as u8,
109            ifindex: 1,
110            state: NUD_REACHABLE,
111            flags: NTF_ROUTER,
112            ntype: NDA_DST as u8,
113        };
114
115        let nlas = vec![];
116        let packet = NeighbourMessage { header, nlas };
117        let mut buf = vec![0; 12];
118
119        assert_eq!(packet.buffer_len(), 12);
120        packet.emit(&mut buf[..]);
121    }
122}