1use core::fmt::Debug;
8use core::num::NonZeroU32;
9use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
10
11use log::{debug, trace};
12use net_types::ethernet::Mac;
13use net_types::ip::{GenericOverIp, Ip, IpMarked, Ipv4, Ipv6, Mtu};
14use net_types::{MulticastAddr, UnicastAddr, Witness};
15use netstack3_base::ref_counted_hash_map::{InsertResult, RefCountedHashSet, RemoveResult};
16use netstack3_base::sync::{Mutex, RwLock};
17use netstack3_base::{
18 BroadcastIpExt, ChecksumOffloadSpec, CoreTimerContext, Device, DeviceIdContext, EventContext,
19 FrameDestination, HandleableTimer, LinkDevice, NestedIntoCoreTimerCtx, NetworkParsingContext,
20 NetworkSerializer, ReceivableFrameMeta, RecvFrameContext, RecvIpFrameMeta,
21 ResourceCounterContext, RngContext, SendFrameError, SendFrameErrorReason, SendableFrameMeta,
22 TimerContext, TimerHandler, TxMetadataBindingsTypes, WeakDeviceIdentifier, WrapBroadcastMarker,
23};
24use netstack3_ip::nud::{LinkResolutionContext, NudHandler, NudState, NudTimerId, NudUserConfig};
25use netstack3_ip::{DeviceIpLayerMetadata, IpPacketDestination};
26use netstack3_trace::trace_duration;
27use packet::{BufferMut, NestablePacketBuilder as _, NestableSerializer as _};
28use packet_formats::arp::{ArpHardwareType, ArpNetworkType, peek_arp_types};
29use packet_formats::ethernet::{
30 ETHERNET_HDR_LEN_NO_TAG, EtherType, EthernetFrame, EthernetFrameBuilder,
31 EthernetFrameLengthCheck, EthernetIpExt,
32};
33
34use crate::internal::arp::{ArpFrameMetadata, ArpPacketHandler, ArpState, ArpTimerId};
35use crate::internal::base::{
36 DeviceBufferBindingsTypes, DeviceCounters, DeviceLayerTypes, DeviceReceiveFrameSpec,
37 EthernetDeviceCounters,
38};
39use crate::internal::id::{DeviceId, EthernetDeviceId};
40use crate::internal::queue::tx::{TransmitQueue, TransmitQueueHandler, TransmitQueueState};
41use crate::internal::queue::{DequeueState, DeviceBufferSpec, TransmitQueueFrameError};
42use crate::internal::socket::{
43 DeviceSocketHandler, DeviceSocketMetadata, DeviceSocketSendTypes, EthernetHeaderParams,
44 ReceivedFrame,
45};
46use crate::internal::state::{DeviceStateSpec, IpLinkDeviceState};
47
48const ETHERNET_HDR_LEN_NO_TAG_U32: u32 = ETHERNET_HDR_LEN_NO_TAG as u32;
49
50pub trait EthernetIpLinkDeviceBindingsContext:
52 RngContext + TimerContext + DeviceLayerTypes + TxMetadataBindingsTypes
53{
54}
55impl<BC: RngContext + TimerContext + DeviceLayerTypes + TxMetadataBindingsTypes>
56 EthernetIpLinkDeviceBindingsContext for BC
57{
58}
59
60pub trait EthernetDeviceEventBindingsContext<DeviceId>:
65 EventContext<EthernetDeviceEvent<DeviceId>>
66{
67}
68impl<BC: EventContext<EthernetDeviceEvent<DeviceId>>, DeviceId>
69 EthernetDeviceEventBindingsContext<DeviceId> for BC
70{
71}
72
73pub trait EthernetIpLinkDeviceStaticStateContext: DeviceIdContext<EthernetLinkDevice> {
75 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
78 &mut self,
79 device_id: &Self::DeviceId,
80 cb: F,
81 ) -> O;
82}
83
84pub trait EthernetIpLinkDeviceDynamicStateContext<BC: EthernetIpLinkDeviceBindingsContext>:
86 EthernetIpLinkDeviceStaticStateContext
87{
88 fn with_ethernet_state<
91 O,
92 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
93 >(
94 &mut self,
95 device_id: &Self::DeviceId,
96 cb: F,
97 ) -> O;
98
99 fn with_ethernet_state_mut<
102 O,
103 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
104 >(
105 &mut self,
106 device_id: &Self::DeviceId,
107 cb: F,
108 ) -> O;
109}
110
111#[derive(Debug, PartialEq, Eq, Hash)]
113pub enum EthernetDeviceEvent<D> {
114 MulticastJoin {
116 device: D,
118 addr: MulticastAddr<Mac>,
120 },
121
122 MulticastLeave {
124 device: D,
126 addr: MulticastAddr<Mac>,
128 },
129}
130
131impl<D> EthernetDeviceEvent<D> {
132 pub fn map_device<N, F: FnOnce(D) -> N>(self, map: F) -> EthernetDeviceEvent<N> {
134 match self {
135 Self::MulticastJoin { device, addr } => {
136 EthernetDeviceEvent::MulticastJoin { device: map(device), addr }
137 }
138 Self::MulticastLeave { device, addr } => {
139 EthernetDeviceEvent::MulticastLeave { device: map(device), addr }
140 }
141 }
142 }
143}
144
145pub fn send_as_ethernet_frame_to_dst<S, BC, CC>(
147 core_ctx: &mut CC,
148 bindings_ctx: &mut BC,
149 device_id: &CC::DeviceId,
150 dst_mac: Mac,
151 body: S,
152 ether_type: EtherType,
153 meta: BC::TxMetadata,
154) -> Result<(), SendFrameError<S>>
155where
156 S: NetworkSerializer,
157 S::Buffer: BufferMut,
158 BC: EthernetIpLinkDeviceBindingsContext,
159 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
160 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
161 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
162{
163 const MIN_BODY_LEN: usize = 0;
169
170 let local_mac = get_mac(core_ctx, device_id);
171 let max_frame_size = get_max_frame_size(core_ctx, device_id);
172 let frame = EthernetFrameBuilder::new(local_mac.get(), dst_mac, ether_type, MIN_BODY_LEN)
173 .wrap_body(body)
174 .with_size_limit(max_frame_size.into());
175 send_ethernet_frame(core_ctx, bindings_ctx, device_id, frame, meta)
176 .map_err(|err| err.into_inner().into_inner())
177}
178
179fn send_ethernet_frame<S, BC, CC>(
180 core_ctx: &mut CC,
181 bindings_ctx: &mut BC,
182 device_id: &CC::DeviceId,
183 frame: S,
184 meta: BC::TxMetadata,
185) -> Result<(), SendFrameError<S>>
186where
187 S: NetworkSerializer,
188 S::Buffer: BufferMut,
189 BC: EthernetIpLinkDeviceBindingsContext,
190 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
191 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
192 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
193{
194 core_ctx.increment_both(device_id, |counters| &counters.send_total_frames);
195 match TransmitQueueHandler::<EthernetLinkDevice, _>::queue_tx_frame(
196 core_ctx,
197 bindings_ctx,
198 device_id,
199 meta,
200 frame,
201 ) {
202 Ok(len) => {
203 core_ctx.add_both_usize(device_id, len, |counters| &counters.send_bytes);
204 core_ctx.increment_both(device_id, |counters| &counters.send_frame);
205 Ok(())
206 }
207 Err(TransmitQueueFrameError::NoQueue(err)) => {
208 core_ctx.increment_both(device_id, |counters| &counters.send_dropped_no_queue);
209 debug!("device {device_id:?} failed to send frame: {err:?}.");
210 Ok(())
211 }
212 Err(TransmitQueueFrameError::QueueFull(serializer)) => {
213 core_ctx.increment_both(device_id, |counters| &counters.send_queue_full);
214 Err(SendFrameError { serializer, error: SendFrameErrorReason::QueueFull })
215 }
216 Err(TransmitQueueFrameError::SerializeError(err)) => {
217 core_ctx.increment_both(device_id, |counters| &counters.send_serialize_error);
218 Err(err.err_into())
219 }
220 }
221}
222
223#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
229pub struct MaxEthernetFrameSize(NonZeroU32);
230
231impl MaxEthernetFrameSize {
232 pub const MIN: MaxEthernetFrameSize = MaxEthernetFrameSize(NonZeroU32::new(60).unwrap());
236
237 pub const fn new(frame_size: u32) -> Option<Self> {
240 if frame_size < Self::MIN.get().get() {
241 return None;
242 }
243 Some(Self(NonZeroU32::new(frame_size).unwrap()))
244 }
245
246 const fn get(&self) -> NonZeroU32 {
247 let Self(frame_size) = *self;
248 frame_size
249 }
250
251 pub const fn as_mtu(&self) -> Mtu {
253 Mtu::new(self.get().get().saturating_sub(ETHERNET_HDR_LEN_NO_TAG_U32))
255 }
256
257 pub const fn from_mtu(mtu: Mtu) -> Option<MaxEthernetFrameSize> {
259 let frame_size = mtu.get().saturating_add(ETHERNET_HDR_LEN_NO_TAG_U32);
260 Self::new(frame_size)
261 }
262}
263
264impl From<MaxEthernetFrameSize> for usize {
265 fn from(MaxEthernetFrameSize(v): MaxEthernetFrameSize) -> Self {
266 v.get().try_into().expect("u32 doesn't fit in usize")
267 }
268}
269
270#[derive(Debug)]
272pub struct EthernetCreationProperties {
273 pub mac: UnicastAddr<Mac>,
275 pub max_frame_size: MaxEthernetFrameSize,
286 pub tx_offload_spec: netstack3_base::ChecksumOffloadSpec,
288}
289
290pub struct DynamicEthernetDeviceState {
292 max_frame_size: MaxEthernetFrameSize,
294
295 link_multicast_groups: RefCountedHashSet<MulticastAddr<Mac>>,
297}
298
299impl DynamicEthernetDeviceState {
300 fn new(max_frame_size: MaxEthernetFrameSize) -> Self {
301 Self { max_frame_size, link_multicast_groups: Default::default() }
302 }
303}
304
305pub struct StaticEthernetDeviceState {
307 mac: UnicastAddr<Mac>,
309
310 max_frame_size: MaxEthernetFrameSize,
312}
313
314pub struct EthernetDeviceState<BT: DeviceLayerTypes> {
316 pub counters: EthernetDeviceCounters,
318 pub static_state: StaticEthernetDeviceState,
320 pub tx_queue: TransmitQueue<
322 BT::TxMetadata,
323 <EthernetLinkDevice as DeviceBufferSpec<BT>>::TxBuffer,
324 <EthernetLinkDevice as DeviceBufferSpec<BT>>::TxAllocator,
325 >,
326 ipv4_arp: Mutex<ArpState<EthernetLinkDevice, BT>>,
327 ipv6_nud: Mutex<NudState<Ipv6, EthernetLinkDevice, BT>>,
328 ipv4_nud_config: RwLock<IpMarked<Ipv4, NudUserConfig>>,
329 ipv6_nud_config: RwLock<IpMarked<Ipv6, NudUserConfig>>,
330 dynamic_state: RwLock<DynamicEthernetDeviceState>,
331}
332
333impl<BT: DeviceLayerTypes, I: Ip> OrderedLockAccess<IpMarked<I, NudUserConfig>>
334 for IpLinkDeviceState<EthernetLinkDevice, BT>
335{
336 type Lock = RwLock<IpMarked<I, NudUserConfig>>;
337 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
338 OrderedLockRef::new(I::map_ip(
339 (),
340 |()| &self.link.ipv4_nud_config,
341 |()| &self.link.ipv6_nud_config,
342 ))
343 }
344}
345
346impl<BT: DeviceLayerTypes> OrderedLockAccess<DynamicEthernetDeviceState>
347 for IpLinkDeviceState<EthernetLinkDevice, BT>
348{
349 type Lock = RwLock<DynamicEthernetDeviceState>;
350 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
351 OrderedLockRef::new(&self.link.dynamic_state)
352 }
353}
354
355impl<BT: DeviceLayerTypes> OrderedLockAccess<NudState<Ipv6, EthernetLinkDevice, BT>>
356 for IpLinkDeviceState<EthernetLinkDevice, BT>
357{
358 type Lock = Mutex<NudState<Ipv6, EthernetLinkDevice, BT>>;
359 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
360 OrderedLockRef::new(&self.link.ipv6_nud)
361 }
362}
363
364impl<BT: DeviceLayerTypes> OrderedLockAccess<ArpState<EthernetLinkDevice, BT>>
365 for IpLinkDeviceState<EthernetLinkDevice, BT>
366{
367 type Lock = Mutex<ArpState<EthernetLinkDevice, BT>>;
368 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
369 OrderedLockRef::new(&self.link.ipv4_arp)
370 }
371}
372
373impl<BT: DeviceLayerTypes>
374 OrderedLockAccess<TransmitQueueState<BT::TxMetadata, BT::TxBuffer, BT::TxAllocator>>
375 for IpLinkDeviceState<EthernetLinkDevice, BT>
376{
377 type Lock = Mutex<TransmitQueueState<BT::TxMetadata, BT::TxBuffer, BT::TxAllocator>>;
378 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
379 OrderedLockRef::new(&self.link.tx_queue.queue)
380 }
381}
382
383impl<BT: DeviceLayerTypes> OrderedLockAccess<DequeueState<BT::TxMetadata, BT::TxBuffer>>
384 for IpLinkDeviceState<EthernetLinkDevice, BT>
385{
386 type Lock = Mutex<DequeueState<BT::TxMetadata, BT::TxBuffer>>;
387 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
388 OrderedLockRef::new(&self.link.tx_queue.deque)
389 }
390}
391
392#[derive(Clone, Eq, PartialEq, Debug, Hash, GenericOverIp)]
396#[generic_over_ip()]
397#[allow(missing_docs)]
398pub enum EthernetTimerId<D: WeakDeviceIdentifier> {
399 Arp(ArpTimerId<EthernetLinkDevice, D>),
400 Nudv6(NudTimerId<Ipv6, EthernetLinkDevice, D>),
401}
402
403impl<I: Ip, D: WeakDeviceIdentifier> From<NudTimerId<I, EthernetLinkDevice, D>>
404 for EthernetTimerId<D>
405{
406 fn from(id: NudTimerId<I, EthernetLinkDevice, D>) -> EthernetTimerId<D> {
407 I::map_ip(id, EthernetTimerId::Arp, EthernetTimerId::Nudv6)
408 }
409}
410
411impl<CC, BC> HandleableTimer<CC, BC> for EthernetTimerId<CC::WeakDeviceId>
412where
413 BC: EthernetIpLinkDeviceBindingsContext,
414 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
415 + TimerHandler<BC, NudTimerId<Ipv6, EthernetLinkDevice, CC::WeakDeviceId>>
416 + TimerHandler<BC, ArpTimerId<EthernetLinkDevice, CC::WeakDeviceId>>,
417{
418 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
419 match self {
420 EthernetTimerId::Arp(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
421 EthernetTimerId::Nudv6(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
422 }
423 }
424}
425
426pub fn send_ip_frame<BC, CC, I, S>(
433 core_ctx: &mut CC,
434 bindings_ctx: &mut BC,
435 device_id: &CC::DeviceId,
436 destination: IpPacketDestination<I, &DeviceId<BC>>,
437 body: S,
438 meta: BC::TxMetadata,
439) -> Result<(), SendFrameError<S>>
440where
441 BC: EthernetIpLinkDeviceBindingsContext + LinkResolutionContext<EthernetLinkDevice>,
442 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
443 + NudHandler<I, EthernetLinkDevice, BC>
444 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
445 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
446 I: EthernetIpExt + BroadcastIpExt,
447 S: NetworkSerializer,
448 S::Buffer: BufferMut,
449{
450 core_ctx.increment_both(device_id, DeviceCounters::send_frame::<I>);
451
452 trace!("ethernet::send_ip_frame: destination = {:?}; device = {:?}", destination, device_id);
453
454 match destination {
455 IpPacketDestination::Broadcast(marker) => {
456 I::map_ip::<_, ()>(
457 WrapBroadcastMarker(marker),
458 |WrapBroadcastMarker(())| (),
459 |WrapBroadcastMarker(never)| match never {},
460 );
461 send_as_ethernet_frame_to_dst(
462 core_ctx,
463 bindings_ctx,
464 device_id,
465 Mac::BROADCAST,
466 body,
467 I::ETHER_TYPE,
468 meta,
469 )
470 }
471 IpPacketDestination::Multicast(multicast_ip) => send_as_ethernet_frame_to_dst(
472 core_ctx,
473 bindings_ctx,
474 device_id,
475 Mac::from(&multicast_ip),
476 body,
477 I::ETHER_TYPE,
478 meta,
479 ),
480 IpPacketDestination::Neighbor(ip) => NudHandler::<I, _, _>::send_ip_packet_to_neighbor(
481 core_ctx,
482 bindings_ctx,
483 device_id,
484 ip,
485 body,
486 meta,
487 ),
488 IpPacketDestination::Loopback(_) => {
489 unreachable!("Loopback packets must be delivered through the loopback device")
490 }
491 }
492}
493
494pub struct RecvEthernetFrameMeta<D> {
496 pub device_id: D,
498 pub parsing_context: NetworkParsingContext,
500}
501
502impl DeviceReceiveFrameSpec for EthernetLinkDevice {
503 type FrameMetadata<D> = RecvEthernetFrameMeta<D>;
504}
505
506impl<CC, BC> ReceivableFrameMeta<CC, BC> for RecvEthernetFrameMeta<CC::DeviceId>
507where
508 BC: EthernetIpLinkDeviceBindingsContext,
509 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
510 + RecvFrameContext<RecvIpFrameMeta<CC::DeviceId, DeviceIpLayerMetadata<BC>, Ipv4>, BC>
511 + RecvFrameContext<RecvIpFrameMeta<CC::DeviceId, DeviceIpLayerMetadata<BC>, Ipv6>, BC>
512 + ArpPacketHandler<EthernetLinkDevice, BC>
513 + DeviceSocketHandler<EthernetLinkDevice, BC>
514 + ResourceCounterContext<CC::DeviceId, DeviceCounters>
515 + ResourceCounterContext<CC::DeviceId, EthernetDeviceCounters>,
516{
517 fn receive_meta<B: BufferMut + Debug>(
518 self,
519 core_ctx: &mut CC,
520 bindings_ctx: &mut BC,
521 mut buffer: B,
522 ) {
523 trace_duration!("device::ethernet::receive_frame");
524 let Self { device_id, parsing_context } = self;
525 trace!("ethernet::receive_frame: device_id = {:?}", device_id);
526 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| &counters.recv_frame);
527 core_ctx.add_both_usize(&device_id, buffer.len(), |counters: &DeviceCounters| {
528 &counters.recv_bytes
529 });
530 let (ethernet, whole_frame) = if let Ok(frame) =
539 buffer.parse_with_view::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck)
540 {
541 frame
542 } else {
543 core_ctx
544 .increment_both(&device_id, |counters: &DeviceCounters| &counters.recv_parse_error);
545 trace!("ethernet::receive_frame: failed to parse ethernet frame");
546 return;
547 };
548
549 let src = ethernet.src_mac();
550 let dst = ethernet.dst_mac();
551
552 let frame_dst = core_ctx.with_static_ethernet_device_state(&device_id, |static_state| {
553 FrameDestination::from_dest(dst, static_state.mac.get())
554 });
555
556 let ethertype = ethernet.ethertype();
557
558 core_ctx.handle_frame(
559 bindings_ctx,
560 &device_id,
561 ReceivedFrame::from_ethernet(ethernet, frame_dst).into(),
562 whole_frame,
563 );
564
565 match ethertype {
566 Some(EtherType::Arp) => {
567 let types = if let Ok(types) = peek_arp_types(buffer.as_ref()) {
568 types
569 } else {
570 return;
571 };
572 match types {
573 (ArpHardwareType::Ethernet, ArpNetworkType::Ipv4) => {
574 ArpPacketHandler::handle_packet(
575 core_ctx,
576 bindings_ctx,
577 device_id,
578 src,
579 frame_dst,
580 buffer,
581 )
582 }
583 }
584 }
585 Some(EtherType::Ipv4) => {
586 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
587 &counters.recv_ipv4_delivered
588 });
589 core_ctx.receive_frame(
590 bindings_ctx,
591 RecvIpFrameMeta::<_, _, Ipv4>::new(
592 device_id,
593 Some(frame_dst),
594 DeviceIpLayerMetadata::default(),
595 parsing_context,
596 ),
597 buffer,
598 )
599 }
600 Some(EtherType::Ipv6) => {
601 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
602 &counters.recv_ipv6_delivered
603 });
604 core_ctx.receive_frame(
605 bindings_ctx,
606 RecvIpFrameMeta::<_, _, Ipv6>::new(
607 device_id,
608 Some(frame_dst),
609 DeviceIpLayerMetadata::default(),
610 parsing_context,
611 ),
612 buffer,
613 )
614 }
615 Some(EtherType::Other(_)) => {
616 core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
617 &counters.recv_unsupported_ethertype
618 });
619 }
620 None => {
621 core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
622 &counters.recv_no_ethertype
623 });
624 }
625 }
626 }
627}
628
629pub fn join_link_multicast<
645 BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
646 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
647>(
648 core_ctx: &mut CC,
649 bindings_ctx: &mut BC,
650 device_id: &CC::DeviceId,
651 multicast_addr: MulticastAddr<Mac>,
652) {
653 core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
654 let groups = &mut dynamic_state.link_multicast_groups;
655
656 match groups.insert(multicast_addr) {
657 InsertResult::Inserted(()) => {
658 trace!(
659 "ethernet::join_link_multicast: joining link multicast {:?}",
660 multicast_addr
661 );
662 bindings_ctx.on_event(EthernetDeviceEvent::MulticastJoin {
663 device: device_id.clone(),
664 addr: multicast_addr,
665 });
666 }
667 InsertResult::AlreadyPresent => {
668 trace!(
669 "ethernet::join_link_multicast: already joined link multicast {:?}",
670 multicast_addr,
671 );
672 }
673 }
674 })
675}
676
677pub fn leave_link_multicast<
696 BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
697 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
698>(
699 core_ctx: &mut CC,
700 bindings_ctx: &mut BC,
701 device_id: &CC::DeviceId,
702 multicast_addr: MulticastAddr<Mac>,
703) {
704 core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
705 let groups = &mut dynamic_state.link_multicast_groups;
706
707 match groups.remove(multicast_addr) {
708 RemoveResult::Removed(()) => {
709 trace!(
710 "ethernet::leave_link_multicast: \
711 leaving link multicast {:?}",
712 multicast_addr
713 );
714 bindings_ctx.on_event(EthernetDeviceEvent::MulticastLeave {
715 device: device_id.clone(),
716 addr: multicast_addr,
717 });
718 }
719 RemoveResult::StillPresent => {
720 trace!(
721 "ethernet::leave_link_multicast: not leaving link multicast \
722 {:?} as there are still listeners for it",
723 multicast_addr,
724 );
725 }
726 RemoveResult::NotPresent => {
727 panic!(
728 "ethernet::leave_link_multicast: device {:?} has not yet \
729 joined link multicast {:?}",
730 device_id, multicast_addr,
731 );
732 }
733 }
734 })
735}
736
737pub fn get_max_frame_size<
738 BC: EthernetIpLinkDeviceBindingsContext,
739 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
740>(
741 core_ctx: &mut CC,
742 device_id: &CC::DeviceId,
743) -> MaxEthernetFrameSize {
744 core_ctx
745 .with_ethernet_state(device_id, |_static_state, dynamic_state| dynamic_state.max_frame_size)
746}
747
748pub fn get_mtu<
750 BC: EthernetIpLinkDeviceBindingsContext,
751 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
752>(
753 core_ctx: &mut CC,
754 device_id: &CC::DeviceId,
755) -> Mtu {
756 get_max_frame_size(core_ctx, device_id).as_mtu()
757}
758
759pub trait UseArpFrameMetadataBlanket {}
765
766impl<
767 BC: EthernetIpLinkDeviceBindingsContext,
768 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
769 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
770 + ResourceCounterContext<CC::DeviceId, DeviceCounters>
771 + UseArpFrameMetadataBlanket,
772> SendableFrameMeta<CC, BC> for ArpFrameMetadata<EthernetLinkDevice, CC::DeviceId>
773{
774 fn send_meta<S>(
775 self,
776 core_ctx: &mut CC,
777 bindings_ctx: &mut BC,
778 body: S,
779 ) -> Result<(), SendFrameError<S>>
780 where
781 S: NetworkSerializer,
782 S::Buffer: BufferMut,
783 {
784 let Self { device_id, dst_addr } = self;
785 let meta: BC::TxMetadata = Default::default();
786 send_as_ethernet_frame_to_dst(
787 core_ctx,
788 bindings_ctx,
789 &device_id,
790 dst_addr,
791 body,
792 EtherType::Arp,
793 meta,
794 )
795 }
796}
797
798impl DeviceSocketSendTypes for EthernetLinkDevice {
799 type Metadata = Option<EthernetHeaderParams>;
802}
803
804impl<
805 BC: EthernetIpLinkDeviceBindingsContext,
806 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
807 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
808 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
809> SendableFrameMeta<CC, BC> for DeviceSocketMetadata<EthernetLinkDevice, EthernetDeviceId<BC>>
810where
811 CC: DeviceIdContext<EthernetLinkDevice, DeviceId = EthernetDeviceId<BC>>,
812{
813 fn send_meta<S>(
814 self,
815 core_ctx: &mut CC,
816 bindings_ctx: &mut BC,
817 body: S,
818 ) -> Result<(), SendFrameError<S>>
819 where
820 S: NetworkSerializer,
821 S::Buffer: BufferMut,
822 {
823 let Self { device_id, metadata } = self;
824 let tx_meta: BC::TxMetadata = Default::default();
827 match metadata {
828 Some(EthernetHeaderParams { dest_addr, protocol }) => send_as_ethernet_frame_to_dst(
829 core_ctx,
830 bindings_ctx,
831 &device_id,
832 dest_addr,
833 body,
834 protocol,
835 tx_meta,
836 ),
837 None => send_ethernet_frame(core_ctx, bindings_ctx, &device_id, body, tx_meta),
838 }
839 }
840}
841
842pub fn get_mac<
844 'a,
845 BC: EthernetIpLinkDeviceBindingsContext,
846 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
847>(
848 core_ctx: &'a mut CC,
849 device_id: &CC::DeviceId,
850) -> UnicastAddr<Mac> {
851 core_ctx.with_static_ethernet_device_state(device_id, |state| state.mac)
852}
853
854pub fn set_mtu<
856 BC: EthernetIpLinkDeviceBindingsContext,
857 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
858>(
859 core_ctx: &mut CC,
860 device_id: &CC::DeviceId,
861 mtu: Mtu,
862) {
863 core_ctx.with_ethernet_state_mut(device_id, |static_state, dynamic_state| {
864 if let Some(mut frame_size ) = MaxEthernetFrameSize::from_mtu(mtu) {
865 if frame_size > static_state.max_frame_size {
868 trace!("ethernet::ndp_device::set_mtu: MTU of {:?} is greater than the device {:?}'s max MTU of {:?}, using device's max MTU instead", mtu, device_id, static_state.max_frame_size.as_mtu());
869 frame_size = static_state.max_frame_size;
870 }
871 trace!("ethernet::ndp_device::set_mtu: setting link MTU to {:?}", mtu);
872 dynamic_state.max_frame_size = frame_size;
873 }
874 })
875}
876
877#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
879pub enum EthernetLinkDevice {}
880
881impl Device for EthernetLinkDevice {}
882
883impl LinkDevice for EthernetLinkDevice {
884 type Address = Mac;
885}
886
887impl<BT: DeviceBufferBindingsTypes> DeviceBufferSpec<BT> for EthernetLinkDevice {
888 type TxBuffer = BT::TxBuffer;
889 type TxAllocator = BT::TxAllocator;
890}
891
892impl DeviceStateSpec for EthernetLinkDevice {
893 type State<BT: DeviceLayerTypes> = EthernetDeviceState<BT>;
894 type External<BT: DeviceLayerTypes> = BT::EthernetDeviceState;
895 type CreationProperties = EthernetCreationProperties;
896 type Counters = EthernetDeviceCounters;
897 type TimerId<D: WeakDeviceIdentifier> = EthernetTimerId<D>;
898
899 fn new_device_state<
900 CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
901 BC: DeviceLayerTypes + TimerContext,
902 >(
903 bindings_ctx: &mut BC,
904 self_id: CC::WeakDeviceId,
905 EthernetCreationProperties { mac, max_frame_size, tx_offload_spec: _ }: Self::CreationProperties,
906 tx_allocator: <Self as DeviceBufferSpec<BC>>::TxAllocator,
907 ) -> Self::State<BC>
908 where
909 Self: DeviceBufferSpec<BC>,
910 {
911 let ipv4_arp = Mutex::new(ArpState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
912 bindings_ctx,
913 self_id.clone(),
914 ));
915 let ipv6_nud =
916 Mutex::new(NudState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx, self_id));
917 EthernetDeviceState {
918 counters: Default::default(),
919 ipv4_arp,
920 ipv6_nud,
921 ipv4_nud_config: Default::default(),
922 ipv6_nud_config: Default::default(),
923 static_state: StaticEthernetDeviceState { mac, max_frame_size },
924 dynamic_state: RwLock::new(DynamicEthernetDeviceState::new(max_frame_size)),
925 tx_queue: TransmitQueue::new(tx_allocator, ChecksumOffloadSpec::default()),
926 }
927 }
928 const IS_LOOPBACK: bool = false;
929 const DEBUG_TYPE: &'static str = "Ethernet";
930}
931
932#[cfg(any(test, feature = "testutils"))]
933pub(crate) mod testutil {
934 use super::*;
935
936 pub const IPV6_MIN_IMPLIED_MAX_FRAME_SIZE: MaxEthernetFrameSize =
938 MaxEthernetFrameSize::from_mtu(Ipv6::MINIMUM_LINK_MTU).unwrap();
939}
940
941#[cfg(test)]
942mod tests {
943 use alloc::vec;
944 use alloc::vec::Vec;
945 use core::convert::Infallible as Never;
946 use netstack3_hashmap::HashSet;
947
948 use net_types::SpecifiedAddr;
949 use net_types::ip::{Ipv4Addr, Ipv6Addr};
950 use netstack3_base::testutil::{
951 FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId, TEST_ADDRS_V4,
952 };
953 use netstack3_base::{CounterContext, CtxPair, IntoCoreTimerCtx};
954 use netstack3_ip::nud::{
955 self, DelegateNudContext, DynamicNeighborUpdateSource, NeighborApi, UseDelegateNudContext,
956 };
957 use packet::Buf;
958 use packet_formats::testutil::parse_ethernet_frame;
959
960 use super::*;
961 use crate::internal::arp::{
962 ArpConfigContext, ArpContext, ArpCounters, ArpNudCtx, ArpSenderContext,
963 };
964 use crate::internal::base::{DeviceBufferBindingsTypes, DeviceSendFrameError};
965 use crate::internal::ethernet::testutil::IPV6_MIN_IMPLIED_MAX_FRAME_SIZE;
966 use crate::internal::queue::tx::{
967 BufVecU8Allocator, TransmitQueueBindingsContext, TransmitQueueCommon, TransmitQueueContext,
968 };
969 use crate::internal::socket::{Frame, ParseSentFrameError, SentFrame};
970
971 struct FakeEthernetCtx {
972 static_state: StaticEthernetDeviceState,
973 dynamic_state: DynamicEthernetDeviceState,
974 tx_queue: TransmitQueueState<FakeTxMetadata, Buf<Vec<u8>>, BufVecU8Allocator>,
975 counters: DeviceCounters,
976 per_device_counters: DeviceCounters,
977 ethernet_counters: EthernetDeviceCounters,
978 arp_counters: ArpCounters,
979 }
980
981 impl FakeEthernetCtx {
982 fn new(mac: UnicastAddr<Mac>, max_frame_size: MaxEthernetFrameSize) -> FakeEthernetCtx {
983 FakeEthernetCtx {
984 static_state: StaticEthernetDeviceState { max_frame_size, mac },
985 dynamic_state: DynamicEthernetDeviceState::new(max_frame_size),
986 tx_queue: Default::default(),
987 counters: Default::default(),
988 per_device_counters: Default::default(),
989 ethernet_counters: Default::default(),
990 arp_counters: Default::default(),
991 }
992 }
993 }
994
995 type FakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
996 EthernetTimerId<FakeWeakDeviceId<FakeDeviceId>>,
997 nud::Event<Mac, FakeDeviceId, Ipv4, FakeInstant>,
998 FakeBindingsState,
999 (),
1000 >;
1001
1002 #[derive(Default)]
1003 struct FakeBindingsState {
1004 link_multicast_group_memberships: HashSet<(FakeDeviceId, MulticastAddr<Mac>)>,
1005 }
1006
1007 type FakeInnerCtx =
1008 netstack3_base::testutil::FakeCoreCtx<FakeEthernetCtx, FakeDeviceId, FakeDeviceId>;
1009
1010 struct FakeCoreCtx {
1011 arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1012 inner: FakeInnerCtx,
1013 }
1014
1015 fn new_context() -> CtxPair<FakeCoreCtx, FakeBindingsCtx> {
1016 CtxPair::with_default_bindings_ctx(|bindings_ctx| FakeCoreCtx {
1017 arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
1018 bindings_ctx,
1019 FakeWeakDeviceId(FakeDeviceId),
1020 ),
1021 inner: FakeInnerCtx::with_state(FakeEthernetCtx::new(
1022 TEST_ADDRS_V4.local_mac,
1023 IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1024 )),
1025 })
1026 }
1027
1028 impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1029 fn handle_frame(
1030 &mut self,
1031 bindings_ctx: &mut FakeBindingsCtx,
1032 device: &Self::DeviceId,
1033 frame: Frame<&[u8]>,
1034 whole_frame: &[u8],
1035 ) {
1036 self.inner.handle_frame(bindings_ctx, device, frame, whole_frame)
1037 }
1038 }
1039
1040 impl CounterContext<DeviceCounters> for FakeCoreCtx {
1041 fn counters(&self) -> &DeviceCounters {
1042 &self.inner.state.counters
1043 }
1044 }
1045
1046 impl CounterContext<DeviceCounters> for FakeInnerCtx {
1047 fn counters(&self) -> &DeviceCounters {
1048 &self.state.counters
1049 }
1050 }
1051
1052 impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeCoreCtx {
1053 fn per_resource_counters<'a>(
1054 &'a self,
1055 &FakeDeviceId: &'a FakeDeviceId,
1056 ) -> &'a DeviceCounters {
1057 &self.inner.state.per_device_counters
1058 }
1059 }
1060
1061 impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeInnerCtx {
1062 fn per_resource_counters<'a>(
1063 &'a self,
1064 &FakeDeviceId: &'a FakeDeviceId,
1065 ) -> &'a DeviceCounters {
1066 &self.state.per_device_counters
1067 }
1068 }
1069
1070 impl CounterContext<EthernetDeviceCounters> for FakeCoreCtx {
1071 fn counters(&self) -> &EthernetDeviceCounters {
1072 &self.inner.state.ethernet_counters
1073 }
1074 }
1075
1076 impl CounterContext<EthernetDeviceCounters> for FakeInnerCtx {
1077 fn counters(&self) -> &EthernetDeviceCounters {
1078 &self.state.ethernet_counters
1079 }
1080 }
1081
1082 impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1083 fn handle_frame(
1084 &mut self,
1085 _bindings_ctx: &mut FakeBindingsCtx,
1086 _device: &Self::DeviceId,
1087 _frame: Frame<&[u8]>,
1088 _whole_frame: &[u8],
1089 ) {
1090 }
1092 }
1093
1094 impl EthernetIpLinkDeviceStaticStateContext for FakeCoreCtx {
1095 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1096 &mut self,
1097 device_id: &FakeDeviceId,
1098 cb: F,
1099 ) -> O {
1100 self.inner.with_static_ethernet_device_state(device_id, cb)
1101 }
1102 }
1103
1104 impl EthernetIpLinkDeviceStaticStateContext for FakeInnerCtx {
1105 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1106 &mut self,
1107 &FakeDeviceId: &FakeDeviceId,
1108 cb: F,
1109 ) -> O {
1110 cb(&self.state.static_state)
1111 }
1112 }
1113
1114 impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeCoreCtx {
1115 fn with_ethernet_state<
1116 O,
1117 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1118 >(
1119 &mut self,
1120 device_id: &FakeDeviceId,
1121 cb: F,
1122 ) -> O {
1123 self.inner.with_ethernet_state(device_id, cb)
1124 }
1125
1126 fn with_ethernet_state_mut<
1127 O,
1128 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1129 >(
1130 &mut self,
1131 device_id: &FakeDeviceId,
1132 cb: F,
1133 ) -> O {
1134 self.inner.with_ethernet_state_mut(device_id, cb)
1135 }
1136 }
1137
1138 impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeInnerCtx {
1139 fn with_ethernet_state<
1140 O,
1141 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1142 >(
1143 &mut self,
1144 &FakeDeviceId: &FakeDeviceId,
1145 cb: F,
1146 ) -> O {
1147 let FakeEthernetCtx { static_state, dynamic_state, .. } = &self.state;
1148 cb(static_state, dynamic_state)
1149 }
1150
1151 fn with_ethernet_state_mut<
1152 O,
1153 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1154 >(
1155 &mut self,
1156 &FakeDeviceId: &FakeDeviceId,
1157 cb: F,
1158 ) -> O {
1159 let FakeEthernetCtx { static_state, dynamic_state, .. } = &mut self.state;
1160 cb(static_state, dynamic_state)
1161 }
1162 }
1163
1164 impl NudHandler<Ipv6, EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1165 fn handle_neighbor_update(
1166 &mut self,
1167 _bindings_ctx: &mut FakeBindingsCtx,
1168 _device_id: &Self::DeviceId,
1169 _neighbor: SpecifiedAddr<Ipv6Addr>,
1170 _source: DynamicNeighborUpdateSource<Mac>,
1171 ) {
1172 unimplemented!()
1173 }
1174
1175 fn flush(&mut self, _bindings_ctx: &mut FakeBindingsCtx, _device_id: &Self::DeviceId) {
1176 unimplemented!()
1177 }
1178
1179 fn send_ip_packet_to_neighbor<S>(
1180 &mut self,
1181 _bindings_ctx: &mut FakeBindingsCtx,
1182 _device_id: &Self::DeviceId,
1183 _neighbor: SpecifiedAddr<Ipv6Addr>,
1184 _body: S,
1185 _tx_meta: FakeTxMetadata,
1186 ) -> Result<(), SendFrameError<S>> {
1187 unimplemented!()
1188 }
1189 }
1190
1191 struct FakeCoreCtxWithDeviceId<'a> {
1192 core_ctx: &'a mut FakeInnerCtx,
1193 device_id: &'a FakeDeviceId,
1194 }
1195
1196 impl<'a> DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxWithDeviceId<'a> {
1197 type DeviceId = FakeDeviceId;
1198 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1199 }
1200
1201 impl<'a> ArpConfigContext for FakeCoreCtxWithDeviceId<'a> {
1202 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1203 cb(&NudUserConfig::default())
1204 }
1205 }
1206
1207 impl UseArpFrameMetadataBlanket for FakeCoreCtx {}
1208
1209 impl ArpContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1210 type ConfigCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1211
1212 type ArpSenderCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1213
1214 fn with_arp_state_mut_and_sender_ctx<
1215 O,
1216 F: FnOnce(
1217 &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1218 &mut Self::ArpSenderCtx<'_>,
1219 ) -> O,
1220 >(
1221 &mut self,
1222 device_id: &Self::DeviceId,
1223 cb: F,
1224 ) -> O {
1225 let Self { arp_state, inner } = self;
1226 cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1227 }
1228
1229 fn get_protocol_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Ipv4Addr> {
1230 unimplemented!()
1231 }
1232
1233 fn get_hardware_addr(
1234 &mut self,
1235 _bindings_ctx: &mut FakeBindingsCtx,
1236 _device_id: &Self::DeviceId,
1237 ) -> UnicastAddr<Mac> {
1238 self.inner.state.static_state.mac
1239 }
1240
1241 fn with_arp_state_mut<
1242 O,
1243 F: FnOnce(
1244 &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1245 &mut Self::ConfigCtx<'_>,
1246 ) -> O,
1247 >(
1248 &mut self,
1249 device_id: &Self::DeviceId,
1250 cb: F,
1251 ) -> O {
1252 let Self { arp_state, inner } = self;
1253 cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1254 }
1255
1256 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtx>) -> O>(
1257 &mut self,
1258 FakeDeviceId: &Self::DeviceId,
1259 cb: F,
1260 ) -> O {
1261 cb(&mut self.arp_state)
1262 }
1263 }
1264
1265 impl UseDelegateNudContext for FakeCoreCtx {}
1266 impl DelegateNudContext<Ipv4> for FakeCoreCtx {
1267 type Delegate<T> = ArpNudCtx<T>;
1268 }
1269
1270 impl ArpConfigContext for FakeInnerCtx {
1271 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1272 cb(&NudUserConfig::default())
1273 }
1274 }
1275
1276 impl<'a> ArpSenderContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtxWithDeviceId<'a> {
1277 fn send_ip_packet_to_neighbor_link_addr<S>(
1278 &mut self,
1279 bindings_ctx: &mut FakeBindingsCtx,
1280 link_addr: Mac,
1281 body: S,
1282 tx_meta: FakeTxMetadata,
1283 ) -> Result<(), SendFrameError<S>>
1284 where
1285 S: NetworkSerializer,
1286 S::Buffer: BufferMut,
1287 {
1288 let Self { core_ctx, device_id } = self;
1289 send_as_ethernet_frame_to_dst(
1290 *core_ctx,
1291 bindings_ctx,
1292 device_id,
1293 link_addr,
1294 body,
1295 EtherType::Ipv4,
1296 tx_meta,
1297 )
1298 }
1299 }
1300
1301 impl TransmitQueueBindingsContext<FakeDeviceId> for FakeBindingsCtx {
1302 fn wake_tx_task(&mut self, FakeDeviceId: &FakeDeviceId) {
1303 unimplemented!("unused by tests")
1304 }
1305 }
1306
1307 impl EventContext<EthernetDeviceEvent<FakeDeviceId>> for FakeBindingsCtx {
1308 fn on_event(&mut self, event: EthernetDeviceEvent<FakeDeviceId>) {
1309 match event {
1311 EthernetDeviceEvent::MulticastJoin { device, addr } => {
1312 assert!(
1313 self.state.link_multicast_group_memberships.insert((device, addr)),
1314 "membership should not be present"
1315 );
1316 }
1317 EthernetDeviceEvent::MulticastLeave { device, addr } => {
1318 assert!(
1319 self.state.link_multicast_group_memberships.remove(&(device, addr)),
1320 "membership should be present"
1321 );
1322 }
1323 }
1324 }
1325 }
1326
1327 impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1328 type Meta = FakeTxMetadata;
1329
1330 type DequeueContext = Never;
1331
1332 fn parse_outgoing_frame<'a>(
1333 buf: &'a [u8],
1334 meta: &'a Self::Meta,
1335 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1336 FakeInnerCtx::parse_outgoing_frame(buf, meta)
1337 }
1338 }
1339
1340 impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1341 type Meta = FakeTxMetadata;
1342
1343 type DequeueContext = Never;
1344
1345 fn parse_outgoing_frame<'a, 'b>(
1346 buf: &'a [u8],
1347 _tx_meta: &'b Self::Meta,
1348 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1349 SentFrame::try_parse_as_ethernet(buf)
1350 }
1351 }
1352
1353 impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1354 fn with_transmit_queue_mut<
1355 O,
1356 F: FnOnce(
1357 &mut TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>,
1358 ) -> O,
1359 >(
1360 &mut self,
1361 device_id: &Self::DeviceId,
1362 cb: F,
1363 ) -> O {
1364 self.inner.with_transmit_queue_mut(device_id, cb)
1365 }
1366
1367 fn with_transmit_queue<
1368 O,
1369 F: FnOnce(&TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>) -> O,
1370 >(
1371 &mut self,
1372 device_id: &Self::DeviceId,
1373 cb: F,
1374 ) -> O {
1375 self.inner.with_transmit_queue(device_id, cb)
1376 }
1377
1378 fn send_frame(
1379 &mut self,
1380 bindings_ctx: &mut FakeBindingsCtx,
1381 device_id: &Self::DeviceId,
1382 dequeue_context: Option<&mut Never>,
1383 tx_meta: Self::Meta,
1384 buf: packet::Buf<Vec<u8>>,
1385 ) -> Result<(), DeviceSendFrameError> {
1386 TransmitQueueContext::send_frame(
1387 &mut self.inner,
1388 bindings_ctx,
1389 device_id,
1390 dequeue_context,
1391 tx_meta,
1392 buf,
1393 )
1394 }
1395 }
1396
1397 impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx
1398 where
1399 Self: TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx, Meta = FakeTxMetadata>,
1400 {
1401 fn with_transmit_queue_mut<
1402 O,
1403 F: FnOnce(
1404 &mut TransmitQueueState<
1405 Self::Meta,
1406 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1407 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1408 >,
1409 ) -> O,
1410 >(
1411 &mut self,
1412 _device_id: &Self::DeviceId,
1413 cb: F,
1414 ) -> O {
1415 cb(&mut self.state.tx_queue)
1416 }
1417
1418 fn with_transmit_queue<
1419 O,
1420 F: FnOnce(
1421 &TransmitQueueState<
1422 Self::Meta,
1423 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1424 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1425 >,
1426 ) -> O,
1427 >(
1428 &mut self,
1429 _device_id: &Self::DeviceId,
1430 cb: F,
1431 ) -> O {
1432 cb(&self.state.tx_queue)
1433 }
1434
1435 fn send_frame(
1436 &mut self,
1437 _bindings_ctx: &mut FakeBindingsCtx,
1438 device_id: &Self::DeviceId,
1439 dequeue_context: Option<&mut Never>,
1440 _tx_meta: Self::Meta,
1441 buf: packet::Buf<Vec<u8>>,
1442 ) -> Result<(), DeviceSendFrameError> {
1443 match dequeue_context {
1444 Some(never) => match *never {},
1445 None => (),
1446 }
1447 self.frames.push(device_id.clone(), buf.as_ref().to_vec());
1448 Ok(())
1449 }
1450 }
1451
1452 impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtx {
1453 type DeviceId = FakeDeviceId;
1454 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1455 }
1456
1457 impl DeviceIdContext<EthernetLinkDevice> for FakeInnerCtx {
1458 type DeviceId = FakeDeviceId;
1459 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1460 }
1461
1462 impl CounterContext<ArpCounters> for FakeCoreCtx {
1463 fn counters(&self) -> &ArpCounters {
1464 &self.inner.state.arp_counters
1465 }
1466 }
1467
1468 #[test]
1469 fn test_mtu() {
1470 fn test(size: usize, expect_frames_sent: bool) {
1474 let mut ctx = new_context();
1475 NeighborApi::<Ipv4, EthernetLinkDevice, _>::new(ctx.as_mut())
1476 .insert_static_entry(
1477 &FakeDeviceId,
1478 TEST_ADDRS_V4.remote_ip.get(),
1479 TEST_ADDRS_V4.remote_mac.get(),
1480 )
1481 .unwrap();
1482 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1483 let result = send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1484 core_ctx,
1485 bindings_ctx,
1486 &FakeDeviceId,
1487 IpPacketDestination::<Ipv4, _>::Neighbor(TEST_ADDRS_V4.remote_ip),
1488 Buf::new(&mut vec![0; size], ..),
1489 FakeTxMetadata::default(),
1490 )
1491 .map_err(|_serializer| ());
1492 let sent_frames = core_ctx.inner.frames().len();
1493 if expect_frames_sent {
1494 assert_eq!(sent_frames, 1);
1495 result.expect("should succeed");
1496 } else {
1497 assert_eq!(sent_frames, 0);
1498 result.expect_err("should fail");
1499 }
1500 }
1501
1502 test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap(), true);
1503 test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap() + 1, false);
1504 }
1505
1506 #[test]
1507 fn broadcast() {
1508 let mut ctx = new_context();
1509 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1510 send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1511 core_ctx,
1512 bindings_ctx,
1513 &FakeDeviceId,
1514 IpPacketDestination::<Ipv4, _>::Broadcast(()),
1515 Buf::new(&mut vec![0; 100], ..),
1516 FakeTxMetadata::default(),
1517 )
1518 .map_err(|_serializer| ())
1519 .expect("send_ip_frame should succeed");
1520 let sent_frames = core_ctx.inner.frames().len();
1521 assert_eq!(sent_frames, 1);
1522 let (FakeDeviceId, frame) = core_ctx.inner.frames()[0].clone();
1523 let (_body, _src_mac, dst_mac, _ether_type) =
1524 parse_ethernet_frame(&frame, EthernetFrameLengthCheck::NoCheck).unwrap();
1525 assert_eq!(dst_mac, Mac::BROADCAST);
1526 }
1527
1528 #[test]
1529 fn test_join_link_multicast() {
1530 let mut ctx = new_context();
1531 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1532
1533 let address1: MulticastAddr<Mac> =
1534 MulticastAddr::new(Ipv4Addr::new([224, 0, 0, 200])).unwrap().into();
1535 let address2: MulticastAddr<Mac> =
1536 MulticastAddr::new(Ipv4Addr::new([224, 0, 10, 30])).unwrap().into();
1537
1538 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1539 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1540 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1541
1542 assert_eq!(
1543 bindings_ctx.state.link_multicast_group_memberships,
1544 HashSet::from_iter([(FakeDeviceId, address1), (FakeDeviceId, address2)])
1545 );
1546
1547 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1548
1549 assert_eq!(
1550 bindings_ctx.state.link_multicast_group_memberships,
1551 HashSet::from_iter([(FakeDeviceId, address2)])
1552 );
1553
1554 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1556
1557 assert_eq!(
1558 bindings_ctx.state.link_multicast_group_memberships,
1559 HashSet::from_iter([(FakeDeviceId, address2)])
1560 );
1561
1562 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1563
1564 assert_eq!(bindings_ctx.state.link_multicast_group_memberships, HashSet::new());
1565 }
1566}