blob: cd5f52726fb0c5266b1688e5c9d328af7e5c33e7 [file] [log] [blame]
// Copyright 2023 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.
//! Structs containing the entire stack state.
use net_types::ip::{GenericOverIp, Ip, IpInvariant, Ipv4, Ipv6};
use crate::{
api::CoreApi,
context::{ContextProvider, CoreTimerContext, CtxPair},
device::{
arp::ArpCounters, DeviceCounters, DeviceId, DeviceLayerState, EthernetDeviceCounters,
PureIpDeviceCounters, WeakDeviceId,
},
filter::FilterBindingsTypes,
ip::{
self,
device::nud::NudCounters,
device::slaac::SlaacCounters,
icmp::{IcmpState, NdpCounters},
IpCounters, IpLayerIpExt, IpLayerTimerId, IpStateInner, Ipv4State, Ipv6State,
},
socket::datagram,
sync::RwLock,
time::TimerId,
transport::{self, tcp::TcpCounters, udp::UdpCounters, TransportLayerState},
BindingsContext, BindingsTypes, CoreCtx,
};
/// A builder for [`StackState`].
#[derive(Default, Clone)]
pub(crate) struct StackStateBuilder {
transport: transport::TransportStateBuilder,
ipv4: ip::Ipv4StateBuilder,
ipv6: ip::Ipv6StateBuilder,
}
impl StackStateBuilder {
#[cfg(test)]
/// Get the builder for the transport layer state.
pub(crate) fn transport_builder(&mut self) -> &mut transport::TransportStateBuilder {
&mut self.transport
}
#[cfg(test)]
/// Get the builder for the IPv4 state.
pub(crate) fn ipv4_builder(&mut self) -> &mut ip::Ipv4StateBuilder {
&mut self.ipv4
}
/// Consume this builder and produce a `StackState`.
pub(crate) fn build_with_ctx<BC: BindingsContext>(
self,
bindings_ctx: &mut BC,
) -> StackState<BC> {
StackState {
transport: self.transport.build_with_ctx(bindings_ctx),
ipv4: self.ipv4.build::<StackState<BC>, _, _>(bindings_ctx),
ipv6: self.ipv6.build::<StackState<BC>, _, _>(bindings_ctx),
device: DeviceLayerState::new(),
}
}
}
/// The state associated with the network stack.
pub struct StackState<BT: BindingsTypes> {
pub(crate) transport: TransportLayerState<BT>,
pub(crate) ipv4: Ipv4State<DeviceId<BT>, BT>,
pub(crate) ipv6: Ipv6State<DeviceId<BT>, BT>,
pub(crate) device: DeviceLayerState<BT>,
}
impl<BT: BindingsTypes> StackState<BT> {
/// Gets access to the API from a mutable reference to the bindings context.
pub fn api<'a, BP: ContextProvider<Context = BT>>(
&'a self,
bindings_ctx: BP,
) -> CoreApi<'a, BP> {
CoreApi::new(CtxPair { core_ctx: CoreCtx::new(self), bindings_ctx })
}
#[cfg(any(test, feature = "testutils"))]
pub(crate) fn context(&self) -> crate::context::UnlockedCoreCtx<'_, BT> {
crate::context::UnlockedCoreCtx::new(self)
}
pub(crate) fn ip_counters<I: IpLayerIpExt>(&self) -> &IpCounters<I> {
I::map_ip(
IpInvariant(self),
|IpInvariant(state)| state.ipv4.as_ref().counters(),
|IpInvariant(state)| state.ipv6.as_ref().counters(),
)
}
pub(crate) fn filter<I: packet_formats::ip::IpExt>(
&self,
) -> &RwLock<crate::filter::State<I, BT>> {
#[derive(GenericOverIp)]
#[generic_over_ip(I, Ip)]
struct Wrap<'a, I: packet_formats::ip::IpExt, BT: FilterBindingsTypes>(
&'a RwLock<crate::filter::State<I, BT>>,
);
let Wrap(state) = I::map_ip(
IpInvariant(self),
|IpInvariant(state)| Wrap(state.ipv4.filter()),
|IpInvariant(state)| Wrap(state.ipv6.filter()),
);
state
}
pub(crate) fn nud_counters<I: Ip>(&self) -> &NudCounters<I> {
I::map_ip(
IpInvariant(self),
|IpInvariant(state)| state.device.nud_counters::<Ipv4>(),
|IpInvariant(state)| state.device.nud_counters::<Ipv6>(),
)
}
pub(crate) fn ndp_counters(&self) -> &NdpCounters {
&self.ipv6.icmp().ndp_counters
}
pub(crate) fn device_counters(&self) -> &DeviceCounters {
&self.device.counters()
}
pub(crate) fn ethernet_device_counters(&self) -> &EthernetDeviceCounters {
&self.device.ethernet_counters()
}
pub(crate) fn pure_ip_device_counters(&self) -> &PureIpDeviceCounters {
&self.device.pure_ip_counters()
}
pub(crate) fn arp_counters(&self) -> &ArpCounters {
&self.device.arp_counters()
}
pub(crate) fn udp_counters<I: Ip>(&self) -> &UdpCounters<I> {
&self.transport.udp_counters::<I>()
}
pub(crate) fn tcp_counters<I: Ip>(&self) -> &TcpCounters<I> {
&self.transport.tcp_counters::<I>()
}
pub(crate) fn slaac_counters(&self) -> &SlaacCounters {
&self.ipv6.slaac_counters()
}
pub(crate) fn inner_ip_state<I: IpLayerIpExt>(&self) -> &IpStateInner<I, DeviceId<BT>, BT> {
I::map_ip((), |()| self.ipv4.inner(), |()| self.ipv6.inner())
}
pub(crate) fn inner_icmp_state<I: ip::IpExt + datagram::DualStackIpExt>(
&self,
) -> &IcmpState<I, WeakDeviceId<BT>, BT> {
I::map_ip((), |()| &self.ipv4.icmp().inner, |()| &self.ipv6.icmp().inner)
}
}
impl<BC: BindingsContext> StackState<BC> {
/// Create a new `StackState`.
pub fn new(bindings_ctx: &mut BC) -> Self {
StackStateBuilder::default().build_with_ctx(bindings_ctx)
}
}
impl<BT: BindingsTypes> CoreTimerContext<IpLayerTimerId, BT> for StackState<BT> {
fn convert_timer(timer: IpLayerTimerId) -> TimerId<BT> {
timer.into()
}
}