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