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