netstack3_device/
ethernet.rs

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