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