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