Skip to main content

netstack3_ip/
base.rs

1// Copyright 2018 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
5use alloc::boxed::Box;
6use alloc::vec::Vec;
7use core::fmt::Debug;
8use core::hash::Hash;
9use core::marker::PhantomData;
10use core::num::NonZeroU8;
11use core::ops::ControlFlow;
12#[cfg(test)]
13use core::ops::DerefMut;
14use core::sync::atomic::{self, AtomicU16};
15
16use derivative::Derivative;
17use explicit::ResultExt as _;
18use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
19use log::{debug, error, trace};
20use net_types::ip::{
21    GenericOverIp, Ip, IpVersion, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu, Subnet,
22};
23use net_types::{
24    LinkLocalAddress, MulticastAddr, MulticastAddress, NonMappedAddr, NonMulticastAddr,
25    SpecifiedAddr, SpecifiedAddress as _, Witness,
26};
27use netstack3_base::socket::{EitherStack, SocketIpAddr, SocketIpAddrExt as _};
28use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
29use netstack3_base::{
30    AnyDevice, BroadcastIpExt, CoreTimerContext, Counter, CounterCollectionSpec, CounterContext,
31    DeviceIdContext, DeviceIdentifier as _, ErrorAndSerializer, EventContext, GsoInfo,
32    HandleableTimer, InstantContext, InterfaceProperties, IpAddressId, IpDeviceAddr,
33    IpDeviceAddressIdContext, IpExt, LocalFrameDestination, MarkDomain, Marks, Matcher as _,
34    MatcherBindingsTypes, NestedIntoCoreTimerCtx, NetworkParsingContext,
35    NetworkSerializationContext, NotFoundError, PacketType, ResourceCounterContext, RngContext,
36    SendFrameErrorReason, StrongDeviceIdentifier, TimerBindingsTypes, TimerContext, TimerHandler,
37    TxMetadata as _, TxMetadataBindingsTypes, WeakIpAddressId, WrapBroadcastMarker,
38};
39use netstack3_filter::{
40    self as filter, ConnectionDirection, ConntrackConnection, FilterBindingsContext,
41    FilterBindingsTypes, FilterHandler as _, FilterIpContext, FilterIpExt, FilterIpMetadata,
42    FilterIpPacket, FilterPacketMetadata, FilterTimerId, ForwardedPacket, IpPacket, MarkAction,
43    MaybeTransportPacket as _, ProofOfEgressCheck, RejectType, SocketInfo,
44    TransportPacketSerializer, Tuple, WeakConnectionError, WeakConntrackConnection,
45};
46use netstack3_hashmap::HashMap;
47use packet::{
48    Buf, BufferMut, GrowBuffer, LayoutBufferAlloc, NestablePacketBuilder as _, PacketConstraints,
49    ParsablePacket as _, ParseBuffer, ParseBufferMut, ParseMetadata, SerializeError,
50    Serializer as _,
51};
52use packet_formats::error::{Ipv6ParseError, ParseError};
53use packet_formats::ip::{DscpAndEcn, IpPacket as _, IpPacketBuilder as _};
54use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Packet};
55use packet_formats::ipv6::ext_hdrs::Ipv6ExtensionHeader;
56use packet_formats::ipv6::{Ipv6Packet, Ipv6PacketRaw};
57use thiserror::Error;
58use zerocopy::SplitByteSlice;
59
60use crate::internal::counters::{IpCounters, IpCountersIpExt};
61use crate::internal::device::opaque_iid::IidSecret;
62use crate::internal::device::slaac::SlaacCounters;
63use crate::internal::device::state::{
64    IpAddressData, IpAddressFlags, IpDeviceStateBindingsTypes, IpDeviceStateIpExt, WeakAddressId,
65};
66use crate::internal::device::{
67    self, IpDeviceAddressContext, IpDeviceBindingsContext, IpDeviceIpExt, IpDeviceSendContext,
68};
69use crate::internal::fragmentation::{FragmentableIpSerializer, FragmentationIpExt, IpFragmenter};
70use crate::internal::gmp::GmpQueryHandler;
71use crate::internal::gmp::igmp::IgmpCounters;
72use crate::internal::gmp::mld::MldCounters;
73use crate::internal::gso::{
74    GsoError, GsoIpExt, MaybeSegmentableIpSerializer, MaybeSegmentableTransportSerializer,
75};
76use crate::internal::icmp::counters::IcmpCountersIpExt;
77use crate::internal::icmp::{
78    IcmpBindingsTypes, IcmpError, IcmpErrorHandler, IcmpHandlerIpExt, Icmpv4Error, Icmpv4State,
79    Icmpv4StateBuilder, Icmpv6Error, Icmpv6State, Icmpv6StateBuilder,
80};
81use crate::internal::ipv6::Ipv6PacketAction;
82use crate::internal::local_delivery::{
83    IpHeaderInfo, Ipv4HeaderInfo, Ipv6HeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta,
84    TransparentLocalDelivery,
85};
86use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
87use crate::internal::multicast_forwarding::route::{
88    MulticastRouteIpExt, MulticastRouteTarget, MulticastRouteTargets,
89};
90use crate::internal::multicast_forwarding::state::{
91    MulticastForwardingState, MulticastForwardingStateContext,
92};
93use crate::internal::multicast_forwarding::{
94    MulticastForwardingBindingsTypes, MulticastForwardingDeviceContext, MulticastForwardingEvent,
95    MulticastForwardingTimerId,
96};
97use crate::internal::path_mtu::{PmtuBindingsTypes, PmtuCache, PmtuTimerId};
98use crate::internal::raw::counters::RawIpSocketCounters;
99use crate::internal::raw::{RawIpSocketHandler, RawIpSocketMap, RawIpSocketsBindingsTypes};
100use crate::internal::reassembly::{
101    FragmentBindingsTypes, FragmentHandler, FragmentProcessingState, FragmentTimerId,
102    FragmentablePacket, IpPacketFragmentCache, ReassemblyIpExt,
103};
104use crate::internal::routing::rules::{Rule, RuleAction, RuleInput, RulesTable};
105use crate::internal::routing::{
106    IpRoutingBindingsTypes, IpRoutingDeviceContext, NonLocalSrcAddrPolicy, PacketOrigin,
107    RoutingTable,
108};
109use crate::internal::socket::{IpSocketBindingsContext, IpSocketContext, IpSocketHandler};
110use crate::internal::types::{
111    self, Destination, InternalForwarding, NextHop, ResolvedRoute, RoutableIpAddr,
112};
113use crate::internal::{ipv6, multicast_forwarding};
114
115#[cfg(test)]
116mod tests;
117
118/// Default IPv4 TTL.
119pub const DEFAULT_TTL: NonZeroU8 = NonZeroU8::new(64).unwrap();
120
121/// Hop limits for packets sent to multicast and unicast destinations.
122#[derive(Copy, Clone, Debug, Eq, PartialEq)]
123#[allow(missing_docs)]
124pub struct HopLimits {
125    pub unicast: NonZeroU8,
126    pub multicast: NonZeroU8,
127}
128
129/// Default hop limits for sockets.
130pub const DEFAULT_HOP_LIMITS: HopLimits =
131    HopLimits { unicast: DEFAULT_TTL, multicast: NonZeroU8::new(1).unwrap() };
132
133/// The IPv6 subnet that contains all addresses; `::/0`.
134pub const IPV6_DEFAULT_SUBNET: Subnet<Ipv6Addr> = Ipv6::ALL_ADDRS_SUBNET;
135
136/// Sidecar metadata passed along with the packet.
137///
138/// Note: This metadata may be regenerated when packet handling requires
139/// performing multiple actions (e.g. sending the packet out multiple interfaces
140/// as part of multicast forwarding).
141pub struct IpLayerPacketMetadata<
142    I: packet_formats::ip::IpExt,
143    A,
144    BT: FilterBindingsTypes + TxMetadataBindingsTypes,
145> {
146    conntrack_connection_and_direction:
147        Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
148
149    /// Tx metadata associated with this packet.
150    ///
151    /// This may be non-default even in the rx path for looped back packets that
152    /// are still forcing tx frame ownership for sockets.
153    tx_metadata: BT::TxMetadata,
154
155    /// Marks attached to the packet that can be acted upon by routing/filtering.
156    marks: Marks,
157
158    /// Socket info of the associate socket if any.
159    socket_info: Option<SocketInfo>,
160
161    /// GSO metadata if the frame requires transport-layer segmentation (e.g.
162    /// because it was coalesced from multiple segments by GRO, or generated
163    /// locally as a large segment).
164    ///
165    /// Note: This is only for transport-layer segmentation, not IP-layer
166    /// fragmentation of reassembled packets.
167    gso_info: Option<GsoInfo>,
168
169    /// Packet type.
170    packet_type: PacketType,
171
172    #[cfg(debug_assertions)]
173    drop_check: IpLayerPacketMetadataDropCheck,
174}
175
176/// A type that asserts, on drop, that it was intentionally being dropped.
177///
178/// NOTE: Unfortunately, debugging this requires backtraces, since track_caller
179/// won't do what we want (https://github.com/rust-lang/rust/issues/116942).
180/// Since this is only enabled in debug, the assumption is that stacktraces are
181/// enabled.
182#[cfg(debug_assertions)]
183#[derive(Default)]
184struct IpLayerPacketMetadataDropCheck {
185    okay_to_drop: bool,
186}
187
188/// Metadata that is produced and consumed by the IP layer for each packet, but
189/// which also traverses the device layer.
190#[derive(Derivative)]
191#[derivative(Debug(bound = ""))]
192pub struct DeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
193    /// Weak reference to this packet's connection tracking entry, if the packet is
194    /// tracked.
195    ///
196    /// This allows NAT to consistently associate locally-generated, looped-back
197    /// packets with the same connection at every filtering hook even when NAT may
198    /// have been performed on them, causing them to no longer match the original or
199    /// reply tuples of the connection.
200    conntrack_entry: Option<(WeakConntrackConnection, ConnectionDirection)>,
201    /// Tx metadata associated with this packet.
202    ///
203    /// This may be non-default even in the rx path for looped back packets that
204    /// are still forcing tx frame ownership for sockets.
205    tx_metadata: BT::TxMetadata,
206    /// Marks attached to this packet. For all the incoming packets, they are None
207    /// by default but can be changed by a filtering rule.
208    ///
209    /// Note: The marks will be preserved if the packet is being looped back, i.e.,
210    /// the receiver will be able to observe the marks set by the sender. This is
211    /// consistent with Linux behavior.
212    marks: Marks,
213    /// The packet type.
214    ///
215    /// For incoming packets set the value is based on the L2 destination.
216    packet_type: PacketType,
217}
218
219/// The result of splitting metadata for a packet sent as multiple frames via
220/// [`DeviceIpLayerMetadata::split_for_multiple_frames`].
221pub(crate) struct SplitDeviceIpLayerMetadata<BT: TxMetadataBindingsTypes> {
222    pub(crate) primary: DeviceIpLayerMetadata<BT>,
223    pub(crate) secondary: DeviceIpLayerMetadata<BT>,
224}
225
226impl<BT: TxMetadataBindingsTypes> DeviceIpLayerMetadata<BT> {
227    /// Creates a new instance with the specified `tx_metadata` and `marks`.
228    pub fn from_tx_metadata_and_marks(tx_metadata: BT::TxMetadata, marks: Marks) -> Self {
229        Self { conntrack_entry: None, tx_metadata, marks, packet_type: PacketType::Outgoing }
230    }
231
232    /// Creates a new `DeviceIpLayerMetadata` with the specified `packet_type`.
233    pub fn new_for_rx_packet(packet_type: PacketType) -> Self {
234        Self {
235            conntrack_entry: None,
236            tx_metadata: Default::default(),
237            marks: Default::default(),
238            packet_type,
239        }
240    }
241
242    /// Creates an empty [`DeviceIpLayerMetadata`].
243    #[cfg(any(test, feature = "testutils"))]
244    pub fn empty() -> Self {
245        Self {
246            conntrack_entry: None,
247            tx_metadata: Default::default(),
248            marks: Default::default(),
249            packet_type: PacketType::Host,
250        }
251    }
252
253    /// Discards the remaining IP layer information and returns only the tx
254    /// metadata used for buffer ownership.
255    pub fn into_tx_metadata(self) -> BT::TxMetadata {
256        self.tx_metadata
257    }
258
259    /// Creates new IP layer metadata with the marks and packet type.
260    #[cfg(any(test, feature = "testutils"))]
261    pub fn with_marks_and_packet_type(marks: Marks, packet_type: PacketType) -> Self {
262        Self { conntrack_entry: None, tx_metadata: Default::default(), marks, packet_type }
263    }
264
265    /// Splits metadata for a packet that is sent as multiple frames (e.g. due
266    /// to IP fragmentation or GSO segmentation) into
267    /// [`SplitDeviceIpLayerMetadata`].
268    ///
269    /// The `primary` instance retains unique resources (`tx_metadata`), while
270    /// the `secondary` instance receives a copy of shareable metadata
271    /// (`conntrack_entry` and `marks`) with default unique resources.
272    pub(crate) fn split_for_multiple_frames(self) -> SplitDeviceIpLayerMetadata<BT> {
273        let secondary = Self {
274            conntrack_entry: self.conntrack_entry.clone(),
275            // TODO(https://fxbug.dev/391953082): We should penalize sockets via
276            // the tx metadata when a packet is sent as multiple frames instead
277            // of just attaching the ownership to one of them. For now, only the
278            // `primary` instance retains the tx metadata.
279            tx_metadata: Default::default(),
280            marks: self.marks,
281            packet_type: self.packet_type,
282        };
283        SplitDeviceIpLayerMetadata { primary: self, secondary }
284    }
285
286    /// Sets the packet type on this metadata.
287    pub fn set_packet_type(&mut self, packet_type: PacketType) {
288        self.packet_type = packet_type;
289    }
290
291    /// Returns the packet type of this metadata.
292    pub fn packet_type(&self) -> PacketType {
293        self.packet_type
294    }
295}
296
297impl<
298    I: IpLayerIpExt,
299    A: WeakIpAddressId<I::Addr>,
300    BT: FilterBindingsTypes + TxMetadataBindingsTypes,
301> IpLayerPacketMetadata<I, A, BT>
302{
303    pub(crate) fn from_device_ip_layer_metadata<CC, D>(
304        core_ctx: &mut CC,
305        device: &D,
306        metadata: DeviceIpLayerMetadata<BT>,
307        gso_info: Option<GsoInfo>,
308    ) -> Self
309    where
310        CC: ResourceCounterContext<D, IpCounters<I>>,
311    {
312        let DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks, packet_type } = metadata;
313        let conntrack_connection_and_direction = match conntrack_entry
314            .map(|(conn, dir)| conn.into_inner().map(|conn| (conn, dir)))
315            .transpose()
316        {
317            // Either the packet was tracked and we've preserved its conntrack entry across
318            // loopback, or it was untracked and we just stash the `None`.
319            Ok(conn_and_dir) => conn_and_dir,
320            // Conntrack entry was removed from table after packet was enqueued in loopback.
321            Err(WeakConnectionError::EntryRemoved) => None,
322            // Conntrack entry no longer matches the packet (for example, it could be that
323            // this is an IPv6 packet that was modified at the device layer and therefore it
324            // no longer matches its IPv4 conntrack entry).
325            Err(WeakConnectionError::InvalidEntry) => {
326                core_ctx.increment_both(device, |c| &c.invalid_cached_conntrack_entry);
327                None
328            }
329        };
330
331        Self {
332            conntrack_connection_and_direction,
333            tx_metadata,
334            marks,
335            // `tx_metadata` belongs to the sending socket (preserved across
336            // loopback for TX buffer accounting). On ingress, `socket_info` must
337            // only reflect the receiving socket (populated later by early demux).
338            socket_info: None,
339            gso_info,
340            packet_type,
341            #[cfg(debug_assertions)]
342            drop_check: Default::default(),
343        }
344    }
345}
346
347/// The result of splitting metadata for multicast replication via
348/// [`IpLayerPacketMetadata::split_for_multicast`].
349pub(crate) struct SplitMulticastPacketMetadata<I, A, BT>
350where
351    I: packet_formats::ip::IpExt,
352    BT: FilterBindingsTypes + TxMetadataBindingsTypes,
353{
354    pub(crate) primary: IpLayerPacketMetadata<I, A, BT>,
355    pub(crate) secondary: IpLayerPacketMetadata<I, A, BT>,
356}
357
358impl<I: IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
359    IpLayerPacketMetadata<I, A, BT>
360{
361    /// Splits metadata for multicast replication into [`SplitMulticastPacketMetadata`].
362    ///
363    /// The `primary` instance retains unique resources
364    /// (`conntrack_connection_and_direction` and `tx_metadata`), while the
365    /// `secondary` instance receives a copy of shareable metadata (`marks`,
366    /// `socket_info`, and `gso_info`) with default unique resources for
367    /// subsequent replications.
368    pub(crate) fn split_for_multicast(self) -> SplitMulticastPacketMetadata<I, A, BT> {
369        let secondary = Self {
370            conntrack_connection_and_direction: None,
371            tx_metadata: Default::default(),
372            marks: self.marks,
373            socket_info: self.socket_info.clone(),
374            gso_info: self.gso_info,
375            packet_type: self.packet_type,
376            #[cfg(debug_assertions)]
377            drop_check: Default::default(),
378        };
379        SplitMulticastPacketMetadata { primary: self, secondary }
380    }
381
382    pub(crate) fn new_local_tx(
383        tx_metadata: BT::TxMetadata,
384        marks: Marks,
385        gso_info: Option<GsoInfo>,
386    ) -> Self {
387        let socket_info = tx_metadata.socket_info();
388        Self {
389            conntrack_connection_and_direction: None,
390            tx_metadata,
391            marks,
392            socket_info,
393            gso_info,
394            packet_type: PacketType::Outgoing,
395            #[cfg(debug_assertions)]
396            drop_check: Default::default(),
397        }
398    }
399
400    /// Creates a new empty [`IpLayerPacketMetadata`].
401    #[cfg(any(test, feature = "testutils"))]
402    pub fn new_empty() -> Self {
403        Self::new_local_tx(Default::default(), Default::default(), None)
404    }
405
406    pub(crate) fn into_parts(
407        self,
408    ) -> (
409        Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)>,
410        BT::TxMetadata,
411        Marks,
412        Option<SocketInfo>,
413        Option<GsoInfo>,
414        PacketType,
415    ) {
416        let Self {
417            tx_metadata,
418            marks,
419            conntrack_connection_and_direction,
420            socket_info,
421            gso_info,
422            packet_type,
423            #[cfg(debug_assertions)]
424            mut drop_check,
425        } = self;
426        #[cfg(debug_assertions)]
427        {
428            drop_check.okay_to_drop = true;
429        }
430        (conntrack_connection_and_direction, tx_metadata, marks, socket_info, gso_info, packet_type)
431    }
432
433    /// Acknowledge that it's okay to drop this packet metadata.
434    ///
435    /// When compiled with debug assertions, dropping [`IplayerPacketMetadata`]
436    /// will panic if this method has not previously been called.
437    pub(crate) fn acknowledge_drop(self) {
438        #[cfg(debug_assertions)]
439        {
440            let mut this = self;
441            this.drop_check.okay_to_drop = true;
442        }
443    }
444
445    /// Returns the tx metadata associated with this packet.
446    pub(crate) fn tx_metadata(&self) -> &BT::TxMetadata {
447        &self.tx_metadata
448    }
449
450    /// Returns the marks attached to this packet.
451    pub(crate) fn marks(&self) -> &Marks {
452        &self.marks
453    }
454
455    /// Returns the GSO metadata attached to this packet, if any.
456    pub(crate) fn gso_info(&self) -> Option<GsoInfo> {
457        self.gso_info
458    }
459
460    /// Sets the packet type on this metadata.
461    pub fn set_packet_type(&mut self, packet_type: PacketType) {
462        self.packet_type = packet_type;
463    }
464}
465
466#[cfg(debug_assertions)]
467impl Drop for IpLayerPacketMetadataDropCheck {
468    fn drop(&mut self) {
469        if !self.okay_to_drop {
470            panic!(
471                "IpLayerPacketMetadata dropped without acknowledgement.  https://fxbug.dev/334127474"
472            );
473        }
474    }
475}
476
477impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
478    FilterIpMetadata<I, A, BT> for IpLayerPacketMetadata<I, A, BT>
479{
480    fn take_connection_and_direction(
481        &mut self,
482    ) -> Option<(ConntrackConnection<I, A, BT>, ConnectionDirection)> {
483        self.conntrack_connection_and_direction.take()
484    }
485
486    fn replace_connection_and_direction(
487        &mut self,
488        conn: ConntrackConnection<I, A, BT>,
489        direction: ConnectionDirection,
490    ) -> Option<ConntrackConnection<I, A, BT>> {
491        self.conntrack_connection_and_direction.replace((conn, direction)).map(|(conn, _dir)| conn)
492    }
493}
494
495impl<I: packet_formats::ip::IpExt, A, BT: FilterBindingsTypes + TxMetadataBindingsTypes>
496    FilterPacketMetadata for IpLayerPacketMetadata<I, A, BT>
497{
498    fn apply_mark_action(&mut self, domain: MarkDomain, action: MarkAction) {
499        action.apply(self.marks.get_mut(domain))
500    }
501
502    fn socket_info(&self) -> Option<SocketInfo> {
503        self.socket_info.clone()
504    }
505
506    fn marks(&self) -> &Marks {
507        &self.marks
508    }
509
510    fn packet_type(&self) -> PacketType {
511        self.packet_type
512    }
513
514    fn gso_info(&self) -> Option<GsoInfo> {
515        self.gso_info
516    }
517}
518
519/// Send errors observed at or above the IP layer that carry a serializer.
520pub type IpSendFrameError<S> = ErrorAndSerializer<IpSendFrameErrorReason, S>;
521
522/// Send error cause for [`IpSendFrameError`].
523#[derive(Debug, PartialEq)]
524pub enum IpSendFrameErrorReason {
525    /// Error comes from the device layer.
526    Device(SendFrameErrorReason),
527    /// The frame's source or destination address is in the loopback subnet, but
528    /// the target device is not the loopback device.
529    IllegalLoopbackAddress,
530}
531
532impl From<SendFrameErrorReason> for IpSendFrameErrorReason {
533    fn from(value: SendFrameErrorReason) -> Self {
534        Self::Device(value)
535    }
536}
537
538/// The execution context provided by a transport layer protocol to the IP
539/// layer.
540///
541/// An implementation for `()` is provided which indicates that a particular
542/// transport layer protocol is unsupported.
543pub trait IpTransportContext<I, BC, CC>
544where
545    I: IpLayerIpExt,
546    CC: DeviceIdContext<AnyDevice> + ?Sized,
547{
548    /// Type used to identify sockets for early demux.
549    type EarlyDemuxSocket;
550
551    /// Performs early demux.
552    ///
553    /// Tries to match the packet with a connected socket that will receive the
554    /// packet. If a match is found, the socket information is passed to
555    /// `LOCAL_INGRESS` filters. The socket is also passed to
556    /// `receive_ip_packet` to avoid demuxing the packet twice.
557    ///
558    /// The socket may be invalidated if the source address is changed by SNAT.
559    /// In that case, `receive_ip_packet` is called with `early_demux_socket`
560    /// set to `None`.
561    fn early_demux<B: ParseBuffer>(
562        core_ctx: &mut CC,
563        device: &CC::DeviceId,
564        src_ip: I::Addr,
565        dst_ip: I::Addr,
566        buffer: B,
567    ) -> Option<Self::EarlyDemuxSocket>;
568
569    /// Receive an ICMP error message.
570    ///
571    /// All arguments beginning with `original_` are fields from the IP packet
572    /// that triggered the error. The `original_body` is provided here so that
573    /// the error can be associated with a transport-layer socket. `device`
574    /// identifies the device that received the ICMP error message packet.
575    ///
576    /// While ICMPv4 error messages are supposed to contain the first 8 bytes of
577    /// the body of the offending packet, and ICMPv6 error messages are supposed
578    /// to contain as much of the offending packet as possible without violating
579    /// the IPv6 minimum MTU, the caller does NOT guarantee that either of these
580    /// hold. It is `receive_icmp_error`'s responsibility to handle any length
581    /// of `original_body`, and to perform any necessary validation.
582    fn receive_icmp_error(
583        core_ctx: &mut CC,
584        bindings_ctx: &mut BC,
585        device: &CC::DeviceId,
586        original_src_ip: Option<SpecifiedAddr<I::Addr>>,
587        original_dst_ip: SpecifiedAddr<I::Addr>,
588        original_body: &[u8],
589        err: I::ErrorCode,
590    );
591
592    /// Receive a transport layer packet in an IP packet.
593    ///
594    /// In the event of an unreachable port, `receive_ip_packet` returns the
595    /// buffer in its original state (with the transport packet un-parsed) in
596    /// the `Err` variant.
597    fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
598        core_ctx: &mut CC,
599        bindings_ctx: &mut BC,
600        device: &CC::DeviceId,
601        src_ip: I::RecvSrcAddr,
602        dst_ip: SpecifiedAddr<I::Addr>,
603        buffer: B,
604        info: &mut LocalDeliveryPacketInfo<I, H>,
605        early_demux_socket: Option<Self::EarlyDemuxSocket>,
606    ) -> Result<(), (B, I::IcmpError)>;
607}
608
609/// The base execution context provided by the IP layer to transport layer
610/// protocols.
611pub trait BaseTransportIpContext<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
612    /// The iterator given to
613    /// [`BaseTransportIpContext::with_devices_with_assigned_addr`].
614    type DevicesWithAddrIter<'s>: Iterator<Item = Self::DeviceId>;
615
616    /// Is this one of our local addresses, and is it in the assigned state?
617    ///
618    /// Calls `cb` with an iterator over all the local interfaces for which
619    /// `addr` is an associated address, and, for IPv6, for which it is in the
620    /// "assigned" state.
621    fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
622        &mut self,
623        addr: SpecifiedAddr<I::Addr>,
624        cb: F,
625    ) -> O;
626
627    /// Get default hop limits.
628    ///
629    /// If `device` is not `None` and exists, its hop limits will be returned.
630    /// Otherwise the system defaults are returned.
631    fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits;
632
633    /// Gets the original destination for the tracked connection indexed by
634    /// `tuple`, which includes the source and destination addresses and
635    /// transport-layer ports as well as the transport protocol number.
636    fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)>;
637}
638
639/// A marker trait for the traits required by the transport layer from the IP
640/// layer.
641pub trait TransportIpContext<I: IpExt + FilterIpExt, BC: TxMetadataBindingsTypes>:
642    BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>
643{
644}
645
646impl<I, CC, BC> TransportIpContext<I, BC> for CC
647where
648    I: IpExt + FilterIpExt,
649    CC: BaseTransportIpContext<I, BC> + IpSocketHandler<I, BC>,
650    BC: TxMetadataBindingsTypes,
651{
652}
653
654/// Abstraction over the ability to join and leave multicast groups.
655pub trait MulticastMembershipHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
656    /// Requests that the specified device join the given multicast group.
657    ///
658    /// If this method is called multiple times with the same device and
659    /// address, the device will remain joined to the multicast group until
660    /// [`MulticastTransportIpContext::leave_multicast_group`] has been called
661    /// the same number of times.
662    fn join_multicast_group(
663        &mut self,
664        bindings_ctx: &mut BC,
665        device: &Self::DeviceId,
666        addr: MulticastAddr<I::Addr>,
667    );
668
669    /// Requests that the specified device leave the given multicast group.
670    ///
671    /// Each call to this method must correspond to an earlier call to
672    /// [`MulticastTransportIpContext::join_multicast_group`]. The device
673    /// remains a member of the multicast group so long as some call to
674    /// `join_multicast_group` has been made without a corresponding call to
675    /// `leave_multicast_group`.
676    fn leave_multicast_group(
677        &mut self,
678        bindings_ctx: &mut BC,
679        device: &Self::DeviceId,
680        addr: MulticastAddr<I::Addr>,
681    );
682
683    /// Selects a default device with which to join the given multicast group.
684    ///
685    /// The selection is made by consulting the routing table; If there is no
686    /// route available to the given address, an error is returned.
687    fn select_device_for_multicast_group(
688        &mut self,
689        addr: MulticastAddr<I::Addr>,
690        marks: &Marks,
691    ) -> Result<Self::DeviceId, ResolveRouteError>;
692}
693
694// TODO(joshlf): With all 256 protocol numbers (minus reserved ones) given their
695// own associated type in both traits, running `cargo check` on a 2018 MacBook
696// Pro takes over a minute. Eventually - and before we formally publish this as
697// a library - we should identify the bottleneck in the compiler and optimize
698// it. For the time being, however, we only support protocol numbers that we
699// actually use (TCP and UDP).
700
701/// Enables a blanket implementation of [`TransportIpContext`].
702///
703/// Implementing this marker trait for a type enables a blanket implementation
704/// of `TransportIpContext` given the other requirements are met.
705pub trait UseTransportIpContextBlanket {}
706
707/// An iterator supporting the blanket implementation of
708/// [`BaseTransportIpContext::with_devices_with_assigned_addr`].
709pub struct AssignedAddressDeviceIterator<Iter, I, D>(Iter, PhantomData<(I, D)>);
710
711impl<Iter, I, D> Iterator for AssignedAddressDeviceIterator<Iter, I, D>
712where
713    Iter: Iterator<Item = (D, I::AddressStatus)>,
714    I: IpLayerIpExt,
715{
716    type Item = D;
717    fn next(&mut self) -> Option<D> {
718        let Self(iter, PhantomData) = self;
719        iter.by_ref().find_map(|(device, state)| is_unicast_assigned::<I>(&state).then_some(device))
720    }
721}
722
723impl<
724    I: IpLayerIpExt,
725    BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + IpRoutingBindingsTypes,
726    CC: IpDeviceContext<I>
727        + IpSocketHandler<I, BC>
728        + IpStateContext<I, BC>
729        + FilterIpContext<I, BC>
730        + UseTransportIpContextBlanket,
731> BaseTransportIpContext<I, BC> for CC
732{
733    type DevicesWithAddrIter<'s> =
734        AssignedAddressDeviceIterator<CC::DeviceAndAddressStatusIter<'s>, I, CC::DeviceId>;
735
736    fn with_devices_with_assigned_addr<O, F: FnOnce(Self::DevicesWithAddrIter<'_>) -> O>(
737        &mut self,
738        addr: SpecifiedAddr<I::Addr>,
739        cb: F,
740    ) -> O {
741        self.with_address_statuses(addr, |it| cb(AssignedAddressDeviceIterator(it, PhantomData)))
742    }
743
744    fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
745        match device {
746            Some(device) => HopLimits {
747                unicast: IpDeviceEgressStateContext::<I>::get_hop_limit(self, device),
748                ..DEFAULT_HOP_LIMITS
749            },
750            None => DEFAULT_HOP_LIMITS,
751        }
752    }
753
754    fn get_original_destination(&mut self, tuple: &Tuple<I>) -> Option<(I::Addr, u16)> {
755        self.with_filter_state(|state| {
756            let conn = state.conntrack.get_connection(&tuple)?;
757
758            if !conn.destination_nat() {
759                return None;
760            }
761
762            // The tuple marking the original direction of the connection is
763            // never modified by NAT. This means it can be used to recover the
764            // destination before NAT was performed.
765            let original = conn.original_tuple();
766            Some((original.dst_addr, original.transport.dst_port_or_id()))
767        })
768    }
769}
770
771/// The status of an IP address on an interface.
772#[derive(Debug, PartialEq)]
773#[allow(missing_docs)]
774pub enum AddressStatus<S> {
775    Present(S),
776    Unassigned,
777}
778
779impl<S> AddressStatus<S> {
780    fn into_present(self) -> Option<S> {
781        match self {
782            Self::Present(s) => Some(s),
783            Self::Unassigned => None,
784        }
785    }
786}
787
788impl AddressStatus<Ipv4PresentAddressStatus> {
789    /// Creates an IPv4 `AddressStatus` for `addr` on `device`.
790    pub fn from_context_addr_v4<
791        BC: IpDeviceStateBindingsTypes,
792        CC: device::IpDeviceStateContext<Ipv4, BC> + GmpQueryHandler<Ipv4, BC>,
793    >(
794        core_ctx: &mut CC,
795        device: &CC::DeviceId,
796        addr: SpecifiedAddr<Ipv4Addr>,
797    ) -> AddressStatus<Ipv4PresentAddressStatus> {
798        if addr.is_limited_broadcast() {
799            return AddressStatus::Present(Ipv4PresentAddressStatus::LimitedBroadcast);
800        }
801
802        if MulticastAddr::new(addr.get())
803            .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
804        {
805            return AddressStatus::Present(Ipv4PresentAddressStatus::Multicast);
806        }
807
808        core_ctx.with_address_ids(device, |mut addrs, core_ctx| {
809            addrs
810                .find_map(|addr_id| {
811                    let dev_addr = addr_id.addr_sub();
812                    let (dev_addr, subnet) = dev_addr.addr_subnet();
813
814                    if **dev_addr == addr {
815                        let assigned = core_ctx.with_ip_address_data(
816                            device,
817                            &addr_id,
818                            |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
819                                *assigned
820                            },
821                        );
822
823                        if assigned {
824                            Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastAssigned))
825                        } else {
826                            Some(AddressStatus::Present(Ipv4PresentAddressStatus::UnicastTentative))
827                        }
828                    } else if addr.get() == subnet.broadcast() {
829                        Some(AddressStatus::Present(Ipv4PresentAddressStatus::SubnetBroadcast))
830                    } else if device.is_loopback() && subnet.contains(addr.as_ref()) {
831                        Some(AddressStatus::Present(Ipv4PresentAddressStatus::LoopbackSubnet))
832                    } else {
833                        None
834                    }
835                })
836                .unwrap_or(AddressStatus::Unassigned)
837        })
838    }
839}
840
841impl AddressStatus<Ipv6PresentAddressStatus> {
842    /// /// Creates an IPv6 `AddressStatus` for `addr` on `device`.
843    pub fn from_context_addr_v6<
844        BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
845        CC: device::Ipv6DeviceContext<BC> + GmpQueryHandler<Ipv6, BC>,
846    >(
847        core_ctx: &mut CC,
848        device: &CC::DeviceId,
849        addr: SpecifiedAddr<Ipv6Addr>,
850    ) -> AddressStatus<Ipv6PresentAddressStatus> {
851        if MulticastAddr::new(addr.get())
852            .is_some_and(|addr| GmpQueryHandler::gmp_is_in_group(core_ctx, device, addr))
853        {
854            return AddressStatus::Present(Ipv6PresentAddressStatus::Multicast);
855        }
856
857        let addr_id = match core_ctx.get_address_id(device, addr) {
858            Ok(o) => o,
859            Err(NotFoundError) => return AddressStatus::Unassigned,
860        };
861
862        let assigned = core_ctx.with_ip_address_data(
863            device,
864            &addr_id,
865            |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
866        );
867
868        if assigned {
869            AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned)
870        } else {
871            AddressStatus::Present(Ipv6PresentAddressStatus::UnicastTentative)
872        }
873    }
874}
875
876impl<S: GenericOverIp<I>, I: Ip> GenericOverIp<I> for AddressStatus<S> {
877    type Type = AddressStatus<S::Type>;
878}
879
880/// The status of an IPv4 address.
881#[derive(Debug, PartialEq)]
882#[allow(missing_docs)]
883pub enum Ipv4PresentAddressStatus {
884    LimitedBroadcast,
885    SubnetBroadcast,
886    Multicast,
887    UnicastAssigned,
888    UnicastTentative,
889    /// This status indicates that the queried device was Loopback. The address
890    /// belongs to a subnet that is assigned to the interface. This status
891    /// takes lower precedence than `Unicast` and `SubnetBroadcast``, E.g. if
892    /// the loopback device is assigned `127.0.0.1/8`:
893    ///   * address `127.0.0.1` -> `Unicast`
894    ///   * address `127.0.0.2` -> `LoopbackSubnet`
895    ///   * address `127.255.255.255` -> `SubnetBroadcast`
896    /// This exists for Linux conformance, which on the Loopback device,
897    /// considers an IPv4 address assigned if it belongs to one of the device's
898    /// assigned subnets.
899    LoopbackSubnet,
900}
901
902impl Ipv4PresentAddressStatus {
903    fn to_broadcast_marker(&self) -> Option<<Ipv4 as BroadcastIpExt>::BroadcastMarker> {
904        match self {
905            Self::LimitedBroadcast | Self::SubnetBroadcast => Some(()),
906            Self::Multicast
907            | Self::UnicastAssigned
908            | Self::UnicastTentative
909            | Self::LoopbackSubnet => None,
910        }
911    }
912}
913
914/// The status of an IPv6 address.
915#[derive(Debug, PartialEq)]
916#[allow(missing_docs)]
917pub enum Ipv6PresentAddressStatus {
918    Multicast,
919    UnicastAssigned,
920    UnicastTentative,
921}
922
923/// An extension trait providing IP layer properties.
924pub trait IpLayerIpExt:
925    IpExt
926    + MulticastRouteIpExt
927    + IcmpHandlerIpExt
928    + FilterIpExt
929    + FragmentationIpExt
930    + GsoIpExt
931    + IpDeviceIpExt
932    + IpCountersIpExt
933    + IcmpCountersIpExt
934    + ReassemblyIpExt
935{
936    /// IP Address status.
937    type AddressStatus: Debug;
938    /// IP Address state.
939    type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>: AsRef<
940        IpStateInner<Self, StrongDeviceId, BT>,
941    >;
942    /// State kept for packet identifiers.
943    type PacketIdState;
944    /// The type of a single packet identifier.
945    type PacketId;
946    /// Produces the next packet ID from the state.
947    fn next_packet_id_from_state(state: &Self::PacketIdState) -> Self::PacketId;
948}
949
950impl IpLayerIpExt for Ipv4 {
951    type AddressStatus = Ipv4PresentAddressStatus;
952    type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
953        Ipv4State<StrongDeviceId, BT>;
954    type PacketIdState = AtomicU16;
955    type PacketId = u16;
956    fn next_packet_id_from_state(next_packet_id: &Self::PacketIdState) -> Self::PacketId {
957        // Relaxed ordering as we only need atomicity without synchronization. See
958        // https://en.cppreference.com/w/cpp/atomic/memory_order#Relaxed_ordering
959        // for more details.
960        next_packet_id.fetch_add(1, atomic::Ordering::Relaxed)
961    }
962}
963
964impl IpLayerIpExt for Ipv6 {
965    type AddressStatus = Ipv6PresentAddressStatus;
966    type State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> =
967        Ipv6State<StrongDeviceId, BT>;
968    type PacketIdState = ();
969    type PacketId = ();
970    fn next_packet_id_from_state((): &Self::PacketIdState) -> Self::PacketId {
971        ()
972    }
973}
974
975/// The state context provided to the IP layer.
976pub trait IpStateContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes + MatcherBindingsTypes>:
977    IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>
978{
979    /// The context that provides access to the IP routing tables.
980    type IpRouteTablesCtx<'a>: IpRouteTablesContext<I, BT, DeviceId = Self::DeviceId>;
981
982    /// Gets an immutable reference to the rules table.
983    fn with_rules_table<
984        O,
985        F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId, BT>) -> O,
986    >(
987        &mut self,
988        cb: F,
989    ) -> O;
990
991    /// Gets a mutable reference to the rules table.
992    fn with_rules_table_mut<
993        O,
994        F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId, BT>) -> O,
995    >(
996        &mut self,
997        cb: F,
998    ) -> O;
999}
1000
1001/// The state context that gives access to routing tables provided to the IP layer.
1002pub trait IpRouteTablesContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
1003    IpRouteTableContext<I, BT> + IpDeviceContext<I>
1004{
1005    /// The inner context that can provide access to individual routing tables.
1006    type Ctx<'a>: IpRouteTableContext<I, BT, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
1007
1008    /// Gets the main table ID.
1009    fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId, BT>;
1010
1011    /// Gets immutable access to all the routing tables that currently exist.
1012    fn with_ip_routing_tables<
1013        O,
1014        F: FnOnce(
1015            &mut Self::Ctx<'_>,
1016            &HashMap<
1017                RoutingTableId<I, Self::DeviceId, BT>,
1018                PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
1019            >,
1020        ) -> O,
1021    >(
1022        &mut self,
1023        cb: F,
1024    ) -> O;
1025
1026    /// Gets mutable access to all the routing tables that currently exist.
1027    fn with_ip_routing_tables_mut<
1028        O,
1029        F: FnOnce(
1030            &mut HashMap<
1031                RoutingTableId<I, Self::DeviceId, BT>,
1032                PrimaryRc<BaseRoutingTableState<I, Self::DeviceId, BT>>,
1033            >,
1034        ) -> O,
1035    >(
1036        &mut self,
1037        cb: F,
1038    ) -> O;
1039
1040    // TODO(https://fxbug.dev/354724171): Remove this function when we no longer
1041    // make routing decisions starting from the main table.
1042    /// Calls the function with an immutable reference to IP routing table.
1043    fn with_main_ip_routing_table<
1044        O,
1045        F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
1046    >(
1047        &mut self,
1048        cb: F,
1049    ) -> O {
1050        let main_table_id = self.main_table_id();
1051        self.with_ip_routing_table(&main_table_id, cb)
1052    }
1053
1054    // TODO(https://fxbug.dev/341194323): Remove this function when we no longer
1055    // only update the main routing table by default.
1056    /// Calls the function with a mutable reference to IP routing table.
1057    fn with_main_ip_routing_table_mut<
1058        O,
1059        F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
1060    >(
1061        &mut self,
1062        cb: F,
1063    ) -> O {
1064        let main_table_id = self.main_table_id();
1065        self.with_ip_routing_table_mut(&main_table_id, cb)
1066    }
1067}
1068
1069/// The state context that gives access to a singular routing table.
1070pub trait IpRouteTableContext<I: IpLayerIpExt, BT: IpRoutingBindingsTypes>:
1071    IpDeviceContext<I>
1072{
1073    /// The inner device id context.
1074    type IpDeviceIdCtx<'a>: DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
1075        + IpRoutingDeviceContext<I>
1076        + IpDeviceContext<I>;
1077
1078    /// Calls the function with an immutable reference to IP routing table.
1079    fn with_ip_routing_table<
1080        O,
1081        F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
1082    >(
1083        &mut self,
1084        table_id: &RoutingTableId<I, Self::DeviceId, BT>,
1085        cb: F,
1086    ) -> O;
1087
1088    /// Calls the function with a mutable reference to IP routing table.
1089    fn with_ip_routing_table_mut<
1090        O,
1091        F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
1092    >(
1093        &mut self,
1094        table_id: &RoutingTableId<I, Self::DeviceId, BT>,
1095        cb: F,
1096    ) -> O;
1097}
1098
1099/// Provides access to an IP device's state for IP layer egress.
1100pub trait IpDeviceEgressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
1101    /// Calls the callback with the next packet ID.
1102    fn with_next_packet_id<O, F: FnOnce(&I::PacketIdState) -> O>(&self, cb: F) -> O;
1103
1104    /// Returns the best local address for communicating with the remote.
1105    fn get_local_addr_for_remote(
1106        &mut self,
1107        device_id: &Self::DeviceId,
1108        remote: Option<SpecifiedAddr<I::Addr>>,
1109    ) -> Option<IpDeviceAddr<I::Addr>>;
1110
1111    /// Returns the hop limit.
1112    fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8;
1113}
1114
1115/// Provides access to an IP device's state for IP layer ingress.
1116pub trait IpDeviceIngressStateContext<I: IpLayerIpExt>: DeviceIdContext<AnyDevice> {
1117    /// Gets the status of an address.
1118    ///
1119    /// Only the specified device will be checked for the address. Returns
1120    /// [`AddressStatus::Unassigned`] if the address is not assigned to the
1121    /// device.
1122    fn address_status_for_device(
1123        &mut self,
1124        addr: SpecifiedAddr<I::Addr>,
1125        device_id: &Self::DeviceId,
1126    ) -> AddressStatus<I::AddressStatus>;
1127}
1128
1129/// The IP device context provided to the IP layer.
1130pub trait IpDeviceContext<I: IpLayerIpExt>:
1131    IpDeviceEgressStateContext<I> + IpDeviceIngressStateContext<I>
1132{
1133    /// Is the device enabled?
1134    fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1135
1136    /// The iterator provided to [`IpDeviceContext::with_address_statuses`].
1137    type DeviceAndAddressStatusIter<'a>: Iterator<Item = (Self::DeviceId, I::AddressStatus)>;
1138
1139    /// Provides access to the status of an address.
1140    ///
1141    /// Calls the provided callback with an iterator over the devices for which
1142    /// the address is assigned and the status of the assignment for each
1143    /// device.
1144    fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
1145        &mut self,
1146        addr: SpecifiedAddr<I::Addr>,
1147        cb: F,
1148    ) -> R;
1149
1150    /// Returns true iff the device has unicast forwarding enabled.
1151    fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool;
1152}
1153
1154/// Provides the ability to check neighbor reachability via a specific device.
1155pub trait IpDeviceConfirmReachableContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1156    /// Confirm transport-layer forward reachability to the specified neighbor
1157    /// through the specified device.
1158    fn confirm_reachable(
1159        &mut self,
1160        bindings_ctx: &mut BC,
1161        device: &Self::DeviceId,
1162        neighbor: SpecifiedAddr<I::Addr>,
1163    );
1164}
1165
1166/// Provides access to an IP device's MTU for the IP layer.
1167pub trait IpDeviceMtuContext<I: Ip>: DeviceIdContext<AnyDevice> {
1168    /// Returns the MTU of the device.
1169    ///
1170    /// The MTU is the maximum size of an IP packet.
1171    fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu;
1172}
1173
1174/// Events observed at the IP layer.
1175#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
1176#[generic_over_ip(I, Ip)]
1177pub enum IpLayerEvent<DeviceId, I: IpLayerIpExt> {
1178    /// A route needs to be added.
1179    AddRoute(types::AddableEntry<I::Addr, DeviceId>),
1180    /// Routes matching these specifiers need to be removed.
1181    RemoveRoutes {
1182        /// Destination subnet
1183        subnet: Subnet<I::Addr>,
1184        /// Outgoing interface
1185        device: DeviceId,
1186        /// Gateway/next-hop
1187        gateway: Option<SpecifiedAddr<I::Addr>>,
1188    },
1189    /// The multicast forwarding engine emitted an event.
1190    MulticastForwarding(MulticastForwardingEvent<I, DeviceId>),
1191}
1192
1193impl<DeviceId, I: IpLayerIpExt> From<MulticastForwardingEvent<I, DeviceId>>
1194    for IpLayerEvent<DeviceId, I>
1195{
1196    fn from(event: MulticastForwardingEvent<I, DeviceId>) -> IpLayerEvent<DeviceId, I> {
1197        IpLayerEvent::MulticastForwarding(event)
1198    }
1199}
1200
1201impl<DeviceId, I: IpLayerIpExt> IpLayerEvent<DeviceId, I> {
1202    /// Changes the device id type with `map`.
1203    pub fn map_device<N, F: Fn(DeviceId) -> N>(self, map: F) -> IpLayerEvent<N, I> {
1204        match self {
1205            IpLayerEvent::AddRoute(types::AddableEntry {
1206                subnet,
1207                device,
1208                gateway,
1209                metric,
1210                route_preference,
1211            }) => IpLayerEvent::AddRoute(types::AddableEntry {
1212                subnet,
1213                device: map(device),
1214                gateway,
1215                metric,
1216                route_preference,
1217            }),
1218            IpLayerEvent::RemoveRoutes { subnet, device, gateway } => {
1219                IpLayerEvent::RemoveRoutes { subnet, device: map(device), gateway }
1220            }
1221            IpLayerEvent::MulticastForwarding(e) => {
1222                IpLayerEvent::MulticastForwarding(e.map_device(map))
1223            }
1224        }
1225    }
1226}
1227
1228/// An event signifying a router advertisement has been received.
1229#[derive(Derivative, PartialEq, Eq, Clone, Hash)]
1230#[derivative(Debug)]
1231pub struct RouterAdvertisementEvent<D> {
1232    /// The raw bytes of the router advertisement message's options.
1233    // NB: avoid deriving Debug for this since it could contain PII.
1234    #[derivative(Debug = "ignore")]
1235    pub options_bytes: Box<[u8]>,
1236    /// The source address of the RA message.
1237    pub source: net_types::ip::Ipv6Addr,
1238    /// The device on which the message was received.
1239    pub device: D,
1240}
1241
1242impl<D> RouterAdvertisementEvent<D> {
1243    /// Maps the contained device ID type.
1244    pub fn map_device<N, F: Fn(D) -> N>(self, map: F) -> RouterAdvertisementEvent<N> {
1245        let Self { options_bytes, source, device } = self;
1246        RouterAdvertisementEvent { options_bytes, source, device: map(device) }
1247    }
1248}
1249
1250/// Ipv6-specific bindings execution context for the IP layer.
1251pub trait NdpBindingsContext<DeviceId>: EventContext<RouterAdvertisementEvent<DeviceId>> {}
1252impl<DeviceId, BC: EventContext<RouterAdvertisementEvent<DeviceId>>> NdpBindingsContext<DeviceId>
1253    for BC
1254{
1255}
1256
1257/// Defines how socket marks should be handled by the IP layer.
1258pub trait MarksBindingsContext {
1259    /// Mark domains for marks that should be kept when an egress packet is
1260    /// passed from the IP layer to the device. For egress packets that are
1261    /// delivered locally through the loopback interface, these marks are
1262    /// passed to the ingress path and can be observed by ingress filter hooks.
1263    fn marks_to_keep_on_egress() -> &'static [MarkDomain];
1264
1265    /// Mark domains for marks that should be copied to ingress packets. If
1266    /// early demux results in a socket then these marks are copied from the
1267    /// socket to the packet and can be observed in `LOCAL_INGRESS` filter
1268    /// hook.
1269    fn marks_to_set_on_ingress() -> &'static [MarkDomain];
1270
1271    /// Returns a copy of `packet_marks` with the mark domains in
1272    /// [`Self::marks_to_set_on_ingress`] overridden from `socket_marks`.
1273    fn update_ingress_marks(mut packet_marks: Marks, socket_marks: &Marks) -> Marks {
1274        for mark in Self::marks_to_set_on_ingress() {
1275            *packet_marks.get_mut(*mark) = *socket_marks.get(*mark);
1276        }
1277        packet_marks
1278    }
1279}
1280
1281/// The bindings execution context for the IP layer.
1282pub trait IpLayerBindingsContext<I: IpLayerIpExt, DeviceId>:
1283    InstantContext
1284    + EventContext<IpLayerEvent<DeviceId, I>>
1285    + FilterBindingsContext<DeviceId>
1286    + TxMetadataBindingsTypes
1287    + IpRoutingBindingsTypes
1288    + MarksBindingsContext
1289{
1290}
1291impl<
1292    I: IpLayerIpExt,
1293    DeviceId,
1294    BC: InstantContext
1295        + EventContext<IpLayerEvent<DeviceId, I>>
1296        + FilterBindingsContext<DeviceId>
1297        + TxMetadataBindingsTypes
1298        + IpRoutingBindingsTypes
1299        + MarksBindingsContext,
1300> IpLayerBindingsContext<I, DeviceId> for BC
1301{
1302}
1303
1304/// A marker trait for bindings types at the IP layer.
1305pub trait IpLayerBindingsTypes:
1306    IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes
1307{
1308}
1309impl<BT: IcmpBindingsTypes + IpStateBindingsTypes + IpRoutingBindingsTypes> IpLayerBindingsTypes
1310    for BT
1311{
1312}
1313
1314/// The execution context for the IP layer.
1315pub trait IpLayerContext<
1316    I: IpLayerIpExt,
1317    BC: IpLayerBindingsContext<I, <Self as DeviceIdContext<AnyDevice>>::DeviceId>,
1318>:
1319    IpStateContext<I, BC>
1320    + IpDeviceContext<I>
1321    + IpDeviceMtuContext<I>
1322    + IpDeviceSendContext<I, BC>
1323    + IcmpErrorHandler<I, BC>
1324    + MulticastForwardingStateContext<I, BC>
1325    + MulticastForwardingDeviceContext<I>
1326    + CounterContext<MulticastForwardingCounters<I>>
1327    + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>
1328{
1329}
1330
1331impl<
1332    I: IpLayerIpExt,
1333    BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
1334    CC: IpStateContext<I, BC>
1335        + IpDeviceContext<I>
1336        + IpDeviceMtuContext<I>
1337        + IpDeviceSendContext<I, BC>
1338        + IcmpErrorHandler<I, BC>
1339        + MulticastForwardingStateContext<I, BC>
1340        + MulticastForwardingDeviceContext<I>
1341        + CounterContext<MulticastForwardingCounters<I>>
1342        + ResourceCounterContext<<Self as DeviceIdContext<AnyDevice>>::DeviceId, IpCounters<I>>,
1343> IpLayerContext<I, BC> for CC
1344{
1345}
1346
1347fn is_unicast_assigned<I: IpLayerIpExt>(status: &I::AddressStatus) -> bool {
1348    #[derive(GenericOverIp)]
1349    #[generic_over_ip(I, Ip)]
1350    struct WrapAddressStatus<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
1351
1352    I::map_ip(
1353        WrapAddressStatus(status),
1354        |WrapAddressStatus(status)| match status {
1355            Ipv4PresentAddressStatus::UnicastAssigned
1356            | Ipv4PresentAddressStatus::LoopbackSubnet => true,
1357            Ipv4PresentAddressStatus::UnicastTentative
1358            | Ipv4PresentAddressStatus::LimitedBroadcast
1359            | Ipv4PresentAddressStatus::SubnetBroadcast
1360            | Ipv4PresentAddressStatus::Multicast => false,
1361        },
1362        |WrapAddressStatus(status)| match status {
1363            Ipv6PresentAddressStatus::UnicastAssigned => true,
1364            Ipv6PresentAddressStatus::Multicast | Ipv6PresentAddressStatus::UnicastTentative => {
1365                false
1366            }
1367        },
1368    )
1369}
1370
1371fn is_local_assigned_address<I: Ip + IpLayerIpExt, CC: IpDeviceIngressStateContext<I>>(
1372    core_ctx: &mut CC,
1373    device: &CC::DeviceId,
1374    addr: IpDeviceAddr<I::Addr>,
1375) -> bool {
1376    match core_ctx.address_status_for_device(addr.into(), device) {
1377        AddressStatus::Present(status) => is_unicast_assigned::<I>(&status),
1378        AddressStatus::Unassigned => false,
1379    }
1380}
1381
1382fn get_device_with_assigned_address<I, CC>(
1383    core_ctx: &mut CC,
1384    addr: IpDeviceAddr<I::Addr>,
1385) -> Option<(CC::DeviceId, I::AddressStatus)>
1386where
1387    I: IpLayerIpExt,
1388    CC: IpDeviceContext<I>,
1389{
1390    core_ctx.with_address_statuses(addr.into(), |mut it| {
1391        it.find_map(|(device, status)| {
1392            is_unicast_assigned::<I>(&status).then_some((device, status))
1393        })
1394    })
1395}
1396
1397// Returns the local IP address to use for sending packets from the
1398// given device to `addr`, restricting to `local_ip` if it is not
1399// `None`.
1400fn get_local_addr<I: Ip + IpLayerIpExt, CC: IpDeviceContext<I>>(
1401    core_ctx: &mut CC,
1402    local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1403    device: &CC::DeviceId,
1404    remote_addr: Option<RoutableIpAddr<I::Addr>>,
1405) -> Result<IpDeviceAddr<I::Addr>, ResolveRouteError> {
1406    match local_ip_and_policy {
1407        Some((local_ip, NonLocalSrcAddrPolicy::Allow)) => Ok(local_ip),
1408        Some((local_ip, NonLocalSrcAddrPolicy::Deny)) => {
1409            is_local_assigned_address(core_ctx, device, local_ip)
1410                .then_some(local_ip)
1411                .ok_or(ResolveRouteError::NoSrcAddr)
1412        }
1413        None => core_ctx
1414            .get_local_addr_for_remote(device, remote_addr.map(Into::into))
1415            .ok_or(ResolveRouteError::NoSrcAddr),
1416    }
1417}
1418
1419/// An error occurred while resolving the route to a destination
1420#[derive(Error, Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
1421#[generic_over_ip()]
1422pub enum ResolveRouteError {
1423    /// A source address could not be selected.
1424    #[error("a source address could not be selected")]
1425    NoSrcAddr,
1426    /// The destination in unreachable.
1427    #[error("no route exists to the destination IP address")]
1428    Unreachable,
1429}
1430
1431/// Like [`get_local_addr`], but willing to forward internally as necessary.
1432fn get_local_addr_with_internal_forwarding<I, CC>(
1433    core_ctx: &mut CC,
1434    local_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1435    device: &CC::DeviceId,
1436    remote_addr: Option<RoutableIpAddr<I::Addr>>,
1437) -> Result<(IpDeviceAddr<I::Addr>, InternalForwarding<CC::DeviceId>), ResolveRouteError>
1438where
1439    I: IpLayerIpExt,
1440    CC: IpDeviceContext<I>,
1441{
1442    match get_local_addr(core_ctx, local_ip_and_policy, device, remote_addr) {
1443        Ok(src_addr) => Ok((src_addr, InternalForwarding::NotUsed)),
1444        Err(e) => {
1445            // If a local_ip was specified, the local_ip is assigned to a
1446            // device, and that device has forwarding enabled, use internal
1447            // forwarding.
1448            //
1449            // This enables a weak host model when the Netstack is configured as
1450            // a router. Conceptually the netstack is forwarding the packet from
1451            // the local IP's device to the output device of the selected route.
1452            if let Some((local_ip, _policy)) = local_ip_and_policy {
1453                if let Some((device, _addr_status)) =
1454                    get_device_with_assigned_address(core_ctx, local_ip)
1455                {
1456                    if core_ctx.is_device_unicast_forwarding_enabled(&device) {
1457                        return Ok((local_ip, InternalForwarding::Used(device)));
1458                    }
1459                }
1460            }
1461            Err(e)
1462        }
1463    }
1464}
1465
1466/// The information about the rule walk in addition to a custom state. This type is introduced so
1467/// that `walk_rules` can be extended later with more information about the walk if needed.
1468#[derive(Debug, PartialEq, Eq)]
1469struct RuleWalkInfo<O> {
1470    /// Whether there is a rule with a source address matcher during the walk.
1471    observed_source_address_matcher: bool,
1472    /// The custom info carried. For example this could be the lookup result from the user provided
1473    /// function.
1474    inner: O,
1475}
1476
1477/// A helper function that traverses through the rules table.
1478///
1479/// To walk through the rules, you need to provide it with an initial value for the loop and a
1480/// callback function that yieds a [`ControlFlow`] result to indicate whether the traversal should
1481/// stop.
1482///
1483/// # Returns
1484///
1485/// - `ControlFlow::Break(RuleAction::Lookup(_))` if we hit a lookup rule and an output is
1486///   yielded from the route table.
1487/// - `ControlFlow::Break(RuleAction::Unreachable)` if we hit an unreachable rule.
1488/// - `ControlFlow::Continue(_)` if we finished walking the rules table without yielding any
1489///   result.
1490fn walk_rules<
1491    I: IpLayerIpExt,
1492    BT: IpRoutingBindingsTypes + MatcherBindingsTypes,
1493    CC: IpRouteTablesContext<I, BT, DeviceId: InterfaceProperties<BT::DeviceClass>>,
1494    O,
1495    State,
1496    F: FnMut(
1497        State,
1498        &mut CC::IpDeviceIdCtx<'_>,
1499        &RoutingTable<I, CC::DeviceId>,
1500    ) -> ControlFlow<O, State>,
1501>(
1502    core_ctx: &mut CC,
1503    rules: &RulesTable<I, CC::DeviceId, BT>,
1504    init: State,
1505    rule_input: &RuleInput<'_, I, CC::DeviceId>,
1506    mut lookup_table: F,
1507) -> ControlFlow<RuleAction<RuleWalkInfo<O>>, RuleWalkInfo<State>> {
1508    rules.iter().try_fold(
1509        RuleWalkInfo { inner: init, observed_source_address_matcher: false },
1510        |RuleWalkInfo { inner: state, observed_source_address_matcher },
1511         Rule { action, matcher }| {
1512            let observed_source_address_matcher =
1513                observed_source_address_matcher || matcher.source_address_matcher.is_some();
1514            if !matcher.matches(rule_input) {
1515                return ControlFlow::Continue(RuleWalkInfo {
1516                    inner: state,
1517                    observed_source_address_matcher,
1518                });
1519            }
1520            match action {
1521                RuleAction::Unreachable => return ControlFlow::Break(RuleAction::Unreachable),
1522                RuleAction::Lookup(table_id) => core_ctx.with_ip_routing_table(
1523                    &table_id,
1524                    |core_ctx, table| match lookup_table(state, core_ctx, table) {
1525                        ControlFlow::Break(out) => {
1526                            ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1527                                inner: out,
1528                                observed_source_address_matcher,
1529                            }))
1530                        }
1531                        ControlFlow::Continue(state) => ControlFlow::Continue(RuleWalkInfo {
1532                            inner: state,
1533                            observed_source_address_matcher,
1534                        }),
1535                    },
1536                ),
1537            }
1538        },
1539    )
1540}
1541
1542/// Returns the outgoing routing instructions for reaching the given destination.
1543///
1544/// If a `device` is specified, the resolved route is limited to those that
1545/// egress over the device.
1546///
1547/// If `src_ip` is specified the resolved route is limited to those that egress
1548/// over a device with the address assigned.
1549///
1550/// This function should only be used for calculating a route for an outgoing packet
1551/// that is generated by us.
1552pub fn resolve_output_route_to_destination<
1553    I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1554    BC: IpDeviceBindingsContext<I, CC::DeviceId> + IpLayerBindingsContext<I, CC::DeviceId>,
1555    CC: IpStateContext<I, BC> + IpDeviceContext<I> + device::IpDeviceConfigurationContext<I, BC>,
1556>(
1557    core_ctx: &mut CC,
1558    device: Option<&CC::DeviceId>,
1559    src_ip_and_policy: Option<(IpDeviceAddr<I::Addr>, NonLocalSrcAddrPolicy)>,
1560    dst_ip: Option<RoutableIpAddr<I::Addr>>,
1561    marks: &Marks,
1562) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1563    enum LocalDelivery<A, D> {
1564        WeakLoopback { dst_ip: A, device: D },
1565        StrongForDevice(D),
1566    }
1567
1568    // Check if locally destined. If the destination is an address assigned on
1569    // an interface, and an egress interface wasn't specifically selected, route
1570    // via the loopback device. This lets us operate as a strong host when an
1571    // outgoing interface is explicitly requested while still enabling local
1572    // delivery via the loopback interface, which is acting as a weak host. Note
1573    // that if the loopback interface is requested as an outgoing interface,
1574    // route selection is still performed as a strong host! This makes the
1575    // loopback interface behave more like the other interfaces on the system.
1576    //
1577    // TODO(https://fxbug.dev/42065870): Encode the delivery of locally-
1578    // destined packets to loopback in the route table.
1579    //
1580    // TODO(https://fxbug.dev/322539434): Linux is more permissive about
1581    // allowing cross-device local delivery even when SO_BINDTODEVICE or
1582    // link-local addresses are involved, and this behavior may need to be
1583    // emulated.
1584    let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1585        let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1586        match (device, dst_ip) {
1587            (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1588                .then_some(LocalDelivery::StrongForDevice(device.clone())),
1589            (None, Some(dst_ip)) => {
1590                get_device_with_assigned_address(core_ctx, dst_ip).map(
1591                    |(dst_device, _addr_status)| {
1592                        // If either the source or destination addresses needs
1593                        // a zone ID, then use strong host to enforce that the
1594                        // source and destination addresses are assigned to the
1595                        // same interface.
1596                        if src_ip_and_policy
1597                            .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1598                            || dst_ip.as_ref().must_have_zone()
1599                        {
1600                            LocalDelivery::StrongForDevice(dst_device)
1601                        } else {
1602                            LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1603                        }
1604                    },
1605                )
1606            }
1607            (_, None) => None,
1608        }
1609    };
1610
1611    if let Some(local_delivery) = local_delivery_instructions {
1612        let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1613
1614        let (src_addr, dest_device) = match local_delivery {
1615            LocalDelivery::WeakLoopback { dst_ip, device } => {
1616                let src_ip = match src_ip_and_policy {
1617                    Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1618                        let _device = get_device_with_assigned_address(core_ctx, src_ip)
1619                            .ok_or(ResolveRouteError::NoSrcAddr)?;
1620                        src_ip
1621                    }
1622                    Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1623                    None => dst_ip,
1624                };
1625                (src_ip, device)
1626            }
1627            LocalDelivery::StrongForDevice(device) => {
1628                (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1629            }
1630        };
1631        return Ok(ResolvedRoute {
1632            src_addr,
1633            local_delivery_device: Some(dest_device),
1634            device: loopback,
1635            next_hop: NextHop::RemoteAsNeighbor,
1636            internal_forwarding: InternalForwarding::NotUsed,
1637        });
1638    }
1639    let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1640    let rule_input = RuleInput {
1641        packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1642        marks,
1643    };
1644    core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
1645        let mut walk_rules = |rule_input, src_ip_and_policy| {
1646            walk_rules(
1647                core_ctx,
1648                rules,
1649                None, /* first error encountered */
1650                rule_input,
1651                |first_error, core_ctx, table| {
1652                    let mut matching_with_addr = table.lookup_filter_map(
1653                        core_ctx,
1654                        device,
1655                        dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1656                        |core_ctx, d| {
1657                            Some(get_local_addr_with_internal_forwarding(
1658                                core_ctx,
1659                                src_ip_and_policy,
1660                                d,
1661                                dst_ip,
1662                            ))
1663                        },
1664                    );
1665
1666                    let first_error_in_this_table = match matching_with_addr.next() {
1667                        Some((
1668                            Destination { device, next_hop },
1669                            Ok((local_addr, internal_forwarding)),
1670                        )) => {
1671                            return ControlFlow::Break(Ok((
1672                                Destination { device: device.clone(), next_hop },
1673                                local_addr,
1674                                internal_forwarding,
1675                            )));
1676                        }
1677                        Some((_, Err(e))) => e,
1678                        // Note: rule evaluation will continue on to the next rule, if the
1679                        // previous rule was `Lookup` but the table didn't have the route
1680                        // inside of it.
1681                        None => return ControlFlow::Continue(first_error),
1682                    };
1683
1684                    matching_with_addr
1685                        .filter_map(|(destination, local_addr)| {
1686                            // Select successful routes. We ignore later errors
1687                            // since we've already saved the first one.
1688                            local_addr.ok_checked::<ResolveRouteError>().map(
1689                                |(local_addr, internal_forwarding)| {
1690                                    (destination, local_addr, internal_forwarding)
1691                                },
1692                            )
1693                        })
1694                        .next()
1695                        .map_or(
1696                            ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1697                            |(
1698                                Destination { device, next_hop },
1699                                local_addr,
1700                                internal_forwarding,
1701                            )| {
1702                                ControlFlow::Break(Ok((
1703                                    Destination { device: device.clone(), next_hop },
1704                                    local_addr,
1705                                    internal_forwarding,
1706                                )))
1707                            },
1708                        )
1709                },
1710            )
1711        };
1712
1713        let result = match walk_rules(&rule_input, src_ip_and_policy) {
1714            // Only try to resolve a route again if all of the following are true:
1715            // 1. The source address is not provided by the caller.
1716            // 2. A route is successfully resolved so we selected a source address.
1717            // 3. There is a rule with a source address matcher during the resolution.
1718            // The rationale is to make sure the route resolution converges to a sensible route
1719            // after considering the source address we select.
1720            ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1721                inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1722                observed_source_address_matcher: true,
1723            })) if src_ip_and_policy.is_none() => walk_rules(
1724                &RuleInput {
1725                    packet_origin: PacketOrigin::Local {
1726                        bound_address: Some(selected_src_addr.into()),
1727                        bound_device: device,
1728                    },
1729                    marks,
1730                },
1731                Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1732            ),
1733            result => result,
1734        };
1735
1736        match result {
1737            ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1738                inner: result,
1739                observed_source_address_matcher: _,
1740            })) => {
1741                result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1742                    ResolvedRoute {
1743                        src_addr,
1744                        device,
1745                        local_delivery_device: None,
1746                        next_hop,
1747                        internal_forwarding,
1748                    }
1749                })
1750            }
1751            ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1752            ControlFlow::Continue(RuleWalkInfo {
1753                inner: first_error,
1754                observed_source_address_matcher: _,
1755            }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1756        }
1757    })
1758}
1759
1760/// Enables a blanket implementation of [`IpSocketContext`].
1761///
1762/// Implementing this marker trait for a type enables a blanket implementation
1763/// of `IpSocketContext` given the other requirements are met.
1764pub trait UseIpSocketContextBlanket {}
1765
1766impl<I, BC, CC> IpSocketContext<I, BC> for CC
1767where
1768    I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1769    BC: IpDeviceBindingsContext<I, CC::DeviceId>
1770        + IpLayerBindingsContext<I, CC::DeviceId>
1771        + IpSocketBindingsContext<CC::DeviceId>,
1772    CC: IpLayerEgressContext<I, BC>
1773        + IpStateContext<I, BC>
1774        + IpDeviceContext<I>
1775        + IpDeviceConfirmReachableContext<I, BC>
1776        + IpDeviceMtuContext<I>
1777        + device::IpDeviceConfigurationContext<I, BC>
1778        + IcmpErrorHandler<I, BC>
1779        + UseIpSocketContextBlanket,
1780{
1781    fn lookup_route(
1782        &mut self,
1783        _bindings_ctx: &mut BC,
1784        device: Option<&CC::DeviceId>,
1785        local_ip: Option<IpDeviceAddr<I::Addr>>,
1786        addr: RoutableIpAddr<I::Addr>,
1787        transparent: bool,
1788        marks: &Marks,
1789    ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1790        let src_ip_and_policy = local_ip.map(|local_ip| {
1791            (
1792                local_ip,
1793                if transparent {
1794                    NonLocalSrcAddrPolicy::Allow
1795                } else {
1796                    NonLocalSrcAddrPolicy::Deny
1797                },
1798            )
1799        });
1800        let res =
1801            resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1802        trace!(
1803            "lookup_route(\
1804                device={device:?}, \
1805                local_ip={local_ip:?}, \
1806                addr={addr:?}, \
1807                transparent={transparent:?}, \
1808                marks={marks:?}) => {res:?}"
1809        );
1810        res
1811    }
1812
1813    fn send_ip_packet<S>(
1814        &mut self,
1815        bindings_ctx: &mut BC,
1816        meta: SendIpPacketMeta<
1817            I,
1818            &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1819            SpecifiedAddr<I::Addr>,
1820        >,
1821        body: S,
1822        packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1823    ) -> Result<(), IpSendFrameError<S>>
1824    where
1825        S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
1826        S::Buffer: BufferMut,
1827    {
1828        send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1829    }
1830
1831    fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1832        device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1833    }
1834
1835    fn confirm_reachable(
1836        &mut self,
1837        bindings_ctx: &mut BC,
1838        dst: SpecifiedAddr<I::Addr>,
1839        input: RuleInput<'_, I, Self::DeviceId>,
1840    ) {
1841        match lookup_route_table(self, dst.get(), input) {
1842            Some(Destination { next_hop, device }) => {
1843                let neighbor = match next_hop {
1844                    NextHop::RemoteAsNeighbor => dst,
1845                    NextHop::Gateway(gateway) => gateway,
1846                    NextHop::Broadcast(marker) => {
1847                        I::map_ip::<_, ()>(
1848                            WrapBroadcastMarker(marker),
1849                            |WrapBroadcastMarker(())| {
1850                                debug!(
1851                                    "can't confirm {dst:?}@{device:?} as reachable: \
1852                                    dst is a broadcast address"
1853                                );
1854                            },
1855                            |WrapBroadcastMarker(never)| match never {},
1856                        );
1857                        return;
1858                    }
1859                };
1860                IpDeviceConfirmReachableContext::confirm_reachable(
1861                    self,
1862                    bindings_ctx,
1863                    &device,
1864                    neighbor,
1865                );
1866            }
1867            None => {
1868                debug!("can't confirm {dst:?} as reachable: no route");
1869            }
1870        }
1871    }
1872}
1873
1874/// Trait that provides basic socket information for types that carry a socket
1875/// ID.
1876pub trait SocketMetadata<CC>
1877where
1878    CC: ?Sized,
1879{
1880    /// Returns the SocketInfo for the socket.
1881    fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo;
1882    /// Returns Socket Marks.
1883    fn marks(&self, _core_ctx: &mut CC) -> Marks;
1884}
1885
1886impl<T, O, CC> SocketMetadata<CC> for EitherStack<T, O>
1887where
1888    CC: ?Sized,
1889    T: SocketMetadata<CC>,
1890    O: SocketMetadata<CC>,
1891{
1892    fn socket_info(&self, core_ctx: &mut CC) -> SocketInfo {
1893        match self {
1894            Self::ThisStack(t) => t.socket_info(core_ctx),
1895            Self::OtherStack(o) => o.socket_info(core_ctx),
1896        }
1897    }
1898
1899    fn marks(&self, core_ctx: &mut CC) -> Marks {
1900        match self {
1901            Self::ThisStack(t) => t.marks(core_ctx),
1902            Self::OtherStack(o) => o.marks(core_ctx),
1903        }
1904    }
1905}
1906
1907/// The IP context providing dispatch to the available transport protocols.
1908///
1909/// This trait acts like a demux on the transport protocol for ingress IP
1910/// packets.
1911pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1912    /// Early Demux result.
1913    type EarlyDemuxSocket: SocketMetadata<Self>;
1914
1915    /// Performs early demux result.
1916    fn early_demux<B: ParseBuffer>(
1917        &mut self,
1918        device: &Self::DeviceId,
1919        frame_dst: Option<LocalFrameDestination>,
1920        src_ip: I::Addr,
1921        dst_ip: I::Addr,
1922        proto: I::Proto,
1923        body: B,
1924    ) -> Option<Self::EarlyDemuxSocket>;
1925
1926    /// Dispatches a received incoming IP packet to the appropriate protocol.
1927    /// In case of a failure returns the kind of the ICMP error that should be
1928    /// sent back to the source.
1929    fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1930        &mut self,
1931        bindings_ctx: &mut BC,
1932        device: &Self::DeviceId,
1933        src_ip: I::RecvSrcAddr,
1934        dst_ip: SpecifiedAddr<I::Addr>,
1935        proto: I::Proto,
1936        body: B,
1937        info: &mut LocalDeliveryPacketInfo<I, H>,
1938        early_demux_socket: Option<Self::EarlyDemuxSocket>,
1939    ) -> Result<(), I::IcmpError>;
1940}
1941
1942/// A marker trait for all the contexts required for IP ingress.
1943pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1944    IpTransportDispatchContext<
1945        I,
1946        BC,
1947        DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1948    > + IpDeviceIngressStateContext<I>
1949    + IpDeviceMtuContext<I>
1950    + IpDeviceSendContext<I, BC>
1951    + IcmpErrorHandler<I, BC>
1952    + IpLayerContext<I, BC>
1953    + FragmentHandler<I, BC>
1954    + FilterHandlerProvider<I, BC>
1955    + RawIpSocketHandler<I, BC>
1956{
1957}
1958
1959impl<
1960    I: IpLayerIpExt,
1961    BC: IpLayerBindingsContext<I, CC::DeviceId>,
1962    CC: IpTransportDispatchContext<
1963            I,
1964            BC,
1965            DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1966        > + IpDeviceIngressStateContext<I>
1967        + IpDeviceMtuContext<I>
1968        + IpDeviceSendContext<I, BC>
1969        + IcmpErrorHandler<I, BC>
1970        + IpLayerContext<I, BC>
1971        + FragmentHandler<I, BC>
1972        + FilterHandlerProvider<I, BC>
1973        + RawIpSocketHandler<I, BC>,
1974> IpLayerIngressContext<I, BC> for CC
1975{
1976}
1977
1978/// A marker trait for all the contexts required for IP egress.
1979pub trait IpLayerEgressContext<I, BC>:
1980    IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1981    + FilterHandlerProvider<I, BC>
1982    + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1983where
1984    I: IpLayerIpExt,
1985    BC: FilterBindingsContext<Self::DeviceId> + TxMetadataBindingsTypes,
1986{
1987}
1988
1989impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1990where
1991    I: IpLayerIpExt,
1992    BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes,
1993    CC: IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1994        + FilterHandlerProvider<I, BC>
1995        + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1996{
1997}
1998
1999/// A marker trait for all the contexts required for IP forwarding.
2000pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
2001    IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
2002{
2003}
2004
2005impl<
2006    I: IpLayerIpExt,
2007    BC: IpLayerBindingsContext<I, CC::DeviceId>,
2008    CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
2009> IpLayerForwardingContext<I, BC> for CC
2010{
2011}
2012
2013/// A builder for IPv4 state.
2014#[derive(Copy, Clone, Default)]
2015pub struct Ipv4StateBuilder {
2016    icmp: Icmpv4StateBuilder,
2017}
2018
2019impl Ipv4StateBuilder {
2020    /// Get the builder for the ICMPv4 state.
2021    #[cfg(any(test, feature = "testutils"))]
2022    pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
2023        &mut self.icmp
2024    }
2025
2026    /// Builds the [`Ipv4State`].
2027    pub fn build<
2028        CC: CoreTimerContext<IpLayerTimerId, BC>,
2029        StrongDeviceId: StrongDeviceIdentifier,
2030        BC: TimerContext + RngContext + IpLayerBindingsTypes,
2031    >(
2032        self,
2033        bindings_ctx: &mut BC,
2034    ) -> Ipv4State<StrongDeviceId, BC> {
2035        let Ipv4StateBuilder { icmp } = self;
2036
2037        Ipv4State {
2038            inner: IpStateInner::new::<CC>(bindings_ctx),
2039            icmp: icmp.build(),
2040            next_packet_id: Default::default(),
2041        }
2042    }
2043}
2044
2045/// A builder for IPv6 state.
2046///
2047/// By default, opaque IIDs will not be used to generate stable SLAAC addresses.
2048#[derive(Copy, Clone)]
2049pub struct Ipv6StateBuilder {
2050    icmp: Icmpv6StateBuilder,
2051    slaac_stable_secret_key: Option<IidSecret>,
2052}
2053
2054impl Ipv6StateBuilder {
2055    /// Sets the secret key used to generate stable SLAAC addresses.
2056    ///
2057    /// If `slaac_stable_secret_key` is left unset, opaque IIDs will not be used to
2058    /// generate stable SLAAC addresses.
2059    pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
2060        self.slaac_stable_secret_key = Some(secret_key);
2061        self
2062    }
2063
2064    /// Builds the [`Ipv6State`].
2065    ///
2066    /// # Panics
2067    ///
2068    /// Panics if the `slaac_stable_secret_key` has not been set.
2069    pub fn build<
2070        CC: CoreTimerContext<IpLayerTimerId, BC>,
2071        StrongDeviceId: StrongDeviceIdentifier,
2072        BC: TimerContext + RngContext + IpLayerBindingsTypes,
2073    >(
2074        self,
2075        bindings_ctx: &mut BC,
2076    ) -> Ipv6State<StrongDeviceId, BC> {
2077        let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
2078
2079        let slaac_stable_secret_key = slaac_stable_secret_key
2080            .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
2081
2082        Ipv6State {
2083            inner: IpStateInner::new::<CC>(bindings_ctx),
2084            icmp: icmp.build(),
2085            slaac_counters: Default::default(),
2086            slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
2087            slaac_stable_secret_key,
2088        }
2089    }
2090}
2091
2092impl Default for Ipv6StateBuilder {
2093    fn default() -> Self {
2094        #[cfg(any(test, feature = "testutils"))]
2095        let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
2096
2097        #[cfg(not(any(test, feature = "testutils")))]
2098        let slaac_stable_secret_key = None;
2099
2100        Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
2101    }
2102}
2103
2104/// The stack's IPv4 state.
2105pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
2106    /// The common inner IP layer state.
2107    pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
2108    /// The ICMP state.
2109    pub icmp: Icmpv4State<BT>,
2110    /// The atomic counter providing IPv4 packet identifiers.
2111    pub next_packet_id: AtomicU16,
2112}
2113
2114impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2115    AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
2116{
2117    fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
2118        &self.inner
2119    }
2120}
2121
2122/// Generates an IP packet ID.
2123///
2124/// This is only meaningful for IPv4, see [`IpLayerIpExt`].
2125pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
2126    core_ctx: &mut CC,
2127) -> I::PacketId {
2128    core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
2129}
2130
2131/// The stack's IPv6 state.
2132pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
2133    /// The common inner IP layer state.
2134    pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
2135    /// ICMPv6 state.
2136    pub icmp: Icmpv6State<BT>,
2137    /// Stateless address autoconfiguration counters.
2138    pub slaac_counters: SlaacCounters,
2139    /// Secret key used for generating SLAAC temporary addresses.
2140    pub slaac_temp_secret_key: IidSecret,
2141    /// Secret key used for generating SLAAC stable addresses.
2142    ///
2143    /// If `None`, opaque IIDs will not be used to generate stable SLAAC
2144    /// addresses.
2145    pub slaac_stable_secret_key: IidSecret,
2146}
2147
2148impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2149    AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
2150{
2151    fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
2152        &self.inner
2153    }
2154}
2155
2156impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2157    OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
2158{
2159    type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
2160    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2161        OrderedLockRef::new(&self.fragment_cache)
2162    }
2163}
2164
2165impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2166    OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
2167{
2168    type Lock = Mutex<PmtuCache<I, BT>>;
2169    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2170        OrderedLockRef::new(&self.pmtu_cache)
2171    }
2172}
2173
2174impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2175    OrderedLockAccess<RulesTable<I, D, BT>> for IpStateInner<I, D, BT>
2176{
2177    type Lock = RwLock<RulesTable<I, D, BT>>;
2178    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2179        OrderedLockRef::new(&self.rules_table)
2180    }
2181}
2182
2183impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2184    OrderedLockAccess<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>
2185    for IpStateInner<I, D, BT>
2186{
2187    type Lock =
2188        Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>;
2189    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2190        OrderedLockRef::new(&self.tables)
2191    }
2192}
2193
2194impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpRoutingBindingsTypes>
2195    OrderedLockAccess<RoutingTable<I, D>> for RoutingTableId<I, D, BT>
2196{
2197    type Lock = RwLock<RoutingTable<I, D>>;
2198    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2199        let Self(inner) = self;
2200        OrderedLockRef::new(&inner.routing_table)
2201    }
2202}
2203
2204impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2205    OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
2206{
2207    type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
2208    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2209        OrderedLockRef::new(&self.multicast_forwarding)
2210    }
2211}
2212
2213impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2214    OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
2215{
2216    type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
2217    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2218        OrderedLockRef::new(&self.raw_sockets)
2219    }
2220}
2221
2222impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2223    OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
2224{
2225    type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
2226    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2227        OrderedLockRef::new(&self.filter)
2228    }
2229}
2230
2231/// Marker trait for the bindings types required by the IP layer's inner state.
2232pub trait IpStateBindingsTypes:
2233    PmtuBindingsTypes
2234    + FragmentBindingsTypes
2235    + RawIpSocketsBindingsTypes
2236    + FilterBindingsTypes
2237    + MulticastForwardingBindingsTypes
2238    + IpDeviceStateBindingsTypes
2239    + IpRoutingBindingsTypes
2240{
2241}
2242impl<BT> IpStateBindingsTypes for BT where
2243    BT: PmtuBindingsTypes
2244        + FragmentBindingsTypes
2245        + RawIpSocketsBindingsTypes
2246        + FilterBindingsTypes
2247        + MulticastForwardingBindingsTypes
2248        + IpDeviceStateBindingsTypes
2249        + IpRoutingBindingsTypes
2250{
2251}
2252
2253/// Bindings ID for a routing table.
2254#[derive(Derivative)]
2255#[derivative(Debug(bound = ""))]
2256#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2257pub enum RoutingTableCookie<BT: IpRoutingBindingsTypes> {
2258    /// Main table.
2259    Main,
2260    /// A table added by user (Bindings).
2261    BindingsId(BT::RoutingTableId),
2262}
2263
2264/// State for a routing table.
2265#[derive(Derivative)]
2266#[derivative(Debug(bound = "D: Debug"))]
2267pub struct BaseRoutingTableState<I: Ip, D, BT: IpRoutingBindingsTypes> {
2268    routing_table: RwLock<RoutingTable<I, D>>,
2269    bindings_id: RoutingTableCookie<BT>,
2270}
2271
2272impl<I: Ip, D, BT: IpRoutingBindingsTypes> BaseRoutingTableState<I, D, BT> {
2273    pub(crate) fn with_bindings_id(bindings_id: RoutingTableCookie<BT>) -> Self {
2274        Self { bindings_id, routing_table: Default::default() }
2275    }
2276}
2277
2278/// Identifier to a routing table.
2279#[derive(Derivative)]
2280#[derivative(PartialEq(bound = ""))]
2281#[derivative(Eq(bound = ""))]
2282#[derivative(Hash(bound = ""))]
2283#[derivative(Clone(bound = ""))]
2284pub struct RoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes>(
2285    StrongRc<BaseRoutingTableState<I, D, BT>>,
2286);
2287
2288impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for RoutingTableId<I, D, BT> {
2289    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2290        let Self(rc) = self;
2291        f.debug_tuple("RoutingTableId").field(&I::NAME).field(&rc.bindings_id).finish()
2292    }
2293}
2294
2295impl<I: Ip, D, BT: IpRoutingBindingsTypes> RoutingTableId<I, D, BT> {
2296    /// Creates a new table ID.
2297    pub(crate) fn new(rc: StrongRc<BaseRoutingTableState<I, D, BT>>) -> Self {
2298        Self(rc)
2299    }
2300
2301    /// Provides direct access to the forwarding table.
2302    #[cfg(any(test, feature = "testutils"))]
2303    pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2304        let Self(inner) = self;
2305        &inner.routing_table
2306    }
2307
2308    /// Downgrades the strong ID into a weak one.
2309    pub fn downgrade(&self) -> WeakRoutingTableId<I, D, BT>
2310    where
2311        BT::RoutingTableId: Clone,
2312    {
2313        let Self(rc) = self;
2314        WeakRoutingTableId { rc: StrongRc::downgrade(rc), bindings_id: rc.bindings_id.clone() }
2315    }
2316
2317    #[cfg(test)]
2318    fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2319        let Self(rc) = self;
2320        rc.routing_table.write()
2321    }
2322
2323    /// Gets the bindings cookie for this routing table.
2324    pub fn bindings_id(&self) -> &RoutingTableCookie<BT> {
2325        let Self(rc) = self;
2326        &rc.bindings_id
2327    }
2328}
2329
2330/// Weak Identifier to a routing table.
2331#[derive(Derivative)]
2332#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2333#[derivative(PartialEq, Eq, Hash)]
2334pub struct WeakRoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes> {
2335    rc: WeakRc<BaseRoutingTableState<I, D, BT>>,
2336    #[derivative(PartialEq = "ignore")]
2337    #[derivative(Hash = "ignore")]
2338    bindings_id: RoutingTableCookie<BT>,
2339}
2340
2341impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for WeakRoutingTableId<I, D, BT> {
2342    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2343        let Self { bindings_id, .. } = self;
2344        f.debug_tuple("WeakRoutingTableId").field(&I::NAME).field(bindings_id).finish()
2345    }
2346}
2347
2348/// The inner state for the IP layer for IP version `I`.
2349#[derive(GenericOverIp)]
2350#[generic_over_ip(I, Ip)]
2351pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2352    rules_table: RwLock<RulesTable<I, D, BT>>,
2353    // TODO(https://fxbug.dev/355059838): Explore the option to let Bindings create the main table.
2354    main_table_id: RoutingTableId<I, D, BT>,
2355    multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2356    multicast_forwarding_counters: MulticastForwardingCounters<I>,
2357    fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2358    pmtu_cache: Mutex<PmtuCache<I, BT>>,
2359    counters: IpCounters<I>,
2360    raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2361    raw_socket_counters: RawIpSocketCounters<I>,
2362    filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2363    // Make sure the primary IDs are dropped last. Also note that the following hash map also stores
2364    // the primary ID to the main table, and if the user (Bindings) attempts to remove the main
2365    // table without dropping `main_table_id` first, it will panic. This serves as an assertion
2366    // that the main table cannot be removed and Bindings must never attempt to remove the main
2367    // routing table.
2368    tables: Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>,
2369    igmp_counters: IgmpCounters,
2370    mld_counters: MldCounters,
2371}
2372
2373impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2374    /// Gets the IP counters.
2375    pub fn counters(&self) -> &IpCounters<I> {
2376        &self.counters
2377    }
2378
2379    /// Gets the multicast forwarding counters.
2380    pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2381        &self.multicast_forwarding_counters
2382    }
2383
2384    /// Gets the aggregate raw IP socket counters.
2385    pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2386        &self.raw_socket_counters
2387    }
2388
2389    /// Gets the main table ID.
2390    pub fn main_table_id(&self) -> &RoutingTableId<I, D, BT> {
2391        &self.main_table_id
2392    }
2393
2394    /// Provides direct access to the path MTU cache.
2395    #[cfg(any(test, feature = "testutils"))]
2396    pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2397        &self.pmtu_cache
2398    }
2399
2400    /// Provides direct access to the filtering state.
2401    #[cfg(any(test, feature = "testutils"))]
2402    pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2403        &self.filter
2404    }
2405
2406    /// Gets the stack-wide IGMP counters.
2407    pub fn igmp_counters(&self) -> &IgmpCounters {
2408        &self.igmp_counters
2409    }
2410
2411    /// Gets the stack-wide MLD counters.
2412    pub fn mld_counters(&self) -> &MldCounters {
2413        &self.mld_counters
2414    }
2415}
2416
2417impl<
2418    I: IpLayerIpExt,
2419    D: StrongDeviceIdentifier,
2420    BC: TimerContext + RngContext + IpStateBindingsTypes + IpRoutingBindingsTypes,
2421> IpStateInner<I, D, BC>
2422{
2423    /// Creates a new inner IP layer state.
2424    fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2425        let main_table: PrimaryRc<BaseRoutingTableState<I, D, BC>> =
2426            PrimaryRc::new(BaseRoutingTableState::with_bindings_id(RoutingTableCookie::Main));
2427        let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2428        Self {
2429            rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2430            tables: Mutex::new(HashMap::from_iter(core::iter::once((
2431                main_table_id.clone(),
2432                main_table,
2433            )))),
2434            main_table_id,
2435            multicast_forwarding: Default::default(),
2436            multicast_forwarding_counters: Default::default(),
2437            fragment_cache: Mutex::new(
2438                IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2439            ),
2440            pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2441            counters: Default::default(),
2442            raw_sockets: Default::default(),
2443            raw_socket_counters: Default::default(),
2444            filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2445            igmp_counters: Default::default(),
2446            mld_counters: Default::default(),
2447        }
2448    }
2449}
2450
2451/// The identifier for timer events in the IP layer.
2452#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2453#[generic_over_ip()]
2454pub enum IpLayerTimerId {
2455    /// A timer event for IPv4 packet reassembly timers.
2456    ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2457    /// A timer event for IPv6 packet reassembly timers.
2458    ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2459    /// A timer event for IPv4 path MTU discovery.
2460    PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2461    /// A timer event for IPv6 path MTU discovery.
2462    PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2463    /// A timer event for IPv4 filtering timers.
2464    FilterTimerv4(FilterTimerId<Ipv4>),
2465    /// A timer event for IPv6 filtering timers.
2466    FilterTimerv6(FilterTimerId<Ipv6>),
2467    /// A timer event for IPv4 Multicast forwarding timers.
2468    MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2469    /// A timer event for IPv6 Multicast forwarding timers.
2470    MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2471}
2472
2473impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2474    fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2475        I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2476    }
2477}
2478
2479impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2480    fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2481        I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2482    }
2483}
2484
2485impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2486    fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2487        I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2488    }
2489}
2490
2491impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2492    fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2493        I::map_ip(
2494            timer,
2495            IpLayerTimerId::MulticastForwardingTimerv4,
2496            IpLayerTimerId::MulticastForwardingTimerv6,
2497        )
2498    }
2499}
2500
2501impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2502where
2503    CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2504        + TimerHandler<BC, FragmentTimerId<Ipv6>>
2505        + TimerHandler<BC, PmtuTimerId<Ipv4>>
2506        + TimerHandler<BC, PmtuTimerId<Ipv6>>
2507        + TimerHandler<BC, FilterTimerId<Ipv4>>
2508        + TimerHandler<BC, FilterTimerId<Ipv6>>
2509        + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2510        + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2511    BC: TimerBindingsTypes,
2512{
2513    fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2514        match self {
2515            IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2516                core_ctx.handle_timer(bindings_ctx, id, timer)
2517            }
2518            IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2519                core_ctx.handle_timer(bindings_ctx, id, timer)
2520            }
2521            IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2522            IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2523            IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2524            IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2525            IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2526                core_ctx.handle_timer(bindings_ctx, id, timer)
2527            }
2528            IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2529                core_ctx.handle_timer(bindings_ctx, id, timer)
2530            }
2531        }
2532    }
2533}
2534
2535/// An ICMP error, and the metadata required to send it.
2536///
2537/// This allows the sending of the ICMP error to be decoupled from the
2538/// generation of the error, which is advantageous because sending the error
2539/// requires the underlying packet buffer, which cannot be "moved" in certain
2540/// contexts.
2541pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2542    /// The ICMP error that should be sent.
2543    err: I::IcmpError,
2544    /// The original source IP address of the packet (before the local-ingress
2545    /// hook evaluation).
2546    src_ip: SocketIpAddr<I::Addr>,
2547    /// The original destination IP address of the packet (before the
2548    /// local-ingress hook evaluation).
2549    dst_ip: SocketIpAddr<I::Addr>,
2550    /// The frame destination of the packet.
2551    frame_dst: Option<LocalFrameDestination>,
2552    /// The device out which to send the error.
2553    device: &'a D,
2554    /// The metadata from the packet, allowing the packet's backing buffer to be
2555    /// returned to it's pre-IP-parse state with [`GrowBuffer::undo_parse`].
2556    meta: ParseMetadata,
2557    /// The marks used to send the ICMP error.
2558    marks: Marks,
2559    /// The protocol of the original packet.
2560    proto: I::Proto,
2561}
2562
2563impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2564    pub fn new<CC, B>(
2565        core_ctx: &mut CC,
2566        err: I::IcmpError,
2567        packet: &I::Packet<B>,
2568        frame_dst: Option<LocalFrameDestination>,
2569        device: &'a D,
2570        marks: Marks,
2571    ) -> Option<Self>
2572    where
2573        I: IpCountersIpExt,
2574        CC: ResourceCounterContext<D, IpCounters<I>>,
2575        B: SplitByteSlice,
2576    {
2577        let Some(src_ip) = SocketIpAddr::new(packet.src_ip()) else {
2578            core_ctx.increment_both(device, |c| &c.unspecified_source);
2579            return None;
2580        };
2581        let Some(dst_ip) = SocketIpAddr::new(packet.dst_ip()) else {
2582            return None;
2583        };
2584
2585        // In IPv4, don't respond to non-initial fragments.
2586        let is_ipv4_fragment = I::map_ip_in(
2587            packet,
2588            |p| {
2589                packet_formats::ipv4::Ipv4Header::fragment_type(p)
2590                    == Ipv4FragmentType::NonInitialFragment
2591            },
2592            |_| false,
2593        );
2594        if is_ipv4_fragment {
2595            return None;
2596        }
2597
2598        let meta = packet.parse_metadata();
2599        let proto = packet.proto();
2600        Some(Self { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto })
2601    }
2602
2603    /// Generate an send an appropriate ICMP error in response to this error.
2604    ///
2605    /// The provided `body` must be the original buffer from which the IP
2606    /// packet responsible for this error was parsed. It is expected to be in a
2607    /// state that allows undoing the IP packet parse (e.g. unmodified after the
2608    /// IP packet was parsed).
2609    pub fn send<B, BC, CC>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, mut body: B)
2610    where
2611        B: BufferMut,
2612        CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2613    {
2614        let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto } = self;
2615        let header_len = meta.header_len();
2616
2617        // Undo the parsing of the IP Packet, moving the buffer's cursor so that
2618        // it points at the start of the IP header. This way, the sent ICMP
2619        // error will contain the entire original IP packet.
2620        body.undo_parse(meta);
2621
2622        core_ctx.send_icmp_error_message(
2623            bindings_ctx,
2624            Some(device),
2625            frame_dst,
2626            src_ip,
2627            dst_ip,
2628            body,
2629            err,
2630            header_len,
2631            proto,
2632            &marks,
2633        );
2634    }
2635}
2636
2637// Early demux results may be invalidated by SNAT in the LOCAL_INGRESS hook.
2638// This struct is used to check if the early demux result is still valid.
2639//
2640// TODO(https://fxbug.dev/476507679): Add tests to ensure this works properly
2641// once SNAT is fully implemented.
2642#[derive(PartialEq, Eq)]
2643struct EarlyDemuxResult<I: Ip, S> {
2644    socket: S,
2645    src_addr: I::Addr,
2646    src_port: Option<u16>,
2647}
2648
2649impl<I: FilterIpExt, S> EarlyDemuxResult<I, S> {
2650    fn new<P: IpPacket<I>>(socket: S, packet: &P) -> Self {
2651        let src_port =
2652            packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port_or_id());
2653        Self { socket, src_addr: packet.src_addr(), src_port }
2654    }
2655
2656    // Returns the socket if it's still the right socket to handle the packet.
2657    fn take_socket<P: IpPacket<I>>(self, packet: &P) -> Option<S> {
2658        let src_port =
2659            packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port_or_id());
2660        (self.src_addr == packet.src_addr() && self.src_port == src_port).then_some(self.socket)
2661    }
2662
2663    fn update_packet_metadata<CC, BC>(
2664        &self,
2665        core_ctx: &mut CC,
2666        packet_metadata: &mut IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2667    ) where
2668        I: IpLayerIpExt,
2669        S: SocketMetadata<CC>,
2670        BC: IpLayerBindingsContext<I, CC::DeviceId>,
2671        CC: IpLayerIngressContext<I, BC>,
2672    {
2673        packet_metadata.socket_info = Some(self.socket.socket_info(core_ctx));
2674        packet_metadata.marks =
2675            BC::update_ingress_marks(packet_metadata.marks, &self.socket.marks(core_ctx));
2676    }
2677}
2678
2679pub(crate) fn reject_type_to_icmpv4_error(reject_type: RejectType) -> Option<Icmpv4Error> {
2680    let error = match reject_type {
2681        RejectType::NetUnreachable => Icmpv4Error::NetUnreachable,
2682        RejectType::ProtoUnreachable => Icmpv4Error::ProtocolUnreachable,
2683        RejectType::PortUnreachable => Icmpv4Error::PortUnreachable,
2684        RejectType::HostUnreachable => Icmpv4Error::HostUnreachable,
2685        RejectType::RoutePolicyFail => Icmpv4Error::NetworkProhibited,
2686        RejectType::RejectRoute => Icmpv4Error::HostProhibited,
2687        RejectType::AdminProhibited => Icmpv4Error::AdminProhibited,
2688        // TODO(https://fxbug.dev/488116504): Implement RejectType::TcpReset.
2689        RejectType::TcpReset => return None,
2690    };
2691    Some(error)
2692}
2693
2694pub(crate) fn reject_type_to_icmpv6_error(reject_type: RejectType) -> Option<Icmpv6Error> {
2695    let error = match reject_type {
2696        RejectType::NetUnreachable => Icmpv6Error::NetUnreachable,
2697        RejectType::PortUnreachable => Icmpv6Error::PortUnreachable,
2698        RejectType::HostUnreachable => Icmpv6Error::AddressUnreachable,
2699        RejectType::AdminProhibited => Icmpv6Error::AdminProhibited,
2700        RejectType::RoutePolicyFail => Icmpv6Error::SourceAddressPolicyFailed,
2701        RejectType::RejectRoute => Icmpv6Error::RejectRoute,
2702        // TODO(https://fxbug.dev/488116504): Implement ProtoUnreachable and TcpReset.
2703        RejectType::TcpReset | RejectType::ProtoUnreachable => return None,
2704    };
2705    Some(error)
2706}
2707// TODO(joshlf): Once we support multiple extension headers in IPv6, we will
2708// need to verify that the callers of this function are still sound. In
2709// particular, they may accidentally pass a parse_metadata argument which
2710// corresponds to a single extension header rather than all of the IPv6 headers.
2711
2712/// Dispatch a received IPv4 packet to the appropriate protocol.
2713///
2714/// `device` is the device the packet was received on. `parse_metadata` is the
2715/// parse metadata associated with parsing the IP headers. It is used to undo
2716/// that parsing. Both `device` and `parse_metadata` are required in order to
2717/// send ICMP messages in response to unrecognized protocols or ports. If either
2718/// of `device` or `parse_metadata` is `None`, the caller promises that the
2719/// protocol and port are recognized.
2720///
2721/// # Panics
2722///
2723/// `dispatch_receive_ipv4_packet` panics if the protocol is unrecognized and
2724/// `parse_metadata` is `None`. If an IGMP message is received but it is not
2725/// coming from a device, i.e., `device` given is `None`,
2726/// `dispatch_receive_ip_packet` will also panic.
2727fn dispatch_receive_ipv4_packet<
2728    'a,
2729    'b,
2730    BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2731    CC: IpLayerIngressContext<Ipv4, BC>,
2732>(
2733    core_ctx: &'a mut CC,
2734    bindings_ctx: &'a mut BC,
2735    device: &'b CC::DeviceId,
2736    frame_dst: Option<LocalFrameDestination>,
2737    mut packet: Ipv4Packet<&'a mut [u8]>,
2738    mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2739    receive_meta: ReceiveIpPacketMeta<Ipv4>,
2740) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2741    core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2742
2743    // Skip early demux if the packet was redirected to a TPROXY.
2744    // TODO(https://fxbug.dev/475851987): Handle TPROXY in early_demux.
2745    let early_demux_result = receive_meta
2746        .transparent_override
2747        .is_none()
2748        .then(|| {
2749            core_ctx.early_demux(
2750                device,
2751                frame_dst,
2752                packet.src_ip(),
2753                packet.dst_ip(),
2754                packet.proto(),
2755                packet.body(),
2756            )
2757        })
2758        .flatten()
2759        .map(|socket| {
2760            let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2761            early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2762            early_demux_result
2763        });
2764
2765    let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2766        bindings_ctx,
2767        &mut packet,
2768        device,
2769        &mut packet_metadata,
2770    );
2771
2772    let marks = packet_metadata.marks;
2773    let packet_type = packet_metadata.packet_type;
2774    let gso_info = packet_metadata.gso_info;
2775    packet_metadata.acknowledge_drop();
2776
2777    match filter_verdict {
2778        filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2779            return Ok(());
2780        }
2781        filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2782            return match reject_type_to_icmpv4_error(reject_type) {
2783                Some(icmp_error) => {
2784                    match IcmpErrorSender::new(
2785                        core_ctx, icmp_error, &packet, frame_dst, device, marks,
2786                    ) {
2787                        Some(icmp_sender) => Err(icmp_sender),
2788                        None => Ok(()),
2789                    }
2790                }
2791                None => {
2792                    debug!("Unsupported reject type: {:?}", reject_type);
2793                    return Ok(());
2794                }
2795            };
2796        }
2797        filter::Verdict::Proceed(filter::Accept) => (),
2798    };
2799
2800    // These invariants are validated by the caller of this function, but it's
2801    // possible for the LOCAL_INGRESS hook to rewrite the packet, so we have to
2802    // check them again.
2803    let Some(src_ip) = packet.src_ipv4() else {
2804        debug!(
2805            "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2806            LOCAL_INGRESS hook; dropping",
2807            packet.src_ip()
2808        );
2809        core_ctx.increment_both(device, |c| &c.invalid_source);
2810        return Ok(());
2811    };
2812    let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2813        core_ctx.increment_both(device, |c| &c.unspecified_destination);
2814        debug!(
2815            "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2816            after the LOCAL_INGRESS hook; dropping"
2817        );
2818        return Ok(());
2819    };
2820
2821    core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2822
2823    // Check if the early demux result is still valid.
2824    let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2825
2826    let proto = packet.proto();
2827    let (prefix, options, body) = packet.parts_with_body_mut();
2828    let buffer = Buf::new(body, ..);
2829    let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2830    let mut receive_info =
2831        LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks, packet_type, gso_info };
2832
2833    core_ctx
2834        .dispatch_receive_ip_packet(
2835            bindings_ctx,
2836            device,
2837            src_ip,
2838            dst_ip,
2839            proto,
2840            buffer,
2841            &mut receive_info,
2842            early_demux_socket,
2843        )
2844        .or_else(|icmp_error| {
2845            match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2846                Some(icmp_sender) => Err(icmp_sender),
2847                None => Ok(()),
2848            }
2849        })
2850}
2851
2852/// Dispatch a received IPv6 packet to the appropriate protocol.
2853///
2854/// `dispatch_receive_ipv6_packet` has the same semantics as
2855/// `dispatch_receive_ipv4_packet`, but for IPv6.
2856fn dispatch_receive_ipv6_packet<
2857    'a,
2858    'b,
2859    BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2860    CC: IpLayerIngressContext<Ipv6, BC>,
2861>(
2862    core_ctx: &'a mut CC,
2863    bindings_ctx: &'a mut BC,
2864    device: &'b CC::DeviceId,
2865    frame_dst: Option<LocalFrameDestination>,
2866    mut packet: Ipv6Packet<&'a mut [u8]>,
2867    mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2868    meta: ReceiveIpPacketMeta<Ipv6>,
2869) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2870    // TODO(https://fxbug.dev/42095067): Once we support multiple extension
2871    // headers in IPv6, we will need to verify that the callers of this
2872    // function are still sound. In particular, they may accidentally pass a
2873    // parse_metadata argument which corresponds to a single extension
2874    // header rather than all of the IPv6 headers.
2875
2876    core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2877
2878    // Skip early demux if the packet was redirected to a TPROXY.
2879    // TODO(https://fxbug.dev/475851987): Handle TPROXY in early_demux.
2880    let early_demux_result = meta
2881        .transparent_override
2882        .is_none()
2883        .then(|| {
2884            core_ctx.early_demux(
2885                device,
2886                frame_dst,
2887                packet.src_ip(),
2888                packet.dst_ip(),
2889                packet.proto(),
2890                packet.body(),
2891            )
2892        })
2893        .flatten()
2894        .map(|socket| {
2895            let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2896            early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2897            early_demux_result
2898        });
2899
2900    let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2901        bindings_ctx,
2902        &mut packet,
2903        device,
2904        &mut packet_metadata,
2905    );
2906
2907    let marks = packet_metadata.marks;
2908    let packet_type = packet_metadata.packet_type;
2909    let gso_info = packet_metadata.gso_info;
2910    packet_metadata.acknowledge_drop();
2911
2912    match filter_verdict {
2913        filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2914            return Ok(());
2915        }
2916        filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2917            return match reject_type_to_icmpv6_error(reject_type) {
2918                Some(icmp_error) => {
2919                    match IcmpErrorSender::new(
2920                        core_ctx, icmp_error, &packet, frame_dst, device, marks,
2921                    ) {
2922                        Some(icmp_sender) => Err(icmp_sender),
2923                        None => Ok(()),
2924                    }
2925                }
2926                None => {
2927                    debug!("Unsupported reject type: {:?}", reject_type);
2928                    return Ok(());
2929                }
2930            };
2931        }
2932        filter::Verdict::Proceed(filter::Accept) => {}
2933    }
2934
2935    // These invariants are validated by the caller of this function, but it's
2936    // possible for the LOCAL_INGRESS hook to rewrite the packet, so we have to
2937    // check them again.
2938    let Some(src_ip) = packet.src_ipv6() else {
2939        debug!(
2940            "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2941            LOCAL_INGRESS hook; dropping",
2942            packet.src_ip()
2943        );
2944
2945        core_ctx.increment_both(device, |c| &c.invalid_source);
2946        return Ok(());
2947    };
2948    let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2949        core_ctx.increment_both(device, |c| &c.unspecified_destination);
2950        debug!(
2951            "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2952            after the LOCAL_INGRESS hook; dropping"
2953        );
2954        return Ok(());
2955    };
2956
2957    core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2958
2959    // Check if the early demux result is still valid.
2960    let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2961
2962    let proto = packet.proto();
2963    let (fixed, extension, body) = packet.parts_with_body_mut();
2964    let buffer = Buf::new(body, ..);
2965    let header_info = Ipv6HeaderInfo { fixed, extension };
2966    let mut receive_info =
2967        LocalDeliveryPacketInfo { meta, header_info, marks, packet_type, gso_info };
2968
2969    core_ctx
2970        .dispatch_receive_ip_packet(
2971            bindings_ctx,
2972            device,
2973            src_ip,
2974            dst_ip,
2975            proto,
2976            buffer,
2977            &mut receive_info,
2978            early_demux_socket,
2979        )
2980        .or_else(|icmp_error| {
2981            let marks = receive_info.marks;
2982            match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2983                Some(icmp_sender) => Err(icmp_sender),
2984                None => Ok(()),
2985            }
2986        })
2987}
2988
2989/// The metadata required to forward an IP Packet.
2990///
2991/// This allows the forwarding of the packet to be decoupled from the
2992/// determination of how to forward. This is advantageous because forwarding
2993/// requires the underlying packet buffer, which cannot be "moved" in certain
2994/// contexts.
2995pub(crate) struct IpPacketForwarder<
2996    'a,
2997    I: IpLayerIpExt,
2998    D,
2999    A,
3000    BT: FilterBindingsTypes + TxMetadataBindingsTypes,
3001> {
3002    inbound_device: &'a D,
3003    outbound_device: &'a D,
3004    packet_meta: IpLayerPacketMetadata<I, A, BT>,
3005    src_ip: I::RecvSrcAddr,
3006    dst_ip: SpecifiedAddr<I::Addr>,
3007    destination: IpPacketDestination<I, &'a D>,
3008    proto: I::Proto,
3009    parse_meta: ParseMetadata,
3010    frame_dst: Option<LocalFrameDestination>,
3011}
3012
3013impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
3014where
3015    I: IpLayerIpExt,
3016    BC: IpLayerBindingsContext<I, D>,
3017{
3018    // Forward the provided buffer as specified by this [`IpPacketForwarder`].
3019    fn forward_with_buffer<CC, B>(
3020        self,
3021        core_ctx: &mut CC,
3022        bindings_ctx: &mut BC,
3023        buffer: B,
3024        max_fragment_len: Option<usize>,
3025    ) where
3026        B: BufferMut,
3027        CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
3028    {
3029        let Self {
3030            inbound_device,
3031            outbound_device,
3032            packet_meta,
3033            src_ip,
3034            dst_ip,
3035            destination,
3036            proto,
3037            parse_meta,
3038            frame_dst,
3039        } = self;
3040
3041        let outbound_mtu = core_ctx.get_mtu(outbound_device);
3042        let marks = packet_meta.marks;
3043
3044        let send_icmp_packet_too_big = |core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B| {
3045            debug!("failed to forward {} packet: MTU exceeded", I::NAME);
3046            core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
3047            // NB: Ipv6 sends a PacketTooBig error. Ipv4 sends nothing.
3048            let Some(err) = I::IcmpError::mtu_exceeded(outbound_mtu) else {
3049                return;
3050            };
3051            // NB: Only send an ICMP error if the sender's src
3052            // is specified.
3053            let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
3054                return;
3055            };
3056
3057            let Some(dst_ip) = SocketIpAddr::new(dst_ip.get()) else {
3058                return;
3059            };
3060
3061            // TODO(https://fxbug.dev/362489447): Increment the TTL since we
3062            // just decremented it. The fact that we don't do this is
3063            // technically a violation of the ICMP spec (we're not
3064            // encapsulating the original packet that caused the
3065            // issue, but a slightly modified version of it), but
3066            // it's not that big of a deal because it won't affect
3067            // the sender's ability to figure out the minimum path
3068            // MTU. This may break other logic, though, so we should
3069            // still fix it eventually.
3070            core_ctx.send_icmp_error_message(
3071                bindings_ctx,
3072                Some(inbound_device),
3073                frame_dst,
3074                src_ip,
3075                dst_ip,
3076                buffer,
3077                err,
3078                parse_meta.header_len(),
3079                proto,
3080                &marks,
3081            );
3082        };
3083
3084        // If the packet was reassembled on ingress, we should refragment at
3085        // the original MTU.
3086        //
3087        // For IPv6, if the maximum fragment was larger than the outbound
3088        // interface's MTU, short circuit and send a `PacketTooBig` ICMP error.
3089        let max_fragment_len = max_fragment_len
3090            .map(|l| Mtu::new(u32::try_from(l).expect("fragment size must fit in u32")));
3091        if I::VERSION == IpVersion::V6
3092            && max_fragment_len.is_some_and(|max_fragment_len| max_fragment_len > outbound_mtu)
3093        {
3094            packet_meta.acknowledge_drop();
3095            send_icmp_packet_too_big(core_ctx, bindings_ctx, buffer);
3096            return;
3097        }
3098        let (was_reassembled, limit_mtu) = match max_fragment_len {
3099            None => (false, Mtu::no_limit()),
3100            Some(max_fragment_len) => (true, max_fragment_len),
3101        };
3102
3103        let packet = ForwardedPacket::new(
3104            src_ip.get(),
3105            dst_ip.get(),
3106            proto,
3107            parse_meta,
3108            buffer,
3109            was_reassembled,
3110        );
3111
3112        trace!("forward_with_buffer: forwarding {} packet", I::NAME);
3113
3114        match send_ip_frame(
3115            core_ctx,
3116            bindings_ctx,
3117            outbound_device,
3118            destination,
3119            packet,
3120            packet_meta,
3121            limit_mtu,
3122        ) {
3123            Ok(()) => (),
3124            Err(IpSendFrameError { serializer, error }) => {
3125                match error {
3126                    IpSendFrameErrorReason::Device(
3127                        SendFrameErrorReason::SizeConstraintsViolation,
3128                    ) => {
3129                        send_icmp_packet_too_big(core_ctx, bindings_ctx, serializer.into_buffer());
3130                    }
3131                    IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
3132                    | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
3133                    | IpSendFrameErrorReason::Device(
3134                        SendFrameErrorReason::AddressResolutionFailed,
3135                    )
3136                    | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
3137                }
3138                debug!("failed to forward {} packet: {error:?}", I::NAME);
3139            }
3140        }
3141    }
3142}
3143
3144/// The action to take for a packet that was a candidate for forwarding.
3145pub(crate) enum ForwardingAction<
3146    'a,
3147    I: IpLayerIpExt,
3148    D,
3149    A,
3150    BT: FilterBindingsTypes + TxMetadataBindingsTypes,
3151> {
3152    /// Drop the packet without forwarding it or generating an ICMP error.
3153    SilentlyDrop,
3154    /// Forward the packet, as specified by the [`IpPacketForwarder`].
3155    Forward(IpPacketForwarder<'a, I, D, A, BT>),
3156    /// Drop the packet without forwarding, and generate an ICMP error as
3157    /// specified by the [`IcmpErrorSender`].
3158    DropWithIcmpError(IcmpErrorSender<'a, I, D>),
3159}
3160
3161impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
3162where
3163    I: IpLayerIpExt,
3164    BC: IpLayerBindingsContext<I, D>,
3165{
3166    /// Perform the action prescribed by self, with the provided packet buffer.
3167    pub(crate) fn perform_action_with_buffer<CC, B>(
3168        self,
3169        core_ctx: &mut CC,
3170        bindings_ctx: &mut BC,
3171        buffer: B,
3172        max_fragment_len: Option<usize>,
3173    ) where
3174        B: BufferMut,
3175        CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
3176    {
3177        match self {
3178            ForwardingAction::SilentlyDrop => {}
3179            ForwardingAction::Forward(forwarder) => {
3180                forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer, max_fragment_len)
3181            }
3182            ForwardingAction::DropWithIcmpError(icmp_sender) => {
3183                icmp_sender.send(core_ctx, bindings_ctx, buffer)
3184            }
3185        }
3186    }
3187}
3188
3189/// Determine which [`ForwardingAction`] should be taken for an IP packet.
3190pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
3191    core_ctx: &'a mut CC,
3192    mut packet: I::Packet<&'a mut [u8]>,
3193    mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3194    minimum_ttl: Option<NonZeroU8>,
3195    inbound_device: &'b CC::DeviceId,
3196    outbound_device: &'b CC::DeviceId,
3197    destination: IpPacketDestination<I, &'b CC::DeviceId>,
3198    frame_dst: Option<LocalFrameDestination>,
3199    src_ip: I::RecvSrcAddr,
3200    dst_ip: SpecifiedAddr<I::Addr>,
3201) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
3202where
3203    I: IpLayerIpExt,
3204    BC: IpLayerBindingsContext<I, CC::DeviceId>,
3205    CC: IpLayerForwardingContext<I, BC>,
3206{
3207    // When forwarding, if a datagram's TTL is one or zero, discard it, as
3208    // decrementing the TTL would put it below the allowed minimum value.
3209    // For IPv4, see "TTL" section, https://tools.ietf.org/html/rfc791#page-14.
3210    // For IPv6, see "Hop Limit" section, https://datatracker.ietf.org/doc/html/rfc2460#page-5.
3211    const DEFAULT_MIN_TTL: u8 = 1;
3212    let minimum_ttl = minimum_ttl.map(NonZeroU8::get).unwrap_or(DEFAULT_MIN_TTL);
3213    let ttl = packet.ttl();
3214    if ttl <= minimum_ttl {
3215        debug!(
3216            "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
3217            I::NAME
3218        );
3219        // As per RFC 792's specification of the Time Exceeded Message:
3220        //     If the gateway processing a datagram finds the time to live
3221        //     field is zero it must discard the datagram. The gateway may
3222        //     also notify the source host via the time exceeded message.
3223        // And RFC 4443 section 3.3:
3224        //    If a router receives a packet with a Hop Limit of zero, or if
3225        //    a router decrements a packet's Hop Limit to zero, it MUST
3226        //    discard the packet and originate an ICMPv6 Time Exceeded
3227        //    message with Code 0 to the source of the packet.
3228        // Don't send a Time Exceeded Message in cases where the netstack is
3229        // enforcing a higher minimum TTL (e.g. as part of a multicast route).
3230        if ttl > 1 {
3231            packet_meta.acknowledge_drop();
3232            return ForwardingAction::SilentlyDrop;
3233        }
3234
3235        core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
3236
3237        let marks = packet_meta.marks;
3238        packet_meta.acknowledge_drop();
3239
3240        // Construct and send the appropriate ICMP error for the IP version.
3241        match IcmpErrorSender::new(
3242            core_ctx,
3243            I::IcmpError::ttl_expired(),
3244            &packet,
3245            frame_dst,
3246            inbound_device,
3247            marks,
3248        ) {
3249            Some(icmp_sender) => return ForwardingAction::DropWithIcmpError(icmp_sender),
3250            None => return ForwardingAction::SilentlyDrop,
3251        }
3252    }
3253
3254    trace!("determine_ip_packet_forwarding_action: adequate TTL");
3255
3256    // For IPv6 packets, handle extension headers first.
3257    //
3258    // Any previous handling of extension headers was done under the
3259    // assumption that we are the final destination of the packet. Now that
3260    // we know we're forwarding, we need to re-examine them.
3261    let maybe_ipv6_packet_action = I::map_ip_in(
3262        &packet,
3263        |_packet| None,
3264        |packet| {
3265            Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
3266        },
3267    );
3268    match maybe_ipv6_packet_action {
3269        None => {} // NB: Ipv4 case.
3270        Some(Ipv6PacketAction::_Discard) => {
3271            core_ctx.increment_both(inbound_device, |c| {
3272                #[derive(GenericOverIp)]
3273                #[generic_over_ip(I, Ip)]
3274                struct InCounters<'a, I: IpLayerIpExt>(
3275                    &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
3276                );
3277                I::map_ip_in::<_, _>(
3278                    InCounters(&c.version_rx),
3279                    |_counters| {
3280                        unreachable!(
3281                            "`I` must be `Ipv6` because we're handling IPv6 extension headers"
3282                        )
3283                    },
3284                    |InCounters(counters)| &counters.extension_header_discard,
3285                )
3286            });
3287            trace!(
3288                "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3289                discarding packet"
3290            );
3291            packet_meta.acknowledge_drop();
3292            return ForwardingAction::SilentlyDrop;
3293        }
3294        Some(Ipv6PacketAction::Continue) => {
3295            trace!(
3296                "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3297                forwarding packet"
3298            );
3299        }
3300        Some(Ipv6PacketAction::ProcessFragment) => {
3301            unreachable!(
3302                "When forwarding packets, we should only ever look at the hop by hop \
3303                    options extension header (if present)"
3304            )
3305        }
3306    };
3307
3308    match core_ctx.filter_handler().forwarding_hook(
3309        I::as_filter_packet(&mut packet),
3310        inbound_device,
3311        outbound_device,
3312        &mut packet_meta,
3313    ) {
3314        filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3315            packet_meta.acknowledge_drop();
3316            trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
3317            return ForwardingAction::SilentlyDrop;
3318        }
3319        filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
3320            // TODO(https://fxbug.dev/466098884): Send reject packet.
3321            packet_meta.acknowledge_drop();
3322            trace!(
3323                "determine_ip_packet_forwarding_action: filter verdict: Reject({:?})",
3324                reject_type
3325            );
3326            return ForwardingAction::SilentlyDrop;
3327        }
3328        filter::Verdict::Proceed(filter::Accept) => {}
3329    }
3330
3331    packet.set_ttl(ttl - 1);
3332    let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
3333    ForwardingAction::Forward(IpPacketForwarder {
3334        inbound_device,
3335        outbound_device,
3336        packet_meta,
3337        src_ip,
3338        dst_ip,
3339        destination,
3340        proto,
3341        parse_meta,
3342        frame_dst,
3343    })
3344}
3345
3346pub(crate) fn send_ip_frame<I, CC, BC, S>(
3347    core_ctx: &mut CC,
3348    bindings_ctx: &mut BC,
3349    device: &CC::DeviceId,
3350    destination: IpPacketDestination<I, &CC::DeviceId>,
3351    mut body: S,
3352    mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3353    limit_mtu: Mtu,
3354) -> Result<(), IpSendFrameError<S>>
3355where
3356    I: IpLayerIpExt,
3357    BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3358    CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
3359    S: FragmentableIpSerializer<I, Buffer: BufferMut>
3360        + MaybeSegmentableIpSerializer<I>
3361        + FilterIpPacket<I>,
3362{
3363    let (verdict, proof) = core_ctx.filter_handler().egress_hook(
3364        bindings_ctx,
3365        &mut body,
3366        device,
3367        &mut packet_metadata,
3368    );
3369    match verdict {
3370        filter::Verdict::Stop(filter::DropPacket) => {
3371            packet_metadata.acknowledge_drop();
3372            return Ok(());
3373        }
3374        filter::Verdict::Proceed(filter::Accept) => {}
3375    }
3376
3377    // If the packet is leaving through the loopback device, attempt to extract a
3378    // weak reference to the packet's conntrack entry to plumb that through the
3379    // device layer so it can be reused on ingress to the IP layer.
3380    let (
3381        conntrack_connection_and_direction,
3382        tx_metadata,
3383        marks,
3384        _socket_cookie,
3385        gso_info,
3386        packet_type,
3387    ) = packet_metadata.into_parts();
3388    let conntrack_entry = if device.is_loopback() {
3389        conntrack_connection_and_direction
3390            .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
3391    } else {
3392        None
3393    };
3394
3395    let mut device_layer_marks = Marks::default();
3396    for mark in BC::marks_to_keep_on_egress() {
3397        *device_layer_marks.get_mut(*mark) = *marks.get(*mark);
3398    }
3399
3400    let device_ip_layer_metadata = DeviceIpLayerMetadata {
3401        conntrack_entry,
3402        tx_metadata,
3403        marks: device_layer_marks,
3404        packet_type,
3405    };
3406
3407    // The filtering layer may have changed our address. Perform a last moment
3408    // check to protect against sending loopback addresses on the wire for
3409    // non-loopback devices, which is an RFC violation.
3410    if !device.is_loopback()
3411        && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
3412            || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
3413    {
3414        core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
3415        return Err(IpSendFrameError {
3416            serializer: body,
3417            error: IpSendFrameErrorReason::IllegalLoopbackAddress,
3418        });
3419    }
3420
3421    // Use the minimum MTU between the target device and the requested mtu.
3422    let mtu = limit_mtu.min(core_ctx.get_mtu(device));
3423
3424    let Some(gso_info) = gso_info else {
3425        // Transport-layer segmentation isn't required. Check if we need to
3426        // fragment and then send.
3427        return send_ip_frame_possibly_fragmented(
3428            core_ctx,
3429            bindings_ctx,
3430            device,
3431            destination,
3432            body,
3433            device_ip_layer_metadata,
3434            mtu,
3435            proof,
3436        );
3437    };
3438
3439    match send_ip_frame_segmented(
3440        core_ctx,
3441        bindings_ctx,
3442        device,
3443        destination.clone(),
3444        &body,
3445        gso_info,
3446        device_ip_layer_metadata,
3447        mtu,
3448        proof,
3449    ) {
3450        Ok(()) => Ok(()),
3451        Err(SendIpFrameSegmentedError::NotSegmentable(error, device_ip_layer_metadata, proof)) => {
3452            // GRO and GSO should always produce packets that can be
3453            // resegmented. If that's not the case, we want to know about it. In
3454            // production, however, we'll attempt to send with fragmentation for
3455            // robustness' sake.
3456            debug_assert!(
3457                false,
3458                "GRO or GSO produced a packet that can't be resegmented: {error:?}"
3459            );
3460            error!("GRO or GSO produced a packet that can't be resegmented: {error:?}");
3461            send_ip_frame_possibly_fragmented(
3462                core_ctx,
3463                bindings_ctx,
3464                device,
3465                destination,
3466                body,
3467                device_ip_layer_metadata,
3468                mtu,
3469                proof,
3470            )
3471        }
3472        Err(SendIpFrameSegmentedError::Send(error)) => {
3473            Err(IpSendFrameError { serializer: body, error })
3474        }
3475    }
3476}
3477
3478/// The error type for [`send_ip_frame_segmented`].
3479enum SendIpFrameSegmentedError<BT: TxMetadataBindingsTypes> {
3480    /// The packet can't be segmented in software.
3481    ///
3482    /// Nothing was sent, so the caller's metadata and egress proof are handed
3483    /// back untouched.
3484    NotSegmentable(GsoError, DeviceIpLayerMetadata<BT>, ProofOfEgressCheck),
3485    /// A segment couldn't be sent.
3486    Send(IpSendFrameErrorReason),
3487}
3488
3489/// Splits `body` into `gso_info`-sized segments and sends each one out of
3490/// `device`, fragmenting any segment that doesn't fit in `mtu`.
3491///
3492/// Takes `body` by reference: segments borrow from the packet's builders and
3493/// payload, and keeping the borrow inside this function is what allows the
3494/// caller to hand `body` back to *its* caller on error.
3495fn send_ip_frame_segmented<I, CC, BC, S>(
3496    core_ctx: &mut CC,
3497    bindings_ctx: &mut BC,
3498    device: &CC::DeviceId,
3499    destination: IpPacketDestination<I, &CC::DeviceId>,
3500    body: &S,
3501    gso_info: GsoInfo,
3502    device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3503    mtu: Mtu,
3504    proof: ProofOfEgressCheck,
3505) -> Result<(), SendIpFrameSegmentedError<BC>>
3506where
3507    I: IpLayerIpExt,
3508    BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3509    CC: IpLayerEgressContext<I, BC>,
3510    S: FragmentableIpSerializer<I, Buffer: BufferMut> + MaybeSegmentableIpSerializer<I>,
3511{
3512    core_ctx.increment_both(device, |c| &c.gso.for_source(S::SOURCE).segmentation_required);
3513
3514    let segmenter = match body.try_segmenter(gso_info) {
3515        Ok(segmenter) => segmenter,
3516        Err(error) => {
3517            core_ctx.increment_both(device, |c| c.gso.for_source(S::SOURCE).error_counter(&error));
3518            return Err(SendIpFrameSegmentedError::NotSegmentable(
3519                error,
3520                device_ip_layer_metadata,
3521                proof,
3522            ));
3523        }
3524    };
3525
3526    let mut device_ip_layer_metadata = device_ip_layer_metadata;
3527    let mut proof = proof;
3528
3529    for (segment, has_more) in segmenter {
3530        let (segment_metadata, segment_proof, remaining) = if has_more {
3531            let SplitDeviceIpLayerMetadata { primary, secondary } =
3532                device_ip_layer_metadata.split_for_multiple_frames();
3533            (secondary, proof.clone_for_multiple_frames(), Some((primary, proof)))
3534        } else {
3535            (device_ip_layer_metadata, proof, None)
3536        };
3537
3538        send_ip_frame_possibly_fragmented(
3539            core_ctx,
3540            bindings_ctx,
3541            device,
3542            destination.clone(),
3543            segment,
3544            segment_metadata,
3545            mtu,
3546            segment_proof,
3547        )
3548        .map_err(|IpSendFrameError { serializer: _, error }| {
3549            SendIpFrameSegmentedError::Send(error)
3550        })?;
3551
3552        core_ctx.increment_both(device, |c| &c.gso.for_source(S::SOURCE).segments);
3553
3554        match remaining {
3555            Some((m, p)) => {
3556                device_ip_layer_metadata = m;
3557                proof = p;
3558            }
3559            None => break,
3560        }
3561    }
3562
3563    Ok(())
3564}
3565
3566/// Sends `body` out of `device`, fragmenting it if it doesn't fit in `mtu`.
3567fn send_ip_frame_possibly_fragmented<I, CC, BC, S>(
3568    core_ctx: &mut CC,
3569    bindings_ctx: &mut BC,
3570    device: &CC::DeviceId,
3571    destination: IpPacketDestination<I, &CC::DeviceId>,
3572    body: S,
3573    device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3574    mtu: Mtu,
3575    proof: ProofOfEgressCheck,
3576) -> Result<(), IpSendFrameError<S>>
3577where
3578    I: IpLayerIpExt,
3579    BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3580    CC: IpLayerEgressContext<I, BC>,
3581    S: FragmentableIpSerializer<I, Buffer: BufferMut>,
3582{
3583    let body = body.with_size_limit(mtu.into());
3584
3585    let fits_mtu = match body.serialize_new_buf(
3586        &mut NetworkSerializationContext::default(),
3587        PacketConstraints::UNCONSTRAINED,
3588        AlwaysFailBufferAlloc,
3589    ) {
3590        // We hit the allocator that refused to allocate new data, which
3591        // means the MTU is respected.
3592        Err(SerializeError::Alloc(())) => true,
3593        // MTU failure, we should try to fragment.
3594        Err(SerializeError::SizeLimitExceeded) => false,
3595    };
3596
3597    if fits_mtu {
3598        return core_ctx
3599            .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
3600            .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
3601                serializer: serializer.into_inner(),
3602                error: error.into(),
3603            });
3604    }
3605
3606    // Body doesn't fit MTU, we must fragment this serializer in order to send
3607    // it out.
3608    core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
3609
3610    let body = body.into_inner();
3611    let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
3612        Ok(mut fragmenter) => {
3613            let mut device_ip_layer_metadata = device_ip_layer_metadata;
3614            loop {
3615                let Some((fragment, has_more)) = fragmenter.next() else {
3616                    break Ok(());
3617                };
3618
3619                let (fragment_metadata, remaining_metadata) = if has_more {
3620                    let SplitDeviceIpLayerMetadata { primary, secondary } =
3621                        device_ip_layer_metadata.split_for_multiple_frames();
3622                    (secondary, Some(primary))
3623                } else {
3624                    (device_ip_layer_metadata, None)
3625                };
3626
3627                match core_ctx.send_ip_frame(
3628                    bindings_ctx,
3629                    device,
3630                    destination.clone(),
3631                    fragment_metadata,
3632                    fragment,
3633                    proof.clone_for_multiple_frames(),
3634                ) {
3635                    Ok(()) => {
3636                        core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
3637                    }
3638                    Err(ErrorAndSerializer { serializer: _, error }) => {
3639                        core_ctx.increment_both(device, |c| {
3640                            &c.fragmentation.error_fragmented_serializer
3641                        });
3642                        break Err(error);
3643                    }
3644                }
3645
3646                match remaining_metadata {
3647                    Some(m) => device_ip_layer_metadata = m,
3648                    None => break Ok(()),
3649                }
3650            }
3651        }
3652        Err(e) => {
3653            core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
3654            Err(SendFrameErrorReason::SizeConstraintsViolation)
3655        }
3656    };
3657    result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3658}
3659
3660/// A buffer allocator that always fails to allocate a new buffer.
3661///
3662/// Can be used to check for packet size constraints in serializer without in
3663/// fact serializing the buffer.
3664struct AlwaysFailBufferAlloc;
3665
3666impl LayoutBufferAlloc<!> for AlwaysFailBufferAlloc {
3667    type Error = ();
3668    fn layout_alloc(self, _prefix: usize, _body: usize, _suffix: usize) -> Result<!, Self::Error> {
3669        Err(())
3670    }
3671}
3672
3673/// Drop a packet and undo the effects of parsing it.
3674///
3675/// `drop_packet_and_undo_parse!` takes a `$packet` and a `$buffer` which the
3676/// packet was parsed from. It saves the results of the `src_ip()`, `dst_ip()`,
3677/// `proto()`, and `parse_metadata()` methods. It drops `$packet` and uses the
3678/// result of `parse_metadata()` to undo the effects of parsing the packet.
3679/// Finally, it returns the source IP, destination IP, protocol, and parse
3680/// metadata.
3681macro_rules! drop_packet_and_undo_parse {
3682    ($packet:expr, $buffer:expr) => {{
3683        let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3684        $buffer.undo_parse(meta);
3685        (src_ip, dst_ip, proto, meta)
3686    }};
3687}
3688
3689/// The result of calling [`process_fragment`], depending on what action needs
3690/// to be taken by the caller.
3691enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3692    /// Processing of the packet is complete and no more action should be
3693    /// taken.
3694    Done,
3695
3696    /// Reassembly is not needed. The returned packet is the same one that was
3697    /// passed in the call to [`process_fragment`].
3698    NotNeeded(I::Packet<&'a mut [u8]>),
3699
3700    /// A packet was successfully reassembled into the provided buffer. If a
3701    /// parsed packet is needed, then the caller must perform that parsing.
3702    Reassembled { buffer: Vec<u8>, max_fragment_len: usize },
3703}
3704
3705/// Process a fragment and reassemble if required.
3706///
3707/// Attempts to process a potential fragment packet and reassemble if we are
3708/// ready to do so. Returns an enum to the caller with the result of processing
3709/// the potential fragment.
3710fn process_fragment<'a, I, CC, BC>(
3711    core_ctx: &mut CC,
3712    bindings_ctx: &mut BC,
3713    device: &CC::DeviceId,
3714    packet: I::Packet<&'a mut [u8]>,
3715) -> ProcessFragmentResult<'a, I>
3716where
3717    I: IpLayerIpExt,
3718    for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3719    CC: IpLayerIngressContext<I, BC>,
3720    BC: IpLayerBindingsContext<I, CC::DeviceId>,
3721{
3722    match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3723        // Handle the packet right away since reassembly is not needed.
3724        FragmentProcessingState::NotNeeded(packet) => {
3725            trace!("receive_ip_packet: not fragmented");
3726            ProcessFragmentResult::NotNeeded(packet)
3727        }
3728        // Ready to reassemble a packet.
3729        FragmentProcessingState::Ready { key, packet_len } => {
3730            trace!("receive_ip_packet: fragmented, ready for reassembly");
3731            // Allocate a buffer of `packet_len` bytes.
3732            let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3733
3734            // Attempt to reassemble the packet.
3735            let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3736                core_ctx,
3737                bindings_ctx,
3738                &key,
3739                buffer.buffer_view_mut(),
3740            ) {
3741                // Successfully reassembled the packet, handle it.
3742                Ok(max_fragment_len) => ProcessFragmentResult::Reassembled {
3743                    buffer: buffer.into_inner(),
3744                    max_fragment_len,
3745                },
3746                Err(e) => {
3747                    core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3748                    debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3749                    ProcessFragmentResult::Done
3750                }
3751            };
3752            reassemble_result
3753        }
3754        // Cannot proceed since we need more fragments before we
3755        // can reassemble a packet.
3756        FragmentProcessingState::NeedMoreFragments => {
3757            core_ctx.increment_both(device, |c| &c.need_more_fragments);
3758            trace!("receive_ip_packet: fragmented, need more before reassembly");
3759            ProcessFragmentResult::Done
3760        }
3761        // TODO(ghanan): Handle invalid fragments.
3762        FragmentProcessingState::InvalidFragment => {
3763            core_ctx.increment_both(device, |c| &c.invalid_fragment);
3764            trace!("receive_ip_packet: fragmented, invalid");
3765            ProcessFragmentResult::Done
3766        }
3767        FragmentProcessingState::OutOfMemory => {
3768            core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3769            trace!("receive_ip_packet: fragmented, dropped because OOM");
3770            ProcessFragmentResult::Done
3771        }
3772    }
3773}
3774
3775/// Reassembles an IPv6 atomic fragment.
3776///
3777/// An atomic fragment is a packet with a Fragment header whose Fragment Offset
3778/// and M flag are both zero. Per RFC 8200 Section 4.5:
3779///
3780///   If the fragment is a whole datagram (that is, both the Fragment Offset
3781///   field and the M flag are zero), then it does not need any further
3782///   reassembly and should be processed as a fully reassembled packet (i.e.,
3783///   updating Next Header, adjust Payload Length, removing the Fragment
3784///   header, etc.).
3785///
3786/// On success, returns a buffer containing `packet` with its Fragment header
3787/// removed, along with the length of `packet` to be used as the maximum
3788/// fragment length of the reassembled packet.
3789///
3790/// # Panics
3791///
3792/// Panics if `packet` does not have a Fragment header.
3793fn reassemble_ipv6_atomic_fragment<B: SplitByteSlice>(
3794    packet: &Ipv6Packet<B>,
3795) -> Result<(Vec<u8>, usize), Ipv6ParseError> {
3796    let body = packet.body();
3797    let max_fragment_len = packet.header_len() + body.len();
3798    let header = packet.copy_header_bytes_for_fragment();
3799    let mut buffer = Buf::new(alloc::vec![0; header.len() + body.len()], ..);
3800    Ipv6Packet::reassemble_fragmented_packet(
3801        buffer.buffer_view_mut(),
3802        &header,
3803        core::iter::once(body),
3804    )?;
3805    Ok((buffer.into_inner(), max_fragment_len))
3806}
3807
3808// TODO(joshlf): Can we turn `try_parse_ip_packet` into a function? So far, I've
3809// been unable to get the borrow checker to accept it.
3810
3811/// Try to parse an IP packet from a buffer.
3812///
3813/// If parsing fails, return the buffer to its original state so that its
3814/// contents can be used to send an ICMP error message. When invoked, the macro
3815/// expands to an expression whose type is `Result<P, P::Error>`, where `P` is
3816/// the parsed packet type.
3817macro_rules! try_parse_ip_packet {
3818    ($buffer:expr) => {{
3819        let p_len = $buffer.prefix_len();
3820        let s_len = $buffer.suffix_len();
3821
3822        let result = $buffer.parse_mut();
3823
3824        if let Err(err) = result {
3825            // Revert `buffer` to it's original state.
3826            let n_p_len = $buffer.prefix_len();
3827            let n_s_len = $buffer.suffix_len();
3828
3829            if n_p_len > p_len {
3830                $buffer.grow_front(n_p_len - p_len);
3831            }
3832
3833            if n_s_len > s_len {
3834                $buffer.grow_back(n_s_len - s_len);
3835            }
3836
3837            Err(err)
3838        } else {
3839            result
3840        }
3841    }};
3842}
3843
3844/// Clone an IP packet so that it may be delivered to a multicast route target.
3845///
3846/// Note: We must copy the underlying data here, as the filtering
3847/// engine may uniquely modify each instance as part of
3848/// performing forwarding.
3849///
3850/// In the future there are potential optimizations we could
3851/// pursue, including:
3852///   * Copy-on-write semantics for the buffer/packet so that
3853///     copies of the underlying data are done on an as-needed
3854///     basis.
3855///   * Avoid reparsing the IP packet. Because we're parsing an
3856///     exact copy of a known good packet, it would be safe to
3857///     adopt the data as an IP packet without performing any
3858///     validation.
3859// NB: This is a macro, not a function, because Rust's "move" semantics prevent
3860// us from returning both a buffer and a packet referencing that buffer.
3861macro_rules! clone_packet_for_mcast_forwarding {
3862    {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3863        let mut $new_data = $packet.to_vec();
3864        let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3865        let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3866    };
3867}
3868
3869/// Receive an IPv4 packet from a device.
3870///
3871/// `frame_dst` specifies how this packet was received; see [`FrameDestination`]
3872/// for options.
3873pub fn receive_ipv4_packet<
3874    BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3875    B: BufferMut,
3876    CC: IpLayerIngressContext<Ipv4, BC>,
3877>(
3878    core_ctx: &mut CC,
3879    bindings_ctx: &mut BC,
3880    device: &CC::DeviceId,
3881    frame_dst: Option<LocalFrameDestination>,
3882    device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3883    parsing_context: NetworkParsingContext,
3884    gso_info: Option<GsoInfo>,
3885    buffer: B,
3886) {
3887    if !core_ctx.is_ip_device_enabled(&device) {
3888        return;
3889    }
3890
3891    // This is required because we may need to process the buffer that was
3892    // passed in or a reassembled one, which have different types.
3893    let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3894
3895    core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3896    trace!("receive_ip_packet({device:?})");
3897
3898    let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3899        Ok(packet) => packet,
3900        Err(ParseError::Format)
3901        | Err(ParseError::Checksum)
3902        | Err(ParseError::NotSupported)
3903        | Err(ParseError::NotExpected) => {
3904            core_ctx.increment_both(device, |c| &c.unparsable_packet);
3905            return;
3906        }
3907    };
3908
3909    // We verify these properties later by actually creating the corresponding
3910    // witness types after the INGRESS filtering hook, but we keep these checks
3911    // here as an optimization to return early and save some work.
3912    if packet.src_ipv4().is_none() {
3913        debug!(
3914            "receive_ipv4_packet: received packet from invalid source {}; dropping",
3915            packet.src_ip()
3916        );
3917        core_ctx.increment_both(device, |c| &c.invalid_source);
3918        return;
3919    };
3920    if !packet.dst_ip().is_specified() {
3921        core_ctx.increment_both(device, |c| &c.unspecified_destination);
3922        debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3923        return;
3924    };
3925
3926    // Per RFC 1122, Section 3.2.1.3:
3927    //   Internal host loopback address.  Addresses of this form
3928    //   MUST NOT appear outside a host.
3929    if !device.is_loopback()
3930        && (Ipv4::LOOPBACK_SUBNET.contains(&packet.src_ip())
3931            || Ipv4::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
3932    {
3933        debug!(
3934            "receive_ipv4_packet: received loopback packet (src={}, dst={}) \
3935            on non-loopback interface; dropping",
3936            packet.src_ip(),
3937            packet.dst_ip(),
3938        );
3939        return;
3940    }
3941
3942    // Per RFC 1122 Section 3.2.1.3, broadcast addresses (including limited and
3943    // subnet directed broadcasts) must not be used as source addresses.
3944    if let Some(src_ip) = SpecifiedAddr::new(packet.src_ip()) {
3945        // NOTE: In case the device doesn't have an address, this can only
3946        // detect limited broadcast (255.255.255.255).
3947        let is_broadcast = core_ctx
3948            .address_status_for_device(src_ip, device)
3949            .into_present()
3950            .and_then(|status| status.to_broadcast_marker())
3951            .is_some();
3952
3953        if is_broadcast {
3954            debug!(
3955                "receive_ipv4_packet: received packet from broadcast source {}; dropping",
3956                packet.src_ip()
3957            );
3958            core_ctx.increment_both(device, |c| &c.invalid_source);
3959            return;
3960        }
3961    }
3962
3963    // Reassemble all packets before local delivery or forwarding. Reassembly
3964    // before forwarding is not RFC-compliant, but it's the easiest way to
3965    // ensure that fragments are filtered properly. Linux does this and it
3966    // doesn't seem to create major problems.
3967    //
3968    // TODO(https://fxbug.dev/345814518): Forward fragments without reassembly.
3969    //
3970    // Note, the `process_fragment` function could panic if the packet does not
3971    // have fragment data. However, we are guaranteed that it will not panic
3972    // because the fragment data is in the fixed header so it is always present
3973    // (even if the fragment data has values that implies that the packet is not
3974    // fragmented).
3975    let (mut packet, max_fragment_len) =
3976        match process_fragment(core_ctx, bindings_ctx, device, packet) {
3977            ProcessFragmentResult::Done => return,
3978            ProcessFragmentResult::NotNeeded(packet) => (packet, None),
3979            ProcessFragmentResult::Reassembled { buffer: buf, max_fragment_len } => {
3980                let buf = Buf::new(buf, ..);
3981                buffer = packet::Either::B(buf);
3982
3983                match buffer.parse_mut() {
3984                    Ok(packet) => (packet, Some(max_fragment_len)),
3985                    Err(err) => {
3986                        core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3987                        debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3988                        return;
3989                    }
3990                }
3991            }
3992        };
3993
3994    // TODO(ghanan): Act upon options.
3995
3996    let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3997        core_ctx,
3998        device,
3999        device_ip_layer_metadata,
4000        gso_info,
4001    );
4002    let mut filter = core_ctx.filter_handler();
4003    match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4004        filter::Verdict::Proceed(filter::Accept) => {}
4005        filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4006            packet_metadata.acknowledge_drop();
4007            return;
4008        }
4009        filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4010            addr,
4011            port,
4012        }) => {
4013            // Drop the filter handler since it holds a mutable borrow of `core_ctx`, which
4014            // we need to provide to the packet dispatch function.
4015            drop(filter);
4016
4017            let Some(addr) = SpecifiedAddr::new(addr) else {
4018                core_ctx.increment_both(device, |c| &c.unspecified_destination);
4019                debug!("cannot perform transparent delivery to unspecified destination; dropping");
4020                packet_metadata.acknowledge_drop();
4021                return;
4022            };
4023
4024            let receive_meta = ReceiveIpPacketMeta {
4025                // It's possible that the packet was actually sent to a
4026                // broadcast address, but it doesn't matter here since it's
4027                // being delivered to a transparent proxy.
4028                broadcast: None,
4029                transparent_override: Some(TransparentLocalDelivery { addr, port }),
4030                parsing_context,
4031            };
4032
4033            // Short-circuit the routing process and override local demux, providing a local
4034            // address and port to which the packet should be transparently delivered at the
4035            // transport layer.
4036            dispatch_receive_ipv4_packet(
4037                core_ctx,
4038                bindings_ctx,
4039                device,
4040                frame_dst,
4041                packet,
4042                packet_metadata,
4043                receive_meta,
4044            )
4045            .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4046            return;
4047        }
4048    }
4049    // Drop the filter handler since it holds a mutable borrow of `core_ctx`, which
4050    // we need below.
4051    drop(filter);
4052
4053    let Some(src_ip) = packet.src_ipv4() else {
4054        core_ctx.increment_both(device, |c| &c.invalid_source);
4055        debug!(
4056            "receive_ipv4_packet: received packet from invalid source {}; dropping",
4057            packet.src_ip()
4058        );
4059        packet_metadata.acknowledge_drop();
4060        return;
4061    };
4062
4063    let action = receive_ipv4_packet_action(
4064        core_ctx,
4065        bindings_ctx,
4066        device,
4067        &packet,
4068        frame_dst,
4069        &packet_metadata.marks,
4070        max_fragment_len,
4071    );
4072    match action {
4073        ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4074            // Multicast forwarding replicates a single flow across multiple
4075            // targets. We split the metadata so that marks and socket info are
4076            // preserved for all targets and local delivery. The first target
4077            // takes the unconfirmed conntrack entry to populate the table,
4078            // which subsequent forwards share.
4079            for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4080                clone_packet_for_mcast_forwarding! {
4081                    let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4082                };
4083                let SplitMulticastPacketMetadata { primary: this_packet_metadata, secondary } =
4084                    packet_metadata.split_for_multicast();
4085                packet_metadata = secondary;
4086                determine_ip_packet_forwarding_action::<Ipv4, _, _>(
4087                    core_ctx,
4088                    copy_of_packet,
4089                    this_packet_metadata,
4090                    Some(*min_ttl),
4091                    device,
4092                    &output_interface,
4093                    IpPacketDestination::from_addr(dst_ip),
4094                    frame_dst,
4095                    src_ip,
4096                    dst_ip,
4097                )
4098                .perform_action_with_buffer(
4099                    core_ctx,
4100                    bindings_ctx,
4101                    copy_of_buffer,
4102                    max_fragment_len,
4103                );
4104            }
4105
4106            // If we also have an interest in the packet, deliver it locally.
4107            if let Some(address_status) = address_status {
4108                let receive_meta = ReceiveIpPacketMeta {
4109                    broadcast: address_status.to_broadcast_marker(),
4110                    transparent_override: None,
4111                    parsing_context,
4112                };
4113                dispatch_receive_ipv4_packet(
4114                    core_ctx,
4115                    bindings_ctx,
4116                    device,
4117                    frame_dst,
4118                    packet,
4119                    packet_metadata,
4120                    receive_meta,
4121                )
4122                .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4123            } else {
4124                packet_metadata.acknowledge_drop();
4125            }
4126        }
4127        ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
4128            // NB: when performing internal forwarding, hit the
4129            // forwarding hook.
4130            match internal_forwarding {
4131                InternalForwarding::Used(outbound_device) => {
4132                    core_ctx.increment_both(device, |c| &c.forward);
4133                    match core_ctx.filter_handler().forwarding_hook(
4134                        &mut packet,
4135                        device,
4136                        &outbound_device,
4137                        &mut packet_metadata,
4138                    ) {
4139                        filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4140                            packet_metadata.acknowledge_drop();
4141                            return;
4142                        }
4143                        filter::Verdict::Stop(filter::DropOrReject::Reject(_reject_type)) => {
4144                            // TODO(https://fxbug.dev/466098884): Send reject packet.
4145                            packet_metadata.acknowledge_drop();
4146                            return;
4147                        }
4148                        filter::Verdict::Proceed(filter::Accept) => {}
4149                    }
4150                }
4151                InternalForwarding::NotUsed => {}
4152            }
4153
4154            let receive_meta = ReceiveIpPacketMeta {
4155                broadcast: address_status.to_broadcast_marker(),
4156                transparent_override: None,
4157                parsing_context,
4158            };
4159            dispatch_receive_ipv4_packet(
4160                core_ctx,
4161                bindings_ctx,
4162                device,
4163                frame_dst,
4164                packet,
4165                packet_metadata,
4166                receive_meta,
4167            )
4168            .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4169        }
4170        ReceivePacketAction::Forward {
4171            original_dst,
4172            dst: Destination { device: dst_device, next_hop },
4173        } => {
4174            determine_ip_packet_forwarding_action::<Ipv4, _, _>(
4175                core_ctx,
4176                packet,
4177                packet_metadata,
4178                None,
4179                device,
4180                &dst_device,
4181                IpPacketDestination::from_next_hop(next_hop, original_dst),
4182                frame_dst,
4183                src_ip,
4184                original_dst,
4185            )
4186            .perform_action_with_buffer(
4187                core_ctx,
4188                bindings_ctx,
4189                buffer,
4190                max_fragment_len,
4191            );
4192        }
4193        ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4194            debug!("received IPv4 packet with no known route to destination {}", dst_ip);
4195
4196            let marks = packet_metadata.marks;
4197            packet_metadata.acknowledge_drop();
4198
4199            if let Some(sender) = IcmpErrorSender::new(
4200                core_ctx,
4201                Icmpv4Error::NetUnreachable,
4202                &packet,
4203                frame_dst,
4204                device,
4205                marks,
4206            ) {
4207                sender.send(core_ctx, bindings_ctx, buffer);
4208            }
4209        }
4210        ReceivePacketAction::Drop { reason } => {
4211            let src_ip = packet.src_ip();
4212            let dst_ip = packet.dst_ip();
4213            packet_metadata.acknowledge_drop();
4214            core_ctx.increment_both(device, |c| &c.dropped);
4215            debug!(
4216                "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
4217                {device:?}: {reason:?}",
4218            );
4219        }
4220    }
4221}
4222
4223fn handle_ipv6_parse_error<BC, B, CC>(
4224    core_ctx: &mut CC,
4225    bindings_ctx: &mut BC,
4226    device: &CC::DeviceId,
4227    frame_dst: Option<LocalFrameDestination>,
4228    device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
4229    mut buffer: B,
4230    error: Ipv6ParseError,
4231) where
4232    BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4233    B: BufferMut,
4234    CC: IpLayerIngressContext<Ipv6, BC>,
4235{
4236    // Conditionally send an ICMP response if we encountered a parameter
4237    // problem error when parsing an IPv6 packet. Note, we do not always
4238    // send back an ICMP response as it can be used as an attack vector for
4239    // DDoS attacks. We only send back an ICMP response if the RFC requires
4240    // that we MUST send one, as noted by `must_send_icmp` and `action`.
4241    let Ipv6ParseError::ParameterProblem { src_ip, dst_ip, code, pointer, must_send_icmp, action } =
4242        error
4243    else {
4244        core_ctx.increment_both(device, |c| &c.unparsable_packet);
4245        debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
4246        return;
4247    };
4248    if !must_send_icmp || !action.should_send_icmp(&dst_ip) {
4249        return;
4250    }
4251    core_ctx.increment_both(device, |c| &c.parameter_problem);
4252    let dst_ip = match SocketIpAddr::new(dst_ip) {
4253        Some(ip) => ip,
4254        None => {
4255            core_ctx.increment_both(device, |c| &c.unspecified_destination);
4256            debug!("receive_ipv6_packet: Dropping packet with unspecified destination IP");
4257            return;
4258        }
4259    };
4260
4261    let src_ip = match Ipv6SourceAddr::new(src_ip) {
4262        None => {
4263            core_ctx.increment_both(device, |c| &c.invalid_source);
4264            return;
4265        }
4266        Some(Ipv6SourceAddr::Unspecified) => {
4267            core_ctx.increment_both(device, |c| &c.unspecified_source);
4268            return;
4269        }
4270        Some(Ipv6SourceAddr::Unicast(src_ip)) => {
4271            SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4272        }
4273    };
4274
4275    // Try raw parser to find main packet protocol and body offset. If this
4276    // fails as well then we can't send an ICMP error message.
4277    let raw_packet: Ipv6PacketRaw<_> = match try_parse_ip_packet!(buffer) {
4278        Ok(packet) => packet,
4279        Err(error) => {
4280            core_ctx.increment_both(device, |c| &c.unparsable_packet);
4281            debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
4282            return;
4283        }
4284    };
4285    let proto = match raw_packet.proto() {
4286        Ok(proto) => proto,
4287        Err(error) => {
4288            core_ctx.increment_both(device, |c| &c.unparsable_packet);
4289            debug!("receive_ipv6_packet: Failed to get protocol from IPv6 packet: {:?}", error);
4290            return;
4291        }
4292    };
4293    let parse_metadata = raw_packet.parse_metadata();
4294    let header_len = parse_metadata.header_len();
4295    buffer.undo_parse(parse_metadata);
4296
4297    let err = Icmpv6Error::ParameterProblem {
4298        code,
4299        pointer,
4300        allow_dst_multicast: action.should_send_icmp_to_multicast(),
4301    };
4302
4303    IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4304        core_ctx,
4305        bindings_ctx,
4306        Some(device),
4307        frame_dst,
4308        src_ip,
4309        dst_ip,
4310        buffer,
4311        err,
4312        header_len,
4313        proto,
4314        &device_ip_layer_metadata.marks,
4315    );
4316}
4317
4318/// Receive an IPv6 packet from a device.
4319///
4320/// `frame_dst` specifies how this packet was received; see [`FrameDestination`]
4321/// for options.
4322pub fn receive_ipv6_packet<
4323    BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4324    B: BufferMut,
4325    CC: IpLayerIngressContext<Ipv6, BC>,
4326>(
4327    core_ctx: &mut CC,
4328    bindings_ctx: &mut BC,
4329    device: &CC::DeviceId,
4330    frame_dst: Option<LocalFrameDestination>,
4331    device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
4332    parsing_context: NetworkParsingContext,
4333    gso_info: Option<GsoInfo>,
4334    buffer: B,
4335) {
4336    if !core_ctx.is_ip_device_enabled(&device) {
4337        return;
4338    }
4339
4340    // This is required because we may need to process the buffer that was
4341    // passed in or a reassembled one, which have different types.
4342    let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
4343
4344    core_ctx.increment_both(device, |c| &c.receive_ip_packet);
4345    trace!("receive_ipv6_packet({:?})", device);
4346
4347    let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
4348        Ok(packet) => packet,
4349        Err(error) => {
4350            handle_ipv6_parse_error(
4351                core_ctx,
4352                bindings_ctx,
4353                device,
4354                frame_dst,
4355                device_ip_layer_metadata,
4356                buffer,
4357                error,
4358            );
4359            return;
4360        }
4361    };
4362
4363    trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
4364
4365    // TODO(ghanan): Act upon extension headers.
4366
4367    // We verify these properties later by actually creating the corresponding
4368    // witness types after the INGRESS filtering hook, but we keep these checks
4369    // here as an optimization to return early and save some work.
4370    if packet.src_ipv6().is_none() {
4371        debug!(
4372            "receive_ipv6_packet: received packet from invalid source {}; dropping",
4373            packet.src_ip()
4374        );
4375        core_ctx.increment_both(device, |c| &c.invalid_source);
4376        return;
4377    };
4378    if !packet.dst_ip().is_specified() {
4379        core_ctx.increment_both(device, |c| &c.unspecified_destination);
4380        debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
4381        return;
4382    };
4383
4384    // Per RFC 4291, Section 2.5.3:
4385    //   The loopback address must not be used as the source address in IPv6
4386    //   packets that are sent outside of a single node.  An IPv6 packet with
4387    //   a destination address of loopback must never be sent outside of a
4388    //   single node and must never be forwarded by an IPv6 router.  A packet
4389    //   received on an interface with a destination address of loopback must
4390    //   be dropped.
4391    if !device.is_loopback()
4392        && (Ipv6::LOOPBACK_SUBNET.contains(&packet.src_ip())
4393            || Ipv6::LOOPBACK_SUBNET.contains(&packet.dst_ip()))
4394    {
4395        debug!(
4396            "receive_ipv6_packet: received loopback packet (src={}, dst={}) \
4397            on non-loopback interface; dropping",
4398            packet.src_ip(),
4399            packet.dst_ip(),
4400        );
4401        return;
4402    }
4403
4404    // Reassemble all packets before local delivery or forwarding. Reassembly
4405    // before forwarding is not RFC-compliant, but it's the easiest way to
4406    // ensure that fragments are filtered properly. Linux does this and it
4407    // doesn't seem to create major problems.
4408    //
4409    // TODO(https://fxbug.dev/345814518): Forward fragments without reassembly.
4410    //
4411    // delivery_extension_header_action is used to prevent looking at the
4412    // extension headers twice when a non-fragmented packet is delivered
4413    // locally.
4414    let (mut packet, delivery_extension_header_action, max_fragment_len) =
4415        match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
4416            Ipv6PacketAction::_Discard => {
4417                core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4418                trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
4419                return;
4420            }
4421            Ipv6PacketAction::Continue => {
4422                trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
4423                (packet, Some(Ipv6PacketAction::Continue), None)
4424            }
4425            Ipv6PacketAction::ProcessFragment => {
4426                trace!(
4427                    "receive_ipv6_packet: handled IPv6 extension headers: handling \
4428                    fragmented packet"
4429                );
4430
4431                // Note, `IpPacketFragmentCache::process_fragment`
4432                // could panic if the packet does not have fragment data.
4433                // However, we are guaranteed that it will not panic for an
4434                // IPv6 packet because the fragment data is in an (optional)
4435                // fragment extension header which we attempt to handle by
4436                // calling `ipv6::handle_extension_headers`. We will only
4437                // end up here if its return value is
4438                // `Ipv6PacketAction::ProcessFragment` which is only
4439                // possible when the packet has the fragment extension
4440                // header (even if the fragment data has values that implies
4441                // that the packet is not fragmented).
4442                let (buf, max_fragment_len) =
4443                    match process_fragment(core_ctx, bindings_ctx, device, packet) {
4444                        ProcessFragmentResult::Done => return,
4445                        ProcessFragmentResult::NotNeeded(packet) => {
4446                            // While strange, it's possible for there to be a
4447                            // Fragment header that says the packet doesn't need
4448                            // defragmentation (an atomic fragment). Such a packet
4449                            // must still be processed as a fully reassembled packet,
4450                            // which means removing the Fragment header and parsing
4451                            // any extension headers that follow it, as they are part
4452                            // of the Fragmentable Part of the packet.
4453                            match reassemble_ipv6_atomic_fragment(&packet) {
4454                                Ok(result) => result,
4455                                Err(err) => {
4456                                    core_ctx
4457                                        .increment_both(device, |c| &c.fragment_reassembly_error);
4458                                    debug!(
4459                                        "receive_ip_packet: failed to reassemble atomic \
4460                                        fragment: {:?}",
4461                                        err
4462                                    );
4463                                    return;
4464                                }
4465                            }
4466                        }
4467                        ProcessFragmentResult::Reassembled { buffer: buf, max_fragment_len } => {
4468                            (buf, max_fragment_len)
4469                        }
4470                    };
4471
4472                let buf = Buf::new(buf, ..);
4473                buffer = packet::Either::B(buf);
4474
4475                // Extension headers that follow the Fragment header are only
4476                // parsed after reassembly, so parsing the reassembled packet
4477                // may result in errors that require an ICMP response.
4478                match try_parse_ip_packet!(buffer) {
4479                    Ok(packet) => {
4480                        let packet: Ipv6Packet<_> = packet;
4481                        // Drop reassembled packets that still contain a
4482                        // Fragment header.
4483                        if packet
4484                            .iter_extension_hdrs()
4485                            .any(|h| matches!(h, Ipv6ExtensionHeader::Fragment { .. }))
4486                        {
4487                            core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4488                            debug!(
4489                                "receive_ipv6_packet: found fragment header after reassembly; \
4490                                dropping"
4491                            );
4492                            return;
4493                        }
4494                        (packet, None, Some(max_fragment_len))
4495                    }
4496                    Err(error) => {
4497                        core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4498                        debug!(
4499                            "receive_ip_packet: fragmented, failed to parse reassembled packet: \
4500                            {:?}",
4501                            error
4502                        );
4503                        handle_ipv6_parse_error(
4504                            core_ctx,
4505                            bindings_ctx,
4506                            device,
4507                            frame_dst,
4508                            device_ip_layer_metadata,
4509                            buffer,
4510                            error,
4511                        );
4512                        return;
4513                    }
4514                }
4515            }
4516        };
4517
4518    let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
4519        core_ctx,
4520        device,
4521        device_ip_layer_metadata,
4522        gso_info,
4523    );
4524    let mut filter = core_ctx.filter_handler();
4525
4526    match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4527        filter::Verdict::Proceed(filter::Accept) => {}
4528        filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4529            packet_metadata.acknowledge_drop();
4530            return;
4531        }
4532        filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4533            addr,
4534            port,
4535        }) => {
4536            // Drop the filter handler since it holds a mutable borrow of `core_ctx`, which
4537            // we need to provide to the packet dispatch function.
4538            drop(filter);
4539
4540            let Some(addr) = SpecifiedAddr::new(addr) else {
4541                core_ctx.increment_both(device, |c| &c.unspecified_destination);
4542                debug!("cannot perform transparent delivery to unspecified destination; dropping");
4543                packet_metadata.acknowledge_drop();
4544                return;
4545            };
4546
4547            let receive_meta = ReceiveIpPacketMeta {
4548                broadcast: None,
4549                transparent_override: Some(TransparentLocalDelivery { addr, port }),
4550                parsing_context,
4551            };
4552
4553            // Short-circuit the routing process and override local demux, providing a local
4554            // address and port to which the packet should be transparently delivered at the
4555            // transport layer.
4556            dispatch_receive_ipv6_packet(
4557                core_ctx,
4558                bindings_ctx,
4559                device,
4560                frame_dst,
4561                packet,
4562                packet_metadata,
4563                receive_meta,
4564            )
4565            .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4566            return;
4567        }
4568    }
4569    // Drop the filter handler since it holds a mutable borrow of `core_ctx`, which
4570    // we need below.
4571    drop(filter);
4572
4573    let Some(src_ip) = packet.src_ipv6() else {
4574        debug!(
4575            "receive_ipv6_packet: received packet from invalid source {}; dropping",
4576            packet.src_ip()
4577        );
4578        core_ctx.increment_both(device, |c| &c.invalid_source);
4579        packet_metadata.acknowledge_drop();
4580        return;
4581    };
4582
4583    match receive_ipv6_packet_action(
4584        core_ctx,
4585        bindings_ctx,
4586        device,
4587        &packet,
4588        frame_dst,
4589        &packet_metadata.marks,
4590        max_fragment_len,
4591    ) {
4592        ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4593            // Multicast forwarding replicates a single flow across multiple
4594            // targets. We split the metadata so that marks and socket info are
4595            // preserved for all targets and local delivery. The first target
4596            // takes the unconfirmed conntrack entry to populate the table,
4597            // which subsequent forwards share.
4598            for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4599                clone_packet_for_mcast_forwarding! {
4600                    let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4601                };
4602                let SplitMulticastPacketMetadata { primary: this_packet_metadata, secondary } =
4603                    packet_metadata.split_for_multicast();
4604                packet_metadata = secondary;
4605                determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4606                    core_ctx,
4607                    copy_of_packet,
4608                    this_packet_metadata,
4609                    Some(*min_ttl),
4610                    device,
4611                    &output_interface,
4612                    IpPacketDestination::from_addr(dst_ip),
4613                    frame_dst,
4614                    src_ip,
4615                    dst_ip,
4616                )
4617                .perform_action_with_buffer(
4618                    core_ctx,
4619                    bindings_ctx,
4620                    copy_of_buffer,
4621                    max_fragment_len,
4622                );
4623            }
4624
4625            // If we also have an interest in the packet, deliver it locally.
4626            if let Some(_) = address_status {
4627                let receive_meta = ReceiveIpPacketMeta {
4628                    broadcast: None,
4629                    transparent_override: None,
4630                    parsing_context,
4631                };
4632
4633                dispatch_receive_ipv6_packet(
4634                    core_ctx,
4635                    bindings_ctx,
4636                    device,
4637                    frame_dst,
4638                    packet,
4639                    packet_metadata,
4640                    receive_meta,
4641                )
4642                .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4643            } else {
4644                packet_metadata.acknowledge_drop();
4645            }
4646        }
4647        ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
4648            trace!("receive_ipv6_packet: delivering locally");
4649
4650            let action = if let Some(action) = delivery_extension_header_action {
4651                action
4652            } else {
4653                ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
4654            };
4655            match action {
4656                Ipv6PacketAction::_Discard => {
4657                    core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4658                    trace!(
4659                        "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
4660                    );
4661                    packet_metadata.acknowledge_drop();
4662                }
4663                Ipv6PacketAction::Continue => {
4664                    trace!(
4665                        "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
4666                    );
4667
4668                    // NB: when performing internal forwarding, hit the
4669                    // forwarding hook.
4670                    match internal_forwarding {
4671                        InternalForwarding::Used(outbound_device) => {
4672                            core_ctx.increment_both(device, |c| &c.forward);
4673                            match core_ctx.filter_handler().forwarding_hook(
4674                                &mut packet,
4675                                device,
4676                                &outbound_device,
4677                                &mut packet_metadata,
4678                            ) {
4679                                filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4680                                    packet_metadata.acknowledge_drop();
4681                                    return;
4682                                }
4683                                filter::Verdict::Stop(filter::DropOrReject::Reject(
4684                                    _reject_type,
4685                                )) => {
4686                                    // TODO(https://fxbug.dev/466098884): Send reject packet.
4687                                    packet_metadata.acknowledge_drop();
4688                                    return;
4689                                }
4690                                filter::Verdict::Proceed(filter::Accept) => {}
4691                            }
4692                        }
4693                        InternalForwarding::NotUsed => {}
4694                    }
4695
4696                    let meta = ReceiveIpPacketMeta {
4697                        broadcast: None,
4698                        transparent_override: None,
4699                        parsing_context,
4700                    };
4701                    dispatch_receive_ipv6_packet(
4702                        core_ctx,
4703                        bindings_ctx,
4704                        device,
4705                        frame_dst,
4706                        packet,
4707                        packet_metadata,
4708                        meta,
4709                    )
4710                    .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4711                }
4712                Ipv6PacketAction::ProcessFragment => {
4713                    // Reassembled packets that still contain a Fragment
4714                    // header are dropped immediately after reassembly.
4715                    unreachable!("found fragment header after reassembly")
4716                }
4717            }
4718        }
4719        ReceivePacketAction::Forward {
4720            original_dst,
4721            dst: Destination { device: dst_device, next_hop },
4722        } => {
4723            determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4724                core_ctx,
4725                packet,
4726                packet_metadata,
4727                None,
4728                device,
4729                &dst_device,
4730                IpPacketDestination::from_next_hop(next_hop, original_dst),
4731                frame_dst,
4732                src_ip,
4733                original_dst,
4734            )
4735            .perform_action_with_buffer(
4736                core_ctx,
4737                bindings_ctx,
4738                buffer,
4739                max_fragment_len,
4740            );
4741        }
4742        ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4743            let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
4744                drop_packet_and_undo_parse!(packet, buffer);
4745            debug!("received IPv6 packet with no known route to destination {}", dst_ip);
4746            let marks = packet_metadata.marks;
4747            packet_metadata.acknowledge_drop();
4748
4749            let src_ip = match src_ip {
4750                Ipv6SourceAddr::Unspecified => {
4751                    core_ctx.increment_both(device, |c| &c.unspecified_source);
4752                    return;
4753                }
4754                Ipv6SourceAddr::Unicast(src_ip) => {
4755                    SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4756                }
4757            };
4758
4759            IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4760                core_ctx,
4761                bindings_ctx,
4762                Some(device),
4763                frame_dst,
4764                src_ip,
4765                SocketIpAddr::new_from_witness(dst_ip),
4766                buffer,
4767                Icmpv6Error::NetUnreachable,
4768                meta.header_len(),
4769                proto,
4770                &marks,
4771            );
4772        }
4773        ReceivePacketAction::Drop { reason } => {
4774            core_ctx.increment_both(device, |c| &c.dropped);
4775            let src_ip = packet.src_ip();
4776            let dst_ip = packet.dst_ip();
4777            packet_metadata.acknowledge_drop();
4778            debug!(
4779                "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
4780                {device:?}: {reason:?}",
4781            );
4782        }
4783    }
4784}
4785
4786/// The action to take in order to process a received IP packet.
4787#[derive(Debug, PartialEq)]
4788pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
4789    /// Deliver the packet locally.
4790    Deliver {
4791        /// Status of the receiving IP address.
4792        address_status: I::AddressStatus,
4793        /// `InternalForwarding::Used(d)` if we're delivering the packet as a
4794        /// Weak Host performing internal forwarding via output device `d`.
4795        internal_forwarding: InternalForwarding<DeviceId>,
4796    },
4797
4798    /// Forward the packet to the given destination.
4799    Forward {
4800        /// The original destination IP address of the packet.
4801        original_dst: SpecifiedAddr<I::Addr>,
4802        /// The destination that the packet should be forwarded to.
4803        dst: Destination<I::Addr, DeviceId>,
4804    },
4805
4806    /// A multicast packet that should be forwarded (& optional local delivery).
4807    ///
4808    /// The packet should be forwarded to each of the given targets. This case
4809    /// is only returned when the packet is eligible for multicast forwarding;
4810    /// `Self::Deliver` is used for packets that are ineligible (either because
4811    /// multicast forwarding is disabled, or because there are no applicable
4812    /// multicast routes with which to forward the packet).
4813    MulticastForward {
4814        /// The multicast targets to forward the packet via.
4815        targets: MulticastRouteTargets<DeviceId>,
4816        /// Some if the host is a member of the multicast group and the packet
4817        /// should be delivered locally (in addition to forwarding).
4818        address_status: Option<I::AddressStatus>,
4819        /// The multicast address the packet should be forwarded to.
4820        dst_ip: SpecifiedAddr<I::Addr>,
4821    },
4822
4823    /// Send a Destination Unreachable ICMP error message to the packet's sender
4824    /// and drop the packet.
4825    ///
4826    /// For ICMPv4, use the code "net unreachable". For ICMPv6, use the code "no
4827    /// route to destination".
4828    SendNoRouteToDest {
4829        /// The destination IP Address to which there was no route.
4830        dst: NonMappedAddr<SpecifiedAddr<I::Addr>>,
4831    },
4832
4833    /// Silently drop the packet.
4834    ///
4835    /// `reason` describes why the packet was dropped.
4836    #[allow(missing_docs)]
4837    Drop { reason: DropReason },
4838}
4839
4840// It's possible that there is more than one device with the address
4841// present. Prefer any address status over `UnicastTentative`.
4842fn choose_highest_priority_address_status<I: IpLayerIpExt>(
4843    address_statuses: impl Iterator<Item = I::AddressStatus>,
4844) -> Option<I::AddressStatus> {
4845    address_statuses.max_by_key(|status| {
4846        #[derive(GenericOverIp)]
4847        #[generic_over_ip(I, Ip)]
4848        struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
4849        I::map_ip_in(
4850            Wrap(status),
4851            |Wrap(v4_status)| match v4_status {
4852                Ipv4PresentAddressStatus::UnicastTentative => 0,
4853                _ => 1,
4854            },
4855            |Wrap(v6_status)| match v6_status {
4856                Ipv6PresentAddressStatus::UnicastTentative => 0,
4857                _ => 1,
4858            },
4859        )
4860    })
4861}
4862
4863/// The reason a received IP packet is dropped.
4864#[derive(Debug, PartialEq)]
4865pub enum DropReason {
4866    /// Remote packet destined to tentative address.
4867    Tentative,
4868    /// Remote packet destined to the unspecified address.
4869    UnspecifiedDestination,
4870    /// Remote packet with an invalid destination address.
4871    InvalidDestination,
4872    /// Cannot forward a packet with unspecified source address.
4873    ForwardUnspecifiedSource,
4874    /// Cannot forward a packet with link-local source or destination address.
4875    ForwardLinkLocal,
4876    /// Packet should be forwarded but packet's inbound interface has forwarding
4877    /// disabled.
4878    ForwardingDisabledInboundIface,
4879    /// Remote packet destined to a multicast address that could not be:
4880    /// * delivered locally (because we are not a member of the multicast
4881    ///   group), or
4882    /// * forwarded (either because multicast forwarding is disabled, or no
4883    ///   applicable multicast route has been installed).
4884    MulticastNoInterest,
4885}
4886
4887/// Computes the action to take in order to process a received IPv4 packet.
4888pub fn receive_ipv4_packet_action<BC, CC, B>(
4889    core_ctx: &mut CC,
4890    bindings_ctx: &mut BC,
4891    device: &CC::DeviceId,
4892    packet: &Ipv4Packet<B>,
4893    frame_dst: Option<LocalFrameDestination>,
4894    marks: &Marks,
4895    max_fragment_len: Option<usize>,
4896) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4897where
4898    BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4899    CC: IpLayerContext<Ipv4, BC>,
4900    B: SplitByteSlice,
4901{
4902    let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4903        core_ctx.increment_both(device, |c| &c.unspecified_destination);
4904        return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4905    };
4906
4907    // If the packet arrived at the loopback interface, check if any local
4908    // interface has the destination address assigned. This effectively lets the
4909    // loopback interface operate as a weak host for incoming packets.
4910    //
4911    // Note that (as of writing) the stack sends all locally destined traffic to
4912    // the loopback interface so we need this hack to allow the stack to accept
4913    // packets that arrive at the loopback interface (after being looped back)
4914    // but destined to an address that is assigned to another local interface.
4915    //
4916    // TODO(https://fxbug.dev/42065870): This should instead be controlled by
4917    // the routing table.
4918
4919    let highest_priority = if device.is_loopback() {
4920        core_ctx.with_address_statuses(dst_ip, |it| {
4921            let it = it.map(|(_device, status)| status);
4922            choose_highest_priority_address_status::<Ipv4>(it)
4923        })
4924    } else {
4925        core_ctx.address_status_for_device(dst_ip, device).into_present()
4926    };
4927    match highest_priority {
4928        Some(
4929            address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4930            | Ipv4PresentAddressStatus::LoopbackSubnet),
4931        ) => {
4932            core_ctx.increment_both(device, |c| &c.deliver_unicast);
4933            ReceivePacketAction::Deliver {
4934                address_status,
4935                internal_forwarding: InternalForwarding::NotUsed,
4936            }
4937        }
4938        Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4939            // If the destination address is tentative (which implies that
4940            // we are still performing Duplicate Address Detection on
4941            // it), then we don't consider the address "assigned to an
4942            // interface", and so we drop packets instead of delivering them
4943            // locally.
4944            core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4945            ReceivePacketAction::Drop { reason: DropReason::Tentative }
4946        }
4947
4948        Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4949            receive_ip_multicast_packet_action(
4950                core_ctx,
4951                bindings_ctx,
4952                device,
4953                packet,
4954                Some(address_status),
4955                dst_ip,
4956                frame_dst,
4957                *marks,
4958                max_fragment_len,
4959            )
4960        }
4961        Some(
4962            address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4963            | Ipv4PresentAddressStatus::SubnetBroadcast),
4964        ) => {
4965            core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4966            ReceivePacketAction::Deliver {
4967                address_status,
4968                internal_forwarding: InternalForwarding::NotUsed,
4969            }
4970        }
4971        None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4972            core_ctx,
4973            bindings_ctx,
4974            dst_ip,
4975            device,
4976            packet,
4977            frame_dst,
4978            marks,
4979            max_fragment_len,
4980        ),
4981    }
4982}
4983
4984/// Computes the action to take in order to process a received IPv6 packet.
4985pub fn receive_ipv6_packet_action<BC, CC, B>(
4986    core_ctx: &mut CC,
4987    bindings_ctx: &mut BC,
4988    device: &CC::DeviceId,
4989    packet: &Ipv6Packet<B>,
4990    frame_dst: Option<LocalFrameDestination>,
4991    marks: &Marks,
4992    max_fragment_len: Option<usize>,
4993) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4994where
4995    BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4996    CC: IpLayerContext<Ipv6, BC>,
4997    B: SplitByteSlice,
4998{
4999    let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
5000        core_ctx.increment_both(device, |c| &c.unspecified_destination);
5001        return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
5002    };
5003
5004    // If the packet arrived at the loopback interface, check if any local
5005    // interface has the destination address assigned. This effectively lets
5006    // the loopback interface operate as a weak host for incoming packets.
5007    //
5008    // Note that (as of writing) the stack sends all locally destined traffic to
5009    // the loopback interface so we need this hack to allow the stack to accept
5010    // packets that arrive at the loopback interface (after being looped back)
5011    // but destined to an address that is assigned to another local interface.
5012    //
5013    // TODO(https://fxbug.dev/42175703): This should instead be controlled by the
5014    // routing table.
5015
5016    let highest_priority = if device.is_loopback() {
5017        core_ctx.with_address_statuses(dst_ip, |it| {
5018            let it = it.map(|(_device, status)| status);
5019            choose_highest_priority_address_status::<Ipv6>(it)
5020        })
5021    } else {
5022        core_ctx.address_status_for_device(dst_ip, device).into_present()
5023    };
5024    match highest_priority {
5025        Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
5026            receive_ip_multicast_packet_action(
5027                core_ctx,
5028                bindings_ctx,
5029                device,
5030                packet,
5031                Some(address_status),
5032                dst_ip,
5033                frame_dst,
5034                *marks,
5035                max_fragment_len,
5036            )
5037        }
5038        Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
5039            core_ctx.increment_both(device, |c| &c.deliver_unicast);
5040            ReceivePacketAction::Deliver {
5041                address_status,
5042                internal_forwarding: InternalForwarding::NotUsed,
5043            }
5044        }
5045        Some(Ipv6PresentAddressStatus::UnicastTentative) => {
5046            // If the destination address is tentative (which implies that
5047            // we are still performing NDP's Duplicate Address Detection on
5048            // it), then we don't consider the address "assigned to an
5049            // interface", and so we drop packets instead of delivering them
5050            // locally.
5051            //
5052            // As per RFC 4862 section 5.4:
5053            //
5054            //   An address on which the Duplicate Address Detection
5055            //   procedure is applied is said to be tentative until the
5056            //   procedure has completed successfully. A tentative address
5057            //   is not considered "assigned to an interface" in the
5058            //   traditional sense.  That is, the interface must accept
5059            //   Neighbor Solicitation and Advertisement messages containing
5060            //   the tentative address in the Target Address field, but
5061            //   processes such packets differently from those whose Target
5062            //   Address matches an address assigned to the interface. Other
5063            //   packets addressed to the tentative address should be
5064            //   silently discarded. Note that the "other packets" include
5065            //   Neighbor Solicitation and Advertisement messages that have
5066            //   the tentative (i.e., unicast) address as the IP destination
5067            //   address and contain the tentative address in the Target
5068            //   Address field.  Such a case should not happen in normal
5069            //   operation, though, since these messages are multicasted in
5070            //   the Duplicate Address Detection procedure.
5071            //
5072            // That is, we accept no packets destined to a tentative
5073            // address. NS and NA packets should be addressed to a multicast
5074            // address that we would have joined during DAD so that we can
5075            // receive those packets.
5076            core_ctx.increment_both(device, |c| &c.drop_for_tentative);
5077            ReceivePacketAction::Drop { reason: DropReason::Tentative }
5078        }
5079        None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
5080            core_ctx,
5081            bindings_ctx,
5082            dst_ip,
5083            device,
5084            packet,
5085            frame_dst,
5086            marks,
5087            max_fragment_len,
5088        ),
5089    }
5090}
5091
5092/// Computes the action to take for multicast packets on behalf of
5093/// [`receive_ipv4_packet_action`] and [`receive_ipv6_packet_action`].
5094fn receive_ip_multicast_packet_action<
5095    I: IpLayerIpExt,
5096    B: SplitByteSlice,
5097    BC: IpLayerBindingsContext<I, CC::DeviceId>,
5098    CC: IpLayerContext<I, BC>,
5099>(
5100    core_ctx: &mut CC,
5101    bindings_ctx: &mut BC,
5102    device: &CC::DeviceId,
5103    packet: &I::Packet<B>,
5104    address_status: Option<I::AddressStatus>,
5105    dst_ip: SpecifiedAddr<I::Addr>,
5106    frame_dst: Option<LocalFrameDestination>,
5107    marks: Marks,
5108    max_fragment_len: Option<usize>,
5109) -> ReceivePacketAction<I, CC::DeviceId> {
5110    let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
5111        core_ctx,
5112        bindings_ctx,
5113        packet,
5114        device,
5115        frame_dst,
5116        max_fragment_len,
5117        marks,
5118    );
5119    match (targets, address_status) {
5120        (Some(targets), address_status) => {
5121            if address_status.is_some() {
5122                core_ctx.increment_both(device, |c| &c.deliver_multicast);
5123            }
5124            ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
5125        }
5126        (None, Some(address_status)) => {
5127            // If the address was present on the device (e.g. the host is a
5128            // member of the multicast group), fallback to local delivery.
5129            core_ctx.increment_both(device, |c| &c.deliver_multicast);
5130            ReceivePacketAction::Deliver {
5131                address_status,
5132                internal_forwarding: InternalForwarding::NotUsed,
5133            }
5134        }
5135        (None, None) => {
5136            // As per RFC 1122 Section 3.2.2
5137            //   An ICMP error message MUST NOT be sent as the result of
5138            //   receiving:
5139            //   ...
5140            //   * a datagram destined to an IP broadcast or IP multicast
5141            //     address
5142            //
5143            // As such, drop the packet
5144            core_ctx.increment_both(device, |c| &c.multicast_no_interest);
5145            ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
5146        }
5147    }
5148}
5149
5150/// Computes the remaining protocol-agnostic actions on behalf of
5151/// [`receive_ipv4_packet_action`] and [`receive_ipv6_packet_action`].
5152fn receive_ip_packet_action_common<
5153    I: IpLayerIpExt,
5154    B: SplitByteSlice,
5155    BC: IpLayerBindingsContext<I, CC::DeviceId>,
5156    CC: IpLayerContext<I, BC>,
5157>(
5158    core_ctx: &mut CC,
5159    bindings_ctx: &mut BC,
5160    dst_ip: SpecifiedAddr<I::Addr>,
5161    device_id: &CC::DeviceId,
5162    packet: &I::Packet<B>,
5163    frame_dst: Option<LocalFrameDestination>,
5164    marks: &Marks,
5165    max_fragment_len: Option<usize>,
5166) -> ReceivePacketAction<I, CC::DeviceId> {
5167    if dst_ip.is_multicast() {
5168        return receive_ip_multicast_packet_action(
5169            core_ctx,
5170            bindings_ctx,
5171            device_id,
5172            packet,
5173            None,
5174            dst_ip,
5175            frame_dst,
5176            *marks,
5177            max_fragment_len,
5178        );
5179    }
5180
5181    // Don't allow mapped IPv6 addresses.
5182    let Some(dst_ip) = NonMappedAddr::new(dst_ip) else {
5183        return ReceivePacketAction::Drop { reason: DropReason::InvalidDestination };
5184    };
5185
5186    // The packet is not destined locally, so we attempt to forward it.
5187    if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
5188        // Forwarding is disabled; we are operating only as a host.
5189        //
5190        // For IPv4, per RFC 1122 Section 3.2.1.3, "A host MUST silently discard
5191        // an incoming datagram that is not destined for the host."
5192        //
5193        // For IPv6, per RFC 4443 Section 3.1, the only instance in which a host
5194        // sends an ICMPv6 Destination Unreachable message is when a packet is
5195        // destined to that host but on an unreachable port (Code 4 - "Port
5196        // unreachable"). Since the only sensible error message to send in this
5197        // case is a Destination Unreachable message, we interpret the RFC text
5198        // to mean that, consistent with IPv4's behavior, we should silently
5199        // discard the packet in this case.
5200        core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
5201        return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
5202    }
5203    // Per https://www.rfc-editor.org/rfc/rfc4291.html#section-2.5.2:
5204    //   An IPv6 packet with a source address of unspecified must never be forwarded by an IPv6
5205    //   router.
5206    // Per https://datatracker.ietf.org/doc/html/rfc1812#section-5.3.7:
5207    //   A router SHOULD NOT forward any packet that has an invalid IP source address or a source
5208    //   address on network 0
5209    let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
5210        return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
5211    };
5212
5213    // If forwarding is enabled, allow local delivery if the packet is destined
5214    // for an IP assigned to a different interface.
5215    //
5216    // This enables a weak host model when the Netstack is configured as a
5217    // router. Conceptually, the netstack is forwarding the packet from the
5218    // input device, to the destination IP's device.
5219    if let Some(dst_ip) = NonMulticastAddr::new(dst_ip) {
5220        if let Some((outbound_device, address_status)) =
5221            get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
5222        {
5223            return ReceivePacketAction::Deliver {
5224                address_status,
5225                internal_forwarding: InternalForwarding::Used(outbound_device),
5226            };
5227        }
5228    }
5229
5230    // For IPv4, RFC 3927 Section 2.7 states:
5231    //
5232    //   An IPv4 packet whose source and/or destination address is in the
5233    //   169.254/16 prefix MUST NOT be sent to any router for forwarding, and
5234    //   any network device receiving such a packet MUST NOT forward it,
5235    //   regardless of the TTL in the IPv4 header.
5236    //
5237    // However, to maintain behavioral similarity to both gVisor/Netstack2 and
5238    // Linux, we omit this check.
5239    //
5240    // For IPv6, RFC 4291 Section 2.5.6 states:
5241    //
5242    //   Routers must not forward any packets with Link-Local source or
5243    //   destination addresses to other links.
5244    if I::map_ip_in(
5245        &packet,
5246        |_| false,
5247        |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
5248    ) {
5249        return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
5250    }
5251
5252    match lookup_route_table(
5253        core_ctx,
5254        dst_ip.get(),
5255        RuleInput {
5256            packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
5257            marks,
5258        },
5259    ) {
5260        Some(dst) => {
5261            core_ctx.increment_both(device_id, |c| &c.forward);
5262            ReceivePacketAction::Forward { original_dst: *dst_ip, dst }
5263        }
5264        None => {
5265            core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
5266            ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
5267        }
5268    }
5269}
5270
5271// Look up the route to a host.
5272fn lookup_route_table<
5273    I: IpLayerIpExt,
5274    BC: IpLayerBindingsContext<I, CC::DeviceId>,
5275    CC: IpStateContext<I, BC>,
5276>(
5277    core_ctx: &mut CC,
5278    dst_ip: I::Addr,
5279    rule_input: RuleInput<'_, I, CC::DeviceId>,
5280) -> Option<Destination<I::Addr, CC::DeviceId>> {
5281    let bound_device = match rule_input.packet_origin {
5282        PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
5283        PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
5284    };
5285    core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
5286        match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
5287            match table.lookup(core_ctx, bound_device, dst_ip) {
5288                Some(dst) => ControlFlow::Break(Some(dst)),
5289                None => ControlFlow::Continue(()),
5290            }
5291        }) {
5292            ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
5293                inner: dst,
5294                observed_source_address_matcher: _,
5295            })) => dst,
5296            ControlFlow::Break(RuleAction::Unreachable) => None,
5297            ControlFlow::Continue(RuleWalkInfo {
5298                inner: (),
5299                observed_source_address_matcher: _,
5300            }) => None,
5301        }
5302    })
5303}
5304
5305/// Packed destination passed to [`IpDeviceSendContext::send_ip_frame`].
5306#[derive(Debug, Derivative, Clone)]
5307#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
5308pub enum IpPacketDestination<I: BroadcastIpExt, D> {
5309    /// Broadcast packet.
5310    Broadcast(I::BroadcastMarker),
5311
5312    /// Multicast packet to the specified IP.
5313    Multicast(MulticastAddr<I::Addr>),
5314
5315    /// Send packet to the neighbor with the specified IP (the receiving
5316    /// node is either a router or the final recipient of the packet).
5317    Neighbor(SpecifiedAddr<I::Addr>),
5318
5319    /// Loopback the packet to the specified device. Can be used only when
5320    /// sending to the loopback device.
5321    Loopback(D),
5322}
5323
5324impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
5325    /// Creates `IpPacketDestination` for IP address.
5326    pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
5327        match MulticastAddr::new(addr.into_addr()) {
5328            Some(mc_addr) => Self::Multicast(mc_addr),
5329            None => Self::Neighbor(addr),
5330        }
5331    }
5332
5333    /// Create `IpPacketDestination` from `NextHop`.
5334    pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
5335        match next_hop {
5336            NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
5337            NextHop::Gateway(gateway) => Self::Neighbor(gateway),
5338            NextHop::Broadcast(marker) => Self::Broadcast(marker),
5339        }
5340    }
5341}
5342
5343/// The metadata associated with an outgoing IP packet.
5344#[derive(Debug, Clone)]
5345pub struct SendIpPacketMeta<I: IpExt, D, Src> {
5346    /// The outgoing device.
5347    pub device: D,
5348
5349    /// The source address of the packet.
5350    pub src_ip: Src,
5351
5352    /// The destination address of the packet.
5353    pub dst_ip: SpecifiedAddr<I::Addr>,
5354
5355    /// The destination for the send operation.
5356    pub destination: IpPacketDestination<I, D>,
5357
5358    /// The upper-layer protocol held in the packet's payload.
5359    pub proto: I::Proto,
5360
5361    /// The time-to-live (IPv4) or hop limit (IPv6) for the packet.
5362    ///
5363    /// If not set, a default TTL may be used.
5364    pub ttl: Option<NonZeroU8>,
5365
5366    /// An MTU to artificially impose on the whole IP packet.
5367    ///
5368    /// Note that the device's and discovered path MTU may still be imposed on
5369    /// the packet.
5370    pub mtu: Mtu,
5371
5372    /// Traffic Class (IPv6) or Type of Service (IPv4) field for the packet.
5373    pub dscp_and_ecn: DscpAndEcn,
5374}
5375
5376impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5377    for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
5378{
5379    fn from(
5380        SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
5381            I,
5382            D,
5383            SpecifiedAddr<I::Addr>,
5384        >,
5385    ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
5386        SendIpPacketMeta {
5387            device,
5388            src_ip: Some(src_ip),
5389            dst_ip,
5390            destination,
5391            proto,
5392            ttl,
5393            mtu,
5394            dscp_and_ecn,
5395        }
5396    }
5397}
5398
5399/// Trait for abstracting the IP layer for locally-generated traffic.  That is,
5400/// traffic generated by the netstack itself (e.g. ICMP, IGMP, or MLD).
5401///
5402/// NOTE: Due to filtering rules, it is possible that the device provided in
5403/// `meta` will not be the device that final IP packet is actually sent from.
5404pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + GsoIpExt + FilterIpExt, BC>:
5405    DeviceIdContext<AnyDevice>
5406{
5407    /// Encapsulate and send the provided transport packet and from the device
5408    /// provided in `meta`.
5409    fn send_ip_packet_from_device<S>(
5410        &mut self,
5411        bindings_ctx: &mut BC,
5412        meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
5413        body: S,
5414    ) -> Result<(), IpSendFrameError<S>>
5415    where
5416        S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
5417        S::Buffer: BufferMut;
5418
5419    /// Send an IP packet that doesn't require the encapsulation and other
5420    /// processing of [`send_ip_packet_from_device`] from the device specified
5421    /// in `meta`.
5422    // TODO(https://fxbug.dev/333908066): The packets going through this
5423    // function only hit the EGRESS filter hook, bypassing LOCAL_EGRESS.
5424    // Refactor callers and other functions to prevent this.
5425    fn send_ip_frame<S>(
5426        &mut self,
5427        bindings_ctx: &mut BC,
5428        device: &Self::DeviceId,
5429        destination: IpPacketDestination<I, &Self::DeviceId>,
5430        body: S,
5431    ) -> Result<(), IpSendFrameError<S>>
5432    where
5433        S: FragmentableIpSerializer<I, Buffer: BufferMut>
5434            + MaybeSegmentableIpSerializer<I>
5435            + FilterIpPacket<I>;
5436}
5437
5438impl<I, BC, CC> IpLayerHandler<I, BC> for CC
5439where
5440    I: IpLayerIpExt,
5441    BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
5442    CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
5443{
5444    fn send_ip_packet_from_device<S>(
5445        &mut self,
5446        bindings_ctx: &mut BC,
5447        meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
5448        body: S,
5449    ) -> Result<(), IpSendFrameError<S>>
5450    where
5451        S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
5452        S::Buffer: BufferMut,
5453    {
5454        send_ip_packet_from_device(
5455            self,
5456            bindings_ctx,
5457            meta,
5458            body,
5459            IpLayerPacketMetadata::new_local_tx(Default::default(), Default::default(), None),
5460        )
5461    }
5462
5463    fn send_ip_frame<S>(
5464        &mut self,
5465        bindings_ctx: &mut BC,
5466        device: &Self::DeviceId,
5467        destination: IpPacketDestination<I, &Self::DeviceId>,
5468        body: S,
5469    ) -> Result<(), IpSendFrameError<S>>
5470    where
5471        S: FragmentableIpSerializer<I, Buffer: BufferMut>
5472            + MaybeSegmentableIpSerializer<I>
5473            + FilterIpPacket<I>,
5474    {
5475        send_ip_frame(
5476            self,
5477            bindings_ctx,
5478            device,
5479            destination,
5480            body,
5481            IpLayerPacketMetadata::new_local_tx(Default::default(), Default::default(), None),
5482            Mtu::no_limit(),
5483        )
5484    }
5485}
5486
5487/// Sends an Ip packet with the specified metadata.
5488///
5489/// # Panics
5490///
5491/// Panics if either the source or destination address is the loopback address
5492/// and the device is a non-loopback device.
5493pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
5494    core_ctx: &mut CC,
5495    bindings_ctx: &mut BC,
5496    meta: SendIpPacketMeta<
5497        I,
5498        &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
5499        Option<SpecifiedAddr<I::Addr>>,
5500    >,
5501    body: S,
5502    packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
5503) -> Result<(), IpSendFrameError<S>>
5504where
5505    I: IpLayerIpExt,
5506    BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
5507    CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
5508    S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
5509    S::Buffer: BufferMut,
5510{
5511    let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
5512        meta;
5513    core_ctx.increment_both(device, |c| &c.send_ip_packet);
5514    let next_packet_id = gen_ip_packet_id(core_ctx);
5515    let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
5516    let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
5517    let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
5518
5519    #[derive(GenericOverIp)]
5520    #[generic_over_ip(I, Ip)]
5521    struct Wrap<'a, I: IpLayerIpExt> {
5522        builder: &'a mut I::PacketBuilder<NetworkSerializationContext>,
5523        next_packet_id: I::PacketId,
5524    }
5525
5526    I::map_ip::<_, ()>(
5527        Wrap { builder: &mut builder, next_packet_id },
5528        |Wrap { builder, next_packet_id }| {
5529            builder.id(next_packet_id);
5530        },
5531        |Wrap { builder: _, next_packet_id: () }| {
5532            // IPv6 doesn't have packet IDs.
5533        },
5534    );
5535
5536    builder.set_dscp_and_ecn(dscp_and_ecn);
5537
5538    let ip_frame = builder.wrap_body(body);
5539    send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
5540        .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
5541}
5542
5543/// Abstracts access to a [`filter::FilterHandler`] for core contexts.
5544pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
5545    IpDeviceAddressIdContext<I, DeviceId: netstack3_base::InterfaceProperties<BT::DeviceClass>>
5546{
5547    /// The filter handler.
5548    type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
5549    where
5550        Self: 'a;
5551
5552    /// Gets the filter handler for this context.
5553    fn filter_handler(&mut self) -> Self::Handler<'_>;
5554}
5555
5556#[cfg(any(test, feature = "testutils"))]
5557pub(crate) mod testutil {
5558    use super::*;
5559
5560    use netstack3_base::testutil::{FakeBindingsCtx, FakeCoreCtx, FakeStrongDeviceId};
5561    use netstack3_base::{
5562        AssignedAddrIpExt, NetworkSerializer, SendFrameContext, SendFrameError, SendableFrameMeta,
5563    };
5564
5565    /// A [`SendIpPacketMeta`] for dual stack contextx.
5566    #[derive(Debug, GenericOverIp)]
5567    #[generic_over_ip()]
5568    #[allow(missing_docs)]
5569    pub enum DualStackSendIpPacketMeta<D> {
5570        V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
5571        V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
5572    }
5573
5574    impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5575        for DualStackSendIpPacketMeta<D>
5576    {
5577        fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
5578            #[derive(GenericOverIp)]
5579            #[generic_over_ip(I, Ip)]
5580            struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
5581            use DualStackSendIpPacketMeta::*;
5582            I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
5583        }
5584    }
5585
5586    impl<I: IpExt, S, DeviceId, BC>
5587        SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
5588        for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
5589    {
5590        fn send_meta<SS>(
5591            self,
5592            core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
5593            bindings_ctx: &mut BC,
5594            frame: SS,
5595        ) -> Result<(), SendFrameError<SS>>
5596        where
5597            SS: NetworkSerializer,
5598            SS::Buffer: BufferMut,
5599        {
5600            SendFrameContext::send_frame(
5601                &mut core_ctx.frames,
5602                bindings_ctx,
5603                DualStackSendIpPacketMeta::from(self),
5604                frame,
5605            )
5606        }
5607    }
5608
5609    /// Error returned when the IP version doesn't match.
5610    #[derive(Debug)]
5611    pub struct WrongIpVersion;
5612
5613    impl<D> DualStackSendIpPacketMeta<D> {
5614        /// Returns the internal [`SendIpPacketMeta`] if this is carrying the
5615        /// version matching `I`.
5616        pub fn try_as<I: IpExt>(
5617            &self,
5618        ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
5619            #[derive(GenericOverIp)]
5620            #[generic_over_ip(I, Ip)]
5621            struct Wrap<'a, I: IpExt, D>(
5622                Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
5623            );
5624            use DualStackSendIpPacketMeta::*;
5625            let Wrap(dual_stack) = I::map_ip(
5626                self,
5627                |value| {
5628                    Wrap(match value {
5629                        V4(meta) => Some(meta),
5630                        V6(_) => None,
5631                    })
5632                },
5633                |value| {
5634                    Wrap(match value {
5635                        V4(_) => None,
5636                        V6(meta) => Some(meta),
5637                    })
5638                },
5639            );
5640            dual_stack.ok_or(WrongIpVersion)
5641        }
5642    }
5643
5644    impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
5645    where
5646        I: AssignedAddrIpExt + FilterIpExt,
5647        BC: FilterBindingsContext<DeviceId>,
5648        DeviceId: FakeStrongDeviceId + netstack3_base::InterfaceProperties<BC::DeviceClass>,
5649    {
5650        type Handler<'a>
5651            = filter::testutil::NoopImpl<DeviceId>
5652        where
5653            Self: 'a;
5654
5655        fn filter_handler(&mut self) -> Self::Handler<'_> {
5656            filter::testutil::NoopImpl::default()
5657        }
5658    }
5659
5660    impl<TimerId, Event: Debug, State, FrameMeta> MarksBindingsContext
5661        for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
5662    {
5663        fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
5664            const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
5665            &MARKS
5666        }
5667
5668        fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
5669            const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
5670            &MARKS
5671        }
5672    }
5673}
5674
5675#[cfg(test)]
5676mod test {
5677    use super::*;
5678
5679    #[test]
5680    fn highest_priority_address_status_v4() {
5681        // Prefer assigned addresses over tentative addresses.
5682        assert_eq!(
5683            choose_highest_priority_address_status::<Ipv4>(
5684                [
5685                    Ipv4PresentAddressStatus::UnicastAssigned,
5686                    Ipv4PresentAddressStatus::UnicastTentative
5687                ]
5688                .into_iter()
5689            ),
5690            Some(Ipv4PresentAddressStatus::UnicastAssigned)
5691        )
5692    }
5693
5694    #[test]
5695    fn highest_priority_address_status_v6() {
5696        // Prefer assigned addresses over tentative addresses.
5697        assert_eq!(
5698            choose_highest_priority_address_status::<Ipv6>(
5699                [
5700                    Ipv6PresentAddressStatus::UnicastAssigned,
5701                    Ipv6PresentAddressStatus::UnicastTentative
5702                ]
5703                .into_iter()
5704            ),
5705            Some(Ipv6PresentAddressStatus::UnicastAssigned)
5706        )
5707    }
5708}