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