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 on
1410    // an interface, and an egress interface wasn't specifically selected, route
1411    // via the loopback device. This lets us operate as a strong host when an
1412    // outgoing interface is explicitly requested while still enabling local
1413    // delivery via the loopback interface, which is acting as a weak host. Note
1414    // that if the loopback interface is requested as an outgoing interface,
1415    // route selection is still performed as a strong host! This makes the
1416    // loopback interface behave more like the other interfaces on the system.
1417    //
1418    // TODO(https://fxbug.dev/42065870): Encode the delivery of locally-
1419    // destined packets to loopback in the route table.
1420    //
1421    // TODO(https://fxbug.dev/322539434): Linux is more permissive about
1422    // allowing cross-device local delivery even when SO_BINDTODEVICE or
1423    // link-local addresses are involved, and this behavior may need to be
1424    // emulated.
1425    let local_delivery_instructions: Option<LocalDelivery<IpDeviceAddr<I::Addr>, CC::DeviceId>> = {
1426        let dst_ip = dst_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr);
1427        match (device, dst_ip) {
1428            (Some(device), Some(dst_ip)) => is_local_assigned_address(core_ctx, device, dst_ip)
1429                .then_some(LocalDelivery::StrongForDevice(device.clone())),
1430            (None, Some(dst_ip)) => {
1431                get_device_with_assigned_address(core_ctx, dst_ip).map(
1432                    |(dst_device, _addr_status)| {
1433                        // If either the source or destination addresses needs
1434                        // a zone ID, then use strong host to enforce that the
1435                        // source and destination addresses are assigned to the
1436                        // same interface.
1437                        if src_ip_and_policy
1438                            .is_some_and(|(ip, _policy)| ip.as_ref().must_have_zone())
1439                            || dst_ip.as_ref().must_have_zone()
1440                        {
1441                            LocalDelivery::StrongForDevice(dst_device)
1442                        } else {
1443                            LocalDelivery::WeakLoopback { dst_ip, device: dst_device }
1444                        }
1445                    },
1446                )
1447            }
1448            (_, None) => None,
1449        }
1450    };
1451
1452    if let Some(local_delivery) = local_delivery_instructions {
1453        let loopback = core_ctx.loopback_id().ok_or(ResolveRouteError::Unreachable)?;
1454
1455        let (src_addr, dest_device) = match local_delivery {
1456            LocalDelivery::WeakLoopback { dst_ip, device } => {
1457                let src_ip = match src_ip_and_policy {
1458                    Some((src_ip, NonLocalSrcAddrPolicy::Deny)) => {
1459                        let _device = get_device_with_assigned_address(core_ctx, src_ip)
1460                            .ok_or(ResolveRouteError::NoSrcAddr)?;
1461                        src_ip
1462                    }
1463                    Some((src_ip, NonLocalSrcAddrPolicy::Allow)) => src_ip,
1464                    None => dst_ip,
1465                };
1466                (src_ip, device)
1467            }
1468            LocalDelivery::StrongForDevice(device) => {
1469                (get_local_addr(core_ctx, src_ip_and_policy, &device, dst_ip)?, device)
1470            }
1471        };
1472        return Ok(ResolvedRoute {
1473            src_addr,
1474            local_delivery_device: Some(dest_device),
1475            device: loopback,
1476            next_hop: NextHop::RemoteAsNeighbor,
1477            internal_forwarding: InternalForwarding::NotUsed,
1478        });
1479    }
1480    let bound_address = src_ip_and_policy.map(|(sock_addr, _policy)| sock_addr.into_inner().get());
1481    let rule_input = RuleInput {
1482        packet_origin: PacketOrigin::Local { bound_address, bound_device: device },
1483        marks,
1484    };
1485    core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
1486        let mut walk_rules = |rule_input, src_ip_and_policy| {
1487            walk_rules(
1488                core_ctx,
1489                rules,
1490                None, /* first error encountered */
1491                rule_input,
1492                |first_error, core_ctx, table| {
1493                    let mut matching_with_addr = table.lookup_filter_map(
1494                        core_ctx,
1495                        device,
1496                        dst_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.addr()),
1497                        |core_ctx, d| {
1498                            Some(get_local_addr_with_internal_forwarding(
1499                                core_ctx,
1500                                src_ip_and_policy,
1501                                d,
1502                                dst_ip,
1503                            ))
1504                        },
1505                    );
1506
1507                    let first_error_in_this_table = match matching_with_addr.next() {
1508                        Some((
1509                            Destination { device, next_hop },
1510                            Ok((local_addr, internal_forwarding)),
1511                        )) => {
1512                            return ControlFlow::Break(Ok((
1513                                Destination { device: device.clone(), next_hop },
1514                                local_addr,
1515                                internal_forwarding,
1516                            )));
1517                        }
1518                        Some((_, Err(e))) => e,
1519                        // Note: rule evaluation will continue on to the next rule, if the
1520                        // previous rule was `Lookup` but the table didn't have the route
1521                        // inside of it.
1522                        None => return ControlFlow::Continue(first_error),
1523                    };
1524
1525                    matching_with_addr
1526                        .filter_map(|(destination, local_addr)| {
1527                            // Select successful routes. We ignore later errors
1528                            // since we've already saved the first one.
1529                            local_addr.ok_checked::<ResolveRouteError>().map(
1530                                |(local_addr, internal_forwarding)| {
1531                                    (destination, local_addr, internal_forwarding)
1532                                },
1533                            )
1534                        })
1535                        .next()
1536                        .map_or(
1537                            ControlFlow::Continue(first_error.or(Some(first_error_in_this_table))),
1538                            |(
1539                                Destination { device, next_hop },
1540                                local_addr,
1541                                internal_forwarding,
1542                            )| {
1543                                ControlFlow::Break(Ok((
1544                                    Destination { device: device.clone(), next_hop },
1545                                    local_addr,
1546                                    internal_forwarding,
1547                                )))
1548                            },
1549                        )
1550                },
1551            )
1552        };
1553
1554        let result = match walk_rules(&rule_input, src_ip_and_policy) {
1555            // Only try to resolve a route again if all of the following are true:
1556            // 1. The source address is not provided by the caller.
1557            // 2. A route is successfully resolved so we selected a source address.
1558            // 3. There is a rule with a source address matcher during the resolution.
1559            // The rationale is to make sure the route resolution converges to a sensible route
1560            // after considering the source address we select.
1561            ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1562                inner: Ok((_dst, selected_src_addr, _internal_forwarding)),
1563                observed_source_address_matcher: true,
1564            })) if src_ip_and_policy.is_none() => walk_rules(
1565                &RuleInput {
1566                    packet_origin: PacketOrigin::Local {
1567                        bound_address: Some(selected_src_addr.into()),
1568                        bound_device: device,
1569                    },
1570                    marks,
1571                },
1572                Some((selected_src_addr, NonLocalSrcAddrPolicy::Deny)),
1573            ),
1574            result => result,
1575        };
1576
1577        match result {
1578            ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
1579                inner: result,
1580                observed_source_address_matcher: _,
1581            })) => {
1582                result.map(|(Destination { device, next_hop }, src_addr, internal_forwarding)| {
1583                    ResolvedRoute {
1584                        src_addr,
1585                        device,
1586                        local_delivery_device: None,
1587                        next_hop,
1588                        internal_forwarding,
1589                    }
1590                })
1591            }
1592            ControlFlow::Break(RuleAction::Unreachable) => Err(ResolveRouteError::Unreachable),
1593            ControlFlow::Continue(RuleWalkInfo {
1594                inner: first_error,
1595                observed_source_address_matcher: _,
1596            }) => Err(first_error.unwrap_or(ResolveRouteError::Unreachable)),
1597        }
1598    })
1599}
1600
1601/// Enables a blanket implementation of [`IpSocketContext`].
1602///
1603/// Implementing this marker trait for a type enables a blanket implementation
1604/// of `IpSocketContext` given the other requirements are met.
1605pub trait UseIpSocketContextBlanket {}
1606
1607impl<I, BC, CC> IpSocketContext<I, BC> for CC
1608where
1609    I: Ip + IpDeviceStateIpExt + IpDeviceIpExt + IpLayerIpExt,
1610    BC: IpDeviceBindingsContext<I, CC::DeviceId>
1611        + IpLayerBindingsContext<I, CC::DeviceId>
1612        + IpSocketBindingsContext<CC::DeviceId>,
1613    CC: IpLayerEgressContext<I, BC>
1614        + IpStateContext<I, BC>
1615        + IpDeviceContext<I>
1616        + IpDeviceConfirmReachableContext<I, BC>
1617        + IpDeviceMtuContext<I>
1618        + device::IpDeviceConfigurationContext<I, BC>
1619        + IcmpErrorHandler<I, BC>
1620        + UseIpSocketContextBlanket,
1621{
1622    fn lookup_route(
1623        &mut self,
1624        _bindings_ctx: &mut BC,
1625        device: Option<&CC::DeviceId>,
1626        local_ip: Option<IpDeviceAddr<I::Addr>>,
1627        addr: RoutableIpAddr<I::Addr>,
1628        transparent: bool,
1629        marks: &Marks,
1630    ) -> Result<ResolvedRoute<I, CC::DeviceId>, ResolveRouteError> {
1631        let src_ip_and_policy = local_ip.map(|local_ip| {
1632            (
1633                local_ip,
1634                if transparent {
1635                    NonLocalSrcAddrPolicy::Allow
1636                } else {
1637                    NonLocalSrcAddrPolicy::Deny
1638                },
1639            )
1640        });
1641        let res =
1642            resolve_output_route_to_destination(self, device, src_ip_and_policy, Some(addr), marks);
1643        trace!(
1644            "lookup_route(\
1645                device={device:?}, \
1646                local_ip={local_ip:?}, \
1647                addr={addr:?}, \
1648                transparent={transparent:?}, \
1649                marks={marks:?}) => {res:?}"
1650        );
1651        res
1652    }
1653
1654    fn send_ip_packet<S>(
1655        &mut self,
1656        bindings_ctx: &mut BC,
1657        meta: SendIpPacketMeta<
1658            I,
1659            &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
1660            SpecifiedAddr<I::Addr>,
1661        >,
1662        body: S,
1663        packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
1664    ) -> Result<(), IpSendFrameError<S>>
1665    where
1666        S: TransportPacketSerializer<I>,
1667        S::Buffer: BufferMut,
1668    {
1669        send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
1670    }
1671
1672    fn get_loopback_device(&mut self) -> Option<Self::DeviceId> {
1673        device::IpDeviceConfigurationContext::<I, _>::loopback_id(self)
1674    }
1675
1676    fn confirm_reachable(
1677        &mut self,
1678        bindings_ctx: &mut BC,
1679        dst: SpecifiedAddr<I::Addr>,
1680        input: RuleInput<'_, I, Self::DeviceId>,
1681    ) {
1682        match lookup_route_table(self, dst.get(), input) {
1683            Some(Destination { next_hop, device }) => {
1684                let neighbor = match next_hop {
1685                    NextHop::RemoteAsNeighbor => dst,
1686                    NextHop::Gateway(gateway) => gateway,
1687                    NextHop::Broadcast(marker) => {
1688                        I::map_ip::<_, ()>(
1689                            WrapBroadcastMarker(marker),
1690                            |WrapBroadcastMarker(())| {
1691                                debug!(
1692                                    "can't confirm {dst:?}@{device:?} as reachable: \
1693                                    dst is a broadcast address"
1694                                );
1695                            },
1696                            |WrapBroadcastMarker(never)| match never {},
1697                        );
1698                        return;
1699                    }
1700                };
1701                IpDeviceConfirmReachableContext::confirm_reachable(
1702                    self,
1703                    bindings_ctx,
1704                    &device,
1705                    neighbor,
1706                );
1707            }
1708            None => {
1709                debug!("can't confirm {dst:?} as reachable: no route");
1710            }
1711        }
1712    }
1713}
1714
1715/// Trait that provides basic socket information for types that carry a socket
1716/// ID.
1717pub trait SocketMetadata<CC>
1718where
1719    CC: ?Sized,
1720{
1721    /// Returns Socket cookie for the socket.
1722    fn socket_cookie(&self, core_ctx: &mut CC) -> SocketCookie;
1723    /// Returns Socket Marks.
1724    fn marks(&self, core_ctx: &mut CC) -> Marks;
1725}
1726
1727impl<T, O, CC> SocketMetadata<CC> for EitherStack<T, O>
1728where
1729    CC: ?Sized,
1730    T: SocketMetadata<CC>,
1731    O: SocketMetadata<CC>,
1732{
1733    fn socket_cookie(&self, core_ctx: &mut CC) -> SocketCookie {
1734        match self {
1735            Self::ThisStack(t) => t.socket_cookie(core_ctx),
1736            Self::OtherStack(o) => o.socket_cookie(core_ctx),
1737        }
1738    }
1739
1740    fn marks(&self, core_ctx: &mut CC) -> Marks {
1741        match self {
1742            Self::ThisStack(t) => t.marks(core_ctx),
1743            Self::OtherStack(o) => o.marks(core_ctx),
1744        }
1745    }
1746}
1747
1748/// The IP context providing dispatch to the available transport protocols.
1749///
1750/// This trait acts like a demux on the transport protocol for ingress IP
1751/// packets.
1752pub trait IpTransportDispatchContext<I: IpLayerIpExt, BC>: DeviceIdContext<AnyDevice> {
1753    /// Early Demux result.
1754    type EarlyDemuxSocket: SocketMetadata<Self>;
1755
1756    /// Performs early demux result.
1757    fn early_demux<B: ParseBuffer>(
1758        &mut self,
1759        device: &Self::DeviceId,
1760        frame_dst: Option<FrameDestination>,
1761        src_ip: I::Addr,
1762        dst_ip: I::Addr,
1763        proto: I::Proto,
1764        body: B,
1765    ) -> Option<Self::EarlyDemuxSocket>;
1766
1767    /// Dispatches a received incoming IP packet to the appropriate protocol.
1768    /// In case of a failure returns the kind of the ICMP error that should be
1769    /// sent back to the source.
1770    fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1771        &mut self,
1772        bindings_ctx: &mut BC,
1773        device: &Self::DeviceId,
1774        src_ip: I::RecvSrcAddr,
1775        dst_ip: SpecifiedAddr<I::Addr>,
1776        proto: I::Proto,
1777        body: B,
1778        info: &LocalDeliveryPacketInfo<I, H>,
1779        early_demux_socket: Option<Self::EarlyDemuxSocket>,
1780    ) -> Result<(), I::IcmpError>;
1781}
1782
1783/// A marker trait for all the contexts required for IP ingress.
1784pub trait IpLayerIngressContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1785    IpTransportDispatchContext<
1786        I,
1787        BC,
1788        DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1789    > + IpDeviceIngressStateContext<I>
1790    + IpDeviceMtuContext<I>
1791    + IpDeviceSendContext<I, BC>
1792    + IcmpErrorHandler<I, BC>
1793    + IpLayerContext<I, BC>
1794    + FragmentHandler<I, BC>
1795    + FilterHandlerProvider<I, BC>
1796    + RawIpSocketHandler<I, BC>
1797{
1798}
1799
1800impl<
1801    I: IpLayerIpExt,
1802    BC: IpLayerBindingsContext<I, CC::DeviceId>,
1803    CC: IpTransportDispatchContext<
1804            I,
1805            BC,
1806            DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>,
1807        > + IpDeviceIngressStateContext<I>
1808        + IpDeviceMtuContext<I>
1809        + IpDeviceSendContext<I, BC>
1810        + IcmpErrorHandler<I, BC>
1811        + IpLayerContext<I, BC>
1812        + FragmentHandler<I, BC>
1813        + FilterHandlerProvider<I, BC>
1814        + RawIpSocketHandler<I, BC>,
1815> IpLayerIngressContext<I, BC> for CC
1816{
1817}
1818
1819/// A marker trait for all the contexts required for IP egress.
1820pub trait IpLayerEgressContext<I, BC>:
1821    IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1822    + FilterHandlerProvider<I, BC>
1823    + ResourceCounterContext<Self::DeviceId, IpCounters<I>>
1824where
1825    I: IpLayerIpExt,
1826    BC: FilterBindingsContext<Self::DeviceId> + TxMetadataBindingsTypes,
1827{
1828}
1829
1830impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
1831where
1832    I: IpLayerIpExt,
1833    BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes,
1834    CC: IpDeviceSendContext<I, BC, DeviceId: netstack3_base::InterfaceProperties<BC::DeviceClass>>
1835        + FilterHandlerProvider<I, BC>
1836        + ResourceCounterContext<Self::DeviceId, IpCounters<I>>,
1837{
1838}
1839
1840/// A marker trait for all the contexts required for IP forwarding.
1841pub trait IpLayerForwardingContext<I: IpLayerIpExt, BC: IpLayerBindingsContext<I, Self::DeviceId>>:
1842    IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>
1843{
1844}
1845
1846impl<
1847    I: IpLayerIpExt,
1848    BC: IpLayerBindingsContext<I, CC::DeviceId>,
1849    CC: IpLayerEgressContext<I, BC> + IcmpErrorHandler<I, BC> + IpDeviceMtuContext<I>,
1850> IpLayerForwardingContext<I, BC> for CC
1851{
1852}
1853
1854/// A builder for IPv4 state.
1855#[derive(Copy, Clone, Default)]
1856pub struct Ipv4StateBuilder {
1857    icmp: Icmpv4StateBuilder,
1858}
1859
1860impl Ipv4StateBuilder {
1861    /// Get the builder for the ICMPv4 state.
1862    #[cfg(any(test, feature = "testutils"))]
1863    pub fn icmpv4_builder(&mut self) -> &mut Icmpv4StateBuilder {
1864        &mut self.icmp
1865    }
1866
1867    /// Builds the [`Ipv4State`].
1868    pub fn build<
1869        CC: CoreTimerContext<IpLayerTimerId, BC>,
1870        StrongDeviceId: StrongDeviceIdentifier,
1871        BC: TimerContext + RngContext + IpLayerBindingsTypes,
1872    >(
1873        self,
1874        bindings_ctx: &mut BC,
1875    ) -> Ipv4State<StrongDeviceId, BC> {
1876        let Ipv4StateBuilder { icmp } = self;
1877
1878        Ipv4State {
1879            inner: IpStateInner::new::<CC>(bindings_ctx),
1880            icmp: icmp.build(),
1881            next_packet_id: Default::default(),
1882        }
1883    }
1884}
1885
1886/// A builder for IPv6 state.
1887///
1888/// By default, opaque IIDs will not be used to generate stable SLAAC addresses.
1889#[derive(Copy, Clone)]
1890pub struct Ipv6StateBuilder {
1891    icmp: Icmpv6StateBuilder,
1892    slaac_stable_secret_key: Option<IidSecret>,
1893}
1894
1895impl Ipv6StateBuilder {
1896    /// Sets the secret key used to generate stable SLAAC addresses.
1897    ///
1898    /// If `slaac_stable_secret_key` is left unset, opaque IIDs will not be used to
1899    /// generate stable SLAAC addresses.
1900    pub fn slaac_stable_secret_key(&mut self, secret_key: IidSecret) -> &mut Self {
1901        self.slaac_stable_secret_key = Some(secret_key);
1902        self
1903    }
1904
1905    /// Builds the [`Ipv6State`].
1906    ///
1907    /// # Panics
1908    ///
1909    /// Panics if the `slaac_stable_secret_key` has not been set.
1910    pub fn build<
1911        CC: CoreTimerContext<IpLayerTimerId, BC>,
1912        StrongDeviceId: StrongDeviceIdentifier,
1913        BC: TimerContext + RngContext + IpLayerBindingsTypes,
1914    >(
1915        self,
1916        bindings_ctx: &mut BC,
1917    ) -> Ipv6State<StrongDeviceId, BC> {
1918        let Ipv6StateBuilder { icmp, slaac_stable_secret_key } = self;
1919
1920        let slaac_stable_secret_key = slaac_stable_secret_key
1921            .expect("stable SLAAC secret key was not provided to `Ipv6StateBuilder`");
1922
1923        Ipv6State {
1924            inner: IpStateInner::new::<CC>(bindings_ctx),
1925            icmp: icmp.build(),
1926            slaac_counters: Default::default(),
1927            slaac_temp_secret_key: IidSecret::new_random(&mut bindings_ctx.rng()),
1928            slaac_stable_secret_key,
1929        }
1930    }
1931}
1932
1933impl Default for Ipv6StateBuilder {
1934    fn default() -> Self {
1935        #[cfg(any(test, feature = "testutils"))]
1936        let slaac_stable_secret_key = Some(IidSecret::ALL_ONES);
1937
1938        #[cfg(not(any(test, feature = "testutils")))]
1939        let slaac_stable_secret_key = None;
1940
1941        Self { icmp: Icmpv6StateBuilder::default(), slaac_stable_secret_key }
1942    }
1943}
1944
1945/// The stack's IPv4 state.
1946pub struct Ipv4State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1947    /// The common inner IP layer state.
1948    pub inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
1949    /// The ICMP state.
1950    pub icmp: Icmpv4State<BT>,
1951    /// The atomic counter providing IPv4 packet identifiers.
1952    pub next_packet_id: AtomicU16,
1953}
1954
1955impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1956    AsRef<IpStateInner<Ipv4, StrongDeviceId, BT>> for Ipv4State<StrongDeviceId, BT>
1957{
1958    fn as_ref(&self) -> &IpStateInner<Ipv4, StrongDeviceId, BT> {
1959        &self.inner
1960    }
1961}
1962
1963/// Generates an IP packet ID.
1964///
1965/// This is only meaningful for IPv4, see [`IpLayerIpExt`].
1966pub fn gen_ip_packet_id<I: IpLayerIpExt, CC: IpDeviceEgressStateContext<I>>(
1967    core_ctx: &mut CC,
1968) -> I::PacketId {
1969    core_ctx.with_next_packet_id(|state| I::next_packet_id_from_state(state))
1970}
1971
1972/// The stack's IPv6 state.
1973pub struct Ipv6State<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes> {
1974    /// The common inner IP layer state.
1975    pub inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
1976    /// ICMPv6 state.
1977    pub icmp: Icmpv6State<BT>,
1978    /// Stateless address autoconfiguration counters.
1979    pub slaac_counters: SlaacCounters,
1980    /// Secret key used for generating SLAAC temporary addresses.
1981    pub slaac_temp_secret_key: IidSecret,
1982    /// Secret key used for generating SLAAC stable addresses.
1983    ///
1984    /// If `None`, opaque IIDs will not be used to generate stable SLAAC
1985    /// addresses.
1986    pub slaac_stable_secret_key: IidSecret,
1987}
1988
1989impl<StrongDeviceId: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1990    AsRef<IpStateInner<Ipv6, StrongDeviceId, BT>> for Ipv6State<StrongDeviceId, BT>
1991{
1992    fn as_ref(&self) -> &IpStateInner<Ipv6, StrongDeviceId, BT> {
1993        &self.inner
1994    }
1995}
1996
1997impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
1998    OrderedLockAccess<IpPacketFragmentCache<I, BT>> for IpStateInner<I, D, BT>
1999{
2000    type Lock = Mutex<IpPacketFragmentCache<I, BT>>;
2001    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2002        OrderedLockRef::new(&self.fragment_cache)
2003    }
2004}
2005
2006impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2007    OrderedLockAccess<PmtuCache<I, BT>> for IpStateInner<I, D, BT>
2008{
2009    type Lock = Mutex<PmtuCache<I, BT>>;
2010    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2011        OrderedLockRef::new(&self.pmtu_cache)
2012    }
2013}
2014
2015impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2016    OrderedLockAccess<RulesTable<I, D, BT>> for IpStateInner<I, D, BT>
2017{
2018    type Lock = RwLock<RulesTable<I, D, BT>>;
2019    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2020        OrderedLockRef::new(&self.rules_table)
2021    }
2022}
2023
2024impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2025    OrderedLockAccess<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>
2026    for IpStateInner<I, D, BT>
2027{
2028    type Lock =
2029        Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>;
2030    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2031        OrderedLockRef::new(&self.tables)
2032    }
2033}
2034
2035impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpRoutingBindingsTypes>
2036    OrderedLockAccess<RoutingTable<I, D>> for RoutingTableId<I, D, BT>
2037{
2038    type Lock = RwLock<RoutingTable<I, D>>;
2039    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2040        let Self(inner) = self;
2041        OrderedLockRef::new(&inner.routing_table)
2042    }
2043}
2044
2045impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2046    OrderedLockAccess<MulticastForwardingState<I, D, BT>> for IpStateInner<I, D, BT>
2047{
2048    type Lock = RwLock<MulticastForwardingState<I, D, BT>>;
2049    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2050        OrderedLockRef::new(&self.multicast_forwarding)
2051    }
2052}
2053
2054impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2055    OrderedLockAccess<RawIpSocketMap<I, D::Weak, BT>> for IpStateInner<I, D, BT>
2056{
2057    type Lock = RwLock<RawIpSocketMap<I, D::Weak, BT>>;
2058    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2059        OrderedLockRef::new(&self.raw_sockets)
2060    }
2061}
2062
2063impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpLayerBindingsTypes>
2064    OrderedLockAccess<filter::State<I, WeakAddressId<I, BT>, BT>> for IpStateInner<I, D, BT>
2065{
2066    type Lock = RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>;
2067    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
2068        OrderedLockRef::new(&self.filter)
2069    }
2070}
2071
2072/// Marker trait for the bindings types required by the IP layer's inner state.
2073pub trait IpStateBindingsTypes:
2074    PmtuBindingsTypes
2075    + FragmentBindingsTypes
2076    + RawIpSocketsBindingsTypes
2077    + FilterBindingsTypes
2078    + MulticastForwardingBindingsTypes
2079    + IpDeviceStateBindingsTypes
2080    + IpRoutingBindingsTypes
2081{
2082}
2083impl<BT> IpStateBindingsTypes for BT where
2084    BT: PmtuBindingsTypes
2085        + FragmentBindingsTypes
2086        + RawIpSocketsBindingsTypes
2087        + FilterBindingsTypes
2088        + MulticastForwardingBindingsTypes
2089        + IpDeviceStateBindingsTypes
2090        + IpRoutingBindingsTypes
2091{
2092}
2093
2094/// Bindings ID for a routing table.
2095#[derive(Derivative)]
2096#[derivative(Debug(bound = ""))]
2097#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2098pub enum RoutingTableCookie<BT: IpRoutingBindingsTypes> {
2099    /// Main table.
2100    Main,
2101    /// A table added by user (Bindings).
2102    BindingsId(BT::RoutingTableId),
2103}
2104
2105/// State for a routing table.
2106#[derive(Derivative)]
2107#[derivative(Debug(bound = "D: Debug"))]
2108pub struct BaseRoutingTableState<I: Ip, D, BT: IpRoutingBindingsTypes> {
2109    routing_table: RwLock<RoutingTable<I, D>>,
2110    bindings_id: RoutingTableCookie<BT>,
2111}
2112
2113impl<I: Ip, D, BT: IpRoutingBindingsTypes> BaseRoutingTableState<I, D, BT> {
2114    pub(crate) fn with_bindings_id(bindings_id: RoutingTableCookie<BT>) -> Self {
2115        Self { bindings_id, routing_table: Default::default() }
2116    }
2117}
2118
2119/// Identifier to a routing table.
2120#[derive(Derivative)]
2121#[derivative(PartialEq(bound = ""))]
2122#[derivative(Eq(bound = ""))]
2123#[derivative(Hash(bound = ""))]
2124#[derivative(Clone(bound = ""))]
2125pub struct RoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes>(
2126    StrongRc<BaseRoutingTableState<I, D, BT>>,
2127);
2128
2129impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for RoutingTableId<I, D, BT> {
2130    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2131        let Self(rc) = self;
2132        f.debug_tuple("RoutingTableId").field(&I::NAME).field(&rc.bindings_id).finish()
2133    }
2134}
2135
2136impl<I: Ip, D, BT: IpRoutingBindingsTypes> RoutingTableId<I, D, BT> {
2137    /// Creates a new table ID.
2138    pub(crate) fn new(rc: StrongRc<BaseRoutingTableState<I, D, BT>>) -> Self {
2139        Self(rc)
2140    }
2141
2142    /// Provides direct access to the forwarding table.
2143    #[cfg(any(test, feature = "testutils"))]
2144    pub fn table(&self) -> &RwLock<RoutingTable<I, D>> {
2145        let Self(inner) = self;
2146        &inner.routing_table
2147    }
2148
2149    /// Downgrades the strong ID into a weak one.
2150    pub fn downgrade(&self) -> WeakRoutingTableId<I, D, BT>
2151    where
2152        BT::RoutingTableId: Clone,
2153    {
2154        let Self(rc) = self;
2155        WeakRoutingTableId { rc: StrongRc::downgrade(rc), bindings_id: rc.bindings_id.clone() }
2156    }
2157
2158    #[cfg(test)]
2159    fn get_mut(&self) -> impl DerefMut<Target = RoutingTable<I, D>> + '_ {
2160        let Self(rc) = self;
2161        rc.routing_table.write()
2162    }
2163
2164    /// Gets the bindings cookie for this routing table.
2165    pub fn bindings_id(&self) -> &RoutingTableCookie<BT> {
2166        let Self(rc) = self;
2167        &rc.bindings_id
2168    }
2169}
2170
2171/// Weak Identifier to a routing table.
2172#[derive(Derivative)]
2173#[derivative(Clone(bound = "BT::RoutingTableId: Clone"))]
2174#[derivative(PartialEq, Eq, Hash)]
2175pub struct WeakRoutingTableId<I: Ip, D, BT: IpRoutingBindingsTypes> {
2176    rc: WeakRc<BaseRoutingTableState<I, D, BT>>,
2177    #[derivative(PartialEq = "ignore")]
2178    #[derivative(Hash = "ignore")]
2179    bindings_id: RoutingTableCookie<BT>,
2180}
2181
2182impl<I: Ip, D, BT: IpRoutingBindingsTypes> Debug for WeakRoutingTableId<I, D, BT> {
2183    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2184        let Self { bindings_id, .. } = self;
2185        f.debug_tuple("WeakRoutingTableId").field(&I::NAME).field(bindings_id).finish()
2186    }
2187}
2188
2189/// The inner state for the IP layer for IP version `I`.
2190#[derive(GenericOverIp)]
2191#[generic_over_ip(I, Ip)]
2192pub struct IpStateInner<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> {
2193    rules_table: RwLock<RulesTable<I, D, BT>>,
2194    // TODO(https://fxbug.dev/355059838): Explore the option to let Bindings create the main table.
2195    main_table_id: RoutingTableId<I, D, BT>,
2196    multicast_forwarding: RwLock<MulticastForwardingState<I, D, BT>>,
2197    multicast_forwarding_counters: MulticastForwardingCounters<I>,
2198    fragment_cache: Mutex<IpPacketFragmentCache<I, BT>>,
2199    pmtu_cache: Mutex<PmtuCache<I, BT>>,
2200    counters: IpCounters<I>,
2201    raw_sockets: RwLock<RawIpSocketMap<I, D::Weak, BT>>,
2202    raw_socket_counters: RawIpSocketCounters<I>,
2203    filter: RwLock<filter::State<I, WeakAddressId<I, BT>, BT>>,
2204    // Make sure the primary IDs are dropped last. Also note that the following hash map also stores
2205    // the primary ID to the main table, and if the user (Bindings) attempts to remove the main
2206    // table without dropping `main_table_id` first, it will panic. This serves as an assertion
2207    // that the main table cannot be removed and Bindings must never attempt to remove the main
2208    // routing table.
2209    tables: Mutex<HashMap<RoutingTableId<I, D, BT>, PrimaryRc<BaseRoutingTableState<I, D, BT>>>>,
2210    igmp_counters: IgmpCounters,
2211    mld_counters: MldCounters,
2212}
2213
2214impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: IpStateBindingsTypes> IpStateInner<I, D, BT> {
2215    /// Gets the IP counters.
2216    pub fn counters(&self) -> &IpCounters<I> {
2217        &self.counters
2218    }
2219
2220    /// Gets the multicast forwarding counters.
2221    pub fn multicast_forwarding_counters(&self) -> &MulticastForwardingCounters<I> {
2222        &self.multicast_forwarding_counters
2223    }
2224
2225    /// Gets the aggregate raw IP socket counters.
2226    pub fn raw_ip_socket_counters(&self) -> &RawIpSocketCounters<I> {
2227        &self.raw_socket_counters
2228    }
2229
2230    /// Gets the main table ID.
2231    pub fn main_table_id(&self) -> &RoutingTableId<I, D, BT> {
2232        &self.main_table_id
2233    }
2234
2235    /// Provides direct access to the path MTU cache.
2236    #[cfg(any(test, feature = "testutils"))]
2237    pub fn pmtu_cache(&self) -> &Mutex<PmtuCache<I, BT>> {
2238        &self.pmtu_cache
2239    }
2240
2241    /// Provides direct access to the filtering state.
2242    #[cfg(any(test, feature = "testutils"))]
2243    pub fn filter(&self) -> &RwLock<filter::State<I, WeakAddressId<I, BT>, BT>> {
2244        &self.filter
2245    }
2246
2247    /// Gets the stack-wide IGMP counters.
2248    pub fn igmp_counters(&self) -> &IgmpCounters {
2249        &self.igmp_counters
2250    }
2251
2252    /// Gets the stack-wide MLD counters.
2253    pub fn mld_counters(&self) -> &MldCounters {
2254        &self.mld_counters
2255    }
2256}
2257
2258impl<
2259    I: IpLayerIpExt,
2260    D: StrongDeviceIdentifier,
2261    BC: TimerContext + RngContext + IpStateBindingsTypes + IpRoutingBindingsTypes,
2262> IpStateInner<I, D, BC>
2263{
2264    /// Creates a new inner IP layer state.
2265    fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
2266        let main_table: PrimaryRc<BaseRoutingTableState<I, D, BC>> =
2267            PrimaryRc::new(BaseRoutingTableState::with_bindings_id(RoutingTableCookie::Main));
2268        let main_table_id = RoutingTableId(PrimaryRc::clone_strong(&main_table));
2269        Self {
2270            rules_table: RwLock::new(RulesTable::new(main_table_id.clone())),
2271            tables: Mutex::new(HashMap::from_iter(core::iter::once((
2272                main_table_id.clone(),
2273                main_table,
2274            )))),
2275            main_table_id,
2276            multicast_forwarding: Default::default(),
2277            multicast_forwarding_counters: Default::default(),
2278            fragment_cache: Mutex::new(
2279                IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
2280            ),
2281            pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2282            counters: Default::default(),
2283            raw_sockets: Default::default(),
2284            raw_socket_counters: Default::default(),
2285            filter: RwLock::new(filter::State::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
2286            igmp_counters: Default::default(),
2287            mld_counters: Default::default(),
2288        }
2289    }
2290}
2291
2292/// The identifier for timer events in the IP layer.
2293#[derive(Debug, Clone, Eq, PartialEq, Hash, GenericOverIp)]
2294#[generic_over_ip()]
2295pub enum IpLayerTimerId {
2296    /// A timer event for IPv4 packet reassembly timers.
2297    ReassemblyTimeoutv4(FragmentTimerId<Ipv4>),
2298    /// A timer event for IPv6 packet reassembly timers.
2299    ReassemblyTimeoutv6(FragmentTimerId<Ipv6>),
2300    /// A timer event for IPv4 path MTU discovery.
2301    PmtuTimeoutv4(PmtuTimerId<Ipv4>),
2302    /// A timer event for IPv6 path MTU discovery.
2303    PmtuTimeoutv6(PmtuTimerId<Ipv6>),
2304    /// A timer event for IPv4 filtering timers.
2305    FilterTimerv4(FilterTimerId<Ipv4>),
2306    /// A timer event for IPv6 filtering timers.
2307    FilterTimerv6(FilterTimerId<Ipv6>),
2308    /// A timer event for IPv4 Multicast forwarding timers.
2309    MulticastForwardingTimerv4(MulticastForwardingTimerId<Ipv4>),
2310    /// A timer event for IPv6 Multicast forwarding timers.
2311    MulticastForwardingTimerv6(MulticastForwardingTimerId<Ipv6>),
2312}
2313
2314impl<I: Ip> From<FragmentTimerId<I>> for IpLayerTimerId {
2315    fn from(timer: FragmentTimerId<I>) -> IpLayerTimerId {
2316        I::map_ip(timer, IpLayerTimerId::ReassemblyTimeoutv4, IpLayerTimerId::ReassemblyTimeoutv6)
2317    }
2318}
2319
2320impl<I: Ip> From<PmtuTimerId<I>> for IpLayerTimerId {
2321    fn from(timer: PmtuTimerId<I>) -> IpLayerTimerId {
2322        I::map_ip(timer, IpLayerTimerId::PmtuTimeoutv4, IpLayerTimerId::PmtuTimeoutv6)
2323    }
2324}
2325
2326impl<I: Ip> From<FilterTimerId<I>> for IpLayerTimerId {
2327    fn from(timer: FilterTimerId<I>) -> IpLayerTimerId {
2328        I::map_ip(timer, IpLayerTimerId::FilterTimerv4, IpLayerTimerId::FilterTimerv6)
2329    }
2330}
2331
2332impl<I: Ip> From<MulticastForwardingTimerId<I>> for IpLayerTimerId {
2333    fn from(timer: MulticastForwardingTimerId<I>) -> IpLayerTimerId {
2334        I::map_ip(
2335            timer,
2336            IpLayerTimerId::MulticastForwardingTimerv4,
2337            IpLayerTimerId::MulticastForwardingTimerv6,
2338        )
2339    }
2340}
2341
2342impl<CC, BC> HandleableTimer<CC, BC> for IpLayerTimerId
2343where
2344    CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
2345        + TimerHandler<BC, FragmentTimerId<Ipv6>>
2346        + TimerHandler<BC, PmtuTimerId<Ipv4>>
2347        + TimerHandler<BC, PmtuTimerId<Ipv6>>
2348        + TimerHandler<BC, FilterTimerId<Ipv4>>
2349        + TimerHandler<BC, FilterTimerId<Ipv6>>
2350        + TimerHandler<BC, MulticastForwardingTimerId<Ipv4>>
2351        + TimerHandler<BC, MulticastForwardingTimerId<Ipv6>>,
2352    BC: TimerBindingsTypes,
2353{
2354    fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
2355        match self {
2356            IpLayerTimerId::ReassemblyTimeoutv4(id) => {
2357                core_ctx.handle_timer(bindings_ctx, id, timer)
2358            }
2359            IpLayerTimerId::ReassemblyTimeoutv6(id) => {
2360                core_ctx.handle_timer(bindings_ctx, id, timer)
2361            }
2362            IpLayerTimerId::PmtuTimeoutv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2363            IpLayerTimerId::PmtuTimeoutv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2364            IpLayerTimerId::FilterTimerv4(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2365            IpLayerTimerId::FilterTimerv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
2366            IpLayerTimerId::MulticastForwardingTimerv4(id) => {
2367                core_ctx.handle_timer(bindings_ctx, id, timer)
2368            }
2369            IpLayerTimerId::MulticastForwardingTimerv6(id) => {
2370                core_ctx.handle_timer(bindings_ctx, id, timer)
2371            }
2372        }
2373    }
2374}
2375
2376/// An ICMP error, and the metadata required to send it.
2377///
2378/// This allows the sending of the ICMP error to be decoupled from the
2379/// generation of the error, which is advantageous because sending the error
2380/// requires the underlying packet buffer, which cannot be "moved" in certain
2381/// contexts.
2382pub(crate) struct IcmpErrorSender<'a, I: IcmpHandlerIpExt, D> {
2383    /// The ICMP error that should be sent.
2384    err: I::IcmpError,
2385    /// The original source IP address of the packet (before the local-ingress
2386    /// hook evaluation).
2387    src_ip: SocketIpAddr<I::Addr>,
2388    /// The original destination IP address of the packet (before the
2389    /// local-ingress hook evaluation).
2390    dst_ip: SocketIpAddr<I::Addr>,
2391    /// The frame destination of the packet.
2392    frame_dst: Option<FrameDestination>,
2393    /// The device out which to send the error.
2394    device: &'a D,
2395    /// The metadata from the packet, allowing the packet's backing buffer to be
2396    /// returned to it's pre-IP-parse state with [`GrowBuffer::undo_parse`].
2397    meta: ParseMetadata,
2398    /// The marks used to send the ICMP error.
2399    marks: Marks,
2400    /// The protocol of the original packet.
2401    proto: I::Proto,
2402}
2403
2404impl<'a, I: IcmpHandlerIpExt, D> IcmpErrorSender<'a, I, D> {
2405    pub fn new<CC, B>(
2406        core_ctx: &mut CC,
2407        err: I::IcmpError,
2408        packet: &I::Packet<B>,
2409        frame_dst: Option<FrameDestination>,
2410        device: &'a D,
2411        marks: Marks,
2412    ) -> Option<Self>
2413    where
2414        I: IpCountersIpExt,
2415        CC: ResourceCounterContext<D, IpCounters<I>>,
2416        B: SplitByteSlice,
2417    {
2418        let Some(src_ip) = SocketIpAddr::new(packet.src_ip()) else {
2419            core_ctx.increment_both(device, |c| &c.unspecified_source);
2420            return None;
2421        };
2422        let Some(dst_ip) = SocketIpAddr::new(packet.dst_ip()) else {
2423            return None;
2424        };
2425
2426        // In IPv4, don't respond to non-initial fragments.
2427        let is_ipv4_fragment = I::map_ip_in(
2428            packet,
2429            |p| {
2430                packet_formats::ipv4::Ipv4Header::fragment_type(p)
2431                    == Ipv4FragmentType::NonInitialFragment
2432            },
2433            |_| false,
2434        );
2435        if is_ipv4_fragment {
2436            return None;
2437        }
2438
2439        let meta = packet.parse_metadata();
2440        let proto = packet.proto();
2441        Some(Self { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto })
2442    }
2443
2444    /// Generate an send an appropriate ICMP error in response to this error.
2445    ///
2446    /// The provided `body` must be the original buffer from which the IP
2447    /// packet responsible for this error was parsed. It is expected to be in a
2448    /// state that allows undoing the IP packet parse (e.g. unmodified after the
2449    /// IP packet was parsed).
2450    pub fn send<B, BC, CC>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, mut body: B)
2451    where
2452        B: BufferMut,
2453        CC: IcmpErrorHandler<I, BC, DeviceId = D>,
2454    {
2455        let IcmpErrorSender { err, src_ip, dst_ip, frame_dst, device, meta, marks, proto } = self;
2456        let header_len = meta.header_len();
2457
2458        // Undo the parsing of the IP Packet, moving the buffer's cursor so that
2459        // it points at the start of the IP header. This way, the sent ICMP
2460        // error will contain the entire original IP packet.
2461        body.undo_parse(meta);
2462
2463        core_ctx.send_icmp_error_message(
2464            bindings_ctx,
2465            Some(device),
2466            frame_dst,
2467            src_ip,
2468            dst_ip,
2469            body,
2470            err,
2471            header_len,
2472            proto,
2473            &marks,
2474        );
2475    }
2476}
2477
2478// Early demux results may be invalidated by SNAT in the LOCAL_INGRESS hook.
2479// This struct is used to check if the early demux result is still valid.
2480//
2481// TODO(https://fxbug.dev/476507679): Add tests to ensure this works properly
2482// once SNAT is fully implemented.
2483#[derive(PartialEq, Eq)]
2484struct EarlyDemuxResult<I: Ip, S> {
2485    socket: S,
2486    src_addr: I::Addr,
2487    src_port: Option<u16>,
2488}
2489
2490impl<I: FilterIpExt, S> EarlyDemuxResult<I, S> {
2491    fn new<P: IpPacket<I>>(socket: S, packet: &P) -> Self {
2492        let src_port =
2493            packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2494        Self { socket, src_addr: packet.src_addr(), src_port }
2495    }
2496
2497    // Returns the socket if it's still the right socket to handle the packet.
2498    fn take_socket<P: IpPacket<I>>(self, packet: &P) -> Option<S> {
2499        let src_port =
2500            packet.maybe_transport_packet().transport_packet_data().map(|t| t.src_port());
2501        (self.src_addr == packet.src_addr() && self.src_port == src_port).then_some(self.socket)
2502    }
2503
2504    fn update_packet_metadata<CC, BC>(
2505        &self,
2506        core_ctx: &mut CC,
2507        packet_metadata: &mut IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
2508    ) where
2509        I: IpLayerIpExt,
2510        S: SocketMetadata<CC>,
2511        BC: IpLayerBindingsContext<I, CC::DeviceId>,
2512        CC: IpLayerIngressContext<I, BC>,
2513    {
2514        packet_metadata.socket_cookie = Some(self.socket.socket_cookie(core_ctx));
2515        for mark in BC::marks_to_set_on_ingress() {
2516            *packet_metadata.marks.get_mut(*mark) = self.socket.marks(core_ctx).get(*mark).clone();
2517        }
2518    }
2519}
2520
2521pub(crate) fn reject_type_to_icmpv4_error(reject_type: RejectType) -> Option<Icmpv4Error> {
2522    let error = match reject_type {
2523        RejectType::NetUnreachable => Icmpv4Error::NetUnreachable,
2524        RejectType::ProtoUnreachable => Icmpv4Error::ProtocolUnreachable,
2525        RejectType::PortUnreachable => Icmpv4Error::PortUnreachable,
2526        RejectType::HostUnreachable => Icmpv4Error::HostUnreachable,
2527        RejectType::RoutePolicyFail => Icmpv4Error::NetworkProhibited,
2528        RejectType::RejectRoute => Icmpv4Error::HostProhibited,
2529        RejectType::AdminProhibited => Icmpv4Error::AdminProhibited,
2530        // TODO(https://fxbug.dev/488116504): Implement RejectType::TcpReset.
2531        RejectType::TcpReset => return None,
2532    };
2533    Some(error)
2534}
2535
2536pub(crate) fn reject_type_to_icmpv6_error(reject_type: RejectType) -> Option<Icmpv6Error> {
2537    let error = match reject_type {
2538        RejectType::NetUnreachable => Icmpv6Error::NetUnreachable,
2539        RejectType::PortUnreachable => Icmpv6Error::PortUnreachable,
2540        RejectType::HostUnreachable => Icmpv6Error::AddressUnreachable,
2541        RejectType::AdminProhibited => Icmpv6Error::AdminProhibited,
2542        RejectType::RoutePolicyFail => Icmpv6Error::SourceAddressPolicyFailed,
2543        RejectType::RejectRoute => Icmpv6Error::RejectRoute,
2544        // TODO(https://fxbug.dev/488116504): Implement ProtoUnreachable and TcpReset.
2545        RejectType::TcpReset | RejectType::ProtoUnreachable => return None,
2546    };
2547    Some(error)
2548}
2549// TODO(joshlf): Once we support multiple extension headers in IPv6, we will
2550// need to verify that the callers of this function are still sound. In
2551// particular, they may accidentally pass a parse_metadata argument which
2552// corresponds to a single extension header rather than all of the IPv6 headers.
2553
2554/// Dispatch a received IPv4 packet to the appropriate protocol.
2555///
2556/// `device` is the device the packet was received on. `parse_metadata` is the
2557/// parse metadata associated with parsing the IP headers. It is used to undo
2558/// that parsing. Both `device` and `parse_metadata` are required in order to
2559/// send ICMP messages in response to unrecognized protocols or ports. If either
2560/// of `device` or `parse_metadata` is `None`, the caller promises that the
2561/// protocol and port are recognized.
2562///
2563/// # Panics
2564///
2565/// `dispatch_receive_ipv4_packet` panics if the protocol is unrecognized and
2566/// `parse_metadata` is `None`. If an IGMP message is received but it is not
2567/// coming from a device, i.e., `device` given is `None`,
2568/// `dispatch_receive_ip_packet` will also panic.
2569fn dispatch_receive_ipv4_packet<
2570    'a,
2571    'b,
2572    BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
2573    CC: IpLayerIngressContext<Ipv4, BC>,
2574>(
2575    core_ctx: &'a mut CC,
2576    bindings_ctx: &'a mut BC,
2577    device: &'b CC::DeviceId,
2578    frame_dst: Option<FrameDestination>,
2579    mut packet: Ipv4Packet<&'a mut [u8]>,
2580    mut packet_metadata: IpLayerPacketMetadata<Ipv4, CC::WeakAddressId, BC>,
2581    receive_meta: ReceiveIpPacketMeta<Ipv4>,
2582) -> Result<(), IcmpErrorSender<'b, Ipv4, CC::DeviceId>> {
2583    core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2584
2585    match frame_dst {
2586        Some(FrameDestination::Individual { local: false }) => {
2587            core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2588        }
2589        Some(FrameDestination::Individual { local: true })
2590        | Some(FrameDestination::Multicast)
2591        | Some(FrameDestination::Broadcast)
2592        | None => (),
2593    };
2594
2595    // Skip early demux if the packet was redirected to a TPROXY.
2596    // TODO(https://fxbug.dev/475851987): Handle TPROXY in early_demux.
2597    let early_demux_result = receive_meta
2598        .transparent_override
2599        .is_none()
2600        .then(|| {
2601            core_ctx.early_demux(
2602                device,
2603                frame_dst,
2604                packet.src_ip(),
2605                packet.dst_ip(),
2606                packet.proto(),
2607                packet.body(),
2608            )
2609        })
2610        .flatten()
2611        .map(|socket| {
2612            let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2613            early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2614            early_demux_result
2615        });
2616
2617    let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2618        bindings_ctx,
2619        &mut packet,
2620        device,
2621        &mut packet_metadata,
2622    );
2623
2624    let marks = packet_metadata.marks;
2625    packet_metadata.acknowledge_drop();
2626
2627    match filter_verdict {
2628        filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2629            return Ok(());
2630        }
2631        filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2632            return match reject_type_to_icmpv4_error(reject_type) {
2633                Some(icmp_error) => {
2634                    match IcmpErrorSender::new(
2635                        core_ctx, icmp_error, &packet, frame_dst, device, marks,
2636                    ) {
2637                        Some(icmp_sender) => Err(icmp_sender),
2638                        None => Ok(()),
2639                    }
2640                }
2641                None => {
2642                    debug!("Unsupported reject type: {:?}", reject_type);
2643                    return Ok(());
2644                }
2645            };
2646        }
2647        filter::Verdict::Proceed(filter::Accept) => (),
2648    };
2649
2650    // These invariants are validated by the caller of this function, but it's
2651    // possible for the LOCAL_INGRESS hook to rewrite the packet, so we have to
2652    // check them again.
2653    let Some(src_ip) = packet.src_ipv4() else {
2654        debug!(
2655            "dispatch_receive_ipv4_packet: received packet from invalid source {} after the \
2656            LOCAL_INGRESS hook; dropping",
2657            packet.src_ip()
2658        );
2659        core_ctx.increment_both(device, |c| &c.invalid_source);
2660        return Ok(());
2661    };
2662    let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2663        core_ctx.increment_both(device, |c| &c.unspecified_destination);
2664        debug!(
2665            "dispatch_receive_ipv4_packet: Received packet with unspecified destination IP address \
2666            after the LOCAL_INGRESS hook; dropping"
2667        );
2668        return Ok(());
2669    };
2670
2671    core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2672
2673    // Check if the early demux result is still valid.
2674    let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2675
2676    let proto = packet.proto();
2677    let (prefix, options, body) = packet.parts_with_body_mut();
2678    let buffer = Buf::new(body, ..);
2679    let header_info = Ipv4HeaderInfo { prefix, options: options.as_ref() };
2680    let receive_info = LocalDeliveryPacketInfo { meta: receive_meta, header_info, marks };
2681
2682    core_ctx
2683        .dispatch_receive_ip_packet(
2684            bindings_ctx,
2685            device,
2686            src_ip,
2687            dst_ip,
2688            proto,
2689            buffer,
2690            &receive_info,
2691            early_demux_socket,
2692        )
2693        .or_else(|icmp_error| {
2694            match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2695                Some(icmp_sender) => Err(icmp_sender),
2696                None => Ok(()),
2697            }
2698        })
2699}
2700
2701/// Dispatch a received IPv6 packet to the appropriate protocol.
2702///
2703/// `dispatch_receive_ipv6_packet` has the same semantics as
2704/// `dispatch_receive_ipv4_packet`, but for IPv6.
2705fn dispatch_receive_ipv6_packet<
2706    'a,
2707    'b,
2708    BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
2709    CC: IpLayerIngressContext<Ipv6, BC>,
2710>(
2711    core_ctx: &'a mut CC,
2712    bindings_ctx: &'a mut BC,
2713    device: &'b CC::DeviceId,
2714    frame_dst: Option<FrameDestination>,
2715    mut packet: Ipv6Packet<&'a mut [u8]>,
2716    mut packet_metadata: IpLayerPacketMetadata<Ipv6, CC::WeakAddressId, BC>,
2717    meta: ReceiveIpPacketMeta<Ipv6>,
2718) -> Result<(), IcmpErrorSender<'b, Ipv6, CC::DeviceId>> {
2719    // TODO(https://fxbug.dev/42095067): Once we support multiple extension
2720    // headers in IPv6, we will need to verify that the callers of this
2721    // function are still sound. In particular, they may accidentally pass a
2722    // parse_metadata argument which corresponds to a single extension
2723    // header rather than all of the IPv6 headers.
2724
2725    core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet);
2726
2727    match frame_dst {
2728        Some(FrameDestination::Individual { local: false }) => {
2729            core_ctx.increment_both(device, |c| &c.dispatch_receive_ip_packet_other_host);
2730        }
2731        Some(FrameDestination::Individual { local: true })
2732        | Some(FrameDestination::Multicast)
2733        | Some(FrameDestination::Broadcast)
2734        | None => (),
2735    }
2736
2737    // Skip early demux if the packet was redirected to a TPROXY.
2738    // TODO(https://fxbug.dev/475851987): Handle TPROXY in early_demux.
2739    let early_demux_result = meta
2740        .transparent_override
2741        .is_none()
2742        .then(|| {
2743            core_ctx.early_demux(
2744                device,
2745                frame_dst,
2746                packet.src_ip(),
2747                packet.dst_ip(),
2748                packet.proto(),
2749                packet.body(),
2750            )
2751        })
2752        .flatten()
2753        .map(|socket| {
2754            let early_demux_result = EarlyDemuxResult::new(socket, &packet);
2755            early_demux_result.update_packet_metadata(core_ctx, &mut packet_metadata);
2756            early_demux_result
2757        });
2758
2759    let filter_verdict = core_ctx.filter_handler().local_ingress_hook(
2760        bindings_ctx,
2761        &mut packet,
2762        device,
2763        &mut packet_metadata,
2764    );
2765
2766    let marks = packet_metadata.marks;
2767    packet_metadata.acknowledge_drop();
2768
2769    match filter_verdict {
2770        filter::Verdict::Stop(filter::DropOrReject::Drop) => {
2771            return Ok(());
2772        }
2773        filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
2774            return match reject_type_to_icmpv6_error(reject_type) {
2775                Some(icmp_error) => {
2776                    match IcmpErrorSender::new(
2777                        core_ctx, icmp_error, &packet, frame_dst, device, marks,
2778                    ) {
2779                        Some(icmp_sender) => Err(icmp_sender),
2780                        None => Ok(()),
2781                    }
2782                }
2783                None => {
2784                    debug!("Unsupported reject type: {:?}", reject_type);
2785                    return Ok(());
2786                }
2787            };
2788        }
2789        filter::Verdict::Proceed(filter::Accept) => {}
2790    }
2791
2792    // These invariants are validated by the caller of this function, but it's
2793    // possible for the LOCAL_INGRESS hook to rewrite the packet, so we have to
2794    // check them again.
2795    let Some(src_ip) = packet.src_ipv6() else {
2796        debug!(
2797            "dispatch_receive_ipv6_packet: received packet from invalid source {} after the \
2798            LOCAL_INGRESS hook; dropping",
2799            packet.src_ip()
2800        );
2801
2802        core_ctx.increment_both(device, |c| &c.invalid_source);
2803        return Ok(());
2804    };
2805    let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
2806        core_ctx.increment_both(device, |c| &c.unspecified_destination);
2807        debug!(
2808            "dispatch_receive_ipv6_packet: Received packet with unspecified destination IP address \
2809            after the LOCAL_INGRESS hook; dropping"
2810        );
2811        return Ok(());
2812    };
2813
2814    core_ctx.deliver_packet_to_raw_ip_sockets(bindings_ctx, &packet, &device);
2815
2816    // Check if the early demux result is still valid.
2817    let early_demux_socket = early_demux_result.and_then(|result| result.take_socket(&packet));
2818
2819    let proto = packet.proto();
2820    let (fixed, extension, body) = packet.parts_with_body_mut();
2821    let buffer = Buf::new(body, ..);
2822    let header_info = Ipv6HeaderInfo { fixed, extension };
2823    let receive_info = LocalDeliveryPacketInfo { meta, header_info, marks };
2824
2825    core_ctx
2826        .dispatch_receive_ip_packet(
2827            bindings_ctx,
2828            device,
2829            src_ip,
2830            dst_ip,
2831            proto,
2832            buffer,
2833            &receive_info,
2834            early_demux_socket,
2835        )
2836        .or_else(|icmp_error| {
2837            let marks = receive_info.marks;
2838            match IcmpErrorSender::new(core_ctx, icmp_error, &packet, frame_dst, device, marks) {
2839                Some(icmp_sender) => Err(icmp_sender),
2840                None => Ok(()),
2841            }
2842        })
2843}
2844
2845/// The metadata required to forward an IP Packet.
2846///
2847/// This allows the forwarding of the packet to be decoupled from the
2848/// determination of how to forward. This is advantageous because forwarding
2849/// requires the underlying packet buffer, which cannot be "moved" in certain
2850/// contexts.
2851pub(crate) struct IpPacketForwarder<
2852    'a,
2853    I: IpLayerIpExt,
2854    D,
2855    A,
2856    BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2857> {
2858    inbound_device: &'a D,
2859    outbound_device: &'a D,
2860    packet_meta: IpLayerPacketMetadata<I, A, BT>,
2861    src_ip: I::RecvSrcAddr,
2862    dst_ip: SpecifiedAddr<I::Addr>,
2863    destination: IpPacketDestination<I, &'a D>,
2864    proto: I::Proto,
2865    parse_meta: ParseMetadata,
2866    frame_dst: Option<FrameDestination>,
2867}
2868
2869impl<'a, I, D, A, BC> IpPacketForwarder<'a, I, D, A, BC>
2870where
2871    I: IpLayerIpExt,
2872    BC: IpLayerBindingsContext<I, D>,
2873{
2874    // Forward the provided buffer as specified by this [`IpPacketForwarder`].
2875    fn forward_with_buffer<CC, B>(self, core_ctx: &mut CC, bindings_ctx: &mut BC, buffer: B)
2876    where
2877        B: BufferMut,
2878        CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2879    {
2880        let Self {
2881            inbound_device,
2882            outbound_device,
2883            packet_meta,
2884            src_ip,
2885            dst_ip,
2886            destination,
2887            proto,
2888            parse_meta,
2889            frame_dst,
2890        } = self;
2891
2892        let packet = ForwardedPacket::new(src_ip.get(), dst_ip.get(), proto, parse_meta, buffer);
2893
2894        trace!("forward_with_buffer: forwarding {} packet", I::NAME);
2895
2896        let marks = packet_meta.marks;
2897        match send_ip_frame(
2898            core_ctx,
2899            bindings_ctx,
2900            outbound_device,
2901            destination,
2902            packet,
2903            packet_meta,
2904            Mtu::no_limit(),
2905        ) {
2906            Ok(()) => (),
2907            Err(IpSendFrameError { serializer, error }) => {
2908                match error {
2909                    IpSendFrameErrorReason::Device(
2910                        SendFrameErrorReason::SizeConstraintsViolation,
2911                    ) => {
2912                        debug!("failed to forward {} packet: MTU exceeded", I::NAME);
2913                        core_ctx.increment_both(outbound_device, |c| &c.mtu_exceeded);
2914                        let mtu = core_ctx.get_mtu(inbound_device);
2915                        // NB: Ipv6 sends a PacketTooBig error. Ipv4 sends nothing.
2916                        let Some(err) = I::IcmpError::mtu_exceeded(mtu) else {
2917                            return;
2918                        };
2919                        // NB: Only send an ICMP error if the sender's src
2920                        // is specified.
2921                        let Some(src_ip) = I::received_source_as_icmp_source(src_ip) else {
2922                            return;
2923                        };
2924
2925                        let Some(dst_ip) = SocketIpAddr::new(dst_ip.get()) else {
2926                            return;
2927                        };
2928
2929                        // TODO(https://fxbug.dev/362489447): Increment the TTL since we
2930                        // just decremented it. The fact that we don't do this is
2931                        // technically a violation of the ICMP spec (we're not
2932                        // encapsulating the original packet that caused the
2933                        // issue, but a slightly modified version of it), but
2934                        // it's not that big of a deal because it won't affect
2935                        // the sender's ability to figure out the minimum path
2936                        // MTU. This may break other logic, though, so we should
2937                        // still fix it eventually.
2938                        core_ctx.send_icmp_error_message(
2939                            bindings_ctx,
2940                            Some(inbound_device),
2941                            frame_dst,
2942                            src_ip,
2943                            dst_ip,
2944                            serializer.into_buffer(),
2945                            err,
2946                            parse_meta.header_len(),
2947                            proto,
2948                            &marks,
2949                        );
2950                    }
2951                    IpSendFrameErrorReason::Device(SendFrameErrorReason::QueueFull)
2952                    | IpSendFrameErrorReason::Device(SendFrameErrorReason::Alloc)
2953                    | IpSendFrameErrorReason::IllegalLoopbackAddress => (),
2954                }
2955                debug!("failed to forward {} packet: {error:?}", I::NAME);
2956            }
2957        }
2958    }
2959}
2960
2961/// The action to take for a packet that was a candidate for forwarding.
2962pub(crate) enum ForwardingAction<
2963    'a,
2964    I: IpLayerIpExt,
2965    D,
2966    A,
2967    BT: FilterBindingsTypes + TxMetadataBindingsTypes,
2968> {
2969    /// Drop the packet without forwarding it or generating an ICMP error.
2970    SilentlyDrop,
2971    /// Forward the packet, as specified by the [`IpPacketForwarder`].
2972    Forward(IpPacketForwarder<'a, I, D, A, BT>),
2973    /// Drop the packet without forwarding, and generate an ICMP error as
2974    /// specified by the [`IcmpErrorSender`].
2975    DropWithIcmpError(IcmpErrorSender<'a, I, D>),
2976}
2977
2978impl<'a, I, D, A, BC> ForwardingAction<'a, I, D, A, BC>
2979where
2980    I: IpLayerIpExt,
2981    BC: IpLayerBindingsContext<I, D>,
2982{
2983    /// Perform the action prescribed by self, with the provided packet buffer.
2984    pub(crate) fn perform_action_with_buffer<CC, B>(
2985        self,
2986        core_ctx: &mut CC,
2987        bindings_ctx: &mut BC,
2988        buffer: B,
2989    ) where
2990        B: BufferMut,
2991        CC: IpLayerForwardingContext<I, BC, DeviceId = D, WeakAddressId = A>,
2992    {
2993        match self {
2994            ForwardingAction::SilentlyDrop => {}
2995            ForwardingAction::Forward(forwarder) => {
2996                forwarder.forward_with_buffer(core_ctx, bindings_ctx, buffer)
2997            }
2998            ForwardingAction::DropWithIcmpError(icmp_sender) => {
2999                icmp_sender.send(core_ctx, bindings_ctx, buffer)
3000            }
3001        }
3002    }
3003}
3004
3005/// Determine which [`ForwardingAction`] should be taken for an IP packet.
3006pub(crate) fn determine_ip_packet_forwarding_action<'a, 'b, I, BC, CC>(
3007    core_ctx: &'a mut CC,
3008    mut packet: I::Packet<&'a mut [u8]>,
3009    mut packet_meta: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3010    minimum_ttl: Option<u8>,
3011    inbound_device: &'b CC::DeviceId,
3012    outbound_device: &'b CC::DeviceId,
3013    destination: IpPacketDestination<I, &'b CC::DeviceId>,
3014    frame_dst: Option<FrameDestination>,
3015    src_ip: I::RecvSrcAddr,
3016    dst_ip: SpecifiedAddr<I::Addr>,
3017) -> ForwardingAction<'b, I, CC::DeviceId, CC::WeakAddressId, BC>
3018where
3019    I: IpLayerIpExt,
3020    BC: IpLayerBindingsContext<I, CC::DeviceId>,
3021    CC: IpLayerForwardingContext<I, BC>,
3022{
3023    // When forwarding, if a datagram's TTL is one or zero, discard it, as
3024    // decrementing the TTL would put it below the allowed minimum value.
3025    // For IPv4, see "TTL" section, https://tools.ietf.org/html/rfc791#page-14.
3026    // For IPv6, see "Hop Limit" section, https://datatracker.ietf.org/doc/html/rfc2460#page-5.
3027    const DEFAULT_MINIMUM_FORWARDING_TTL: u8 = 2;
3028    let minimum_ttl = minimum_ttl.unwrap_or(DEFAULT_MINIMUM_FORWARDING_TTL);
3029
3030    let ttl = packet.ttl();
3031    if ttl < minimum_ttl {
3032        debug!(
3033            "{} packet not forwarded due to inadequate TTL: got={ttl} minimum={minimum_ttl}",
3034            I::NAME
3035        );
3036        // As per RFC 792's specification of the Time Exceeded Message:
3037        //     If the gateway processing a datagram finds the time to live
3038        //     field is zero it must discard the datagram. The gateway may
3039        //     also notify the source host via the time exceeded message.
3040        // And RFC 4443 section 3.3:
3041        //    If a router receives a packet with a Hop Limit of zero, or if
3042        //    a router decrements a packet's Hop Limit to zero, it MUST
3043        //    discard the packet and originate an ICMPv6 Time Exceeded
3044        //    message with Code 0 to the source of the packet.
3045        // Don't send a Time Exceeded Message in cases where the netstack is
3046        // enforcing a higher minimum TTL (e.g. as part of a multicast route).
3047        if ttl > 1 {
3048            packet_meta.acknowledge_drop();
3049            return ForwardingAction::SilentlyDrop;
3050        }
3051
3052        core_ctx.increment_both(inbound_device, |c| &c.ttl_expired);
3053
3054        let marks = packet_meta.marks;
3055        packet_meta.acknowledge_drop();
3056
3057        // Construct and send the appropriate ICMP error for the IP version.
3058        match IcmpErrorSender::new(
3059            core_ctx,
3060            I::IcmpError::ttl_expired(),
3061            &packet,
3062            frame_dst,
3063            inbound_device,
3064            marks,
3065        ) {
3066            Some(icmp_sender) => return ForwardingAction::DropWithIcmpError(icmp_sender),
3067            None => return ForwardingAction::SilentlyDrop,
3068        }
3069    }
3070
3071    trace!("determine_ip_packet_forwarding_action: adequate TTL");
3072
3073    // For IPv6 packets, handle extension headers first.
3074    //
3075    // Any previous handling of extension headers was done under the
3076    // assumption that we are the final destination of the packet. Now that
3077    // we know we're forwarding, we need to re-examine them.
3078    let maybe_ipv6_packet_action = I::map_ip_in(
3079        &packet,
3080        |_packet| None,
3081        |packet| {
3082            Some(ipv6::handle_extension_headers(core_ctx, inbound_device, frame_dst, packet, false))
3083        },
3084    );
3085    match maybe_ipv6_packet_action {
3086        None => {} // NB: Ipv4 case.
3087        Some(Ipv6PacketAction::_Discard) => {
3088            core_ctx.increment_both(inbound_device, |c| {
3089                #[derive(GenericOverIp)]
3090                #[generic_over_ip(I, Ip)]
3091                struct InCounters<'a, I: IpLayerIpExt>(
3092                    &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<Counter>,
3093                );
3094                I::map_ip_in::<_, _>(
3095                    InCounters(&c.version_rx),
3096                    |_counters| {
3097                        unreachable!(
3098                            "`I` must be `Ipv6` because we're handling IPv6 extension headers"
3099                        )
3100                    },
3101                    |InCounters(counters)| &counters.extension_header_discard,
3102                )
3103            });
3104            trace!(
3105                "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3106                discarding packet"
3107            );
3108            packet_meta.acknowledge_drop();
3109            return ForwardingAction::SilentlyDrop;
3110        }
3111        Some(Ipv6PacketAction::Continue) => {
3112            trace!(
3113                "determine_ip_packet_forwarding_action: handled IPv6 extension headers: \
3114                forwarding packet"
3115            );
3116        }
3117        Some(Ipv6PacketAction::ProcessFragment) => {
3118            unreachable!(
3119                "When forwarding packets, we should only ever look at the hop by hop \
3120                    options extension header (if present)"
3121            )
3122        }
3123    };
3124
3125    match core_ctx.filter_handler().forwarding_hook(
3126        I::as_filter_packet(&mut packet),
3127        inbound_device,
3128        outbound_device,
3129        &mut packet_meta,
3130    ) {
3131        filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3132            packet_meta.acknowledge_drop();
3133            trace!("determine_ip_packet_forwarding_action: filter verdict: Drop");
3134            return ForwardingAction::SilentlyDrop;
3135        }
3136        filter::Verdict::Stop(filter::DropOrReject::Reject(reject_type)) => {
3137            // TODO(https://fxbug.dev/466098884): Send reject packet.
3138            packet_meta.acknowledge_drop();
3139            trace!(
3140                "determine_ip_packet_forwarding_action: filter verdict: Reject({:?})",
3141                reject_type
3142            );
3143            return ForwardingAction::SilentlyDrop;
3144        }
3145        filter::Verdict::Proceed(filter::Accept) => {}
3146    }
3147
3148    packet.set_ttl(ttl - 1);
3149    let (_, _, proto, parse_meta): (I::Addr, I::Addr, _, _) = packet.into_metadata();
3150    ForwardingAction::Forward(IpPacketForwarder {
3151        inbound_device,
3152        outbound_device,
3153        packet_meta,
3154        src_ip,
3155        dst_ip,
3156        destination,
3157        proto,
3158        parse_meta,
3159        frame_dst,
3160    })
3161}
3162
3163pub(crate) fn send_ip_frame<I, CC, BC, S>(
3164    core_ctx: &mut CC,
3165    bindings_ctx: &mut BC,
3166    device: &CC::DeviceId,
3167    destination: IpPacketDestination<I, &CC::DeviceId>,
3168    mut body: S,
3169    mut packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
3170    limit_mtu: Mtu,
3171) -> Result<(), IpSendFrameError<S>>
3172where
3173    I: IpLayerIpExt,
3174    BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
3175    CC: IpLayerEgressContext<I, BC> + IpDeviceMtuContext<I> + IpDeviceAddressIdContext<I>,
3176    S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
3177{
3178    let (verdict, proof) = core_ctx.filter_handler().egress_hook(
3179        bindings_ctx,
3180        &mut body,
3181        device,
3182        &mut packet_metadata,
3183    );
3184    match verdict {
3185        filter::Verdict::Stop(filter::DropPacket) => {
3186            packet_metadata.acknowledge_drop();
3187            return Ok(());
3188        }
3189        filter::Verdict::Proceed(filter::Accept) => {}
3190    }
3191
3192    // If the packet is leaving through the loopback device, attempt to extract a
3193    // weak reference to the packet's conntrack entry to plumb that through the
3194    // device layer so it can be reused on ingress to the IP layer.
3195    let (conntrack_connection_and_direction, tx_metadata, marks, _socket_cookie) =
3196        packet_metadata.into_parts();
3197    let conntrack_entry = if device.is_loopback() {
3198        conntrack_connection_and_direction
3199            .and_then(|(conn, dir)| WeakConntrackConnection::new(&conn).map(|conn| (conn, dir)))
3200    } else {
3201        None
3202    };
3203
3204    let mut device_layer_marks = Marks::default();
3205    for mark in BC::marks_to_keep_on_egress() {
3206        *device_layer_marks.get_mut(*mark) = *marks.get(*mark);
3207    }
3208
3209    let device_ip_layer_metadata =
3210        DeviceIpLayerMetadata { conntrack_entry, tx_metadata, marks: device_layer_marks };
3211
3212    // The filtering layer may have changed our address. Perform a last moment
3213    // check to protect against sending loopback addresses on the wire for
3214    // non-loopback devices, which is an RFC violation.
3215    if !device.is_loopback()
3216        && (I::LOOPBACK_SUBNET.contains(&body.src_addr())
3217            || I::LOOPBACK_SUBNET.contains(&body.dst_addr()))
3218    {
3219        core_ctx.increment_both(device, |c| &c.tx_illegal_loopback_address);
3220        return Err(IpSendFrameError {
3221            serializer: body,
3222            error: IpSendFrameErrorReason::IllegalLoopbackAddress,
3223        });
3224    }
3225
3226    // Use the minimum MTU between the target device and the requested mtu.
3227    let mtu = limit_mtu.min(core_ctx.get_mtu(device));
3228
3229    let body = body.with_size_limit(mtu.into());
3230
3231    let fits_mtu =
3232        match body.serialize_new_buf(PacketConstraints::UNCONSTRAINED, AlwaysFailBufferAlloc) {
3233            // We hit the allocator that refused to allocate new data, which
3234            // means the MTU is respected.
3235            Err(SerializeError::Alloc(())) => true,
3236            // MTU failure, we should try to fragment.
3237            Err(SerializeError::SizeLimitExceeded) => false,
3238        };
3239
3240    if fits_mtu {
3241        return core_ctx
3242            .send_ip_frame(bindings_ctx, device, destination, device_ip_layer_metadata, body, proof)
3243            .map_err(|ErrorAndSerializer { serializer, error }| IpSendFrameError {
3244                serializer: serializer.into_inner(),
3245                error: error.into(),
3246            });
3247    }
3248
3249    // Body doesn't fit MTU, we must fragment this serializer in order to send
3250    // it out.
3251    core_ctx.increment_both(device, |c| &c.fragmentation.fragmentation_required);
3252
3253    // Taken on the last frame.
3254    let mut device_ip_layer_metadata = Some(device_ip_layer_metadata);
3255    let body = body.into_inner();
3256    let result = match IpFragmenter::new(bindings_ctx, &body, mtu) {
3257        Ok(mut fragmenter) => loop {
3258            let (fragment, has_more) = match fragmenter.next() {
3259                None => break Ok(()),
3260                Some(f) => f,
3261            };
3262
3263            // TODO(https://fxbug.dev/391953082): We should penalize sockets
3264            // via the tx metadata when we incur IP fragmentation instead of
3265            // just attaching the ownership to the last fragment. For now, we
3266            // attach the tx metadata to the last frame only.
3267            let device_ip_layer_metadata = if has_more {
3268                // Unwrap here because only the last frame can take it.
3269                let device_ip_layer_metadata = device_ip_layer_metadata.as_ref().unwrap();
3270                DeviceIpLayerMetadata {
3271                    conntrack_entry: device_ip_layer_metadata.conntrack_entry.clone(),
3272                    tx_metadata: Default::default(),
3273                    marks: device_ip_layer_metadata.marks,
3274                }
3275            } else {
3276                // Unwrap here because the last frame can only happen once.
3277                device_ip_layer_metadata.take().unwrap()
3278            };
3279
3280            match core_ctx.send_ip_frame(
3281                bindings_ctx,
3282                device,
3283                destination.clone(),
3284                device_ip_layer_metadata,
3285                fragment,
3286                proof.clone_for_fragmentation(),
3287            ) {
3288                Ok(()) => {
3289                    core_ctx.increment_both(device, |c| &c.fragmentation.fragments);
3290                }
3291                Err(ErrorAndSerializer { serializer: _, error }) => {
3292                    core_ctx
3293                        .increment_both(device, |c| &c.fragmentation.error_fragmented_serializer);
3294                    break Err(error);
3295                }
3296            }
3297        },
3298        Err(e) => {
3299            core_ctx.increment_both(device, |c| &c.fragmentation.error_counter(&e));
3300            Err(SendFrameErrorReason::SizeConstraintsViolation)
3301        }
3302    };
3303    result.map_err(|e| IpSendFrameError { serializer: body, error: e.into() })
3304}
3305
3306/// A buffer allocator that always fails to allocate a new buffer.
3307///
3308/// Can be used to check for packet size constraints in serializer without in
3309/// fact serializing the buffer.
3310struct AlwaysFailBufferAlloc;
3311
3312impl LayoutBufferAlloc<Never> for AlwaysFailBufferAlloc {
3313    type Error = ();
3314    fn layout_alloc(
3315        self,
3316        _prefix: usize,
3317        _body: usize,
3318        _suffix: usize,
3319    ) -> Result<Never, Self::Error> {
3320        Err(())
3321    }
3322}
3323
3324/// Drop a packet and undo the effects of parsing it.
3325///
3326/// `drop_packet_and_undo_parse!` takes a `$packet` and a `$buffer` which the
3327/// packet was parsed from. It saves the results of the `src_ip()`, `dst_ip()`,
3328/// `proto()`, and `parse_metadata()` methods. It drops `$packet` and uses the
3329/// result of `parse_metadata()` to undo the effects of parsing the packet.
3330/// Finally, it returns the source IP, destination IP, protocol, and parse
3331/// metadata.
3332macro_rules! drop_packet_and_undo_parse {
3333    ($packet:expr, $buffer:expr) => {{
3334        let (src_ip, dst_ip, proto, meta) = $packet.into_metadata();
3335        $buffer.undo_parse(meta);
3336        (src_ip, dst_ip, proto, meta)
3337    }};
3338}
3339
3340/// The result of calling [`process_fragment`], depending on what action needs
3341/// to be taken by the caller.
3342enum ProcessFragmentResult<'a, I: IpLayerIpExt> {
3343    /// Processing of the packet is complete and no more action should be
3344    /// taken.
3345    Done,
3346
3347    /// Reassembly is not needed. The returned packet is the same one that was
3348    /// passed in the call to [`process_fragment`].
3349    NotNeeded(I::Packet<&'a mut [u8]>),
3350
3351    /// A packet was successfully reassembled into the provided buffer. If a
3352    /// parsed packet is needed, then the caller must perform that parsing.
3353    Reassembled(Vec<u8>),
3354}
3355
3356/// Process a fragment and reassemble if required.
3357///
3358/// Attempts to process a potential fragment packet and reassemble if we are
3359/// ready to do so. Returns an enum to the caller with the result of processing
3360/// the potential fragment.
3361fn process_fragment<'a, I, CC, BC>(
3362    core_ctx: &mut CC,
3363    bindings_ctx: &mut BC,
3364    device: &CC::DeviceId,
3365    packet: I::Packet<&'a mut [u8]>,
3366) -> ProcessFragmentResult<'a, I>
3367where
3368    I: IpLayerIpExt,
3369    for<'b> I::Packet<&'b mut [u8]>: FragmentablePacket,
3370    CC: IpLayerIngressContext<I, BC>,
3371    BC: IpLayerBindingsContext<I, CC::DeviceId>,
3372{
3373    match FragmentHandler::<I, _>::process_fragment::<&mut [u8]>(core_ctx, bindings_ctx, packet) {
3374        // Handle the packet right away since reassembly is not needed.
3375        FragmentProcessingState::NotNeeded(packet) => {
3376            trace!("receive_ip_packet: not fragmented");
3377            ProcessFragmentResult::NotNeeded(packet)
3378        }
3379        // Ready to reassemble a packet.
3380        FragmentProcessingState::Ready { key, packet_len } => {
3381            trace!("receive_ip_packet: fragmented, ready for reassembly");
3382            // Allocate a buffer of `packet_len` bytes.
3383            let mut buffer = Buf::new(alloc::vec![0; packet_len], ..);
3384
3385            // Attempt to reassemble the packet.
3386            let reassemble_result = match FragmentHandler::<I, _>::reassemble_packet(
3387                core_ctx,
3388                bindings_ctx,
3389                &key,
3390                buffer.buffer_view_mut(),
3391            ) {
3392                // Successfully reassembled the packet, handle it.
3393                Ok(()) => ProcessFragmentResult::Reassembled(buffer.into_inner()),
3394                Err(e) => {
3395                    core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3396                    debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", e);
3397                    ProcessFragmentResult::Done
3398                }
3399            };
3400            reassemble_result
3401        }
3402        // Cannot proceed since we need more fragments before we
3403        // can reassemble a packet.
3404        FragmentProcessingState::NeedMoreFragments => {
3405            core_ctx.increment_both(device, |c| &c.need_more_fragments);
3406            trace!("receive_ip_packet: fragmented, need more before reassembly");
3407            ProcessFragmentResult::Done
3408        }
3409        // TODO(ghanan): Handle invalid fragments.
3410        FragmentProcessingState::InvalidFragment => {
3411            core_ctx.increment_both(device, |c| &c.invalid_fragment);
3412            trace!("receive_ip_packet: fragmented, invalid");
3413            ProcessFragmentResult::Done
3414        }
3415        FragmentProcessingState::OutOfMemory => {
3416            core_ctx.increment_both(device, |c| &c.fragment_cache_full);
3417            trace!("receive_ip_packet: fragmented, dropped because OOM");
3418            ProcessFragmentResult::Done
3419        }
3420    }
3421}
3422
3423// TODO(joshlf): Can we turn `try_parse_ip_packet` into a function? So far, I've
3424// been unable to get the borrow checker to accept it.
3425
3426/// Try to parse an IP packet from a buffer.
3427///
3428/// If parsing fails, return the buffer to its original state so that its
3429/// contents can be used to send an ICMP error message. When invoked, the macro
3430/// expands to an expression whose type is `Result<P, P::Error>`, where `P` is
3431/// the parsed packet type.
3432macro_rules! try_parse_ip_packet {
3433    ($buffer:expr) => {{
3434        let p_len = $buffer.prefix_len();
3435        let s_len = $buffer.suffix_len();
3436
3437        let result = $buffer.parse_mut();
3438
3439        if let Err(err) = result {
3440            // Revert `buffer` to it's original state.
3441            let n_p_len = $buffer.prefix_len();
3442            let n_s_len = $buffer.suffix_len();
3443
3444            if n_p_len > p_len {
3445                $buffer.grow_front(n_p_len - p_len);
3446            }
3447
3448            if n_s_len > s_len {
3449                $buffer.grow_back(n_s_len - s_len);
3450            }
3451
3452            Err(err)
3453        } else {
3454            result
3455        }
3456    }};
3457}
3458
3459/// Clone an IP packet so that it may be delivered to a multicast route target.
3460///
3461/// Note: We must copy the underlying data here, as the filtering
3462/// engine may uniquely modify each instance as part of
3463/// performing forwarding.
3464///
3465/// In the future there are potential optimizations we could
3466/// pursue, including:
3467///   * Copy-on-write semantics for the buffer/packet so that
3468///     copies of the underlying data are done on an as-needed
3469///     basis.
3470///   * Avoid reparsing the IP packet. Because we're parsing an
3471///     exact copy of a known good packet, it would be safe to
3472///     adopt the data as an IP packet without performing any
3473///     validation.
3474// NB: This is a macro, not a function, because Rust's "move" semantics prevent
3475// us from returning both a buffer and a packet referencing that buffer.
3476macro_rules! clone_packet_for_mcast_forwarding {
3477    {let ($new_data:ident, $new_buffer:ident, $new_packet:ident) = $packet:ident} => {
3478        let mut $new_data = $packet.to_vec();
3479        let mut $new_buffer: Buf<&mut [u8]> = Buf::new($new_data.as_mut(), ..);
3480        let $new_packet = try_parse_ip_packet!($new_buffer).unwrap();
3481    };
3482}
3483
3484/// Receive an IPv4 packet from a device.
3485///
3486/// `frame_dst` specifies how this packet was received; see [`FrameDestination`]
3487/// for options.
3488pub fn receive_ipv4_packet<
3489    BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
3490    B: BufferMut,
3491    CC: IpLayerIngressContext<Ipv4, BC>,
3492>(
3493    core_ctx: &mut CC,
3494    bindings_ctx: &mut BC,
3495    device: &CC::DeviceId,
3496    frame_dst: Option<FrameDestination>,
3497    device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3498    buffer: B,
3499) {
3500    if !core_ctx.is_ip_device_enabled(&device) {
3501        return;
3502    }
3503
3504    // This is required because we may need to process the buffer that was
3505    // passed in or a reassembled one, which have different types.
3506    let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3507
3508    core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3509    trace!("receive_ip_packet({device:?})");
3510
3511    let packet: Ipv4Packet<_> = match try_parse_ip_packet!(buffer) {
3512        Ok(packet) => packet,
3513        Err(ParseError::Format)
3514        | Err(ParseError::Checksum)
3515        | Err(ParseError::NotSupported)
3516        | Err(ParseError::NotExpected) => {
3517            core_ctx.increment_both(device, |c| &c.unparsable_packet);
3518            return;
3519        }
3520    };
3521
3522    // We verify these properties later by actually creating the corresponding
3523    // witness types after the INGRESS filtering hook, but we keep these checks
3524    // here as an optimization to return early and save some work.
3525    if packet.src_ipv4().is_none() {
3526        debug!(
3527            "receive_ipv4_packet: received packet from invalid source {}; dropping",
3528            packet.src_ip()
3529        );
3530        core_ctx.increment_both(device, |c| &c.invalid_source);
3531        return;
3532    };
3533    if !packet.dst_ip().is_specified() {
3534        core_ctx.increment_both(device, |c| &c.unspecified_destination);
3535        debug!("receive_ipv4_packet: Received packet with unspecified destination IP; dropping");
3536        return;
3537    };
3538
3539    // Reassemble all packets before local delivery or forwarding. Reassembly
3540    // before forwarding is not RFC-compliant, but it's the easiest way to
3541    // ensure that fragments are filtered properly. Linux does this and it
3542    // doesn't seem to create major problems.
3543    //
3544    // TODO(https://fxbug.dev/345814518): Forward fragments without reassembly.
3545    //
3546    // Note, the `process_fragment` function could panic if the packet does not
3547    // have fragment data. However, we are guaranteed that it will not panic
3548    // because the fragment data is in the fixed header so it is always present
3549    // (even if the fragment data has values that implies that the packet is not
3550    // fragmented).
3551    let mut packet = match process_fragment(core_ctx, bindings_ctx, device, packet) {
3552        ProcessFragmentResult::Done => return,
3553        ProcessFragmentResult::NotNeeded(packet) => packet,
3554        ProcessFragmentResult::Reassembled(buf) => {
3555            let buf = Buf::new(buf, ..);
3556            buffer = packet::Either::B(buf);
3557
3558            match buffer.parse_mut() {
3559                Ok(packet) => packet,
3560                Err(err) => {
3561                    core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
3562                    debug!("receive_ip_packet: fragmented, failed to reassemble: {:?}", err);
3563                    return;
3564                }
3565            }
3566        }
3567    };
3568
3569    // TODO(ghanan): Act upon options.
3570
3571    let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
3572        core_ctx,
3573        device,
3574        device_ip_layer_metadata,
3575    );
3576    let mut filter = core_ctx.filter_handler();
3577    match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
3578        filter::Verdict::Proceed(filter::Accept) => {}
3579        filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
3580            packet_metadata.acknowledge_drop();
3581            return;
3582        }
3583        filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
3584            addr,
3585            port,
3586        }) => {
3587            // Drop the filter handler since it holds a mutable borrow of `core_ctx`, which
3588            // we need to provide to the packet dispatch function.
3589            drop(filter);
3590
3591            let Some(addr) = SpecifiedAddr::new(addr) else {
3592                core_ctx.increment_both(device, |c| &c.unspecified_destination);
3593                debug!("cannot perform transparent delivery to unspecified destination; dropping");
3594                return;
3595            };
3596
3597            let receive_meta = ReceiveIpPacketMeta {
3598                // It's possible that the packet was actually sent to a
3599                // broadcast address, but it doesn't matter here since it's
3600                // being delivered to a transparent proxy.
3601                broadcast: None,
3602                transparent_override: Some(TransparentLocalDelivery { addr, port }),
3603            };
3604
3605            // Short-circuit the routing process and override local demux, providing a local
3606            // address and port to which the packet should be transparently delivered at the
3607            // transport layer.
3608            dispatch_receive_ipv4_packet(
3609                core_ctx,
3610                bindings_ctx,
3611                device,
3612                frame_dst,
3613                packet,
3614                packet_metadata,
3615                receive_meta,
3616            )
3617            .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3618            return;
3619        }
3620    }
3621    // Drop the filter handler since it holds a mutable borrow of `core_ctx`, which
3622    // we need below.
3623    drop(filter);
3624
3625    let Some(src_ip) = packet.src_ipv4() else {
3626        core_ctx.increment_both(device, |c| &c.invalid_source);
3627        debug!(
3628            "receive_ipv4_packet: received packet from invalid source {}; dropping",
3629            packet.src_ip()
3630        );
3631        return;
3632    };
3633
3634    let action = receive_ipv4_packet_action(
3635        core_ctx,
3636        bindings_ctx,
3637        device,
3638        &packet,
3639        frame_dst,
3640        &packet_metadata.marks,
3641    );
3642    match action {
3643        ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
3644            // TOOD(https://fxbug.dev/364242513): Support connection tracking of
3645            // the multiplexed flows created by multicast forwarding. Here, we
3646            // use the existing metadata for the first action taken, and then
3647            // a default instance for each subsequent action. The first action
3648            // will populate the conntrack table with an entry, which will then
3649            // be used by all subsequent forwards.
3650            let mut packet_metadata = Some(packet_metadata);
3651            for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
3652                clone_packet_for_mcast_forwarding! {
3653                    let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
3654                };
3655                determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3656                    core_ctx,
3657                    copy_of_packet,
3658                    packet_metadata.take().unwrap_or_default(),
3659                    Some(*min_ttl),
3660                    device,
3661                    &output_interface,
3662                    IpPacketDestination::from_addr(dst_ip),
3663                    frame_dst,
3664                    src_ip,
3665                    dst_ip,
3666                )
3667                .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
3668            }
3669
3670            // If we also have an interest in the packet, deliver it locally.
3671            if let Some(address_status) = address_status {
3672                let receive_meta = ReceiveIpPacketMeta {
3673                    broadcast: address_status.to_broadcast_marker(),
3674                    transparent_override: None,
3675                };
3676                dispatch_receive_ipv4_packet(
3677                    core_ctx,
3678                    bindings_ctx,
3679                    device,
3680                    frame_dst,
3681                    packet,
3682                    packet_metadata.take().unwrap_or_default(),
3683                    receive_meta,
3684                )
3685                .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3686            }
3687        }
3688        ReceivePacketAction::Deliver { address_status, internal_forwarding } => {
3689            // NB: when performing internal forwarding, hit the
3690            // forwarding hook.
3691            match internal_forwarding {
3692                InternalForwarding::Used(outbound_device) => {
3693                    core_ctx.increment_both(device, |c| &c.forward);
3694                    match core_ctx.filter_handler().forwarding_hook(
3695                        &mut packet,
3696                        device,
3697                        &outbound_device,
3698                        &mut packet_metadata,
3699                    ) {
3700                        filter::Verdict::Stop(filter::DropOrReject::Drop) => {
3701                            packet_metadata.acknowledge_drop();
3702                            return;
3703                        }
3704                        filter::Verdict::Stop(filter::DropOrReject::Reject(_reject_type)) => {
3705                            // TODO(https://fxbug.dev/466098884): Send reject packet.
3706                            packet_metadata.acknowledge_drop();
3707                            return;
3708                        }
3709                        filter::Verdict::Proceed(filter::Accept) => {}
3710                    }
3711                }
3712                InternalForwarding::NotUsed => {}
3713            }
3714
3715            let receive_meta = ReceiveIpPacketMeta {
3716                broadcast: address_status.to_broadcast_marker(),
3717                transparent_override: None,
3718            };
3719            dispatch_receive_ipv4_packet(
3720                core_ctx,
3721                bindings_ctx,
3722                device,
3723                frame_dst,
3724                packet,
3725                packet_metadata,
3726                receive_meta,
3727            )
3728            .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
3729        }
3730        ReceivePacketAction::Forward {
3731            original_dst,
3732            dst: Destination { device: dst_device, next_hop },
3733        } => {
3734            determine_ip_packet_forwarding_action::<Ipv4, _, _>(
3735                core_ctx,
3736                packet,
3737                packet_metadata,
3738                None,
3739                device,
3740                &dst_device,
3741                IpPacketDestination::from_next_hop(next_hop, original_dst),
3742                frame_dst,
3743                src_ip,
3744                original_dst,
3745            )
3746            .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
3747        }
3748        ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
3749            core_ctx.increment_both(device, |c| &c.no_route_to_host);
3750            debug!("received IPv4 packet with no known route to destination {}", dst_ip);
3751
3752            let marks = packet_metadata.marks;
3753            packet_metadata.acknowledge_drop();
3754
3755            if let Some(sender) = IcmpErrorSender::new(
3756                core_ctx,
3757                Icmpv4Error::NetUnreachable,
3758                &packet,
3759                frame_dst,
3760                device,
3761                marks,
3762            ) {
3763                sender.send(core_ctx, bindings_ctx, buffer);
3764            }
3765        }
3766        ReceivePacketAction::Drop { reason } => {
3767            let src_ip = packet.src_ip();
3768            let dst_ip = packet.dst_ip();
3769            packet_metadata.acknowledge_drop();
3770            core_ctx.increment_both(device, |c| &c.dropped);
3771            debug!(
3772                "receive_ipv4_packet: dropping packet from {src_ip} to {dst_ip} received on \
3773                {device:?}: {reason:?}",
3774            );
3775        }
3776    }
3777}
3778
3779fn handle_ipv6_parse_error<BC, B, CC>(
3780    core_ctx: &mut CC,
3781    bindings_ctx: &mut BC,
3782    device: &CC::DeviceId,
3783    frame_dst: Option<FrameDestination>,
3784    device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3785    mut buffer: B,
3786    error: Ipv6ParseError,
3787) where
3788    BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3789    B: BufferMut,
3790    CC: IpLayerIngressContext<Ipv6, BC>,
3791{
3792    // Conditionally send an ICMP response if we encountered a parameter
3793    // problem error when parsing an IPv6 packet. Note, we do not always
3794    // send back an ICMP response as it can be used as an attack vector for
3795    // DDoS attacks. We only send back an ICMP response if the RFC requires
3796    // that we MUST send one, as noted by `must_send_icmp` and `action`.
3797    let Ipv6ParseError::ParameterProblem { src_ip, dst_ip, code, pointer, must_send_icmp, action } =
3798        error
3799    else {
3800        core_ctx.increment_both(device, |c| &c.unparsable_packet);
3801        debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3802        return;
3803    };
3804    if !must_send_icmp || !action.should_send_icmp(&dst_ip) {
3805        return;
3806    }
3807    core_ctx.increment_both(device, |c| &c.parameter_problem);
3808    let dst_ip = match SocketIpAddr::new(dst_ip) {
3809        Some(ip) => ip,
3810        None => {
3811            core_ctx.increment_both(device, |c| &c.unspecified_destination);
3812            debug!("receive_ipv6_packet: Dropping packet with unspecified destination IP");
3813            return;
3814        }
3815    };
3816
3817    let src_ip = match Ipv6SourceAddr::new(src_ip) {
3818        None => {
3819            core_ctx.increment_both(device, |c| &c.invalid_source);
3820            return;
3821        }
3822        Some(Ipv6SourceAddr::Unspecified) => {
3823            core_ctx.increment_both(device, |c| &c.unspecified_source);
3824            return;
3825        }
3826        Some(Ipv6SourceAddr::Unicast(src_ip)) => {
3827            SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
3828        }
3829    };
3830
3831    // Try raw parser to find main packet protocol and body offset. If this
3832    // fails as well then we can't send an ICMP error message.
3833    let raw_packet: Ipv6PacketRaw<_> = match try_parse_ip_packet!(buffer) {
3834        Ok(packet) => packet,
3835        Err(error) => {
3836            core_ctx.increment_both(device, |c| &c.unparsable_packet);
3837            debug!("receive_ipv6_packet: Failed to parse IPv6 packet: {:?}", error);
3838            return;
3839        }
3840    };
3841    let proto = match raw_packet.proto() {
3842        Ok(proto) => proto,
3843        Err(error) => {
3844            core_ctx.increment_both(device, |c| &c.unparsable_packet);
3845            debug!("receive_ipv6_packet: Failed to get protocol from IPv6 packet: {:?}", error);
3846            return;
3847        }
3848    };
3849    let parse_metadata = raw_packet.parse_metadata();
3850    let header_len = parse_metadata.header_len();
3851    buffer.undo_parse(parse_metadata);
3852
3853    let err = Icmpv6Error::ParameterProblem {
3854        code,
3855        pointer,
3856        allow_dst_multicast: action.should_send_icmp_to_multicast(),
3857    };
3858
3859    IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
3860        core_ctx,
3861        bindings_ctx,
3862        Some(device),
3863        frame_dst,
3864        src_ip,
3865        dst_ip,
3866        buffer,
3867        err,
3868        header_len,
3869        proto,
3870        &device_ip_layer_metadata.marks,
3871    );
3872}
3873
3874/// Receive an IPv6 packet from a device.
3875///
3876/// `frame_dst` specifies how this packet was received; see [`FrameDestination`]
3877/// for options.
3878pub fn receive_ipv6_packet<
3879    BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
3880    B: BufferMut,
3881    CC: IpLayerIngressContext<Ipv6, BC>,
3882>(
3883    core_ctx: &mut CC,
3884    bindings_ctx: &mut BC,
3885    device: &CC::DeviceId,
3886    frame_dst: Option<FrameDestination>,
3887    device_ip_layer_metadata: DeviceIpLayerMetadata<BC>,
3888    buffer: B,
3889) {
3890    if !core_ctx.is_ip_device_enabled(&device) {
3891        return;
3892    }
3893
3894    // This is required because we may need to process the buffer that was
3895    // passed in or a reassembled one, which have different types.
3896    let mut buffer: packet::Either<B, Buf<Vec<u8>>> = packet::Either::A(buffer);
3897
3898    core_ctx.increment_both(device, |c| &c.receive_ip_packet);
3899    trace!("receive_ipv6_packet({:?})", device);
3900
3901    let packet: Ipv6Packet<_> = match try_parse_ip_packet!(buffer) {
3902        Ok(packet) => packet,
3903        Err(error) => {
3904            handle_ipv6_parse_error(
3905                core_ctx,
3906                bindings_ctx,
3907                device,
3908                frame_dst,
3909                device_ip_layer_metadata,
3910                buffer,
3911                error,
3912            );
3913            return;
3914        }
3915    };
3916
3917    trace!("receive_ipv6_packet: parsed packet: {:?}", packet);
3918
3919    // TODO(ghanan): Act upon extension headers.
3920
3921    // We verify these properties later by actually creating the corresponding
3922    // witness types after the INGRESS filtering hook, but we keep these checks
3923    // here as an optimization to return early and save some work.
3924    if packet.src_ipv6().is_none() {
3925        debug!(
3926            "receive_ipv6_packet: received packet from invalid source {}; dropping",
3927            packet.src_ip()
3928        );
3929        core_ctx.increment_both(device, |c| &c.invalid_source);
3930        return;
3931    };
3932    if !packet.dst_ip().is_specified() {
3933        core_ctx.increment_both(device, |c| &c.unspecified_destination);
3934        debug!("receive_ipv6_packet: Received packet with unspecified destination IP; dropping");
3935        return;
3936    };
3937
3938    // Reassemble all packets before local delivery or forwarding. Reassembly
3939    // before forwarding is not RFC-compliant, but it's the easiest way to
3940    // ensure that fragments are filtered properly. Linux does this and it
3941    // doesn't seem to create major problems.
3942    //
3943    // TODO(https://fxbug.dev/345814518): Forward fragments without reassembly.
3944    //
3945    // delivery_extension_header_action is used to prevent looking at the
3946    // extension headers twice when a non-fragmented packet is delivered
3947    // locally.
3948    let (mut packet, delivery_extension_header_action) =
3949        match ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true) {
3950            Ipv6PacketAction::_Discard => {
3951                core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
3952                trace!("receive_ipv6_packet: handled IPv6 extension headers: discarding packet");
3953                return;
3954            }
3955            Ipv6PacketAction::Continue => {
3956                trace!("receive_ipv6_packet: handled IPv6 extension headers: dispatching packet");
3957                (packet, Some(Ipv6PacketAction::Continue))
3958            }
3959            Ipv6PacketAction::ProcessFragment => {
3960                trace!(
3961                    "receive_ipv6_packet: handled IPv6 extension headers: handling \
3962                    fragmented packet"
3963                );
3964
3965                // Note, `IpPacketFragmentCache::process_fragment`
3966                // could panic if the packet does not have fragment data.
3967                // However, we are guaranteed that it will not panic for an
3968                // IPv6 packet because the fragment data is in an (optional)
3969                // fragment extension header which we attempt to handle by
3970                // calling `ipv6::handle_extension_headers`. We will only
3971                // end up here if its return value is
3972                // `Ipv6PacketAction::ProcessFragment` which is only
3973                // possible when the packet has the fragment extension
3974                // header (even if the fragment data has values that implies
3975                // that the packet is not fragmented).
3976                match process_fragment(core_ctx, bindings_ctx, device, packet) {
3977                    ProcessFragmentResult::Done => return,
3978                    ProcessFragmentResult::NotNeeded(packet) => {
3979                        // While strange, it's possible for there to be a Fragment
3980                        // header that says the packet doesn't need defragmentation.
3981                        // As per RFC 8200 4.5:
3982                        //
3983                        //   If the fragment is a whole datagram (that is, both the
3984                        //   Fragment Offset field and the M flag are zero), then it
3985                        //   does not need any further reassembly and should be
3986                        //   processed as a fully reassembled packet (i.e., updating
3987                        //   Next Header, adjust Payload Length, removing the
3988                        //   Fragment header, etc.).
3989                        //
3990                        // In this case, we're not technically reassembling the
3991                        // packet, since, per the RFC, that would mean removing the
3992                        // Fragment header.
3993                        (packet, Some(Ipv6PacketAction::Continue))
3994                    }
3995                    ProcessFragmentResult::Reassembled(buf) => {
3996                        let buf = Buf::new(buf, ..);
3997                        buffer = packet::Either::B(buf);
3998
3999                        match buffer.parse_mut() {
4000                            Ok(packet) => (packet, None),
4001                            Err(err) => {
4002                                core_ctx.increment_both(device, |c| &c.fragment_reassembly_error);
4003                                debug!(
4004                                    "receive_ip_packet: fragmented, failed to reassemble: {:?}",
4005                                    err
4006                                );
4007                                return;
4008                            }
4009                        }
4010                    }
4011                }
4012            }
4013        };
4014
4015    let mut packet_metadata = IpLayerPacketMetadata::from_device_ip_layer_metadata(
4016        core_ctx,
4017        device,
4018        device_ip_layer_metadata,
4019    );
4020    let mut filter = core_ctx.filter_handler();
4021
4022    match filter.ingress_hook(bindings_ctx, &mut packet, device, &mut packet_metadata) {
4023        filter::Verdict::Proceed(filter::Accept) => {}
4024        filter::Verdict::Stop(filter::IngressStopReason::Drop) => {
4025            packet_metadata.acknowledge_drop();
4026            return;
4027        }
4028        filter::Verdict::Stop(filter::IngressStopReason::TransparentLocalDelivery {
4029            addr,
4030            port,
4031        }) => {
4032            // Drop the filter handler since it holds a mutable borrow of `core_ctx`, which
4033            // we need to provide to the packet dispatch function.
4034            drop(filter);
4035
4036            let Some(addr) = SpecifiedAddr::new(addr) else {
4037                core_ctx.increment_both(device, |c| &c.unspecified_destination);
4038                debug!("cannot perform transparent delivery to unspecified destination; dropping");
4039                return;
4040            };
4041
4042            let receive_meta = ReceiveIpPacketMeta {
4043                broadcast: None,
4044                transparent_override: Some(TransparentLocalDelivery { addr, port }),
4045            };
4046
4047            // Short-circuit the routing process and override local demux, providing a local
4048            // address and port to which the packet should be transparently delivered at the
4049            // transport layer.
4050            dispatch_receive_ipv6_packet(
4051                core_ctx,
4052                bindings_ctx,
4053                device,
4054                frame_dst,
4055                packet,
4056                packet_metadata,
4057                receive_meta,
4058            )
4059            .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4060            return;
4061        }
4062    }
4063    // Drop the filter handler since it holds a mutable borrow of `core_ctx`, which
4064    // we need below.
4065    drop(filter);
4066
4067    let Some(src_ip) = packet.src_ipv6() else {
4068        debug!(
4069            "receive_ipv6_packet: received packet from invalid source {}; dropping",
4070            packet.src_ip()
4071        );
4072        core_ctx.increment_both(device, |c| &c.invalid_source);
4073        return;
4074    };
4075
4076    match receive_ipv6_packet_action(
4077        core_ctx,
4078        bindings_ctx,
4079        device,
4080        &packet,
4081        frame_dst,
4082        &packet_metadata.marks,
4083    ) {
4084        ReceivePacketAction::MulticastForward { targets, address_status, dst_ip } => {
4085            // TOOD(https://fxbug.dev/364242513): Support connection tracking of
4086            // the multiplexed flows created by multicast forwarding. Here, we
4087            // use the existing metadata for the first action taken, and then
4088            // a default instance for each subsequent action. The first action
4089            // will populate the conntrack table with an entry, which will then
4090            // be used by all subsequent forwards.
4091            let mut packet_metadata = Some(packet_metadata);
4092            for MulticastRouteTarget { output_interface, min_ttl } in targets.as_ref() {
4093                clone_packet_for_mcast_forwarding! {
4094                    let (copy_of_data, copy_of_buffer, copy_of_packet) = packet
4095                };
4096                determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4097                    core_ctx,
4098                    copy_of_packet,
4099                    packet_metadata.take().unwrap_or_default(),
4100                    Some(*min_ttl),
4101                    device,
4102                    &output_interface,
4103                    IpPacketDestination::from_addr(dst_ip),
4104                    frame_dst,
4105                    src_ip,
4106                    dst_ip,
4107                )
4108                .perform_action_with_buffer(core_ctx, bindings_ctx, copy_of_buffer);
4109            }
4110
4111            // If we also have an interest in the packet, deliver it locally.
4112            if let Some(_) = address_status {
4113                let receive_meta =
4114                    ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
4115
4116                dispatch_receive_ipv6_packet(
4117                    core_ctx,
4118                    bindings_ctx,
4119                    device,
4120                    frame_dst,
4121                    packet,
4122                    packet_metadata.take().unwrap_or_default(),
4123                    receive_meta,
4124                )
4125                .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4126            }
4127        }
4128        ReceivePacketAction::Deliver { address_status: _, internal_forwarding } => {
4129            trace!("receive_ipv6_packet: delivering locally");
4130
4131            let action = if let Some(action) = delivery_extension_header_action {
4132                action
4133            } else {
4134                ipv6::handle_extension_headers(core_ctx, device, frame_dst, &packet, true)
4135            };
4136            match action {
4137                Ipv6PacketAction::_Discard => {
4138                    core_ctx.increment_both(device, |c| &c.version_rx.extension_header_discard);
4139                    trace!(
4140                        "receive_ipv6_packet: handled IPv6 extension headers: discarding packet"
4141                    );
4142                    packet_metadata.acknowledge_drop();
4143                }
4144                Ipv6PacketAction::Continue => {
4145                    trace!(
4146                        "receive_ipv6_packet: handled IPv6 extension headers: dispatching packet"
4147                    );
4148
4149                    // NB: when performing internal forwarding, hit the
4150                    // forwarding hook.
4151                    match internal_forwarding {
4152                        InternalForwarding::Used(outbound_device) => {
4153                            core_ctx.increment_both(device, |c| &c.forward);
4154                            match core_ctx.filter_handler().forwarding_hook(
4155                                &mut packet,
4156                                device,
4157                                &outbound_device,
4158                                &mut packet_metadata,
4159                            ) {
4160                                filter::Verdict::Stop(filter::DropOrReject::Drop) => {
4161                                    packet_metadata.acknowledge_drop();
4162                                    return;
4163                                }
4164                                filter::Verdict::Stop(filter::DropOrReject::Reject(
4165                                    _reject_type,
4166                                )) => {
4167                                    // TODO(https://fxbug.dev/466098884): Send reject packet.
4168                                    packet_metadata.acknowledge_drop();
4169                                    return;
4170                                }
4171                                filter::Verdict::Proceed(filter::Accept) => {}
4172                            }
4173                        }
4174                        InternalForwarding::NotUsed => {}
4175                    }
4176
4177                    let meta = ReceiveIpPacketMeta { broadcast: None, transparent_override: None };
4178                    dispatch_receive_ipv6_packet(
4179                        core_ctx,
4180                        bindings_ctx,
4181                        device,
4182                        frame_dst,
4183                        packet,
4184                        packet_metadata,
4185                        meta,
4186                    )
4187                    .unwrap_or_else(|icmp_sender| icmp_sender.send(core_ctx, bindings_ctx, buffer));
4188                }
4189                Ipv6PacketAction::ProcessFragment => {
4190                    debug!("receive_ipv6_packet: found fragment header after reassembly; dropping");
4191                    packet_metadata.acknowledge_drop();
4192                }
4193            }
4194        }
4195        ReceivePacketAction::Forward {
4196            original_dst,
4197            dst: Destination { device: dst_device, next_hop },
4198        } => {
4199            determine_ip_packet_forwarding_action::<Ipv6, _, _>(
4200                core_ctx,
4201                packet,
4202                packet_metadata,
4203                None,
4204                device,
4205                &dst_device,
4206                IpPacketDestination::from_next_hop(next_hop, original_dst),
4207                frame_dst,
4208                src_ip,
4209                original_dst,
4210            )
4211            .perform_action_with_buffer(core_ctx, bindings_ctx, buffer);
4212        }
4213        ReceivePacketAction::SendNoRouteToDest { dst: dst_ip } => {
4214            core_ctx.increment_both(device, |c| &c.no_route_to_host);
4215            let (_, _, proto, meta): (Ipv6Addr, Ipv6Addr, _, _) =
4216                drop_packet_and_undo_parse!(packet, buffer);
4217            debug!("received IPv6 packet with no known route to destination {}", dst_ip);
4218            let marks = packet_metadata.marks;
4219            packet_metadata.acknowledge_drop();
4220
4221            let src_ip = match src_ip {
4222                Ipv6SourceAddr::Unspecified => {
4223                    core_ctx.increment_both(device, |c| &c.unspecified_source);
4224                    return;
4225                }
4226                Ipv6SourceAddr::Unicast(src_ip) => {
4227                    SocketIpAddr::new_from_ipv6_non_mapped_unicast(src_ip)
4228                }
4229            };
4230
4231            IcmpErrorHandler::<Ipv6, _>::send_icmp_error_message(
4232                core_ctx,
4233                bindings_ctx,
4234                Some(device),
4235                frame_dst,
4236                src_ip,
4237                SocketIpAddr::new_from_witness(dst_ip),
4238                buffer,
4239                Icmpv6Error::NetUnreachable,
4240                meta.header_len(),
4241                proto,
4242                &marks,
4243            );
4244        }
4245        ReceivePacketAction::Drop { reason } => {
4246            core_ctx.increment_both(device, |c| &c.dropped);
4247            let src_ip = packet.src_ip();
4248            let dst_ip = packet.dst_ip();
4249            packet_metadata.acknowledge_drop();
4250            debug!(
4251                "receive_ipv6_packet: dropping packet from {src_ip} to {dst_ip} received on \
4252                {device:?}: {reason:?}",
4253            );
4254        }
4255    }
4256}
4257
4258/// The action to take in order to process a received IP packet.
4259#[derive(Debug, PartialEq)]
4260pub enum ReceivePacketAction<I: BroadcastIpExt + IpLayerIpExt, DeviceId: StrongDeviceIdentifier> {
4261    /// Deliver the packet locally.
4262    Deliver {
4263        /// Status of the receiving IP address.
4264        address_status: I::AddressStatus,
4265        /// `InternalForwarding::Used(d)` if we're delivering the packet as a
4266        /// Weak Host performing internal forwarding via output device `d`.
4267        internal_forwarding: InternalForwarding<DeviceId>,
4268    },
4269
4270    /// Forward the packet to the given destination.
4271    Forward {
4272        /// The original destination IP address of the packet.
4273        original_dst: SpecifiedAddr<I::Addr>,
4274        /// The destination that the packet should be forwarded to.
4275        dst: Destination<I::Addr, DeviceId>,
4276    },
4277
4278    /// A multicast packet that should be forwarded (& optional local delivery).
4279    ///
4280    /// The packet should be forwarded to each of the given targets. This case
4281    /// is only returned when the packet is eligible for multicast forwarding;
4282    /// `Self::Deliver` is used for packets that are ineligible (either because
4283    /// multicast forwarding is disabled, or because there are no applicable
4284    /// multicast routes with which to forward the packet).
4285    MulticastForward {
4286        /// The multicast targets to forward the packet via.
4287        targets: MulticastRouteTargets<DeviceId>,
4288        /// Some if the host is a member of the multicast group and the packet
4289        /// should be delivered locally (in addition to forwarding).
4290        address_status: Option<I::AddressStatus>,
4291        /// The multicast address the packet should be forwarded to.
4292        dst_ip: SpecifiedAddr<I::Addr>,
4293    },
4294
4295    /// Send a Destination Unreachable ICMP error message to the packet's sender
4296    /// and drop the packet.
4297    ///
4298    /// For ICMPv4, use the code "net unreachable". For ICMPv6, use the code "no
4299    /// route to destination".
4300    SendNoRouteToDest {
4301        /// The destination IP Address to which there was no route.
4302        dst: NonMappedAddr<SpecifiedAddr<I::Addr>>,
4303    },
4304
4305    /// Silently drop the packet.
4306    ///
4307    /// `reason` describes why the packet was dropped.
4308    #[allow(missing_docs)]
4309    Drop { reason: DropReason },
4310}
4311
4312// It's possible that there is more than one device with the address
4313// present. Prefer any address status over `UnicastTentative`.
4314fn choose_highest_priority_address_status<I: IpLayerIpExt>(
4315    address_statuses: impl Iterator<Item = I::AddressStatus>,
4316) -> Option<I::AddressStatus> {
4317    address_statuses.max_by_key(|status| {
4318        #[derive(GenericOverIp)]
4319        #[generic_over_ip(I, Ip)]
4320        struct Wrap<'a, I: IpLayerIpExt>(&'a I::AddressStatus);
4321        I::map_ip_in(
4322            Wrap(status),
4323            |Wrap(v4_status)| match v4_status {
4324                Ipv4PresentAddressStatus::UnicastTentative => 0,
4325                _ => 1,
4326            },
4327            |Wrap(v6_status)| match v6_status {
4328                Ipv6PresentAddressStatus::UnicastTentative => 0,
4329                _ => 1,
4330            },
4331        )
4332    })
4333}
4334
4335/// The reason a received IP packet is dropped.
4336#[derive(Debug, PartialEq)]
4337pub enum DropReason {
4338    /// Remote packet destined to tentative address.
4339    Tentative,
4340    /// Remote packet destined to the unspecified address.
4341    UnspecifiedDestination,
4342    /// Remote packet with an invalid destination address.
4343    InvalidDestination,
4344    /// Cannot forward a packet with unspecified source address.
4345    ForwardUnspecifiedSource,
4346    /// Cannot forward a packet with link-local source or destination address.
4347    ForwardLinkLocal,
4348    /// Packet should be forwarded but packet's inbound interface has forwarding
4349    /// disabled.
4350    ForwardingDisabledInboundIface,
4351    /// Remote packet destined to a multicast address that could not be:
4352    /// * delivered locally (because we are not a member of the multicast
4353    ///   group), or
4354    /// * forwarded (either because multicast forwarding is disabled, or no
4355    ///   applicable multicast route has been installed).
4356    MulticastNoInterest,
4357}
4358
4359/// Computes the action to take in order to process a received IPv4 packet.
4360pub fn receive_ipv4_packet_action<BC, CC, B>(
4361    core_ctx: &mut CC,
4362    bindings_ctx: &mut BC,
4363    device: &CC::DeviceId,
4364    packet: &Ipv4Packet<B>,
4365    frame_dst: Option<FrameDestination>,
4366    marks: &Marks,
4367) -> ReceivePacketAction<Ipv4, CC::DeviceId>
4368where
4369    BC: IpLayerBindingsContext<Ipv4, CC::DeviceId>,
4370    CC: IpLayerContext<Ipv4, BC>,
4371    B: SplitByteSlice,
4372{
4373    let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4374        core_ctx.increment_both(device, |c| &c.unspecified_destination);
4375        return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4376    };
4377
4378    // If the packet arrived at the loopback interface, check if any local
4379    // interface has the destination address assigned. This effectively lets the
4380    // loopback interface operate as a weak host for incoming packets.
4381    //
4382    // Note that (as of writing) the stack sends all locally destined traffic to
4383    // the loopback interface so we need this hack to allow the stack to accept
4384    // packets that arrive at the loopback interface (after being looped back)
4385    // but destined to an address that is assigned to another local interface.
4386    //
4387    // TODO(https://fxbug.dev/42065870): This should instead be controlled by
4388    // the routing table.
4389
4390    let highest_priority = if device.is_loopback() {
4391        core_ctx.with_address_statuses(dst_ip, |it| {
4392            let it = it.map(|(_device, status)| status);
4393            choose_highest_priority_address_status::<Ipv4>(it)
4394        })
4395    } else {
4396        core_ctx.address_status_for_device(dst_ip, device).into_present()
4397    };
4398    match highest_priority {
4399        Some(
4400            address_status @ (Ipv4PresentAddressStatus::UnicastAssigned
4401            | Ipv4PresentAddressStatus::LoopbackSubnet),
4402        ) => {
4403            core_ctx.increment_both(device, |c| &c.deliver_unicast);
4404            ReceivePacketAction::Deliver {
4405                address_status,
4406                internal_forwarding: InternalForwarding::NotUsed,
4407            }
4408        }
4409        Some(Ipv4PresentAddressStatus::UnicastTentative) => {
4410            // If the destination address is tentative (which implies that
4411            // we are still performing Duplicate Address Detection on
4412            // it), then we don't consider the address "assigned to an
4413            // interface", and so we drop packets instead of delivering them
4414            // locally.
4415            core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4416            ReceivePacketAction::Drop { reason: DropReason::Tentative }
4417        }
4418
4419        Some(address_status @ Ipv4PresentAddressStatus::Multicast) => {
4420            receive_ip_multicast_packet_action(
4421                core_ctx,
4422                bindings_ctx,
4423                device,
4424                packet,
4425                Some(address_status),
4426                dst_ip,
4427                frame_dst,
4428            )
4429        }
4430        Some(
4431            address_status @ (Ipv4PresentAddressStatus::LimitedBroadcast
4432            | Ipv4PresentAddressStatus::SubnetBroadcast),
4433        ) => {
4434            core_ctx.increment_both(device, |c| &c.version_rx.deliver_broadcast);
4435            ReceivePacketAction::Deliver {
4436                address_status,
4437                internal_forwarding: InternalForwarding::NotUsed,
4438            }
4439        }
4440        None => receive_ip_packet_action_common::<Ipv4, _, _, _>(
4441            core_ctx,
4442            bindings_ctx,
4443            dst_ip,
4444            device,
4445            packet,
4446            frame_dst,
4447            marks,
4448        ),
4449    }
4450}
4451
4452/// Computes the action to take in order to process a received IPv6 packet.
4453pub fn receive_ipv6_packet_action<BC, CC, B>(
4454    core_ctx: &mut CC,
4455    bindings_ctx: &mut BC,
4456    device: &CC::DeviceId,
4457    packet: &Ipv6Packet<B>,
4458    frame_dst: Option<FrameDestination>,
4459    marks: &Marks,
4460) -> ReceivePacketAction<Ipv6, CC::DeviceId>
4461where
4462    BC: IpLayerBindingsContext<Ipv6, CC::DeviceId>,
4463    CC: IpLayerContext<Ipv6, BC>,
4464    B: SplitByteSlice,
4465{
4466    let Some(dst_ip) = SpecifiedAddr::new(packet.dst_ip()) else {
4467        core_ctx.increment_both(device, |c| &c.unspecified_destination);
4468        return ReceivePacketAction::Drop { reason: DropReason::UnspecifiedDestination };
4469    };
4470
4471    // If the packet arrived at the loopback interface, check if any local
4472    // interface has the destination address assigned. This effectively lets
4473    // the loopback interface operate as a weak host for incoming packets.
4474    //
4475    // Note that (as of writing) the stack sends all locally destined traffic to
4476    // the loopback interface so we need this hack to allow the stack to accept
4477    // packets that arrive at the loopback interface (after being looped back)
4478    // but destined to an address that is assigned to another local interface.
4479    //
4480    // TODO(https://fxbug.dev/42175703): This should instead be controlled by the
4481    // routing table.
4482
4483    let highest_priority = if device.is_loopback() {
4484        core_ctx.with_address_statuses(dst_ip, |it| {
4485            let it = it.map(|(_device, status)| status);
4486            choose_highest_priority_address_status::<Ipv6>(it)
4487        })
4488    } else {
4489        core_ctx.address_status_for_device(dst_ip, device).into_present()
4490    };
4491    match highest_priority {
4492        Some(address_status @ Ipv6PresentAddressStatus::Multicast) => {
4493            receive_ip_multicast_packet_action(
4494                core_ctx,
4495                bindings_ctx,
4496                device,
4497                packet,
4498                Some(address_status),
4499                dst_ip,
4500                frame_dst,
4501            )
4502        }
4503        Some(address_status @ Ipv6PresentAddressStatus::UnicastAssigned) => {
4504            core_ctx.increment_both(device, |c| &c.deliver_unicast);
4505            ReceivePacketAction::Deliver {
4506                address_status,
4507                internal_forwarding: InternalForwarding::NotUsed,
4508            }
4509        }
4510        Some(Ipv6PresentAddressStatus::UnicastTentative) => {
4511            // If the destination address is tentative (which implies that
4512            // we are still performing NDP's Duplicate Address Detection on
4513            // it), then we don't consider the address "assigned to an
4514            // interface", and so we drop packets instead of delivering them
4515            // locally.
4516            //
4517            // As per RFC 4862 section 5.4:
4518            //
4519            //   An address on which the Duplicate Address Detection
4520            //   procedure is applied is said to be tentative until the
4521            //   procedure has completed successfully. A tentative address
4522            //   is not considered "assigned to an interface" in the
4523            //   traditional sense.  That is, the interface must accept
4524            //   Neighbor Solicitation and Advertisement messages containing
4525            //   the tentative address in the Target Address field, but
4526            //   processes such packets differently from those whose Target
4527            //   Address matches an address assigned to the interface. Other
4528            //   packets addressed to the tentative address should be
4529            //   silently discarded. Note that the "other packets" include
4530            //   Neighbor Solicitation and Advertisement messages that have
4531            //   the tentative (i.e., unicast) address as the IP destination
4532            //   address and contain the tentative address in the Target
4533            //   Address field.  Such a case should not happen in normal
4534            //   operation, though, since these messages are multicasted in
4535            //   the Duplicate Address Detection procedure.
4536            //
4537            // That is, we accept no packets destined to a tentative
4538            // address. NS and NA packets should be addressed to a multicast
4539            // address that we would have joined during DAD so that we can
4540            // receive those packets.
4541            core_ctx.increment_both(device, |c| &c.drop_for_tentative);
4542            ReceivePacketAction::Drop { reason: DropReason::Tentative }
4543        }
4544        None => receive_ip_packet_action_common::<Ipv6, _, _, _>(
4545            core_ctx,
4546            bindings_ctx,
4547            dst_ip,
4548            device,
4549            packet,
4550            frame_dst,
4551            marks,
4552        ),
4553    }
4554}
4555
4556/// Computes the action to take for multicast packets on behalf of
4557/// [`receive_ipv4_packet_action`] and [`receive_ipv6_packet_action`].
4558fn receive_ip_multicast_packet_action<
4559    I: IpLayerIpExt,
4560    B: SplitByteSlice,
4561    BC: IpLayerBindingsContext<I, CC::DeviceId>,
4562    CC: IpLayerContext<I, BC>,
4563>(
4564    core_ctx: &mut CC,
4565    bindings_ctx: &mut BC,
4566    device: &CC::DeviceId,
4567    packet: &I::Packet<B>,
4568    address_status: Option<I::AddressStatus>,
4569    dst_ip: SpecifiedAddr<I::Addr>,
4570    frame_dst: Option<FrameDestination>,
4571) -> ReceivePacketAction<I, CC::DeviceId> {
4572    let targets = multicast_forwarding::lookup_multicast_route_or_stash_packet(
4573        core_ctx,
4574        bindings_ctx,
4575        packet,
4576        device,
4577        frame_dst,
4578    );
4579    match (targets, address_status) {
4580        (Some(targets), address_status) => {
4581            if address_status.is_some() {
4582                core_ctx.increment_both(device, |c| &c.deliver_multicast);
4583            }
4584            ReceivePacketAction::MulticastForward { targets, address_status, dst_ip }
4585        }
4586        (None, Some(address_status)) => {
4587            // If the address was present on the device (e.g. the host is a
4588            // member of the multicast group), fallback to local delivery.
4589            core_ctx.increment_both(device, |c| &c.deliver_multicast);
4590            ReceivePacketAction::Deliver {
4591                address_status,
4592                internal_forwarding: InternalForwarding::NotUsed,
4593            }
4594        }
4595        (None, None) => {
4596            // As per RFC 1122 Section 3.2.2
4597            //   An ICMP error message MUST NOT be sent as the result of
4598            //   receiving:
4599            //   ...
4600            //   * a datagram destined to an IP broadcast or IP multicast
4601            //     address
4602            //
4603            // As such, drop the packet
4604            core_ctx.increment_both(device, |c| &c.multicast_no_interest);
4605            ReceivePacketAction::Drop { reason: DropReason::MulticastNoInterest }
4606        }
4607    }
4608}
4609
4610/// Computes the remaining protocol-agnostic actions on behalf of
4611/// [`receive_ipv4_packet_action`] and [`receive_ipv6_packet_action`].
4612fn receive_ip_packet_action_common<
4613    I: IpLayerIpExt,
4614    B: SplitByteSlice,
4615    BC: IpLayerBindingsContext<I, CC::DeviceId>,
4616    CC: IpLayerContext<I, BC>,
4617>(
4618    core_ctx: &mut CC,
4619    bindings_ctx: &mut BC,
4620    dst_ip: SpecifiedAddr<I::Addr>,
4621    device_id: &CC::DeviceId,
4622    packet: &I::Packet<B>,
4623    frame_dst: Option<FrameDestination>,
4624    marks: &Marks,
4625) -> ReceivePacketAction<I, CC::DeviceId> {
4626    if dst_ip.is_multicast() {
4627        return receive_ip_multicast_packet_action(
4628            core_ctx,
4629            bindings_ctx,
4630            device_id,
4631            packet,
4632            None,
4633            dst_ip,
4634            frame_dst,
4635        );
4636    }
4637
4638    // Don't allow mapped IPv6 addresses.
4639    let Some(dst_ip) = NonMappedAddr::new(dst_ip) else {
4640        return ReceivePacketAction::Drop { reason: DropReason::InvalidDestination };
4641    };
4642
4643    // The packet is not destined locally, so we attempt to forward it.
4644    if !core_ctx.is_device_unicast_forwarding_enabled(device_id) {
4645        // Forwarding is disabled; we are operating only as a host.
4646        //
4647        // For IPv4, per RFC 1122 Section 3.2.1.3, "A host MUST silently discard
4648        // an incoming datagram that is not destined for the host."
4649        //
4650        // For IPv6, per RFC 4443 Section 3.1, the only instance in which a host
4651        // sends an ICMPv6 Destination Unreachable message is when a packet is
4652        // destined to that host but on an unreachable port (Code 4 - "Port
4653        // unreachable"). Since the only sensible error message to send in this
4654        // case is a Destination Unreachable message, we interpret the RFC text
4655        // to mean that, consistent with IPv4's behavior, we should silently
4656        // discard the packet in this case.
4657        core_ctx.increment_both(device_id, |c| &c.forwarding_disabled);
4658        return ReceivePacketAction::Drop { reason: DropReason::ForwardingDisabledInboundIface };
4659    }
4660    // Per https://www.rfc-editor.org/rfc/rfc4291.html#section-2.5.2:
4661    //   An IPv6 packet with a source address of unspecified must never be forwarded by an IPv6
4662    //   router.
4663    // Per https://datatracker.ietf.org/doc/html/rfc1812#section-5.3.7:
4664    //   A router SHOULD NOT forward any packet that has an invalid IP source address or a source
4665    //   address on network 0
4666    let Some(source_address) = SpecifiedAddr::new(packet.src_ip()) else {
4667        return ReceivePacketAction::Drop { reason: DropReason::ForwardUnspecifiedSource };
4668    };
4669
4670    // If forwarding is enabled, allow local delivery if the packet is destined
4671    // for an IP assigned to a different interface.
4672    //
4673    // This enables a weak host model when the Netstack is configured as a
4674    // router. Conceptually, the netstack is forwarding the packet from the
4675    // input device, to the destination IP's device.
4676    if let Some(dst_ip) = NonMulticastAddr::new(dst_ip) {
4677        if let Some((outbound_device, address_status)) =
4678            get_device_with_assigned_address(core_ctx, IpDeviceAddr::new_from_witness(dst_ip))
4679        {
4680            return ReceivePacketAction::Deliver {
4681                address_status,
4682                internal_forwarding: InternalForwarding::Used(outbound_device),
4683            };
4684        }
4685    }
4686
4687    // For IPv4, RFC 3927 Section 2.7 states:
4688    //
4689    //   An IPv4 packet whose source and/or destination address is in the
4690    //   169.254/16 prefix MUST NOT be sent to any router for forwarding, and
4691    //   any network device receiving such a packet MUST NOT forward it,
4692    //   regardless of the TTL in the IPv4 header.
4693    //
4694    // However, to maintain behavioral similarity to both gVisor/Netstack2 and
4695    // Linux, we omit this check.
4696    //
4697    // For IPv6, RFC 4291 Section 2.5.6 states:
4698    //
4699    //   Routers must not forward any packets with Link-Local source or
4700    //   destination addresses to other links.
4701    if I::map_ip_in(
4702        &packet,
4703        |_| false,
4704        |packet| packet.src_ip().is_link_local() || packet.dst_ip().is_link_local(),
4705    ) {
4706        return ReceivePacketAction::Drop { reason: DropReason::ForwardLinkLocal };
4707    }
4708
4709    match lookup_route_table(
4710        core_ctx,
4711        dst_ip.get(),
4712        RuleInput {
4713            packet_origin: PacketOrigin::NonLocal { source_address, incoming_device: device_id },
4714            marks,
4715        },
4716    ) {
4717        Some(dst) => {
4718            core_ctx.increment_both(device_id, |c| &c.forward);
4719            ReceivePacketAction::Forward { original_dst: *dst_ip, dst }
4720        }
4721        None => {
4722            core_ctx.increment_both(device_id, |c| &c.no_route_to_host);
4723            ReceivePacketAction::SendNoRouteToDest { dst: dst_ip }
4724        }
4725    }
4726}
4727
4728// Look up the route to a host.
4729fn lookup_route_table<
4730    I: IpLayerIpExt,
4731    BC: IpLayerBindingsContext<I, CC::DeviceId>,
4732    CC: IpStateContext<I, BC>,
4733>(
4734    core_ctx: &mut CC,
4735    dst_ip: I::Addr,
4736    rule_input: RuleInput<'_, I, CC::DeviceId>,
4737) -> Option<Destination<I::Addr, CC::DeviceId>> {
4738    let bound_device = match rule_input.packet_origin {
4739        PacketOrigin::Local { bound_address: _, bound_device } => bound_device,
4740        PacketOrigin::NonLocal { source_address: _, incoming_device: _ } => None,
4741    };
4742    core_ctx.with_rules_table(|core_ctx, rules: &RulesTable<_, _, BC>| {
4743        match walk_rules(core_ctx, rules, (), &rule_input, |(), core_ctx, table| {
4744            match table.lookup(core_ctx, bound_device, dst_ip) {
4745                Some(dst) => ControlFlow::Break(Some(dst)),
4746                None => ControlFlow::Continue(()),
4747            }
4748        }) {
4749            ControlFlow::Break(RuleAction::Lookup(RuleWalkInfo {
4750                inner: dst,
4751                observed_source_address_matcher: _,
4752            })) => dst,
4753            ControlFlow::Break(RuleAction::Unreachable) => None,
4754            ControlFlow::Continue(RuleWalkInfo {
4755                inner: (),
4756                observed_source_address_matcher: _,
4757            }) => None,
4758        }
4759    })
4760}
4761
4762/// Packed destination passed to [`IpDeviceSendContext::send_ip_frame`].
4763#[derive(Debug, Derivative, Clone)]
4764#[derivative(Eq(bound = "D: Eq"), PartialEq(bound = "D: PartialEq"))]
4765pub enum IpPacketDestination<I: BroadcastIpExt, D> {
4766    /// Broadcast packet.
4767    Broadcast(I::BroadcastMarker),
4768
4769    /// Multicast packet to the specified IP.
4770    Multicast(MulticastAddr<I::Addr>),
4771
4772    /// Send packet to the neighbor with the specified IP (the receiving
4773    /// node is either a router or the final recipient of the packet).
4774    Neighbor(SpecifiedAddr<I::Addr>),
4775
4776    /// Loopback the packet to the specified device. Can be used only when
4777    /// sending to the loopback device.
4778    Loopback(D),
4779}
4780
4781impl<I: BroadcastIpExt, D> IpPacketDestination<I, D> {
4782    /// Creates `IpPacketDestination` for IP address.
4783    pub fn from_addr(addr: SpecifiedAddr<I::Addr>) -> Self {
4784        match MulticastAddr::new(addr.into_addr()) {
4785            Some(mc_addr) => Self::Multicast(mc_addr),
4786            None => Self::Neighbor(addr),
4787        }
4788    }
4789
4790    /// Create `IpPacketDestination` from `NextHop`.
4791    pub fn from_next_hop(next_hop: NextHop<I::Addr>, dst_ip: SpecifiedAddr<I::Addr>) -> Self {
4792        match next_hop {
4793            NextHop::RemoteAsNeighbor => Self::from_addr(dst_ip),
4794            NextHop::Gateway(gateway) => Self::Neighbor(gateway),
4795            NextHop::Broadcast(marker) => Self::Broadcast(marker),
4796        }
4797    }
4798}
4799
4800/// The metadata associated with an outgoing IP packet.
4801#[derive(Debug, Clone)]
4802pub struct SendIpPacketMeta<I: IpExt, D, Src> {
4803    /// The outgoing device.
4804    pub device: D,
4805
4806    /// The source address of the packet.
4807    pub src_ip: Src,
4808
4809    /// The destination address of the packet.
4810    pub dst_ip: SpecifiedAddr<I::Addr>,
4811
4812    /// The destination for the send operation.
4813    pub destination: IpPacketDestination<I, D>,
4814
4815    /// The upper-layer protocol held in the packet's payload.
4816    pub proto: I::Proto,
4817
4818    /// The time-to-live (IPv4) or hop limit (IPv6) for the packet.
4819    ///
4820    /// If not set, a default TTL may be used.
4821    pub ttl: Option<NonZeroU8>,
4822
4823    /// An MTU to artificially impose on the whole IP packet.
4824    ///
4825    /// Note that the device's and discovered path MTU may still be imposed on
4826    /// the packet.
4827    pub mtu: Mtu,
4828
4829    /// Traffic Class (IPv6) or Type of Service (IPv4) field for the packet.
4830    pub dscp_and_ecn: DscpAndEcn,
4831}
4832
4833impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
4834    for SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>>
4835{
4836    fn from(
4837        SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn }: SendIpPacketMeta<
4838            I,
4839            D,
4840            SpecifiedAddr<I::Addr>,
4841        >,
4842    ) -> SendIpPacketMeta<I, D, Option<SpecifiedAddr<I::Addr>>> {
4843        SendIpPacketMeta {
4844            device,
4845            src_ip: Some(src_ip),
4846            dst_ip,
4847            destination,
4848            proto,
4849            ttl,
4850            mtu,
4851            dscp_and_ecn,
4852        }
4853    }
4854}
4855
4856/// Trait for abstracting the IP layer for locally-generated traffic.  That is,
4857/// traffic generated by the netstack itself (e.g. ICMP, IGMP, or MLD).
4858///
4859/// NOTE: Due to filtering rules, it is possible that the device provided in
4860/// `meta` will not be the device that final IP packet is actually sent from.
4861pub trait IpLayerHandler<I: IpExt + FragmentationIpExt + FilterIpExt, BC>:
4862    DeviceIdContext<AnyDevice>
4863{
4864    /// Encapsulate and send the provided transport packet and from the device
4865    /// provided in `meta`.
4866    fn send_ip_packet_from_device<S>(
4867        &mut self,
4868        bindings_ctx: &mut BC,
4869        meta: SendIpPacketMeta<I, &Self::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4870        body: S,
4871    ) -> Result<(), IpSendFrameError<S>>
4872    where
4873        S: TransportPacketSerializer<I>,
4874        S::Buffer: BufferMut;
4875
4876    /// Send an IP packet that doesn't require the encapsulation and other
4877    /// processing of [`send_ip_packet_from_device`] from the device specified
4878    /// in `meta`.
4879    // TODO(https://fxbug.dev/333908066): The packets going through this
4880    // function only hit the EGRESS filter hook, bypassing LOCAL_EGRESS.
4881    // Refactor callers and other functions to prevent this.
4882    fn send_ip_frame<S>(
4883        &mut self,
4884        bindings_ctx: &mut BC,
4885        device: &Self::DeviceId,
4886        destination: IpPacketDestination<I, &Self::DeviceId>,
4887        body: S,
4888    ) -> Result<(), IpSendFrameError<S>>
4889    where
4890        S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>;
4891}
4892
4893impl<
4894    I: IpLayerIpExt,
4895    BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
4896    CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4897> IpLayerHandler<I, BC> for CC
4898{
4899    fn send_ip_packet_from_device<S>(
4900        &mut self,
4901        bindings_ctx: &mut BC,
4902        meta: SendIpPacketMeta<I, &CC::DeviceId, Option<SpecifiedAddr<I::Addr>>>,
4903        body: S,
4904    ) -> Result<(), IpSendFrameError<S>>
4905    where
4906        S: TransportPacketSerializer<I>,
4907        S::Buffer: BufferMut,
4908    {
4909        send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
4910    }
4911
4912    fn send_ip_frame<S>(
4913        &mut self,
4914        bindings_ctx: &mut BC,
4915        device: &Self::DeviceId,
4916        destination: IpPacketDestination<I, &Self::DeviceId>,
4917        body: S,
4918    ) -> Result<(), IpSendFrameError<S>>
4919    where
4920        S: FragmentableIpSerializer<I, Buffer: BufferMut> + FilterIpPacket<I>,
4921    {
4922        send_ip_frame(
4923            self,
4924            bindings_ctx,
4925            device,
4926            destination,
4927            body,
4928            IpLayerPacketMetadata::default(),
4929            Mtu::no_limit(),
4930        )
4931    }
4932}
4933
4934/// Sends an Ip packet with the specified metadata.
4935///
4936/// # Panics
4937///
4938/// Panics if either the source or destination address is the loopback address
4939/// and the device is a non-loopback device.
4940pub(crate) fn send_ip_packet_from_device<I, BC, CC, S>(
4941    core_ctx: &mut CC,
4942    bindings_ctx: &mut BC,
4943    meta: SendIpPacketMeta<
4944        I,
4945        &<CC as DeviceIdContext<AnyDevice>>::DeviceId,
4946        Option<SpecifiedAddr<I::Addr>>,
4947    >,
4948    body: S,
4949    packet_metadata: IpLayerPacketMetadata<I, CC::WeakAddressId, BC>,
4950) -> Result<(), IpSendFrameError<S>>
4951where
4952    I: IpLayerIpExt,
4953    BC: FilterBindingsContext<CC::DeviceId> + TxMetadataBindingsTypes + MarksBindingsContext,
4954    CC: IpLayerEgressContext<I, BC> + IpDeviceEgressStateContext<I> + IpDeviceMtuContext<I>,
4955    S: TransportPacketSerializer<I>,
4956    S::Buffer: BufferMut,
4957{
4958    let SendIpPacketMeta { device, src_ip, dst_ip, destination, proto, ttl, mtu, dscp_and_ecn } =
4959        meta;
4960    core_ctx.increment_both(device, |c| &c.send_ip_packet);
4961    let next_packet_id = gen_ip_packet_id(core_ctx);
4962    let ttl = ttl.unwrap_or_else(|| core_ctx.get_hop_limit(device)).get();
4963    let src_ip = src_ip.map_or(I::UNSPECIFIED_ADDRESS, |a| a.get());
4964    let mut builder = I::PacketBuilder::new(src_ip, dst_ip.get(), ttl, proto);
4965
4966    #[derive(GenericOverIp)]
4967    #[generic_over_ip(I, Ip)]
4968    struct Wrap<'a, I: IpLayerIpExt> {
4969        builder: &'a mut I::PacketBuilder,
4970        next_packet_id: I::PacketId,
4971    }
4972
4973    I::map_ip::<_, ()>(
4974        Wrap { builder: &mut builder, next_packet_id },
4975        |Wrap { builder, next_packet_id }| {
4976            builder.id(next_packet_id);
4977        },
4978        |Wrap { builder: _, next_packet_id: () }| {
4979            // IPv6 doesn't have packet IDs.
4980        },
4981    );
4982
4983    builder.set_dscp_and_ecn(dscp_and_ecn);
4984
4985    let ip_frame = builder.wrap_body(body);
4986    send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_frame, packet_metadata, mtu)
4987        .map_err(|ser| ser.map_serializer(|s| s.into_inner()))
4988}
4989
4990/// Abstracts access to a [`filter::FilterHandler`] for core contexts.
4991pub trait FilterHandlerProvider<I: FilterIpExt, BT: FilterBindingsTypes>:
4992    IpDeviceAddressIdContext<I, DeviceId: netstack3_base::InterfaceProperties<BT::DeviceClass>>
4993{
4994    /// The filter handler.
4995    type Handler<'a>: filter::FilterHandler<I, BT, DeviceId = Self::DeviceId, WeakAddressId = Self::WeakAddressId>
4996    where
4997        Self: 'a;
4998
4999    /// Gets the filter handler for this context.
5000    fn filter_handler(&mut self) -> Self::Handler<'_>;
5001}
5002
5003#[cfg(any(test, feature = "testutils"))]
5004pub(crate) mod testutil {
5005    use super::*;
5006
5007    use netstack3_base::testutil::{FakeBindingsCtx, FakeCoreCtx, FakeStrongDeviceId};
5008    use netstack3_base::{AssignedAddrIpExt, SendFrameContext, SendFrameError, SendableFrameMeta};
5009    use packet::Serializer;
5010
5011    /// A [`SendIpPacketMeta`] for dual stack contextx.
5012    #[derive(Debug, GenericOverIp)]
5013    #[generic_over_ip()]
5014    #[allow(missing_docs)]
5015    pub enum DualStackSendIpPacketMeta<D> {
5016        V4(SendIpPacketMeta<Ipv4, D, SpecifiedAddr<Ipv4Addr>>),
5017        V6(SendIpPacketMeta<Ipv6, D, SpecifiedAddr<Ipv6Addr>>),
5018    }
5019
5020    impl<I: IpExt, D> From<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>
5021        for DualStackSendIpPacketMeta<D>
5022    {
5023        fn from(value: SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>) -> Self {
5024            #[derive(GenericOverIp)]
5025            #[generic_over_ip(I, Ip)]
5026            struct Wrap<I: IpExt, D>(SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>);
5027            use DualStackSendIpPacketMeta::*;
5028            I::map_ip_in(Wrap(value), |Wrap(value)| V4(value), |Wrap(value)| V6(value))
5029        }
5030    }
5031
5032    impl<I: IpExt, S, DeviceId, BC>
5033        SendableFrameMeta<FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>, BC>
5034        for SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>
5035    {
5036        fn send_meta<SS>(
5037            self,
5038            core_ctx: &mut FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>,
5039            bindings_ctx: &mut BC,
5040            frame: SS,
5041        ) -> Result<(), SendFrameError<SS>>
5042        where
5043            SS: Serializer,
5044            SS::Buffer: BufferMut,
5045        {
5046            SendFrameContext::send_frame(
5047                &mut core_ctx.frames,
5048                bindings_ctx,
5049                DualStackSendIpPacketMeta::from(self),
5050                frame,
5051            )
5052        }
5053    }
5054
5055    /// Error returned when the IP version doesn't match.
5056    #[derive(Debug)]
5057    pub struct WrongIpVersion;
5058
5059    impl<D> DualStackSendIpPacketMeta<D> {
5060        /// Returns the internal [`SendIpPacketMeta`] if this is carrying the
5061        /// version matching `I`.
5062        pub fn try_as<I: IpExt>(
5063            &self,
5064        ) -> Result<&SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, WrongIpVersion> {
5065            #[derive(GenericOverIp)]
5066            #[generic_over_ip(I, Ip)]
5067            struct Wrap<'a, I: IpExt, D>(
5068                Option<&'a SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>>,
5069            );
5070            use DualStackSendIpPacketMeta::*;
5071            let Wrap(dual_stack) = I::map_ip(
5072                self,
5073                |value| {
5074                    Wrap(match value {
5075                        V4(meta) => Some(meta),
5076                        V6(_) => None,
5077                    })
5078                },
5079                |value| {
5080                    Wrap(match value {
5081                        V4(_) => None,
5082                        V6(meta) => Some(meta),
5083                    })
5084                },
5085            );
5086            dual_stack.ok_or(WrongIpVersion)
5087        }
5088    }
5089
5090    impl<I, BC, S, Meta, DeviceId> FilterHandlerProvider<I, BC> for FakeCoreCtx<S, Meta, DeviceId>
5091    where
5092        I: AssignedAddrIpExt + FilterIpExt,
5093        BC: FilterBindingsContext<DeviceId>,
5094        DeviceId: FakeStrongDeviceId + netstack3_base::InterfaceProperties<BC::DeviceClass>,
5095    {
5096        type Handler<'a>
5097            = filter::testutil::NoopImpl<DeviceId>
5098        where
5099            Self: 'a;
5100
5101        fn filter_handler(&mut self) -> Self::Handler<'_> {
5102            filter::testutil::NoopImpl::default()
5103        }
5104    }
5105
5106    impl<TimerId, Event: Debug, State, FrameMeta> MarksBindingsContext
5107        for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
5108    {
5109        fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
5110            const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
5111            &MARKS
5112        }
5113
5114        fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
5115            const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
5116            &MARKS
5117        }
5118    }
5119}
5120
5121#[cfg(test)]
5122mod test {
5123    use super::*;
5124
5125    #[test]
5126    fn highest_priority_address_status_v4() {
5127        // Prefer assigned addresses over tentative addresses.
5128        assert_eq!(
5129            choose_highest_priority_address_status::<Ipv4>(
5130                [
5131                    Ipv4PresentAddressStatus::UnicastAssigned,
5132                    Ipv4PresentAddressStatus::UnicastTentative
5133                ]
5134                .into_iter()
5135            ),
5136            Some(Ipv4PresentAddressStatus::UnicastAssigned)
5137        )
5138    }
5139
5140    #[test]
5141    fn highest_priority_address_status_v6() {
5142        // Prefer assigned addresses over tentative addresses.
5143        assert_eq!(
5144            choose_highest_priority_address_status::<Ipv6>(
5145                [
5146                    Ipv6PresentAddressStatus::UnicastAssigned,
5147                    Ipv6PresentAddressStatus::UnicastTentative
5148                ]
5149                .into_iter()
5150            ),
5151            Some(Ipv6PresentAddressStatus::UnicastAssigned)
5152        )
5153    }
5154}