use alloc::sync::Arc;
use core::fmt::Debug;
use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
use net_types::ip::{Ipv4, Ipv6};
use netstack3_base::sync::{RwLock, WeakRc};
use netstack3_base::{
CoreTimerContext, Device, DeviceIdContext, Inspectable, TimerContext, WeakDeviceIdentifier,
};
use netstack3_ip::device::{DualStackIpDeviceState, IpAddressIdSpec, IpDeviceTimerId};
use netstack3_ip::RawMetric;
use crate::internal::base::{DeviceCounters, DeviceLayerTypes, OriginTracker};
use crate::internal::socket::HeldDeviceSockets;
pub trait DeviceStateSpec: Device + Sized + Send + Sync + 'static {
type Link<BT: DeviceLayerTypes>: Send + Sync;
type External<BT: DeviceLayerTypes>: Send + Sync;
type CreationProperties: Debug;
type Counters: Inspectable;
type TimerId<D: WeakDeviceIdentifier>;
fn new_link_state<
CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
BC: DeviceLayerTypes + TimerContext,
>(
bindings_ctx: &mut BC,
self_id: CC::WeakDeviceId,
properties: Self::CreationProperties,
) -> Self::Link<BC>;
const IS_LOOPBACK: bool;
const DEBUG_TYPE: &'static str;
}
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>>,
}
pub type IpLinkDeviceState<T, BT> = IpLinkDeviceStateInner<<T as DeviceStateSpec>::Link<BT>, BT>;
pub struct IpLinkDeviceStateInner<T, BT: DeviceLayerTypes> {
pub ip: DualStackIpDeviceState<BT>,
pub link: T,
pub(crate) origin: OriginTracker,
pub(super) sockets: RwLock<HeldDeviceSockets<BT>>,
pub counters: DeviceCounters,
}
impl<T, BC: DeviceLayerTypes + TimerContext> IpLinkDeviceStateInner<T, BC> {
pub fn new<
D: WeakDeviceIdentifier,
A: IpAddressIdSpec,
CC: CoreTimerContext<IpDeviceTimerId<Ipv6, D, A>, BC>
+ CoreTimerContext<IpDeviceTimerId<Ipv4, D, A>, BC>,
>(
bindings_ctx: &mut BC,
device_id: D,
link: T,
metric: RawMetric,
origin: OriginTracker,
) -> Self {
Self {
ip: DualStackIpDeviceState::new::<D, A, 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
}
}
impl<T, BT: DeviceLayerTypes> OrderedLockAccess<HeldDeviceSockets<BT>>
for IpLinkDeviceStateInner<T, BT>
{
type Lock = RwLock<HeldDeviceSockets<BT>>;
fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
OrderedLockRef::new(&self.sockets)
}
}