Skip to main content

netstack3_device/
ethernet.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! The Ethernet protocol.
6
7use 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
54/// The execution context for an Ethernet device provided by bindings.
55pub trait EthernetIpLinkDeviceBindingsContext:
56    RngContext + TimerContext + DeviceLayerTypes + TxMetadataBindingsTypes
57{
58}
59impl<BC: RngContext + TimerContext + DeviceLayerTypes + TxMetadataBindingsTypes>
60    EthernetIpLinkDeviceBindingsContext for BC
61{
62}
63
64/// The execution context for an Ethernet device provided by bindings.
65///
66/// This context trait is separate from `EthernetIpLinkDeviceBindingsContext` to prevent
67/// trait bound resolution cycles.
68pub trait EthernetDeviceEventBindingsContext<DeviceId>:
69    EventContext<EthernetDeviceEvent<DeviceId>>
70{
71}
72impl<BC: EventContext<EthernetDeviceEvent<DeviceId>>, DeviceId>
73    EthernetDeviceEventBindingsContext<DeviceId> for BC
74{
75}
76
77/// Provides access to an ethernet device's static state.
78pub trait EthernetIpLinkDeviceStaticStateContext: DeviceIdContext<EthernetLinkDevice> {
79    /// Calls the function with an immutable reference to the ethernet device's
80    /// static state.
81    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
88/// Provides access to an ethernet device's dynamic state.
89pub trait EthernetIpLinkDeviceDynamicStateContext<BC: EthernetIpLinkDeviceBindingsContext>:
90    EthernetIpLinkDeviceStaticStateContext
91{
92    /// Calls the function with the ethernet device's static state and immutable
93    /// reference to the dynamic state.
94    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    /// Calls the function with the ethernet device's static state and mutable
104    /// reference to the dynamic state.
105    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/// Events emitted from ethernet devices.
116#[derive(Debug, PartialEq, Eq, Hash)]
117pub enum EthernetDeviceEvent<D> {
118    /// Device joined a new multicast group.
119    MulticastJoin {
120        /// The device.
121        device: D,
122        /// The address of the multicast group.
123        addr: MulticastAddr<Mac>,
124    },
125
126    /// Device left a multicast group.
127    MulticastLeave {
128        /// The device.
129        device: D,
130        /// The address of the multicast group.
131        addr: MulticastAddr<Mac>,
132    },
133}
134
135impl<D> EthernetDeviceEvent<D> {
136    /// Maps the contained device ID type.
137    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
149/// Send an Ethernet frame `body` directly to `dst_mac` with `ether_type`.
150pub 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    /// The minimum body length for the Ethernet frame.
168    ///
169    /// Using a frame length of 0 improves efficiency by avoiding unnecessary
170    /// padding at this layer. The expectation is that the implementation of
171    /// bindings will add any padding required by the implementation.
172    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/// The maximum frame size one ethernet device can send.
228///
229/// The frame size includes the ethernet header, the data payload, but excludes
230/// the 4 bytes from FCS (frame check sequence) as we don't calculate CRC and it
231/// is normally handled by the device.
232#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
233pub struct MaxEthernetFrameSize(NonZeroU32);
234
235impl MaxEthernetFrameSize {
236    /// The minimum ethernet frame size.
237    ///
238    /// We don't care about FCS, so the minimum frame size for us is 64 - 4.
239    pub const MIN: MaxEthernetFrameSize = MaxEthernetFrameSize(NonZeroU32::new(60).unwrap());
240
241    /// Creates from the maximum size of ethernet header and ethernet payload,
242    /// checks that it is valid, i.e., larger than the minimum frame size.
243    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    /// Converts the maximum frame size to its corresponding MTU.
256    pub const fn as_mtu(&self) -> Mtu {
257        // MTU must be positive because of the limit on minimum ethernet frame size
258        Mtu::new(self.get().get().saturating_sub(ETHERNET_HDR_LEN_NO_TAG_U32))
259    }
260
261    /// Creates the maximum ethernet frame size from MTU.
262    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/// Base properties to create a new Ethernet device.
275#[derive(Debug)]
276pub struct EthernetCreationProperties {
277    /// The device's MAC address.
278    pub mac: UnicastAddr<Mac>,
279    /// The maximum frame size this device supports.
280    // TODO(https://fxbug.dev/42072516): Add a minimum frame size for all
281    // Ethernet devices such that you can't create an `EthernetDeviceState`
282    // with a `MaxEthernetFrameSize` smaller than the minimum. The absolute minimum
283    // needs to be at least the minimum body size of an Ethernet frame. For
284    // IPv6-capable devices, the minimum needs to be higher - the frame size
285    // implied by the IPv6 minimum MTU. The easy path is to simply use that
286    // frame size as the minimum in all cases, although we may at some point
287    // want to figure out how to configure devices which don't support IPv6,
288    // and allow smaller frame sizes for those devices.
289    pub max_frame_size: MaxEthernetFrameSize,
290}
291
292/// Ethernet device state that can change at runtime.
293pub struct DynamicEthernetDeviceState {
294    /// The value this netstack assumes as the device's maximum frame size.
295    max_frame_size: MaxEthernetFrameSize,
296
297    /// Link multicast groups this device has joined.
298    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
307/// Ethernet device state that is fixed after creation.
308pub struct StaticEthernetDeviceState {
309    /// Mac address of the device this state is for.
310    mac: UnicastAddr<Mac>,
311
312    /// The maximum frame size allowed by the hardware.
313    max_frame_size: MaxEthernetFrameSize,
314}
315
316/// The state associated with an Ethernet device.
317pub struct EthernetDeviceState<BT: NudBindingsTypes<EthernetLinkDevice>> {
318    /// Ethernet device counters.
319    pub counters: EthernetDeviceCounters,
320    /// Immutable Ethernet device state.
321    pub static_state: StaticEthernetDeviceState,
322    /// Ethernet device transmit queue.
323    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/// A timer ID for Ethernet devices.
391///
392/// `D` is the type of device ID that identifies different Ethernet devices.
393#[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
424/// Send an IP packet in an Ethernet frame.
425///
426/// `send_ip_frame` accepts a device ID, a local IP address, and a
427/// serializer. It computes the routing information, serializes
428/// the serializer, and sends the resulting buffer in a new Ethernet
429/// frame.
430pub 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
492/// Metadata for received ethernet frames.
493pub struct RecvEthernetFrameMeta<D> {
494    /// The device a frame was received on.
495    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!("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        // NOTE(joshlf): We do not currently validate that the Ethernet frame
527        // satisfies the minimum length requirement. We expect that if this
528        // requirement is necessary (due to requirements of the physical medium),
529        // the driver or hardware will have checked it, and that if this requirement
530        // is not necessary, it is acceptable for us to operate on a smaller
531        // Ethernet frame. If this becomes insufficient in the future, we may want
532        // to consider making this behavior configurable (at compile time, at
533        // runtime on a global basis, or at runtime on a per-device basis).
534        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 src = ethernet.src_mac();
546        let dst = ethernet.dst_mac();
547
548        let frame_dst = core_ctx.with_static_ethernet_device_state(&device_id, |static_state| {
549            FrameDestination::from_dest(dst, static_state.mac.get())
550        });
551
552        let ethertype = ethernet.ethertype();
553
554        core_ctx.handle_frame(
555            bindings_ctx,
556            &device_id,
557            ReceivedFrame::from_ethernet(ethernet, frame_dst).into(),
558            whole_frame,
559        );
560
561        match ethertype {
562            Some(EtherType::Arp) => {
563                let types = if let Ok(types) = peek_arp_types(buffer.as_ref()) {
564                    types
565                } else {
566                    return;
567                };
568                match types {
569                    (ArpHardwareType::Ethernet, ArpNetworkType::Ipv4) => {
570                        ArpPacketHandler::handle_packet(
571                            core_ctx,
572                            bindings_ctx,
573                            device_id,
574                            src,
575                            frame_dst,
576                            buffer,
577                        )
578                    }
579                }
580            }
581            Some(EtherType::Ipv4) => {
582                core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
583                    &counters.recv_ipv4_delivered
584                });
585                core_ctx.receive_frame(
586                    bindings_ctx,
587                    RecvIpFrameMeta::<_, _, Ipv4>::new(
588                        device_id,
589                        Some(frame_dst),
590                        DeviceIpLayerMetadata::default(),
591                    ),
592                    buffer,
593                )
594            }
595            Some(EtherType::Ipv6) => {
596                core_ctx.increment_both(&device_id, |counters: &DeviceCounters| {
597                    &counters.recv_ipv6_delivered
598                });
599                core_ctx.receive_frame(
600                    bindings_ctx,
601                    RecvIpFrameMeta::<_, _, Ipv6>::new(
602                        device_id,
603                        Some(frame_dst),
604                        DeviceIpLayerMetadata::default(),
605                    ),
606                    buffer,
607                )
608            }
609            Some(EtherType::Other(_)) => {
610                core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
611                    &counters.recv_unsupported_ethertype
612                });
613            }
614            None => {
615                core_ctx.increment_both(&device_id, |counters: &EthernetDeviceCounters| {
616                    &counters.recv_no_ethertype
617                });
618            }
619        }
620    }
621}
622
623/// Add `device_id` to a link multicast group `multicast_addr`.
624///
625/// Calling `join_link_multicast` with the same `device_id` and `multicast_addr`
626/// is completely safe. A counter will be kept for the number of times
627/// `join_link_multicast` has been called with the same `device_id` and
628/// `multicast_addr` pair. To completely leave a multicast group,
629/// [`leave_link_multicast`] must be called the same number of times
630/// `join_link_multicast` has been called for the same `device_id` and
631/// `multicast_addr` pair. The first time `join_link_multicast` is called for a
632/// new `device` and `multicast_addr` pair, the device will actually join the
633/// multicast group.
634///
635/// `join_link_multicast` is different from [`join_ip_multicast`] as
636/// `join_link_multicast` joins an L2 multicast group, whereas
637/// `join_ip_multicast` joins an L3 multicast group.
638pub fn join_link_multicast<
639    BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
640    CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
641>(
642    core_ctx: &mut CC,
643    bindings_ctx: &mut BC,
644    device_id: &CC::DeviceId,
645    multicast_addr: MulticastAddr<Mac>,
646) {
647    core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
648        let groups = &mut dynamic_state.link_multicast_groups;
649
650        match groups.insert(multicast_addr) {
651            InsertResult::Inserted(()) => {
652                trace!(
653                    "ethernet::join_link_multicast: joining link multicast {:?}",
654                    multicast_addr
655                );
656                bindings_ctx.on_event(EthernetDeviceEvent::MulticastJoin {
657                    device: device_id.clone(),
658                    addr: multicast_addr,
659                });
660            }
661            InsertResult::AlreadyPresent => {
662                trace!(
663                    "ethernet::join_link_multicast: already joined link multicast {:?}",
664                    multicast_addr,
665                );
666            }
667        }
668    })
669}
670
671/// Remove `device_id` from a link multicast group `multicast_addr`.
672///
673/// `leave_link_multicast` will attempt to remove `device_id` from the multicast
674/// group `multicast_addr`. `device_id` may have "joined" the same multicast
675/// address multiple times, so `device_id` will only leave the multicast group
676/// once `leave_ip_multicast` has been called for each corresponding
677/// [`join_link_multicast`]. That is, if `join_link_multicast` gets called 3
678/// times and `leave_link_multicast` gets called two times (after all 3
679/// `join_link_multicast` calls), `device_id` will still be in the multicast
680/// group until the next (final) call to `leave_link_multicast`.
681///
682/// `leave_link_multicast` is different from [`leave_ip_multicast`] as
683/// `leave_link_multicast` leaves an L2 multicast group, whereas
684/// `leave_ip_multicast` leaves an L3 multicast group.
685///
686/// # Panics
687///
688/// If `device_id` is not in the multicast group `multicast_addr`.
689pub fn leave_link_multicast<
690    BC: EthernetIpLinkDeviceBindingsContext + EthernetDeviceEventBindingsContext<CC::DeviceId>,
691    CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
692>(
693    core_ctx: &mut CC,
694    bindings_ctx: &mut BC,
695    device_id: &CC::DeviceId,
696    multicast_addr: MulticastAddr<Mac>,
697) {
698    core_ctx.with_ethernet_state_mut(device_id, |_static_state, dynamic_state| {
699        let groups = &mut dynamic_state.link_multicast_groups;
700
701        match groups.remove(multicast_addr) {
702            RemoveResult::Removed(()) => {
703                trace!(
704                    "ethernet::leave_link_multicast: \
705                    leaving link multicast {:?}",
706                    multicast_addr
707                );
708                bindings_ctx.on_event(EthernetDeviceEvent::MulticastLeave {
709                    device: device_id.clone(),
710                    addr: multicast_addr,
711                });
712            }
713            RemoveResult::StillPresent => {
714                trace!(
715                    "ethernet::leave_link_multicast: not leaving link multicast \
716                    {:?} as there are still listeners for it",
717                    multicast_addr,
718                );
719            }
720            RemoveResult::NotPresent => {
721                panic!(
722                    "ethernet::leave_link_multicast: device {:?} has not yet \
723                    joined link multicast {:?}",
724                    device_id, multicast_addr,
725                );
726            }
727        }
728    })
729}
730
731pub fn get_max_frame_size<
732    BC: EthernetIpLinkDeviceBindingsContext,
733    CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
734>(
735    core_ctx: &mut CC,
736    device_id: &CC::DeviceId,
737) -> MaxEthernetFrameSize {
738    core_ctx
739        .with_ethernet_state(device_id, |_static_state, dynamic_state| dynamic_state.max_frame_size)
740}
741
742/// Get the MTU associated with this device.
743pub fn get_mtu<
744    BC: EthernetIpLinkDeviceBindingsContext,
745    CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
746>(
747    core_ctx: &mut CC,
748    device_id: &CC::DeviceId,
749) -> Mtu {
750    get_max_frame_size(core_ctx, device_id).as_mtu()
751}
752
753/// Enables a blanket implementation of [`SendableFrameData`] for
754/// [`ArpFrameMetadata`].
755///
756/// Implementing this marker trait for a type enables a blanket implementation
757/// of `SendableFrameData` given the other requirements are met.
758pub trait UseArpFrameMetadataBlanket {}
759
760impl<
761    BC: EthernetIpLinkDeviceBindingsContext,
762    CC: EthernetIpLinkDeviceDynamicStateContext<BC>
763        + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
764        + ResourceCounterContext<CC::DeviceId, DeviceCounters>
765        + UseArpFrameMetadataBlanket,
766> SendableFrameMeta<CC, BC> for ArpFrameMetadata<EthernetLinkDevice, CC::DeviceId>
767{
768    fn send_meta<S>(
769        self,
770        core_ctx: &mut CC,
771        bindings_ctx: &mut BC,
772        body: S,
773    ) -> Result<(), SendFrameError<S>>
774    where
775        S: Serializer,
776        S::Buffer: BufferMut,
777    {
778        let Self { device_id, dst_addr } = self;
779        let meta: BC::TxMetadata = Default::default();
780        send_as_ethernet_frame_to_dst(
781            core_ctx,
782            bindings_ctx,
783            &device_id,
784            dst_addr,
785            body,
786            EtherType::Arp,
787            meta,
788        )
789    }
790}
791
792impl DeviceSocketSendTypes for EthernetLinkDevice {
793    /// When `None`, data will be sent as a raw Ethernet frame without any
794    /// system-applied headers.
795    type Metadata = Option<EthernetHeaderParams>;
796}
797
798impl<
799    BC: EthernetIpLinkDeviceBindingsContext,
800    CC: EthernetIpLinkDeviceDynamicStateContext<BC>
801        + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>
802        + ResourceCounterContext<CC::DeviceId, DeviceCounters>,
803> SendableFrameMeta<CC, BC> for DeviceSocketMetadata<EthernetLinkDevice, EthernetDeviceId<BC>>
804where
805    CC: DeviceIdContext<EthernetLinkDevice, DeviceId = EthernetDeviceId<BC>>,
806{
807    fn send_meta<S>(
808        self,
809        core_ctx: &mut CC,
810        bindings_ctx: &mut BC,
811        body: S,
812    ) -> Result<(), SendFrameError<S>>
813    where
814        S: Serializer,
815        S::Buffer: BufferMut,
816    {
817        let Self { device_id, metadata } = self;
818        // TODO(https://fxbug.dev/391946195): Apply send buffer enforcement from
819        // device sockets instead of using default.
820        let tx_meta: BC::TxMetadata = Default::default();
821        match metadata {
822            Some(EthernetHeaderParams { dest_addr, protocol }) => send_as_ethernet_frame_to_dst(
823                core_ctx,
824                bindings_ctx,
825                &device_id,
826                dest_addr,
827                body,
828                protocol,
829                tx_meta,
830            ),
831            None => send_ethernet_frame(core_ctx, bindings_ctx, &device_id, body, tx_meta),
832        }
833    }
834}
835
836/// Gets `device_id`'s MAC address.
837pub fn get_mac<
838    'a,
839    BC: EthernetIpLinkDeviceBindingsContext,
840    CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
841>(
842    core_ctx: &'a mut CC,
843    device_id: &CC::DeviceId,
844) -> UnicastAddr<Mac> {
845    core_ctx.with_static_ethernet_device_state(device_id, |state| state.mac)
846}
847
848/// Sets `device_id`'s MTU.
849pub fn set_mtu<
850    BC: EthernetIpLinkDeviceBindingsContext,
851    CC: EthernetIpLinkDeviceDynamicStateContext<BC>,
852>(
853    core_ctx: &mut CC,
854    device_id: &CC::DeviceId,
855    mtu: Mtu,
856) {
857    core_ctx.with_ethernet_state_mut(device_id, |static_state, dynamic_state| {
858        if let Some(mut frame_size ) = MaxEthernetFrameSize::from_mtu(mtu) {
859            // If `frame_size` is greater than what the device supports, set it
860            // to maximum frame size the device supports.
861            if frame_size > static_state.max_frame_size {
862                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());
863                frame_size = static_state.max_frame_size;
864            }
865            trace!("ethernet::ndp_device::set_mtu: setting link MTU to {:?}", mtu);
866            dynamic_state.max_frame_size = frame_size;
867        }
868    })
869}
870
871/// An implementation of the [`LinkDevice`] trait for Ethernet devices.
872#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
873pub enum EthernetLinkDevice {}
874
875impl Device for EthernetLinkDevice {}
876
877impl LinkDevice for EthernetLinkDevice {
878    type Address = Mac;
879}
880
881impl DeviceStateSpec for EthernetLinkDevice {
882    type State<BT: DeviceLayerTypes> = EthernetDeviceState<BT>;
883    type External<BT: DeviceLayerTypes> = BT::EthernetDeviceState;
884    type CreationProperties = EthernetCreationProperties;
885    type Counters = EthernetDeviceCounters;
886    type TimerId<D: WeakDeviceIdentifier> = EthernetTimerId<D>;
887
888    fn new_device_state<
889        CC: CoreTimerContext<Self::TimerId<CC::WeakDeviceId>, BC> + DeviceIdContext<Self>,
890        BC: DeviceLayerTypes + TimerContext,
891    >(
892        bindings_ctx: &mut BC,
893        self_id: CC::WeakDeviceId,
894        EthernetCreationProperties { mac, max_frame_size }: Self::CreationProperties,
895    ) -> Self::State<BC> {
896        let ipv4_arp = Mutex::new(ArpState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
897            bindings_ctx,
898            self_id.clone(),
899        ));
900        let ipv6_nud =
901            Mutex::new(NudState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx, self_id));
902        EthernetDeviceState {
903            counters: Default::default(),
904            ipv4_arp,
905            ipv6_nud,
906            ipv4_nud_config: Default::default(),
907            ipv6_nud_config: Default::default(),
908            static_state: StaticEthernetDeviceState { mac, max_frame_size },
909            dynamic_state: RwLock::new(DynamicEthernetDeviceState::new(max_frame_size)),
910            tx_queue: Default::default(),
911        }
912    }
913    const IS_LOOPBACK: bool = false;
914    const DEBUG_TYPE: &'static str = "Ethernet";
915}
916
917#[cfg(any(test, feature = "testutils"))]
918pub(crate) mod testutil {
919    use super::*;
920
921    /// The mimum implied maximum Ethernet frame size for IPv6.
922    pub const IPV6_MIN_IMPLIED_MAX_FRAME_SIZE: MaxEthernetFrameSize =
923        MaxEthernetFrameSize::from_mtu(Ipv6::MINIMUM_LINK_MTU).unwrap();
924}
925
926#[cfg(test)]
927mod tests {
928    use alloc::vec;
929    use core::convert::Infallible as Never;
930    use netstack3_hashmap::HashSet;
931
932    use net_types::SpecifiedAddr;
933    use net_types::ip::{Ipv4Addr, Ipv6Addr};
934    use netstack3_base::testutil::{
935        FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId, TEST_ADDRS_V4,
936    };
937    use netstack3_base::{CounterContext, CtxPair, IntoCoreTimerCtx};
938    use netstack3_ip::nud::{
939        self, DelegateNudContext, DynamicNeighborUpdateSource, NeighborApi, UseDelegateNudContext,
940    };
941    use packet_formats::testutil::parse_ethernet_frame;
942
943    use super::*;
944    use crate::internal::arp::{
945        ArpConfigContext, ArpContext, ArpCounters, ArpNudCtx, ArpSenderContext,
946    };
947    use crate::internal::base::DeviceSendFrameError;
948    use crate::internal::ethernet::testutil::IPV6_MIN_IMPLIED_MAX_FRAME_SIZE;
949    use crate::internal::queue::tx::{
950        TransmitQueueBindingsContext, TransmitQueueCommon, TransmitQueueContext,
951    };
952    use crate::internal::socket::{Frame, ParseSentFrameError, SentFrame};
953
954    struct FakeEthernetCtx {
955        static_state: StaticEthernetDeviceState,
956        dynamic_state: DynamicEthernetDeviceState,
957        tx_queue: TransmitQueueState<FakeTxMetadata, Buf<Vec<u8>>, BufVecU8Allocator>,
958        counters: DeviceCounters,
959        per_device_counters: DeviceCounters,
960        ethernet_counters: EthernetDeviceCounters,
961        arp_counters: ArpCounters,
962    }
963
964    impl FakeEthernetCtx {
965        fn new(mac: UnicastAddr<Mac>, max_frame_size: MaxEthernetFrameSize) -> FakeEthernetCtx {
966            FakeEthernetCtx {
967                static_state: StaticEthernetDeviceState { max_frame_size, mac },
968                dynamic_state: DynamicEthernetDeviceState::new(max_frame_size),
969                tx_queue: Default::default(),
970                counters: Default::default(),
971                per_device_counters: Default::default(),
972                ethernet_counters: Default::default(),
973                arp_counters: Default::default(),
974            }
975        }
976    }
977
978    type FakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
979        EthernetTimerId<FakeWeakDeviceId<FakeDeviceId>>,
980        nud::Event<Mac, FakeDeviceId, Ipv4, FakeInstant>,
981        FakeBindingsState,
982        (),
983    >;
984
985    #[derive(Default)]
986    struct FakeBindingsState {
987        link_multicast_group_memberships: HashSet<(FakeDeviceId, MulticastAddr<Mac>)>,
988    }
989
990    type FakeInnerCtx =
991        netstack3_base::testutil::FakeCoreCtx<FakeEthernetCtx, FakeDeviceId, FakeDeviceId>;
992
993    struct FakeCoreCtx {
994        arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtx>,
995        inner: FakeInnerCtx,
996    }
997
998    fn new_context() -> CtxPair<FakeCoreCtx, FakeBindingsCtx> {
999        CtxPair::with_default_bindings_ctx(|bindings_ctx| FakeCoreCtx {
1000            arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
1001                bindings_ctx,
1002                FakeWeakDeviceId(FakeDeviceId),
1003            ),
1004            inner: FakeInnerCtx::with_state(FakeEthernetCtx::new(
1005                TEST_ADDRS_V4.local_mac,
1006                IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1007            )),
1008        })
1009    }
1010
1011    impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1012        fn handle_frame(
1013            &mut self,
1014            bindings_ctx: &mut FakeBindingsCtx,
1015            device: &Self::DeviceId,
1016            frame: Frame<&[u8]>,
1017            whole_frame: &[u8],
1018        ) {
1019            self.inner.handle_frame(bindings_ctx, device, frame, whole_frame)
1020        }
1021    }
1022
1023    impl CounterContext<DeviceCounters> for FakeCoreCtx {
1024        fn counters(&self) -> &DeviceCounters {
1025            &self.inner.state.counters
1026        }
1027    }
1028
1029    impl CounterContext<DeviceCounters> for FakeInnerCtx {
1030        fn counters(&self) -> &DeviceCounters {
1031            &self.state.counters
1032        }
1033    }
1034
1035    impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeCoreCtx {
1036        fn per_resource_counters<'a>(
1037            &'a self,
1038            &FakeDeviceId: &'a FakeDeviceId,
1039        ) -> &'a DeviceCounters {
1040            &self.inner.state.per_device_counters
1041        }
1042    }
1043
1044    impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeInnerCtx {
1045        fn per_resource_counters<'a>(
1046            &'a self,
1047            &FakeDeviceId: &'a FakeDeviceId,
1048        ) -> &'a DeviceCounters {
1049            &self.state.per_device_counters
1050        }
1051    }
1052
1053    impl CounterContext<EthernetDeviceCounters> for FakeCoreCtx {
1054        fn counters(&self) -> &EthernetDeviceCounters {
1055            &self.inner.state.ethernet_counters
1056        }
1057    }
1058
1059    impl CounterContext<EthernetDeviceCounters> for FakeInnerCtx {
1060        fn counters(&self) -> &EthernetDeviceCounters {
1061            &self.state.ethernet_counters
1062        }
1063    }
1064
1065    impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1066        fn handle_frame(
1067            &mut self,
1068            _bindings_ctx: &mut FakeBindingsCtx,
1069            _device: &Self::DeviceId,
1070            _frame: Frame<&[u8]>,
1071            _whole_frame: &[u8],
1072        ) {
1073            // No-op: don't deliver frames.
1074        }
1075    }
1076
1077    impl EthernetIpLinkDeviceStaticStateContext for FakeCoreCtx {
1078        fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1079            &mut self,
1080            device_id: &FakeDeviceId,
1081            cb: F,
1082        ) -> O {
1083            self.inner.with_static_ethernet_device_state(device_id, cb)
1084        }
1085    }
1086
1087    impl EthernetIpLinkDeviceStaticStateContext for FakeInnerCtx {
1088        fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1089            &mut self,
1090            &FakeDeviceId: &FakeDeviceId,
1091            cb: F,
1092        ) -> O {
1093            cb(&self.state.static_state)
1094        }
1095    }
1096
1097    impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeCoreCtx {
1098        fn with_ethernet_state<
1099            O,
1100            F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1101        >(
1102            &mut self,
1103            device_id: &FakeDeviceId,
1104            cb: F,
1105        ) -> O {
1106            self.inner.with_ethernet_state(device_id, cb)
1107        }
1108
1109        fn with_ethernet_state_mut<
1110            O,
1111            F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1112        >(
1113            &mut self,
1114            device_id: &FakeDeviceId,
1115            cb: F,
1116        ) -> O {
1117            self.inner.with_ethernet_state_mut(device_id, cb)
1118        }
1119    }
1120
1121    impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeInnerCtx {
1122        fn with_ethernet_state<
1123            O,
1124            F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1125        >(
1126            &mut self,
1127            &FakeDeviceId: &FakeDeviceId,
1128            cb: F,
1129        ) -> O {
1130            let FakeEthernetCtx { static_state, dynamic_state, .. } = &self.state;
1131            cb(static_state, dynamic_state)
1132        }
1133
1134        fn with_ethernet_state_mut<
1135            O,
1136            F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1137        >(
1138            &mut self,
1139            &FakeDeviceId: &FakeDeviceId,
1140            cb: F,
1141        ) -> O {
1142            let FakeEthernetCtx { static_state, dynamic_state, .. } = &mut self.state;
1143            cb(static_state, dynamic_state)
1144        }
1145    }
1146
1147    impl NudHandler<Ipv6, EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1148        fn handle_neighbor_update(
1149            &mut self,
1150            _bindings_ctx: &mut FakeBindingsCtx,
1151            _device_id: &Self::DeviceId,
1152            _neighbor: SpecifiedAddr<Ipv6Addr>,
1153            _source: DynamicNeighborUpdateSource<Mac>,
1154        ) {
1155            unimplemented!()
1156        }
1157
1158        fn flush(&mut self, _bindings_ctx: &mut FakeBindingsCtx, _device_id: &Self::DeviceId) {
1159            unimplemented!()
1160        }
1161
1162        fn send_ip_packet_to_neighbor<S>(
1163            &mut self,
1164            _bindings_ctx: &mut FakeBindingsCtx,
1165            _device_id: &Self::DeviceId,
1166            _neighbor: SpecifiedAddr<Ipv6Addr>,
1167            _body: S,
1168            _tx_meta: FakeTxMetadata,
1169        ) -> Result<(), SendFrameError<S>> {
1170            unimplemented!()
1171        }
1172    }
1173
1174    struct FakeCoreCtxWithDeviceId<'a> {
1175        core_ctx: &'a mut FakeInnerCtx,
1176        device_id: &'a FakeDeviceId,
1177    }
1178
1179    impl<'a> DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxWithDeviceId<'a> {
1180        type DeviceId = FakeDeviceId;
1181        type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1182    }
1183
1184    impl<'a> ArpConfigContext for FakeCoreCtxWithDeviceId<'a> {
1185        fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1186            cb(&NudUserConfig::default())
1187        }
1188    }
1189
1190    impl UseArpFrameMetadataBlanket for FakeCoreCtx {}
1191
1192    impl ArpContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1193        type ConfigCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1194
1195        type ArpSenderCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1196
1197        fn with_arp_state_mut_and_sender_ctx<
1198            O,
1199            F: FnOnce(
1200                &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1201                &mut Self::ArpSenderCtx<'_>,
1202            ) -> O,
1203        >(
1204            &mut self,
1205            device_id: &Self::DeviceId,
1206            cb: F,
1207        ) -> O {
1208            let Self { arp_state, inner } = self;
1209            cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1210        }
1211
1212        fn get_protocol_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Ipv4Addr> {
1213            unimplemented!()
1214        }
1215
1216        fn get_hardware_addr(
1217            &mut self,
1218            _bindings_ctx: &mut FakeBindingsCtx,
1219            _device_id: &Self::DeviceId,
1220        ) -> UnicastAddr<Mac> {
1221            self.inner.state.static_state.mac
1222        }
1223
1224        fn with_arp_state_mut<
1225            O,
1226            F: FnOnce(
1227                &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1228                &mut Self::ConfigCtx<'_>,
1229            ) -> O,
1230        >(
1231            &mut self,
1232            device_id: &Self::DeviceId,
1233            cb: F,
1234        ) -> O {
1235            let Self { arp_state, inner } = self;
1236            cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1237        }
1238
1239        fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtx>) -> O>(
1240            &mut self,
1241            FakeDeviceId: &Self::DeviceId,
1242            cb: F,
1243        ) -> O {
1244            cb(&mut self.arp_state)
1245        }
1246    }
1247
1248    impl UseDelegateNudContext for FakeCoreCtx {}
1249    impl DelegateNudContext<Ipv4> for FakeCoreCtx {
1250        type Delegate<T> = ArpNudCtx<T>;
1251    }
1252
1253    impl ArpConfigContext for FakeInnerCtx {
1254        fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1255            cb(&NudUserConfig::default())
1256        }
1257    }
1258
1259    impl<'a> ArpSenderContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtxWithDeviceId<'a> {
1260        fn send_ip_packet_to_neighbor_link_addr<S>(
1261            &mut self,
1262            bindings_ctx: &mut FakeBindingsCtx,
1263            link_addr: Mac,
1264            body: S,
1265            tx_meta: FakeTxMetadata,
1266        ) -> Result<(), SendFrameError<S>>
1267        where
1268            S: Serializer,
1269            S::Buffer: BufferMut,
1270        {
1271            let Self { core_ctx, device_id } = self;
1272            send_as_ethernet_frame_to_dst(
1273                *core_ctx,
1274                bindings_ctx,
1275                device_id,
1276                link_addr,
1277                body,
1278                EtherType::Ipv4,
1279                tx_meta,
1280            )
1281        }
1282    }
1283
1284    impl TransmitQueueBindingsContext<FakeDeviceId> for FakeBindingsCtx {
1285        fn wake_tx_task(&mut self, FakeDeviceId: &FakeDeviceId) {
1286            unimplemented!("unused by tests")
1287        }
1288    }
1289
1290    impl EventContext<EthernetDeviceEvent<FakeDeviceId>> for FakeBindingsCtx {
1291        fn on_event(&mut self, event: EthernetDeviceEvent<FakeDeviceId>) {
1292            // Panic if we get more than one join or leave event per group.
1293            match event {
1294                EthernetDeviceEvent::MulticastJoin { device, addr } => {
1295                    assert!(
1296                        self.state.link_multicast_group_memberships.insert((device, addr)),
1297                        "membership should not be present"
1298                    );
1299                }
1300                EthernetDeviceEvent::MulticastLeave { device, addr } => {
1301                    assert!(
1302                        self.state.link_multicast_group_memberships.remove(&(device, addr)),
1303                        "membership should be present"
1304                    );
1305                }
1306            }
1307        }
1308    }
1309
1310    impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1311        type Meta = FakeTxMetadata;
1312        type Allocator = BufVecU8Allocator;
1313        type Buffer = Buf<Vec<u8>>;
1314        type DequeueContext = Never;
1315
1316        fn parse_outgoing_frame<'a>(
1317            buf: &'a [u8],
1318            meta: &'a Self::Meta,
1319        ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1320            FakeInnerCtx::parse_outgoing_frame(buf, meta)
1321        }
1322    }
1323
1324    impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1325        type Meta = FakeTxMetadata;
1326        type Allocator = BufVecU8Allocator;
1327        type Buffer = Buf<Vec<u8>>;
1328        type DequeueContext = Never;
1329
1330        fn parse_outgoing_frame<'a, 'b>(
1331            buf: &'a [u8],
1332            _tx_meta: &'b Self::Meta,
1333        ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1334            SentFrame::try_parse_as_ethernet(buf)
1335        }
1336    }
1337
1338    impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1339        fn with_transmit_queue_mut<
1340            O,
1341            F: FnOnce(&mut TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
1342        >(
1343            &mut self,
1344            device_id: &Self::DeviceId,
1345            cb: F,
1346        ) -> O {
1347            self.inner.with_transmit_queue_mut(device_id, cb)
1348        }
1349
1350        fn with_transmit_queue<
1351            O,
1352            F: FnOnce(&TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
1353        >(
1354            &mut self,
1355            device_id: &Self::DeviceId,
1356            cb: F,
1357        ) -> O {
1358            self.inner.with_transmit_queue(device_id, cb)
1359        }
1360
1361        fn send_frame(
1362            &mut self,
1363            bindings_ctx: &mut FakeBindingsCtx,
1364            device_id: &Self::DeviceId,
1365            dequeue_context: Option<&mut Never>,
1366            tx_meta: Self::Meta,
1367            buf: Self::Buffer,
1368        ) -> Result<(), DeviceSendFrameError> {
1369            TransmitQueueContext::send_frame(
1370                &mut self.inner,
1371                bindings_ctx,
1372                device_id,
1373                dequeue_context,
1374                tx_meta,
1375                buf,
1376            )
1377        }
1378    }
1379
1380    impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1381        fn with_transmit_queue_mut<
1382            O,
1383            F: FnOnce(&mut TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
1384        >(
1385            &mut self,
1386            _device_id: &Self::DeviceId,
1387            cb: F,
1388        ) -> O {
1389            cb(&mut self.state.tx_queue)
1390        }
1391
1392        fn with_transmit_queue<
1393            O,
1394            F: FnOnce(&TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
1395        >(
1396            &mut self,
1397            _device_id: &Self::DeviceId,
1398            cb: F,
1399        ) -> O {
1400            cb(&self.state.tx_queue)
1401        }
1402
1403        fn send_frame(
1404            &mut self,
1405            _bindings_ctx: &mut FakeBindingsCtx,
1406            device_id: &Self::DeviceId,
1407            dequeue_context: Option<&mut Never>,
1408            _tx_meta: Self::Meta,
1409            buf: Self::Buffer,
1410        ) -> Result<(), DeviceSendFrameError> {
1411            match dequeue_context {
1412                Some(never) => match *never {},
1413                None => (),
1414            }
1415            self.frames.push(device_id.clone(), buf.as_ref().to_vec());
1416            Ok(())
1417        }
1418    }
1419
1420    impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtx {
1421        type DeviceId = FakeDeviceId;
1422        type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1423    }
1424
1425    impl DeviceIdContext<EthernetLinkDevice> for FakeInnerCtx {
1426        type DeviceId = FakeDeviceId;
1427        type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1428    }
1429
1430    impl CounterContext<ArpCounters> for FakeCoreCtx {
1431        fn counters(&self) -> &ArpCounters {
1432            &self.inner.state.arp_counters
1433        }
1434    }
1435
1436    #[test]
1437    fn test_mtu() {
1438        // Test that we send an Ethernet frame whose size is less than the MTU,
1439        // and that we don't send an Ethernet frame whose size is greater than
1440        // the MTU.
1441        fn test(size: usize, expect_frames_sent: bool) {
1442            let mut ctx = new_context();
1443            NeighborApi::<Ipv4, EthernetLinkDevice, _>::new(ctx.as_mut())
1444                .insert_static_entry(
1445                    &FakeDeviceId,
1446                    TEST_ADDRS_V4.remote_ip.get(),
1447                    TEST_ADDRS_V4.remote_mac.get(),
1448                )
1449                .unwrap();
1450            let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1451            let result = send_ip_frame(
1452                core_ctx,
1453                bindings_ctx,
1454                &FakeDeviceId,
1455                IpPacketDestination::<Ipv4, _>::Neighbor(TEST_ADDRS_V4.remote_ip),
1456                Buf::new(&mut vec![0; size], ..),
1457                FakeTxMetadata::default(),
1458            )
1459            .map_err(|_serializer| ());
1460            let sent_frames = core_ctx.inner.frames().len();
1461            if expect_frames_sent {
1462                assert_eq!(sent_frames, 1);
1463                result.expect("should succeed");
1464            } else {
1465                assert_eq!(sent_frames, 0);
1466                result.expect_err("should fail");
1467            }
1468        }
1469
1470        test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap(), true);
1471        test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap() + 1, false);
1472    }
1473
1474    #[test]
1475    fn broadcast() {
1476        let mut ctx = new_context();
1477        let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1478        send_ip_frame(
1479            core_ctx,
1480            bindings_ctx,
1481            &FakeDeviceId,
1482            IpPacketDestination::<Ipv4, _>::Broadcast(()),
1483            Buf::new(&mut vec![0; 100], ..),
1484            FakeTxMetadata::default(),
1485        )
1486        .map_err(|_serializer| ())
1487        .expect("send_ip_frame should succeed");
1488        let sent_frames = core_ctx.inner.frames().len();
1489        assert_eq!(sent_frames, 1);
1490        let (FakeDeviceId, frame) = core_ctx.inner.frames()[0].clone();
1491        let (_body, _src_mac, dst_mac, _ether_type) =
1492            parse_ethernet_frame(&frame, EthernetFrameLengthCheck::NoCheck).unwrap();
1493        assert_eq!(dst_mac, Mac::BROADCAST);
1494    }
1495
1496    #[test]
1497    fn test_join_link_multicast() {
1498        let mut ctx = new_context();
1499        let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1500
1501        let address1: MulticastAddr<Mac> =
1502            MulticastAddr::new(Ipv4Addr::new([224, 0, 0, 200])).unwrap().into();
1503        let address2: MulticastAddr<Mac> =
1504            MulticastAddr::new(Ipv4Addr::new([224, 0, 10, 30])).unwrap().into();
1505
1506        join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1507        join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1508        join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1509
1510        assert_eq!(
1511            bindings_ctx.state.link_multicast_group_memberships,
1512            HashSet::from_iter([(FakeDeviceId, address1), (FakeDeviceId, address2)])
1513        );
1514
1515        leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1516
1517        assert_eq!(
1518            bindings_ctx.state.link_multicast_group_memberships,
1519            HashSet::from_iter([(FakeDeviceId, address2)])
1520        );
1521
1522        // Since we joined address2 twice, we need to leave it twice as well.
1523        leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1524
1525        assert_eq!(
1526            bindings_ctx.state.link_multicast_group_memberships,
1527            HashSet::from_iter([(FakeDeviceId, address2)])
1528        );
1529
1530        leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1531
1532        assert_eq!(bindings_ctx.state.link_multicast_group_memberships, HashSet::new());
1533    }
1534}