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