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::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.
64pub trait LinkUnicastAddress: LinkAddress + UnicastAddress {}
65impl<L: LinkAddress + UnicastAddress> LinkUnicastAddress 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: LinkUnicastAddress;
74}
75
76/// Utilities for testing link devices.
77#[cfg(any(test, feature = "testutils"))]
78pub(crate) mod testutil {
79    use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
80
81    use super::*;
82    use crate::testutil::{FakeCoreCtx, FakeStrongDeviceId, FakeWeakDeviceId};
83    use crate::{DeviceIdContext, DeviceIdentifier, StrongDeviceIdentifier};
84
85    /// A fake [`LinkDevice`].
86    #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
87    pub enum FakeLinkDevice {}
88
89    const FAKE_LINK_ADDRESS_LEN: usize = 1;
90
91    /// A fake [`LinkAddress`].
92    ///
93    /// The value 0xFF is the broadcast address.
94    #[derive(
95        KnownLayout,
96        FromBytes,
97        IntoBytes,
98        Immutable,
99        Unaligned,
100        Copy,
101        Clone,
102        Debug,
103        Hash,
104        PartialEq,
105        Eq,
106    )]
107    #[repr(transparent)]
108    pub struct FakeLinkAddress(pub [u8; FAKE_LINK_ADDRESS_LEN]);
109
110    impl UnicastAddress for FakeLinkAddress {
111        fn is_unicast(&self) -> bool {
112            let Self(bytes) = self;
113            bytes != &[0xff]
114        }
115    }
116
117    impl LinkAddress for FakeLinkAddress {
118        const BYTES_LENGTH: usize = FAKE_LINK_ADDRESS_LEN;
119
120        fn bytes(&self) -> &[u8] {
121            &self.0[..]
122        }
123
124        fn from_bytes(bytes: &[u8]) -> FakeLinkAddress {
125            FakeLinkAddress(bytes.try_into().unwrap())
126        }
127    }
128
129    impl Device for FakeLinkDevice {}
130
131    impl LinkDevice for FakeLinkDevice {
132        type Address = FakeLinkAddress;
133    }
134
135    /// A fake ID identifying a [`FakeLinkDevice`].
136    #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
137    pub struct FakeLinkDeviceId;
138
139    impl StrongDeviceIdentifier for FakeLinkDeviceId {
140        type Weak = FakeWeakDeviceId<Self>;
141
142        fn downgrade(&self) -> Self::Weak {
143            FakeWeakDeviceId(*self)
144        }
145    }
146
147    impl DeviceIdentifier for FakeLinkDeviceId {
148        fn is_loopback(&self) -> bool {
149            false
150        }
151    }
152
153    impl<S, M> DeviceIdContext<FakeLinkDevice> for FakeCoreCtx<S, M, FakeLinkDeviceId> {
154        type DeviceId = FakeLinkDeviceId;
155        type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
156    }
157
158    impl FakeStrongDeviceId for FakeLinkDeviceId {
159        fn is_alive(&self) -> bool {
160            true
161        }
162    }
163
164    impl PartialEq<FakeWeakDeviceId<FakeLinkDeviceId>> for FakeLinkDeviceId {
165        fn eq(&self, FakeWeakDeviceId(other): &FakeWeakDeviceId<FakeLinkDeviceId>) -> bool {
166            self == other
167        }
168    }
169}