netlink_packet_route/neighbour_discovery_user_option/
header.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_utils::Parseable;
4
5use crate::AddressFamily;
6
7use super::buffer::NeighbourDiscoveryUserOptionMessageBuffer;
8
9#[derive(Debug, PartialEq, Eq, Clone, Copy)]
10#[non_exhaustive]
11pub enum NeighbourDiscoveryIcmpV6Type {
12    RouterSolicitation,
13    RouterAdvertisement,
14    NeighbourSolicitation,
15    NeighbourAdvertisement,
16    Redirect,
17    Other { type_: u8, code: u8 },
18}
19
20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
21#[non_exhaustive]
22pub enum NeighbourDiscoveryIcmpV4Type {
23    Other { type_: u8, code: u8 },
24}
25
26impl NeighbourDiscoveryIcmpV4Type {
27    pub fn into_type_and_code(self) -> (u8, u8) {
28        match self {
29            NeighbourDiscoveryIcmpV4Type::Other { type_, code } => (type_, code),
30        }
31    }
32}
33
34#[derive(Debug, PartialEq, Eq, Clone, Copy)]
35#[non_exhaustive]
36pub enum NeighbourDiscoveryIcmpType {
37    Inet(NeighbourDiscoveryIcmpV4Type),
38    Inet6(NeighbourDiscoveryIcmpV6Type),
39    Other { family: AddressFamily, type_: u8, code: u8 },
40}
41
42impl NeighbourDiscoveryIcmpType {
43    pub fn family(&self) -> AddressFamily {
44        match self {
45            NeighbourDiscoveryIcmpType::Inet(_) => AddressFamily::Inet,
46            NeighbourDiscoveryIcmpType::Inet6(_) => AddressFamily::Inet6,
47            NeighbourDiscoveryIcmpType::Other { family, type_: _, code: _ } => *family,
48        }
49    }
50
51    pub fn into_type_and_code(self) -> (u8, u8) {
52        match self {
53            NeighbourDiscoveryIcmpType::Inet(type_) => type_.into_type_and_code(),
54            NeighbourDiscoveryIcmpType::Inet6(type_) => type_.into_type_and_code(),
55            NeighbourDiscoveryIcmpType::Other { family: _, type_, code } => (type_, code),
56        }
57    }
58}
59
60impl NeighbourDiscoveryIcmpV6Type {
61    /// Determines the `NeighbourDiscoveryIcmpV6Type` from a given ICMP `type_` and `code`,
62    /// as defined in RFC 4443 (for IPv6).
63    pub fn new(type_: u8, code: u8) -> Self {
64        match (type_, code) {
65            (133, 0) => NeighbourDiscoveryIcmpV6Type::RouterSolicitation,
66            (134, 0) => NeighbourDiscoveryIcmpV6Type::RouterAdvertisement,
67            (135, 0) => NeighbourDiscoveryIcmpV6Type::NeighbourSolicitation,
68            (136, 0) => NeighbourDiscoveryIcmpV6Type::NeighbourAdvertisement,
69            (137, 0) => NeighbourDiscoveryIcmpV6Type::Redirect,
70            _ => NeighbourDiscoveryIcmpV6Type::Other { type_, code },
71        }
72    }
73
74    /// Given a `NeighbourDiscoveryIcmpV6Type`, returns the ICMP `type_` and `code`.
75    pub fn into_type_and_code(self) -> (u8, u8) {
76        match self {
77            NeighbourDiscoveryIcmpV6Type::RouterSolicitation => (133, 0),
78            NeighbourDiscoveryIcmpV6Type::RouterAdvertisement => (134, 0),
79            NeighbourDiscoveryIcmpV6Type::NeighbourSolicitation => (135, 0),
80            NeighbourDiscoveryIcmpV6Type::NeighbourAdvertisement => (136, 0),
81            NeighbourDiscoveryIcmpV6Type::Redirect => (137, 0),
82            NeighbourDiscoveryIcmpV6Type::Other { type_, code } => (type_, code),
83        }
84    }
85}
86
87impl<T: AsRef<[u8]>> Parseable<NeighbourDiscoveryUserOptionMessageBuffer<T>>
88    for NeighbourDiscoveryUserOptionHeader
89{
90    type Error = netlink_packet_utils::DecodeError;
91
92    fn parse(
93        buf: &NeighbourDiscoveryUserOptionMessageBuffer<T>,
94    ) -> Result<Self, netlink_packet_utils::DecodeError> {
95        let icmp_type = match AddressFamily::from(buf.address_family()) {
96            AddressFamily::Inet => {
97                NeighbourDiscoveryIcmpType::Inet(NeighbourDiscoveryIcmpV4Type::Other {
98                    type_: buf.icmp_type(),
99                    code: buf.icmp_code(),
100                })
101            }
102            AddressFamily::Inet6 => NeighbourDiscoveryIcmpType::Inet6(
103                NeighbourDiscoveryIcmpV6Type::new(buf.icmp_type(), buf.icmp_code()),
104            ),
105            family => NeighbourDiscoveryIcmpType::Other {
106                family,
107                type_: buf.icmp_type(),
108                code: buf.icmp_code(),
109            },
110        };
111        Ok(Self { interface_index: buf.interface_index(), icmp_type })
112    }
113}
114
115#[derive(Debug, PartialEq, Eq, Clone)]
116#[non_exhaustive]
117pub struct NeighbourDiscoveryUserOptionHeader {
118    /// The index of this ND user option's interface.
119    pub interface_index: u32,
120    /// The ICMP message type associated with this ND user option. As defined
121    /// in RFC 792 for ICMPv4, and RFC 4443 for ICMPv6.
122    pub icmp_type: NeighbourDiscoveryIcmpType,
123}
124
125impl NeighbourDiscoveryUserOptionHeader {
126    pub fn new(interface_index: u32, icmp_type: NeighbourDiscoveryIcmpType) -> Self {
127        Self { interface_index, icmp_type }
128    }
129}