Skip to main content

netstack3_device/
ethernet.rs

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