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