| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| //! Link device (L2) definitions. |
| //! |
| //! This module contains definitions of link-layer devices, otherwise known as |
| //! L2 devices. |
| |
| use core::fmt::Debug; |
| |
| use net_types::ethernet::Mac; |
| use zerocopy::{AsBytes, FromBytes, Unaligned}; |
| |
| /// The type of address used by a link device. |
| pub(crate) trait LinkAddress: |
| 'static + FromBytes + AsBytes + Unaligned + Copy + Clone + Debug + Eq |
| { |
| /// The length of the address in bytes. |
| const BYTES_LENGTH: usize; |
| |
| /// Returns the underlying bytes of a `LinkAddress`. |
| fn bytes(&self) -> &[u8]; |
| |
| /// Constructs a `LinkLayerAddress` from the provided bytes. |
| /// |
| /// # Panics |
| /// |
| /// `from_bytes` may panic if `bytes` is not **exactly** [`BYTES_LENGTH`] |
| /// long. |
| fn from_bytes(bytes: &[u8]) -> Self; |
| } |
| |
| /// A [`LinkAddress`] with a broadcast value. |
| /// |
| /// A `BroadcastLinkAddress` is a `LinkAddress` for which at least one address |
| /// is a "broadcast" address, indicating that a frame should be received by all |
| /// hosts on a link. |
| pub(crate) trait BroadcastLinkAddress: LinkAddress { |
| /// The broadcast address. |
| /// |
| /// If the addressing scheme supports multiple broadcast addresses, then |
| /// there is no requirement as to which one is chosen for this constant. |
| const BROADCAST: Self; |
| } |
| |
| impl LinkAddress for Mac { |
| const BYTES_LENGTH: usize = 6; |
| |
| fn bytes(&self) -> &[u8] { |
| self.as_ref() |
| } |
| |
| fn from_bytes(bytes: &[u8]) -> Self { |
| // assert that contract is being held: |
| debug_assert_eq!(bytes.len(), Self::BYTES_LENGTH); |
| let mut b = [0; Self::BYTES_LENGTH]; |
| b.copy_from_slice(bytes); |
| Self::new(b) |
| } |
| } |
| |
| impl BroadcastLinkAddress for Mac { |
| const BROADCAST: Mac = Mac::BROADCAST; |
| } |
| |
| /// A link device. |
| /// |
| /// `LinkDevice` is used to identify a particular link device implementation. It |
| /// is only intended to exist at the type level, never instantiated at runtime. |
| pub(crate) trait LinkDevice: 'static + Copy + Clone { |
| /// The type of address used to address link devices of this type. |
| type Address: LinkAddress; |
| } |
| |
| /// Utilities for testing link devices. |
| #[cfg(test)] |
| pub(crate) mod testutil { |
| use core::convert::TryInto; |
| use core::fmt::{self, Display, Formatter}; |
| |
| use super::*; |
| use crate::device::DeviceIdContext; |
| |
| /// A dummy [`LinkDevice`]. |
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
| pub(crate) enum DummyLinkDevice {} |
| |
| const DUMMY_LINK_ADDRESS_LEN: usize = 1; |
| |
| /// A dummy [`LinkAddress`]. |
| /// |
| /// The value 0xFF is the broadcast address. |
| #[derive(FromBytes, AsBytes, Unaligned, Copy, Clone, Debug, Hash, PartialEq, Eq)] |
| #[repr(transparent)] |
| pub(crate) struct DummyLinkAddress([u8; DUMMY_LINK_ADDRESS_LEN]); |
| |
| impl LinkAddress for DummyLinkAddress { |
| const BYTES_LENGTH: usize = DUMMY_LINK_ADDRESS_LEN; |
| |
| fn bytes(&self) -> &[u8] { |
| &self.0[..] |
| } |
| |
| fn from_bytes(bytes: &[u8]) -> DummyLinkAddress { |
| DummyLinkAddress(bytes.try_into().unwrap()) |
| } |
| } |
| |
| impl BroadcastLinkAddress for DummyLinkAddress { |
| const BROADCAST: DummyLinkAddress = DummyLinkAddress([0xFF]); |
| } |
| |
| impl LinkDevice for DummyLinkDevice { |
| type Address = DummyLinkAddress; |
| } |
| |
| /// A dummy ID identifying a [`DummyLinkDevice`]. |
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
| pub(crate) struct DummyLinkDeviceId; |
| |
| impl Display for DummyLinkDeviceId { |
| fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
| write!(f, "{:?}", self) |
| } |
| } |
| |
| impl<C> DeviceIdContext<DummyLinkDevice> for C { |
| type DeviceId = DummyLinkDeviceId; |
| } |
| } |