Skip to main content

netstack3_base/device/
link.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Link device (L2) definitions.
6//!
7//! This module contains definitions of link-layer devices, otherwise known as
8//! L2 devices.
9
10use core::fmt::Debug;
11
12use net_types::ethernet::Mac;
13use net_types::{MulticastAddress, UnicastAddress};
14use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
15
16use crate::Device;
17
18/// The type of address used by a link device.
19pub trait LinkAddress:
20    'static
21    + FromBytes
22    + IntoBytes
23    + KnownLayout
24    + Immutable
25    + Unaligned
26    + Copy
27    + Clone
28    + Debug
29    + Eq
30    + Send
31{
32    /// The length of the address in bytes.
33    const BYTES_LENGTH: usize;
34
35    /// Returns the underlying bytes of a `LinkAddress`.
36    fn bytes(&self) -> &[u8];
37
38    /// Constructs a `LinkLayerAddress` from the provided bytes.
39    ///
40    /// # Panics
41    ///
42    /// `from_bytes` may panic if `bytes` is not **exactly** [`BYTES_LENGTH`]
43    /// long.
44    fn from_bytes(bytes: &[u8]) -> Self;
45}
46
47impl LinkAddress for Mac {
48    const BYTES_LENGTH: usize = 6;
49
50    fn bytes(&self) -> &[u8] {
51        self.as_ref()
52    }
53
54    fn from_bytes(bytes: &[u8]) -> Self {
55        // Assert that contract is being held.
56        debug_assert_eq!(bytes.len(), Self::BYTES_LENGTH);
57        let mut b = [0; Self::BYTES_LENGTH];
58        b.copy_from_slice(bytes);
59        Self::new(b)
60    }
61}
62
63/// A link address that can be unicast and multicast.
64pub trait LinkDeviceAddress: LinkAddress + UnicastAddress + MulticastAddress {}
65impl<L: LinkAddress + UnicastAddress + MulticastAddress> LinkDeviceAddress for L {}
66
67/// A link device.
68///
69/// `LinkDevice` is used to identify a particular link device implementation. It
70/// is only intended to exist at the type level, never instantiated at runtime.
71pub trait LinkDevice: Device + Debug {
72    /// The type of address used to address link devices of this type.
73    type Address: LinkDeviceAddress;
74}
75
76/// Utilities for testing link devices.
77#[cfg(any(test, feature = "testutils"))]
78pub(crate) mod testutil {
79    use net_types::BroadcastAddress;
80    use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
81
82    use super::*;
83    use crate::testutil::{FakeCoreCtx, FakeStrongDeviceId, FakeWeakDeviceId};
84    use crate::{DeviceIdContext, DeviceIdentifier, StrongDeviceIdentifier};
85
86    /// A fake [`LinkDevice`].
87    #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
88    pub enum FakeLinkDevice {}
89
90    const FAKE_LINK_ADDRESS_LEN: usize = 1;
91
92    /// A fake [`LinkAddress`].
93    ///
94    /// The value 0xFF is the broadcast address. The LSB is the individual/group bit.
95    #[derive(
96        KnownLayout,
97        FromBytes,
98        IntoBytes,
99        Immutable,
100        Unaligned,
101        Copy,
102        Clone,
103        Debug,
104        Hash,
105        PartialEq,
106        Eq,
107    )]
108    #[repr(transparent)]
109    pub struct FakeLinkAddress(pub [u8; FAKE_LINK_ADDRESS_LEN]);
110
111    impl FakeLinkAddress {
112        const BROADCAST: Self = Self([0xff; FAKE_LINK_ADDRESS_LEN]);
113    }
114
115    impl UnicastAddress for FakeLinkAddress {
116        #[inline]
117        fn is_unicast(&self) -> bool {
118            self.0[0] & 1 == 0
119        }
120    }
121
122    impl MulticastAddress for FakeLinkAddress {
123        #[inline]
124        fn is_multicast(&self) -> bool {
125            (self.0[0] & 1 == 1) && !self.is_broadcast()
126        }
127    }
128
129    impl BroadcastAddress for FakeLinkAddress {
130        #[inline]
131        fn is_broadcast(&self) -> bool {
132            *self == Self::BROADCAST
133        }
134    }
135
136    impl LinkAddress for FakeLinkAddress {
137        const BYTES_LENGTH: usize = FAKE_LINK_ADDRESS_LEN;
138
139        fn bytes(&self) -> &[u8] {
140            &self.0[..]
141        }
142
143        fn from_bytes(bytes: &[u8]) -> FakeLinkAddress {
144            FakeLinkAddress(bytes.try_into().unwrap())
145        }
146    }
147
148    impl Device for FakeLinkDevice {}
149
150    impl LinkDevice for FakeLinkDevice {
151        type Address = FakeLinkAddress;
152    }
153
154    /// A fake ID identifying a [`FakeLinkDevice`].
155    #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
156    pub struct FakeLinkDeviceId;
157
158    impl StrongDeviceIdentifier for FakeLinkDeviceId {
159        type Weak = FakeWeakDeviceId<Self>;
160
161        fn downgrade(&self) -> Self::Weak {
162            FakeWeakDeviceId(*self)
163        }
164    }
165
166    impl DeviceIdentifier for FakeLinkDeviceId {
167        fn is_loopback(&self) -> bool {
168            false
169        }
170    }
171
172    impl<S, M> DeviceIdContext<FakeLinkDevice> for FakeCoreCtx<S, M, FakeLinkDeviceId> {
173        type DeviceId = FakeLinkDeviceId;
174        type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
175    }
176
177    impl FakeStrongDeviceId for FakeLinkDeviceId {
178        fn is_alive(&self) -> bool {
179            true
180        }
181    }
182
183    impl PartialEq<FakeWeakDeviceId<FakeLinkDeviceId>> for FakeLinkDeviceId {
184        fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeLinkDeviceId>) -> bool {
185            self == other
186        }
187    }
188}