Skip to main content

netstack3_core/device/
ethernet.rs

1// Copyright 2024 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 traits defined in foreign modules for the types defined
6//! in the ethernet module.
7
8use core::time::Duration;
9
10use alloc::vec::Vec;
11use lock_order::lock::LockLevelFor;
12use lock_order::relation::LockBefore;
13
14use log::debug;
15use net_types::ethernet::Mac;
16use net_types::ip::{Ip, IpMarked, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
17use net_types::{SpecifiedAddr, UnicastAddr, Witness};
18use netstack3_base::socket::SocketIpAddr;
19use netstack3_base::{CoreTimerContext, CounterContext, DeviceIdContext, Marks, SendFrameError};
20use netstack3_device::ethernet::{
21    self, DynamicEthernetDeviceState, EthernetDeviceId, EthernetIpLinkDeviceDynamicStateContext,
22    EthernetIpLinkDeviceStaticStateContext, EthernetLinkDevice, EthernetTimerId,
23    EthernetWeakDeviceId, StaticEthernetDeviceState,
24};
25use netstack3_device::queue::{
26    BufVecU8Allocator, DequeueState, TransmitDequeueContext, TransmitQueueCommon,
27    TransmitQueueContext, TransmitQueueState,
28};
29use netstack3_device::socket::{ParseSentFrameError, SentFrame};
30use netstack3_device::{
31    ArpConfigContext, ArpContext, ArpIpLayerContext, ArpNudCtx, ArpSenderContext, ArpState,
32    DeviceId, DeviceLayerEventDispatcher, DeviceLayerTimerId, DeviceSendFrameError,
33    IpLinkDeviceState,
34};
35use netstack3_ip::IpDeviceEgressStateContext;
36use netstack3_ip::icmp::{self, IcmpErrorHandler, Icmpv4Error, Icmpv6Error, NdpCounters};
37use netstack3_ip::nud::{
38    DelegateNudContext, NudConfigContext, NudContext, NudIcmpContext, NudSenderContext, NudState,
39    NudUserConfig, UseDelegateNudContext,
40};
41use packet::{Buf, BufferMut, InnerPacketBuilder as _, Serializer};
42use packet_formats::ethernet::EtherType;
43use packet_formats::icmp::IcmpZeroCode;
44use packet_formats::icmp::ndp::options::NdpOptionBuilder;
45use packet_formats::icmp::ndp::{NeighborSolicitation, OptionSequenceBuilder};
46use packet_formats::ip::{Ipv4Proto, Ipv6Proto};
47use packet_formats::ipv4::Ipv4FragmentType;
48use packet_formats::utils::NonZeroDuration;
49
50use crate::context::WrapLockLevel;
51use crate::context::prelude::*;
52use crate::device::integration;
53use crate::{BindingsContext, BindingsTypes, CoreCtx};
54
55pub struct CoreCtxWithDeviceId<'a, CC: DeviceIdContext<EthernetLinkDevice>> {
56    core_ctx: &'a mut CC,
57    device_id: &'a CC::DeviceId,
58}
59
60impl<'a, CC: DeviceIdContext<EthernetLinkDevice>> DeviceIdContext<EthernetLinkDevice>
61    for CoreCtxWithDeviceId<'a, CC>
62{
63    type DeviceId = CC::DeviceId;
64    type WeakDeviceId = CC::WeakDeviceId;
65}
66
67impl<BC: BindingsContext, L> EthernetIpLinkDeviceStaticStateContext for CoreCtx<'_, BC, L> {
68    fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
69        &mut self,
70        device_id: &EthernetDeviceId<BC>,
71        cb: F,
72    ) -> O {
73        let state = integration::device_state(self, device_id);
74        cb(&state.unlocked_access::<crate::lock_ordering::UnlockedState>().link.static_state)
75    }
76}
77
78impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>>
79    EthernetIpLinkDeviceDynamicStateContext<BC> for CoreCtx<'_, BC, L>
80{
81    fn with_ethernet_state<
82        O,
83        F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
84    >(
85        &mut self,
86        device_id: &EthernetDeviceId<BC>,
87        cb: F,
88    ) -> O {
89        let mut state = integration::device_state(self, device_id);
90        let (dynamic_state, locked) =
91            state.read_lock_and::<crate::lock_ordering::EthernetDeviceDynamicState>();
92        cb(
93            &locked.unlocked_access::<crate::lock_ordering::UnlockedState>().link.static_state,
94            &dynamic_state,
95        )
96    }
97
98    fn with_ethernet_state_mut<
99        O,
100        F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
101    >(
102        &mut self,
103        device_id: &EthernetDeviceId<BC>,
104        cb: F,
105    ) -> O {
106        let mut state = integration::device_state(self, device_id);
107        let (mut dynamic_state, locked) =
108            state.write_lock_and::<crate::lock_ordering::EthernetDeviceDynamicState>();
109        cb(
110            &locked.unlocked_access::<crate::lock_ordering::UnlockedState>().link.static_state,
111            &mut dynamic_state,
112        )
113    }
114}
115
116impl<BT: BindingsTypes, L> CoreTimerContext<EthernetTimerId<EthernetWeakDeviceId<BT>>, BT>
117    for CoreCtx<'_, BT, L>
118{
119    fn convert_timer(dispatch_id: EthernetTimerId<EthernetWeakDeviceId<BT>>) -> BT::DispatchId {
120        DeviceLayerTimerId::from(dispatch_id).into()
121    }
122}
123
124impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::FilterState<Ipv6>>>
125    NudContext<Ipv6, EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
126{
127    type ConfigCtx<'a> = CoreCtxWithDeviceId<
128        'a,
129        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv6Nud>>,
130    >;
131
132    type SenderCtx<'a> = CoreCtxWithDeviceId<
133        'a,
134        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv6Nud>>,
135    >;
136
137    fn with_nud_state_mut_and_sender_ctx<
138        O,
139        F: FnOnce(&mut NudState<Ipv6, EthernetLinkDevice, BC>, &mut Self::SenderCtx<'_>) -> O,
140    >(
141        &mut self,
142        device_id: &EthernetDeviceId<BC>,
143        cb: F,
144    ) -> O {
145        let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
146        let (mut nud, mut locked) = core_ctx_and_resource
147            .lock_with_and::<crate::lock_ordering::EthernetIpv6Nud, _>(|c| c.right());
148        let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
149        cb(&mut nud, &mut locked)
150    }
151
152    fn with_nud_state_mut<
153        O,
154        F: FnOnce(&mut NudState<Ipv6, EthernetLinkDevice, BC>, &mut Self::ConfigCtx<'_>) -> O,
155    >(
156        &mut self,
157        device_id: &EthernetDeviceId<BC>,
158        cb: F,
159    ) -> O {
160        let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
161        let (mut nud, mut locked) = core_ctx_and_resource
162            .lock_with_and::<crate::lock_ordering::EthernetIpv6Nud, _>(|c| c.right());
163        let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
164        cb(&mut nud, &mut locked)
165    }
166
167    fn with_nud_state<O, F: FnOnce(&NudState<Ipv6, EthernetLinkDevice, BC>) -> O>(
168        &mut self,
169        device_id: &EthernetDeviceId<BC>,
170        cb: F,
171    ) -> O {
172        let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
173        let nud = core_ctx_and_resource
174            .lock_with::<crate::lock_ordering::EthernetIpv6Nud, _>(|c| c.right());
175        cb(&nud)
176    }
177
178    fn send_neighbor_solicitation(
179        &mut self,
180        bindings_ctx: &mut BC,
181        device_id: &EthernetDeviceId<BC>,
182        lookup_addr: SpecifiedAddr<Ipv6Addr>,
183        remote_link_addr: Option<Mac>,
184    ) {
185        let dst_ip = match remote_link_addr {
186            // TODO(https://fxbug.dev/42081683): once `send_ndp_packet` does not go through
187            // the normal IP egress flow, using the NUD table to resolve the link address,
188            // use the specified link address to determine where to unicast the
189            // solicitation.
190            Some(_) => lookup_addr,
191            None => lookup_addr.to_solicited_node_address().into_specified(),
192        };
193        let src_ip = IpDeviceEgressStateContext::<Ipv6>::get_local_addr_for_remote(
194            self,
195            &device_id.clone().into(),
196            Some(dst_ip),
197        );
198        let src_ip = match src_ip {
199            Some(s) => s,
200            None => return,
201        };
202
203        let mac = ethernet::get_mac(self, device_id);
204
205        CounterContext::<NdpCounters>::counters(self).tx.neighbor_solicitation.increment();
206        debug!("sending NDP solicitation for {lookup_addr} to {dst_ip}");
207        // TODO(https://fxbug.dev/42165912): Either panic or guarantee that this error
208        // can't happen statically.
209        let _: Result<(), _> = icmp::send_ndp_packet(
210            self,
211            bindings_ctx,
212            &device_id.clone().into(),
213            Some(src_ip.into()),
214            dst_ip,
215            OptionSequenceBuilder::<_>::new(
216                [NdpOptionBuilder::SourceLinkLayerAddress(mac.bytes().as_ref())].iter(),
217            )
218            .into_serializer(),
219            icmp::NdpMessage::NeighborSolicitation {
220                message: NeighborSolicitation::new(lookup_addr.get()),
221                code: IcmpZeroCode,
222            },
223        );
224    }
225}
226
227impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv6>>>
228    NudIcmpContext<Ipv6, EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
229{
230    fn send_icmp_dest_unreachable(
231        &mut self,
232        bindings_ctx: &mut BC,
233        frame: Buf<Vec<u8>>,
234        device_id: Option<&Self::DeviceId>,
235        original_src_ip: SocketIpAddr<Ipv6Addr>,
236        original_dst_ip: SocketIpAddr<Ipv6Addr>,
237        header_len: usize,
238        proto: Ipv6Proto,
239        _metadata: (),
240    ) {
241        <Self as IcmpErrorHandler<Ipv6, BC>>::send_icmp_error_message(
242            self,
243            bindings_ctx,
244            device_id.map(|device_id| device_id.clone().into()).as_ref(), // This is Option<&CC::DeviceId>
245            // NB: link layer address resolution only happens for packets destined for
246            // a unicast address, so passing `None` as `FrameDestination` here is always
247            // correct since there's never a need to not send the ICMP error due to
248            // a multicast/broadcast destination.
249            None,
250            original_src_ip,
251            original_dst_ip,
252            frame,
253            Icmpv6Error::AddressUnreachable,
254            header_len,
255            proto,
256            // TODO(https://fxbug.dev/400977853): The pending frame this ICMP message is
257            // responding to can either be generated from ourselves or being forwarded.
258            // In the former case, the marks are irrelevant because this message will end
259            // up being delivered locally. For the later case, we need to make sure the
260            // marks are stored with the pending frames.
261            &Marks::default(),
262        );
263    }
264}
265
266impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::Ipv6DeviceLearnedParams>>
267    NudConfigContext<Ipv6> for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
268{
269    fn retransmit_timeout(&mut self) -> NonZeroDuration {
270        let Self { device_id, core_ctx } = self;
271        let mut state = integration::device_state(core_ctx, device_id);
272        let mut state = state.cast();
273        // NB: This assignment is satisfying borrow checking on state.
274        let x = state.read_lock::<crate::lock_ordering::Ipv6DeviceLearnedParams>().retrans_timer();
275        x.unwrap_or_else(|| {
276            NudConfigContext::<Ipv6>::with_nud_user_config(self, |c| c.retrans_timer)
277        })
278    }
279
280    fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
281        let Self { device_id, core_ctx } = self;
282        let mut state = integration::device_state(core_ctx, device_id);
283        let x = state.read_lock::<crate::lock_ordering::NudConfig<Ipv6>>();
284        cb(&*x)
285    }
286
287    fn override_lock_time(&mut self) -> Duration {
288        Duration::ZERO
289    }
290}
291
292impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::AllDeviceSockets>>
293    NudSenderContext<Ipv6, EthernetLinkDevice, BC> for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
294{
295    fn send_ip_packet_to_neighbor_link_addr<S>(
296        &mut self,
297        bindings_ctx: &mut BC,
298        dst_mac: Mac,
299        body: S,
300        meta: BC::TxMetadata,
301    ) -> Result<(), SendFrameError<S>>
302    where
303        S: Serializer,
304        S::Buffer: BufferMut,
305    {
306        let Self { device_id, core_ctx } = self;
307        ethernet::send_as_ethernet_frame_to_dst(
308            *core_ctx,
309            bindings_ctx,
310            device_id,
311            dst_mac,
312            body,
313            EtherType::Ipv6,
314            meta,
315        )
316    }
317}
318
319impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv4>>>
320    ArpContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
321{
322    type ConfigCtx<'a> = CoreCtxWithDeviceId<
323        'a,
324        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv4Arp>>,
325    >;
326
327    type ArpSenderCtx<'a> = CoreCtxWithDeviceId<
328        'a,
329        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv4Arp>>,
330    >;
331
332    fn with_arp_state_mut_and_sender_ctx<
333        O,
334        F: FnOnce(&mut ArpState<EthernetLinkDevice, BC>, &mut Self::ArpSenderCtx<'_>) -> O,
335    >(
336        &mut self,
337        device_id: &EthernetDeviceId<BC>,
338        cb: F,
339    ) -> O {
340        let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
341        let (mut arp, mut locked) = core_ctx_and_resource
342            .lock_with_and::<crate::lock_ordering::EthernetIpv4Arp, _>(|c| c.right());
343        let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
344        cb(&mut arp, &mut locked)
345    }
346
347    fn get_protocol_addr(&mut self, device_id: &EthernetDeviceId<BC>) -> Option<Ipv4Addr> {
348        let mut state = integration::device_state(self, device_id);
349        let mut state = state.cast();
350        let ipv4 = state.read_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>();
351        // NB: This assignment is satisfying borrow checking on state.
352        let x = ipv4.iter().next().map(|addr| addr.addr().get());
353        x
354    }
355
356    fn get_hardware_addr(
357        &mut self,
358        _bindings_ctx: &mut BC,
359        device_id: &EthernetDeviceId<BC>,
360    ) -> UnicastAddr<Mac> {
361        ethernet::get_mac(self, device_id)
362    }
363
364    fn with_arp_state_mut<
365        O,
366        F: FnOnce(&mut ArpState<EthernetLinkDevice, BC>, &mut Self::ConfigCtx<'_>) -> O,
367    >(
368        &mut self,
369        device_id: &EthernetDeviceId<BC>,
370        cb: F,
371    ) -> O {
372        let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
373        let (mut arp, mut locked) = core_ctx_and_resource
374            .lock_with_and::<crate::lock_ordering::EthernetIpv4Arp, _>(|c| c.right());
375        let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
376        cb(&mut arp, &mut locked)
377    }
378
379    fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, BC>) -> O>(
380        &mut self,
381        device_id: &EthernetDeviceId<BC>,
382        cb: F,
383    ) -> O {
384        let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
385        let arp = core_ctx_and_resource
386            .lock_with::<crate::lock_ordering::EthernetIpv4Arp, _>(|c| c.right());
387        cb(&arp)
388    }
389}
390
391impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>>
392    ArpIpLayerContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
393{
394    fn on_arp_packet(
395        &mut self,
396        bindings_ctx: &mut BC,
397        device_id: &EthernetDeviceId<BC>,
398        frame_src: Mac,
399        sender_hwaddr: Mac,
400        sender_addr: Ipv4Addr,
401        target_addr: Ipv4Addr,
402        is_arp_probe: bool,
403    ) -> bool {
404        let device_id = DeviceId::Ethernet(device_id.clone());
405        netstack3_ip::device::on_arp_packet(
406            self,
407            bindings_ctx,
408            &device_id,
409            frame_src,
410            sender_hwaddr,
411            sender_addr,
412            target_addr,
413            is_arp_probe,
414        )
415    }
416}
417
418impl<BT: BindingsTypes, L> UseDelegateNudContext for CoreCtx<'_, BT, L> {}
419impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv4>>>
420    DelegateNudContext<Ipv4> for CoreCtx<'_, BC, L>
421{
422    type Delegate<T> = ArpNudCtx<T>;
423}
424
425impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv4>>>
426    NudIcmpContext<Ipv4, EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
427{
428    fn send_icmp_dest_unreachable(
429        &mut self,
430        bindings_ctx: &mut BC,
431        frame: Buf<Vec<u8>>,
432        device_id: Option<&Self::DeviceId>,
433        original_src_ip: SocketIpAddr<Ipv4Addr>,
434        original_dst_ip: SocketIpAddr<Ipv4Addr>,
435        header_len: usize,
436        proto: Ipv4Proto,
437        fragment_type: Ipv4FragmentType,
438    ) {
439        if fragment_type != Ipv4FragmentType::InitialFragment {
440            return;
441        }
442
443        <Self as IcmpErrorHandler<Ipv4, BC>>::send_icmp_error_message(
444            self,
445            bindings_ctx,
446            device_id.map(|device_id| device_id.clone().into()).as_ref(), // This is Option<&CC::DeviceId>
447            // NB: link layer address resolution only happens for packets destined for
448            // a unicast address, so passing `None` as `FrameDestination` here is always
449            // correct since there's never a need to not send the ICMP error due to
450            // a multicast/broadcast destination.
451            None,
452            original_src_ip,
453            original_dst_ip,
454            frame,
455            Icmpv4Error::HostUnreachable,
456            header_len,
457            proto,
458            // TODO(https://fxbug.dev/400977853): The pending frame this ICMP message is
459            // responding to can either be generated from ourselves or being forwarded.
460            // In the former case, the marks are irrelevant because this message will end
461            // up being delivered locally. For the later case, we need to make sure the
462            // marks are stored with the pending frames.
463            &Marks::default(),
464        );
465    }
466}
467
468impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::NudConfig<Ipv4>>> ArpConfigContext
469    for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
470{
471    fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
472        let Self { device_id, core_ctx } = self;
473        let mut state = integration::device_state(core_ctx, device_id);
474        let x = state.read_lock::<crate::lock_ordering::NudConfig<Ipv4>>();
475        cb(&*x)
476    }
477}
478
479impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::AllDeviceSockets>>
480    ArpSenderContext<EthernetLinkDevice, BC> for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
481{
482    fn send_ip_packet_to_neighbor_link_addr<S>(
483        &mut self,
484        bindings_ctx: &mut BC,
485        dst_mac: Mac,
486        body: S,
487        meta: BC::TxMetadata,
488    ) -> Result<(), SendFrameError<S>>
489    where
490        S: Serializer,
491        S::Buffer: BufferMut,
492    {
493        let Self { device_id, core_ctx } = self;
494        ethernet::send_as_ethernet_frame_to_dst(
495            *core_ctx,
496            bindings_ctx,
497            device_id,
498            dst_mac,
499            body,
500            EtherType::Ipv4,
501            meta,
502        )
503    }
504}
505
506impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetTxQueue>>
507    TransmitQueueCommon<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
508{
509    type Meta = BC::TxMetadata;
510    type Allocator = BufVecU8Allocator;
511    type Buffer = Buf<Vec<u8>>;
512    type DequeueContext = BC::DequeueContext;
513
514    fn parse_outgoing_frame<'a, 'b>(
515        buf: &'a [u8],
516        _meta: &'b Self::Meta,
517    ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
518        SentFrame::try_parse_as_ethernet(buf)
519    }
520}
521
522impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetTxQueue>>
523    TransmitQueueContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
524{
525    fn with_transmit_queue_mut<
526        O,
527        F: FnOnce(&mut TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
528    >(
529        &mut self,
530        device_id: &EthernetDeviceId<BC>,
531        cb: F,
532    ) -> O {
533        let mut state = integration::device_state(self, device_id);
534        let mut x = state.lock::<crate::lock_ordering::EthernetTxQueue>();
535        cb(&mut x)
536    }
537
538    fn with_transmit_queue<
539        O,
540        F: FnOnce(&TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
541    >(
542        &mut self,
543        device_id: &EthernetDeviceId<BC>,
544        cb: F,
545    ) -> O {
546        let mut state = integration::device_state(self, device_id);
547        let x = state.lock::<crate::lock_ordering::EthernetTxQueue>();
548        cb(&x)
549    }
550
551    fn send_frame(
552        &mut self,
553        bindings_ctx: &mut BC,
554        device_id: &Self::DeviceId,
555        dequeue_context: Option<&mut BC::DequeueContext>,
556        _meta: Self::Meta,
557        buf: Self::Buffer,
558    ) -> Result<(), DeviceSendFrameError> {
559        DeviceLayerEventDispatcher::send_ethernet_frame(
560            bindings_ctx,
561            device_id,
562            buf,
563            dequeue_context,
564        )
565    }
566}
567
568impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetTxDequeue>>
569    TransmitDequeueContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
570{
571    type TransmitQueueCtx<'a> =
572        CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetTxDequeue>>;
573
574    fn with_dequed_packets_and_tx_queue_ctx<
575        O,
576        F: FnOnce(&mut DequeueState<Self::Meta, Self::Buffer>, &mut Self::TransmitQueueCtx<'_>) -> O,
577    >(
578        &mut self,
579        device_id: &Self::DeviceId,
580        cb: F,
581    ) -> O {
582        let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
583        let (mut x, mut locked) = core_ctx_and_resource
584            .lock_with_and::<crate::lock_ordering::EthernetTxDequeue, _>(|c| c.right());
585        cb(&mut x, &mut locked.cast_core_ctx())
586    }
587}
588
589impl<I: Ip, BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
590    for crate::lock_ordering::NudConfig<I>
591{
592    type Data = IpMarked<I, NudUserConfig>;
593}
594
595impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
596    for crate::lock_ordering::EthernetDeviceDynamicState
597{
598    type Data = DynamicEthernetDeviceState;
599}
600
601impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
602    for crate::lock_ordering::EthernetIpv6Nud
603{
604    type Data = NudState<Ipv6, EthernetLinkDevice, BT>;
605}
606
607impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
608    for crate::lock_ordering::EthernetIpv4Arp
609{
610    type Data = ArpState<EthernetLinkDevice, BT>;
611}
612
613impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
614    for crate::lock_ordering::EthernetTxQueue
615{
616    type Data = TransmitQueueState<BT::TxMetadata, Buf<Vec<u8>>, BufVecU8Allocator>;
617}
618
619impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
620    for crate::lock_ordering::EthernetTxDequeue
621{
622    type Data = DequeueState<BT::TxMetadata, Buf<Vec<u8>>>;
623}