netstack3_core/
state.rs

1// Copyright 2023 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.
4
5//! Structs containing the entire stack state.
6
7use lock_order::lock::UnlockedAccess;
8use netstack3_base::{BuildableCoreContext, ContextProvider, CoreTimerContext, CtxPair};
9use netstack3_device::{DeviceId, DeviceLayerState};
10use netstack3_ip::icmp::IcmpState;
11use netstack3_ip::{self as ip, IpLayerIpExt, IpLayerTimerId, IpStateInner, Ipv4State, Ipv6State};
12
13use crate::api::CoreApi;
14use crate::time::TimerId;
15use crate::transport::{TransportLayerState, TransportStateBuilder};
16use crate::{BindingsContext, BindingsTypes, CoreCtx};
17
18/// A builder for [`StackState`].
19#[derive(Clone, Default)]
20pub struct StackStateBuilder {
21    transport: TransportStateBuilder,
22    ipv4: ip::Ipv4StateBuilder,
23    ipv6: ip::Ipv6StateBuilder,
24}
25
26impl StackStateBuilder {
27    /// Get the builder for the transport layer state.
28    pub fn transport_builder(&mut self) -> &mut TransportStateBuilder {
29        &mut self.transport
30    }
31
32    /// Get the builder for the IPv4 state.
33    pub fn ipv4_builder(&mut self) -> &mut ip::Ipv4StateBuilder {
34        &mut self.ipv4
35    }
36
37    /// Get the builder for the IPv6 state.
38    pub fn ipv6_builder(&mut self) -> &mut ip::Ipv6StateBuilder {
39        &mut self.ipv6
40    }
41
42    /// Consume this builder and produce a `StackState`.
43    pub fn build_with_ctx<BC: BindingsContext>(self, bindings_ctx: &mut BC) -> StackState<BC> {
44        StackState {
45            transport: self.transport.build_with_ctx(bindings_ctx),
46            ipv4: self.ipv4.build::<StackState<BC>, _, _>(bindings_ctx),
47            ipv6: self.ipv6.build::<StackState<BC>, _, _>(bindings_ctx),
48            device: Default::default(),
49        }
50    }
51}
52
53impl<BC: BindingsContext> BuildableCoreContext<BC> for StackState<BC> {
54    type Builder = StackStateBuilder;
55    fn build(bindings_ctx: &mut BC, builder: StackStateBuilder) -> Self {
56        builder.build_with_ctx(bindings_ctx)
57    }
58}
59
60/// The state associated with the network stack.
61pub struct StackState<BT: BindingsTypes> {
62    pub(crate) transport: TransportLayerState<BT>,
63    pub(crate) ipv4: Ipv4State<DeviceId<BT>, BT>,
64    pub(crate) ipv6: Ipv6State<DeviceId<BT>, BT>,
65    pub(crate) device: DeviceLayerState<BT>,
66}
67
68impl<BT: BindingsTypes> StackState<BT> {
69    /// Gets access to the API from a mutable reference to the bindings context.
70    pub fn api<'a, BP: ContextProvider<Context = BT>>(
71        &'a self,
72        bindings_ctx: BP,
73    ) -> CoreApi<'a, BP> {
74        CoreApi::new(CtxPair { core_ctx: CoreCtx::new(self), bindings_ctx })
75    }
76
77    pub(crate) fn inner_ip_state<I: IpLayerIpExt>(&self) -> &IpStateInner<I, DeviceId<BT>, BT> {
78        I::map_ip((), |()| &self.ipv4.inner, |()| &self.ipv6.inner)
79    }
80
81    pub(crate) fn inner_icmp_state<I: netstack3_base::IpExt>(&self) -> &IcmpState<I, BT> {
82        I::map_ip((), |()| &self.ipv4.icmp.inner, |()| &self.ipv6.icmp.inner)
83    }
84}
85
86// Stack state accessors for use in tests.
87// We don't want bindings using this directly.
88#[cfg(any(test, feature = "testutils"))]
89
90impl<BT: BindingsTypes> StackState<BT> {
91    /// Accessor for transport state.
92    pub fn transport(&self) -> &TransportLayerState<BT> {
93        &self.transport
94    }
95    /// Accessor for IPv4 state.
96    pub fn ipv4(&self) -> &Ipv4State<DeviceId<BT>, BT> {
97        &self.ipv4
98    }
99    /// Accessor for IPv6 state.
100    pub fn ipv6(&self) -> &Ipv6State<DeviceId<BT>, BT> {
101        &self.ipv6
102    }
103    /// Accessor for device state.
104    pub fn device(&self) -> &DeviceLayerState<BT> {
105        &self.device
106    }
107    /// Gets the core context.
108    pub fn context(&self) -> crate::context::UnlockedCoreCtx<'_, BT> {
109        crate::context::UnlockedCoreCtx::new(self)
110    }
111    /// Accessor for common IP state for `I`.
112    pub fn common_ip<I: IpLayerIpExt>(&self) -> &IpStateInner<I, DeviceId<BT>, BT> {
113        self.inner_ip_state::<I>()
114    }
115    /// Accessor for common ICMP state for `I`.
116    pub fn common_icmp<I: netstack3_base::IpExt>(&self) -> &IcmpState<I, BT> {
117        self.inner_icmp_state::<I>()
118    }
119}
120
121impl<BT: BindingsTypes> CoreTimerContext<IpLayerTimerId, BT> for StackState<BT> {
122    fn convert_timer(timer: IpLayerTimerId) -> TimerId<BT> {
123        timer.into()
124    }
125}
126
127/// It is safe to provide unlocked access to [`StackState`] itself here because
128/// care has been taken to avoid exposing publicly to the core integration crate
129/// any state that is held by a lock, as opposed to read-only state that can be
130/// accessed safely at any lock level, e.g. state with no interior mutability or
131/// atomics.
132///
133/// Access to state held by locks *must* be mediated using the global lock
134/// ordering declared in [`crate::lock_ordering`].
135impl<BT: BindingsTypes> UnlockedAccess<crate::lock_ordering::UnlockedState> for StackState<BT> {
136    type Data = StackState<BT>;
137    type Guard<'l>
138        = &'l StackState<BT>
139    where
140        Self: 'l;
141
142    fn access(&self) -> Self::Guard<'_> {
143        &self
144    }
145}