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