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, IpCounters, 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 + ResourceCounterContext<CC::DeviceId, IpCounters<Ipv4>>
517 + ResourceCounterContext<CC::DeviceId, IpCounters<Ipv6>>,
518{
519 fn receive_meta<B: BufferMut + Debug>(
520 self,
521 core_ctx: &mut CC,
522 bindings_ctx: &mut BC,
523 mut buffer: B,
524 ) {
525 trace_duration!("device::ethernet::receive_frame");
526 let Self { device_id, parsing_context } = self;
527 trace!("ethernet::receive_frame: device_id = {:?}", device_id);
528 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| &counters.recv_frame);
529 core_ctx.add_both_usize(&device_id, buffer.len(), |counters: &DeviceCounters| {
530 &counters.recv_bytes
531 });
532 let (ethernet, whole_frame) = if let Ok(frame) =
541 buffer.parse_with_view::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::NoCheck)
542 {
543 frame
544 } else {
545 core_ctx
546 .increment_both(&device_id, |counters: &DeviceCounters| &counters.recv_parse_error);
547 trace!("ethernet::receive_frame: failed to parse ethernet frame");
548 return;
549 };
550
551 let src = ethernet.src_mac();
552 let dst = ethernet.dst_mac();
553
554 let frame_dst = core_ctx.with_static_ethernet_device_state(&device_id, |static_state| {
555 FrameDestination::from_dest(dst, static_state.mac.get())
556 });
557
558 let ethertype = ethernet.ethertype();
559
560 core_ctx.handle_frame(
561 bindings_ctx,
562 &device_id,
563 ReceivedFrame::from_ethernet(ethernet, frame_dst).into(),
564 whole_frame,
565 );
566
567 match ethertype {
568 Some(EtherType::Arp) => {
569 let types = if let Ok(types) = peek_arp_types(buffer.as_ref()) {
570 types
571 } else {
572 return;
573 };
574 match types {
575 (ArpHardwareType::Ethernet, ArpNetworkType::Ipv4) => {
576 ArpPacketHandler::handle_packet(
577 core_ctx,
578 bindings_ctx,
579 device_id,
580 src,
581 frame_dst,
582 buffer,
583 )
584 }
585 }
586 }
587 Some(EtherType::Ipv4) => {
588 let local_frame_dst = match frame_dst.check_local() {
589 Some(dst) => dst,
590 None => {
591 core_ctx.increment_both(&device_id, |counters: &IpCounters<Ipv4>| {
592 &counters.drop_ip_packet_other_host
593 });
594 return;
595 }
596 };
597 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
598 &counters.recv_ipv4_delivered
599 });
600 core_ctx.receive_frame(
601 bindings_ctx,
602 RecvIpFrameMeta::<_, _, Ipv4>::new(
603 device_id,
604 Some(local_frame_dst),
605 DeviceIpLayerMetadata::default(),
606 parsing_context,
607 ),
608 buffer,
609 )
610 }
611 Some(EtherType::Ipv6) => {
612 let local_frame_dst = match frame_dst.check_local() {
613 Some(dst) => dst,
614 None => {
615 core_ctx.increment_both(&device_id, |counters: &IpCounters<Ipv6>| {
616 &counters.drop_ip_packet_other_host
617 });
618 return;
619 }
620 };
621 core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
622 &counters.recv_ipv6_delivered
623 });
624 core_ctx.receive_frame(
625 bindings_ctx,
626 RecvIpFrameMeta::<_, _, Ipv6>::new(
627 device_id,
628 Some(local_frame_dst),
629 DeviceIpLayerMetadata::default(),
630 parsing_context,
631 ),
632 buffer,
633 )
634 }
635 Some(EtherType::Other(_)) => {
636 core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
637 &counters.recv_unsupported_ethertype
638 });
639 }
640 None => {
641 core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
642 &counters.recv_no_ethertype
643 });
644 }
645 }
646 }
647}
648
649pub fn join_link_multicast<
665 BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
666 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
667>(
668 core_ctx: &mut CC,
669 bindings_ctx: &mut BC,
670 device_id: &CC::DeviceId,
671 multicast_addr: MulticastAddr<Mac>,
672) {
673 core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
674 let groups = &mut dynamic_state.link_multicast_groups;
675
676 match groups.insert(multicast_addr) {
677 InsertResult::Inserted(()) => {
678 trace!(
679 "ethernet::join_link_multicast: joining link multicast {:?}",
680 multicast_addr
681 );
682 bindings_ctx.on_event(EthernetDeviceEvent::MulticastJoin {
683 device: device_id.clone(),
684 addr: multicast_addr,
685 });
686 }
687 InsertResult::AlreadyPresent => {
688 trace!(
689 "ethernet::join_link_multicast: already joined link multicast {:?}",
690 multicast_addr,
691 );
692 }
693 }
694 })
695}
696
697pub fn leave_link_multicast<
716 BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
717 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
718>(
719 core_ctx: &mut CC,
720 bindings_ctx: &mut BC,
721 device_id: &CC::DeviceId,
722 multicast_addr: MulticastAddr<Mac>,
723) {
724 core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
725 let groups = &mut dynamic_state.link_multicast_groups;
726
727 match groups.remove(multicast_addr) {
728 RemoveResult::Removed(()) => {
729 trace!(
730 "ethernet::leave_link_multicast: \
731 leaving link multicast {:?}",
732 multicast_addr
733 );
734 bindings_ctx.on_event(EthernetDeviceEvent::MulticastLeave {
735 device: device_id.clone(),
736 addr: multicast_addr,
737 });
738 }
739 RemoveResult::StillPresent => {
740 trace!(
741 "ethernet::leave_link_multicast: not leaving link multicast \
742 {:?} as there are still listeners for it",
743 multicast_addr,
744 );
745 }
746 RemoveResult::NotPresent => {
747 panic!(
748 "ethernet::leave_link_multicast: device {:?} has not yet \
749 joined link multicast {:?}",
750 device_id, multicast_addr,
751 );
752 }
753 }
754 })
755}
756
757pub fn get_max_frame_size<
758 BC: EthernetIpLinkDeviceBindingsContext,
759 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
760>(
761 core_ctx: &mut CC,
762 device_id: &CC::DeviceId,
763) -> MaxEthernetFrameSize {
764 core_ctx
765 .with_ethernet_state(device_id, |_static_state, dynamic_state| dynamic_state.max_frame_size)
766}
767
768pub fn get_mtu<
770 BC: EthernetIpLinkDeviceBindingsContext,
771 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
772>(
773 core_ctx: &mut CC,
774 device_id: &CC::DeviceId,
775) -> Mtu {
776 get_max_frame_size(core_ctx, device_id).as_mtu()
777}
778
779pub trait UseArpFrameMetadataBlanket {}
785
786impl<
787 BC: EthernetIpLinkDeviceBindingsContext,
788 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
789 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
790 + ResourceCounterContext<CC::DeviceId, DeviceCounters>
791 + UseArpFrameMetadataBlanket,
792> SendableFrameMeta<CC, BC> for ArpFrameMetadata<EthernetLinkDevice, CC::DeviceId>
793{
794 fn send_meta<S>(
795 self,
796 core_ctx: &mut CC,
797 bindings_ctx: &mut BC,
798 body: S,
799 ) -> Result<(), SendFrameError<S>>
800 where
801 S: NetworkSerializer,
802 S::Buffer: BufferMut,
803 {
804 let Self { device_id, dst_addr } = self;
805 let meta: BC::TxMetadata = Default::default();
806 send_as_ethernet_frame_to_dst(
807 core_ctx,
808 bindings_ctx,
809 &device_id,
810 dst_addr.get(),
811 body,
812 EtherType::Arp,
813 meta,
814 )
815 }
816}
817
818impl DeviceSocketSendTypes for EthernetLinkDevice {
819 type Metadata = Option<EthernetHeaderParams>;
822}
823
824impl<
825 BC: EthernetIpLinkDeviceBindingsContext,
826 CC: EthernetIpLinkDeviceDynamicStateContext<BC>
827 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
828 + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
829> SendableFrameMeta<CC, BC> for DeviceSocketMetadata<EthernetLinkDevice, EthernetDeviceId<BC>>
830where
831 CC: DeviceIdContext<EthernetLinkDevice, DeviceId = EthernetDeviceId<BC>>,
832{
833 fn send_meta<S>(
834 self,
835 core_ctx: &mut CC,
836 bindings_ctx: &mut BC,
837 body: S,
838 ) -> Result<(), SendFrameError<S>>
839 where
840 S: NetworkSerializer,
841 S::Buffer: BufferMut,
842 {
843 let Self { device_id, metadata } = self;
844 let tx_meta: BC::TxMetadata = Default::default();
847 match metadata {
848 Some(EthernetHeaderParams { dest_addr, protocol }) => send_as_ethernet_frame_to_dst(
849 core_ctx,
850 bindings_ctx,
851 &device_id,
852 dest_addr,
853 body,
854 protocol,
855 tx_meta,
856 ),
857 None => send_ethernet_frame(core_ctx, bindings_ctx, &device_id, body, tx_meta),
858 }
859 }
860}
861
862pub fn get_mac<
864 'a,
865 BC: EthernetIpLinkDeviceBindingsContext,
866 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
867>(
868 core_ctx: &'a mut CC,
869 device_id: &CC::DeviceId,
870) -> UnicastAddr<Mac> {
871 core_ctx.with_static_ethernet_device_state(device_id, |state| state.mac)
872}
873
874pub fn set_mtu<
876 BC: EthernetIpLinkDeviceBindingsContext,
877 CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
878>(
879 core_ctx: &mut CC,
880 device_id: &CC::DeviceId,
881 mtu: Mtu,
882) {
883 core_ctx.with_ethernet_state_mut(device_id, |static_state, dynamic_state| {
884 if let Some(mut frame_size ) = MaxEthernetFrameSize::from_mtu(mtu) {
885 if frame_size > static_state.max_frame_size {
888 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());
889 frame_size = static_state.max_frame_size;
890 }
891 trace!("ethernet::ndp_device::set_mtu: setting link MTU to {:?}", mtu);
892 dynamic_state.max_frame_size = frame_size;
893 }
894 })
895}
896
897#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
899pub enum EthernetLinkDevice {}
900
901impl Device for EthernetLinkDevice {}
902
903impl LinkDevice for EthernetLinkDevice {
904 type Address = Mac;
905}
906
907impl<BT: DeviceBufferBindingsTypes> DeviceBufferSpec<BT> for EthernetLinkDevice {
908 type TxBuffer = BT::TxBuffer;
909 type TxAllocator = BT::TxAllocator;
910}
911
912impl DeviceStateSpec for EthernetLinkDevice {
913 type State<BT: DeviceLayerTypes> = EthernetDeviceState<BT>;
914 type External<BT: DeviceLayerTypes> = BT::EthernetDeviceState;
915 type CreationProperties = EthernetCreationProperties;
916 type Counters = EthernetDeviceCounters;
917 type TimerId<D: WeakDeviceIdentifier> = EthernetTimerId<D>;
918
919 fn new_device_state<
920 CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
921 BC: DeviceLayerTypes + TimerContext,
922 >(
923 bindings_ctx: &mut BC,
924 self_id: CC::WeakDeviceId,
925 EthernetCreationProperties { mac, max_frame_size, tx_offload_spec }: Self::CreationProperties,
926 tx_allocator: <Self as DeviceBufferSpec<BC>>::TxAllocator,
927 ) -> Self::State<BC>
928 where
929 Self: DeviceBufferSpec<BC>,
930 {
931 let ipv4_arp = Mutex::new(ArpState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
932 bindings_ctx,
933 self_id.clone(),
934 ));
935 let ipv6_nud =
936 Mutex::new(NudState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx, self_id));
937 EthernetDeviceState {
938 counters: Default::default(),
939 ipv4_arp,
940 ipv6_nud,
941 ipv4_nud_config: Default::default(),
942 ipv6_nud_config: Default::default(),
943 static_state: StaticEthernetDeviceState { mac, max_frame_size },
944 dynamic_state: RwLock::new(DynamicEthernetDeviceState::new(max_frame_size)),
945 tx_queue: TransmitQueue::new(tx_allocator, tx_offload_spec),
946 }
947 }
948 const IS_LOOPBACK: bool = false;
949 const DEBUG_TYPE: &'static str = "Ethernet";
950
951 fn tx_offload_spec<BT: DeviceLayerTypes>(
952 state: &Self::State<BT>,
953 ) -> Option<ChecksumOffloadSpec> {
954 Some(state.tx_queue.tx_offload_spec())
955 }
956}
957
958#[cfg(any(test, feature = "testutils"))]
959pub(crate) mod testutil {
960 use super::*;
961
962 pub const IPV6_MIN_IMPLIED_MAX_FRAME_SIZE: MaxEthernetFrameSize =
964 MaxEthernetFrameSize::from_mtu(Ipv6::MINIMUM_LINK_MTU).unwrap();
965}
966
967#[cfg(test)]
968mod tests {
969 use alloc::vec;
970 use alloc::vec::Vec;
971 use core::convert::Infallible as Never;
972 use netstack3_hashmap::HashSet;
973
974 use net_types::SpecifiedAddr;
975 use net_types::ip::{Ipv4Addr, Ipv6Addr};
976 use netstack3_base::testutil::{
977 FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId, TEST_ADDRS_V4,
978 };
979 use netstack3_base::{CounterContext, CtxPair, IntoCoreTimerCtx};
980 use netstack3_ip::nud::{
981 self, DelegateNudContext, DynamicNeighborUpdateSource, NeighborApi, UseDelegateNudContext,
982 };
983 use packet::Buf;
984 use packet_formats::testutil::parse_ethernet_frame;
985
986 use super::*;
987 use crate::internal::arp::{
988 ArpConfigContext, ArpContext, ArpCounters, ArpNudCtx, ArpSenderContext,
989 };
990 use crate::internal::base::{DeviceBufferBindingsTypes, DeviceSendFrameError};
991 use crate::internal::ethernet::testutil::IPV6_MIN_IMPLIED_MAX_FRAME_SIZE;
992 use crate::internal::queue::tx::{
993 BufVecU8Allocator, TransmitQueueBindingsContext, TransmitQueueCommon, TransmitQueueContext,
994 };
995 use crate::internal::socket::{Frame, ParseSentFrameError, SentFrame};
996
997 struct FakeEthernetCtx {
998 static_state: StaticEthernetDeviceState,
999 dynamic_state: DynamicEthernetDeviceState,
1000 tx_queue: TransmitQueueState<FakeTxMetadata, Buf<Vec<u8>>, BufVecU8Allocator>,
1001 counters: DeviceCounters,
1002 per_device_counters: DeviceCounters,
1003 ethernet_counters: EthernetDeviceCounters,
1004 arp_counters: ArpCounters,
1005 }
1006
1007 impl FakeEthernetCtx {
1008 fn new(mac: UnicastAddr<Mac>, max_frame_size: MaxEthernetFrameSize) -> FakeEthernetCtx {
1009 FakeEthernetCtx {
1010 static_state: StaticEthernetDeviceState { max_frame_size, mac },
1011 dynamic_state: DynamicEthernetDeviceState::new(max_frame_size),
1012 tx_queue: Default::default(),
1013 counters: Default::default(),
1014 per_device_counters: Default::default(),
1015 ethernet_counters: Default::default(),
1016 arp_counters: Default::default(),
1017 }
1018 }
1019 }
1020
1021 type FakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
1022 EthernetTimerId<FakeWeakDeviceId<FakeDeviceId>>,
1023 nud::Event<Mac, FakeDeviceId, Ipv4, FakeInstant>,
1024 FakeBindingsState,
1025 (),
1026 >;
1027
1028 #[derive(Default)]
1029 struct FakeBindingsState {
1030 link_multicast_group_memberships: HashSet<(FakeDeviceId, MulticastAddr<Mac>)>,
1031 }
1032
1033 type FakeInnerCtx =
1034 netstack3_base::testutil::FakeCoreCtx<FakeEthernetCtx, FakeDeviceId, FakeDeviceId>;
1035
1036 struct FakeCoreCtx {
1037 arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1038 inner: FakeInnerCtx,
1039 }
1040
1041 fn new_context() -> CtxPair<FakeCoreCtx, FakeBindingsCtx> {
1042 CtxPair::with_default_bindings_ctx(|bindings_ctx| FakeCoreCtx {
1043 arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
1044 bindings_ctx,
1045 FakeWeakDeviceId(FakeDeviceId),
1046 ),
1047 inner: FakeInnerCtx::with_state(FakeEthernetCtx::new(
1048 TEST_ADDRS_V4.local_mac,
1049 IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1050 )),
1051 })
1052 }
1053
1054 impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1055 fn handle_frame(
1056 &mut self,
1057 bindings_ctx: &mut FakeBindingsCtx,
1058 device: &Self::DeviceId,
1059 frame: Frame<&[u8]>,
1060 whole_frame: &[u8],
1061 ) {
1062 self.inner.handle_frame(bindings_ctx, device, frame, whole_frame)
1063 }
1064 }
1065
1066 impl CounterContext<DeviceCounters> for FakeCoreCtx {
1067 fn counters(&self) -> &DeviceCounters {
1068 &self.inner.state.counters
1069 }
1070 }
1071
1072 impl CounterContext<DeviceCounters> for FakeInnerCtx {
1073 fn counters(&self) -> &DeviceCounters {
1074 &self.state.counters
1075 }
1076 }
1077
1078 impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeCoreCtx {
1079 fn per_resource_counters<'a>(
1080 &'a self,
1081 &FakeDeviceId: &'a FakeDeviceId,
1082 ) -> &'a DeviceCounters {
1083 &self.inner.state.per_device_counters
1084 }
1085 }
1086
1087 impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeInnerCtx {
1088 fn per_resource_counters<'a>(
1089 &'a self,
1090 &FakeDeviceId: &'a FakeDeviceId,
1091 ) -> &'a DeviceCounters {
1092 &self.state.per_device_counters
1093 }
1094 }
1095
1096 impl CounterContext<EthernetDeviceCounters> for FakeCoreCtx {
1097 fn counters(&self) -> &EthernetDeviceCounters {
1098 &self.inner.state.ethernet_counters
1099 }
1100 }
1101
1102 impl CounterContext<EthernetDeviceCounters> for FakeInnerCtx {
1103 fn counters(&self) -> &EthernetDeviceCounters {
1104 &self.state.ethernet_counters
1105 }
1106 }
1107
1108 impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1109 fn handle_frame(
1110 &mut self,
1111 _bindings_ctx: &mut FakeBindingsCtx,
1112 _device: &Self::DeviceId,
1113 _frame: Frame<&[u8]>,
1114 _whole_frame: &[u8],
1115 ) {
1116 }
1118 }
1119
1120 impl EthernetIpLinkDeviceStaticStateContext for FakeCoreCtx {
1121 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1122 &mut self,
1123 device_id: &FakeDeviceId,
1124 cb: F,
1125 ) -> O {
1126 self.inner.with_static_ethernet_device_state(device_id, cb)
1127 }
1128 }
1129
1130 impl EthernetIpLinkDeviceStaticStateContext for FakeInnerCtx {
1131 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1132 &mut self,
1133 &FakeDeviceId: &FakeDeviceId,
1134 cb: F,
1135 ) -> O {
1136 cb(&self.state.static_state)
1137 }
1138 }
1139
1140 impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeCoreCtx {
1141 fn with_ethernet_state<
1142 O,
1143 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1144 >(
1145 &mut self,
1146 device_id: &FakeDeviceId,
1147 cb: F,
1148 ) -> O {
1149 self.inner.with_ethernet_state(device_id, cb)
1150 }
1151
1152 fn with_ethernet_state_mut<
1153 O,
1154 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1155 >(
1156 &mut self,
1157 device_id: &FakeDeviceId,
1158 cb: F,
1159 ) -> O {
1160 self.inner.with_ethernet_state_mut(device_id, cb)
1161 }
1162 }
1163
1164 impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeInnerCtx {
1165 fn with_ethernet_state<
1166 O,
1167 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1168 >(
1169 &mut self,
1170 &FakeDeviceId: &FakeDeviceId,
1171 cb: F,
1172 ) -> O {
1173 let FakeEthernetCtx { static_state, dynamic_state, .. } = &self.state;
1174 cb(static_state, dynamic_state)
1175 }
1176
1177 fn with_ethernet_state_mut<
1178 O,
1179 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1180 >(
1181 &mut self,
1182 &FakeDeviceId: &FakeDeviceId,
1183 cb: F,
1184 ) -> O {
1185 let FakeEthernetCtx { static_state, dynamic_state, .. } = &mut self.state;
1186 cb(static_state, dynamic_state)
1187 }
1188 }
1189
1190 impl NudHandler<Ipv6, EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1191 fn handle_neighbor_update(
1192 &mut self,
1193 _bindings_ctx: &mut FakeBindingsCtx,
1194 _device_id: &Self::DeviceId,
1195 _neighbor: SpecifiedAddr<Ipv6Addr>,
1196 _source: DynamicNeighborUpdateSource<Mac>,
1197 ) {
1198 unimplemented!()
1199 }
1200
1201 fn flush(&mut self, _bindings_ctx: &mut FakeBindingsCtx, _device_id: &Self::DeviceId) {
1202 unimplemented!()
1203 }
1204
1205 fn send_ip_packet_to_neighbor<S>(
1206 &mut self,
1207 _bindings_ctx: &mut FakeBindingsCtx,
1208 _device_id: &Self::DeviceId,
1209 _neighbor: SpecifiedAddr<Ipv6Addr>,
1210 _body: S,
1211 _tx_meta: FakeTxMetadata,
1212 ) -> Result<(), SendFrameError<S>> {
1213 unimplemented!()
1214 }
1215 }
1216
1217 struct FakeCoreCtxWithDeviceId<'a> {
1218 core_ctx: &'a mut FakeInnerCtx,
1219 device_id: &'a FakeDeviceId,
1220 }
1221
1222 impl<'a> DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxWithDeviceId<'a> {
1223 type DeviceId = FakeDeviceId;
1224 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1225 }
1226
1227 impl<'a> ArpConfigContext for FakeCoreCtxWithDeviceId<'a> {
1228 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1229 cb(&NudUserConfig::default())
1230 }
1231 }
1232
1233 impl UseArpFrameMetadataBlanket for FakeCoreCtx {}
1234
1235 impl ArpContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1236 type ConfigCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1237
1238 type ArpSenderCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1239
1240 fn with_arp_state_mut_and_sender_ctx<
1241 O,
1242 F: FnOnce(
1243 &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1244 &mut Self::ArpSenderCtx<'_>,
1245 ) -> O,
1246 >(
1247 &mut self,
1248 device_id: &Self::DeviceId,
1249 cb: F,
1250 ) -> O {
1251 let Self { arp_state, inner } = self;
1252 cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1253 }
1254
1255 fn get_protocol_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Ipv4Addr> {
1256 unimplemented!()
1257 }
1258
1259 fn get_hardware_addr(
1260 &mut self,
1261 _bindings_ctx: &mut FakeBindingsCtx,
1262 _device_id: &Self::DeviceId,
1263 ) -> UnicastAddr<Mac> {
1264 self.inner.state.static_state.mac
1265 }
1266
1267 fn with_arp_state_mut<
1268 O,
1269 F: FnOnce(
1270 &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1271 &mut Self::ConfigCtx<'_>,
1272 ) -> O,
1273 >(
1274 &mut self,
1275 device_id: &Self::DeviceId,
1276 cb: F,
1277 ) -> O {
1278 let Self { arp_state, inner } = self;
1279 cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1280 }
1281
1282 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtx>) -> O>(
1283 &mut self,
1284 FakeDeviceId: &Self::DeviceId,
1285 cb: F,
1286 ) -> O {
1287 cb(&mut self.arp_state)
1288 }
1289 }
1290
1291 impl UseDelegateNudContext for FakeCoreCtx {}
1292 impl DelegateNudContext<Ipv4> for FakeCoreCtx {
1293 type Delegate<T> = ArpNudCtx<T>;
1294 }
1295
1296 impl ArpConfigContext for FakeInnerCtx {
1297 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1298 cb(&NudUserConfig::default())
1299 }
1300 }
1301
1302 impl<'a> ArpSenderContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtxWithDeviceId<'a> {
1303 fn send_ip_packet_to_neighbor_link_addr<S>(
1304 &mut self,
1305 bindings_ctx: &mut FakeBindingsCtx,
1306 link_addr: UnicastAddr<Mac>,
1307 body: S,
1308 tx_meta: FakeTxMetadata,
1309 ) -> Result<(), SendFrameError<S>>
1310 where
1311 S: NetworkSerializer,
1312 S::Buffer: BufferMut,
1313 {
1314 let Self { core_ctx, device_id } = self;
1315 send_as_ethernet_frame_to_dst(
1316 *core_ctx,
1317 bindings_ctx,
1318 device_id,
1319 link_addr.get(),
1320 body,
1321 EtherType::Ipv4,
1322 tx_meta,
1323 )
1324 }
1325 }
1326
1327 impl TransmitQueueBindingsContext<FakeDeviceId> for FakeBindingsCtx {
1328 fn wake_tx_task(&mut self, FakeDeviceId: &FakeDeviceId) {
1329 unimplemented!("unused by tests")
1330 }
1331 }
1332
1333 impl EventContext<EthernetDeviceEvent<FakeDeviceId>> for FakeBindingsCtx {
1334 fn on_event(&mut self, event: EthernetDeviceEvent<FakeDeviceId>) {
1335 match event {
1337 EthernetDeviceEvent::MulticastJoin { device, addr } => {
1338 assert!(
1339 self.state.link_multicast_group_memberships.insert((device, addr)),
1340 "membership should not be present"
1341 );
1342 }
1343 EthernetDeviceEvent::MulticastLeave { device, addr } => {
1344 assert!(
1345 self.state.link_multicast_group_memberships.remove(&(device, addr)),
1346 "membership should be present"
1347 );
1348 }
1349 }
1350 }
1351 }
1352
1353 impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1354 type Meta = FakeTxMetadata;
1355
1356 type DequeueContext = Never;
1357
1358 fn parse_outgoing_frame<'a>(
1359 buf: &'a [u8],
1360 meta: &'a Self::Meta,
1361 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1362 FakeInnerCtx::parse_outgoing_frame(buf, meta)
1363 }
1364 }
1365
1366 impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1367 type Meta = FakeTxMetadata;
1368
1369 type DequeueContext = Never;
1370
1371 fn parse_outgoing_frame<'a, 'b>(
1372 buf: &'a [u8],
1373 _tx_meta: &'b Self::Meta,
1374 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1375 SentFrame::try_parse_as_ethernet(buf)
1376 }
1377 }
1378
1379 impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1380 fn with_transmit_queue_mut<
1381 O,
1382 F: FnOnce(
1383 &mut TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>,
1384 ) -> O,
1385 >(
1386 &mut self,
1387 device_id: &Self::DeviceId,
1388 cb: F,
1389 ) -> O {
1390 self.inner.with_transmit_queue_mut(device_id, cb)
1391 }
1392
1393 fn with_transmit_queue<
1394 O,
1395 F: FnOnce(&TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>) -> O,
1396 >(
1397 &mut self,
1398 device_id: &Self::DeviceId,
1399 cb: F,
1400 ) -> O {
1401 self.inner.with_transmit_queue(device_id, cb)
1402 }
1403
1404 fn send_frame(
1405 &mut self,
1406 bindings_ctx: &mut FakeBindingsCtx,
1407 device_id: &Self::DeviceId,
1408 dequeue_context: Option<&mut Never>,
1409 tx_meta: Self::Meta,
1410 buf: packet::Buf<Vec<u8>>,
1411 ) -> Result<(), DeviceSendFrameError> {
1412 TransmitQueueContext::send_frame(
1413 &mut self.inner,
1414 bindings_ctx,
1415 device_id,
1416 dequeue_context,
1417 tx_meta,
1418 buf,
1419 )
1420 }
1421 }
1422
1423 impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx
1424 where
1425 Self: TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx, Meta = FakeTxMetadata>,
1426 {
1427 fn with_transmit_queue_mut<
1428 O,
1429 F: FnOnce(
1430 &mut TransmitQueueState<
1431 Self::Meta,
1432 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1433 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1434 >,
1435 ) -> O,
1436 >(
1437 &mut self,
1438 _device_id: &Self::DeviceId,
1439 cb: F,
1440 ) -> O {
1441 cb(&mut self.state.tx_queue)
1442 }
1443
1444 fn with_transmit_queue<
1445 O,
1446 F: FnOnce(
1447 &TransmitQueueState<
1448 Self::Meta,
1449 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1450 <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1451 >,
1452 ) -> O,
1453 >(
1454 &mut self,
1455 _device_id: &Self::DeviceId,
1456 cb: F,
1457 ) -> O {
1458 cb(&self.state.tx_queue)
1459 }
1460
1461 fn send_frame(
1462 &mut self,
1463 _bindings_ctx: &mut FakeBindingsCtx,
1464 device_id: &Self::DeviceId,
1465 dequeue_context: Option<&mut Never>,
1466 _tx_meta: Self::Meta,
1467 buf: packet::Buf<Vec<u8>>,
1468 ) -> Result<(), DeviceSendFrameError> {
1469 match dequeue_context {
1470 Some(never) => match *never {},
1471 None => (),
1472 }
1473 self.frames.push(device_id.clone(), buf.as_ref().to_vec());
1474 Ok(())
1475 }
1476 }
1477
1478 impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtx {
1479 type DeviceId = FakeDeviceId;
1480 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1481 }
1482
1483 impl DeviceIdContext<EthernetLinkDevice> for FakeInnerCtx {
1484 type DeviceId = FakeDeviceId;
1485 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1486 }
1487
1488 impl CounterContext<ArpCounters> for FakeCoreCtx {
1489 fn counters(&self) -> &ArpCounters {
1490 &self.inner.state.arp_counters
1491 }
1492 }
1493
1494 #[test]
1495 fn test_mtu() {
1496 fn test(size: usize, expect_frames_sent: bool) {
1500 let mut ctx = new_context();
1501 NeighborApi::<Ipv4, EthernetLinkDevice, _>::new(ctx.as_mut())
1502 .insert_static_entry(
1503 &FakeDeviceId,
1504 TEST_ADDRS_V4.remote_ip.get(),
1505 TEST_ADDRS_V4.remote_mac,
1506 )
1507 .unwrap();
1508 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1509 let result = send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1510 core_ctx,
1511 bindings_ctx,
1512 &FakeDeviceId,
1513 IpPacketDestination::<Ipv4, _>::Neighbor(TEST_ADDRS_V4.remote_ip),
1514 Buf::new(&mut vec![0; size], ..),
1515 FakeTxMetadata::default(),
1516 )
1517 .map_err(|_serializer| ());
1518 let sent_frames = core_ctx.inner.frames().len();
1519 if expect_frames_sent {
1520 assert_eq!(sent_frames, 1);
1521 result.expect("should succeed");
1522 } else {
1523 assert_eq!(sent_frames, 0);
1524 result.expect_err("should fail");
1525 }
1526 }
1527
1528 test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap(), true);
1529 test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap() + 1, false);
1530 }
1531
1532 #[test]
1533 fn broadcast() {
1534 let mut ctx = new_context();
1535 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1536 send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1537 core_ctx,
1538 bindings_ctx,
1539 &FakeDeviceId,
1540 IpPacketDestination::<Ipv4, _>::Broadcast(()),
1541 Buf::new(&mut vec![0; 100], ..),
1542 FakeTxMetadata::default(),
1543 )
1544 .map_err(|_serializer| ())
1545 .expect("send_ip_frame should succeed");
1546 let sent_frames = core_ctx.inner.frames().len();
1547 assert_eq!(sent_frames, 1);
1548 let (FakeDeviceId, frame) = core_ctx.inner.frames()[0].clone();
1549 let (_body, _src_mac, dst_mac, _ether_type) =
1550 parse_ethernet_frame(&frame, EthernetFrameLengthCheck::NoCheck).unwrap();
1551 assert_eq!(dst_mac, Mac::BROADCAST);
1552 }
1553
1554 #[test]
1555 fn test_join_link_multicast() {
1556 let mut ctx = new_context();
1557 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1558
1559 let address1: MulticastAddr<Mac> =
1560 MulticastAddr::new(Ipv4Addr::new([224, 0, 0, 200])).unwrap().into();
1561 let address2: MulticastAddr<Mac> =
1562 MulticastAddr::new(Ipv4Addr::new([224, 0, 10, 30])).unwrap().into();
1563
1564 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1565 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1566 join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1567
1568 assert_eq!(
1569 bindings_ctx.state.link_multicast_group_memberships,
1570 HashSet::from_iter([(FakeDeviceId, address1), (FakeDeviceId, address2)])
1571 );
1572
1573 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1574
1575 assert_eq!(
1576 bindings_ctx.state.link_multicast_group_memberships,
1577 HashSet::from_iter([(FakeDeviceId, address2)])
1578 );
1579
1580 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1582
1583 assert_eq!(
1584 bindings_ctx.state.link_multicast_group_memberships,
1585 HashSet::from_iter([(FakeDeviceId, address2)])
1586 );
1587
1588 leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1589
1590 assert_eq!(bindings_ctx.state.link_multicast_group_memberships, HashSet::new());
1591 }
1592}