Skip to main content

netstack3_core/device/
base.rs

1// Copyright 2023 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//! Implementations of device layer traits for [`CoreCtx`].
6
7use core::fmt::Debug;
8use core::num::NonZeroU8;
9use core::ops::Deref as _;
10
11use lock_order::lock::{DelegatedOrderedLockAccess, LockLevelFor, UnlockedAccess};
12use lock_order::relation::LockBefore;
13use log::debug;
14use net_types::ethernet::Mac;
15use net_types::ip::{
16    AddrSubnet, Ip, IpAddress, IpInvariant, IpVersion, IpVersionMarker, Ipv4, Ipv4Addr, Ipv6,
17    Ipv6Addr, Mtu,
18};
19use net_types::{MulticastAddr, SpecifiedAddr, UnicastAddr, Witness as _, map_ip_twice};
20use netstack3_base::{
21    AnyDevice, BroadcastIpExt, CounterContext, DeviceIdContext, ExistsError, IpAddressId,
22    IpDeviceAddressIdContext, Ipv4DeviceAddr, Ipv6DeviceAddr, NetworkSerializer, NotFoundError,
23    ReceivableFrameMeta, RecvIpFrameMeta, ReferenceNotifiersExt, RemoveResourceResultWithContext,
24    ResourceCounterContext, SendFrameError, WeakDeviceIdentifier,
25};
26use netstack3_device::blackhole::{BlackholeDeviceCounters, BlackholeDeviceId};
27use netstack3_device::ethernet::{
28    self, EthernetDeviceCounters, EthernetDeviceId, EthernetIpLinkDeviceDynamicStateContext,
29    EthernetLinkDevice, EthernetPrimaryDeviceId, EthernetWeakDeviceId,
30};
31use netstack3_device::loopback::{self, LoopbackDevice, LoopbackDeviceId, LoopbackPrimaryDeviceId};
32use netstack3_device::pure_ip::{self, PureIpDeviceCounters, PureIpDeviceId};
33use netstack3_device::queue::TransmitQueueHandler;
34use netstack3_device::socket::{DeviceSocketCounters, DeviceSocketId, HeldDeviceSockets};
35use netstack3_device::{
36    ArpCounters, BaseDeviceId, DeviceCollectionContext, DeviceConfigurationContext, DeviceCounters,
37    DeviceId, DeviceLayerState, DeviceStateSpec, Devices, DevicesIter, IpLinkDeviceState,
38    IpLinkDeviceStateInner, Ipv6DeviceLinkLayerAddr, OriginTracker, OriginTrackerContext,
39    WeakDeviceId, for_any_device_id,
40};
41use netstack3_filter::ProofOfEgressCheck;
42use netstack3_ip::device::{
43    AddressId, AddressIdIter, DadState, DualStackIpDeviceState, IpAddressData, IpAddressEntry,
44    IpDeviceAddAddressContext, IpDeviceAddressContext, IpDeviceConfigurationContext, IpDeviceFlags,
45    IpDeviceIpExt, IpDeviceSendContext, IpDeviceStateContext, Ipv4AddrConfig,
46    Ipv4DeviceConfiguration, Ipv6AddrConfig, Ipv6DeviceConfiguration,
47    Ipv6DeviceConfigurationContext, Ipv6DeviceContext, Ipv6NetworkLearnedParameters,
48    PrimaryAddressId, WeakAddressId,
49};
50use netstack3_ip::nud::{
51    ConfirmationFlags, DynamicNeighborUpdateSource, NudHandler, NudIpHandler, NudUserConfig,
52};
53use netstack3_ip::{
54    self as ip, DeviceIpLayerMetadata, IpPacketDestination, IpRoutingDeviceContext, RawMetric,
55};
56use packet::BufferMut;
57use packet_formats::ethernet::EthernetIpExt;
58
59use crate::context::prelude::*;
60use crate::context::{CoreCtxAndResource, Locked, WrapLockLevel};
61use crate::ip::integration::CoreCtxWithIpDeviceConfiguration;
62use crate::{BindingsContext, BindingsTypes, CoreCtx, StackState};
63
64fn bytes_to_unicast_mac(b: &[u8]) -> Option<UnicastAddr<Mac>> {
65    (b.len() >= Mac::BYTES)
66        .then(|| {
67            let mut bytes = [0; Mac::BYTES];
68            bytes.copy_from_slice(&b[..Mac::BYTES]);
69            Mac::new(bytes)
70        })
71        .and_then(UnicastAddr::new)
72}
73
74impl<
75    I: Ip,
76    BC: BindingsContext,
77    L: LockBefore<crate::lock_ordering::EthernetIpv4Arp>
78        + LockBefore<crate::lock_ordering::EthernetIpv6Nud>,
79> NudIpHandler<I, BC> for CoreCtx<'_, BC, L>
80where
81    Self: NudHandler<I, EthernetLinkDevice, BC>
82        + DeviceIdContext<EthernetLinkDevice, DeviceId = EthernetDeviceId<BC>>,
83{
84    fn handle_neighbor_probe(
85        &mut self,
86        bindings_ctx: &mut BC,
87        device_id: &DeviceId<BC>,
88        neighbor: SpecifiedAddr<I::Addr>,
89        link_addr: &[u8],
90    ) {
91        match device_id {
92            DeviceId::Ethernet(id) => {
93                if let Some(link_address) = bytes_to_unicast_mac(link_addr) {
94                    NudHandler::<I, EthernetLinkDevice, _>::handle_neighbor_update(
95                        self,
96                        bindings_ctx,
97                        &id,
98                        neighbor,
99                        DynamicNeighborUpdateSource::Probe { link_address },
100                    )
101                }
102            }
103            // NUD is not supported on Loopback, Blackhole, and Pure IP devices.
104            DeviceId::Loopback(LoopbackDeviceId { .. })
105            | DeviceId::Blackhole(BlackholeDeviceId { .. })
106            | DeviceId::PureIp(PureIpDeviceId { .. }) => {}
107        }
108    }
109
110    fn handle_neighbor_confirmation(
111        &mut self,
112        bindings_ctx: &mut BC,
113        device_id: &DeviceId<BC>,
114        neighbor: SpecifiedAddr<I::Addr>,
115        link_addr: Option<&[u8]>,
116        flags: ConfirmationFlags,
117    ) {
118        match device_id {
119            DeviceId::Ethernet(id) => {
120                let link_address = match link_addr {
121                    Some(link_addr) => {
122                        // Drop a confirmation with a link address that is not long enough or
123                        // not unicast.
124                        let Some(link_addr) = bytes_to_unicast_mac(link_addr) else {
125                            return;
126                        };
127                        Some(link_addr)
128                    }
129                    None => None,
130                };
131
132                NudHandler::<I, EthernetLinkDevice, _>::handle_neighbor_update(
133                    self,
134                    bindings_ctx,
135                    &id,
136                    neighbor,
137                    DynamicNeighborUpdateSource::Confirmation { link_address, flags },
138                )
139            }
140            // NUD is not supported on Loopback, Blackhole, and Pure IP devices.
141            DeviceId::Loopback(LoopbackDeviceId { .. })
142            | DeviceId::Blackhole(BlackholeDeviceId { .. })
143            | DeviceId::PureIp(PureIpDeviceId { .. }) => {}
144        }
145    }
146
147    fn flush_neighbor_table(&mut self, bindings_ctx: &mut BC, device_id: &DeviceId<BC>) {
148        match device_id {
149            DeviceId::Ethernet(id) => {
150                NudHandler::<I, EthernetLinkDevice, _>::flush(self, bindings_ctx, &id)
151            }
152            // NUD is not supported on Loopback, Blackhole, and Pure IP devices.
153            DeviceId::Loopback(LoopbackDeviceId { .. })
154            | DeviceId::Blackhole(BlackholeDeviceId { .. })
155            | DeviceId::PureIp(PureIpDeviceId { .. }) => {}
156        }
157    }
158}
159
160impl<I, D, L, BC> ReceivableFrameMeta<CoreCtx<'_, BC, L>, BC>
161    for RecvIpFrameMeta<D, DeviceIpLayerMetadata<BC>, I>
162where
163    BC: BindingsContext,
164    D: Into<DeviceId<BC>>,
165    L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv4>>,
166    I: Ip,
167{
168    fn receive_meta<B: BufferMut + Debug>(
169        self,
170        core_ctx: &mut CoreCtx<'_, BC, L>,
171        bindings_ctx: &mut BC,
172        frame: B,
173    ) {
174        let RecvIpFrameMeta {
175            device,
176            frame_dst,
177            ip_layer_metadata,
178            marker: IpVersionMarker { .. },
179            parsing_context,
180        } = self;
181        let device = device.into();
182        match I::VERSION {
183            IpVersion::V4 => ip::receive_ipv4_packet(
184                core_ctx,
185                bindings_ctx,
186                &device,
187                frame_dst,
188                ip_layer_metadata,
189                parsing_context,
190                frame,
191            ),
192            IpVersion::V6 => ip::receive_ipv6_packet(
193                core_ctx,
194                bindings_ctx,
195                &device,
196                frame_dst,
197                ip_layer_metadata,
198                parsing_context,
199                frame,
200            ),
201        }
202    }
203}
204
205#[netstack3_macros::instantiate_ip_impl_block(I)]
206impl<I: BroadcastIpExt, BC: BindingsContext, L: LockBefore<crate::lock_ordering::FilterState<I>>>
207    IpDeviceSendContext<I, BC> for CoreCtx<'_, BC, L>
208{
209    fn send_ip_frame<S>(
210        &mut self,
211        bindings_ctx: &mut BC,
212        device: &DeviceId<BC>,
213        destination: IpPacketDestination<I, &DeviceId<BC>>,
214        ip_layer_metadata: DeviceIpLayerMetadata<BC>,
215        body: S,
216        ProofOfEgressCheck { .. }: ProofOfEgressCheck,
217    ) -> Result<(), SendFrameError<S>>
218    where
219        S: NetworkSerializer,
220        S::Buffer: BufferMut,
221    {
222        send_ip_frame(self, bindings_ctx, device, destination, ip_layer_metadata, body)
223    }
224}
225
226#[netstack3_macros::instantiate_ip_impl_block(I)]
227impl<
228    I: BroadcastIpExt,
229    Config,
230    BC: BindingsContext,
231    L: LockBefore<crate::lock_ordering::FilterState<I>>,
232> IpDeviceSendContext<I, BC> for CoreCtxWithIpDeviceConfiguration<'_, Config, L, BC>
233{
234    fn send_ip_frame<S>(
235        &mut self,
236        bindings_ctx: &mut BC,
237        device: &DeviceId<BC>,
238        destination: IpPacketDestination<I, &DeviceId<BC>>,
239        ip_layer_metadata: DeviceIpLayerMetadata<BC>,
240        body: S,
241        ProofOfEgressCheck { .. }: ProofOfEgressCheck,
242    ) -> Result<(), SendFrameError<S>>
243    where
244        S: NetworkSerializer,
245        S::Buffer: BufferMut,
246    {
247        let Self { config: _, core_ctx } = self;
248        send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_layer_metadata, body)
249    }
250}
251
252impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>>
253    IpDeviceConfigurationContext<Ipv4, BC> for CoreCtx<'_, BC, L>
254{
255    type DevicesIter<'s> = DevicesIter<'s, BC>;
256    type WithIpDeviceConfigurationInnerCtx<'s> = CoreCtxWithIpDeviceConfiguration<
257        's,
258        &'s Ipv4DeviceConfiguration,
259        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>,
260        BC,
261    >;
262    type WithIpDeviceConfigurationMutInner<'s> = CoreCtxWithIpDeviceConfiguration<
263        's,
264        &'s mut Ipv4DeviceConfiguration,
265        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>,
266        BC,
267    >;
268    type DeviceAddressAndGroupsAccessor<'s> =
269        CoreCtx<'s, BC, WrapLockLevel<crate::lock_ordering::DeviceLayerState>>;
270
271    fn with_ip_device_configuration<
272        O,
273        F: FnOnce(&Ipv4DeviceConfiguration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
274    >(
275        &mut self,
276        device_id: &Self::DeviceId,
277        cb: F,
278    ) -> O {
279        let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
280        let (state, mut locked) = core_ctx_and_resource
281            .read_lock_with_and::<crate::lock_ordering::IpDeviceConfiguration<Ipv4>, _>(|c| {
282                c.right()
283            });
284        cb(
285            &state,
286            CoreCtxWithIpDeviceConfiguration { config: &state, core_ctx: locked.cast_core_ctx() },
287        )
288    }
289
290    fn with_ip_device_configuration_mut<
291        O,
292        F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
293    >(
294        &mut self,
295        device_id: &Self::DeviceId,
296        cb: F,
297    ) -> O {
298        let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
299        let (mut state, mut locked) = core_ctx_and_resource
300            .write_lock_with_and::<crate::lock_ordering::IpDeviceConfiguration<Ipv4>, _>(
301            |c| c.right(),
302        );
303        cb(CoreCtxWithIpDeviceConfiguration {
304            config: &mut state,
305            core_ctx: locked.cast_core_ctx(),
306        })
307    }
308
309    fn with_devices_and_state<
310        O,
311        F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
312    >(
313        &mut self,
314        cb: F,
315    ) -> O {
316        let (devices, locked) = self.read_lock_and::<crate::lock_ordering::DeviceLayerState>();
317        cb(devices.iter(), locked)
318    }
319
320    fn loopback_id(&mut self) -> Option<Self::DeviceId> {
321        let devices = &*self.read_lock::<crate::lock_ordering::DeviceLayerState>();
322        devices.loopback.as_ref().map(|primary| DeviceId::Loopback(primary.clone_strong()))
323    }
324}
325
326impl<BC: BindingsContext, L> IpDeviceAddressIdContext<Ipv4> for CoreCtx<'_, BC, L> {
327    type AddressId = AddressId<Ipv4, BC>;
328    type WeakAddressId = WeakAddressId<Ipv4, BC>;
329}
330
331impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddresses<Ipv4>>>
332    IpDeviceAddAddressContext<Ipv4, BC> for CoreCtx<'_, BC, L>
333{
334    fn add_ip_address(
335        &mut self,
336        device_id: &Self::DeviceId,
337        addr: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
338        config: Ipv4AddrConfig<BC::Instant>,
339    ) -> Result<Self::AddressId, ExistsError> {
340        let mut state = ip_device_state(self, device_id);
341        let addr_id = state
342            .write_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>()
343            .add(IpAddressEntry::new(addr, DadState::Uninitialized, config));
344        addr_id
345    }
346}
347
348impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddresses<Ipv4>>>
349    IpDeviceStateContext<Ipv4, BC> for CoreCtx<'_, BC, L>
350{
351    type IpDeviceAddressCtx<'a> =
352        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpDeviceAddresses<Ipv4>>>;
353
354    fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
355        &mut self,
356        device_id: &Self::DeviceId,
357        cb: F,
358    ) -> O {
359        let mut state = ip_device_state(self, device_id);
360        let flags = &*state.lock::<crate::lock_ordering::IpDeviceFlags<Ipv4>>();
361        cb(flags)
362    }
363
364    fn remove_ip_address(
365        &mut self,
366        device_id: &Self::DeviceId,
367        addr: Self::AddressId,
368    ) -> RemoveResourceResultWithContext<AddrSubnet<Ipv4Addr>, BC> {
369        let mut state = ip_device_state(self, device_id);
370        let primary = state
371            .write_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>()
372            .remove(&addr.addr().addr())
373            .expect("should exist when address ID exists");
374        assert!(PrimaryAddressId::ptr_eq(&primary, &addr));
375        core::mem::drop(addr);
376
377        BC::unwrap_or_notify_with_new_reference_notifier(primary.into_inner(), |entry| {
378            entry.addr_sub().to_witness::<SpecifiedAddr<_>>()
379        })
380    }
381
382    fn get_address_id(
383        &mut self,
384        device_id: &Self::DeviceId,
385        addr: SpecifiedAddr<Ipv4Addr>,
386    ) -> Result<Self::AddressId, NotFoundError> {
387        let mut state = ip_device_state(self, device_id);
388        let addr_id = state
389            .read_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>()
390            .iter()
391            .find(|a| {
392                let a: Ipv4Addr = a.addr().get();
393                a == *addr
394            })
395            .map(PrimaryAddressId::clone_strong)
396            .ok_or(NotFoundError);
397        addr_id
398    }
399
400    type AddressIdsIter<'a> = AddressIdIter<'a, Ipv4, BC>;
401    fn with_address_ids<
402        O,
403        F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
404    >(
405        &mut self,
406        device_id: &Self::DeviceId,
407        cb: F,
408    ) -> O {
409        let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
410        let (state, mut locked) = core_ctx_and_resource
411            .read_lock_with_and::<crate::lock_ordering::IpDeviceAddresses<Ipv4>, _>(|c| c.right());
412        cb(state.strong_iter(), &mut locked.cast_core_ctx())
413    }
414
415    fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
416        &mut self,
417        device_id: &Self::DeviceId,
418        cb: F,
419    ) -> O {
420        let mut state = ip_device_state(self, device_id);
421        let mut state = state.read_lock::<crate::lock_ordering::IpDeviceDefaultHopLimit<Ipv4>>();
422        cb(&mut state)
423    }
424
425    fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
426        &mut self,
427        device_id: &Self::DeviceId,
428        cb: F,
429    ) -> O {
430        let mut state = ip_device_state(self, device_id);
431        let mut state = state.write_lock::<crate::lock_ordering::IpDeviceDefaultHopLimit<Ipv4>>();
432        cb(&mut state)
433    }
434
435    fn join_link_multicast_group(
436        &mut self,
437        bindings_ctx: &mut BC,
438        device_id: &Self::DeviceId,
439        multicast_addr: MulticastAddr<Ipv4Addr>,
440    ) {
441        join_link_multicast_group(self, bindings_ctx, device_id, multicast_addr)
442    }
443
444    fn leave_link_multicast_group(
445        &mut self,
446        bindings_ctx: &mut BC,
447        device_id: &Self::DeviceId,
448        multicast_addr: MulticastAddr<Ipv4Addr>,
449    ) {
450        leave_link_multicast_group(self, bindings_ctx, device_id, multicast_addr)
451    }
452}
453
454impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>>
455    Ipv6DeviceConfigurationContext<BC> for CoreCtx<'_, BC, L>
456{
457    type Ipv6DeviceStateCtx<'s> = CoreCtxWithIpDeviceConfiguration<
458        's,
459        &'s Ipv6DeviceConfiguration,
460        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
461        BC,
462    >;
463    type WithIpv6DeviceConfigurationMutInner<'s> = CoreCtxWithIpDeviceConfiguration<
464        's,
465        &'s mut Ipv6DeviceConfiguration,
466        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
467        BC,
468    >;
469
470    fn with_ipv6_device_configuration<
471        O,
472        F: FnOnce(&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) -> O,
473    >(
474        &mut self,
475        device_id: &Self::DeviceId,
476        cb: F,
477    ) -> O {
478        IpDeviceConfigurationContext::<Ipv6, _>::with_ip_device_configuration(self, device_id, cb)
479    }
480
481    fn with_ipv6_device_configuration_mut<
482        O,
483        F: FnOnce(Self::WithIpv6DeviceConfigurationMutInner<'_>) -> O,
484    >(
485        &mut self,
486        device_id: &Self::DeviceId,
487        cb: F,
488    ) -> O {
489        IpDeviceConfigurationContext::<Ipv6, _>::with_ip_device_configuration_mut(
490            self, device_id, cb,
491        )
492    }
493}
494
495impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>>
496    IpDeviceConfigurationContext<Ipv6, BC> for CoreCtx<'_, BC, L>
497{
498    type DevicesIter<'s> = DevicesIter<'s, BC>;
499    type WithIpDeviceConfigurationInnerCtx<'s> = CoreCtxWithIpDeviceConfiguration<
500        's,
501        &'s Ipv6DeviceConfiguration,
502        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
503        BC,
504    >;
505    type WithIpDeviceConfigurationMutInner<'s> = CoreCtxWithIpDeviceConfiguration<
506        's,
507        &'s mut Ipv6DeviceConfiguration,
508        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
509        BC,
510    >;
511    type DeviceAddressAndGroupsAccessor<'s> =
512        CoreCtx<'s, BC, WrapLockLevel<crate::lock_ordering::DeviceLayerState>>;
513
514    fn with_ip_device_configuration<
515        O,
516        F: FnOnce(&Ipv6DeviceConfiguration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
517    >(
518        &mut self,
519        device_id: &Self::DeviceId,
520        cb: F,
521    ) -> O {
522        let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
523        let (state, mut locked) = core_ctx_and_resource
524            .read_lock_with_and::<crate::lock_ordering::IpDeviceConfiguration<Ipv6>, _>(|c| {
525                c.right()
526            });
527        cb(
528            &state,
529            CoreCtxWithIpDeviceConfiguration { config: &state, core_ctx: locked.cast_core_ctx() },
530        )
531    }
532
533    fn with_ip_device_configuration_mut<
534        O,
535        F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
536    >(
537        &mut self,
538        device_id: &Self::DeviceId,
539        cb: F,
540    ) -> O {
541        let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
542        let (mut state, mut locked) = core_ctx_and_resource
543            .write_lock_with_and::<crate::lock_ordering::IpDeviceConfiguration<Ipv6>, _>(
544            |c| c.right(),
545        );
546        cb(CoreCtxWithIpDeviceConfiguration {
547            config: &mut state,
548            core_ctx: locked.cast_core_ctx(),
549        })
550    }
551
552    fn with_devices_and_state<
553        O,
554        F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
555    >(
556        &mut self,
557        cb: F,
558    ) -> O {
559        let (devices, locked) = self.read_lock_and::<crate::lock_ordering::DeviceLayerState>();
560        cb(devices.iter(), locked)
561    }
562
563    fn loopback_id(&mut self) -> Option<Self::DeviceId> {
564        let devices = &*self.read_lock::<crate::lock_ordering::DeviceLayerState>();
565        devices.loopback.as_ref().map(|primary| DeviceId::Loopback(primary.clone_strong()))
566    }
567}
568
569impl<BC: BindingsContext, L> IpDeviceAddressIdContext<Ipv6> for CoreCtx<'_, BC, L> {
570    type AddressId = AddressId<Ipv6, BC>;
571    type WeakAddressId = WeakAddressId<Ipv6, BC>;
572}
573
574#[netstack3_macros::instantiate_ip_impl_block(I)]
575impl<
576    I: IpLayerIpExt,
577    BC: BindingsContext,
578    L: LockBefore<crate::lock_ordering::IpDeviceAddressData<I>>,
579> IpDeviceAddressContext<I, BC> for CoreCtx<'_, BC, L>
580{
581    fn with_ip_address_data<O, F: FnOnce(&IpAddressData<I, BC::Instant>) -> O>(
582        &mut self,
583        _device_id: &Self::DeviceId,
584        addr_id: &Self::AddressId,
585        cb: F,
586    ) -> O {
587        let mut locked = self.adopt(addr_id.deref());
588        let x = cb(&locked
589            .read_lock_with::<crate::lock_ordering::IpDeviceAddressData<I>, _>(|c| c.right()));
590        x
591    }
592
593    fn with_ip_address_data_mut<O, F: FnOnce(&mut IpAddressData<I, BC::Instant>) -> O>(
594        &mut self,
595        _device_id: &Self::DeviceId,
596        addr_id: &Self::AddressId,
597        cb: F,
598    ) -> O {
599        let mut locked = self.adopt(addr_id.deref());
600        let x = cb(&mut locked
601            .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<I>, _>(|c| c.right()));
602        x
603    }
604}
605
606impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddresses<Ipv6>>>
607    IpDeviceAddAddressContext<Ipv6, BC> for CoreCtx<'_, BC, L>
608{
609    fn add_ip_address(
610        &mut self,
611        device_id: &Self::DeviceId,
612        addr: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
613        config: Ipv6AddrConfig<BC::Instant>,
614    ) -> Result<Self::AddressId, ExistsError> {
615        let mut state = ip_device_state(self, device_id);
616        let addr_id = state
617            .write_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv6>>()
618            .add(IpAddressEntry::new(addr, DadState::Uninitialized, config));
619        addr_id
620    }
621}
622
623impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddresses<Ipv6>>>
624    IpDeviceStateContext<Ipv6, BC> for CoreCtx<'_, BC, L>
625{
626    type IpDeviceAddressCtx<'a> =
627        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpDeviceAddresses<Ipv6>>>;
628
629    fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
630        &mut self,
631        device_id: &Self::DeviceId,
632        cb: F,
633    ) -> O {
634        let mut state = ip_device_state(self, device_id);
635        let flags = &*state.lock::<crate::lock_ordering::IpDeviceFlags<Ipv6>>();
636        cb(flags)
637    }
638
639    fn remove_ip_address(
640        &mut self,
641        device_id: &Self::DeviceId,
642        addr: Self::AddressId,
643    ) -> RemoveResourceResultWithContext<AddrSubnet<Ipv6Addr>, BC> {
644        let mut state = ip_device_state(self, device_id);
645        let primary = state
646            .write_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv6>>()
647            .remove(&addr.addr().addr())
648            .expect("should exist when address ID exists");
649        assert!(PrimaryAddressId::ptr_eq(&primary, &addr));
650        core::mem::drop(addr);
651
652        BC::unwrap_or_notify_with_new_reference_notifier(primary.into_inner(), |entry| {
653            entry.addr_sub().to_witness::<SpecifiedAddr<_>>()
654        })
655    }
656
657    fn get_address_id(
658        &mut self,
659        device_id: &Self::DeviceId,
660        addr: SpecifiedAddr<Ipv6Addr>,
661    ) -> Result<Self::AddressId, NotFoundError> {
662        let mut state = ip_device_state(self, device_id);
663        let addr_id = state
664            .read_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv6>>()
665            .iter()
666            .find_map(|a| {
667                let inner: Ipv6Addr = a.addr().get();
668                (inner == *addr).then(|| PrimaryAddressId::clone_strong(a))
669            })
670            .ok_or(NotFoundError);
671        addr_id
672    }
673
674    type AddressIdsIter<'a> = AddressIdIter<'a, Ipv6, BC>;
675    fn with_address_ids<
676        O,
677        F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
678    >(
679        &mut self,
680        device_id: &Self::DeviceId,
681        cb: F,
682    ) -> O {
683        let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
684        let (state, mut core_ctx) = core_ctx_and_resource
685            .read_lock_with_and::<crate::lock_ordering::IpDeviceAddresses<Ipv6>, _>(|c| c.right());
686        cb(state.strong_iter(), &mut core_ctx.cast_core_ctx())
687    }
688
689    fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
690        &mut self,
691        device_id: &Self::DeviceId,
692        cb: F,
693    ) -> O {
694        let mut state = ip_device_state(self, device_id);
695        let mut state = state.read_lock::<crate::lock_ordering::IpDeviceDefaultHopLimit<Ipv6>>();
696        cb(&mut state)
697    }
698
699    fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
700        &mut self,
701        device_id: &Self::DeviceId,
702        cb: F,
703    ) -> O {
704        let mut state = ip_device_state(self, device_id);
705        let mut state = state.write_lock::<crate::lock_ordering::IpDeviceDefaultHopLimit<Ipv6>>();
706        cb(&mut state)
707    }
708
709    fn join_link_multicast_group(
710        &mut self,
711        bindings_ctx: &mut BC,
712        device_id: &Self::DeviceId,
713        multicast_addr: MulticastAddr<Ipv6Addr>,
714    ) {
715        join_link_multicast_group(self, bindings_ctx, device_id, multicast_addr)
716    }
717
718    fn leave_link_multicast_group(
719        &mut self,
720        bindings_ctx: &mut BC,
721        device_id: &Self::DeviceId,
722        multicast_addr: MulticastAddr<Ipv6Addr>,
723    ) {
724        leave_link_multicast_group(self, bindings_ctx, device_id, multicast_addr)
725    }
726}
727
728impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddresses<Ipv6>>>
729    Ipv6DeviceContext<BC> for CoreCtx<'_, BC, L>
730{
731    type LinkLayerAddr = Ipv6DeviceLinkLayerAddr;
732
733    fn get_link_layer_addr(
734        &mut self,
735        device_id: &Self::DeviceId,
736    ) -> Option<Ipv6DeviceLinkLayerAddr> {
737        match device_id {
738            DeviceId::Ethernet(id) => {
739                Some(Ipv6DeviceLinkLayerAddr::Mac(ethernet::get_mac(self, &id).get()))
740            }
741            DeviceId::Loopback(LoopbackDeviceId { .. })
742            | DeviceId::Blackhole(BlackholeDeviceId { .. })
743            | DeviceId::PureIp(PureIpDeviceId { .. }) => None,
744        }
745    }
746
747    fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
748        if mtu < Ipv6::MINIMUM_LINK_MTU {
749            return;
750        }
751
752        match device_id {
753            DeviceId::Ethernet(id) => ethernet::set_mtu(self, &id, mtu),
754            DeviceId::Loopback(LoopbackDeviceId { .. }) => {}
755            DeviceId::PureIp(id) => pure_ip::set_mtu(self, &id, mtu),
756            DeviceId::Blackhole(BlackholeDeviceId { .. }) => {}
757        }
758    }
759
760    fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
761        &mut self,
762        device_id: &Self::DeviceId,
763        cb: F,
764    ) -> O {
765        let mut state = ip_device_state(self, device_id);
766        let state = state.read_lock::<crate::lock_ordering::Ipv6DeviceLearnedParams>();
767        cb(&state)
768    }
769
770    fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
771        &mut self,
772        device_id: &Self::DeviceId,
773        cb: F,
774    ) -> O {
775        let mut state = ip_device_state(self, device_id);
776        let mut state = state.write_lock::<crate::lock_ordering::Ipv6DeviceLearnedParams>();
777        cb(&mut state)
778    }
779}
780
781impl<BT: BindingsTypes, L> DeviceIdContext<EthernetLinkDevice> for CoreCtx<'_, BT, L> {
782    type DeviceId = EthernetDeviceId<BT>;
783    type WeakDeviceId = EthernetWeakDeviceId<BT>;
784}
785
786impl<BT: BindingsTypes> DelegatedOrderedLockAccess<Devices<BT>> for StackState<BT> {
787    type Inner = DeviceLayerState<BT>;
788    fn delegate_ordered_lock_access(&self) -> &Self::Inner {
789        &self.device
790    }
791}
792
793impl<BT: BindingsTypes> LockLevelFor<StackState<BT>> for crate::lock_ordering::DeviceLayerState {
794    type Data = Devices<BT>;
795}
796
797impl<BT: BindingsTypes, L> DeviceIdContext<AnyDevice> for CoreCtx<'_, BT, L> {
798    type DeviceId = DeviceId<BT>;
799    type WeakDeviceId = WeakDeviceId<BT>;
800}
801
802/// It is safe to provide unlocked access to [`IpLinkDeviceStateInner`] itself
803/// here because care has been taken to avoid exposing publicly to the core
804/// integration crate any state that is held by a lock, as opposed to read-only
805/// state that can be accessed safely at any lock level, e.g. state with no
806/// interior mutability or atomics.
807///
808/// Access to state held by locks *must* be mediated using the global lock
809/// ordering declared in [`crate::lock_ordering`].
810impl<T, BT: BindingsTypes> UnlockedAccess<crate::lock_ordering::UnlockedState>
811    for IpLinkDeviceStateInner<T, BT>
812{
813    type Data = IpLinkDeviceStateInner<T, BT>;
814    type Guard<'l>
815        = &'l IpLinkDeviceStateInner<T, BT>
816    where
817        Self: 'l;
818
819    fn access(&self) -> Self::Guard<'_> {
820        &self
821    }
822}
823
824pub(crate) fn device_state<'a, BT: BindingsTypes, L, D: DeviceStateSpec>(
825    core_ctx: &'a mut CoreCtx<'_, BT, L>,
826    device_id: &'a BaseDeviceId<D, BT>,
827) -> Locked<&'a IpLinkDeviceState<D, BT>, L> {
828    let state = device_id.device_state(
829        &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
830    );
831    core_ctx.replace(state)
832}
833
834pub(crate) fn device_state_and_core_ctx<'a, BT: BindingsTypes, L, D: DeviceStateSpec>(
835    core_ctx: &'a mut CoreCtx<'_, BT, L>,
836    id: &'a BaseDeviceId<D, BT>,
837) -> CoreCtxAndResource<'a, BT, IpLinkDeviceState<D, BT>, L> {
838    let state = id.device_state(
839        &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
840    );
841    core_ctx.adopt(state)
842}
843
844pub(crate) fn ip_device_state<'a, BC: BindingsContext, L>(
845    core_ctx: &'a mut CoreCtx<'_, BC, L>,
846    device: &'a DeviceId<BC>,
847) -> Locked<&'a DualStackIpDeviceState<BC>, L> {
848    for_any_device_id!(
849        DeviceId,
850        device,
851        id => {
852            let state = id.device_state(
853                &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin
854            );
855            core_ctx.replace(state.as_ref())
856        }
857    )
858}
859
860pub(crate) fn ip_device_state_and_core_ctx<'a, BC: BindingsContext, L>(
861    core_ctx: &'a mut CoreCtx<'_, BC, L>,
862    device: &'a DeviceId<BC>,
863) -> CoreCtxAndResource<'a, BC, DualStackIpDeviceState<BC>, L> {
864    for_any_device_id!(
865        DeviceId,
866        device,
867        id => {
868            let state = id.device_state(
869                &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin
870            );
871            core_ctx.adopt(state.as_ref())
872        }
873    )
874}
875
876pub(crate) fn get_mtu<
877    BC: BindingsContext,
878    L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>,
879>(
880    core_ctx: &mut CoreCtx<'_, BC, L>,
881    device: &DeviceId<BC>,
882) -> Mtu {
883    match device {
884        DeviceId::Ethernet(id) => ethernet::get_mtu(core_ctx, &id),
885        DeviceId::Loopback(id) => device_state(core_ctx, id).cast_with(|s| &s.link.mtu).copied(),
886        DeviceId::PureIp(id) => pure_ip::get_mtu(core_ctx, &id),
887        DeviceId::Blackhole(_id) => Mtu::no_limit(),
888    }
889}
890
891fn join_link_multicast_group<
892    BC: BindingsContext,
893    A: IpAddress,
894    L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>,
895>(
896    core_ctx: &mut CoreCtx<'_, BC, L>,
897    bindings_ctx: &mut BC,
898    device_id: &DeviceId<BC>,
899    multicast_addr: MulticastAddr<A>,
900) {
901    match device_id {
902        DeviceId::Ethernet(id) => ethernet::join_link_multicast(
903            core_ctx,
904            bindings_ctx,
905            &id,
906            MulticastAddr::from(&multicast_addr),
907        ),
908        DeviceId::Loopback(LoopbackDeviceId { .. })
909        | DeviceId::PureIp(PureIpDeviceId { .. })
910        | DeviceId::Blackhole(BlackholeDeviceId { .. }) => {}
911    }
912}
913
914fn leave_link_multicast_group<
915    BC: BindingsContext,
916    A: IpAddress,
917    L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>,
918>(
919    core_ctx: &mut CoreCtx<'_, BC, L>,
920    bindings_ctx: &mut BC,
921    device_id: &DeviceId<BC>,
922    multicast_addr: MulticastAddr<A>,
923) {
924    match device_id {
925        DeviceId::Ethernet(id) => ethernet::leave_link_multicast(
926            core_ctx,
927            bindings_ctx,
928            &id,
929            MulticastAddr::from(&multicast_addr),
930        ),
931        DeviceId::Loopback(LoopbackDeviceId { .. })
932        | DeviceId::PureIp(PureIpDeviceId { .. })
933        | DeviceId::Blackhole(BlackholeDeviceId { .. }) => {}
934    }
935}
936
937fn send_ip_frame<BC, S, I, L>(
938    core_ctx: &mut CoreCtx<'_, BC, L>,
939    bindings_ctx: &mut BC,
940    device: &DeviceId<BC>,
941    destination: IpPacketDestination<I, &DeviceId<BC>>,
942    ip_layer_metadata: DeviceIpLayerMetadata<BC>,
943    body: S,
944) -> Result<(), SendFrameError<S>>
945where
946    BC: BindingsContext,
947    S: NetworkSerializer,
948    S::Buffer: BufferMut,
949    I: EthernetIpExt + BroadcastIpExt,
950    L: LockBefore<crate::lock_ordering::IpState<I>>
951        + LockBefore<crate::lock_ordering::LoopbackTxQueue>
952        + LockBefore<crate::lock_ordering::PureIpDeviceTxQueue>,
953    for<'a> CoreCtx<'a, BC, L>: EthernetIpLinkDeviceDynamicStateContext<BC, DeviceId = EthernetDeviceId<BC>>
954        + NudHandler<I, EthernetLinkDevice, BC>
955        + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>,
956{
957    match device {
958        DeviceId::Ethernet(id) => ethernet::send_ip_frame(
959            core_ctx,
960            bindings_ctx,
961            id,
962            destination,
963            body,
964            ip_layer_metadata.into_tx_metadata(),
965        ),
966        DeviceId::Loopback(id) => loopback::send_ip_frame(
967            core_ctx,
968            bindings_ctx,
969            id,
970            destination,
971            ip_layer_metadata,
972            body,
973        ),
974        DeviceId::PureIp(id) => pure_ip::send_ip_frame(
975            core_ctx,
976            bindings_ctx,
977            id,
978            destination,
979            body,
980            ip_layer_metadata.into_tx_metadata(),
981        ),
982        DeviceId::Blackhole(id) => {
983            // Just drop the frame.
984            debug!("dropping frame in send_ip_frame on blackhole device {id:?}");
985            core_ctx.increment_both(id, DeviceCounters::send_frame::<I>);
986            Ok(())
987        }
988    }
989}
990
991impl<'a, BT, L> DeviceCollectionContext<EthernetLinkDevice, BT> for CoreCtx<'a, BT, L>
992where
993    BT: BindingsTypes,
994    L: LockBefore<crate::lock_ordering::DeviceLayerState>,
995{
996    fn insert(&mut self, device: EthernetPrimaryDeviceId<BT>) {
997        let mut devices = self.write_lock::<crate::lock_ordering::DeviceLayerState>();
998        let strong = device.clone_strong();
999        assert!(devices.ethernet.insert(strong, device).is_none());
1000    }
1001
1002    fn remove(&mut self, device: &EthernetDeviceId<BT>) -> Option<EthernetPrimaryDeviceId<BT>> {
1003        let mut devices = self.write_lock::<crate::lock_ordering::DeviceLayerState>();
1004        devices.ethernet.remove(device)
1005    }
1006}
1007
1008impl<'a, BT, L> DeviceCollectionContext<LoopbackDevice, BT> for CoreCtx<'a, BT, L>
1009where
1010    BT: BindingsTypes,
1011    L: LockBefore<crate::lock_ordering::DeviceLayerState>,
1012{
1013    fn insert(&mut self, device: LoopbackPrimaryDeviceId<BT>) {
1014        let mut devices = self.write_lock::<crate::lock_ordering::DeviceLayerState>();
1015        let prev = devices.loopback.replace(device);
1016        // NB: At a previous version we returned an error when bindings tried to
1017        // install the loopback device twice. Turns out that all callers
1018        // panicked on that error so might as well panic here and simplify the
1019        // API code.
1020        assert!(prev.is_none(), "can't install loopback device more than once");
1021    }
1022
1023    fn remove(&mut self, device: &LoopbackDeviceId<BT>) -> Option<LoopbackPrimaryDeviceId<BT>> {
1024        // We assert here because there's an invariant that only one loopback
1025        // device exists. So if we're calling this function with a loopback
1026        // device ID then it *must* exist and it *must* be the same as the
1027        // currently installed device.
1028        let mut devices = self.write_lock::<crate::lock_ordering::DeviceLayerState>();
1029        let primary = devices.loopback.take().expect("loopback device not installed");
1030        assert_eq!(device, &primary);
1031        Some(primary)
1032    }
1033}
1034
1035impl<'a, BT: BindingsTypes, L> OriginTrackerContext for CoreCtx<'a, BT, L> {
1036    fn origin_tracker(&mut self) -> OriginTracker {
1037        self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin.clone()
1038    }
1039}
1040
1041impl<'a, BT, L> DeviceConfigurationContext<EthernetLinkDevice> for CoreCtx<'a, BT, L>
1042where
1043    L: LockBefore<crate::lock_ordering::NudConfig<Ipv4>>
1044        + LockBefore<crate::lock_ordering::NudConfig<Ipv6>>,
1045    BT: BindingsTypes,
1046{
1047    fn with_nud_config<I: Ip, O, F: FnOnce(Option<&NudUserConfig>) -> O>(
1048        &mut self,
1049        device_id: &Self::DeviceId,
1050        f: F,
1051    ) -> O {
1052        let state = device_state(self, device_id);
1053        // NB: We need map_ip here because we can't write a lock ordering
1054        // restriction for all IP versions.
1055        let IpInvariant(o) =
1056            map_ip_twice!(I, IpInvariant((state, f)), |IpInvariant((mut state, f))| {
1057                IpInvariant(f(Some(&*state.read_lock::<crate::lock_ordering::NudConfig<I>>())))
1058            });
1059        o
1060    }
1061
1062    fn with_nud_config_mut<I: Ip, O, F: FnOnce(Option<&mut NudUserConfig>) -> O>(
1063        &mut self,
1064        device_id: &Self::DeviceId,
1065        f: F,
1066    ) -> O {
1067        let state = device_state(self, device_id);
1068        // NB: We need map_ip here because we can't write a lock ordering
1069        // restriction for all IP versions.
1070        let IpInvariant(o) =
1071            map_ip_twice!(I, IpInvariant((state, f)), |IpInvariant((mut state, f))| {
1072                IpInvariant(f(Some(&mut *state.write_lock::<crate::lock_ordering::NudConfig<I>>())))
1073            });
1074        o
1075    }
1076}
1077
1078impl<'a, BT, L> DeviceConfigurationContext<LoopbackDevice> for CoreCtx<'a, BT, L>
1079where
1080    BT: BindingsTypes,
1081{
1082    fn with_nud_config<I: Ip, O, F: FnOnce(Option<&NudUserConfig>) -> O>(
1083        &mut self,
1084        _device_id: &Self::DeviceId,
1085        f: F,
1086    ) -> O {
1087        // Loopback doesn't support NUD.
1088        f(None)
1089    }
1090
1091    fn with_nud_config_mut<I: Ip, O, F: FnOnce(Option<&mut NudUserConfig>) -> O>(
1092        &mut self,
1093        _device_id: &Self::DeviceId,
1094        f: F,
1095    ) -> O {
1096        // Loopback doesn't support NUD.
1097        f(None)
1098    }
1099}
1100
1101impl<BC: BindingsContext, L> CounterContext<EthernetDeviceCounters> for CoreCtx<'_, BC, L> {
1102    fn counters(&self) -> &EthernetDeviceCounters {
1103        &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.ethernet_counters
1104    }
1105}
1106
1107impl<BC: BindingsContext, L> CounterContext<DeviceSocketCounters> for CoreCtx<'_, BC, L> {
1108    fn counters(&self) -> &DeviceSocketCounters {
1109        &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.device_socket_counters
1110    }
1111}
1112
1113impl<BC: BindingsContext, L> CounterContext<PureIpDeviceCounters> for CoreCtx<'_, BC, L> {
1114    fn counters(&self) -> &PureIpDeviceCounters {
1115        &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.pure_ip_counters
1116    }
1117}
1118
1119impl<'a, BC: BindingsContext, L> ResourceCounterContext<DeviceId<BC>, DeviceCounters>
1120    for CoreCtx<'a, BC, L>
1121{
1122    fn per_resource_counters<'b>(&'b self, device_id: &'b DeviceId<BC>) -> &'b DeviceCounters {
1123        for_any_device_id!(DeviceId, device_id, id => {
1124            let state = id.device_state(
1125                &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1126            );
1127            &state.counters
1128        })
1129    }
1130}
1131
1132impl<'a, BC: BindingsContext, D: DeviceStateSpec, L>
1133    ResourceCounterContext<BaseDeviceId<D, BC>, DeviceCounters> for CoreCtx<'a, BC, L>
1134{
1135    fn per_resource_counters<'b>(
1136        &'b self,
1137        device_id: &'b BaseDeviceId<D, BC>,
1138    ) -> &'b DeviceCounters {
1139        let state = device_id.device_state(
1140            &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1141        );
1142        &state.counters
1143    }
1144}
1145
1146impl<'a, BC: BindingsContext, L, D: WeakDeviceIdentifier>
1147    ResourceCounterContext<DeviceSocketId<D, BC>, DeviceSocketCounters> for CoreCtx<'a, BC, L>
1148{
1149    fn per_resource_counters<'b>(
1150        &'b self,
1151        socket_id: &'b DeviceSocketId<D, BC>,
1152    ) -> &'b DeviceSocketCounters {
1153        socket_id.counters()
1154    }
1155}
1156
1157impl<'a, BC: BindingsContext, L>
1158    ResourceCounterContext<EthernetDeviceId<BC>, EthernetDeviceCounters> for CoreCtx<'a, BC, L>
1159{
1160    fn per_resource_counters<'b>(
1161        &'b self,
1162        device_id: &'b EthernetDeviceId<BC>,
1163    ) -> &'b EthernetDeviceCounters {
1164        let state = device_id.device_state(
1165            &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1166        );
1167        &state.link.counters
1168    }
1169}
1170
1171impl<'a, BC: BindingsContext, L>
1172    ResourceCounterContext<LoopbackDeviceId<BC>, EthernetDeviceCounters> for CoreCtx<'a, BC, L>
1173{
1174    fn per_resource_counters<'b>(
1175        &'b self,
1176        device_id: &'b LoopbackDeviceId<BC>,
1177    ) -> &'b EthernetDeviceCounters {
1178        let state = device_id.device_state(
1179            &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1180        );
1181        &state.link.counters
1182    }
1183}
1184
1185impl<'a, BC: BindingsContext, L> ResourceCounterContext<PureIpDeviceId<BC>, PureIpDeviceCounters>
1186    for CoreCtx<'a, BC, L>
1187{
1188    fn per_resource_counters<'b>(
1189        &'b self,
1190        device_id: &'b PureIpDeviceId<BC>,
1191    ) -> &'b PureIpDeviceCounters {
1192        let state = device_id.device_state(
1193            &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1194        );
1195        &state.link.counters
1196    }
1197}
1198
1199// Blackhole devices have no device-specific counters.
1200impl<'a, BC: BindingsContext, L> CounterContext<BlackholeDeviceCounters> for CoreCtx<'a, BC, L> {
1201    fn counters(&self) -> &BlackholeDeviceCounters {
1202        &BlackholeDeviceCounters
1203    }
1204}
1205
1206impl<'a, BC: BindingsContext, L>
1207    ResourceCounterContext<BlackholeDeviceId<BC>, BlackholeDeviceCounters> for CoreCtx<'a, BC, L>
1208{
1209    fn per_resource_counters<'b>(
1210        &'b self,
1211        _device_id: &'b BlackholeDeviceId<BC>,
1212    ) -> &'b BlackholeDeviceCounters {
1213        &BlackholeDeviceCounters
1214    }
1215}
1216
1217impl<T, BT: BindingsTypes> LockLevelFor<IpLinkDeviceStateInner<T, BT>>
1218    for crate::lock_ordering::DeviceSockets
1219{
1220    type Data = HeldDeviceSockets<BT>;
1221}
1222
1223impl<BT: BindingsTypes, L> CounterContext<DeviceCounters> for CoreCtx<'_, BT, L> {
1224    fn counters(&self) -> &DeviceCounters {
1225        &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.counters
1226    }
1227}
1228
1229impl<I: IpDeviceIpExt, BC: BindingsContext, L> IpRoutingDeviceContext<I> for CoreCtx<'_, BC, L>
1230where
1231    Self: IpDeviceStateContext<I, BC, DeviceId = DeviceId<BC>>,
1232{
1233    fn get_routing_metric(&mut self, device_id: &Self::DeviceId) -> RawMetric {
1234        let state = ip_device_state(self, device_id);
1235        *state.unlocked_access::<crate::lock_ordering::UnlockedState>().metric()
1236    }
1237
1238    fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
1239        IpDeviceStateContext::<I, _>::with_ip_device_flags(
1240            self,
1241            device_id,
1242            |IpDeviceFlags { ip_enabled }| *ip_enabled,
1243        )
1244    }
1245}
1246
1247impl<BT: BindingsTypes, L> CounterContext<ArpCounters> for CoreCtx<'_, BT, L> {
1248    fn counters(&self) -> &ArpCounters {
1249        &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.arp_counters
1250    }
1251}