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.
45//! Provides common SAS (Source Address Selection) implementations.
67use net_types::ip::{Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
8use net_types::SpecifiedAddr;
9use netstack3_base::{IpAddressId, IpDeviceAddr, IpDeviceAddressIdContext};
1011use 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};
1617/// 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`.
27fn get_local_addr_for_remote(
28&mut self,
29 device_id: &Self::DeviceId,
30 remote: Option<SpecifiedAddr<I::Addr>>,
31 ) -> Option<IpDeviceAddr<I::Addr>> {
32self.get_local_addr_id_for_remote(device_id, remote).map(|id| id.addr())
33 }
3435/// Returns a strongly-held reference to the best local address on `device_id`
36 /// for communicating with `remote`.
37fn 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}
4344impl<CC, BT> IpSasHandler<Ipv4, BT> for CC
45where
46CC: IpDeviceStateContext<Ipv4, BT>,
47 BT: IpDeviceStateBindingsTypes,
48{
49fn get_local_addr_id_for_remote(
50&mut self,
51 device_id: &Self::DeviceId,
52 _remote: Option<SpecifiedAddr<Ipv4Addr>>,
53 ) -> Option<CC::AddressId> {
54self.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next())
55 }
56}
5758impl<CC, BT> IpSasHandler<Ipv6, BT> for CC
59where
60CC: IpDeviceStateContext<Ipv6, BT>,
61 BT: IpDeviceStateBindingsTypes,
62{
63fn get_local_addr_id_for_remote(
64&mut self,
65 device_id: &Self::DeviceId,
66 remote: Option<SpecifiedAddr<Ipv6Addr>>,
67 ) -> Option<CC::AddressId> {
68self.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.
81const 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.
86const ASSUME_TEMPORARY: bool = false;
87let (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}