netstack3_core/transport.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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
// Copyright 2018 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.
//! The transport layer.
//!
//! # Listeners and connections
//!
//! Some transport layer protocols (notably TCP and UDP) follow a common pattern
//! with respect to registering listeners and connections. There are some
//! subtleties here that are worth pointing out.
//!
//! ## Connections
//!
//! A connection has simpler semantics than a listener. It is bound to a single
//! local address and port and a single remote address and port. By virtue of
//! being bound to a local address, it is also bound to a local interface. This
//! means that, regardless of the entries in the forwarding table, all traffic
//! on that connection will always egress over the same interface. [^1] This
//! also means that, if the interface's address changes, any connections bound
//! to it are severed.
//!
//! ## Listeners
//!
//! A listener, on the other hand, can be bound to any number of local addresses
//! (although it is still always bound to a particular port). From the
//! perspective of this crate, there are two ways of registering a listener:
//! - By specifying one or more local addresses, the listener will be bound to
//! each of those local addresses.
//! - By specifying zero local addresses, the listener will be bound to all
//! addresses. These are referred to in our documentation as "wildcard
//! listeners".
//!
//! The algorithm for figuring out what listener to deliver a packet to is as
//! follows: If there is any listener bound to the specific local address and
//! port addressed in the packet, deliver the packet to that listener.
//! Otherwise, if there is a wildcard listener bound the port addressed in the
//! packet, deliver the packet to that listener. This implies that if a listener
//! is removed which was bound to a particular local address, it can "uncover" a
//! wildcard listener bound to the same port, allowing traffic which would
//! previously have been delivered to the normal listener to now be delivered to
//! the wildcard listener.
//!
//! If desired, clients of this crate can implement a different mechanism for
//! registering listeners on all local addresses - enumerate every local
//! address, and then specify all of the local addresses when registering the
//! listener. This approach will not support shadowing, as a different listener
//! binding to the same port will explicitly conflict with the existing
//! listener, and will thus be rejected. In other words, from the perspective of
//! this crate's API, such listeners will appear like normal listeners that just
//! happen to bind all of the addresses, rather than appearing like wildcard
//! listeners.
//!
//! [^1]: It is an open design question as to whether incoming traffic on the
//! connection will be accepted from a different interface. This is part
//! of the "weak host model" vs "strong host model" discussion.
mod integration;
use derivative::Derivative;
use net_types::ip::{Ip, Ipv4, Ipv6};
use netstack3_base::{HandleableTimer, TimerHandler};
use netstack3_datagram as datagram;
use netstack3_device::WeakDeviceId;
use netstack3_icmp_echo::IcmpSockets;
use netstack3_tcp::{self as tcp, TcpCounters, TcpState, TcpTimerId};
use netstack3_udp::{UdpCounters, UdpState, UdpStateBuilder};
use crate::{BindingsContext, BindingsTypes};
/// A builder for transport layer state.
#[derive(Default, Clone)]
pub struct TransportStateBuilder {
udp: UdpStateBuilder,
}
impl TransportStateBuilder {
/// Get the builder for the UDP state.
pub fn udp_builder(&mut self) -> &mut UdpStateBuilder {
&mut self.udp
}
pub(crate) fn build_with_ctx<BC: BindingsContext>(
self,
bindings_ctx: &mut BC,
) -> TransportLayerState<BC> {
let now = bindings_ctx.now();
let mut rng = bindings_ctx.rng();
TransportLayerState {
udpv4: self.udp.clone().build(),
udpv6: self.udp.build(),
tcpv4: TcpState::new(now, &mut rng),
tcpv6: TcpState::new(now, &mut rng),
icmp_echo_v4: Default::default(),
icmp_echo_v6: Default::default(),
}
}
}
/// The state associated with the transport layer.
pub struct TransportLayerState<BT: BindingsTypes> {
udpv4: UdpState<Ipv4, WeakDeviceId<BT>, BT>,
udpv6: UdpState<Ipv6, WeakDeviceId<BT>, BT>,
tcpv4: TcpState<Ipv4, WeakDeviceId<BT>, BT>,
tcpv6: TcpState<Ipv6, WeakDeviceId<BT>, BT>,
icmp_echo_v4: IcmpSockets<Ipv4, WeakDeviceId<BT>, BT>,
icmp_echo_v6: IcmpSockets<Ipv6, WeakDeviceId<BT>, BT>,
}
impl<BT: BindingsTypes> TransportLayerState<BT> {
fn tcp_state<I: tcp::DualStackIpExt>(&self) -> &TcpState<I, WeakDeviceId<BT>, BT> {
I::map_ip((), |()| &self.tcpv4, |()| &self.tcpv6)
}
fn udp_state<I: datagram::IpExt>(&self) -> &UdpState<I, WeakDeviceId<BT>, BT> {
I::map_ip((), |()| &self.udpv4, |()| &self.udpv6)
}
pub(crate) fn icmp_echo_state<I: datagram::IpExt>(
&self,
) -> &IcmpSockets<I, WeakDeviceId<BT>, BT> {
I::map_ip((), |()| &self.icmp_echo_v4, |()| &self.icmp_echo_v6)
}
pub(crate) fn udp_counters<I: Ip>(&self) -> &UdpCounters<I> {
I::map_ip((), |()| &self.udpv4.counters, |()| &self.udpv6.counters)
}
pub(crate) fn tcp_counters<I: Ip>(&self) -> &TcpCounters<I> {
I::map_ip((), |()| &self.tcpv4.counters, |()| &self.tcpv6.counters)
}
}
/// The identifier for timer events in the transport layer.
#[derive(Derivative)]
#[derivative(
Clone(bound = ""),
Eq(bound = ""),
PartialEq(bound = ""),
Hash(bound = ""),
Debug(bound = "")
)]
pub(crate) enum TransportLayerTimerId<BT: BindingsTypes> {
Tcp(TcpTimerId<WeakDeviceId<BT>, BT>),
}
impl<CC, BT> HandleableTimer<CC, BT> for TransportLayerTimerId<BT>
where
BT: BindingsTypes,
CC: TimerHandler<BT, TcpTimerId<WeakDeviceId<BT>, BT>>,
{
fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BT, timer: BT::UniqueTimerId) {
match self {
TransportLayerTimerId::Tcp(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
}
}
}
impl<BT: BindingsTypes> From<TcpTimerId<WeakDeviceId<BT>, BT>> for TransportLayerTimerId<BT> {
fn from(id: TcpTimerId<WeakDeviceId<BT>, BT>) -> Self {
TransportLayerTimerId::Tcp(id)
}
}