erbium_net/addr/
link.rs

1/*   Copyright 2023 Perry Lorier
2 *
3 *  Licensed under the Apache License, Version 2.0 (the "License");
4 *  you may not use this file except in compliance with the License.
5 *  You may obtain a copy of the License at
6 *
7 *      http://www.apache.org/licenses/LICENSE-2.0
8 *
9 *  Unless required by applicable law or agreed to in writing, software
10 *  distributed under the License is distributed on an "AS IS" BASIS,
11 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 *  See the License for the specific language governing permissions and
13 *  limitations under the License.
14 *
15 *  SPDX-License-Identifier: Apache-2.0
16 *
17 *  We try and use the nix types here, but they're somewhat frustrating to use, for instance not
18 *  providing useful safe constructors.  So we do that here.
19 */
20
21pub use nix::sys::socket::LinkAddr;
22pub type IfIndex = usize;
23
24/// physical layer protocol (Ethertype)
25#[derive(Debug, PartialEq, Eq, Hash)]
26pub struct EtherType(pub u16);
27impl EtherType {
28    pub const UNSPECIFIED: EtherType = EtherType(0);
29    pub const IP: EtherType = EtherType(0x0800);
30    pub const ARP: EtherType = EtherType(0x0806);
31    pub const IPV6: EtherType = EtherType(0x86DD);
32    pub const LLDP: EtherType = EtherType(0x88CC);
33}
34
35impl From<EtherType> for u16 {
36    fn from(e: EtherType) -> u16 {
37        e.0
38    }
39}
40
41impl From<u16> for EtherType {
42    fn from(e: u16) -> EtherType {
43        EtherType(e)
44    }
45}
46
47/// Arp Hardware Type (ArpHrd)
48#[derive(Debug, Hash, Eq, PartialEq)]
49pub struct ArpHrd(pub u16);
50#[allow(dead_code)]
51impl ArpHrd {
52    const UNSPECIFIED: ArpHrd = ArpHrd(0);
53    const ETHERNET: ArpHrd = ArpHrd(1);
54}
55
56impl From<ArpHrd> for u16 {
57    fn from(a: ArpHrd) -> u16 {
58        a.0
59    }
60}
61
62impl From<u16> for ArpHrd {
63    fn from(u: u16) -> Self {
64        Self(u)
65    }
66}
67
68#[derive(Debug, Hash, Eq, PartialEq)]
69pub struct PacketType(pub u8);
70#[allow(dead_code)]
71impl PacketType {
72    const HOST: PacketType = PacketType(0);
73    const BROADCAST: PacketType = PacketType(1);
74    const MULTICAST: PacketType = PacketType(2);
75    const OTHER_HOST: PacketType = PacketType(3);
76    const OUTGOING: PacketType = PacketType(4);
77    const LOOPBACK: PacketType = PacketType(5);
78    const USER: PacketType = PacketType(6);
79    const KERNEL: PacketType = PacketType(7);
80    const FAST_ROUTE: PacketType = PacketType(8);
81}
82
83impl From<PacketType> for u8 {
84    fn from(p: PacketType) -> u8 {
85        p.0
86    }
87}
88
89impl From<u8> for PacketType {
90    fn from(p: u8) -> PacketType {
91        Self(p)
92    }
93}
94
95/// nix doesn't provide a safe way to construct LinkAddrs, so we provide our own.
96pub fn new_linkaddr(
97    protocol: EtherType,
98    ifindex: IfIndex,
99    hatype: ArpHrd,
100    pkttype: PacketType,
101    addr: &[u8],
102) -> LinkAddr {
103    let mut sll_addr = [0_u8; 8];
104    sll_addr[..addr.len()].copy_from_slice(addr);
105    // We are careful to use the same version of libc here as nix does to avoid type confusion.
106    let ll = nix::libc::sockaddr_ll {
107        sll_family: nix::libc::AF_PACKET as u16,
108        sll_protocol: u16::to_be(protocol.into()),
109        sll_ifindex: ifindex as i32,
110        sll_hatype: hatype.into(),
111        sll_pkttype: pkttype.into(),
112        sll_halen: addr.len() as u8,
113        sll_addr,
114    };
115    unsafe {
116        use nix::sys::socket::SockaddrLike as _;
117        LinkAddr::from_raw(
118            &ll as *const _ as *const _,
119            Some(
120                std::mem::size_of_val(&ll) as u32, /* why doesn't from_raw take a usize? */
121            ),
122        )
123        .unwrap()
124    }
125}
126
127pub fn linkaddr_for_ifindex(ifindex: IfIndex) -> LinkAddr {
128    new_linkaddr(
129        EtherType::UNSPECIFIED,
130        ifindex,
131        ArpHrd::UNSPECIFIED,
132        PacketType::HOST,
133        &[0; 8],
134    )
135}