netstack3_core/ip/
device.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! The integrations for protocols built on top of an IP device.
6
7use core::borrow::Borrow;
8use core::marker::PhantomData;
9use core::num::NonZeroU8;
10use core::ops::{Deref as _, DerefMut as _};
11use core::sync::atomic::AtomicU16;
12
13use lock_order::lock::{LockLevelFor, UnlockedAccess};
14use lock_order::relation::LockBefore;
15use log::debug;
16use net_types::ip::{AddrSubnet, Ip, IpMarked, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Mtu};
17use net_types::{LinkLocalUnicastAddr, MulticastAddr, SpecifiedAddr, UnicastAddr, Witness as _};
18use netstack3_base::{
19    AnyDevice, CoreTimerContext, CounterContext, DeviceIdContext, ExistsError, IpAddressId as _,
20    IpDeviceAddr, IpDeviceAddressIdContext, Ipv4DeviceAddr, Ipv6DeviceAddr, NotFoundError,
21    RemoveResourceResultWithContext, ResourceCounterContext,
22};
23use netstack3_device::ethernet::EthernetDeviceId;
24use netstack3_device::{DeviceId, WeakDeviceId};
25use netstack3_filter::FilterImpl;
26use netstack3_ip::device::{
27    self, AddressRemovedReason, DadAddressContext, DadAddressStateRef, DadContext, DadState,
28    DadStateRef, DadTimerId, DefaultHopLimit, DelIpAddr, DualStackIpDeviceState, IpAddressData,
29    IpAddressEntry, IpAddressFlags, IpDeviceAddresses, IpDeviceConfiguration, IpDeviceFlags,
30    IpDeviceIpExt, IpDeviceMulticastGroups, IpDeviceStateBindingsTypes, IpDeviceStateContext,
31    IpDeviceStateIpExt, IpDeviceTimerId, Ipv4DadSendData, Ipv4DeviceConfiguration,
32    Ipv4DeviceTimerId, Ipv6AddrConfig, Ipv6AddrSlaacConfig, Ipv6DadAddressContext, Ipv6DadSendData,
33    Ipv6DeviceConfiguration, Ipv6DeviceTimerId, Ipv6DiscoveredRoute, Ipv6DiscoveredRoutesContext,
34    Ipv6NetworkLearnedParameters, Ipv6RouteDiscoveryContext, Ipv6RouteDiscoveryState, RsContext,
35    RsState, RsTimerId, SlaacAddressEntry, SlaacAddressEntryMut, SlaacAddresses,
36    SlaacConfigAndState, SlaacContext, SlaacCounters, SlaacState, WeakAddressId,
37    add_ip_addr_subnet_with_config, del_ip_addr_inner, get_ipv6_hop_limit, is_ip_device_enabled,
38    is_ip_multicast_forwarding_enabled, is_ip_unicast_forwarding_enabled,
39    join_ip_multicast_with_config, leave_ip_multicast_with_config,
40};
41use netstack3_ip::gmp::{
42    GmpGroupState, GmpState, GmpStateRef, IgmpContext, IgmpContextMarker, IgmpSendContext,
43    IgmpStateContext, IgmpTypeLayout, MldContext, MldContextMarker, MldSendContext,
44    MldStateContext, MldTypeLayout, MulticastGroupSet,
45};
46use netstack3_ip::nud::{self, ConfirmationFlags, NudCounters, NudIpHandler};
47use netstack3_ip::{
48    self as ip, AddableMetric, AddressStatus, DEFAULT_TTL, FilterHandlerProvider, IpDeviceContext,
49    IpDeviceEgressStateContext, IpDeviceIngressStateContext, IpLayerIpExt, IpSasHandler,
50    IpSendFrameError, Ipv4PresentAddressStatus,
51};
52use packet::{EmptyBuf, InnerPacketBuilder, PartialSerializer, Serializer};
53use packet_formats::icmp::IcmpZeroCode;
54use packet_formats::icmp::ndp::options::{NdpNonce, NdpOptionBuilder};
55use packet_formats::icmp::ndp::{OptionSequenceBuilder, RouterSolicitation};
56
57use crate::context::WrapLockLevel;
58use crate::context::prelude::*;
59use crate::{BindingsContext, BindingsTypes, CoreCtx, IpExt};
60
61pub struct SlaacAddrs<'a, BC: BindingsContext> {
62    pub(crate) core_ctx: CoreCtxWithIpDeviceConfiguration<
63        'a,
64        &'a Ipv6DeviceConfiguration,
65        WrapLockLevel<crate::lock_ordering::Ipv6DeviceSlaac>,
66        BC,
67    >,
68    pub(crate) device_id: DeviceId<BC>,
69    pub(crate) config: &'a Ipv6DeviceConfiguration,
70}
71
72/// Provides an Iterator for `SlaacAddrs` to implement `SlaacAddresses`.
73///
74/// Note that we use concrete types here instead of going through traits because
75/// it's the only way to satisfy the GAT bounds on `SlaacAddresses`' associated
76/// type.
77pub struct SlaacAddrsIter<'x, BC: BindingsContext> {
78    core_ctx: CoreCtx<'x, BC, WrapLockLevel<crate::lock_ordering::IpDeviceAddresses<Ipv6>>>,
79    addrs: ip::device::AddressIdIter<'x, Ipv6, BC>,
80    device_id: &'x DeviceId<BC>,
81}
82
83impl<'x, BC> Iterator for SlaacAddrsIter<'x, BC>
84where
85    BC: BindingsContext,
86{
87    type Item = SlaacAddressEntry<BC::Instant>;
88    fn next(&mut self) -> Option<Self::Item> {
89        let Self { core_ctx, addrs, device_id } = self;
90        // NB: This form is equivalent to using the `filter_map` combinator but
91        // keeps the type signature simple.
92        addrs.by_ref().find_map(|addr_id| {
93            device::IpDeviceAddressContext::<Ipv6, _>::with_ip_address_data(
94                core_ctx,
95                device_id,
96                &addr_id,
97                |IpAddressData { flags: IpAddressFlags { assigned: _ }, config }| {
98                    let addr_sub = addr_id.addr_sub();
99                    match config {
100                        Some(Ipv6AddrConfig::Slaac(config)) => {
101                            Some(SlaacAddressEntry { addr_sub: addr_sub, config: *config })
102                        }
103                        None | Some(Ipv6AddrConfig::Manual(_)) => None,
104                    }
105                },
106            )
107        })
108    }
109}
110
111impl<'a, BC: BindingsContext> CounterContext<SlaacCounters> for SlaacAddrs<'a, BC> {
112    fn counters(&self) -> &SlaacCounters {
113        &self
114            .core_ctx
115            .core_ctx
116            .unlocked_access::<crate::lock_ordering::UnlockedState>()
117            .ipv6
118            .slaac_counters
119    }
120}
121
122impl<'a, BC: BindingsContext> SlaacAddresses<BC> for SlaacAddrs<'a, BC> {
123    fn for_each_addr_mut<F: FnMut(SlaacAddressEntryMut<'_, BC::Instant>)>(&mut self, mut cb: F) {
124        let SlaacAddrs { core_ctx, device_id, config: _ } = self;
125        let CoreCtxWithIpDeviceConfiguration { config: _, core_ctx } = core_ctx;
126        let mut state = crate::device::integration::ip_device_state(core_ctx, device_id);
127        let (addrs, mut locked) =
128            state.read_lock_and::<crate::lock_ordering::IpDeviceAddresses<Ipv6>>();
129        addrs.iter().for_each(|entry| {
130            let addr_sub = *entry.addr_sub();
131            let mut locked = locked.adopt(&**entry);
132            let mut state = locked
133                .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv6>, _>(|c| {
134                    c.right()
135                });
136            let IpAddressData { config, flags: IpAddressFlags { assigned: _ } } = &mut *state;
137
138            match config {
139                Some(Ipv6AddrConfig::Slaac(config)) => {
140                    cb(SlaacAddressEntryMut { addr_sub, config })
141                }
142                None | Some(Ipv6AddrConfig::Manual(_)) => {}
143            }
144        })
145    }
146
147    type AddrsIter<'x> = SlaacAddrsIter<'x, BC>;
148
149    fn with_addrs<O, F: FnOnce(Self::AddrsIter<'_>) -> O>(&mut self, cb: F) -> O {
150        let SlaacAddrs { core_ctx, device_id, config: _ } = self;
151        device::IpDeviceStateContext::<Ipv6, BC>::with_address_ids(
152            core_ctx,
153            device_id,
154            |addrs, core_ctx| {
155                cb(SlaacAddrsIter { core_ctx: core_ctx.as_owned(), addrs, device_id })
156            },
157        )
158    }
159
160    fn add_addr_sub_and_then<O, F: FnOnce(SlaacAddressEntryMut<'_, BC::Instant>, &mut BC) -> O>(
161        &mut self,
162        bindings_ctx: &mut BC,
163        add_addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
164        slaac_config: Ipv6AddrSlaacConfig<BC::Instant>,
165        and_then: F,
166    ) -> Result<O, ExistsError> {
167        let SlaacAddrs { core_ctx, device_id, config } = self;
168
169        add_ip_addr_subnet_with_config::<Ipv6, _, _>(
170            core_ctx,
171            bindings_ctx,
172            device_id,
173            add_addr_sub.to_witness(),
174            Ipv6AddrConfig::Slaac(slaac_config),
175            config,
176        )
177        .map(|entry| {
178            let addr_sub = entry.addr_sub();
179            let mut locked = core_ctx.core_ctx.adopt(entry.deref());
180            let mut state = locked
181                .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv6>, _>(|c| {
182                    c.right()
183                });
184            let IpAddressData { config, flags: _ } = &mut *state;
185            let config = assert_matches::assert_matches!(
186                config,
187                Some(Ipv6AddrConfig::Slaac(c)) => c
188            );
189            and_then(SlaacAddressEntryMut { addr_sub: addr_sub, config }, bindings_ctx)
190        })
191    }
192
193    fn remove_addr(
194        &mut self,
195        bindings_ctx: &mut BC,
196        addr: &Ipv6DeviceAddr,
197    ) -> Result<
198        (AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>, Ipv6AddrSlaacConfig<BC::Instant>),
199        NotFoundError,
200    > {
201        let SlaacAddrs { core_ctx, device_id, config } = self;
202        del_ip_addr_inner::<Ipv6, _, _>(
203            core_ctx,
204            bindings_ctx,
205            device_id,
206            DelIpAddr::SpecifiedAddr(addr.into_specified()),
207            AddressRemovedReason::Manual,
208            config,
209        )
210        .map(|(addr_sub, config, result)| {
211            assert_eq!(&addr_sub.addr(), addr);
212            bindings_ctx.defer_removal_result(result);
213            match config {
214                Ipv6AddrConfig::Slaac(config) => (addr_sub, config),
215                Ipv6AddrConfig::Manual(_manual_config) => {
216                    unreachable!(
217                        "address {addr_sub} on device {device_id:?} should have been a SLAAC \
218                        address; config = {config:?}",
219                    );
220                }
221            }
222        })
223    }
224}
225
226impl<BT: BindingsTypes, L> IgmpContextMarker for CoreCtx<'_, BT, L> {}
227
228impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv4>>>
229    IgmpStateContext<BC> for CoreCtx<'_, BC, L>
230{
231    fn with_igmp_state<
232        O,
233        F: FnOnce(
234            &MulticastGroupSet<Ipv4Addr, GmpGroupState<Ipv4, BC>>,
235            &GmpState<Ipv4, IgmpTypeLayout, BC>,
236        ) -> O,
237    >(
238        &mut self,
239        device: &Self::DeviceId,
240        cb: F,
241    ) -> O {
242        let mut state = crate::device::integration::ip_device_state(self, device);
243        let state = state.read_lock::<crate::lock_ordering::IpDeviceGmp<Ipv4>>();
244        let IpDeviceMulticastGroups { groups, gmp, .. } = &*state;
245        cb(groups, gmp)
246    }
247}
248
249impl<BT: BindingsTypes, L> MldContextMarker for CoreCtx<'_, BT, L> {}
250
251impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv6>>>
252    MldStateContext<BC> for CoreCtx<'_, BC, L>
253{
254    fn with_mld_state<
255        O,
256        F: FnOnce(
257            &MulticastGroupSet<Ipv6Addr, GmpGroupState<Ipv6, BC>>,
258            &GmpState<Ipv6, MldTypeLayout, BC>,
259        ) -> O,
260    >(
261        &mut self,
262        device: &Self::DeviceId,
263        cb: F,
264    ) -> O {
265        let mut state = crate::device::integration::ip_device_state(self, device);
266        let state = state.read_lock::<crate::lock_ordering::IpDeviceGmp<Ipv6>>();
267        let IpDeviceMulticastGroups { groups, gmp, .. } = &*state;
268        cb(groups, gmp)
269    }
270}
271
272/// Iterator over a device and its status for an address.
273///
274/// This is functionally identical to using `Iterator::filter_map` on the
275/// provided devices and yielding devices with the address assigned (and the
276/// status), but is named so that it can be used as an associated type.
277pub struct FilterPresentWithDevices<
278    I: IpLayerIpExt,
279    Devices: Iterator<Item = Accessor::DeviceId>,
280    Accessor: DeviceIdContext<AnyDevice>,
281    BT,
282> {
283    devices: Devices,
284    addr: SpecifiedAddr<I::Addr>,
285    state_accessor: Accessor,
286    assignment_state: fn(
287        &mut Accessor,
288        &Accessor::DeviceId,
289        SpecifiedAddr<I::Addr>,
290    ) -> AddressStatus<I::AddressStatus>,
291    _marker: PhantomData<BT>,
292}
293
294impl<
295    I: IpLayerIpExt,
296    Devices: Iterator<Item = Accessor::DeviceId>,
297    Accessor: DeviceIdContext<AnyDevice>,
298    BT,
299> FilterPresentWithDevices<I, Devices, Accessor, BT>
300{
301    fn new(
302        devices: Devices,
303        state_accessor: Accessor,
304        assignment_state: fn(
305            &mut Accessor,
306            &Accessor::DeviceId,
307            SpecifiedAddr<I::Addr>,
308        ) -> AddressStatus<I::AddressStatus>,
309        addr: SpecifiedAddr<I::Addr>,
310    ) -> Self {
311        Self { devices, addr, state_accessor, assignment_state, _marker: PhantomData }
312    }
313}
314
315impl<
316    's,
317    BT: IpDeviceStateBindingsTypes,
318    I: Ip + IpLayerIpExt + IpDeviceIpExt,
319    Devices: Iterator<Item = Accessor::DeviceId>,
320    Accessor: IpDeviceStateContext<I, BT>,
321> Iterator for FilterPresentWithDevices<I, Devices, Accessor, BT>
322where
323    <I as IpDeviceIpExt>::State<BT>: 's,
324{
325    type Item = (Accessor::DeviceId, I::AddressStatus);
326    fn next(&mut self) -> Option<Self::Item> {
327        let Self { devices, addr, state_accessor, assignment_state, _marker } = self;
328        devices
329            .filter_map(|d| match assignment_state(state_accessor, &d, *addr) {
330                AddressStatus::Present(status) => Some((d, status)),
331                AddressStatus::Unassigned => None,
332            })
333            .next()
334    }
335}
336
337impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv4>>>
338    IpDeviceEgressStateContext<Ipv4> for CoreCtx<'_, BC, L>
339{
340    fn with_next_packet_id<O, F: FnOnce(&AtomicU16) -> O>(&self, cb: F) -> O {
341        cb(&self.unlocked_access::<crate::lock_ordering::UnlockedState>().ipv4.next_packet_id)
342    }
343
344    fn get_local_addr_for_remote(
345        &mut self,
346        device_id: &Self::DeviceId,
347        remote: Option<SpecifiedAddr<Ipv4Addr>>,
348    ) -> Option<IpDeviceAddr<Ipv4Addr>> {
349        IpSasHandler::<Ipv4, _>::get_local_addr_for_remote(self, device_id, remote)
350    }
351
352    fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
353        DEFAULT_TTL
354    }
355}
356
357impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv4>>>
358    IpDeviceIngressStateContext<Ipv4> for CoreCtx<'_, BC, L>
359{
360    fn address_status_for_device(
361        &mut self,
362        dst_ip: SpecifiedAddr<Ipv4Addr>,
363        device_id: &Self::DeviceId,
364    ) -> AddressStatus<Ipv4PresentAddressStatus> {
365        AddressStatus::from_context_addr_v4(self, device_id, dst_ip)
366    }
367}
368
369impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>>
370    IpDeviceContext<Ipv4> for CoreCtx<'_, BC, L>
371{
372    fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
373        is_ip_device_enabled::<Ipv4, _, _>(self, device_id)
374    }
375
376    type DeviceAndAddressStatusIter<'a> = FilterPresentWithDevices<
377        Ipv4,
378        <Self as device::IpDeviceConfigurationContext<Ipv4, BC>>::DevicesIter<'a>,
379        <Self as device::IpDeviceConfigurationContext<Ipv4, BC>>::DeviceAddressAndGroupsAccessor<
380            'a,
381        >,
382        BC,
383    >;
384
385    fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
386        &mut self,
387        addr: SpecifiedAddr<Ipv4Addr>,
388        cb: F,
389    ) -> R {
390        device::IpDeviceConfigurationContext::<Ipv4, _>::with_devices_and_state(
391            self,
392            |devices, state| {
393                cb(FilterPresentWithDevices::new(
394                    devices,
395                    state,
396                    AddressStatus::from_context_addr_v4,
397                    addr,
398                ))
399            },
400        )
401    }
402
403    fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
404        is_ip_unicast_forwarding_enabled::<Ipv4, _, _>(self, device_id)
405    }
406}
407
408impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv6>>>
409    IpDeviceEgressStateContext<Ipv6> for CoreCtx<'_, BC, L>
410{
411    fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
412        cb(&())
413    }
414
415    fn get_local_addr_for_remote(
416        &mut self,
417        device_id: &Self::DeviceId,
418        remote: Option<SpecifiedAddr<Ipv6Addr>>,
419    ) -> Option<IpDeviceAddr<Ipv6Addr>> {
420        ip::IpSasHandler::<Ipv6, _>::get_local_addr_for_remote(self, device_id, remote)
421    }
422
423    fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8 {
424        get_ipv6_hop_limit(self, device_id)
425    }
426}
427
428impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv6>>>
429    IpDeviceIngressStateContext<Ipv6> for CoreCtx<'_, BC, L>
430{
431    fn address_status_for_device(
432        &mut self,
433        addr: SpecifiedAddr<Ipv6Addr>,
434        device_id: &Self::DeviceId,
435    ) -> AddressStatus<<Ipv6 as IpLayerIpExt>::AddressStatus> {
436        AddressStatus::from_context_addr_v6(self, device_id, addr)
437    }
438}
439
440impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>>
441    ip::IpDeviceContext<Ipv6> for CoreCtx<'_, BC, L>
442{
443    fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
444        is_ip_device_enabled::<Ipv6, _, _>(self, device_id)
445    }
446
447    type DeviceAndAddressStatusIter<'a> = FilterPresentWithDevices<
448        Ipv6,
449        <Self as device::IpDeviceConfigurationContext<Ipv6, BC>>::DevicesIter<'a>,
450        <Self as device::IpDeviceConfigurationContext<Ipv6, BC>>::DeviceAddressAndGroupsAccessor<
451            'a,
452        >,
453        BC,
454    >;
455
456    fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
457        &mut self,
458        addr: SpecifiedAddr<Ipv6Addr>,
459        cb: F,
460    ) -> R {
461        device::IpDeviceConfigurationContext::<Ipv6, _>::with_devices_and_state(
462            self,
463            |devices, state| {
464                cb(FilterPresentWithDevices::new(
465                    devices,
466                    state,
467                    AddressStatus::from_context_addr_v6,
468                    addr,
469                ))
470            },
471        )
472    }
473
474    fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
475        is_ip_unicast_forwarding_enabled::<Ipv6, _, _>(self, device_id)
476    }
477}
478
479#[netstack3_macros::instantiate_ip_impl_block(I)]
480impl<I: IpExt, BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<I>>>
481    ip::IpDeviceConfirmReachableContext<I, BC> for CoreCtx<'_, BC, L>
482{
483    fn confirm_reachable(
484        &mut self,
485        bindings_ctx: &mut BC,
486        device: &Self::DeviceId,
487        neighbor: SpecifiedAddr<<I as Ip>::Addr>,
488    ) {
489        match device {
490            DeviceId::Ethernet(id) => {
491                nud::confirm_reachable::<I, _, _, _>(self, bindings_ctx, id, neighbor)
492            }
493            // NUD is not supported on Loopback, pure IP, or blackhole devices.
494            DeviceId::Loopback(_) | DeviceId::PureIp(_) | DeviceId::Blackhole(_) => {}
495        }
496    }
497}
498
499impl<I: IpExt, BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>>
500    ip::IpDeviceMtuContext<I> for CoreCtx<'_, BC, L>
501{
502    fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu {
503        crate::device::integration::get_mtu(self, device_id)
504    }
505}
506
507#[netstack3_macros::instantiate_ip_impl_block(I)]
508impl<I: IpExt, BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<I>>>
509    ip::multicast_forwarding::MulticastForwardingDeviceContext<I> for CoreCtx<'_, BC, L>
510{
511    fn is_device_multicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
512        is_ip_multicast_forwarding_enabled::<I, _, _>(self, device_id)
513    }
514}
515
516pub struct CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC: BindingsContext> {
517    pub config: Config,
518    pub core_ctx: CoreCtx<'a, BC, L>,
519}
520
521impl<'a, Config, L, BC: BindingsContext, T> CounterContext<T>
522    for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
523where
524    CoreCtx<'a, BC, L>: CounterContext<T>,
525{
526    fn counters(&self) -> &T {
527        self.core_ctx.counters()
528    }
529}
530
531impl<'a, Config, L, BC: BindingsContext, R, T> ResourceCounterContext<R, T>
532    for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
533where
534    CoreCtx<'a, BC, L>: ResourceCounterContext<R, T>,
535{
536    fn per_resource_counters<'b>(&'b self, resource: &'b R) -> &'b T {
537        self.core_ctx.per_resource_counters(resource)
538    }
539}
540
541impl<'a, Config, L, BC: BindingsContext, T> CoreTimerContext<T, BC>
542    for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
543where
544    CoreCtx<'a, BC, L>: CoreTimerContext<T, BC>,
545{
546    fn convert_timer(dispatch_id: T) -> BC::DispatchId {
547        <CoreCtx<'a, BC, L> as CoreTimerContext<T, BC>>::convert_timer(dispatch_id)
548    }
549}
550
551#[netstack3_macros::instantiate_ip_impl_block(I)]
552impl<'a, I: gmp::IpExt + IpDeviceIpExt, BC: BindingsContext>
553    device::WithIpDeviceConfigurationMutInner<I, BC>
554    for CoreCtxWithIpDeviceConfiguration<
555        'a,
556        &mut <I as IpDeviceIpExt>::Configuration,
557        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<I>>,
558        BC,
559    >
560{
561    type IpDeviceStateCtx<'s>
562        = CoreCtxWithIpDeviceConfiguration<
563        's,
564        &'s <I as IpDeviceIpExt>::Configuration,
565        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<I>>,
566        BC,
567    >
568    where
569        Self: 's;
570
571    fn ip_device_configuration_and_ctx(
572        &mut self,
573    ) -> (&<I as IpDeviceIpExt>::Configuration, Self::IpDeviceStateCtx<'_>) {
574        let Self { config, core_ctx } = self;
575        let config = &**config;
576        (config, CoreCtxWithIpDeviceConfiguration { config, core_ctx: core_ctx.as_owned() })
577    }
578
579    fn with_configuration_and_flags_mut<
580        O,
581        F: FnOnce(&mut <I as IpDeviceIpExt>::Configuration, &mut IpDeviceFlags) -> O,
582    >(
583        &mut self,
584        device_id: &Self::DeviceId,
585        cb: F,
586    ) -> O {
587        let Self { config, core_ctx } = self;
588        let mut state = crate::device::integration::ip_device_state(core_ctx, device_id);
589        let mut flags = state.lock::<crate::lock_ordering::IpDeviceFlags<I>>();
590        cb(*config, &mut *flags)
591    }
592}
593
594impl<'a, BC: BindingsContext> device::WithIpv6DeviceConfigurationMutInner<BC>
595    for CoreCtxWithIpDeviceConfiguration<
596        'a,
597        &mut Ipv6DeviceConfiguration,
598        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
599        BC,
600    >
601{
602    type Ipv6DeviceStateCtx<'s>
603        = CoreCtxWithIpDeviceConfiguration<
604        's,
605        &'s Ipv6DeviceConfiguration,
606        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
607        BC,
608    >
609    where
610        Self: 's;
611
612    fn ipv6_device_configuration_and_ctx(
613        &mut self,
614    ) -> (&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) {
615        let Self { config, core_ctx } = self;
616        let config = &**config;
617        (config, CoreCtxWithIpDeviceConfiguration { config, core_ctx: core_ctx.as_owned() })
618    }
619}
620
621impl<'a, Config, BC: BindingsContext, L> DeviceIdContext<AnyDevice>
622    for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
623{
624    type DeviceId = <CoreCtx<'a, BC, L> as DeviceIdContext<AnyDevice>>::DeviceId;
625    type WeakDeviceId = <CoreCtx<'a, BC, L> as DeviceIdContext<AnyDevice>>::WeakDeviceId;
626}
627
628impl<'a, Config: Borrow<Ipv6DeviceConfiguration>, BC: BindingsContext> SlaacContext<BC>
629    for CoreCtxWithIpDeviceConfiguration<
630        'a,
631        Config,
632        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
633        BC,
634    >
635{
636    type LinkLayerAddr = <Self as device::Ipv6DeviceContext<BC>>::LinkLayerAddr;
637
638    type SlaacAddrs<'s> = SlaacAddrs<'s, BC>;
639
640    fn with_slaac_addrs_mut_and_configs<
641        O,
642        F: FnOnce(
643            &mut Self::SlaacAddrs<'_>,
644            SlaacConfigAndState<Self::LinkLayerAddr, BC>,
645            &mut SlaacState<BC>,
646        ) -> O,
647    >(
648        &mut self,
649        device_id: &Self::DeviceId,
650        cb: F,
651    ) -> O {
652        let Self { config, core_ctx } = self;
653        let retrans_timer = device::Ipv6DeviceContext::with_network_learned_parameters(
654            core_ctx,
655            device_id,
656            |params| {
657                // NB: We currently only change the retransmission timer from
658                // learning it from the network. We might need to consider user
659                // settings once we allow users to override the value.
660                params.retrans_timer_or_default().get()
661            },
662        );
663        // We use the link-layer address to derive opaque IIDs for the interface, rather
664        // than the interface ID or name, because it is more stable. This does imply
665        // that we do not generate SLAAC addresses for interfaces without a link-layer
666        // address (e.g. loopback and pure IP devices); we could revisit this in the
667        // future if desired.
668        let link_layer_addr = device::Ipv6DeviceContext::get_link_layer_addr(core_ctx, device_id);
669
670        let config = Borrow::borrow(config);
671        let Ipv6DeviceConfiguration {
672            max_router_solicitations: _,
673            slaac_config,
674            ip_config:
675                IpDeviceConfiguration {
676                    unicast_forwarding_enabled: _,
677                    multicast_forwarding_enabled: _,
678                    gmp_enabled: _,
679                    dad_transmits,
680                },
681        } = *config;
682
683        let ipv6_state = &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().ipv6;
684        let stable_secret_key = ipv6_state.slaac_stable_secret_key;
685        let temp_secret_key = ipv6_state.slaac_temp_secret_key;
686        let mut core_ctx_and_resource =
687            crate::device::integration::ip_device_state_and_core_ctx(core_ctx, device_id);
688        let (mut state, mut locked) = core_ctx_and_resource
689            .lock_with_and::<crate::lock_ordering::Ipv6DeviceSlaac, _>(|x| x.right());
690        let core_ctx =
691            CoreCtxWithIpDeviceConfiguration { config, core_ctx: locked.cast_core_ctx() };
692
693        let mut addrs = SlaacAddrs { core_ctx, device_id: device_id.clone(), config };
694
695        cb(
696            &mut addrs,
697            SlaacConfigAndState {
698                config: slaac_config,
699                dad_transmits,
700                retrans_timer,
701                link_layer_addr,
702                temp_secret_key,
703                stable_secret_key,
704                _marker: PhantomData,
705            },
706            &mut state,
707        )
708    }
709}
710
711/// Returns `Some` if the provided device supports the ARP protocol.
712fn into_arp_compatible_device<BT: BindingsTypes>(
713    device_id: &DeviceId<BT>,
714) -> Option<&EthernetDeviceId<BT>> {
715    match device_id {
716        DeviceId::Loopback(_) | DeviceId::PureIp(_) | DeviceId::Blackhole(_) => None,
717        // At the moment, Ethernet is the only device type that supports ARP.
718        // However, in the future that may change as we introduce new device
719        // types (e.g. Token Ring devices as specified in IEEE 802.5).
720        DeviceId::Ethernet(id) => Some(id),
721    }
722}
723
724impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddressData<Ipv4>>>
725    DadAddressContext<Ipv4, BC>
726    for CoreCtxWithIpDeviceConfiguration<'_, &'_ Ipv4DeviceConfiguration, L, BC>
727{
728    fn with_address_assigned<O, F: FnOnce(&mut bool) -> O>(
729        &mut self,
730        _: &Self::DeviceId,
731        addr: &Self::AddressId,
732        cb: F,
733    ) -> O {
734        let mut locked = self.core_ctx.adopt(addr.deref());
735        let mut state = locked
736            .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv4>, _>(|c| c.right());
737        let IpAddressData { flags: IpAddressFlags { assigned }, config: _ } = &mut *state;
738
739        cb(assigned)
740    }
741
742    fn should_perform_dad(&mut self, device: &Self::DeviceId, addr: &Self::AddressId) -> bool {
743        // NB: DAD can only be performed for IPv4 addresses on devices that
744        // support ARP. Short circuit for devices that are unsupported.
745        if into_arp_compatible_device(device).is_none() {
746            return false;
747        }
748
749        let mut locked = self.core_ctx.adopt(addr.deref());
750        let state = locked
751            .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv4>, _>(|c| c.right());
752        state.should_perform_dad()
753    }
754}
755
756impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddressData<Ipv6>>>
757    DadAddressContext<Ipv6, BC>
758    for CoreCtxWithIpDeviceConfiguration<'_, &'_ Ipv6DeviceConfiguration, L, BC>
759{
760    fn with_address_assigned<O, F: FnOnce(&mut bool) -> O>(
761        &mut self,
762        _: &Self::DeviceId,
763        addr: &Self::AddressId,
764        cb: F,
765    ) -> O {
766        let mut locked = self.core_ctx.adopt(addr.deref());
767        let mut state = locked
768            .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv6>, _>(|c| c.right());
769        let IpAddressData { flags: IpAddressFlags { assigned }, config: _ } = &mut *state;
770
771        cb(assigned)
772    }
773
774    fn should_perform_dad(&mut self, _: &Self::DeviceId, addr: &Self::AddressId) -> bool {
775        let mut locked = self.core_ctx.adopt(addr.deref());
776        let state = locked
777            .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv6>, _>(|c| c.right());
778        state.should_perform_dad()
779    }
780}
781
782impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv6>>>
783    Ipv6DadAddressContext<BC>
784    for CoreCtxWithIpDeviceConfiguration<'_, &'_ Ipv6DeviceConfiguration, L, BC>
785{
786    fn join_multicast_group(
787        &mut self,
788        bindings_ctx: &mut BC,
789        device_id: &Self::DeviceId,
790        multicast_addr: MulticastAddr<Ipv6Addr>,
791    ) {
792        let Self { config, core_ctx } = self;
793        let config = Borrow::borrow(&*config);
794        join_ip_multicast_with_config(
795            &mut CoreCtxWithIpDeviceConfiguration { config, core_ctx: core_ctx.as_owned() },
796            bindings_ctx,
797            device_id,
798            multicast_addr,
799            config,
800        )
801    }
802
803    fn leave_multicast_group(
804        &mut self,
805        bindings_ctx: &mut BC,
806        device_id: &Self::DeviceId,
807        multicast_addr: MulticastAddr<Ipv6Addr>,
808    ) {
809        let Self { config, core_ctx } = self;
810        let config = Borrow::borrow(&*config);
811        leave_ip_multicast_with_config(
812            &mut CoreCtxWithIpDeviceConfiguration { config, core_ctx: core_ctx.as_owned() },
813            bindings_ctx,
814            device_id,
815            multicast_addr,
816            config,
817        )
818    }
819}
820
821impl<
822    'a,
823    Config: Borrow<Ipv4DeviceConfiguration>,
824    BC: BindingsContext,
825    L: LockBefore<crate::lock_ordering::IpDeviceAddressDad<Ipv4>>,
826> DadContext<Ipv4, BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
827{
828    type DadAddressCtx<'b> = CoreCtxWithIpDeviceConfiguration<
829        'b,
830        &'b Ipv4DeviceConfiguration,
831        WrapLockLevel<crate::lock_ordering::IpDeviceAddressDad<Ipv4>>,
832        BC,
833    >;
834
835    fn with_dad_state<O, F: FnOnce(DadStateRef<'_, Ipv4, Self::DadAddressCtx<'_>, BC>) -> O>(
836        &mut self,
837        _device_id: &Self::DeviceId,
838        addr: &Self::AddressId,
839        cb: F,
840    ) -> O {
841        let Self { config, core_ctx } = self;
842        let mut core_ctx = core_ctx.adopt(addr.deref());
843        let config = Borrow::borrow(&*config);
844
845        let (mut dad_state, mut locked) = core_ctx
846            .lock_with_and::<crate::lock_ordering::IpDeviceAddressDad<Ipv4>, _>(|c| c.right());
847        let mut core_ctx =
848            CoreCtxWithIpDeviceConfiguration { config, core_ctx: locked.cast_core_ctx() };
849
850        cb(DadStateRef {
851            state: DadAddressStateRef { dad_state: dad_state.deref_mut(), core_ctx: &mut core_ctx },
852            retrans_timer_data: &(),
853            max_dad_transmits: &config.ip_config.dad_transmits,
854        })
855    }
856
857    fn send_dad_probe(
858        &mut self,
859        bindings_ctx: &mut BC,
860        device_id: &Self::DeviceId,
861        data: Ipv4DadSendData,
862    ) {
863        // NB: Safe to `unwrap` here because DAD is disabled for IPv4 addresses
864        // on devices that don't support ARP. See the implementation of
865        // [`DadAddressContext::should_perform_dad`] for IPv4.
866        let device_id = into_arp_compatible_device(device_id).unwrap_or_else(|| {
867            panic!("shouldn't run IPv4 DAD on devices that don't support ARP. dev={device_id:?}")
868        });
869
870        // As per RFC 5227 Section 2.1.1:
871        //   A host probes to see if an address is already in use by broadcasting
872        //   an ARP Request for the desired address.  The client MUST fill in the
873        //  'sender hardware address' field of the ARP Request with the hardware
874        //   address of the interface through which it is sending the packet.
875        //   [...]
876        //   The 'target hardware address' field is ignored and SHOULD be set to
877        //   all zeroes.
878        //
879        // Setting the `target_link_addr` to `None` causes `send_arp_request` to
880        // 1) broadcast the request, and 2) set the target hardware address to
881        // all 0s.
882        let target_link_addr = None;
883
884        let (sender_ip, target_ip) = data.into_sender_and_target_addr();
885
886        let Self { config: _, core_ctx } = self;
887        netstack3_device::send_arp_request(
888            core_ctx,
889            bindings_ctx,
890            device_id,
891            sender_ip,
892            target_ip,
893            target_link_addr,
894        )
895    }
896}
897
898impl<
899    'a,
900    Config: Borrow<Ipv6DeviceConfiguration>,
901    BC: BindingsContext,
902    L: LockBefore<crate::lock_ordering::IpDeviceAddressDad<Ipv6>>,
903> DadContext<Ipv6, BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
904{
905    type DadAddressCtx<'b> = CoreCtxWithIpDeviceConfiguration<
906        'b,
907        &'b Ipv6DeviceConfiguration,
908        WrapLockLevel<crate::lock_ordering::IpDeviceAddressDad<Ipv6>>,
909        BC,
910    >;
911
912    fn with_dad_state<O, F: FnOnce(DadStateRef<'_, Ipv6, Self::DadAddressCtx<'_>, BC>) -> O>(
913        &mut self,
914        device_id: &Self::DeviceId,
915        addr: &Self::AddressId,
916        cb: F,
917    ) -> O {
918        let Self { config, core_ctx } = self;
919        let retrans_timer = device::Ipv6DeviceContext::<BC>::with_network_learned_parameters(
920            core_ctx,
921            device_id,
922            |p| {
923                // NB: We currently only change the retransmission timer from
924                // learning it from the network. We might need to consider user
925                // settings once we allow users to override the value.
926                p.retrans_timer_or_default()
927            },
928        );
929
930        let mut core_ctx = core_ctx.adopt(addr.deref());
931        let config = Borrow::borrow(&*config);
932
933        let (mut dad_state, mut locked) = core_ctx
934            .lock_with_and::<crate::lock_ordering::IpDeviceAddressDad<Ipv6>, _>(|c| c.right());
935        let mut core_ctx =
936            CoreCtxWithIpDeviceConfiguration { config, core_ctx: locked.cast_core_ctx() };
937
938        cb(DadStateRef {
939            state: DadAddressStateRef { dad_state: dad_state.deref_mut(), core_ctx: &mut core_ctx },
940            retrans_timer_data: &retrans_timer,
941            max_dad_transmits: &config.ip_config.dad_transmits,
942        })
943    }
944    /// Sends an NDP Neighbor Solicitation message for DAD to the local-link.
945    ///
946    /// The message will be sent with the unspecified (all-zeroes) source
947    /// address.
948    fn send_dad_probe(
949        &mut self,
950        bindings_ctx: &mut BC,
951        device_id: &Self::DeviceId,
952        Ipv6DadSendData { dst_ip, message, nonce }: Ipv6DadSendData,
953    ) {
954        // Do not include the source link-layer option when the NS
955        // message as DAD messages are sent with the unspecified source
956        // address which must not hold a source link-layer option.
957        //
958        // As per RFC 4861 section 4.3,
959        //
960        //   Possible options:
961        //
962        //      Source link-layer address
963        //           The link-layer address for the sender. MUST NOT be
964        //           included when the source IP address is the
965        //           unspecified address. Otherwise, on link layers
966        //           that have addresses this option MUST be included in
967        //           multicast solicitations and SHOULD be included in
968        //           unicast solicitations.
969        let src_ip = None;
970        let options = [NdpOptionBuilder::Nonce(NdpNonce::from(&nonce))];
971
972        let result = ip::icmp::send_ndp_packet(
973            self,
974            bindings_ctx,
975            device_id,
976            src_ip,
977            dst_ip.into_specified(),
978            OptionSequenceBuilder::new(options.iter()).into_serializer(),
979            ip::icmp::NdpMessage::NeighborSolicitation { message, code: IcmpZeroCode },
980        );
981        match result {
982            Ok(()) => {}
983            Err(IpSendFrameError { serializer: _, error }) => {
984                // TODO(https://fxbug.dev/42165912): Either panic or guarantee
985                // that this error can't happen statically.
986                debug!("error sending DAD packet: {error:?}")
987            }
988        }
989    }
990}
991
992impl<'a, Config: Borrow<Ipv6DeviceConfiguration>, BC: BindingsContext> RsContext<BC>
993    for CoreCtxWithIpDeviceConfiguration<
994        'a,
995        Config,
996        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
997        BC,
998    >
999{
1000    type LinkLayerAddr = <CoreCtx<
1001        'a,
1002        BC,
1003        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
1004    > as device::Ipv6DeviceContext<BC>>::LinkLayerAddr;
1005
1006    fn with_rs_state_mut_and_max<O, F: FnOnce(&mut RsState<BC>, Option<NonZeroU8>) -> O>(
1007        &mut self,
1008        device_id: &Self::DeviceId,
1009        cb: F,
1010    ) -> O {
1011        let Self { config, core_ctx } = self;
1012        let mut state = crate::device::integration::ip_device_state(core_ctx, device_id);
1013        let mut state = state.lock::<crate::lock_ordering::Ipv6DeviceRouterSolicitations>();
1014        cb(&mut state, Borrow::borrow(&*config).max_router_solicitations)
1015    }
1016
1017    fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr> {
1018        let Self { config: _, core_ctx } = self;
1019        device::Ipv6DeviceContext::get_link_layer_addr(core_ctx, device_id)
1020    }
1021
1022    fn send_rs_packet<
1023        S: Serializer<Buffer = EmptyBuf> + PartialSerializer,
1024        F: FnOnce(Option<UnicastAddr<Ipv6Addr>>) -> S,
1025    >(
1026        &mut self,
1027        bindings_ctx: &mut BC,
1028        device_id: &Self::DeviceId,
1029        message: RouterSolicitation,
1030        body: F,
1031    ) -> Result<(), IpSendFrameError<S>> {
1032        let Self { config: _, core_ctx } = self;
1033
1034        let dst_ip = Ipv6::ALL_ROUTERS_LINK_LOCAL_MULTICAST_ADDRESS.into_specified();
1035        let src_ip = ip::IpSasHandler::<Ipv6, _>::get_local_addr_for_remote(
1036            core_ctx,
1037            device_id,
1038            Some(dst_ip),
1039        )
1040        .and_then(|addr| UnicastAddr::new(addr.addr()));
1041        ip::icmp::send_ndp_packet(
1042            core_ctx,
1043            bindings_ctx,
1044            device_id,
1045            src_ip.map(UnicastAddr::into_specified),
1046            dst_ip,
1047            body(src_ip),
1048            ip::icmp::NdpMessage::RouterSolicitation { message, code: IcmpZeroCode },
1049        )
1050    }
1051}
1052
1053impl<
1054    I: IpExt,
1055    Config,
1056    BC: BindingsContext,
1057    L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>,
1058> ip::IpDeviceMtuContext<I> for CoreCtxWithIpDeviceConfiguration<'_, Config, L, BC>
1059{
1060    fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu {
1061        ip::IpDeviceMtuContext::<I>::get_mtu(&mut self.core_ctx, device_id)
1062    }
1063}
1064
1065impl<L, BT: BindingsTypes> CoreTimerContext<RsTimerId<WeakDeviceId<BT>>, BT>
1066    for CoreCtx<'_, BT, L>
1067{
1068    fn convert_timer(dispatch_id: RsTimerId<WeakDeviceId<BT>>) -> BT::DispatchId {
1069        IpDeviceTimerId::<Ipv6, _, _>::from(Ipv6DeviceTimerId::from(dispatch_id)).into()
1070    }
1071}
1072
1073impl<BC: BindingsContext> Ipv6DiscoveredRoutesContext<BC>
1074    for CoreCtx<'_, BC, WrapLockLevel<crate::lock_ordering::Ipv6DeviceRouteDiscovery>>
1075{
1076    fn add_discovered_ipv6_route(
1077        &mut self,
1078        bindings_ctx: &mut BC,
1079        device_id: &Self::DeviceId,
1080        Ipv6DiscoveredRoute { subnet, gateway }: Ipv6DiscoveredRoute,
1081    ) {
1082        let device_id = device_id.clone();
1083        let entry = ip::AddableEntry {
1084            subnet,
1085            device: device_id,
1086            gateway: gateway.map(|g| (*g).into_specified()),
1087            metric: AddableMetric::MetricTracksInterface,
1088        };
1089
1090        ip::request_context_add_route::<Ipv6, _, _>(bindings_ctx, entry);
1091    }
1092
1093    fn del_discovered_ipv6_route(
1094        &mut self,
1095        bindings_ctx: &mut BC,
1096        device_id: &Self::DeviceId,
1097        Ipv6DiscoveredRoute { subnet, gateway }: Ipv6DiscoveredRoute,
1098    ) {
1099        ip::request_context_del_routes::<Ipv6, _, _>(
1100            bindings_ctx,
1101            subnet,
1102            device_id.clone(),
1103            gateway.map(|g| (*g).into_specified()),
1104        );
1105    }
1106}
1107
1108impl<'a, Config, BC: BindingsContext> Ipv6RouteDiscoveryContext<BC>
1109    for CoreCtxWithIpDeviceConfiguration<
1110        'a,
1111        Config,
1112        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
1113        BC,
1114    >
1115{
1116    type WithDiscoveredRoutesMutCtx<'b> =
1117        CoreCtx<'b, BC, WrapLockLevel<crate::lock_ordering::Ipv6DeviceRouteDiscovery>>;
1118
1119    fn with_discovered_routes_mut<
1120        O,
1121        F: FnOnce(&mut Ipv6RouteDiscoveryState<BC>, &mut Self::WithDiscoveredRoutesMutCtx<'_>) -> O,
1122    >(
1123        &mut self,
1124        device_id: &Self::DeviceId,
1125        cb: F,
1126    ) -> O {
1127        let Self { config: _, core_ctx } = self;
1128        let mut core_ctx_and_resource =
1129            crate::device::integration::ip_device_state_and_core_ctx(core_ctx, device_id);
1130
1131        let (mut state, mut locked) =
1132            core_ctx_and_resource
1133                .lock_with_and::<crate::lock_ordering::Ipv6DeviceRouteDiscovery, _>(|x| x.right());
1134        cb(&mut state, &mut locked.cast_core_ctx())
1135    }
1136}
1137
1138impl<'a, Config, BC: BindingsContext> device::Ipv6DeviceContext<BC>
1139    for CoreCtxWithIpDeviceConfiguration<
1140        'a,
1141        Config,
1142        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
1143        BC,
1144    >
1145{
1146    type LinkLayerAddr = <CoreCtx<
1147        'a,
1148        BC,
1149        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
1150    > as device::Ipv6DeviceContext<BC>>::LinkLayerAddr;
1151
1152    fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr> {
1153        let Self { config: _, core_ctx } = self;
1154        device::Ipv6DeviceContext::get_link_layer_addr(core_ctx, device_id)
1155    }
1156
1157    fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
1158        let Self { config: _, core_ctx } = self;
1159        device::Ipv6DeviceContext::set_link_mtu(core_ctx, device_id, mtu)
1160    }
1161
1162    fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
1163        &mut self,
1164        device_id: &Self::DeviceId,
1165        cb: F,
1166    ) -> O {
1167        let Self { config: _, core_ctx } = self;
1168        device::Ipv6DeviceContext::with_network_learned_parameters(core_ctx, device_id, cb)
1169    }
1170
1171    fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
1172        &mut self,
1173        device_id: &Self::DeviceId,
1174        cb: F,
1175    ) -> O {
1176        let Self { config: _, core_ctx } = self;
1177        device::Ipv6DeviceContext::with_network_learned_parameters_mut(core_ctx, device_id, cb)
1178    }
1179}
1180
1181impl<'a, Config, I: IpDeviceIpExt, L, BC: BindingsContext> IpDeviceAddressIdContext<I>
1182    for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1183where
1184    CoreCtx<'a, BC, L>: IpDeviceAddressIdContext<I>,
1185{
1186    type AddressId = <CoreCtx<'a, BC, L> as IpDeviceAddressIdContext<I>>::AddressId;
1187    type WeakAddressId = <CoreCtx<'a, BC, L> as IpDeviceAddressIdContext<I>>::WeakAddressId;
1188}
1189
1190impl<'a, Config, I: IpDeviceIpExt, BC: BindingsContext, L> device::IpDeviceAddressContext<I, BC>
1191    for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1192where
1193    CoreCtx<'a, BC, L>: device::IpDeviceAddressContext<I, BC>,
1194{
1195    fn with_ip_address_data<O, F: FnOnce(&IpAddressData<I, BC::Instant>) -> O>(
1196        &mut self,
1197        device_id: &Self::DeviceId,
1198        addr_id: &Self::AddressId,
1199        cb: F,
1200    ) -> O {
1201        let Self { config: _, core_ctx } = self;
1202        device::IpDeviceAddressContext::<I, BC>::with_ip_address_data(
1203            core_ctx, device_id, addr_id, cb,
1204        )
1205    }
1206
1207    fn with_ip_address_data_mut<O, F: FnOnce(&mut IpAddressData<I, BC::Instant>) -> O>(
1208        &mut self,
1209        device_id: &Self::DeviceId,
1210        addr_id: &Self::AddressId,
1211        cb: F,
1212    ) -> O {
1213        let Self { config: _, core_ctx } = self;
1214        device::IpDeviceAddressContext::<I, BC>::with_ip_address_data_mut(
1215            core_ctx, device_id, addr_id, cb,
1216        )
1217    }
1218}
1219
1220impl<'a, Config, I: IpDeviceIpExt, BC: BindingsContext, L> device::IpDeviceStateContext<I, BC>
1221    for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1222where
1223    CoreCtx<'a, BC, L>: device::IpDeviceStateContext<I, BC>,
1224{
1225    type IpDeviceAddressCtx<'b> =
1226        <CoreCtx<'a, BC, L> as device::IpDeviceStateContext<I, BC>>::IpDeviceAddressCtx<'b>;
1227
1228    fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
1229        &mut self,
1230        device_id: &Self::DeviceId,
1231        cb: F,
1232    ) -> O {
1233        let Self { config: _, core_ctx } = self;
1234        device::IpDeviceStateContext::<I, BC>::with_ip_device_flags(core_ctx, device_id, cb)
1235    }
1236
1237    fn add_ip_address(
1238        &mut self,
1239        device_id: &Self::DeviceId,
1240        addr: AddrSubnet<I::Addr, I::AssignedWitness>,
1241        config: I::AddressConfig<BC::Instant>,
1242    ) -> Result<Self::AddressId, ExistsError> {
1243        let Self { config: _, core_ctx } = self;
1244        device::IpDeviceStateContext::<I, BC>::add_ip_address(core_ctx, device_id, addr, config)
1245    }
1246
1247    fn remove_ip_address(
1248        &mut self,
1249        device_id: &Self::DeviceId,
1250        addr: Self::AddressId,
1251    ) -> RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC> {
1252        let Self { config: _, core_ctx } = self;
1253        device::IpDeviceStateContext::<I, BC>::remove_ip_address(core_ctx, device_id, addr)
1254    }
1255
1256    fn get_address_id(
1257        &mut self,
1258        device_id: &Self::DeviceId,
1259        addr: SpecifiedAddr<I::Addr>,
1260    ) -> Result<Self::AddressId, NotFoundError> {
1261        let Self { config: _, core_ctx } = self;
1262        device::IpDeviceStateContext::<I, BC>::get_address_id(core_ctx, device_id, addr)
1263    }
1264
1265    type AddressIdsIter<'b> =
1266        <CoreCtx<'a, BC, L> as device::IpDeviceStateContext<I, BC>>::AddressIdsIter<'b>;
1267    fn with_address_ids<
1268        O,
1269        F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
1270    >(
1271        &mut self,
1272        device_id: &Self::DeviceId,
1273        cb: F,
1274    ) -> O {
1275        let Self { config: _, core_ctx } = self;
1276        device::IpDeviceStateContext::<I, BC>::with_address_ids(core_ctx, device_id, cb)
1277    }
1278
1279    fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
1280        &mut self,
1281        device_id: &Self::DeviceId,
1282        cb: F,
1283    ) -> O {
1284        let Self { config: _, core_ctx } = self;
1285        device::IpDeviceStateContext::<I, BC>::with_default_hop_limit(core_ctx, device_id, cb)
1286    }
1287
1288    fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
1289        &mut self,
1290        device_id: &Self::DeviceId,
1291        cb: F,
1292    ) -> O {
1293        let Self { config: _, core_ctx } = self;
1294        device::IpDeviceStateContext::<I, BC>::with_default_hop_limit_mut(core_ctx, device_id, cb)
1295    }
1296
1297    fn join_link_multicast_group(
1298        &mut self,
1299        bindings_ctx: &mut BC,
1300        device_id: &Self::DeviceId,
1301        multicast_addr: MulticastAddr<I::Addr>,
1302    ) {
1303        let Self { config: _, core_ctx } = self;
1304        device::IpDeviceStateContext::<I, BC>::join_link_multicast_group(
1305            core_ctx,
1306            bindings_ctx,
1307            device_id,
1308            multicast_addr,
1309        )
1310    }
1311
1312    fn leave_link_multicast_group(
1313        &mut self,
1314        bindings_ctx: &mut BC,
1315        device_id: &Self::DeviceId,
1316        multicast_addr: MulticastAddr<I::Addr>,
1317    ) {
1318        let Self { config: _, core_ctx } = self;
1319        device::IpDeviceStateContext::<I, BC>::leave_link_multicast_group(
1320            core_ctx,
1321            bindings_ctx,
1322            device_id,
1323            multicast_addr,
1324        )
1325    }
1326}
1327
1328impl<BC: BindingsContext, Config, L> IgmpContextMarker
1329    for CoreCtxWithIpDeviceConfiguration<'_, Config, L, BC>
1330{
1331}
1332
1333impl<'a, Config: Borrow<Ipv4DeviceConfiguration>, BC: BindingsContext> IgmpContext<BC>
1334    for CoreCtxWithIpDeviceConfiguration<
1335        'a,
1336        Config,
1337        WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>,
1338        BC,
1339    >
1340{
1341    type SendContext<'b> = CoreCtx<'b, BC, WrapLockLevel<crate::lock_ordering::IpDeviceGmp<Ipv4>>>;
1342
1343    /// Calls the function with a mutable reference to the device's IGMP state
1344    /// and whether or not IGMP is enabled for the `device`.
1345    fn with_igmp_state_mut<
1346        O,
1347        F: for<'b> FnOnce(Self::SendContext<'b>, GmpStateRef<'b, Ipv4, IgmpTypeLayout, BC>) -> O,
1348    >(
1349        &mut self,
1350        device: &Self::DeviceId,
1351        cb: F,
1352    ) -> O {
1353        let Self { config, core_ctx } = self;
1354        let Ipv4DeviceConfiguration { ip_config: IpDeviceConfiguration { gmp_enabled, .. } } =
1355            Borrow::borrow(&*config);
1356
1357        let mut state = crate::device::integration::ip_device_state_and_core_ctx(core_ctx, device);
1358        // Note that changes to `ip_enabled` is not possible in this context
1359        // since IP enabled changes are only performed while the IP device
1360        // configuration lock is held exclusively. Since we have access to
1361        // the IP device configuration here (`config`), we know changes to
1362        // IP enabled are not possible.
1363        let ip_enabled = state
1364            .lock_with::<crate::lock_ordering::IpDeviceFlags<Ipv4>, _>(|x| x.right())
1365            .ip_enabled;
1366        let (mut state, mut locked) =
1367            state.write_lock_with_and::<crate::lock_ordering::IpDeviceGmp<Ipv4>, _>(|x| x.right());
1368        let IpDeviceMulticastGroups { groups, gmp, gmp_config } = &mut *state;
1369        let enabled = ip_enabled && *gmp_enabled;
1370        cb(locked.cast_core_ctx(), GmpStateRef { enabled, groups, gmp, config: gmp_config })
1371    }
1372}
1373
1374impl<'a, BC: BindingsContext> IgmpSendContext<BC>
1375    for CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpDeviceGmp<Ipv4>>>
1376{
1377    fn get_ip_addr_subnet(
1378        &mut self,
1379        device: &Self::DeviceId,
1380    ) -> Option<AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> {
1381        ip::device::get_ipv4_addr_subnet(self, device)
1382    }
1383}
1384
1385impl<BC: BindingsContext, Config, L> MldContextMarker
1386    for CoreCtxWithIpDeviceConfiguration<'_, Config, L, BC>
1387{
1388}
1389
1390impl<
1391    'a,
1392    Config: Borrow<Ipv6DeviceConfiguration>,
1393    BC: BindingsContext,
1394    L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv6>>,
1395> MldContext<BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1396{
1397    type SendContext<'b> = CoreCtx<'b, BC, WrapLockLevel<crate::lock_ordering::IpDeviceGmp<Ipv6>>>;
1398
1399    fn with_mld_state_mut<
1400        O,
1401        F: FnOnce(Self::SendContext<'_>, GmpStateRef<'_, Ipv6, MldTypeLayout, BC>) -> O,
1402    >(
1403        &mut self,
1404        device: &Self::DeviceId,
1405        cb: F,
1406    ) -> O {
1407        let Self { config, core_ctx } = self;
1408        let Ipv6DeviceConfiguration {
1409            max_router_solicitations: _,
1410            slaac_config: _,
1411            ip_config: IpDeviceConfiguration { gmp_enabled, .. },
1412        } = Borrow::borrow(&*config);
1413
1414        let mut state = crate::device::integration::ip_device_state_and_core_ctx(core_ctx, device);
1415        let ip_enabled = state
1416            .lock_with::<crate::lock_ordering::IpDeviceFlags<Ipv6>, _>(|x| x.right())
1417            .ip_enabled;
1418        let (mut state, mut locked) =
1419            state.write_lock_with_and::<crate::lock_ordering::IpDeviceGmp<Ipv6>, _>(|x| x.right());
1420        let IpDeviceMulticastGroups { groups, gmp, gmp_config } = &mut *state;
1421        let enabled = ip_enabled && *gmp_enabled;
1422        cb(locked.cast_core_ctx(), GmpStateRef { enabled, groups, gmp, config: gmp_config })
1423    }
1424}
1425
1426impl<'a, BC: BindingsContext> MldSendContext<BC>
1427    for CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpDeviceGmp<Ipv6>>>
1428{
1429    fn get_ipv6_link_local_addr(
1430        &mut self,
1431        device: &Self::DeviceId,
1432    ) -> Option<LinkLocalUnicastAddr<Ipv6Addr>> {
1433        device::IpDeviceStateContext::<Ipv6, BC>::with_address_ids(
1434            self,
1435            device,
1436            |mut addrs, core_ctx| {
1437                addrs.find_map(|addr_id| {
1438                    device::IpDeviceAddressContext::<Ipv6, _>::with_ip_address_data(
1439                        core_ctx,
1440                        device,
1441                        &addr_id,
1442                        |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
1443                            if *assigned {
1444                                LinkLocalUnicastAddr::new(addr_id.addr_sub().addr().get())
1445                            } else {
1446                                None
1447                            }
1448                        },
1449                    )
1450                })
1451            },
1452        )
1453    }
1454}
1455
1456impl<'a, Config, I: IpDeviceIpExt, BC: BindingsContext, L> NudIpHandler<I, BC>
1457    for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1458where
1459    CoreCtx<'a, BC, L>: NudIpHandler<I, BC>,
1460{
1461    fn handle_neighbor_probe(
1462        &mut self,
1463        bindings_ctx: &mut BC,
1464        device_id: &Self::DeviceId,
1465        neighbor: SpecifiedAddr<I::Addr>,
1466        link_addr: &[u8],
1467    ) {
1468        let Self { config: _, core_ctx } = self;
1469        NudIpHandler::<I, BC>::handle_neighbor_probe(
1470            core_ctx,
1471            bindings_ctx,
1472            device_id,
1473            neighbor,
1474            link_addr,
1475        )
1476    }
1477
1478    fn handle_neighbor_confirmation(
1479        &mut self,
1480        bindings_ctx: &mut BC,
1481        device_id: &Self::DeviceId,
1482        neighbor: SpecifiedAddr<I::Addr>,
1483        link_addr: Option<&[u8]>,
1484        flags: ConfirmationFlags,
1485    ) {
1486        let Self { config: _, core_ctx } = self;
1487        NudIpHandler::<I, BC>::handle_neighbor_confirmation(
1488            core_ctx,
1489            bindings_ctx,
1490            device_id,
1491            neighbor,
1492            link_addr,
1493            flags,
1494        )
1495    }
1496
1497    fn flush_neighbor_table(&mut self, bindings_ctx: &mut BC, device_id: &Self::DeviceId) {
1498        let Self { config: _, core_ctx } = self;
1499        NudIpHandler::<I, BC>::flush_neighbor_table(core_ctx, bindings_ctx, device_id)
1500    }
1501}
1502
1503#[netstack3_macros::instantiate_ip_impl_block(I)]
1504impl<'a, I: IpExt, Config, BC: BindingsContext, L: LockBefore<crate::lock_ordering::FilterState<I>>>
1505    FilterHandlerProvider<I, BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1506{
1507    type Handler<'b>
1508        = FilterImpl<'b, CoreCtx<'a, BC, L>>
1509    where
1510        Self: 'b;
1511
1512    fn filter_handler(&mut self) -> Self::Handler<'_> {
1513        let Self { config: _, core_ctx } = self;
1514        FilterHandlerProvider::<I, BC>::filter_handler(core_ctx)
1515    }
1516}
1517
1518#[netstack3_macros::instantiate_ip_impl_block(I)]
1519impl<
1520    'a,
1521    I: IpLayerIpExt,
1522    Config,
1523    BC: BindingsContext,
1524    L: LockBefore<crate::lock_ordering::IpDeviceGmp<I>>,
1525> IpDeviceEgressStateContext<I> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1526{
1527    fn with_next_packet_id<O, F: FnOnce(&<I as IpLayerIpExt>::PacketIdState) -> O>(
1528        &self,
1529        cb: F,
1530    ) -> O {
1531        let Self { config: _, core_ctx } = self;
1532        IpDeviceEgressStateContext::<I>::with_next_packet_id(core_ctx, cb)
1533    }
1534
1535    fn get_local_addr_for_remote(
1536        &mut self,
1537        device_id: &Self::DeviceId,
1538        remote: Option<SpecifiedAddr<<I as Ip>::Addr>>,
1539    ) -> Option<IpDeviceAddr<<I as Ip>::Addr>> {
1540        let Self { config: _, core_ctx } = self;
1541        IpDeviceEgressStateContext::<I>::get_local_addr_for_remote(core_ctx, device_id, remote)
1542    }
1543
1544    fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8 {
1545        let Self { config: _, core_ctx } = self;
1546        IpDeviceEgressStateContext::<I>::get_hop_limit(core_ctx, device_id)
1547    }
1548}
1549
1550#[netstack3_macros::instantiate_ip_impl_block(I)]
1551impl<
1552    'a,
1553    I: IpLayerIpExt,
1554    Config,
1555    BC: BindingsContext,
1556    L: LockBefore<crate::lock_ordering::IpDeviceGmp<I>>,
1557> IpDeviceIngressStateContext<I> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1558{
1559    fn address_status_for_device(
1560        &mut self,
1561        dst_ip: SpecifiedAddr<<I as Ip>::Addr>,
1562        device_id: &Self::DeviceId,
1563    ) -> AddressStatus<<I as IpLayerIpExt>::AddressStatus> {
1564        let Self { config: _, core_ctx } = self;
1565        IpDeviceIngressStateContext::<I>::address_status_for_device(core_ctx, dst_ip, device_id)
1566    }
1567}
1568
1569impl<BC: BindingsContext, I: Ip, L> CounterContext<NudCounters<I>> for CoreCtx<'_, BC, L> {
1570    fn counters(&self) -> &NudCounters<I> {
1571        self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.nud_counters::<I>()
1572    }
1573}
1574
1575impl<L, BT: BindingsTypes>
1576    CoreTimerContext<DadTimerId<Ipv4, WeakDeviceId<BT>, WeakAddressId<Ipv4, BT>>, BT>
1577    for CoreCtx<'_, BT, L>
1578{
1579    fn convert_timer(
1580        dispatch_id: DadTimerId<Ipv4, WeakDeviceId<BT>, WeakAddressId<Ipv4, BT>>,
1581    ) -> BT::DispatchId {
1582        IpDeviceTimerId::<Ipv4, _, _>::from(Ipv4DeviceTimerId::from(dispatch_id)).into()
1583    }
1584}
1585
1586impl<L, BT: BindingsTypes>
1587    CoreTimerContext<DadTimerId<Ipv6, WeakDeviceId<BT>, WeakAddressId<Ipv6, BT>>, BT>
1588    for CoreCtx<'_, BT, L>
1589{
1590    fn convert_timer(
1591        dispatch_id: DadTimerId<Ipv6, WeakDeviceId<BT>, WeakAddressId<Ipv6, BT>>,
1592    ) -> BT::DispatchId {
1593        IpDeviceTimerId::<Ipv6, _, _>::from(Ipv6DeviceTimerId::from(dispatch_id)).into()
1594    }
1595}
1596
1597impl<I: IpDeviceIpExt, BT: BindingsTypes, L>
1598    CoreTimerContext<IpDeviceTimerId<I, WeakDeviceId<BT>, BT>, BT> for CoreCtx<'_, BT, L>
1599{
1600    fn convert_timer(dispatch_id: IpDeviceTimerId<I, WeakDeviceId<BT>, BT>) -> BT::DispatchId {
1601        dispatch_id.into()
1602    }
1603}
1604
1605impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1606    for crate::lock_ordering::IpDeviceAddresses<I>
1607{
1608    type Data = IpDeviceAddresses<I, BT>;
1609}
1610
1611impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1612    for crate::lock_ordering::IpDeviceGmp<I>
1613{
1614    type Data = IpDeviceMulticastGroups<I, BT>;
1615}
1616
1617impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1618    for crate::lock_ordering::IpDeviceDefaultHopLimit<I>
1619{
1620    type Data = DefaultHopLimit<I>;
1621}
1622
1623impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1624    for crate::lock_ordering::IpDeviceFlags<I>
1625{
1626    type Data = IpMarked<I, IpDeviceFlags>;
1627}
1628
1629impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1630    for crate::lock_ordering::Ipv6DeviceSlaac
1631{
1632    type Data = SlaacState<BT>;
1633}
1634
1635/// It is safe to provide unlocked access to [`DualStackIpDeviceState`] itself
1636/// here because care has been taken to avoid exposing publicly to the core
1637/// integration crate any state that is held by a lock, as opposed to read-only
1638/// state that can be accessed safely at any lock level, e.g. state with no
1639/// interior mutability or atomics.
1640///
1641/// Access to state held by locks *must* be mediated using the global lock
1642/// ordering declared in [`crate::lock_ordering`].
1643impl<BT: IpDeviceStateBindingsTypes> UnlockedAccess<crate::lock_ordering::UnlockedState>
1644    for DualStackIpDeviceState<BT>
1645{
1646    type Data = DualStackIpDeviceState<BT>;
1647    type Guard<'l>
1648        = &'l DualStackIpDeviceState<BT>
1649    where
1650        Self: 'l;
1651
1652    fn access(&self) -> Self::Guard<'_> {
1653        &self
1654    }
1655}
1656
1657impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1658    for crate::lock_ordering::IpDeviceConfiguration<Ipv4>
1659{
1660    type Data = Ipv4DeviceConfiguration;
1661}
1662
1663impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1664    for crate::lock_ordering::Ipv6DeviceLearnedParams
1665{
1666    type Data = Ipv6NetworkLearnedParameters;
1667}
1668
1669impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1670    for crate::lock_ordering::Ipv6DeviceRouteDiscovery
1671{
1672    type Data = Ipv6RouteDiscoveryState<BT>;
1673}
1674
1675impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1676    for crate::lock_ordering::Ipv6DeviceRouterSolicitations
1677{
1678    type Data = RsState<BT>;
1679}
1680
1681impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1682    for crate::lock_ordering::IpDeviceConfiguration<Ipv6>
1683{
1684    type Data = Ipv6DeviceConfiguration;
1685}
1686
1687impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<IpAddressEntry<Ipv4, BT>>
1688    for crate::lock_ordering::IpDeviceAddressDad<Ipv4>
1689{
1690    type Data = DadState<Ipv4, BT>;
1691}
1692
1693impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<IpAddressEntry<Ipv4, BT>>
1694    for crate::lock_ordering::IpDeviceAddressData<Ipv4>
1695{
1696    type Data = IpAddressData<Ipv4, BT::Instant>;
1697}
1698
1699impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<IpAddressEntry<Ipv6, BT>>
1700    for crate::lock_ordering::IpDeviceAddressDad<Ipv6>
1701{
1702    type Data = DadState<Ipv6, BT>;
1703}
1704
1705impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<IpAddressEntry<Ipv6, BT>>
1706    for crate::lock_ordering::IpDeviceAddressData<Ipv6>
1707{
1708    type Data = IpAddressData<Ipv6, BT::Instant>;
1709}
1710
1711impl<BT: BindingsTypes, L> CounterContext<SlaacCounters> for CoreCtx<'_, BT, L> {
1712    fn counters(&self) -> &SlaacCounters {
1713        &self.unlocked_access::<crate::lock_ordering::UnlockedState>().ipv6.slaac_counters
1714    }
1715}