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