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