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