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