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