1// Copyright 2021 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.
45//! State maintained by the device layer.
67use alloc::sync::Arc;
8use core::fmt::Debug;
910use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
11use net_types::ip::{Ipv4, Ipv6};
12use netstack3_base::sync::{RwLock, WeakRc};
13use netstack3_base::{
14 CoreTimerContext, Device, DeviceIdContext, Inspectable, TimerContext, WeakDeviceIdentifier,
15};
16use netstack3_ip::device::{DualStackIpDeviceState, IpAddressIdSpec, IpDeviceTimerId};
17use netstack3_ip::RawMetric;
1819use crate::internal::base::{DeviceCounters, DeviceLayerTypes, OriginTracker};
20use crate::internal::socket::HeldDeviceSockets;
2122/// Provides the specifications for device state held by [`BaseDeviceId`] in
23/// [`BaseDeviceState`].
24pub trait DeviceStateSpec: Device + Sized + Send + Sync + 'static {
25/// The device state.
26type State<BT: DeviceLayerTypes>: Send + Sync;
27/// The external (bindings) state.
28type External<BT: DeviceLayerTypes>: Send + Sync;
29/// Properties given to device creation.
30type CreationProperties: Debug;
31/// Device-specific counters.
32type Counters: Inspectable;
33/// The timer identifier required by this device state.
34type TimerId<D: WeakDeviceIdentifier>;
3536/// Creates a new device state from the given properties.
37fn new_device_state<
38 CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
39 BC: DeviceLayerTypes + TimerContext,
40 >(
41 bindings_ctx: &mut BC,
42 self_id: CC::WeakDeviceId,
43 properties: Self::CreationProperties,
44 ) -> Self::State<BC>;
4546/// Marker for loopback devices.
47const IS_LOOPBACK: bool;
48/// Marker used to print debug information for device identifiers.
49const DEBUG_TYPE: &'static str;
50}
5152/// Groups state kept by weak device references.
53///
54/// A weak device reference must be able to carry the bindings identifier
55/// infallibly. The `WeakCookie` is kept inside [`BaseDeviceState`] in an `Arc`
56/// to group all the information that is cloned out to support weak device
57/// references.
58pub(crate) struct WeakCookie<T: DeviceStateSpec, BT: DeviceLayerTypes> {
59pub(crate) bindings_id: BT::DeviceIdentifier,
60pub(crate) weak_ref: WeakRc<BaseDeviceState<T, BT>>,
61}
6263pub(crate) struct BaseDeviceState<T: DeviceStateSpec, BT: DeviceLayerTypes> {
64pub(crate) ip: IpLinkDeviceState<T, BT>,
65pub(crate) external_state: T::External<BT>,
66pub(crate) weak_cookie: Arc<WeakCookie<T, BT>>,
67}
6869/// A convenience wrapper around `IpLinkDeviceStateInner` that uses
70/// `DeviceStateSpec` to extract the link state type and make type signatures
71/// shorter.
72pub type IpLinkDeviceState<T, BT> = IpLinkDeviceStateInner<<T as DeviceStateSpec>::State<BT>, BT>;
7374/// State for a link-device that is also an IP device.
75///
76/// `D` is the link-specific state.
77pub struct IpLinkDeviceStateInner<T, BT: DeviceLayerTypes> {
78/// The device's IP state.
79pub ip: DualStackIpDeviceState<BT>,
80/// The device's link state.
81pub link: T,
82pub(crate) origin: OriginTracker,
83pub(super) sockets: RwLock<HeldDeviceSockets<BT>>,
84/// Common device counters.
85pub counters: DeviceCounters,
86}
8788impl<T, BC: DeviceLayerTypes + TimerContext> IpLinkDeviceStateInner<T, BC> {
89/// Create a new `IpLinkDeviceState` with a link-specific state `link`.
90pub fn new<
91 D: WeakDeviceIdentifier,
92 A: IpAddressIdSpec,
93 CC: CoreTimerContext<IpDeviceTimerId<Ipv6, D, A>, BC>
94 + CoreTimerContext<IpDeviceTimerId<Ipv4, D, A>, BC>,
95 >(
96 bindings_ctx: &mut BC,
97 device_id: D,
98 link: T,
99 metric: RawMetric,
100 origin: OriginTracker,
101 ) -> Self {
102Self {
103 ip: DualStackIpDeviceState::new::<D, A, CC>(bindings_ctx, device_id, metric),
104 link,
105 origin,
106 sockets: RwLock::new(HeldDeviceSockets::default()),
107 counters: DeviceCounters::default(),
108 }
109 }
110}
111112impl<T, BT: DeviceLayerTypes> AsRef<DualStackIpDeviceState<BT>> for IpLinkDeviceStateInner<T, BT> {
113fn as_ref(&self) -> &DualStackIpDeviceState<BT> {
114&self.ip
115 }
116}
117118impl<T, BT: DeviceLayerTypes> OrderedLockAccess<HeldDeviceSockets<BT>>
119for IpLinkDeviceStateInner<T, BT>
120{
121type Lock = RwLock<HeldDeviceSockets<BT>>;
122fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
123 OrderedLockRef::new(&self.sockets)
124 }
125}