Skip to main content

netstack3_core/ip/
base.rs

1// Copyright 2022 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
5//! The integrations for protocols built on top of IP.
6
7use lock_order::lock::{DelegatedOrderedLockAccess, LockLevelFor};
8use lock_order::relation::LockBefore;
9use log::trace;
10use net_types::ip::{Ip, IpMarked, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr, Ipv6SourceAddr};
11use net_types::{MulticastAddr, SpecifiedAddr};
12use netstack3_base::socket::SocketIpAddr;
13use netstack3_base::{
14    CounterContext, FrameDestination, Icmpv4ErrorCode, Icmpv6ErrorCode, LocalFrameDestination,
15    Marks, ResourceCounterContext, TokenBucket, WeakDeviceIdentifier,
16};
17use netstack3_datagram::{self as datagram};
18use netstack3_device::{BaseDeviceId, DeviceId, DeviceStateSpec, WeakDeviceId, for_any_device_id};
19use netstack3_hashmap::HashMap;
20use netstack3_icmp_echo::{
21    self as icmp_echo, IcmpEchoBoundStateContext, IcmpEchoContextMarker,
22    IcmpEchoIpTransportContext, IcmpEchoStateContext, IcmpSocketId, IcmpSocketSet, IcmpSocketState,
23    IcmpSockets,
24};
25use netstack3_ip::device::{self, IpDeviceBindingsContext, IpDeviceIpExt};
26use netstack3_ip::gmp::{IgmpCounters, MldCounters};
27use netstack3_ip::icmp::{
28    self, IcmpIpTransportContext, IcmpRxCounters, IcmpSendContext, IcmpState, IcmpTxCounters,
29    Icmpv4Error, Icmpv6Error, InnerIcmpContext, InnerIcmpv4Context, NdpCounters,
30};
31use netstack3_ip::multicast_forwarding::MulticastForwardingState;
32use netstack3_ip::raw::RawIpSocketMap;
33use netstack3_ip::{
34    self as ip, BaseRoutingTableState, FragmentContext, IpCounters, IpDeviceContext, IpHeaderInfo,
35    IpLayerBindingsContext, IpLayerIpExt, IpPacketFragmentCache, IpRouteTableContext,
36    IpRouteTablesContext, IpStateContext, IpStateInner, IpTransportContext,
37    IpTransportDispatchContext, LocalDeliveryPacketInfo, MulticastMembershipHandler, PmtuCache,
38    PmtuContext, ResolveRouteError, ResolvedRoute, RoutingTable, RoutingTableId, RulesTable,
39    SocketMetadata,
40};
41use netstack3_sync::rc::Primary;
42use netstack3_tcp::{DualStackTcpSocketId, TcpBindingsTypes, TcpIpTransportContext};
43use netstack3_udp::{DualStackUdpSocketId, UdpBindingsTypes, UdpIpTransportContext};
44use packet::{BufferMut, ParseBuffer};
45use packet_formats::ip::{IpProto, Ipv4Proto, Ipv6Proto};
46
47use crate::context::WrapLockLevel;
48use crate::context::prelude::*;
49use crate::{BindingsContext, BindingsTypes, CoreCtx, StackState};
50
51impl<I, BT, L> FragmentContext<I, BT> for CoreCtx<'_, BT, L>
52where
53    I: IpLayerIpExt,
54    BT: BindingsTypes,
55    L: LockBefore<crate::lock_ordering::IpStateFragmentCache<I>>,
56{
57    fn with_state_mut<O, F: FnOnce(&mut IpPacketFragmentCache<I, BT>) -> O>(&mut self, cb: F) -> O {
58        let mut cache = self.lock::<crate::lock_ordering::IpStateFragmentCache<I>>();
59        cb(&mut cache)
60    }
61}
62
63impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpStatePmtuCache<Ipv4>>>
64    PmtuContext<Ipv4, BC> for CoreCtx<'_, BC, L>
65{
66    fn with_state_mut<O, F: FnOnce(&mut PmtuCache<Ipv4, BC>) -> O>(&mut self, cb: F) -> O {
67        let mut cache = self.lock::<crate::lock_ordering::IpStatePmtuCache<Ipv4>>();
68        cb(&mut cache)
69    }
70}
71
72impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpStatePmtuCache<Ipv6>>>
73    PmtuContext<Ipv6, BC> for CoreCtx<'_, BC, L>
74{
75    fn with_state_mut<O, F: FnOnce(&mut PmtuCache<Ipv6, BC>) -> O>(&mut self, cb: F) -> O {
76        let mut cache = self.lock::<crate::lock_ordering::IpStatePmtuCache<Ipv6>>();
77        cb(&mut cache)
78    }
79}
80
81impl<
82    I: Ip + IpDeviceIpExt + IpLayerIpExt,
83    BC: BindingsContext
84        + IpDeviceBindingsContext<I, Self::DeviceId>
85        + IpLayerBindingsContext<I, Self::DeviceId>,
86    L: LockBefore<crate::lock_ordering::IpState<I>>,
87> MulticastMembershipHandler<I, BC> for CoreCtx<'_, BC, L>
88where
89    Self: device::IpDeviceConfigurationContext<I, BC> + IpStateContext<I, BC> + IpDeviceContext<I>,
90{
91    fn join_multicast_group(
92        &mut self,
93        bindings_ctx: &mut BC,
94        device: &Self::DeviceId,
95        addr: MulticastAddr<I::Addr>,
96    ) {
97        ip::device::join_ip_multicast::<I, _, _>(self, bindings_ctx, device, addr)
98    }
99
100    fn leave_multicast_group(
101        &mut self,
102        bindings_ctx: &mut BC,
103        device: &Self::DeviceId,
104        addr: MulticastAddr<I::Addr>,
105    ) {
106        ip::device::leave_ip_multicast::<I, _, _>(self, bindings_ctx, device, addr)
107    }
108
109    fn select_device_for_multicast_group(
110        &mut self,
111        addr: MulticastAddr<I::Addr>,
112        marks: &Marks,
113    ) -> Result<Self::DeviceId, ResolveRouteError> {
114        let remote_ip = SocketIpAddr::new_from_multicast(addr);
115        let ResolvedRoute {
116            src_addr: _,
117            device,
118            local_delivery_device,
119            next_hop: _,
120            internal_forwarding: _,
121        } = ip::resolve_output_route_to_destination(self, None, None, Some(remote_ip), marks)?;
122        // NB: Because the original address is multicast, it cannot be assigned
123        // to a local interface. Thus local delivery should never be requested.
124        debug_assert!(local_delivery_device.is_none(), "{:?}", local_delivery_device);
125        Ok(device)
126    }
127}
128
129impl<BT: BindingsTypes, I: datagram::DualStackIpExt, L> CounterContext<IcmpTxCounters<I>>
130    for CoreCtx<'_, BT, L>
131{
132    fn counters(&self) -> &IcmpTxCounters<I> {
133        &self
134            .unlocked_access::<crate::lock_ordering::UnlockedState>()
135            .inner_icmp_state::<I>()
136            .tx_counters
137    }
138}
139
140impl<BT: BindingsTypes, I: datagram::DualStackIpExt, L> CounterContext<IcmpRxCounters<I>>
141    for CoreCtx<'_, BT, L>
142{
143    fn counters(&self) -> &IcmpRxCounters<I> {
144        &self
145            .unlocked_access::<crate::lock_ordering::UnlockedState>()
146            .inner_icmp_state::<I>()
147            .rx_counters
148    }
149}
150
151impl<BT: BindingsTypes, L> CounterContext<IgmpCounters> for CoreCtx<'_, BT, L> {
152    fn counters(&self) -> &IgmpCounters {
153        &self
154            .unlocked_access::<crate::lock_ordering::UnlockedState>()
155            .inner_ip_state::<Ipv4>()
156            .igmp_counters()
157    }
158}
159
160impl<BT: BindingsTypes, L> ResourceCounterContext<DeviceId<BT>, IgmpCounters>
161    for CoreCtx<'_, BT, L>
162{
163    fn per_resource_counters<'a>(&'a self, device_id: &'a DeviceId<BT>) -> &'a IgmpCounters {
164        for_any_device_id!(
165            DeviceId,
166            device_id,
167            id => self.per_resource_counters(id)
168        )
169    }
170}
171
172impl<BT: BindingsTypes, D: DeviceStateSpec, L>
173    ResourceCounterContext<BaseDeviceId<D, BT>, IgmpCounters> for CoreCtx<'_, BT, L>
174{
175    fn per_resource_counters<'a>(&'a self, device_id: &'a BaseDeviceId<D, BT>) -> &'a IgmpCounters {
176        device_id
177            .device_state(
178                &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
179            )
180            .as_ref()
181            .igmp_counters()
182    }
183}
184
185impl<BT: BindingsTypes, L> CounterContext<MldCounters> for CoreCtx<'_, BT, L> {
186    fn counters(&self) -> &MldCounters {
187        &self
188            .unlocked_access::<crate::lock_ordering::UnlockedState>()
189            .inner_ip_state::<Ipv4>()
190            .mld_counters()
191    }
192}
193
194impl<BT: BindingsTypes, L> ResourceCounterContext<DeviceId<BT>, MldCounters>
195    for CoreCtx<'_, BT, L>
196{
197    fn per_resource_counters<'a>(&'a self, device_id: &'a DeviceId<BT>) -> &'a MldCounters {
198        for_any_device_id!(
199            DeviceId,
200            device_id,
201            id => self.per_resource_counters(id)
202        )
203    }
204}
205
206impl<BT: BindingsTypes, D: DeviceStateSpec, L>
207    ResourceCounterContext<BaseDeviceId<D, BT>, MldCounters> for CoreCtx<'_, BT, L>
208{
209    fn per_resource_counters<'a>(&'a self, device_id: &'a BaseDeviceId<D, BT>) -> &'a MldCounters {
210        device_id
211            .device_state(
212                &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
213            )
214            .as_ref()
215            .mld_counters()
216    }
217}
218
219impl<BT: BindingsTypes, L> CounterContext<NdpCounters> for CoreCtx<'_, BT, L> {
220    fn counters(&self) -> &NdpCounters {
221        &self.unlocked_access::<crate::lock_ordering::UnlockedState>().ipv6.icmp.ndp_counters
222    }
223}
224
225impl<
226    BC: BindingsContext,
227    L: LockBefore<crate::lock_ordering::IcmpBoundMap<Ipv4>>
228        + LockBefore<crate::lock_ordering::TcpAllSocketsSet<Ipv4>>
229        + LockBefore<crate::lock_ordering::UdpAllSocketsSet<Ipv4>>,
230> InnerIcmpv4Context<BC> for CoreCtx<'_, BC, L>
231{
232    fn should_send_timestamp_reply(&self) -> bool {
233        self.unlocked_access::<crate::lock_ordering::UnlockedState>().ipv4.icmp.send_timestamp_reply
234    }
235}
236
237impl<BT: BindingsTypes, I: IpLayerIpExt, L> CounterContext<IpCounters<I>> for CoreCtx<'_, BT, L> {
238    fn counters(&self) -> &IpCounters<I> {
239        &self.unlocked_access::<crate::lock_ordering::UnlockedState>().inner_ip_state().counters()
240    }
241}
242
243impl<BT: BindingsTypes, I: IpLayerIpExt, L> ResourceCounterContext<DeviceId<BT>, IpCounters<I>>
244    for CoreCtx<'_, BT, L>
245{
246    fn per_resource_counters<'a>(&'a self, device_id: &'a DeviceId<BT>) -> &'a IpCounters<I> {
247        for_any_device_id!(
248            DeviceId,
249            device_id,
250            id => self.per_resource_counters(id)
251        )
252    }
253}
254
255impl<BT: BindingsTypes, D: DeviceStateSpec, I: IpLayerIpExt, L>
256    ResourceCounterContext<BaseDeviceId<D, BT>, IpCounters<I>> for CoreCtx<'_, BT, L>
257{
258    fn per_resource_counters<'a>(
259        &'a self,
260        device_id: &'a BaseDeviceId<D, BT>,
261    ) -> &'a IpCounters<I> {
262        device_id
263            .device_state(
264                &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
265            )
266            .as_ref()
267            .ip_counters::<I>()
268    }
269}
270
271#[netstack3_macros::instantiate_ip_impl_block(I)]
272impl<I, BC, L> IpStateContext<I, BC> for CoreCtx<'_, BC, L>
273where
274    I: IpLayerIpExt,
275    BC: BindingsContext,
276    L: LockBefore<crate::lock_ordering::IpStateRulesTable<I>>,
277{
278    type IpRouteTablesCtx<'a> =
279        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpStateRulesTable<I>>>;
280
281    fn with_rules_table<
282        O,
283        F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &RulesTable<I, Self::DeviceId, BC>) -> O,
284    >(
285        &mut self,
286        cb: F,
287    ) -> O {
288        let (rules_table, mut restricted) =
289            self.read_lock_and::<crate::lock_ordering::IpStateRulesTable<I>>();
290        cb(&mut restricted, &rules_table)
291    }
292
293    fn with_rules_table_mut<
294        O,
295        F: FnOnce(&mut Self::IpRouteTablesCtx<'_>, &mut RulesTable<I, Self::DeviceId, BC>) -> O,
296    >(
297        &mut self,
298        cb: F,
299    ) -> O {
300        let (mut rules_table, mut restricted) =
301            self.write_lock_and::<crate::lock_ordering::IpStateRulesTable<I>>();
302        cb(&mut restricted, &mut rules_table)
303    }
304}
305
306#[netstack3_macros::instantiate_ip_impl_block(I)]
307impl<I, BC, L> IpRouteTablesContext<I, BC> for CoreCtx<'_, BC, L>
308where
309    I: IpLayerIpExt,
310    BC: BindingsContext,
311    L: LockBefore<crate::lock_ordering::IpStateRoutingTables<I>>,
312{
313    type Ctx<'a> = CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpStateRoutingTables<I>>>;
314
315    fn main_table_id(&self) -> RoutingTableId<I, Self::DeviceId, BC> {
316        self.unlocked_access::<crate::lock_ordering::UnlockedState>()
317            .inner_ip_state()
318            .main_table_id()
319            .clone()
320    }
321
322    fn with_ip_routing_tables<
323        O,
324        F: FnOnce(
325            &mut Self::Ctx<'_>,
326            &HashMap<
327                RoutingTableId<I, Self::DeviceId, BC>,
328                Primary<BaseRoutingTableState<I, Self::DeviceId, BC>>,
329            >,
330        ) -> O,
331    >(
332        &mut self,
333        cb: F,
334    ) -> O {
335        let (table, mut ctx) = self.lock_and::<crate::lock_ordering::IpStateRoutingTables<I>>();
336        cb(&mut ctx, &table)
337    }
338
339    fn with_ip_routing_tables_mut<
340        O,
341        F: FnOnce(
342            &mut HashMap<
343                RoutingTableId<I, Self::DeviceId, BC>,
344                Primary<BaseRoutingTableState<I, Self::DeviceId, BC>>,
345            >,
346        ) -> O,
347    >(
348        &mut self,
349        cb: F,
350    ) -> O {
351        let mut tables = self.lock::<crate::lock_ordering::IpStateRoutingTables<I>>();
352        cb(&mut *tables)
353    }
354}
355
356#[netstack3_macros::instantiate_ip_impl_block(I)]
357impl<I, BC, L> IpRouteTableContext<I, BC> for CoreCtx<'_, BC, L>
358where
359    I: IpLayerIpExt,
360    BC: BindingsContext,
361    L: LockBefore<crate::lock_ordering::IpStateRoutingTable<I>>,
362{
363    type IpDeviceIdCtx<'a> =
364        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpStateRoutingTable<I>>>;
365
366    fn with_ip_routing_table<
367        O,
368        F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &RoutingTable<I, Self::DeviceId>) -> O,
369    >(
370        &mut self,
371        table_id: &RoutingTableId<I, Self::DeviceId, BC>,
372        cb: F,
373    ) -> O {
374        let mut table = self.adopt(table_id);
375        let (table, mut restricted) = table
376            .read_lock_with_and::<crate::lock_ordering::IpStateRoutingTable<I>, _>(|c| c.right());
377        let mut restricted = restricted.cast_core_ctx();
378        cb(&mut restricted, &table)
379    }
380
381    fn with_ip_routing_table_mut<
382        O,
383        F: FnOnce(&mut Self::IpDeviceIdCtx<'_>, &mut RoutingTable<I, Self::DeviceId>) -> O,
384    >(
385        &mut self,
386        table_id: &RoutingTableId<I, Self::DeviceId, BC>,
387        cb: F,
388    ) -> O {
389        let mut table = self.adopt(table_id);
390        let (mut table, mut restricted) = table
391            .write_lock_with_and::<crate::lock_ordering::IpStateRoutingTable<I>, _>(|c| c.right());
392        let mut restricted = restricted.cast_core_ctx();
393        cb(&mut restricted, &mut table)
394    }
395}
396
397pub enum EarlyDemuxSocket<I, D, BT>
398where
399    I: netstack3_datagram::IpExt + netstack3_tcp::DualStackIpExt,
400    D: WeakDeviceIdentifier,
401    BT: UdpBindingsTypes + TcpBindingsTypes,
402{
403    UdpSocket(DualStackUdpSocketId<I, D, BT>),
404    TcpSocket(DualStackTcpSocketId<I, D, BT>),
405}
406
407impl<I, D, BT> EarlyDemuxSocket<I, D, BT>
408where
409    I: netstack3_datagram::IpExt + netstack3_tcp::DualStackIpExt,
410    D: WeakDeviceIdentifier,
411    BT: UdpBindingsTypes + TcpBindingsTypes,
412{
413    // Returns the UDP socket ID if this is a UDP socket, panics otherwise.
414    // Used in `dispatch_receive_ip_packet()` when demultiplexing a UDP packet
415    // (`early_demux()` returns only UDP sockets for UDP packets).
416    fn into_udp(self) -> DualStackUdpSocketId<I, D, BT> {
417        match self {
418            EarlyDemuxSocket::UdpSocket(id) => id,
419            EarlyDemuxSocket::TcpSocket(_) => panic!("not a udp socket"),
420        }
421    }
422
423    // Returns the TCP socket ID if this is a TCP socket, panics otherwise.
424    // Used in `dispatch_receive_ip_packet()` when demultiplexing a TCP packet
425    // (`early_demux()` returns only TCP sockets for TCP packets).
426    fn into_tcp(self) -> DualStackTcpSocketId<I, D, BT> {
427        match self {
428            EarlyDemuxSocket::TcpSocket(id) => id,
429            EarlyDemuxSocket::UdpSocket(_) => panic!("not a tcp socket"),
430        }
431    }
432}
433
434impl<I, D, BT, CC> SocketMetadata<CC> for EarlyDemuxSocket<I, D, BT>
435where
436    CC: netstack3_base::DeviceIdContext<netstack3_base::AnyDevice, WeakDeviceId = D>,
437    I: netstack3_datagram::IpExt + netstack3_tcp::DualStackIpExt,
438    D: WeakDeviceIdentifier,
439    BT: BindingsTypes,
440    DualStackUdpSocketId<I, D, BT>: SocketMetadata<CC>,
441    DualStackTcpSocketId<I, D, BT>: SocketMetadata<CC>,
442{
443    fn socket_info(&self, core_ctx: &mut CC) -> netstack3_base::socket::SocketInfo {
444        match self {
445            Self::UdpSocket(s) => s.socket_info(core_ctx),
446            Self::TcpSocket(s) => s.socket_info(core_ctx),
447        }
448    }
449
450    fn marks(&self, core_ctx: &mut CC) -> Marks {
451        match self {
452            Self::UdpSocket(s) => s.marks(core_ctx),
453            Self::TcpSocket(s) => s.marks(core_ctx),
454        }
455    }
456}
457
458impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv4>>>
459    IpTransportDispatchContext<Ipv4, BC> for CoreCtx<'_, BC, L>
460{
461    type EarlyDemuxSocket = EarlyDemuxSocket<Ipv4, Self::WeakDeviceId, BC>;
462
463    fn early_demux<B: ParseBuffer>(
464        &mut self,
465        device: &Self::DeviceId,
466        frame_dst: Option<LocalFrameDestination>,
467        src_ip: Ipv4Addr,
468        dst_ip: Ipv4Addr,
469        proto: Ipv4Proto,
470        body: B,
471    ) -> Option<Self::EarlyDemuxSocket> {
472        // Only unicast packets are demuxed early.
473        // TODO(https://fxbug.com/476450053): Consider early demuxing multicast
474        // packets as well.
475        match frame_dst {
476            Some(FrameDestination::Individual { local: () }) => (),
477            Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) | None => {
478                return None;
479            }
480        };
481
482        match proto {
483            Ipv4Proto::Proto(IpProto::Udp) => {
484                <UdpIpTransportContext as IpTransportContext<Ipv4, _, _>>::early_demux(
485                    self, device, src_ip, dst_ip, body,
486                )
487                .map(EarlyDemuxSocket::UdpSocket)
488            }
489            Ipv4Proto::Proto(IpProto::Tcp) => {
490                <TcpIpTransportContext as IpTransportContext<Ipv4, _, _>>::early_demux(
491                    self, device, src_ip, dst_ip, body,
492                )
493                .map(EarlyDemuxSocket::TcpSocket)
494            }
495            Ipv4Proto::Icmp
496            | Ipv4Proto::Igmp
497            | Ipv4Proto::Proto(IpProto::Reserved)
498            | Ipv4Proto::Other(_) => None,
499        }
500    }
501
502    fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv4>>(
503        &mut self,
504        bindings_ctx: &mut BC,
505        device: &Self::DeviceId,
506        src_ip: Ipv4SourceAddr,
507        dst_ip: SpecifiedAddr<Ipv4Addr>,
508        proto: Ipv4Proto,
509        body: B,
510        info: &mut LocalDeliveryPacketInfo<Ipv4, H>,
511        early_demux_socket: Option<Self::EarlyDemuxSocket>,
512    ) -> Result<(), Icmpv4Error> {
513        match proto {
514            Ipv4Proto::Icmp => {
515                <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
516                    self,
517                    bindings_ctx,
518                    device,
519                    src_ip,
520                    dst_ip,
521                    body,
522                    info,
523                    None,
524                )
525                .map_err(|(_body, err)| err)
526            }
527            Ipv4Proto::Igmp => {
528                device::receive_igmp_packet(self, bindings_ctx, device, src_ip, dst_ip, body, info);
529                Ok(())
530            }
531            Ipv4Proto::Proto(IpProto::Udp) => {
532                <UdpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
533                    self,
534                    bindings_ctx,
535                    device,
536                    src_ip,
537                    dst_ip,
538                    body,
539                    info,
540                    early_demux_socket.map(EarlyDemuxSocket::into_udp),
541                )
542                .map_err(|(_body, err)| err)
543            }
544            Ipv4Proto::Proto(IpProto::Tcp) => {
545                <TcpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
546                    self,
547                    bindings_ctx,
548                    device,
549                    src_ip,
550                    dst_ip,
551                    body,
552                    info,
553                    early_demux_socket.map(EarlyDemuxSocket::into_tcp),
554                )
555                .map_err(|(_body, err)| err)
556            }
557            Ipv4Proto::Proto(IpProto::Reserved) | Ipv4Proto::Other(_) => {
558                Err(Icmpv4Error::ProtocolUnreachable)
559            }
560        }
561    }
562}
563
564impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv6>>>
565    IpTransportDispatchContext<Ipv6, BC> for CoreCtx<'_, BC, L>
566{
567    type EarlyDemuxSocket = EarlyDemuxSocket<Ipv6, Self::WeakDeviceId, BC>;
568
569    fn early_demux<B: ParseBuffer>(
570        &mut self,
571        device: &Self::DeviceId,
572        frame_dst: Option<LocalFrameDestination>,
573        src_ip: Ipv6Addr,
574        dst_ip: Ipv6Addr,
575        proto: Ipv6Proto,
576        body: B,
577    ) -> Option<Self::EarlyDemuxSocket> {
578        // Only unicast packets are demuxed early.
579        // TODO(https://fxbug.com/476450053): Consider early demuxing multicast
580        // packets as well.
581        match frame_dst {
582            Some(FrameDestination::Individual { local: () }) => (),
583            Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) | None => {
584                return None;
585            }
586        };
587
588        match proto {
589            Ipv6Proto::Proto(IpProto::Udp) => {
590                <UdpIpTransportContext as IpTransportContext<Ipv6, _, _>>::early_demux(
591                    self, device, src_ip, dst_ip, body,
592                )
593                .map(EarlyDemuxSocket::UdpSocket)
594            }
595            Ipv6Proto::Proto(IpProto::Tcp) => {
596                <TcpIpTransportContext as IpTransportContext<Ipv6, _, _>>::early_demux(
597                    self, device, src_ip, dst_ip, body,
598                )
599                .map(EarlyDemuxSocket::TcpSocket)
600            }
601            Ipv6Proto::Icmpv6
602            | Ipv6Proto::NoNextHeader
603            | Ipv6Proto::Proto(IpProto::Reserved)
604            | Ipv6Proto::Other(_) => None,
605        }
606    }
607
608    fn dispatch_receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
609        &mut self,
610        bindings_ctx: &mut BC,
611        device: &Self::DeviceId,
612        src_ip: Ipv6SourceAddr,
613        dst_ip: SpecifiedAddr<Ipv6Addr>,
614        proto: Ipv6Proto,
615        body: B,
616        info: &mut LocalDeliveryPacketInfo<Ipv6, H>,
617        early_demux_socket: Option<Self::EarlyDemuxSocket>,
618    ) -> Result<(), Icmpv6Error> {
619        match proto {
620            Ipv6Proto::Icmpv6 => {
621                <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
622                    self,
623                    bindings_ctx,
624                    device,
625                    src_ip,
626                    dst_ip,
627                    body,
628                    info,
629                    None,
630                )
631                .map_err(|(_body, err)| err)
632            }
633            // A value of `Ipv6Proto::NoNextHeader` tells us that there is no
634            // header whatsoever following the last lower-level header so we stop
635            // processing here.
636            Ipv6Proto::NoNextHeader => Ok(()),
637            Ipv6Proto::Proto(IpProto::Tcp) => {
638                <TcpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
639                    self,
640                    bindings_ctx,
641                    device,
642                    src_ip,
643                    dst_ip,
644                    body,
645                    info,
646                    early_demux_socket.map(EarlyDemuxSocket::into_tcp),
647                )
648                .map_err(|(_body, err)| err)
649            }
650            Ipv6Proto::Proto(IpProto::Udp) => {
651                <UdpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
652                    self,
653                    bindings_ctx,
654                    device,
655                    src_ip,
656                    dst_ip,
657                    body,
658                    info,
659                    early_demux_socket.map(EarlyDemuxSocket::into_udp),
660                )
661                .map_err(|(_body, err)| err)
662            }
663            Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::Other(_) => {
664                // The next header should not be unrecognized at this point.
665                // Packet parsing should have detected this, and for fragmented
666                // packets additional parsing and checks after reassembly should
667                // guarantee that this invariant is upheld.
668                unreachable!()
669            }
670        }
671    }
672}
673
674impl<
675    BC: BindingsContext,
676    L: LockBefore<crate::lock_ordering::IcmpBoundMap<Ipv4>>
677        + LockBefore<crate::lock_ordering::TcpAllSocketsSet<Ipv4>>
678        + LockBefore<crate::lock_ordering::UdpAllSocketsSet<Ipv4>>,
679> InnerIcmpContext<Ipv4, BC> for CoreCtx<'_, BC, L>
680{
681    type EchoTransportContext = IcmpEchoIpTransportContext;
682
683    fn receive_icmp_error(
684        &mut self,
685        bindings_ctx: &mut BC,
686        device: &DeviceId<BC>,
687        original_src_ip: Option<SpecifiedAddr<Ipv4Addr>>,
688        original_dst_ip: SpecifiedAddr<Ipv4Addr>,
689        original_proto: Ipv4Proto,
690        original_body: &[u8],
691        err: Icmpv4ErrorCode,
692    ) {
693        self.increment_both(device, |c: &IpCounters<Ipv4>| &c.receive_icmp_error);
694        trace!("InnerIcmpContext<Ipv4>::receive_icmp_error({:?})", err);
695
696        match original_proto {
697            Ipv4Proto::Icmp => {
698                <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_icmp_error(
699                    self,
700                    bindings_ctx,
701                    device,
702                    original_src_ip,
703                    original_dst_ip,
704                    original_body,
705                    err,
706                )
707            }
708            Ipv4Proto::Proto(IpProto::Tcp) => {
709                <TcpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_icmp_error(
710                    self,
711                    bindings_ctx,
712                    device,
713                    original_src_ip,
714                    original_dst_ip,
715                    original_body,
716                    err,
717                )
718            }
719            Ipv4Proto::Proto(IpProto::Udp) => {
720                <UdpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_icmp_error(
721                    self,
722                    bindings_ctx,
723                    device,
724                    original_src_ip,
725                    original_dst_ip,
726                    original_body,
727                    err,
728                )
729            }
730            Ipv4Proto::Igmp | Ipv4Proto::Other(_) | Ipv4Proto::Proto(IpProto::Reserved) => {
731                trace!(
732                    "Received ICMP error message ({:?}) for unsupported IP protocol: {:?}",
733                    err, original_proto
734                );
735            }
736        }
737    }
738}
739
740impl<BC, L> IcmpSendContext<Ipv4, BC> for CoreCtx<'_, BC, L>
741where
742    BC: BindingsContext,
743    L: LockBefore<crate::lock_ordering::IcmpTokenBucket<Ipv4>>,
744{
745    fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
746        &mut self,
747        cb: F,
748    ) -> O {
749        cb(&mut self.lock::<crate::lock_ordering::IcmpTokenBucket<Ipv4>>())
750    }
751}
752
753impl<
754    BC: BindingsContext,
755    L: LockBefore<crate::lock_ordering::IcmpBoundMap<Ipv6>>
756        + LockBefore<crate::lock_ordering::TcpAllSocketsSet<Ipv6>>
757        + LockBefore<crate::lock_ordering::UdpAllSocketsSet<Ipv6>>,
758> InnerIcmpContext<Ipv6, BC> for CoreCtx<'_, BC, L>
759{
760    type EchoTransportContext = IcmpEchoIpTransportContext;
761
762    fn receive_icmp_error(
763        &mut self,
764        bindings_ctx: &mut BC,
765        device: &DeviceId<BC>,
766        original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
767        original_dst_ip: SpecifiedAddr<Ipv6Addr>,
768        original_next_header: Ipv6Proto,
769        original_body: &[u8],
770        err: Icmpv6ErrorCode,
771    ) {
772        self.increment_both(device, |c: &IpCounters<Ipv6>| &c.receive_icmp_error);
773        trace!("InnerIcmpContext<Ipv6>::receive_icmp_error({:?})", err);
774
775        match original_next_header {
776            Ipv6Proto::Icmpv6 => {
777                <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_icmp_error(
778                    self,
779                    bindings_ctx,
780                    device,
781                    original_src_ip,
782                    original_dst_ip,
783                    original_body,
784                    err,
785                )
786            }
787            Ipv6Proto::Proto(IpProto::Tcp) => {
788                <TcpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_icmp_error(
789                    self,
790                    bindings_ctx,
791                    device,
792                    original_src_ip,
793                    original_dst_ip,
794                    original_body,
795                    err,
796                )
797            }
798            Ipv6Proto::Proto(IpProto::Udp) => {
799                <UdpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_icmp_error(
800                    self,
801                    bindings_ctx,
802                    device,
803                    original_src_ip,
804                    original_dst_ip,
805                    original_body,
806                    err,
807                )
808            }
809            Ipv6Proto::NoNextHeader | Ipv6Proto::Other(_) | Ipv6Proto::Proto(IpProto::Reserved) => {
810                trace!(
811                    "Received ICMPv6 error message ({:?}) for unsupported IP protocol: {:?}",
812                    err, original_next_header
813                );
814            }
815        }
816    }
817}
818
819impl<BC, L> IcmpSendContext<Ipv6, BC> for CoreCtx<'_, BC, L>
820where
821    BC: BindingsContext,
822    L: LockBefore<crate::lock_ordering::IcmpTokenBucket<Ipv6>>,
823{
824    fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
825        &mut self,
826        cb: F,
827    ) -> O {
828        cb(&mut self.lock::<crate::lock_ordering::IcmpTokenBucket<Ipv6>>())
829    }
830}
831
832impl<L, BC: BindingsContext> icmp::IcmpStateContext for CoreCtx<'_, BC, L> {}
833
834impl<BT: BindingsTypes, L> IcmpEchoContextMarker for CoreCtx<'_, BT, L> {}
835
836#[netstack3_macros::instantiate_ip_impl_block(I)]
837impl<I, BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<I>>>
838    IcmpEchoStateContext<I, BC> for CoreCtx<'_, BC, L>
839{
840    type SocketStateCtx<'a> =
841        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IcmpSocketState<I>>>;
842
843    fn with_all_sockets_mut<O, F: FnOnce(&mut IcmpSocketSet<I, Self::WeakDeviceId, BC>) -> O>(
844        &mut self,
845        cb: F,
846    ) -> O {
847        cb(&mut self.write_lock::<crate::lock_ordering::IcmpAllSocketsSet<I>>())
848    }
849
850    fn with_all_sockets<O, F: FnOnce(&IcmpSocketSet<I, Self::WeakDeviceId, BC>) -> O>(
851        &mut self,
852        cb: F,
853    ) -> O {
854        cb(&self.read_lock::<crate::lock_ordering::IcmpAllSocketsSet<I>>())
855    }
856
857    fn with_socket_state<
858        O,
859        F: FnOnce(&mut Self::SocketStateCtx<'_>, &IcmpSocketState<I, Self::WeakDeviceId, BC>) -> O,
860    >(
861        &mut self,
862        id: &IcmpSocketId<I, Self::WeakDeviceId, BC>,
863        cb: F,
864    ) -> O {
865        let mut locked = self.adopt(id);
866        let (socket_state, mut restricted) =
867            locked.read_lock_with_and::<crate::lock_ordering::IcmpSocketState<I>, _>(|c| c.right());
868        let mut restricted = restricted.cast_core_ctx();
869        cb(&mut restricted, &socket_state)
870    }
871
872    fn with_socket_state_mut<
873        O,
874        F: FnOnce(&mut Self::SocketStateCtx<'_>, &mut IcmpSocketState<I, Self::WeakDeviceId, BC>) -> O,
875    >(
876        &mut self,
877        id: &IcmpSocketId<I, Self::WeakDeviceId, BC>,
878        cb: F,
879    ) -> O {
880        let mut locked = self.adopt(id);
881        let (mut socket_state, mut restricted) = locked
882            .write_lock_with_and::<crate::lock_ordering::IcmpSocketState<I>, _>(|c| c.right());
883        let mut restricted = restricted.cast_core_ctx();
884        cb(&mut restricted, &mut socket_state)
885    }
886
887    fn with_bound_state_context<O, F: FnOnce(&mut Self::SocketStateCtx<'_>) -> O>(
888        &mut self,
889        cb: F,
890    ) -> O {
891        cb(&mut self.cast_locked::<crate::lock_ordering::IcmpSocketState<I>>())
892    }
893
894    fn for_each_socket<
895        F: FnMut(
896            &mut Self::SocketStateCtx<'_>,
897            &IcmpSocketId<I, Self::WeakDeviceId, BC>,
898            &IcmpSocketState<I, Self::WeakDeviceId, BC>,
899        ),
900    >(
901        &mut self,
902        mut cb: F,
903    ) {
904        let (all_sockets, mut locked) =
905            self.read_lock_and::<crate::lock_ordering::IcmpAllSocketsSet<I>>();
906        all_sockets.keys().for_each(|id| {
907            let id = IcmpSocketId::from(id.clone());
908            let mut locked = locked.adopt(&id);
909            let (socket_state, mut restricted) = locked
910                .read_lock_with_and::<crate::lock_ordering::IcmpSocketState<I>, _>(|c| c.right());
911            let mut restricted = restricted.cast_core_ctx();
912            cb(&mut restricted, &id, &socket_state);
913        });
914    }
915}
916
917#[netstack3_macros::instantiate_ip_impl_block(I)]
918impl<I, BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpBoundMap<I>>>
919    IcmpEchoBoundStateContext<I, BC> for CoreCtx<'_, BC, L>
920{
921    type IpSocketsCtx<'a> = CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IcmpBoundMap<I>>>;
922    fn with_icmp_ctx_and_sockets_mut<
923        O,
924        F: FnOnce(
925            &mut Self::IpSocketsCtx<'_>,
926            &mut icmp_echo::BoundSockets<I, Self::WeakDeviceId, BC>,
927        ) -> O,
928    >(
929        &mut self,
930        cb: F,
931    ) -> O {
932        let (mut sockets, mut core_ctx) =
933            self.write_lock_and::<crate::lock_ordering::IcmpBoundMap<I>>();
934        cb(&mut core_ctx, &mut sockets)
935    }
936}
937
938impl<I: IpLayerIpExt, BT: BindingsTypes> DelegatedOrderedLockAccess<IpPacketFragmentCache<I, BT>>
939    for StackState<BT>
940{
941    type Inner = IpStateInner<I, DeviceId<BT>, BT>;
942    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
943        self.inner_ip_state()
944    }
945}
946
947impl<I: IpLayerIpExt, BT: BindingsTypes> LockLevelFor<StackState<BT>>
948    for crate::lock_ordering::IpStateFragmentCache<I>
949{
950    type Data = IpPacketFragmentCache<I, BT>;
951}
952
953impl<I: IpLayerIpExt, BT: BindingsTypes> DelegatedOrderedLockAccess<PmtuCache<I, BT>>
954    for StackState<BT>
955{
956    type Inner = IpStateInner<I, DeviceId<BT>, BT>;
957    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
958        self.inner_ip_state()
959    }
960}
961
962impl<I: IpLayerIpExt, BT: BindingsTypes> LockLevelFor<StackState<BT>>
963    for crate::lock_ordering::IpStateRulesTable<I>
964{
965    type Data = RulesTable<I, DeviceId<BT>, BT>;
966}
967
968impl<I: IpLayerIpExt, BT: BindingsTypes> DelegatedOrderedLockAccess<RulesTable<I, DeviceId<BT>, BT>>
969    for StackState<BT>
970{
971    type Inner = IpStateInner<I, DeviceId<BT>, BT>;
972    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
973        self.inner_ip_state()
974    }
975}
976
977impl<I: IpLayerIpExt, BT: BindingsTypes> LockLevelFor<StackState<BT>>
978    for crate::lock_ordering::IpStatePmtuCache<I>
979{
980    type Data = PmtuCache<I, BT>;
981}
982
983impl<I: IpLayerIpExt, BT: BindingsTypes> LockLevelFor<StackState<BT>>
984    for crate::lock_ordering::IpStateRoutingTables<I>
985{
986    type Data = HashMap<
987        RoutingTableId<I, DeviceId<BT>, BT>,
988        Primary<BaseRoutingTableState<I, DeviceId<BT>, BT>>,
989    >;
990}
991
992impl<I: IpLayerIpExt, BT: BindingsTypes>
993    DelegatedOrderedLockAccess<
994        HashMap<
995            RoutingTableId<I, DeviceId<BT>, BT>,
996            Primary<BaseRoutingTableState<I, DeviceId<BT>, BT>>,
997        >,
998    > for StackState<BT>
999{
1000    type Inner = IpStateInner<I, DeviceId<BT>, BT>;
1001    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
1002        self.inner_ip_state()
1003    }
1004}
1005
1006impl<I: IpLayerIpExt, BT: BindingsTypes> LockLevelFor<RoutingTableId<I, DeviceId<BT>, BT>>
1007    for crate::lock_ordering::IpStateRoutingTable<I>
1008{
1009    type Data = RoutingTable<I, DeviceId<BT>>;
1010}
1011
1012impl<I: IpLayerIpExt, BT: BindingsTypes>
1013    DelegatedOrderedLockAccess<MulticastForwardingState<I, DeviceId<BT>, BT>> for StackState<BT>
1014{
1015    type Inner = IpStateInner<I, DeviceId<BT>, BT>;
1016    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
1017        self.inner_ip_state()
1018    }
1019}
1020
1021impl<I: IpLayerIpExt, BT: BindingsTypes> LockLevelFor<StackState<BT>>
1022    for crate::lock_ordering::IpMulticastForwardingState<I>
1023{
1024    type Data = MulticastForwardingState<I, DeviceId<BT>, BT>;
1025}
1026
1027impl<I: IpLayerIpExt, BT: BindingsTypes>
1028    DelegatedOrderedLockAccess<RawIpSocketMap<I, WeakDeviceId<BT>, BT>> for StackState<BT>
1029{
1030    type Inner = IpStateInner<I, DeviceId<BT>, BT>;
1031    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
1032        self.inner_ip_state()
1033    }
1034}
1035
1036impl<I: IpLayerIpExt, BT: BindingsTypes> LockLevelFor<StackState<BT>>
1037    for crate::lock_ordering::AllRawIpSockets<I>
1038{
1039    type Data = RawIpSocketMap<I, WeakDeviceId<BT>, BT>;
1040}
1041
1042impl<I: datagram::DualStackIpExt, BT: BindingsTypes>
1043    DelegatedOrderedLockAccess<icmp_echo::BoundSockets<I, WeakDeviceId<BT>, BT>>
1044    for StackState<BT>
1045{
1046    type Inner = IcmpSockets<I, WeakDeviceId<BT>, BT>;
1047    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
1048        &self.transport.icmp_echo_state()
1049    }
1050}
1051
1052impl<I: datagram::DualStackIpExt, BT: BindingsTypes> LockLevelFor<StackState<BT>>
1053    for crate::lock_ordering::IcmpBoundMap<I>
1054{
1055    type Data = icmp_echo::BoundSockets<I, WeakDeviceId<BT>, BT>;
1056}
1057
1058impl<I: datagram::DualStackIpExt, BT: BindingsTypes>
1059    DelegatedOrderedLockAccess<IcmpSocketSet<I, WeakDeviceId<BT>, BT>> for StackState<BT>
1060{
1061    type Inner = IcmpSockets<I, WeakDeviceId<BT>, BT>;
1062    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
1063        &self.transport.icmp_echo_state()
1064    }
1065}
1066
1067impl<I: datagram::DualStackIpExt, BT: BindingsTypes> LockLevelFor<StackState<BT>>
1068    for crate::lock_ordering::IcmpAllSocketsSet<I>
1069{
1070    type Data = IcmpSocketSet<I, WeakDeviceId<BT>, BT>;
1071}
1072
1073impl<I: datagram::DualStackIpExt, BT: BindingsTypes>
1074    DelegatedOrderedLockAccess<IpMarked<I, TokenBucket<BT::Instant>>> for StackState<BT>
1075{
1076    type Inner = IcmpState<I, BT>;
1077    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
1078        self.inner_icmp_state()
1079    }
1080}
1081
1082impl<I: datagram::DualStackIpExt, BT: BindingsTypes> LockLevelFor<StackState<BT>>
1083    for crate::lock_ordering::IcmpTokenBucket<I>
1084{
1085    type Data = IpMarked<I, TokenBucket<BT::Instant>>;
1086}
1087
1088impl<I: datagram::DualStackIpExt, D: WeakDeviceIdentifier, BT: BindingsTypes>
1089    LockLevelFor<IcmpSocketId<I, D, BT>> for crate::lock_ordering::IcmpSocketState<I>
1090{
1091    type Data = IcmpSocketState<I, D, BT>;
1092}