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, ChecksumOffloadSpec::default()),
946        }
947    }
948    const IS_LOOPBACK: bool = false;
949    const DEBUG_TYPE: &'static str = "Ethernet";
950}
951
952#[cfg(any(test, feature = "testutils"))]
953pub(crate) mod testutil {
954    use super::*;
955
956    /// The mimum implied maximum Ethernet frame size for IPv6.
957    pub const IPV6_MIN_IMPLIED_MAX_FRAME_SIZE: MaxEthernetFrameSize =
958        MaxEthernetFrameSize::from_mtu(Ipv6::MINIMUM_LINK_MTU).unwrap();
959}
960
961#[cfg(test)]
962mod tests {
963    use alloc::vec;
964    use alloc::vec::Vec;
965    use core::convert::Infallible as Never;
966    use netstack3_hashmap::HashSet;
967
968    use net_types::SpecifiedAddr;
969    use net_types::ip::{Ipv4Addr, Ipv6Addr};
970    use netstack3_base::testutil::{
971        FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId, TEST_ADDRS_V4,
972    };
973    use netstack3_base::{CounterContext, CtxPair, IntoCoreTimerCtx};
974    use netstack3_ip::nud::{
975        self, DelegateNudContext, DynamicNeighborUpdateSource, NeighborApi, UseDelegateNudContext,
976    };
977    use packet::Buf;
978    use packet_formats::testutil::parse_ethernet_frame;
979
980    use super::*;
981    use crate::internal::arp::{
982        ArpConfigContext, ArpContext, ArpCounters, ArpNudCtx, ArpSenderContext,
983    };
984    use crate::internal::base::{DeviceBufferBindingsTypes, DeviceSendFrameError};
985    use crate::internal::ethernet::testutil::IPV6_MIN_IMPLIED_MAX_FRAME_SIZE;
986    use crate::internal::queue::tx::{
987        BufVecU8Allocator, TransmitQueueBindingsContext, TransmitQueueCommon, TransmitQueueContext,
988    };
989    use crate::internal::socket::{Frame, ParseSentFrameError, SentFrame};
990
991    struct FakeEthernetCtx {
992        static_state: StaticEthernetDeviceState,
993        dynamic_state: DynamicEthernetDeviceState,
994        tx_queue: TransmitQueueState<FakeTxMetadata, Buf<Vec<u8>>, BufVecU8Allocator>,
995        counters: DeviceCounters,
996        per_device_counters: DeviceCounters,
997        ethernet_counters: EthernetDeviceCounters,
998        arp_counters: ArpCounters,
999    }
1000
1001    impl FakeEthernetCtx {
1002        fn new(mac: UnicastAddr<Mac>, max_frame_size: MaxEthernetFrameSize) -> FakeEthernetCtx {
1003            FakeEthernetCtx {
1004                static_state: StaticEthernetDeviceState { max_frame_size, mac },
1005                dynamic_state: DynamicEthernetDeviceState::new(max_frame_size),
1006                tx_queue: Default::default(),
1007                counters: Default::default(),
1008                per_device_counters: Default::default(),
1009                ethernet_counters: Default::default(),
1010                arp_counters: Default::default(),
1011            }
1012        }
1013    }
1014
1015    type FakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
1016        EthernetTimerId<FakeWeakDeviceId<FakeDeviceId>>,
1017        nud::Event<Mac, FakeDeviceId, Ipv4, FakeInstant>,
1018        FakeBindingsState,
1019        (),
1020    >;
1021
1022    #[derive(Default)]
1023    struct FakeBindingsState {
1024        link_multicast_group_memberships: HashSet<(FakeDeviceId, MulticastAddr<Mac>)>,
1025    }
1026
1027    type FakeInnerCtx =
1028        netstack3_base::testutil::FakeCoreCtx<FakeEthernetCtx, FakeDeviceId, FakeDeviceId>;
1029
1030    struct FakeCoreCtx {
1031        arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1032        inner: FakeInnerCtx,
1033    }
1034
1035    fn new_context() -> CtxPair<FakeCoreCtx, FakeBindingsCtx> {
1036        CtxPair::with_default_bindings_ctx(|bindings_ctx| FakeCoreCtx {
1037            arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
1038                bindings_ctx,
1039                FakeWeakDeviceId(FakeDeviceId),
1040            ),
1041            inner: FakeInnerCtx::with_state(FakeEthernetCtx::new(
1042                TEST_ADDRS_V4.local_mac,
1043                IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1044            )),
1045        })
1046    }
1047
1048    impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1049        fn handle_frame(
1050            &mut self,
1051            bindings_ctx: &mut FakeBindingsCtx,
1052            device: &Self::DeviceId,
1053            frame: Frame<&[u8]>,
1054            whole_frame: &[u8],
1055        ) {
1056            self.inner.handle_frame(bindings_ctx, device, frame, whole_frame)
1057        }
1058    }
1059
1060    impl CounterContext<DeviceCounters> for FakeCoreCtx {
1061        fn counters(&self) -> &DeviceCounters {
1062            &self.inner.state.counters
1063        }
1064    }
1065
1066    impl CounterContext<DeviceCounters> for FakeInnerCtx {
1067        fn counters(&self) -> &DeviceCounters {
1068            &self.state.counters
1069        }
1070    }
1071
1072    impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeCoreCtx {
1073        fn per_resource_counters<'a>(
1074            &'a self,
1075            &FakeDeviceId: &'a FakeDeviceId,
1076        ) -> &'a DeviceCounters {
1077            &self.inner.state.per_device_counters
1078        }
1079    }
1080
1081    impl ResourceCounterContext<FakeDeviceId, DeviceCounters> for FakeInnerCtx {
1082        fn per_resource_counters<'a>(
1083            &'a self,
1084            &FakeDeviceId: &'a FakeDeviceId,
1085        ) -> &'a DeviceCounters {
1086            &self.state.per_device_counters
1087        }
1088    }
1089
1090    impl CounterContext<EthernetDeviceCounters> for FakeCoreCtx {
1091        fn counters(&self) -> &EthernetDeviceCounters {
1092            &self.inner.state.ethernet_counters
1093        }
1094    }
1095
1096    impl CounterContext<EthernetDeviceCounters> for FakeInnerCtx {
1097        fn counters(&self) -> &EthernetDeviceCounters {
1098            &self.state.ethernet_counters
1099        }
1100    }
1101
1102    impl DeviceSocketHandler<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1103        fn handle_frame(
1104            &mut self,
1105            _bindings_ctx: &mut FakeBindingsCtx,
1106            _device: &Self::DeviceId,
1107            _frame: Frame<&[u8]>,
1108            _whole_frame: &[u8],
1109        ) {
1110            // No-op: don't deliver frames.
1111        }
1112    }
1113
1114    impl EthernetIpLinkDeviceStaticStateContext for FakeCoreCtx {
1115        fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1116            &mut self,
1117            device_id: &FakeDeviceId,
1118            cb: F,
1119        ) -> O {
1120            self.inner.with_static_ethernet_device_state(device_id, cb)
1121        }
1122    }
1123
1124    impl EthernetIpLinkDeviceStaticStateContext for FakeInnerCtx {
1125        fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
1126            &mut self,
1127            &FakeDeviceId: &FakeDeviceId,
1128            cb: F,
1129        ) -> O {
1130            cb(&self.state.static_state)
1131        }
1132    }
1133
1134    impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeCoreCtx {
1135        fn with_ethernet_state<
1136            O,
1137            F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1138        >(
1139            &mut self,
1140            device_id: &FakeDeviceId,
1141            cb: F,
1142        ) -> O {
1143            self.inner.with_ethernet_state(device_id, cb)
1144        }
1145
1146        fn with_ethernet_state_mut<
1147            O,
1148            F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1149        >(
1150            &mut self,
1151            device_id: &FakeDeviceId,
1152            cb: F,
1153        ) -> O {
1154            self.inner.with_ethernet_state_mut(device_id, cb)
1155        }
1156    }
1157
1158    impl EthernetIpLinkDeviceDynamicStateContext<FakeBindingsCtx> for FakeInnerCtx {
1159        fn with_ethernet_state<
1160            O,
1161            F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
1162        >(
1163            &mut self,
1164            &FakeDeviceId: &FakeDeviceId,
1165            cb: F,
1166        ) -> O {
1167            let FakeEthernetCtx { static_state, dynamic_state, .. } = &self.state;
1168            cb(static_state, dynamic_state)
1169        }
1170
1171        fn with_ethernet_state_mut<
1172            O,
1173            F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
1174        >(
1175            &mut self,
1176            &FakeDeviceId: &FakeDeviceId,
1177            cb: F,
1178        ) -> O {
1179            let FakeEthernetCtx { static_state, dynamic_state, .. } = &mut self.state;
1180            cb(static_state, dynamic_state)
1181        }
1182    }
1183
1184    impl NudHandler<Ipv6, EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1185        fn handle_neighbor_update(
1186            &mut self,
1187            _bindings_ctx: &mut FakeBindingsCtx,
1188            _device_id: &Self::DeviceId,
1189            _neighbor: SpecifiedAddr<Ipv6Addr>,
1190            _source: DynamicNeighborUpdateSource<Mac>,
1191        ) {
1192            unimplemented!()
1193        }
1194
1195        fn flush(&mut self, _bindings_ctx: &mut FakeBindingsCtx, _device_id: &Self::DeviceId) {
1196            unimplemented!()
1197        }
1198
1199        fn send_ip_packet_to_neighbor<S>(
1200            &mut self,
1201            _bindings_ctx: &mut FakeBindingsCtx,
1202            _device_id: &Self::DeviceId,
1203            _neighbor: SpecifiedAddr<Ipv6Addr>,
1204            _body: S,
1205            _tx_meta: FakeTxMetadata,
1206        ) -> Result<(), SendFrameError<S>> {
1207            unimplemented!()
1208        }
1209    }
1210
1211    struct FakeCoreCtxWithDeviceId<'a> {
1212        core_ctx: &'a mut FakeInnerCtx,
1213        device_id: &'a FakeDeviceId,
1214    }
1215
1216    impl<'a> DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxWithDeviceId<'a> {
1217        type DeviceId = FakeDeviceId;
1218        type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1219    }
1220
1221    impl<'a> ArpConfigContext for FakeCoreCtxWithDeviceId<'a> {
1222        fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1223            cb(&NudUserConfig::default())
1224        }
1225    }
1226
1227    impl UseArpFrameMetadataBlanket for FakeCoreCtx {}
1228
1229    impl ArpContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1230        type ConfigCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1231
1232        type ArpSenderCtx<'a> = FakeCoreCtxWithDeviceId<'a>;
1233
1234        fn with_arp_state_mut_and_sender_ctx<
1235            O,
1236            F: FnOnce(
1237                &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1238                &mut Self::ArpSenderCtx<'_>,
1239            ) -> O,
1240        >(
1241            &mut self,
1242            device_id: &Self::DeviceId,
1243            cb: F,
1244        ) -> O {
1245            let Self { arp_state, inner } = self;
1246            cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1247        }
1248
1249        fn get_protocol_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Ipv4Addr> {
1250            unimplemented!()
1251        }
1252
1253        fn get_hardware_addr(
1254            &mut self,
1255            _bindings_ctx: &mut FakeBindingsCtx,
1256            _device_id: &Self::DeviceId,
1257        ) -> UnicastAddr<Mac> {
1258            self.inner.state.static_state.mac
1259        }
1260
1261        fn with_arp_state_mut<
1262            O,
1263            F: FnOnce(
1264                &mut ArpState<EthernetLinkDevice, FakeBindingsCtx>,
1265                &mut Self::ConfigCtx<'_>,
1266            ) -> O,
1267        >(
1268            &mut self,
1269            device_id: &Self::DeviceId,
1270            cb: F,
1271        ) -> O {
1272            let Self { arp_state, inner } = self;
1273            cb(arp_state, &mut FakeCoreCtxWithDeviceId { core_ctx: inner, device_id })
1274        }
1275
1276        fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtx>) -> O>(
1277            &mut self,
1278            FakeDeviceId: &Self::DeviceId,
1279            cb: F,
1280        ) -> O {
1281            cb(&mut self.arp_state)
1282        }
1283    }
1284
1285    impl UseDelegateNudContext for FakeCoreCtx {}
1286    impl DelegateNudContext<Ipv4> for FakeCoreCtx {
1287        type Delegate<T> = ArpNudCtx<T>;
1288    }
1289
1290    impl ArpConfigContext for FakeInnerCtx {
1291        fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
1292            cb(&NudUserConfig::default())
1293        }
1294    }
1295
1296    impl<'a> ArpSenderContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtxWithDeviceId<'a> {
1297        fn send_ip_packet_to_neighbor_link_addr<S>(
1298            &mut self,
1299            bindings_ctx: &mut FakeBindingsCtx,
1300            link_addr: UnicastAddr<Mac>,
1301            body: S,
1302            tx_meta: FakeTxMetadata,
1303        ) -> Result<(), SendFrameError<S>>
1304        where
1305            S: NetworkSerializer,
1306            S::Buffer: BufferMut,
1307        {
1308            let Self { core_ctx, device_id } = self;
1309            send_as_ethernet_frame_to_dst(
1310                *core_ctx,
1311                bindings_ctx,
1312                device_id,
1313                link_addr.get(),
1314                body,
1315                EtherType::Ipv4,
1316                tx_meta,
1317            )
1318        }
1319    }
1320
1321    impl TransmitQueueBindingsContext<FakeDeviceId> for FakeBindingsCtx {
1322        fn wake_tx_task(&mut self, FakeDeviceId: &FakeDeviceId) {
1323            unimplemented!("unused by tests")
1324        }
1325    }
1326
1327    impl EventContext<EthernetDeviceEvent<FakeDeviceId>> for FakeBindingsCtx {
1328        fn on_event(&mut self, event: EthernetDeviceEvent<FakeDeviceId>) {
1329            // Panic if we get more than one join or leave event per group.
1330            match event {
1331                EthernetDeviceEvent::MulticastJoin { device, addr } => {
1332                    assert!(
1333                        self.state.link_multicast_group_memberships.insert((device, addr)),
1334                        "membership should not be present"
1335                    );
1336                }
1337                EthernetDeviceEvent::MulticastLeave { device, addr } => {
1338                    assert!(
1339                        self.state.link_multicast_group_memberships.remove(&(device, addr)),
1340                        "membership should be present"
1341                    );
1342                }
1343            }
1344        }
1345    }
1346
1347    impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1348        type Meta = FakeTxMetadata;
1349
1350        type DequeueContext = Never;
1351
1352        fn parse_outgoing_frame<'a>(
1353            buf: &'a [u8],
1354            meta: &'a Self::Meta,
1355        ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1356            FakeInnerCtx::parse_outgoing_frame(buf, meta)
1357        }
1358    }
1359
1360    impl TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx {
1361        type Meta = FakeTxMetadata;
1362
1363        type DequeueContext = Never;
1364
1365        fn parse_outgoing_frame<'a, 'b>(
1366            buf: &'a [u8],
1367            _tx_meta: &'b Self::Meta,
1368        ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
1369            SentFrame::try_parse_as_ethernet(buf)
1370        }
1371    }
1372
1373    impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeCoreCtx {
1374        fn with_transmit_queue_mut<
1375            O,
1376            F: FnOnce(
1377                &mut TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>,
1378            ) -> O,
1379        >(
1380            &mut self,
1381            device_id: &Self::DeviceId,
1382            cb: F,
1383        ) -> O {
1384            self.inner.with_transmit_queue_mut(device_id, cb)
1385        }
1386
1387        fn with_transmit_queue<
1388            O,
1389            F: FnOnce(&TransmitQueueState<Self::Meta, packet::Buf<Vec<u8>>, BufVecU8Allocator>) -> O,
1390        >(
1391            &mut self,
1392            device_id: &Self::DeviceId,
1393            cb: F,
1394        ) -> O {
1395            self.inner.with_transmit_queue(device_id, cb)
1396        }
1397
1398        fn send_frame(
1399            &mut self,
1400            bindings_ctx: &mut FakeBindingsCtx,
1401            device_id: &Self::DeviceId,
1402            dequeue_context: Option<&mut Never>,
1403            tx_meta: Self::Meta,
1404            buf: packet::Buf<Vec<u8>>,
1405        ) -> Result<(), DeviceSendFrameError> {
1406            TransmitQueueContext::send_frame(
1407                &mut self.inner,
1408                bindings_ctx,
1409                device_id,
1410                dequeue_context,
1411                tx_meta,
1412                buf,
1413            )
1414        }
1415    }
1416
1417    impl TransmitQueueContext<EthernetLinkDevice, FakeBindingsCtx> for FakeInnerCtx
1418    where
1419        Self: TransmitQueueCommon<EthernetLinkDevice, FakeBindingsCtx, Meta = FakeTxMetadata>,
1420    {
1421        fn with_transmit_queue_mut<
1422            O,
1423            F: FnOnce(
1424                &mut TransmitQueueState<
1425                    Self::Meta,
1426                    <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1427                    <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1428                >,
1429            ) -> O,
1430        >(
1431            &mut self,
1432            _device_id: &Self::DeviceId,
1433            cb: F,
1434        ) -> O {
1435            cb(&mut self.state.tx_queue)
1436        }
1437
1438        fn with_transmit_queue<
1439            O,
1440            F: FnOnce(
1441                &TransmitQueueState<
1442                    Self::Meta,
1443                    <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxBuffer,
1444                    <FakeBindingsCtx as DeviceBufferBindingsTypes>::TxAllocator,
1445                >,
1446            ) -> O,
1447        >(
1448            &mut self,
1449            _device_id: &Self::DeviceId,
1450            cb: F,
1451        ) -> O {
1452            cb(&self.state.tx_queue)
1453        }
1454
1455        fn send_frame(
1456            &mut self,
1457            _bindings_ctx: &mut FakeBindingsCtx,
1458            device_id: &Self::DeviceId,
1459            dequeue_context: Option<&mut Never>,
1460            _tx_meta: Self::Meta,
1461            buf: packet::Buf<Vec<u8>>,
1462        ) -> Result<(), DeviceSendFrameError> {
1463            match dequeue_context {
1464                Some(never) => match *never {},
1465                None => (),
1466            }
1467            self.frames.push(device_id.clone(), buf.as_ref().to_vec());
1468            Ok(())
1469        }
1470    }
1471
1472    impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtx {
1473        type DeviceId = FakeDeviceId;
1474        type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1475    }
1476
1477    impl DeviceIdContext<EthernetLinkDevice> for FakeInnerCtx {
1478        type DeviceId = FakeDeviceId;
1479        type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
1480    }
1481
1482    impl CounterContext<ArpCounters> for FakeCoreCtx {
1483        fn counters(&self) -> &ArpCounters {
1484            &self.inner.state.arp_counters
1485        }
1486    }
1487
1488    #[test]
1489    fn test_mtu() {
1490        // Test that we send an Ethernet frame whose size is less than the MTU,
1491        // and that we don't send an Ethernet frame whose size is greater than
1492        // the MTU.
1493        fn test(size: usize, expect_frames_sent: bool) {
1494            let mut ctx = new_context();
1495            NeighborApi::<Ipv4, EthernetLinkDevice, _>::new(ctx.as_mut())
1496                .insert_static_entry(
1497                    &FakeDeviceId,
1498                    TEST_ADDRS_V4.remote_ip.get(),
1499                    TEST_ADDRS_V4.remote_mac,
1500                )
1501                .unwrap();
1502            let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1503            let result = send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1504                core_ctx,
1505                bindings_ctx,
1506                &FakeDeviceId,
1507                IpPacketDestination::<Ipv4, _>::Neighbor(TEST_ADDRS_V4.remote_ip),
1508                Buf::new(&mut vec![0; size], ..),
1509                FakeTxMetadata::default(),
1510            )
1511            .map_err(|_serializer| ());
1512            let sent_frames = core_ctx.inner.frames().len();
1513            if expect_frames_sent {
1514                assert_eq!(sent_frames, 1);
1515                result.expect("should succeed");
1516            } else {
1517                assert_eq!(sent_frames, 0);
1518                result.expect_err("should fail");
1519            }
1520        }
1521
1522        test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap(), true);
1523        test(usize::try_from(u32::from(Ipv6::MINIMUM_LINK_MTU)).unwrap() + 1, false);
1524    }
1525
1526    #[test]
1527    fn broadcast() {
1528        let mut ctx = new_context();
1529        let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1530        send_ip_frame::<FakeBindingsCtx, FakeCoreCtx, Ipv4, _>(
1531            core_ctx,
1532            bindings_ctx,
1533            &FakeDeviceId,
1534            IpPacketDestination::<Ipv4, _>::Broadcast(()),
1535            Buf::new(&mut vec![0; 100], ..),
1536            FakeTxMetadata::default(),
1537        )
1538        .map_err(|_serializer| ())
1539        .expect("send_ip_frame should succeed");
1540        let sent_frames = core_ctx.inner.frames().len();
1541        assert_eq!(sent_frames, 1);
1542        let (FakeDeviceId, frame) = core_ctx.inner.frames()[0].clone();
1543        let (_body, _src_mac, dst_mac, _ether_type) =
1544            parse_ethernet_frame(&frame, EthernetFrameLengthCheck::NoCheck).unwrap();
1545        assert_eq!(dst_mac, Mac::BROADCAST);
1546    }
1547
1548    #[test]
1549    fn test_join_link_multicast() {
1550        let mut ctx = new_context();
1551        let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
1552
1553        let address1: MulticastAddr<Mac> =
1554            MulticastAddr::new(Ipv4Addr::new([224, 0, 0, 200])).unwrap().into();
1555        let address2: MulticastAddr<Mac> =
1556            MulticastAddr::new(Ipv4Addr::new([224, 0, 10, 30])).unwrap().into();
1557
1558        join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1559        join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1560        join_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1561
1562        assert_eq!(
1563            bindings_ctx.state.link_multicast_group_memberships,
1564            HashSet::from_iter([(FakeDeviceId, address1), (FakeDeviceId, address2)])
1565        );
1566
1567        leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address1);
1568
1569        assert_eq!(
1570            bindings_ctx.state.link_multicast_group_memberships,
1571            HashSet::from_iter([(FakeDeviceId, address2)])
1572        );
1573
1574        // Since we joined address2 twice, we need to leave it twice as well.
1575        leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1576
1577        assert_eq!(
1578            bindings_ctx.state.link_multicast_group_memberships,
1579            HashSet::from_iter([(FakeDeviceId, address2)])
1580        );
1581
1582        leave_link_multicast(core_ctx, bindings_ctx, &FakeDeviceId, address2);
1583
1584        assert_eq!(bindings_ctx.state.link_multicast_group_memberships, HashSet::new());
1585    }
1586}