netstack3_ip/
sas.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//! Provides common SAS (Source Address Selection) implementations.
6
7use net_types::ip::{Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
8use net_types::SpecifiedAddr;
9use netstack3_base::{IpAddressId, IpDeviceAddr, IpDeviceAddressIdContext};
10
11use crate::internal::device::state::{
12    IpDeviceStateBindingsTypes, Ipv6AddressFlags, Ipv6AddressState,
13};
14use crate::internal::device::{IpDeviceAddressContext as _, IpDeviceIpExt, IpDeviceStateContext};
15use crate::internal::socket::ipv6_source_address_selection::{self, SasCandidate};
16
17/// A handler for Source Address Selection.
18///
19/// This trait helps implement source address selection for a variety of traits,
20/// like [`crate::IpDeviceStateContext`].
21///
22/// A blanket implementation on IPv4 and IPv6 is provided for all types
23/// implementing [`IpDeviceStateContext`].
24pub trait IpSasHandler<I: IpDeviceIpExt, BT>: IpDeviceAddressIdContext<I> {
25    /// Returns the best local address on `device_id` for communicating with
26    /// `remote`.
27    fn get_local_addr_for_remote(
28        &mut self,
29        device_id: &Self::DeviceId,
30        remote: Option<SpecifiedAddr<I::Addr>>,
31    ) -> Option<IpDeviceAddr<I::Addr>> {
32        self.get_local_addr_id_for_remote(device_id, remote).map(|id| id.addr())
33    }
34
35    /// Returns a strongly-held reference to the best local address on `device_id`
36    /// for communicating with `remote`.
37    fn get_local_addr_id_for_remote(
38        &mut self,
39        device_id: &Self::DeviceId,
40        remote: Option<SpecifiedAddr<I::Addr>>,
41    ) -> Option<Self::AddressId>;
42}
43
44impl<CC, BT> IpSasHandler<Ipv4, BT> for CC
45where
46    CC: IpDeviceStateContext<Ipv4, BT>,
47    BT: IpDeviceStateBindingsTypes,
48{
49    fn get_local_addr_id_for_remote(
50        &mut self,
51        device_id: &Self::DeviceId,
52        _remote: Option<SpecifiedAddr<Ipv4Addr>>,
53    ) -> Option<CC::AddressId> {
54        self.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next())
55    }
56}
57
58impl<CC, BT> IpSasHandler<Ipv6, BT> for CC
59where
60    CC: IpDeviceStateContext<Ipv6, BT>,
61    BT: IpDeviceStateBindingsTypes,
62{
63    fn get_local_addr_id_for_remote(
64        &mut self,
65        device_id: &Self::DeviceId,
66        remote: Option<SpecifiedAddr<Ipv6Addr>>,
67    ) -> Option<CC::AddressId> {
68        self.with_address_ids(device_id, |addrs, core_ctx| {
69            ipv6_source_address_selection::select_ipv6_source_address(
70                remote,
71                device_id,
72                addrs,
73                |addr_id| {
74                    core_ctx.with_ip_address_state(
75                        device_id,
76                        addr_id,
77                        |Ipv6AddressState { flags: Ipv6AddressFlags { assigned }, config }| {
78                            // Assume an address is deprecated if config is
79                            // not available. That means the address is
80                            // going away, so we should not prefer it.
81                            const ASSUME_DEPRECATED: bool = true;
82                            // Assume an address is not temporary if config
83                            // is not available. That means the address is
84                            // going away and we should remove any
85                            // preference on it.
86                            const ASSUME_TEMPORARY: bool = false;
87                            let (deprecated, temporary) = config
88                                .map(|c| (c.is_deprecated(), c.is_temporary()))
89                                .unwrap_or((ASSUME_DEPRECATED, ASSUME_TEMPORARY));
90                            SasCandidate {
91                                addr_sub: addr_id.addr_sub(),
92                                assigned: *assigned,
93                                temporary,
94                                deprecated,
95                                device: device_id.clone(),
96                            }
97                        },
98                    )
99                },
100            )
101        })
102    }
103}