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