blob: 777140158b55b01f6ba5c29a62d3bd9103ea0de0 [file] [log] [blame]
// 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;
}
}