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