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