Skip to main content

netstack3_device/
arp.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 Address Resolution Protocol (ARP).
6
7use core::time::Duration;
8
9use alloc::fmt::Debug;
10
11use log::{debug, trace, warn};
12use net_types::ip::{Ip, Ipv4, Ipv4Addr};
13use net_types::{NonMulticastAddr, SpecifiedAddr, UnicastAddr, Witness as _};
14use netstack3_base::{
15    CoreTimerContext, Counter, CounterContext, DeviceIdContext, EventContext, FrameDestination,
16    InstantBindingsTypes, LinkDevice, NetworkSerializer, SendFrameContext, SendFrameError,
17    TimerContext, TxMetadataBindingsTypes, WeakDeviceIdentifier,
18};
19use netstack3_ip::nud::{
20    self, ConfirmationFlags, DynamicNeighborUpdateSource, LinkResolutionContext, NudBindingsTypes,
21    NudConfigContext, NudContext, NudHandler, NudSenderContext, NudState, NudTimerId,
22    NudUserConfig,
23};
24use packet::{BufferMut, InnerPacketBuilder};
25use packet_formats::arp::{ArpOp, ArpPacket, ArpPacketBuilder, HType};
26use packet_formats::utils::NonZeroDuration;
27use ref_cast::RefCast;
28
29/// A link device whose addressing scheme is supported by ARP.
30///
31/// `ArpDevice` is implemented for all `L: LinkDevice where L::Address: HType`.
32pub trait ArpDevice: LinkDevice<Address: HType> {}
33
34impl<L: LinkDevice<Address: HType>> ArpDevice for L {}
35
36/// The identifier for timer events in the ARP layer.
37pub(crate) type ArpTimerId<L, D> = NudTimerId<Ipv4, L, D>;
38
39/// The metadata associated with an ARP frame.
40#[cfg_attr(test, derive(Debug, PartialEq, Clone))]
41pub struct ArpFrameMetadata<D: ArpDevice, DeviceId> {
42    /// The ID of the ARP device.
43    pub(super) device_id: DeviceId,
44    /// The destination hardware address.
45    pub(super) dst_addr: NonMulticastAddr<D::Address>,
46}
47
48/// Counters for the ARP layer.
49#[derive(Default)]
50pub struct ArpCounters {
51    /// Count of ARP packets received from the link layer.
52    pub rx_packets: Counter,
53    /// Count of received ARP packets that were dropped due to being unparsable.
54    pub rx_malformed_packets: Counter,
55    /// Count of received ARP packets that were dropped due to being echoed.
56    /// E.g. an ARP packet sent by us that was reflected back by the network.
57    pub rx_echoed_packets: Counter,
58    /// Count of ARP request packets received.
59    pub rx_requests: Counter,
60    /// Count of ARP response packets received.
61    pub rx_responses: Counter,
62    /// Count of non-gratuitous ARP packets received and dropped because the
63    /// destination address is non-local.
64    pub rx_dropped_non_local_target: Counter,
65    /// Count of ARP request packets sent.
66    pub tx_requests: Counter,
67    /// Count of ARP request packets not sent because the source address was
68    /// unknown or unassigned.
69    pub tx_requests_dropped_no_local_addr: Counter,
70    /// Count of ARP response packets sent.
71    pub tx_responses: Counter,
72}
73
74/// An execution context for the ARP protocol that allows sending IP packets to
75/// specific neighbors.
76pub trait ArpSenderContext<D: ArpDevice, BC: ArpBindingsContext<D, Self::DeviceId>>:
77    ArpConfigContext + DeviceIdContext<D>
78{
79    /// Send an IP packet to the neighbor with address `dst_link_address`.
80    fn send_ip_packet_to_neighbor_link_addr<S>(
81        &mut self,
82        bindings_ctx: &mut BC,
83        dst_link_address: UnicastAddr<D::Address>,
84        body: S,
85        meta: BC::TxMetadata,
86    ) -> Result<(), SendFrameError<S>>
87    where
88        S: NetworkSerializer,
89        S::Buffer: BufferMut;
90}
91
92// NOTE(joshlf): The `ArpDevice` parameter may seem unnecessary. We only ever
93// use the associated `HType` type, so why not just take that directly? By the
94// same token, why have it as a parameter on `ArpState`, `ArpTimerId`, and
95// `ArpFrameMetadata`? The answer is that, if we did, there would be no way to
96// distinguish between different link device protocols that all happened to use
97// the same hardware addressing scheme.
98//
99// Consider that the way that we implement context traits is via blanket impls.
100// Even though each module's code _feels_ isolated from the rest of the system,
101// in reality, all context impls end up on the same context type. In particular,
102// all impls are of the form `impl<C: SomeContextTrait> SomeOtherContextTrait
103// for C`. The `C` is the same throughout the whole stack.
104//
105// Thus, for two different link device protocols with the same `HType` and
106// `PType`, if we used an `HType` parameter rather than an `ArpDevice`
107// parameter, the `ArpContext` impls would conflict (in fact, the
108// `StateContext`, `TimerContext`, and `FrameContext` impls would all conflict
109// for similar reasons).
110
111/// The execution context for the ARP protocol provided by bindings.
112pub trait ArpBindingsContext<D: ArpDevice, DeviceId>:
113    TimerContext
114    + LinkResolutionContext<D>
115    + EventContext<nud::Event<D::Address, DeviceId, Ipv4, <Self as InstantBindingsTypes>::Instant>>
116    + TxMetadataBindingsTypes
117{
118}
119
120impl<
121    DeviceId,
122    D: ArpDevice,
123    BC: TimerContext
124        + LinkResolutionContext<D>
125        + EventContext<
126            nud::Event<D::Address, DeviceId, Ipv4, <Self as InstantBindingsTypes>::Instant>,
127        > + TxMetadataBindingsTypes,
128> ArpBindingsContext<D, DeviceId> for BC
129{
130}
131
132/// An execution context for the ARP protocol.
133pub trait ArpContext<D: ArpDevice, BC: ArpBindingsContext<D, Self::DeviceId>>:
134    DeviceIdContext<D>
135    + SendFrameContext<BC, ArpFrameMetadata<D, Self::DeviceId>>
136    + CounterContext<ArpCounters>
137{
138    /// The inner configuration context.
139    type ConfigCtx<'a>: ArpConfigContext;
140    /// The inner sender context.
141    type ArpSenderCtx<'a>: ArpSenderContext<D, BC, DeviceId = Self::DeviceId>;
142
143    /// Calls the function with a mutable reference to ARP state and the
144    /// core sender context.
145    fn with_arp_state_mut_and_sender_ctx<
146        O,
147        F: FnOnce(&mut ArpState<D, BC>, &mut Self::ArpSenderCtx<'_>) -> O,
148    >(
149        &mut self,
150        device_id: &Self::DeviceId,
151        cb: F,
152    ) -> O;
153
154    /// Get a protocol address of this interface.
155    ///
156    /// If `device_id` does not have any addresses associated with it, return
157    /// `None`.
158    ///
159    /// NOTE: If the interface has multiple addresses, an arbitrary one will be
160    /// returned.
161    fn get_protocol_addr(&mut self, device_id: &Self::DeviceId) -> Option<Ipv4Addr>;
162
163    /// Get the hardware address of this interface.
164    fn get_hardware_addr(
165        &mut self,
166        bindings_ctx: &mut BC,
167        device_id: &Self::DeviceId,
168    ) -> UnicastAddr<D::Address>;
169
170    /// Calls the function with a mutable reference to ARP state and the ARP
171    /// configuration context.
172    fn with_arp_state_mut<O, F: FnOnce(&mut ArpState<D, BC>, &mut Self::ConfigCtx<'_>) -> O>(
173        &mut self,
174        device_id: &Self::DeviceId,
175        cb: F,
176    ) -> O;
177
178    /// Calls the function with an immutable reference to ARP state.
179    fn with_arp_state<O, F: FnOnce(&ArpState<D, BC>) -> O>(
180        &mut self,
181        device_id: &Self::DeviceId,
182        cb: F,
183    ) -> O;
184}
185
186/// An execution context for ARP providing functionality from the IP layer.
187pub trait ArpIpLayerContext<D: ArpDevice, BC>: DeviceIdContext<D> {
188    /// Dispatches a received ARP Request or Reply to the IP layer.
189    ///
190    /// The IP layer may use this packet to update internal state, such as
191    /// facilitating Address Conflict Detection (RFC 5227).
192    ///
193    /// `frame_src` is the link address in the L2 Frame that carried this ARP
194    /// packet, while `sender_hwaddr` is the sender_hardware_addr field from the
195    /// ARP header.
196    ///
197    /// Returns whether the `target_addr` is assigned on the device. This is
198    /// used by ARP to send responses to the packet (if applicable).
199    fn on_arp_packet(
200        &mut self,
201        bindings_ctx: &mut BC,
202        device: &Self::DeviceId,
203        frame_src: D::Address,
204        sender_hwaddr: UnicastAddr<D::Address>,
205        sender_addr: Ipv4Addr,
206        target_addr: Ipv4Addr,
207        is_arp_probe: bool,
208    ) -> bool;
209}
210
211/// An execution context for the ARP protocol that allows accessing
212/// configuration parameters.
213pub trait ArpConfigContext {
214    /// The retransmit timeout for ARP frames.
215    ///
216    /// Provided implementation always return the default RFC period.
217    fn retransmit_timeout(&mut self) -> NonZeroDuration {
218        self.with_nud_user_config(|c| c.retrans_timer)
219    }
220
221    /// Calls the callback with an immutable reference to NUD configurations.
222    fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O;
223}
224
225/// Provides a [`NudContext`] IPv4 implementation for a core context that
226/// implements [`ArpContext`].
227#[derive(RefCast)]
228#[repr(transparent)]
229pub struct ArpNudCtx<CC>(CC);
230
231impl<D, CC> DeviceIdContext<D> for ArpNudCtx<CC>
232where
233    D: ArpDevice,
234    CC: DeviceIdContext<D>,
235{
236    type DeviceId = CC::DeviceId;
237    type WeakDeviceId = CC::WeakDeviceId;
238}
239
240impl<D, CC, BC> NudContext<Ipv4, D, BC> for ArpNudCtx<CC>
241where
242    D: ArpDevice,
243    BC: ArpBindingsContext<D, CC::DeviceId>,
244    CC: ArpContext<D, BC>,
245{
246    type ConfigCtx<'a> = ArpNudCtx<CC::ConfigCtx<'a>>;
247    type SenderCtx<'a> = ArpNudCtx<CC::ArpSenderCtx<'a>>;
248
249    fn with_nud_state_mut_and_sender_ctx<
250        O,
251        F: FnOnce(&mut NudState<Ipv4, D, BC>, &mut Self::SenderCtx<'_>) -> O,
252    >(
253        &mut self,
254        device_id: &Self::DeviceId,
255        cb: F,
256    ) -> O {
257        let Self(core_ctx) = self;
258        core_ctx.with_arp_state_mut_and_sender_ctx(device_id, |ArpState { nud }, core_ctx| {
259            cb(nud, ArpNudCtx::ref_cast_mut(core_ctx))
260        })
261    }
262
263    fn with_nud_state_mut<
264        O,
265        F: FnOnce(&mut NudState<Ipv4, D, BC>, &mut Self::ConfigCtx<'_>) -> O,
266    >(
267        &mut self,
268        device_id: &Self::DeviceId,
269        cb: F,
270    ) -> O {
271        let Self(core_ctx) = self;
272        core_ctx.with_arp_state_mut(device_id, |ArpState { nud }, core_ctx| {
273            cb(nud, ArpNudCtx::ref_cast_mut(core_ctx))
274        })
275    }
276
277    fn with_nud_state<O, F: FnOnce(&NudState<Ipv4, D, BC>) -> O>(
278        &mut self,
279        device_id: &Self::DeviceId,
280        cb: F,
281    ) -> O {
282        let Self(core_ctx) = self;
283        core_ctx.with_arp_state(device_id, |ArpState { nud }| cb(nud))
284    }
285
286    fn send_neighbor_solicitation(
287        &mut self,
288        bindings_ctx: &mut BC,
289        device_id: &Self::DeviceId,
290        lookup_addr: SpecifiedAddr<<Ipv4 as net_types::ip::Ip>::Addr>,
291        remote_link_addr: Option<UnicastAddr<<D as LinkDevice>::Address>>,
292    ) {
293        let Self(core_ctx) = self;
294
295        if let Some(sender_addr) = core_ctx.get_protocol_addr(device_id) {
296            send_arp_request(
297                core_ctx,
298                bindings_ctx,
299                device_id,
300                sender_addr,
301                *lookup_addr,
302                remote_link_addr,
303            );
304        } else {
305            // RFC 826 does not specify what to do if we don't have a local address,
306            // but there is no reasonable way to send an ARP request without one (as
307            // the receiver will cache our local address on receiving the packet).
308            // So, if this is the case, we do not send an ARP request.
309            core_ctx.counters().tx_requests_dropped_no_local_addr.increment();
310            debug!("Not sending ARP request, since we don't know our local protocol address");
311        }
312    }
313}
314
315/// How long entries are locked before they can be overridden.
316pub const ARP_OVERRIDE_LOCK_TIME: Duration = Duration::from_secs(1);
317
318impl<CC: ArpConfigContext> NudConfigContext<Ipv4> for ArpNudCtx<CC> {
319    fn retransmit_timeout(&mut self) -> NonZeroDuration {
320        let Self(core_ctx) = self;
321        core_ctx.retransmit_timeout()
322    }
323
324    fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
325        let Self(core_ctx) = self;
326        core_ctx.with_nud_user_config(cb)
327    }
328
329    fn override_lock_time(&mut self) -> Duration {
330        ARP_OVERRIDE_LOCK_TIME
331    }
332}
333
334impl<D: ArpDevice, BC: ArpBindingsContext<D, CC::DeviceId>, CC: ArpSenderContext<D, BC>>
335    NudSenderContext<Ipv4, D, BC> for ArpNudCtx<CC>
336{
337    fn send_ip_packet_to_neighbor_link_addr<S>(
338        &mut self,
339        bindings_ctx: &mut BC,
340        dst_mac: UnicastAddr<D::Address>,
341        body: S,
342        meta: BC::TxMetadata,
343    ) -> Result<(), SendFrameError<S>>
344    where
345        S: NetworkSerializer,
346        S::Buffer: BufferMut,
347    {
348        let Self(core_ctx) = self;
349        core_ctx.send_ip_packet_to_neighbor_link_addr(bindings_ctx, dst_mac, body, meta)
350    }
351}
352
353pub(crate) trait ArpPacketHandler<D: ArpDevice, BC>: DeviceIdContext<D> {
354    fn handle_packet<B: BufferMut + Debug>(
355        &mut self,
356        bindings_ctx: &mut BC,
357        device_id: Self::DeviceId,
358        frame_src: D::Address,
359        frame_dst: FrameDestination,
360        buffer: B,
361    );
362}
363
364impl<
365    D: ArpDevice,
366    BC: ArpBindingsContext<D, CC::DeviceId>,
367    CC: ArpContext<D, BC> + ArpIpLayerContext<D, BC> + NudHandler<Ipv4, D, BC>,
368> ArpPacketHandler<D, BC> for CC
369{
370    /// Handles an inbound ARP packet.
371    fn handle_packet<B: BufferMut + Debug>(
372        &mut self,
373        bindings_ctx: &mut BC,
374        device_id: Self::DeviceId,
375        frame_src: D::Address,
376        frame_dst: FrameDestination,
377        buffer: B,
378    ) {
379        handle_packet(self, bindings_ctx, device_id, frame_src, frame_dst, buffer)
380    }
381}
382
383fn handle_packet<
384    D: ArpDevice,
385    BC: ArpBindingsContext<D, CC::DeviceId>,
386    B: BufferMut + Debug,
387    CC: ArpContext<D, BC> + ArpIpLayerContext<D, BC> + NudHandler<Ipv4, D, BC>,
388>(
389    core_ctx: &mut CC,
390    bindings_ctx: &mut BC,
391    device_id: CC::DeviceId,
392    frame_src: D::Address,
393    frame_dst: FrameDestination,
394    mut buffer: B,
395) {
396    core_ctx.counters().rx_packets.increment();
397    let packet = match buffer.parse::<ArpPacket<_, D::Address, Ipv4Addr>>() {
398        Ok(packet) => packet,
399        Err(err) => {
400            // If parse failed, it's because either the packet was malformed, or
401            // it was for an unexpected hardware or network protocol. In either
402            // case, we just drop the packet and move on. RFC 826's "Packet
403            // Reception" section says of packet processing algorithm, "Negative
404            // conditionals indicate an end of processing and a discarding of
405            // the packet."
406            debug!("discarding malformed ARP packet: {}", err);
407            core_ctx.counters().rx_malformed_packets.increment();
408            return;
409        }
410    };
411
412    #[derive(Debug)]
413    enum ValidArpOp {
414        Request,
415        Response,
416    }
417
418    let op = match packet.operation() {
419        ArpOp::Request => {
420            core_ctx.counters().rx_requests.increment();
421            ValidArpOp::Request
422        }
423        ArpOp::Response => {
424            core_ctx.counters().rx_responses.increment();
425            ValidArpOp::Response
426        }
427        ArpOp::Other(o) => {
428            core_ctx.counters().rx_malformed_packets.increment();
429            debug!("dropping arp packet with op = {:?}", o);
430            return;
431        }
432    };
433
434    let sender_hw_addr = packet.sender_hardware_address();
435    let Some(sender_hw_addr) = UnicastAddr::new(sender_hw_addr) else {
436        debug!("dropping ARP packet with non-unicast sender HW addr: {:?}", sender_hw_addr);
437        return;
438    };
439    // If the sender's hardware address is *our* hardware address, this is
440    // an echoed ARP packet (e.g. the network reflected back an ARP packet that
441    // we sent). Here we deviate from the behavior specified in RFC 826 (which
442    // makes no comment on handling echoed ARP packets), and drop the packet.
443    // There's no benefit to tracking our own ARP packets in the ARP table, and
444    // some RFCs built on top of ARP (i.e. RFC 5227 - IPv4 Address Conflict
445    // Detection) explicitly call out that echoed ARP packets should be ignored.
446    if sender_hw_addr == core_ctx.get_hardware_addr(bindings_ctx, &device_id) {
447        core_ctx.counters().rx_echoed_packets.increment();
448        debug!("dropping an echoed ARP packet: {op:?}");
449        return;
450    }
451
452    let sender_addr = packet.sender_protocol_address();
453    let target_addr = packet.target_protocol_address();
454
455    // As per RFC 5227, section 1.1:
456    // the term 'ARP Probe' is used to refer to an ARP Request packet, broadcast
457    // on the local link, with an all-zero 'sender IP address'.
458    let is_arp_probe = sender_addr == Ipv4::UNSPECIFIED_ADDRESS
459        && packet.operation() == ArpOp::Request
460        && frame_dst == FrameDestination::Broadcast;
461
462    // As Per RFC 5227, section 2.1.1 dispatch any received ARP packet
463    // (Request *or* Reply) to the DAD engine.
464    let targets_interface = core_ctx.on_arp_packet(
465        bindings_ctx,
466        &device_id,
467        frame_src,
468        sender_hw_addr,
469        sender_addr,
470        target_addr,
471        is_arp_probe,
472    );
473
474    enum PacketKind {
475        Gratuitous,
476        AddressedToMe,
477    }
478
479    // The following logic is equivalent to the "Packet Reception" section of
480    // RFC 826.
481    //
482    // We statically know that the hardware type and protocol type are correct,
483    // so we do not need to have additional code to check that. The remainder of
484    // the algorithm is:
485    //
486    // Merge_flag := false
487    // If the pair <protocol type, sender protocol address> is
488    //     already in my translation table, update the sender
489    //     hardware address field of the entry with the new
490    //     information in the packet and set Merge_flag to true.
491    // ?Am I the target protocol address?
492    // Yes:
493    //   If Merge_flag is false, add the triplet <protocol type,
494    //       sender protocol address, sender hardware address> to
495    //       the translation table.
496    //   ?Is the opcode ares_op$REQUEST?  (NOW look at the opcode!!)
497    //   Yes:
498    //     Swap hardware and protocol fields, putting the local
499    //         hardware and protocol addresses in the sender fields.
500    //     Set the ar$op field to ares_op$REPLY
501    //     Send the packet to the (new) target hardware address on
502    //         the same hardware on which the request was received.
503    //
504    // This can be summed up as follows:
505    //
506    // +----------+---------------+---------------+-----------------------------+
507    // | opcode   | Am I the TPA? | SPA in table? | action                      |
508    // +----------+---------------+---------------+-----------------------------+
509    // | REQUEST  | yes           | yes           | Update table, Send response |
510    // | REQUEST  | yes           | no            | Update table, Send response |
511    // | REQUEST  | no            | yes           | Update table                |
512    // | REQUEST  | no            | no            | NOP                         |
513    // | RESPONSE | yes           | yes           | Update table                |
514    // | RESPONSE | yes           | no            | Update table                |
515    // | RESPONSE | no            | yes           | Update table                |
516    // | RESPONSE | no            | no            | NOP                         |
517    // +----------+---------------+---------------+-----------------------------+
518
519    let garp = sender_addr == target_addr;
520    let (source, kind) = match (garp, targets_interface) {
521        (true, false) => {
522            // Treat all GARP messages as neighbor probes as GARPs are not
523            // responses for previously sent requests, even if the packet
524            // operation is a response OP code.
525            //
526            // Per RFC 5944 section 4.6,
527            //
528            //   A Gratuitous ARP [45] is an ARP packet sent by a node in order
529            //   to spontaneously cause other nodes to update an entry in their
530            //   ARP cache. A gratuitous ARP MAY use either an ARP Request or an
531            //   ARP Reply packet. In either case, the ARP Sender Protocol
532            //   Address and ARP Target Protocol Address are both set to the IP
533            //   address of the cache entry to be updated, and the ARP Sender
534            //   Hardware Address is set to the link-layer address to which this
535            //   cache entry should be updated. When using an ARP Reply packet,
536            //   the Target Hardware Address is also set to the link-layer
537            //   address to which this cache entry should be updated (this field
538            //   is not used in an ARP Request packet).
539            //
540            //   In either case, for a gratuitous ARP, the ARP packet MUST be
541            //   transmitted as a local broadcast packet on the local link. As
542            //   specified in [16], any node receiving any ARP packet (Request
543            //   or Reply) MUST update its local ARP cache with the Sender
544            //   Protocol and Hardware Addresses in the ARP packet, if the
545            //   receiving node has an entry for that IP address already in its
546            //   ARP cache. This requirement in the ARP protocol applies even
547            //   for ARP Request packets, and for ARP Reply packets that do not
548            //   match any ARP Request transmitted by the receiving node [16].
549            (
550                DynamicNeighborUpdateSource::Probe { link_address: sender_hw_addr },
551                PacketKind::Gratuitous,
552            )
553        }
554        (false, true) => {
555            // Consider ARP replies as solicited if they were unicast directly to us, and
556            // unsolicited otherwise.
557            let solicited = match frame_dst {
558                FrameDestination::Individual { local } => local,
559                FrameDestination::Broadcast | FrameDestination::Multicast => false,
560            };
561            let source = match op {
562                ValidArpOp::Request => {
563                    DynamicNeighborUpdateSource::Probe { link_address: sender_hw_addr }
564                }
565                ValidArpOp::Response => {
566                    DynamicNeighborUpdateSource::Confirmation {
567                        link_address: Some(sender_hw_addr),
568                        flags: ConfirmationFlags {
569                            solicited_flag: solicited,
570                            // ARP does not have the concept of an override flag in a neighbor
571                            // confirmation. In order to ensure we don't fail to update a cached
572                            // link address when a neighbor informs us of the update, always
573                            // consider ARP replies as overrides.
574                            override_flag: true,
575                        },
576                    }
577                }
578            };
579            (source, PacketKind::AddressedToMe)
580        }
581        (false, false) => {
582            core_ctx.counters().rx_dropped_non_local_target.increment();
583            trace!(
584                "non-gratuitous ARP packet not targetting us; sender = {}, target={}",
585                sender_addr, target_addr
586            );
587            return;
588        }
589        (true, true) => {
590            warn!(
591                "got gratuitous ARP packet with our address {target_addr} on device {device_id:?}, \
592                dropping...",
593            );
594            return;
595        }
596    };
597
598    if let Some(addr) = SpecifiedAddr::new(sender_addr) {
599        NudHandler::<Ipv4, D, _>::handle_neighbor_update(
600            core_ctx,
601            bindings_ctx,
602            &device_id,
603            addr,
604            source,
605        )
606    };
607
608    match kind {
609        PacketKind::Gratuitous => return,
610        PacketKind::AddressedToMe => match source {
611            DynamicNeighborUpdateSource::Probe { .. } => {
612                let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, &device_id);
613
614                core_ctx.counters().tx_responses.increment();
615                debug!("sending ARP response for {target_addr} to {sender_addr}");
616
617                SendFrameContext::send_frame(
618                    core_ctx,
619                    bindings_ctx,
620                    ArpFrameMetadata {
621                        device_id,
622                        dst_addr: NonMulticastAddr::from(sender_hw_addr),
623                    },
624                    ArpPacketBuilder::new(
625                        ArpOp::Response,
626                        self_hw_addr.get(),
627                        target_addr,
628                        sender_hw_addr.get(),
629                        sender_addr,
630                    )
631                    .into_serializer_with(buffer),
632                )
633                .unwrap_or_else(|serializer| {
634                    warn!(
635                        "failed to send ARP response for {target_addr} to {sender_addr}: \
636                        {serializer:?}"
637                    )
638                });
639            }
640            DynamicNeighborUpdateSource::Confirmation { .. } => {}
641        },
642    }
643}
644
645/// Sends an Arp Request for the provided lookup_addr.
646///
647/// If remote_link_addr is provided, it will be the destination of the request.
648/// If unset, the request will be broadcast.
649pub fn send_arp_request<
650    D: ArpDevice,
651    BC: ArpBindingsContext<D, CC::DeviceId>,
652    CC: ArpContext<D, BC> + CounterContext<ArpCounters>,
653>(
654    core_ctx: &mut CC,
655    bindings_ctx: &mut BC,
656    device_id: &CC::DeviceId,
657    sender_addr: Ipv4Addr,
658    lookup_addr: Ipv4Addr,
659    remote_link_addr: Option<UnicastAddr<D::Address>>,
660) {
661    let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, device_id);
662    let dst_addr = match remote_link_addr {
663        Some(addr) => NonMulticastAddr::from(addr),
664        None => NonMulticastAddr::new(D::Address::BROADCAST).expect("broadcast is non-multicast"),
665    };
666    core_ctx.counters().tx_requests.increment();
667    debug!("sending ARP request for {lookup_addr} to {:?}", dst_addr.get());
668    SendFrameContext::send_frame(
669        core_ctx,
670        bindings_ctx,
671        ArpFrameMetadata { device_id: device_id.clone(), dst_addr },
672        ArpPacketBuilder::new(
673            ArpOp::Request,
674            self_hw_addr.get(),
675            sender_addr,
676            // This field is relatively meaningless, since RFC 826 does not
677            // specify the behavior. However, RFC 5227 section 2.1.1. specifies
678            // that the target hardware address SHOULD be set to all 0s when
679            // sending an Address Conflict Detection probe.
680            //
681            // To accommodate this, we use the `remote_link_addr` if provided,
682            // or otherwise the unspecified address. Notably this makes the
683            // ARP target hardware address field differ from the destination
684            // address in the Frame Metadata.
685            remote_link_addr.map(|a| a.get()).unwrap_or(D::Address::UNSPECIFIED),
686            lookup_addr,
687        )
688        .into_serializer(),
689    )
690    .unwrap_or_else(|serializer| {
691        warn!("failed to send ARP request for {lookup_addr} to {dst_addr:?}: {serializer:?}")
692    });
693}
694
695/// The state associated with an instance of the Address Resolution Protocol
696/// (ARP).
697///
698/// Each device will contain an `ArpState` object for each of the network
699/// protocols that it supports.
700pub struct ArpState<D: ArpDevice, BT: NudBindingsTypes<D>> {
701    pub(crate) nud: NudState<Ipv4, D, BT>,
702}
703
704impl<D: ArpDevice, BC: NudBindingsTypes<D> + TimerContext> ArpState<D, BC> {
705    /// Creates a new `ArpState` for `device_id`.
706    pub fn new<
707        DeviceId: WeakDeviceIdentifier,
708        CC: CoreTimerContext<ArpTimerId<D, DeviceId>, BC>,
709    >(
710        bindings_ctx: &mut BC,
711        device_id: DeviceId,
712    ) -> Self {
713        ArpState { nud: NudState::new::<_, CC>(bindings_ctx, device_id) }
714    }
715}
716
717#[cfg(test)]
718mod tests {
719    use alloc::vec;
720    use alloc::vec::Vec;
721    use core::iter;
722    use net_types::ip::Ip;
723    use packet_formats::ip::Ipv4Proto;
724
725    use assert_matches::assert_matches;
726    use net_types::ethernet::Mac;
727    use netstack3_base::socket::SocketIpAddr;
728    use netstack3_base::testutil::{
729        FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeLinkDeviceId, FakeNetworkSpec,
730        FakeTimerId, FakeTxMetadata, FakeWeakDeviceId, WithFakeFrameContext, assert_empty,
731    };
732    use netstack3_base::{
733        CtxPair, InstantContext as _, IntoCoreTimerCtx, NetworkSerializationContext, TimerHandler,
734    };
735    use netstack3_ip::nud::testutil::{
736        assert_dynamic_neighbor_state, assert_dynamic_neighbor_with_addr, assert_neighbor_unknown,
737    };
738    use netstack3_ip::nud::{
739        DelegateNudContext, DynamicNeighborState, NudCounters, NudIcmpContext, Reachable, Stale,
740        UseDelegateNudContext,
741    };
742    use packet::{Buf, ParseBuffer, Serializer as _};
743    use packet_formats::arp::{ArpHardwareType, ArpNetworkType, peek_arp_types};
744    use packet_formats::ipv4::Ipv4FragmentType;
745    use test_case::test_case;
746
747    use super::*;
748    use crate::internal::ethernet::EthernetLinkDevice;
749
750    const TEST_LOCAL_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
751    const TEST_LOCAL_IPV4_2: Ipv4Addr = Ipv4Addr::new([4, 5, 6, 7]);
752    const TEST_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
753    const TEST_ANOTHER_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([9, 10, 11, 12]);
754    const TEST_LOCAL_MAC: Mac = Mac::new([0, 1, 2, 3, 4, 5]);
755    const TEST_REMOTE_MAC: Mac = Mac::new([6, 7, 8, 9, 10, 11]);
756    const TEST_INVALID_MAC: Mac = Mac::new([0, 0, 0, 0, 0, 0]);
757
758    /// A fake `ArpContext` that stores frames, address resolution events, and
759    /// address resolution failure events.
760    struct FakeArpCtx {
761        proto_addrs: Vec<Ipv4Addr>,
762        hw_addr: UnicastAddr<Mac>,
763        arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
764        inner: FakeArpInnerCtx,
765        config: FakeArpConfigCtx,
766        counters: ArpCounters,
767        nud_counters: NudCounters<Ipv4>,
768        // Stores received ARP packets that were dispatched to the IP Layer.
769        // Holds a tuple of (sender_addr, target_addr, is_arp_probe).
770        dispatched_arp_packets: Vec<(Ipv4Addr, Ipv4Addr, bool)>,
771    }
772
773    /// A fake `ArpSenderContext` that sends IP packets.
774    struct FakeArpInnerCtx;
775
776    /// A fake `ArpConfigContext`.
777    struct FakeArpConfigCtx;
778
779    impl FakeArpCtx {
780        fn new(bindings_ctx: &mut FakeBindingsCtxImpl) -> FakeArpCtx {
781            FakeArpCtx {
782                proto_addrs: vec![TEST_LOCAL_IPV4, TEST_LOCAL_IPV4_2],
783                hw_addr: UnicastAddr::new(TEST_LOCAL_MAC).unwrap(),
784                arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
785                    bindings_ctx,
786                    FakeWeakDeviceId(FakeLinkDeviceId),
787                ),
788                inner: FakeArpInnerCtx,
789                config: FakeArpConfigCtx,
790                counters: Default::default(),
791                nud_counters: Default::default(),
792                dispatched_arp_packets: Default::default(),
793            }
794        }
795    }
796
797    type FakeBindingsCtxImpl = FakeBindingsCtx<
798        ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>,
799        nud::Event<Mac, FakeLinkDeviceId, Ipv4, FakeInstant>,
800        (),
801        (),
802    >;
803
804    type FakeCoreCtxImpl = FakeCoreCtx<
805        FakeArpCtx,
806        ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>,
807        FakeDeviceId,
808    >;
809
810    fn new_context() -> CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl> {
811        CtxPair::with_default_bindings_ctx(|bindings_ctx| {
812            FakeCoreCtxImpl::with_state(FakeArpCtx::new(bindings_ctx))
813        })
814    }
815
816    enum ArpNetworkSpec {}
817    impl FakeNetworkSpec for ArpNetworkSpec {
818        type Context = CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl>;
819        type TimerId = ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>;
820        type SendMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
821        type RecvMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
822
823        fn handle_frame(
824            ctx: &mut Self::Context,
825            ArpFrameMetadata { device_id, .. }: Self::RecvMeta,
826            data: Buf<Vec<u8>>,
827        ) {
828            let CtxPair { core_ctx, bindings_ctx } = ctx;
829            handle_packet(
830                core_ctx,
831                bindings_ctx,
832                device_id,
833                TEST_REMOTE_MAC,
834                FrameDestination::Individual { local: true },
835                data,
836            )
837        }
838        fn handle_timer(ctx: &mut Self::Context, dispatch: Self::TimerId, timer: FakeTimerId) {
839            let CtxPair { core_ctx, bindings_ctx } = ctx;
840            TimerHandler::handle_timer(core_ctx, bindings_ctx, dispatch, timer)
841        }
842
843        fn process_queues(_ctx: &mut Self::Context) -> bool {
844            false
845        }
846
847        fn fake_frames(ctx: &mut Self::Context) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
848            &mut ctx.core_ctx
849        }
850    }
851
852    impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxImpl {
853        type DeviceId = FakeLinkDeviceId;
854        type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
855    }
856
857    impl DeviceIdContext<EthernetLinkDevice> for FakeArpInnerCtx {
858        type DeviceId = FakeLinkDeviceId;
859        type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
860    }
861
862    impl ArpContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
863        type ConfigCtx<'a> = FakeArpConfigCtx;
864
865        type ArpSenderCtx<'a> = FakeArpInnerCtx;
866
867        fn with_arp_state_mut_and_sender_ctx<
868            O,
869            F: FnOnce(
870                &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
871                &mut Self::ArpSenderCtx<'_>,
872            ) -> O,
873        >(
874            &mut self,
875            FakeLinkDeviceId: &FakeLinkDeviceId,
876            cb: F,
877        ) -> O {
878            let FakeArpCtx { arp_state, inner, .. } = &mut self.state;
879            cb(arp_state, inner)
880        }
881
882        fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>) -> O>(
883            &mut self,
884            FakeLinkDeviceId: &FakeLinkDeviceId,
885            cb: F,
886        ) -> O {
887            cb(&self.state.arp_state)
888        }
889
890        fn get_protocol_addr(&mut self, _device_id: &FakeLinkDeviceId) -> Option<Ipv4Addr> {
891            self.state.proto_addrs.first().copied()
892        }
893
894        fn get_hardware_addr(
895            &mut self,
896            _bindings_ctx: &mut FakeBindingsCtxImpl,
897            _device_id: &FakeLinkDeviceId,
898        ) -> UnicastAddr<Mac> {
899            self.state.hw_addr
900        }
901
902        fn with_arp_state_mut<
903            O,
904            F: FnOnce(
905                &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
906                &mut Self::ConfigCtx<'_>,
907            ) -> O,
908        >(
909            &mut self,
910            FakeLinkDeviceId: &FakeLinkDeviceId,
911            cb: F,
912        ) -> O {
913            let FakeArpCtx { arp_state, config, .. } = &mut self.state;
914            cb(arp_state, config)
915        }
916    }
917
918    impl ArpIpLayerContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
919        fn on_arp_packet(
920            &mut self,
921            _bindings_ctx: &mut FakeBindingsCtxImpl,
922            _device_id: &FakeLinkDeviceId,
923            _frame_src: Mac,
924            _sender_hwaddr: UnicastAddr<Mac>,
925            sender_addr: Ipv4Addr,
926            target_addr: Ipv4Addr,
927            is_arp_probe: bool,
928        ) -> bool {
929            self.state.dispatched_arp_packets.push((sender_addr, target_addr, is_arp_probe));
930
931            self.state.proto_addrs.iter().any(|&a| a == target_addr)
932        }
933    }
934
935    impl UseDelegateNudContext for FakeArpCtx {}
936    impl DelegateNudContext<Ipv4> for FakeArpCtx {
937        type Delegate<T> = ArpNudCtx<T>;
938    }
939
940    impl NudIcmpContext<Ipv4, EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
941        fn send_icmp_dest_unreachable(
942            &mut self,
943            _bindings_ctx: &mut FakeBindingsCtxImpl,
944            _frame: Buf<Vec<u8>>,
945            _device_id: Option<&Self::DeviceId>,
946            _original_src: SocketIpAddr<Ipv4Addr>,
947            _original_dst: SocketIpAddr<Ipv4Addr>,
948            _header_len: usize,
949            _proto: Ipv4Proto,
950            _metadata: Ipv4FragmentType,
951        ) {
952            panic!("send_icmp_dest_unreachable should not be called");
953        }
954    }
955
956    impl ArpConfigContext for FakeArpConfigCtx {
957        fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
958            cb(&NudUserConfig::default())
959        }
960    }
961    impl ArpConfigContext for FakeArpInnerCtx {
962        fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
963            cb(&NudUserConfig::default())
964        }
965    }
966
967    impl ArpSenderContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeArpInnerCtx {
968        fn send_ip_packet_to_neighbor_link_addr<S>(
969            &mut self,
970            _bindings_ctx: &mut FakeBindingsCtxImpl,
971            _dst_link_address: UnicastAddr<Mac>,
972            _body: S,
973            _tx_meta: FakeTxMetadata,
974        ) -> Result<(), SendFrameError<S>> {
975            Ok(())
976        }
977    }
978
979    impl CounterContext<ArpCounters> for FakeArpCtx {
980        fn counters(&self) -> &ArpCounters {
981            &self.counters
982        }
983    }
984
985    impl CounterContext<NudCounters<Ipv4>> for FakeArpCtx {
986        fn counters(&self) -> &NudCounters<Ipv4> {
987            &self.nud_counters
988        }
989    }
990
991    fn send_arp_packet(
992        core_ctx: &mut FakeCoreCtxImpl,
993        bindings_ctx: &mut FakeBindingsCtxImpl,
994        op: ArpOp,
995        sender_ipv4: Ipv4Addr,
996        target_ipv4: Ipv4Addr,
997        sender_mac: Mac,
998        target_mac: Mac,
999        frame_dst: FrameDestination,
1000    ) {
1001        let buf = ArpPacketBuilder::new(op, sender_mac, sender_ipv4, target_mac, target_ipv4)
1002            .into_serializer()
1003            .serialize_vec_outer(&mut NetworkSerializationContext::default())
1004            .unwrap();
1005        let (hw, proto) = peek_arp_types(buf.as_ref()).unwrap();
1006        assert_eq!(hw, ArpHardwareType::Ethernet);
1007        assert_eq!(proto, ArpNetworkType::Ipv4);
1008
1009        handle_packet::<_, _, _, _>(
1010            core_ctx,
1011            bindings_ctx,
1012            FakeLinkDeviceId,
1013            sender_mac,
1014            frame_dst,
1015            buf,
1016        );
1017    }
1018
1019    // Validate that buf is an ARP packet with the specific op, local_ipv4,
1020    // remote_ipv4, local_mac and remote_mac.
1021    fn validate_arp_packet(
1022        mut buf: &[u8],
1023        op: ArpOp,
1024        local_ipv4: Ipv4Addr,
1025        remote_ipv4: Ipv4Addr,
1026        local_mac: Mac,
1027        remote_mac: Mac,
1028    ) {
1029        let packet = buf.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap();
1030        assert_eq!(packet.sender_hardware_address(), local_mac);
1031        assert_eq!(packet.target_hardware_address(), remote_mac);
1032        assert_eq!(packet.sender_protocol_address(), local_ipv4);
1033        assert_eq!(packet.target_protocol_address(), remote_ipv4);
1034        assert_eq!(packet.operation(), op);
1035    }
1036
1037    // Validate that we've sent `total_frames` frames in total, and that the
1038    // most recent one was sent to `dst` with the given ARP packet contents.
1039    fn validate_last_arp_packet(
1040        core_ctx: &FakeCoreCtxImpl,
1041        total_frames: usize,
1042        dst: Mac,
1043        op: ArpOp,
1044        local_ipv4: Ipv4Addr,
1045        remote_ipv4: Ipv4Addr,
1046        local_mac: Mac,
1047        remote_mac: Mac,
1048    ) {
1049        assert_eq!(core_ctx.frames().len(), total_frames);
1050        let (meta, frame) = &core_ctx.frames()[total_frames - 1];
1051        assert_eq!(meta.dst_addr.get(), dst);
1052        validate_arp_packet(frame, op, local_ipv4, remote_ipv4, local_mac, remote_mac);
1053    }
1054
1055    #[test]
1056    fn test_receive_gratuitous_arp_request() {
1057        // Test that, when we receive a gratuitous ARP request, we cache the
1058        // sender's address information, and we do not send a response.
1059
1060        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1061        send_arp_packet(
1062            &mut core_ctx,
1063            &mut bindings_ctx,
1064            ArpOp::Request,
1065            TEST_REMOTE_IPV4,
1066            TEST_REMOTE_IPV4,
1067            TEST_REMOTE_MAC,
1068            TEST_INVALID_MAC,
1069            FrameDestination::Individual { local: false },
1070        );
1071
1072        // We should have cached the sender's address information.
1073        assert_dynamic_neighbor_with_addr(
1074            &mut core_ctx,
1075            FakeLinkDeviceId,
1076            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1077            UnicastAddr::new(TEST_REMOTE_MAC).unwrap(),
1078        );
1079        // Gratuitous ARPs should not prompt a response.
1080        assert_empty(core_ctx.frames().iter());
1081    }
1082
1083    #[test]
1084    fn test_receive_gratuitous_arp_response() {
1085        // Test that, when we receive a gratuitous ARP response, we cache the
1086        // sender's address information, and we do not send a response.
1087
1088        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1089        send_arp_packet(
1090            &mut core_ctx,
1091            &mut bindings_ctx,
1092            ArpOp::Response,
1093            TEST_REMOTE_IPV4,
1094            TEST_REMOTE_IPV4,
1095            TEST_REMOTE_MAC,
1096            TEST_REMOTE_MAC,
1097            FrameDestination::Individual { local: false },
1098        );
1099
1100        // We should have cached the sender's address information.
1101        assert_dynamic_neighbor_with_addr(
1102            &mut core_ctx,
1103            FakeLinkDeviceId,
1104            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1105            UnicastAddr::new(TEST_REMOTE_MAC).unwrap(),
1106        );
1107        // Gratuitous ARPs should not send a response.
1108        assert_empty(core_ctx.frames().iter());
1109    }
1110
1111    #[test]
1112    fn test_receive_gratuitous_arp_response_existing_request() {
1113        // Test that, if we have an outstanding request retry timer and receive
1114        // a gratuitous ARP for the same host, we cancel the timer and notify
1115        // the device layer.
1116
1117        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1118
1119        // Trigger link resolution.
1120        assert_neighbor_unknown(
1121            &mut core_ctx,
1122            FakeLinkDeviceId,
1123            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1124        );
1125        assert_eq!(
1126            NudHandler::send_ip_packet_to_neighbor(
1127                &mut core_ctx,
1128                &mut bindings_ctx,
1129                &FakeLinkDeviceId,
1130                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1131                Buf::new([1], ..),
1132                FakeTxMetadata::default(),
1133            ),
1134            Ok(())
1135        );
1136
1137        send_arp_packet(
1138            &mut core_ctx,
1139            &mut bindings_ctx,
1140            ArpOp::Response,
1141            TEST_REMOTE_IPV4,
1142            TEST_REMOTE_IPV4,
1143            TEST_REMOTE_MAC,
1144            TEST_REMOTE_MAC,
1145            FrameDestination::Individual { local: false },
1146        );
1147
1148        // The response should now be in our cache.
1149        assert_dynamic_neighbor_with_addr(
1150            &mut core_ctx,
1151            FakeLinkDeviceId,
1152            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1153            UnicastAddr::new(TEST_REMOTE_MAC).unwrap(),
1154        );
1155
1156        // Gratuitous ARPs should not send a response (the 1 frame is for the
1157        // original request).
1158        assert_eq!(core_ctx.frames().len(), 1);
1159    }
1160
1161    #[test_case(TEST_LOCAL_IPV4)]
1162    #[test_case(TEST_LOCAL_IPV4_2)]
1163    fn test_handle_arp_request(local_addr: Ipv4Addr) {
1164        // Test that, when we receive an ARP request, we cache the sender's
1165        // address information and send an ARP response.
1166
1167        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1168
1169        send_arp_packet(
1170            &mut core_ctx,
1171            &mut bindings_ctx,
1172            ArpOp::Request,
1173            TEST_REMOTE_IPV4,
1174            local_addr,
1175            TEST_REMOTE_MAC,
1176            TEST_LOCAL_MAC,
1177            FrameDestination::Individual { local: true },
1178        );
1179
1180        // Make sure we cached the sender's address information.
1181        assert_dynamic_neighbor_with_addr(
1182            &mut core_ctx,
1183            FakeLinkDeviceId,
1184            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1185            UnicastAddr::new(TEST_REMOTE_MAC).unwrap(),
1186        );
1187
1188        // We should have sent an ARP response.
1189        validate_last_arp_packet(
1190            &core_ctx,
1191            1,
1192            TEST_REMOTE_MAC,
1193            ArpOp::Response,
1194            local_addr,
1195            TEST_REMOTE_IPV4,
1196            TEST_LOCAL_MAC,
1197            TEST_REMOTE_MAC,
1198        );
1199    }
1200
1201    struct ArpHostConfig<'a> {
1202        name: &'a str,
1203        proto_addr: Ipv4Addr,
1204        hw_addr: Mac,
1205    }
1206
1207    #[test_case(ArpHostConfig {
1208                    name: "remote",
1209                    proto_addr: TEST_REMOTE_IPV4,
1210                    hw_addr: TEST_REMOTE_MAC
1211                },
1212                vec![]
1213    )]
1214    #[test_case(ArpHostConfig {
1215                    name: "requested_remote",
1216                    proto_addr: TEST_REMOTE_IPV4,
1217                    hw_addr: TEST_REMOTE_MAC
1218                },
1219                vec![
1220                    ArpHostConfig {
1221                        name: "non_requested_remote",
1222                        proto_addr: TEST_ANOTHER_REMOTE_IPV4,
1223                        hw_addr: TEST_REMOTE_MAC
1224                    }
1225                ]
1226    )]
1227    fn test_address_resolution(
1228        requested_remote_cfg: ArpHostConfig<'_>,
1229        other_remote_cfgs: Vec<ArpHostConfig<'_>>,
1230    ) {
1231        // Test a basic ARP resolution scenario.
1232        // We expect the following steps:
1233        // 1. When a lookup is performed and results in a cache miss, we send an
1234        //    ARP request and set a request retry timer.
1235        // 2. When the requested remote receives the request, it populates its cache with
1236        //    the local's information, and sends an ARP reply.
1237        // 3. Any non-requested remotes will neither populate their caches nor send ARP replies.
1238        // 4. When the reply is received, the timer is canceled, the table is
1239        //    updated, a new entry expiration timer is installed, and the device
1240        //    layer is notified of the resolution.
1241
1242        const LOCAL_HOST_CFG: ArpHostConfig<'_> =
1243            ArpHostConfig { name: "local", proto_addr: TEST_LOCAL_IPV4, hw_addr: TEST_LOCAL_MAC };
1244        let host_iter = other_remote_cfgs
1245            .iter()
1246            .chain(iter::once(&requested_remote_cfg))
1247            .chain(iter::once(&LOCAL_HOST_CFG));
1248
1249        let mut network = ArpNetworkSpec::new_network(
1250            {
1251                host_iter.clone().map(|cfg| {
1252                    let ArpHostConfig { name, proto_addr, hw_addr } = cfg;
1253                    let mut ctx = new_context();
1254                    let CtxPair { core_ctx, bindings_ctx: _ } = &mut ctx;
1255                    core_ctx.state.hw_addr = UnicastAddr::new(*hw_addr).unwrap();
1256                    core_ctx.state.proto_addrs = vec![*proto_addr];
1257                    (*name, ctx)
1258                })
1259            },
1260            |ctx: &str, meta: ArpFrameMetadata<_, _>| {
1261                host_iter
1262                    .clone()
1263                    .filter_map(|cfg| {
1264                        let ArpHostConfig { name, proto_addr: _, hw_addr: _ } = cfg;
1265                        if !ctx.eq(*name) { Some((*name, meta.clone(), None)) } else { None }
1266                    })
1267                    .collect::<Vec<_>>()
1268            },
1269        );
1270
1271        let ArpHostConfig {
1272            name: local_name,
1273            proto_addr: local_proto_addr,
1274            hw_addr: local_hw_addr,
1275        } = LOCAL_HOST_CFG;
1276
1277        let ArpHostConfig {
1278            name: requested_remote_name,
1279            proto_addr: requested_remote_proto_addr,
1280            hw_addr: requested_remote_hw_addr,
1281        } = requested_remote_cfg;
1282
1283        // Trigger link resolution.
1284        network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx }| {
1285            assert_neighbor_unknown(
1286                core_ctx,
1287                FakeLinkDeviceId,
1288                SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1289            );
1290            assert_eq!(
1291                NudHandler::send_ip_packet_to_neighbor(
1292                    core_ctx,
1293                    bindings_ctx,
1294                    &FakeLinkDeviceId,
1295                    SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1296                    Buf::new([1], ..),
1297                    FakeTxMetadata::default(),
1298                ),
1299                Ok(())
1300            );
1301
1302            // We should have sent an ARP request.
1303            validate_last_arp_packet(
1304                core_ctx,
1305                1,
1306                Mac::BROADCAST,
1307                ArpOp::Request,
1308                local_proto_addr,
1309                requested_remote_proto_addr,
1310                local_hw_addr,
1311                Mac::UNSPECIFIED,
1312            );
1313        });
1314        // Step once to deliver the ARP request to the remotes.
1315        let res = network.step();
1316        assert_eq!(res.timers_fired, 0);
1317
1318        // Our faked broadcast network should deliver frames to every host other
1319        // than the sender itself. These should include all non-participating remotes
1320        // and either the local or the participating remote, depending on who is
1321        // sending the packet.
1322        let expected_frames_sent_bcast = other_remote_cfgs.len() + 1;
1323        assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1324
1325        // The requested remote should have populated its ARP cache with the local's
1326        // information.
1327        network.with_context(requested_remote_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1328            assert_dynamic_neighbor_with_addr(
1329                core_ctx,
1330                FakeLinkDeviceId,
1331                SpecifiedAddr::new(local_proto_addr).unwrap(),
1332                UnicastAddr::new(LOCAL_HOST_CFG.hw_addr).unwrap(),
1333            );
1334
1335            // The requested remote should have sent an ARP response.
1336            validate_last_arp_packet(
1337                core_ctx,
1338                1,
1339                local_hw_addr,
1340                ArpOp::Response,
1341                requested_remote_proto_addr,
1342                local_proto_addr,
1343                requested_remote_hw_addr,
1344                local_hw_addr,
1345            );
1346        });
1347
1348        // Step once to deliver the ARP response to the local.
1349        let res = network.step();
1350        assert_eq!(res.timers_fired, 0);
1351        assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1352
1353        // The local should have populated its cache with the remote's
1354        // information.
1355        network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1356            assert_dynamic_neighbor_with_addr(
1357                core_ctx,
1358                FakeLinkDeviceId,
1359                SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1360                UnicastAddr::new(requested_remote_hw_addr).unwrap(),
1361            );
1362        });
1363
1364        other_remote_cfgs.iter().for_each(
1365            |ArpHostConfig { name: unrequested_remote_name, proto_addr: _, hw_addr: _ }| {
1366                // The non-requested_remote should not have populated its ARP cache.
1367                network.with_context(
1368                    *unrequested_remote_name,
1369                    |CtxPair { core_ctx, bindings_ctx: _ }| {
1370                        // The non-requested_remote should not have sent an ARP response.
1371                        assert_empty(core_ctx.frames().iter());
1372
1373                        assert_neighbor_unknown(
1374                            core_ctx,
1375                            FakeLinkDeviceId,
1376                            SpecifiedAddr::new(local_proto_addr).unwrap(),
1377                        );
1378                    },
1379                )
1380            },
1381        );
1382    }
1383
1384    #[test_case(FrameDestination::Individual { local: true }, true; "unicast to us is solicited")]
1385    #[test_case(
1386        FrameDestination::Individual { local: false },
1387        false;
1388        "unicast to other addr is unsolicited"
1389    )]
1390    #[test_case(FrameDestination::Multicast, false; "multicast reply is unsolicited")]
1391    #[test_case(FrameDestination::Broadcast, false; "broadcast reply is unsolicited")]
1392    fn only_unicast_reply_treated_as_solicited(
1393        frame_dst: FrameDestination,
1394        expect_solicited: bool,
1395    ) {
1396        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1397
1398        // Trigger link resolution.
1399        assert_neighbor_unknown(
1400            &mut core_ctx,
1401            FakeLinkDeviceId,
1402            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1403        );
1404        assert_eq!(
1405            NudHandler::send_ip_packet_to_neighbor(
1406                &mut core_ctx,
1407                &mut bindings_ctx,
1408                &FakeLinkDeviceId,
1409                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1410                Buf::new([1], ..),
1411                FakeTxMetadata::default(),
1412            ),
1413            Ok(())
1414        );
1415
1416        // Now send a confirmation with the specified frame destination.
1417        send_arp_packet(
1418            &mut core_ctx,
1419            &mut bindings_ctx,
1420            ArpOp::Response,
1421            TEST_REMOTE_IPV4,
1422            TEST_LOCAL_IPV4,
1423            TEST_REMOTE_MAC,
1424            TEST_LOCAL_MAC,
1425            frame_dst,
1426        );
1427
1428        // If the confirmation was interpreted as solicited, the entry should be
1429        // marked as REACHABLE; otherwise, it should have transitioned to STALE.
1430        let expected_state = if expect_solicited {
1431            DynamicNeighborState::Reachable(Reachable {
1432                link_address: UnicastAddr::new(TEST_REMOTE_MAC).unwrap(),
1433                last_confirmed_at: bindings_ctx.now(),
1434            })
1435        } else {
1436            DynamicNeighborState::Stale(Stale {
1437                link_address: UnicastAddr::new(TEST_REMOTE_MAC).unwrap(),
1438            })
1439        };
1440        assert_dynamic_neighbor_state(
1441            &mut core_ctx,
1442            FakeLinkDeviceId,
1443            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1444            expected_state,
1445        );
1446    }
1447
1448    // Test that we ignore ARP packets that have our hardware address as the
1449    // sender hardware address.
1450    #[test]
1451    fn test_drop_echoed_arp_packet() {
1452        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1453
1454        // Receive an ARP packet that matches an ARP probe (as specified in
1455        // RFC 5227 section 2.1.1) that has been echoed back to ourselves.
1456        send_arp_packet(
1457            &mut core_ctx,
1458            &mut bindings_ctx,
1459            ArpOp::Request,
1460            Ipv4::UNSPECIFIED_ADDRESS, /* sender_ipv4 */
1461            TEST_LOCAL_IPV4,           /* target_ipv4 */
1462            TEST_LOCAL_MAC,            /* sender_mac */
1463            Mac::UNSPECIFIED,          /* target_mac */
1464            FrameDestination::Broadcast,
1465        );
1466
1467        // We should not have cached the sender's address information.
1468        assert_neighbor_unknown(
1469            &mut core_ctx,
1470            FakeLinkDeviceId,
1471            SpecifiedAddr::new(TEST_LOCAL_IPV4).unwrap(),
1472        );
1473
1474        // We should not have sent an ARP response.
1475        assert_eq!(core_ctx.frames().len(), 0);
1476    }
1477
1478    // Test sending an ARP probe as specified in Address Conflict Detection.
1479    #[test]
1480    fn test_send_arp_probe() {
1481        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1482
1483        const LOCAL_IP: Ipv4Addr = Ipv4::UNSPECIFIED_ADDRESS;
1484        send_arp_request(
1485            &mut core_ctx,
1486            &mut bindings_ctx,
1487            &FakeLinkDeviceId,
1488            LOCAL_IP,
1489            TEST_REMOTE_IPV4,
1490            None,
1491        );
1492
1493        // We should have sent 1 ARP Request.
1494        let (meta, frame) = assert_matches!(core_ctx.frames(), [frame] => frame);
1495        // The request should have been broadcast, with the destination MAC
1496        // left unspecified.
1497        assert_eq!(meta.dst_addr.get(), Mac::BROADCAST);
1498        validate_arp_packet(
1499            frame,
1500            ArpOp::Request,
1501            LOCAL_IP,
1502            TEST_REMOTE_IPV4,
1503            TEST_LOCAL_MAC,
1504            Mac::UNSPECIFIED,
1505        );
1506    }
1507
1508    // Test receiving an ARP packet and dispatching it to the IP Layer.
1509    #[test_case(ArpOp::Request, TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, true; "dispatch_request")]
1510    #[test_case(ArpOp::Response, TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, true; "dispatch_reply")]
1511    #[test_case(ArpOp::Request, Ipv4::UNSPECIFIED_ADDRESS, TEST_LOCAL_IPV4, true; "dispatch_probe")]
1512    #[test_case(ArpOp::Other(99), TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, false; "ignore_other")]
1513    fn test_receive_arp_packet(
1514        op: ArpOp,
1515        sender_addr: Ipv4Addr,
1516        target_addr: Ipv4Addr,
1517        expect_dispatch: bool,
1518    ) {
1519        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1520
1521        send_arp_packet(
1522            &mut core_ctx,
1523            &mut bindings_ctx,
1524            op,
1525            sender_addr,
1526            target_addr,
1527            TEST_REMOTE_MAC,
1528            TEST_LOCAL_MAC,
1529            FrameDestination::Broadcast,
1530        );
1531
1532        let is_arp_probe = sender_addr == Ipv4::UNSPECIFIED_ADDRESS && op == ArpOp::Request;
1533
1534        if expect_dispatch {
1535            assert_eq!(
1536                &core_ctx.state.dispatched_arp_packets[..],
1537                [(sender_addr, target_addr, is_arp_probe)]
1538            );
1539        } else {
1540            assert_eq!(&core_ctx.state.dispatched_arp_packets[..], []);
1541        }
1542    }
1543
1544    #[test]
1545    fn test_ignore_duplicate_response_within_lock_time() {
1546        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1547
1548        // Trigger link resolution.
1549        assert_neighbor_unknown(
1550            &mut core_ctx,
1551            FakeLinkDeviceId,
1552            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1553        );
1554        assert_eq!(
1555            NudHandler::send_ip_packet_to_neighbor(
1556                &mut core_ctx,
1557                &mut bindings_ctx,
1558                &FakeLinkDeviceId,
1559                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1560                Buf::new([1], ..),
1561                FakeTxMetadata::default(),
1562            ),
1563            Ok(())
1564        );
1565
1566        let send_arp_response = |core_ctx: &mut _, bindings_ctx: &mut _, mac| {
1567            send_arp_packet(
1568                core_ctx,
1569                bindings_ctx,
1570                ArpOp::Response,
1571                TEST_REMOTE_IPV4,
1572                TEST_LOCAL_IPV4,
1573                mac,
1574                TEST_LOCAL_MAC,
1575                FrameDestination::Individual { local: true },
1576            );
1577        };
1578        let verify_addr = |core_ctx: &mut _, mac| {
1579            assert_dynamic_neighbor_with_addr(
1580                core_ctx,
1581                FakeLinkDeviceId,
1582                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1583                UnicastAddr::new(mac).unwrap(),
1584            );
1585        };
1586
1587        // Receive an ARP response.
1588        send_arp_response(&mut core_ctx, &mut bindings_ctx, TEST_REMOTE_MAC);
1589
1590        // Verify state is REACHABLE with TEST_REMOTE_MAC.
1591        verify_addr(&mut core_ctx, TEST_REMOTE_MAC);
1592
1593        // Receive another ARP response with a different MAC address shortly
1594        // after the first one. This should be ignored because it's within the
1595        // override lock time (FakeArpConfigCtx::override_lock_time returns 1s).
1596        const SPOOFED_MAC: Mac = Mac::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
1597        bindings_ctx.timers.instant.sleep(Duration::from_millis(100));
1598        send_arp_response(&mut core_ctx, &mut bindings_ctx, SPOOFED_MAC);
1599
1600        // Verify state is REACHABLE with the old MAC (TEST_REMOTE_MAC).
1601        verify_addr(&mut core_ctx, TEST_REMOTE_MAC);
1602
1603        // Receive the "spoofed" ARP response again after 1 second. Now it
1604        // should be accepted.
1605        bindings_ctx.timers.instant.sleep(ARP_OVERRIDE_LOCK_TIME);
1606        send_arp_response(&mut core_ctx, &mut bindings_ctx, SPOOFED_MAC);
1607
1608        // Verify state updated to REACHABLE with SPOOFED_MAC.
1609        verify_addr(&mut core_ctx, SPOOFED_MAC);
1610    }
1611
1612    #[test]
1613    fn test_gratuitous_arp_response_within_lock_time() {
1614        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1615
1616        // Trigger link resolution.
1617        assert_neighbor_unknown(
1618            &mut core_ctx,
1619            FakeLinkDeviceId,
1620            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1621        );
1622        assert_eq!(
1623            NudHandler::send_ip_packet_to_neighbor(
1624                &mut core_ctx,
1625                &mut bindings_ctx,
1626                &FakeLinkDeviceId,
1627                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1628                Buf::new([1], ..),
1629                FakeTxMetadata::default(),
1630            ),
1631            Ok(())
1632        );
1633
1634        // Receive an ARP response.
1635        send_arp_packet(
1636            &mut core_ctx,
1637            &mut bindings_ctx,
1638            ArpOp::Response,
1639            TEST_REMOTE_IPV4,
1640            TEST_LOCAL_IPV4,
1641            TEST_REMOTE_MAC,
1642            TEST_LOCAL_MAC,
1643            FrameDestination::Individual { local: true },
1644        );
1645
1646        // Verify state is REACHABLE with TEST_REMOTE_MAC.
1647        assert_dynamic_neighbor_state(
1648            &mut core_ctx,
1649            FakeLinkDeviceId,
1650            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1651            DynamicNeighborState::Reachable(Reachable {
1652                link_address: UnicastAddr::new(TEST_REMOTE_MAC).unwrap(),
1653                last_confirmed_at: bindings_ctx.now(),
1654            }),
1655        );
1656
1657        // Receive gratuitous ARP response with a different MAC address shortly
1658        // after the direct ARP response.
1659        const NEW_MAC: Mac = Mac::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
1660        bindings_ctx.timers.instant.sleep(Duration::from_millis(100));
1661        send_arp_packet(
1662            &mut core_ctx,
1663            &mut bindings_ctx,
1664            ArpOp::Response,
1665            TEST_REMOTE_IPV4,
1666            TEST_REMOTE_IPV4,
1667            NEW_MAC,
1668            NEW_MAC,
1669            FrameDestination::Individual { local: false },
1670        );
1671
1672        // Verify state is STALE with NEW_MAC.
1673        assert_dynamic_neighbor_state(
1674            &mut core_ctx,
1675            FakeLinkDeviceId,
1676            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1677            DynamicNeighborState::Stale(Stale { link_address: UnicastAddr::new(NEW_MAC).unwrap() }),
1678        );
1679    }
1680}