netstack3_ip/
sas.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Provides common SAS (Source Address Selection) implementations.

use net_types::ip::{Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
use net_types::SpecifiedAddr;
use netstack3_base::{IpAddressId, IpDeviceAddr, IpDeviceAddressIdContext};

use crate::internal::device::state::{
    IpDeviceStateBindingsTypes, Ipv6AddressFlags, Ipv6AddressState,
};
use crate::internal::device::{IpDeviceAddressContext as _, IpDeviceIpExt, IpDeviceStateContext};
use crate::internal::socket::ipv6_source_address_selection::{self, SasCandidate};

/// A handler for Source Address Selection.
///
/// This trait helps implement source address selection for a variety of traits,
/// like [`crate::IpDeviceStateContext`].
///
/// A blanket implementation on IPv4 and IPv6 is provided for all types
/// implementing [`IpDeviceStateContext`].
pub trait IpSasHandler<I: IpDeviceIpExt, BT>: IpDeviceAddressIdContext<I> {
    /// Returns the best local address on `device_id` for communicating with
    /// `remote`.
    fn get_local_addr_for_remote(
        &mut self,
        device_id: &Self::DeviceId,
        remote: Option<SpecifiedAddr<I::Addr>>,
    ) -> Option<IpDeviceAddr<I::Addr>> {
        self.get_local_addr_id_for_remote(device_id, remote).map(|id| id.addr())
    }

    /// Returns a strongly-held reference to the best local address on `device_id`
    /// for communicating with `remote`.
    fn get_local_addr_id_for_remote(
        &mut self,
        device_id: &Self::DeviceId,
        remote: Option<SpecifiedAddr<I::Addr>>,
    ) -> Option<Self::AddressId>;
}

impl<CC, BT> IpSasHandler<Ipv4, BT> for CC
where
    CC: IpDeviceStateContext<Ipv4, BT>,
    BT: IpDeviceStateBindingsTypes,
{
    fn get_local_addr_id_for_remote(
        &mut self,
        device_id: &Self::DeviceId,
        _remote: Option<SpecifiedAddr<Ipv4Addr>>,
    ) -> Option<CC::AddressId> {
        self.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next())
    }
}

impl<CC, BT> IpSasHandler<Ipv6, BT> for CC
where
    CC: IpDeviceStateContext<Ipv6, BT>,
    BT: IpDeviceStateBindingsTypes,
{
    fn get_local_addr_id_for_remote(
        &mut self,
        device_id: &Self::DeviceId,
        remote: Option<SpecifiedAddr<Ipv6Addr>>,
    ) -> Option<CC::AddressId> {
        self.with_address_ids(device_id, |addrs, core_ctx| {
            ipv6_source_address_selection::select_ipv6_source_address(
                remote,
                device_id,
                addrs,
                |addr_id| {
                    core_ctx.with_ip_address_state(
                        device_id,
                        addr_id,
                        |Ipv6AddressState { flags: Ipv6AddressFlags { assigned }, config }| {
                            // Assume an address is deprecated if config is
                            // not available. That means the address is
                            // going away, so we should not prefer it.
                            const ASSUME_DEPRECATED: bool = true;
                            // Assume an address is not temporary if config
                            // is not available. That means the address is
                            // going away and we should remove any
                            // preference on it.
                            const ASSUME_TEMPORARY: bool = false;
                            let (deprecated, temporary) = config
                                .map(|c| (c.is_deprecated(), c.is_temporary()))
                                .unwrap_or((ASSUME_DEPRECATED, ASSUME_TEMPORARY));
                            SasCandidate {
                                addr_sub: addr_id.addr_sub(),
                                assigned: *assigned,
                                temporary,
                                deprecated,
                                device: device_id.clone(),
                            }
                        },
                    )
                },
            )
        })
    }
}