1use 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 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 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(), None,
250 original_src_ip,
251 original_dst_ip,
252 frame,
253 Icmpv6Error::AddressUnreachable,
254 header_len,
255 proto,
256 &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 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 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(), None,
452 original_src_ip,
453 original_dst_ip,
454 frame,
455 Icmpv4Error::HostUnreachable,
456 header_len,
457 proto,
458 &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}