netstack3_base/device/
address.rs

1// Copyright 2024 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//! Address definitions for devices.
6
7use core::fmt::{Debug, Display};
8use core::hash::Hash;
9
10use net_types::ip::{
11    AddrSubnet, GenericOverIp, Ip, IpAddress, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr,
12};
13use net_types::{NonMappedAddr, NonMulticastAddr, SpecifiedAddr, UnicastAddr, Witness};
14
15use crate::device::{AnyDevice, DeviceIdContext};
16use crate::inspect::InspectableValue;
17use crate::socket::SocketIpAddr;
18
19/// An extension trait adding an associated type for an IP address assigned to a
20/// device.
21pub trait AssignedAddrIpExt: Ip {
22    /// The witness type for assigned addresses.
23    type AssignedWitness: Witness<Self::Addr>
24        + Copy
25        + Eq
26        + PartialEq
27        + Debug
28        + Display
29        + Hash
30        + Send
31        + Sync
32        + Into<SpecifiedAddr<Self::Addr>>;
33}
34
35impl AssignedAddrIpExt for Ipv4 {
36    type AssignedWitness = Ipv4DeviceAddr;
37}
38
39impl AssignedAddrIpExt for Ipv6 {
40    type AssignedWitness = Ipv6DeviceAddr;
41}
42
43/// A weak IP address ID.
44pub trait WeakIpAddressId<A: IpAddress>:
45    Clone + Eq + Debug + Hash + Send + Sync + InspectableValue + 'static
46{
47    /// The strong version of this ID.
48    type Strong: IpAddressId<A>;
49
50    /// Attempts to upgrade this ID to the strong version.
51    ///
52    /// Upgrading fails if this is no longer a valid assigned IP address.
53    fn upgrade(&self) -> Option<Self::Strong>;
54
55    /// Returns whether this address is still assigned.
56    fn is_assigned(&self) -> bool;
57}
58
59/// An IP address ID.
60pub trait IpAddressId<A: IpAddress>: Clone + Eq + Debug + Hash {
61    /// The weak version of this ID.
62    type Weak: WeakIpAddressId<A>;
63
64    /// Downgrades this ID to a weak reference.
65    fn downgrade(&self) -> Self::Weak;
66
67    /// Returns the address this ID represents.
68    //
69    // TODO(https://fxbug.dev/382104850): align this method with `addr_sub` by
70    // returning `A::Version::AssignedWitness` directly, and add an
71    // `Into: IpDeviceAddr<A>` bound on that associated type.
72    fn addr(&self) -> IpDeviceAddr<A>;
73
74    /// Returns the address subnet this ID represents.
75    fn addr_sub(&self) -> AddrSubnet<A, <A::Version as AssignedAddrIpExt>::AssignedWitness>
76    where
77        A::Version: AssignedAddrIpExt;
78}
79
80/// Provides the execution context related to address IDs.
81pub trait IpDeviceAddressIdContext<I: Ip>: DeviceIdContext<AnyDevice> {
82    /// The strong address identifier.
83    type AddressId: IpAddressId<I::Addr, Weak = Self::WeakAddressId>;
84    /// The weak address identifier.
85    type WeakAddressId: WeakIpAddressId<I::Addr, Strong = Self::AddressId>;
86}
87
88/// An IP address that witnesses properties needed to be assigned to a device.
89#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
90#[generic_over_ip(A, IpAddress)]
91pub struct IpDeviceAddr<A: IpAddress>(NonMulticastAddr<NonMappedAddr<SpecifiedAddr<A>>>);
92
93impl<A: IpAddress> Display for IpDeviceAddr<A> {
94    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95        let Self(addr) = self;
96        write!(f, "{}", addr)
97    }
98}
99
100impl<A: IpAddress> IpDeviceAddr<A> {
101    /// Returns the inner address, dropping all witnesses.
102    pub fn addr(self) -> A {
103        let Self(addr) = self;
104        ***addr
105    }
106
107    /// Returns the inner address, including all witness types.
108    pub fn into_inner(self) -> NonMulticastAddr<NonMappedAddr<SpecifiedAddr<A>>> {
109        let IpDeviceAddr(addr) = self;
110        addr
111    }
112
113    /// Constructs an [`IpDeviceAddr`] if the address is compliant, else `None`.
114    pub fn new(addr: A) -> Option<IpDeviceAddr<A>> {
115        Some(IpDeviceAddr(NonMulticastAddr::new(NonMappedAddr::new(SpecifiedAddr::new(addr)?)?)?))
116    }
117
118    /// Constructs an [`IpDeviceAddr`] from the inner witness.
119    pub fn new_from_witness(addr: NonMulticastAddr<NonMappedAddr<SpecifiedAddr<A>>>) -> Self {
120        Self(addr)
121    }
122
123    /// Attempts to constructs an [`IpDeviceAddr`] from a [`SocketIpAddr`].
124    pub fn new_from_socket_ip_addr(addr: SocketIpAddr<A>) -> Option<Self> {
125        NonMulticastAddr::new(addr.into_inner()).map(Self)
126    }
127}
128
129impl IpDeviceAddr<Ipv6Addr> {
130    /// Constructs an [`IpDeviceAddr`] from the given [`Ipv6DeviceAddr`].
131    pub fn new_from_ipv6_device_addr(addr: Ipv6DeviceAddr) -> Self {
132        let addr: UnicastAddr<NonMappedAddr<Ipv6Addr>> = addr.transpose();
133        let addr: NonMappedAddr<SpecifiedAddr<Ipv6Addr>> = addr.into_specified().transpose();
134        // SAFETY: The address is known to be unicast, because it was provided
135        // as a `UnicastAddr`. A unicast address must be `NonMulticast`.
136        let addr = unsafe { NonMulticastAddr::new_unchecked(addr) };
137        Self(addr)
138    }
139
140    /// Constructs an [`IpDeviceAddr`] from the given [`Ipv6SourceAddr`].
141    pub fn new_from_ipv6_source(addr: Ipv6SourceAddr) -> Option<Self> {
142        match addr {
143            Ipv6SourceAddr::Unicast(addr) => Some(Self::new_from_ipv6_device_addr(addr)),
144            Ipv6SourceAddr::Unspecified => None,
145        }
146    }
147}
148
149impl<A: IpAddress> From<IpDeviceAddr<A>> for SpecifiedAddr<A> {
150    fn from(addr: IpDeviceAddr<A>) -> Self {
151        **addr.into_inner()
152    }
153}
154
155impl<A: IpAddress> AsRef<SpecifiedAddr<A>> for IpDeviceAddr<A> {
156    fn as_ref(&self) -> &SpecifiedAddr<A> {
157        let Self(addr) = self;
158        addr.as_ref()
159    }
160}
161
162impl<A: IpAddress> From<IpDeviceAddr<A>> for SocketIpAddr<A> {
163    fn from(addr: IpDeviceAddr<A>) -> Self {
164        SocketIpAddr::new_from_witness(*addr.into_inner())
165    }
166}
167
168#[derive(Debug)]
169pub enum IpDeviceAddrError {
170    NotNonMapped,
171    NotNonMulticast,
172}
173
174impl<A: IpAddress> TryFrom<SpecifiedAddr<A>> for IpDeviceAddr<A> {
175    type Error = IpDeviceAddrError;
176    fn try_from(addr: SpecifiedAddr<A>) -> Result<Self, Self::Error> {
177        Ok(IpDeviceAddr::new_from_witness(
178            NonMulticastAddr::new(NonMappedAddr::new(addr).ok_or(IpDeviceAddrError::NotNonMapped)?)
179                .ok_or(IpDeviceAddrError::NotNonMulticast)?,
180        ))
181    }
182}
183
184/// An Ipv4 address that witnesses properties needed to be assigned to a device.
185///
186/// These witnesses are the same that are held by [`IpDeviceAddr`], however that
187/// type cannot be used here directly because we need [`Ipv4DeviceAddr`] to
188/// implement `Witness<Ipv4Addr>`. That implementation is not present for our
189/// new type [`IpDeviceAddr`] which wraps the true witnesses from the net-types
190/// crate.
191pub type Ipv4DeviceAddr = NonMulticastAddr<NonMappedAddr<SpecifiedAddr<Ipv4Addr>>>;
192
193/// An IPv6 address that witnesses properties needed to be assigned to a device.
194///
195/// Like [`IpDeviceAddr`] but with stricter witnesses that are permitted for
196/// IPv6 addresses.
197pub type Ipv6DeviceAddr = NonMappedAddr<UnicastAddr<Ipv6Addr>>;
198
199#[cfg(any(test, feature = "testutils"))]
200pub mod testutil {
201    use net_types::ip::GenericOverIp;
202
203    use super::*;
204    use crate::inspect::Inspector;
205    use crate::testutil::FakeCoreCtx;
206    use crate::StrongDeviceIdentifier;
207
208    /// A fake weak address ID.
209    #[derive(Clone, Debug, Hash, Eq, PartialEq)]
210    pub struct FakeWeakAddressId<T>(pub T);
211
212    impl<A: IpAddress, T: IpAddressId<A> + Send + Sync + 'static> WeakIpAddressId<A>
213        for FakeWeakAddressId<T>
214    {
215        type Strong = T;
216
217        fn upgrade(&self) -> Option<Self::Strong> {
218            let Self(inner) = self;
219            Some(inner.clone())
220        }
221
222        fn is_assigned(&self) -> bool {
223            true
224        }
225    }
226
227    impl<T> InspectableValue for FakeWeakAddressId<T> {
228        fn record<I: Inspector>(&self, _name: &str, _inspector: &mut I) {
229            unimplemented!()
230        }
231    }
232
233    impl<A: IpAddress> IpAddressId<A>
234        for AddrSubnet<A, <A::Version as AssignedAddrIpExt>::AssignedWitness>
235    where
236        A::Version: AssignedAddrIpExt,
237    {
238        type Weak = FakeWeakAddressId<Self>;
239
240        fn downgrade(&self) -> Self::Weak {
241            FakeWeakAddressId(self.clone())
242        }
243
244        fn addr(&self) -> IpDeviceAddr<A> {
245            #[derive(GenericOverIp)]
246            #[generic_over_ip(I, Ip)]
247            struct WrapIn<I: AssignedAddrIpExt>(I::AssignedWitness);
248            A::Version::map_ip(
249                WrapIn(self.addr()),
250                |WrapIn(v4_addr)| IpDeviceAddr::new_from_witness(v4_addr),
251                |WrapIn(v6_addr)| IpDeviceAddr::new_from_ipv6_device_addr(v6_addr),
252            )
253        }
254
255        fn addr_sub(&self) -> AddrSubnet<A, <A::Version as AssignedAddrIpExt>::AssignedWitness> {
256            self.clone()
257        }
258    }
259
260    impl<I: AssignedAddrIpExt, S, Meta, DeviceId: StrongDeviceIdentifier>
261        IpDeviceAddressIdContext<I> for FakeCoreCtx<S, Meta, DeviceId>
262    {
263        type AddressId = AddrSubnet<I::Addr, I::AssignedWitness>;
264        type WeakAddressId = FakeWeakAddressId<Self::AddressId>;
265    }
266}