netstack3_datagram/
diagnostics.rs

1// Copyright 2025 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//! Definitions for datagram socket types that implement socket diagnostics.
6
7use core::marker::PhantomData;
8
9use net_types::Witness;
10use netstack3_base::{
11    IpSocketProperties, Matcher, SocketTransportProtocolMatcher, WeakDeviceIdentifier,
12};
13
14use crate::internal::datagram::{
15    DatagramBindingsTypes, DatagramBoundStateContext, DatagramSocketSpec, IpExt, SocketState,
16};
17
18/// Implementation-specific functionality for matching datagram sockets.
19///
20/// Implementing this trait means that [`SocketStateForMatching`] will
21/// automatically implement [`IpSocketProperties`] for that datagram socket
22/// protocol.
23pub trait DatagramSocketDiagnosticsSpec: DatagramSocketSpec {
24    /// The device class of physical interfaces used by the sockets.
25    type DeviceClass;
26
27    /// Returns whether the provided `state` is matched by the transport
28    /// protocol matcher `matcher`.
29    fn transport_protocol_matches<I: IpExt, D: WeakDeviceIdentifier>(
30        state: &SocketState<I, D, Self>,
31        matcher: &SocketTransportProtocolMatcher,
32    ) -> bool;
33
34    /// Returns whether the provided `id` is matched by the cookie matcher
35    /// `matcher`.
36    fn cookie_matches<I: IpExt, D: WeakDeviceIdentifier>(
37        id: &Self::SocketId<I, D>,
38        matcher: &netstack3_base::SocketCookieMatcher,
39    ) -> bool;
40}
41
42/// State required for matching a socket, gathered into one struct to allow
43/// implementing traits against the collection.
44pub struct SocketStateForMatching<'a, I, D, S, BC, CC>
45where
46    I: IpExt,
47    D: WeakDeviceIdentifier,
48    S: DatagramSocketSpec,
49    BC: DatagramBindingsTypes,
50{
51    state: &'a SocketState<I, D, S>,
52    id: &'a S::SocketId<I, D>,
53    ctx: &'a CC,
54    _bindings_ctx: PhantomData<BC>,
55}
56
57impl<'a, I, D, S, BC, CC> SocketStateForMatching<'a, I, D, S, BC, CC>
58where
59    I: IpExt,
60    D: WeakDeviceIdentifier,
61    S: DatagramSocketSpec,
62    BC: DatagramBindingsTypes,
63{
64    /// Wraps the required state into a [`SocketStateForMatching`].
65    pub fn new(state: &'a SocketState<I, D, S>, id: &'a S::SocketId<I, D>, ctx: &'a CC) -> Self {
66        Self { state, id, ctx, _bindings_ctx: PhantomData }
67    }
68}
69
70impl<I, D, S, BC, CC> IpSocketProperties<S::DeviceClass>
71    for SocketStateForMatching<'_, I, D, S, BC, CC>
72where
73    I: IpExt,
74    D: WeakDeviceIdentifier,
75    S: DatagramSocketDiagnosticsSpec,
76    BC: DatagramBindingsTypes,
77    CC: DatagramBoundStateContext<I, BC, S, WeakDeviceId = D>,
78    D::Strong: netstack3_base::InterfaceProperties<S::DeviceClass>,
79{
80    fn family_matches(&self, family: &net_types::ip::IpVersion) -> bool {
81        I::VERSION == *family
82    }
83
84    fn src_addr_matches(&self, addr: &netstack3_base::AddressMatcherEither) -> bool {
85        addr.required_matches(self.state.local_ip().map(|addr| addr.addr().get().into()).as_ref())
86    }
87
88    fn dst_addr_matches(&self, addr: &netstack3_base::AddressMatcherEither) -> bool {
89        addr.required_matches(self.state.remote_ip().map(|addr| addr.addr().get().into()).as_ref())
90    }
91
92    fn transport_protocol_matches(&self, proto: &SocketTransportProtocolMatcher) -> bool {
93        S::transport_protocol_matches(self.state, proto)
94    }
95
96    fn bound_interface_matches(
97        &self,
98        iface: &netstack3_base::BoundInterfaceMatcher<S::DeviceClass>,
99    ) -> bool {
100        let (_, device) = self.state.get_options_device(self.ctx);
101        let device = device.as_ref().and_then(|weak| weak.upgrade());
102        iface.matches(&device.as_ref())
103    }
104
105    fn cookie_matches(&self, cookie: &netstack3_base::SocketCookieMatcher) -> bool {
106        S::cookie_matches(self.id, cookie)
107    }
108
109    fn mark_matches(&self, mark: &netstack3_base::MarkInDomainMatcher) -> bool {
110        let options = self.state.get_options(self.ctx);
111        mark.matcher.matches(options.marks().get(mark.domain))
112    }
113}