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