1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// SPDX-License-Identifier: MIT

use anyhow::Context;

use crate::{
    nlas::neighbour::Nla,
    traits::{Emitable, Parseable},
    DecodeError,
    NeighbourHeader,
    NeighbourMessageBuffer,
};

#[derive(Debug, PartialEq, Eq, Clone, Default)]
pub struct NeighbourMessage {
    pub header: NeighbourHeader,
    pub nlas: Vec<Nla>,
}

impl Emitable for NeighbourMessage {
    fn buffer_len(&self) -> usize {
        self.header.buffer_len() + self.nlas.as_slice().buffer_len()
    }

    fn emit(&self, buffer: &mut [u8]) {
        self.header.emit(buffer);
        self.nlas
            .as_slice()
            .emit(&mut buffer[self.header.buffer_len()..]);
    }
}

impl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourMessageBuffer<&'a T>> for NeighbourMessage {
    fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
        Ok(NeighbourMessage {
            header: NeighbourHeader::parse(buf)
                .context("failed to parse neighbour message header")?,
            nlas: Vec::<Nla>::parse(buf).context("failed to parse neighbour message NLAs")?,
        })
    }
}

impl<'a, T: AsRef<[u8]> + 'a> Parseable<NeighbourMessageBuffer<&'a T>> for Vec<Nla> {
    fn parse(buf: &NeighbourMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
        let mut nlas = vec![];
        for nla_buf in buf.nlas() {
            nlas.push(Nla::parse(&nla_buf?)?);
        }
        Ok(nlas)
    }
}

#[cfg(test)]
mod test {
    use crate::{
        constants::*,
        traits::Emitable,
        NeighbourHeader,
        NeighbourMessage,
        NeighbourMessageBuffer,
    };

    // 0020   0a 00 00 00 02 00 00 00 02 00 80 01 14 00 01 00
    // 0030   2a 02 80 10 66 d5 00 00 f6 90 ea ff fe 00 2d 83
    // 0040   0a 00 02 00 f4 90 ea 00 2d 83 00 00 08 00 04 00
    // 0050   01 00 00 00 14 00 03 00 00 00 00 00 00 00 00 00
    // 0060   00 00 00 00 02 00 00 00

    #[rustfmt::skip]
    static HEADER: [u8; 12] = [
        0x0a, // interface family (inet6)
        0xff, 0xff, 0xff, // padding
        0x01, 0x00, 0x00, 0x00, // interface index = 1
        0x02, 0x00, // state NUD_REACHABLE
        0x80, // flags NTF_PROXY
        0x01  // ntype

        // nlas
        // will add some once I've got them parsed out.
    ];

    #[test]
    fn packet_header_read() {
        let packet = NeighbourMessageBuffer::new(&HEADER[0..12]);
        assert_eq!(packet.family(), AF_INET6 as u8);
        assert_eq!(packet.ifindex(), 1);
        assert_eq!(packet.state(), NUD_REACHABLE);
        assert_eq!(packet.flags(), NTF_ROUTER);
        assert_eq!(packet.ntype(), NDA_DST as u8);
    }

    #[test]
    fn packet_header_build() {
        let mut buf = vec![0xff; 12];
        {
            let mut packet = NeighbourMessageBuffer::new(&mut buf);
            packet.set_family(AF_INET6 as u8);
            packet.set_ifindex(1);
            packet.set_state(NUD_REACHABLE);
            packet.set_flags(NTF_ROUTER);
            packet.set_ntype(NDA_DST as u8);
        }
        assert_eq!(&buf[..], &HEADER[0..12]);
    }

    #[test]
    fn emit() {
        let header = NeighbourHeader {
            family: AF_INET6 as u8,
            ifindex: 1,
            state: NUD_REACHABLE,
            flags: NTF_ROUTER,
            ntype: NDA_DST as u8,
        };

        let nlas = vec![];
        let packet = NeighbourMessage { header, nlas };
        let mut buf = vec![0; 12];

        assert_eq!(packet.buffer_len(), 12);
        packet.emit(&mut buf[..]);
    }
}