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