blob: ab942550a08113c1f9051486549b02ba0990c207 [file] [log] [blame]
// Copyright 2021 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.
//! State maintained by the device layer.
use alloc::sync::Arc;
use core::fmt::Debug;
use net_types::ip::Ipv6;
use crate::{
context::{CoreTimerContext, TimerContext2},
device::{
self, socket::HeldDeviceSockets, Device, DeviceCounters, DeviceIdContext, DeviceLayerTypes,
OriginTracker,
},
inspect::Inspectable,
ip::{
device::{state::DualStackIpDeviceState, IpDeviceTimerId},
types::RawMetric,
},
sync::RwLock,
sync::WeakRc,
};
/// Provides the specifications for device state held by [`BaseDeviceId`] in
/// [`BaseDeviceState`].
pub trait DeviceStateSpec: Device + Sized + Send + Sync + 'static {
/// The link state.
type Link<BT: DeviceLayerTypes>: Send + Sync;
/// The external (bindings) state.
type External<BT: DeviceLayerTypes>: Send + Sync;
/// Properties given to device creation.
type CreationProperties: Debug;
/// Device-specific counters.
type Counters: Inspectable;
/// The timer identifier required by this device state.
type TimerId<D: device::WeakId>;
/// Creates a new link state from the given properties.
fn new_link_state<
CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
BC: DeviceLayerTypes + TimerContext2,
>(
bindings_ctx: &mut BC,
self_id: CC::WeakDeviceId,
properties: Self::CreationProperties,
) -> Self::Link<BC>;
/// Marker for loopback devices.
const IS_LOOPBACK: bool;
/// Marker used to print debug information for device identifiers.
const DEBUG_TYPE: &'static str;
}
/// Groups state kept by weak device references.
///
/// A weak device reference must be able to carry the bindings identifier
/// infallibly. The `WeakCookie` is kept inside [`BaseDeviceState`] in an `Arc`
/// to group all the information that is cloned out to support weak device
/// references.
pub(crate) struct WeakCookie<T: DeviceStateSpec, BT: DeviceLayerTypes> {
pub(crate) bindings_id: BT::DeviceIdentifier,
pub(crate) weak_ref: WeakRc<BaseDeviceState<T, BT>>,
}
pub(crate) struct BaseDeviceState<T: DeviceStateSpec, BT: DeviceLayerTypes> {
pub(crate) ip: IpLinkDeviceState<T, BT>,
pub(crate) external_state: T::External<BT>,
pub(crate) weak_cookie: Arc<WeakCookie<T, BT>>,
}
/// A convenience wrapper around `IpLinkDeviceStateInner` that uses
/// `DeviceStateSpec` to extract the link state type and make type signatures
/// shorter.
pub(crate) type IpLinkDeviceState<T, BT> =
IpLinkDeviceStateInner<<T as DeviceStateSpec>::Link<BT>, BT>;
/// State for a link-device that is also an IP device.
///
/// `D` is the link-specific state.
pub(crate) struct IpLinkDeviceStateInner<T, BT: DeviceLayerTypes> {
pub ip: DualStackIpDeviceState<BT>,
pub link: T,
pub(super) origin: OriginTracker,
pub(super) sockets: RwLock<HeldDeviceSockets<BT>>,
pub(super) counters: DeviceCounters,
}
impl<T, BC: DeviceLayerTypes + TimerContext2> IpLinkDeviceStateInner<T, BC> {
/// Create a new `IpLinkDeviceState` with a link-specific state `link`.
pub(super) fn new<D: device::StrongId, CC: CoreTimerContext<IpDeviceTimerId<Ipv6, D>, BC>>(
bindings_ctx: &mut BC,
device_id: D::Weak,
link: T,
metric: RawMetric,
origin: OriginTracker,
) -> Self {
Self {
ip: DualStackIpDeviceState::new::<_, CC>(bindings_ctx, device_id, metric),
link,
origin,
sockets: RwLock::new(HeldDeviceSockets::default()),
counters: DeviceCounters::default(),
}
}
}
impl<T, BT: DeviceLayerTypes> AsRef<DualStackIpDeviceState<BT>> for IpLinkDeviceStateInner<T, BT> {
fn as_ref(&self) -> &DualStackIpDeviceState<BT> {
&self.ip
}
}