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::{SpecifiedAddr, UnicastAddr, Witness as _};
14use netstack3_base::{
15    CoreTimerContext, Counter, CounterContext, DeviceIdContext, EventContext, FrameDestination,
16    InstantBindingsTypes, LinkDevice, SendFrameContext, SendFrameError, TimerContext,
17    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, Serializer};
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: 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: D::Address,
84        body: S,
85        meta: BC::TxMetadata,
86    ) -> Result<(), SendFrameError<S>>
87    where
88        S: Serializer,
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: 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<<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: D::Address,
341        body: S,
342        meta: BC::TxMetadata,
343    ) -> Result<(), SendFrameError<S>>
344    where
345        S: Serializer,
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    // If the sender's hardware address is *our* hardware address, this is
435    // an echoed ARP packet (e.g. the network reflected back an ARP packet that
436    // we sent). Here we deviate from the behavior specified in RFC 826 (which
437    // makes no comment on handling echoed ARP packets), and drop the packet.
438    // There's no benefit to tracking our own ARP packets in the ARP table, and
439    // some RFCs built on top of ARP (i.e. RFC 5227 - IPv4 Address Conflict
440    // Detection) explicitly call out that echoed ARP packets should be ignored.
441    let sender_hw_addr = packet.sender_hardware_address();
442    if sender_hw_addr == *core_ctx.get_hardware_addr(bindings_ctx, &device_id) {
443        core_ctx.counters().rx_echoed_packets.increment();
444        debug!("dropping an echoed ARP packet: {op:?}");
445        return;
446    }
447
448    let sender_addr = packet.sender_protocol_address();
449    let target_addr = packet.target_protocol_address();
450
451    // As per RFC 5227, section 1.1:
452    // the term 'ARP Probe' is used to refer to an ARP Request packet, broadcast
453    // on the local link, with an all-zero 'sender IP address'.
454    let is_arp_probe = sender_addr == Ipv4::UNSPECIFIED_ADDRESS
455        && packet.operation() == ArpOp::Request
456        && frame_dst == FrameDestination::Broadcast;
457
458    // As Per RFC 5227, section 2.1.1 dispatch any received ARP packet
459    // (Request *or* Reply) to the DAD engine.
460    let targets_interface = core_ctx.on_arp_packet(
461        bindings_ctx,
462        &device_id,
463        frame_src,
464        sender_hw_addr,
465        sender_addr,
466        target_addr,
467        is_arp_probe,
468    );
469
470    enum PacketKind {
471        Gratuitous,
472        AddressedToMe,
473    }
474
475    // The following logic is equivalent to the "Packet Reception" section of
476    // RFC 826.
477    //
478    // We statically know that the hardware type and protocol type are correct,
479    // so we do not need to have additional code to check that. The remainder of
480    // the algorithm is:
481    //
482    // Merge_flag := false
483    // If the pair <protocol type, sender protocol address> is
484    //     already in my translation table, update the sender
485    //     hardware address field of the entry with the new
486    //     information in the packet and set Merge_flag to true.
487    // ?Am I the target protocol address?
488    // Yes:
489    //   If Merge_flag is false, add the triplet <protocol type,
490    //       sender protocol address, sender hardware address> to
491    //       the translation table.
492    //   ?Is the opcode ares_op$REQUEST?  (NOW look at the opcode!!)
493    //   Yes:
494    //     Swap hardware and protocol fields, putting the local
495    //         hardware and protocol addresses in the sender fields.
496    //     Set the ar$op field to ares_op$REPLY
497    //     Send the packet to the (new) target hardware address on
498    //         the same hardware on which the request was received.
499    //
500    // This can be summed up as follows:
501    //
502    // +----------+---------------+---------------+-----------------------------+
503    // | opcode   | Am I the TPA? | SPA in table? | action                      |
504    // +----------+---------------+---------------+-----------------------------+
505    // | REQUEST  | yes           | yes           | Update table, Send response |
506    // | REQUEST  | yes           | no            | Update table, Send response |
507    // | REQUEST  | no            | yes           | Update table                |
508    // | REQUEST  | no            | no            | NOP                         |
509    // | RESPONSE | yes           | yes           | Update table                |
510    // | RESPONSE | yes           | no            | Update table                |
511    // | RESPONSE | no            | yes           | Update table                |
512    // | RESPONSE | no            | no            | NOP                         |
513    // +----------+---------------+---------------+-----------------------------+
514
515    let garp = sender_addr == target_addr;
516    let (source, kind) = match (garp, targets_interface) {
517        (true, false) => {
518            // Treat all GARP messages as neighbor probes as GARPs are not
519            // responses for previously sent requests, even if the packet
520            // operation is a response OP code.
521            //
522            // Per RFC 5944 section 4.6,
523            //
524            //   A Gratuitous ARP [45] is an ARP packet sent by a node in order
525            //   to spontaneously cause other nodes to update an entry in their
526            //   ARP cache. A gratuitous ARP MAY use either an ARP Request or an
527            //   ARP Reply packet. In either case, the ARP Sender Protocol
528            //   Address and ARP Target Protocol Address are both set to the IP
529            //   address of the cache entry to be updated, and the ARP Sender
530            //   Hardware Address is set to the link-layer address to which this
531            //   cache entry should be updated. When using an ARP Reply packet,
532            //   the Target Hardware Address is also set to the link-layer
533            //   address to which this cache entry should be updated (this field
534            //   is not used in an ARP Request packet).
535            //
536            //   In either case, for a gratuitous ARP, the ARP packet MUST be
537            //   transmitted as a local broadcast packet on the local link. As
538            //   specified in [16], any node receiving any ARP packet (Request
539            //   or Reply) MUST update its local ARP cache with the Sender
540            //   Protocol and Hardware Addresses in the ARP packet, if the
541            //   receiving node has an entry for that IP address already in its
542            //   ARP cache. This requirement in the ARP protocol applies even
543            //   for ARP Request packets, and for ARP Reply packets that do not
544            //   match any ARP Request transmitted by the receiving node [16].
545            (
546                DynamicNeighborUpdateSource::Probe { link_address: sender_hw_addr },
547                PacketKind::Gratuitous,
548            )
549        }
550        (false, true) => {
551            // Consider ARP replies as solicited if they were unicast directly to us, and
552            // unsolicited otherwise.
553            let solicited = match frame_dst {
554                FrameDestination::Individual { local } => local,
555                FrameDestination::Broadcast | FrameDestination::Multicast => false,
556            };
557            let source = match op {
558                ValidArpOp::Request => {
559                    DynamicNeighborUpdateSource::Probe { link_address: sender_hw_addr }
560                }
561                ValidArpOp::Response => {
562                    DynamicNeighborUpdateSource::Confirmation {
563                        link_address: Some(sender_hw_addr),
564                        flags: ConfirmationFlags {
565                            solicited_flag: solicited,
566                            // ARP does not have the concept of an override flag in a neighbor
567                            // confirmation. In order to ensure we don't fail to update a cached
568                            // link address when a neighbor informs us of the update, always
569                            // consider ARP replies as overrides.
570                            override_flag: true,
571                        },
572                    }
573                }
574            };
575            (source, PacketKind::AddressedToMe)
576        }
577        (false, false) => {
578            core_ctx.counters().rx_dropped_non_local_target.increment();
579            trace!(
580                "non-gratuitous ARP packet not targetting us; sender = {}, target={}",
581                sender_addr, target_addr
582            );
583            return;
584        }
585        (true, true) => {
586            warn!(
587                "got gratuitous ARP packet with our address {target_addr} on device {device_id:?}, \
588                dropping...",
589            );
590            return;
591        }
592    };
593
594    if let Some(addr) = SpecifiedAddr::new(sender_addr) {
595        NudHandler::<Ipv4, D, _>::handle_neighbor_update(
596            core_ctx,
597            bindings_ctx,
598            &device_id,
599            addr,
600            source,
601        )
602    };
603
604    match kind {
605        PacketKind::Gratuitous => return,
606        PacketKind::AddressedToMe => match source {
607            DynamicNeighborUpdateSource::Probe { .. } => {
608                let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, &device_id);
609
610                core_ctx.counters().tx_responses.increment();
611                debug!("sending ARP response for {target_addr} to {sender_addr}");
612
613                SendFrameContext::send_frame(
614                    core_ctx,
615                    bindings_ctx,
616                    ArpFrameMetadata { device_id, dst_addr: sender_hw_addr },
617                    ArpPacketBuilder::new(
618                        ArpOp::Response,
619                        self_hw_addr.get(),
620                        target_addr,
621                        sender_hw_addr,
622                        sender_addr,
623                    )
624                    .into_serializer_with(buffer),
625                )
626                .unwrap_or_else(|serializer| {
627                    warn!(
628                        "failed to send ARP response for {target_addr} to {sender_addr}: \
629                        {serializer:?}"
630                    )
631                });
632            }
633            DynamicNeighborUpdateSource::Confirmation { .. } => {}
634        },
635    }
636}
637
638/// Sends an Arp Request for the provided lookup_addr.
639///
640/// If remote_link_addr is provided, it will be the destination of the request.
641/// If unset, the request will be broadcast.
642pub fn send_arp_request<
643    D: ArpDevice,
644    BC: ArpBindingsContext<D, CC::DeviceId>,
645    CC: ArpContext<D, BC> + CounterContext<ArpCounters>,
646>(
647    core_ctx: &mut CC,
648    bindings_ctx: &mut BC,
649    device_id: &CC::DeviceId,
650    sender_addr: Ipv4Addr,
651    lookup_addr: Ipv4Addr,
652    remote_link_addr: Option<D::Address>,
653) {
654    let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, device_id);
655    let dst_addr = remote_link_addr.unwrap_or(D::Address::BROADCAST);
656    core_ctx.counters().tx_requests.increment();
657    debug!("sending ARP request for {lookup_addr} to {dst_addr:?}");
658    SendFrameContext::send_frame(
659        core_ctx,
660        bindings_ctx,
661        ArpFrameMetadata { device_id: device_id.clone(), dst_addr },
662        ArpPacketBuilder::new(
663            ArpOp::Request,
664            self_hw_addr.get(),
665            sender_addr,
666            // This field is relatively meaningless, since RFC 826 does not
667            // specify the behavior. However, RFC 5227 section 2.1.1. specifies
668            // that the target hardware address SHOULD be set to all 0s when
669            // sending an Address Conflict Detection probe.
670            //
671            // To accommodate this, we use the `remote_link_addr` if provided,
672            // or otherwise the unspecified address. Notably this makes the
673            // ARP target hardware address field differ from the destination
674            // address in the Frame Metadata.
675            remote_link_addr.unwrap_or(D::Address::UNSPECIFIED),
676            lookup_addr,
677        )
678        .into_serializer(),
679    )
680    .unwrap_or_else(|serializer| {
681        warn!("failed to send ARP request for {lookup_addr} to {dst_addr:?}: {serializer:?}")
682    });
683}
684
685/// The state associated with an instance of the Address Resolution Protocol
686/// (ARP).
687///
688/// Each device will contain an `ArpState` object for each of the network
689/// protocols that it supports.
690pub struct ArpState<D: ArpDevice, BT: NudBindingsTypes<D>> {
691    pub(crate) nud: NudState<Ipv4, D, BT>,
692}
693
694impl<D: ArpDevice, BC: NudBindingsTypes<D> + TimerContext> ArpState<D, BC> {
695    /// Creates a new `ArpState` for `device_id`.
696    pub fn new<
697        DeviceId: WeakDeviceIdentifier,
698        CC: CoreTimerContext<ArpTimerId<D, DeviceId>, BC>,
699    >(
700        bindings_ctx: &mut BC,
701        device_id: DeviceId,
702    ) -> Self {
703        ArpState { nud: NudState::new::<_, CC>(bindings_ctx, device_id) }
704    }
705}
706
707#[cfg(test)]
708mod tests {
709    use alloc::vec;
710    use alloc::vec::Vec;
711    use core::iter;
712    use net_types::ip::Ip;
713    use packet_formats::ip::Ipv4Proto;
714
715    use assert_matches::assert_matches;
716    use net_types::ethernet::Mac;
717    use netstack3_base::socket::SocketIpAddr;
718    use netstack3_base::testutil::{
719        FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeLinkDeviceId, FakeNetworkSpec,
720        FakeTimerId, FakeTxMetadata, FakeWeakDeviceId, WithFakeFrameContext, assert_empty,
721    };
722    use netstack3_base::{CtxPair, InstantContext as _, IntoCoreTimerCtx, TimerHandler};
723    use netstack3_ip::nud::testutil::{
724        assert_dynamic_neighbor_state, assert_dynamic_neighbor_with_addr, assert_neighbor_unknown,
725    };
726    use netstack3_ip::nud::{
727        DelegateNudContext, DynamicNeighborState, NudCounters, NudIcmpContext, Reachable, Stale,
728        UseDelegateNudContext,
729    };
730    use packet::{Buf, ParseBuffer};
731    use packet_formats::arp::{ArpHardwareType, ArpNetworkType, peek_arp_types};
732    use packet_formats::ipv4::Ipv4FragmentType;
733    use test_case::test_case;
734
735    use super::*;
736    use crate::internal::ethernet::EthernetLinkDevice;
737
738    const TEST_LOCAL_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
739    const TEST_LOCAL_IPV4_2: Ipv4Addr = Ipv4Addr::new([4, 5, 6, 7]);
740    const TEST_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
741    const TEST_ANOTHER_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([9, 10, 11, 12]);
742    const TEST_LOCAL_MAC: Mac = Mac::new([0, 1, 2, 3, 4, 5]);
743    const TEST_REMOTE_MAC: Mac = Mac::new([6, 7, 8, 9, 10, 11]);
744    const TEST_INVALID_MAC: Mac = Mac::new([0, 0, 0, 0, 0, 0]);
745
746    /// A fake `ArpContext` that stores frames, address resolution events, and
747    /// address resolution failure events.
748    struct FakeArpCtx {
749        proto_addrs: Vec<Ipv4Addr>,
750        hw_addr: UnicastAddr<Mac>,
751        arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
752        inner: FakeArpInnerCtx,
753        config: FakeArpConfigCtx,
754        counters: ArpCounters,
755        nud_counters: NudCounters<Ipv4>,
756        // Stores received ARP packets that were dispatched to the IP Layer.
757        // Holds a tuple of (sender_addr, target_addr, is_arp_probe).
758        dispatched_arp_packets: Vec<(Ipv4Addr, Ipv4Addr, bool)>,
759    }
760
761    /// A fake `ArpSenderContext` that sends IP packets.
762    struct FakeArpInnerCtx;
763
764    /// A fake `ArpConfigContext`.
765    struct FakeArpConfigCtx;
766
767    impl FakeArpCtx {
768        fn new(bindings_ctx: &mut FakeBindingsCtxImpl) -> FakeArpCtx {
769            FakeArpCtx {
770                proto_addrs: vec![TEST_LOCAL_IPV4, TEST_LOCAL_IPV4_2],
771                hw_addr: UnicastAddr::new(TEST_LOCAL_MAC).unwrap(),
772                arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
773                    bindings_ctx,
774                    FakeWeakDeviceId(FakeLinkDeviceId),
775                ),
776                inner: FakeArpInnerCtx,
777                config: FakeArpConfigCtx,
778                counters: Default::default(),
779                nud_counters: Default::default(),
780                dispatched_arp_packets: Default::default(),
781            }
782        }
783    }
784
785    type FakeBindingsCtxImpl = FakeBindingsCtx<
786        ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>,
787        nud::Event<Mac, FakeLinkDeviceId, Ipv4, FakeInstant>,
788        (),
789        (),
790    >;
791
792    type FakeCoreCtxImpl = FakeCoreCtx<
793        FakeArpCtx,
794        ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>,
795        FakeDeviceId,
796    >;
797
798    fn new_context() -> CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl> {
799        CtxPair::with_default_bindings_ctx(|bindings_ctx| {
800            FakeCoreCtxImpl::with_state(FakeArpCtx::new(bindings_ctx))
801        })
802    }
803
804    enum ArpNetworkSpec {}
805    impl FakeNetworkSpec for ArpNetworkSpec {
806        type Context = CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl>;
807        type TimerId = ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>;
808        type SendMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
809        type RecvMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
810
811        fn handle_frame(
812            ctx: &mut Self::Context,
813            ArpFrameMetadata { device_id, .. }: Self::RecvMeta,
814            data: Buf<Vec<u8>>,
815        ) {
816            let CtxPair { core_ctx, bindings_ctx } = ctx;
817            handle_packet(
818                core_ctx,
819                bindings_ctx,
820                device_id,
821                TEST_REMOTE_MAC,
822                FrameDestination::Individual { local: true },
823                data,
824            )
825        }
826        fn handle_timer(ctx: &mut Self::Context, dispatch: Self::TimerId, timer: FakeTimerId) {
827            let CtxPair { core_ctx, bindings_ctx } = ctx;
828            TimerHandler::handle_timer(core_ctx, bindings_ctx, dispatch, timer)
829        }
830
831        fn process_queues(_ctx: &mut Self::Context) -> bool {
832            false
833        }
834
835        fn fake_frames(ctx: &mut Self::Context) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
836            &mut ctx.core_ctx
837        }
838    }
839
840    impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxImpl {
841        type DeviceId = FakeLinkDeviceId;
842        type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
843    }
844
845    impl DeviceIdContext<EthernetLinkDevice> for FakeArpInnerCtx {
846        type DeviceId = FakeLinkDeviceId;
847        type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
848    }
849
850    impl ArpContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
851        type ConfigCtx<'a> = FakeArpConfigCtx;
852
853        type ArpSenderCtx<'a> = FakeArpInnerCtx;
854
855        fn with_arp_state_mut_and_sender_ctx<
856            O,
857            F: FnOnce(
858                &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
859                &mut Self::ArpSenderCtx<'_>,
860            ) -> O,
861        >(
862            &mut self,
863            FakeLinkDeviceId: &FakeLinkDeviceId,
864            cb: F,
865        ) -> O {
866            let FakeArpCtx { arp_state, inner, .. } = &mut self.state;
867            cb(arp_state, inner)
868        }
869
870        fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>) -> O>(
871            &mut self,
872            FakeLinkDeviceId: &FakeLinkDeviceId,
873            cb: F,
874        ) -> O {
875            cb(&self.state.arp_state)
876        }
877
878        fn get_protocol_addr(&mut self, _device_id: &FakeLinkDeviceId) -> Option<Ipv4Addr> {
879            self.state.proto_addrs.first().copied()
880        }
881
882        fn get_hardware_addr(
883            &mut self,
884            _bindings_ctx: &mut FakeBindingsCtxImpl,
885            _device_id: &FakeLinkDeviceId,
886        ) -> UnicastAddr<Mac> {
887            self.state.hw_addr
888        }
889
890        fn with_arp_state_mut<
891            O,
892            F: FnOnce(
893                &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
894                &mut Self::ConfigCtx<'_>,
895            ) -> O,
896        >(
897            &mut self,
898            FakeLinkDeviceId: &FakeLinkDeviceId,
899            cb: F,
900        ) -> O {
901            let FakeArpCtx { arp_state, config, .. } = &mut self.state;
902            cb(arp_state, config)
903        }
904    }
905
906    impl ArpIpLayerContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
907        fn on_arp_packet(
908            &mut self,
909            _bindings_ctx: &mut FakeBindingsCtxImpl,
910            _device_id: &FakeLinkDeviceId,
911            _frame_src: Mac,
912            _sender_hwaddr: Mac,
913            sender_addr: Ipv4Addr,
914            target_addr: Ipv4Addr,
915            is_arp_probe: bool,
916        ) -> bool {
917            self.state.dispatched_arp_packets.push((sender_addr, target_addr, is_arp_probe));
918
919            self.state.proto_addrs.iter().any(|&a| a == target_addr)
920        }
921    }
922
923    impl UseDelegateNudContext for FakeArpCtx {}
924    impl DelegateNudContext<Ipv4> for FakeArpCtx {
925        type Delegate<T> = ArpNudCtx<T>;
926    }
927
928    impl NudIcmpContext<Ipv4, EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
929        fn send_icmp_dest_unreachable(
930            &mut self,
931            _bindings_ctx: &mut FakeBindingsCtxImpl,
932            _frame: Buf<Vec<u8>>,
933            _device_id: Option<&Self::DeviceId>,
934            _original_src: SocketIpAddr<Ipv4Addr>,
935            _original_dst: SocketIpAddr<Ipv4Addr>,
936            _header_len: usize,
937            _proto: Ipv4Proto,
938            _metadata: Ipv4FragmentType,
939        ) {
940            panic!("send_icmp_dest_unreachable should not be called");
941        }
942    }
943
944    impl ArpConfigContext for FakeArpConfigCtx {
945        fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
946            cb(&NudUserConfig::default())
947        }
948    }
949    impl ArpConfigContext for FakeArpInnerCtx {
950        fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
951            cb(&NudUserConfig::default())
952        }
953    }
954
955    impl ArpSenderContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeArpInnerCtx {
956        fn send_ip_packet_to_neighbor_link_addr<S>(
957            &mut self,
958            _bindings_ctx: &mut FakeBindingsCtxImpl,
959            _dst_link_address: Mac,
960            _body: S,
961            _tx_meta: FakeTxMetadata,
962        ) -> Result<(), SendFrameError<S>> {
963            Ok(())
964        }
965    }
966
967    impl CounterContext<ArpCounters> for FakeArpCtx {
968        fn counters(&self) -> &ArpCounters {
969            &self.counters
970        }
971    }
972
973    impl CounterContext<NudCounters<Ipv4>> for FakeArpCtx {
974        fn counters(&self) -> &NudCounters<Ipv4> {
975            &self.nud_counters
976        }
977    }
978
979    fn send_arp_packet(
980        core_ctx: &mut FakeCoreCtxImpl,
981        bindings_ctx: &mut FakeBindingsCtxImpl,
982        op: ArpOp,
983        sender_ipv4: Ipv4Addr,
984        target_ipv4: Ipv4Addr,
985        sender_mac: Mac,
986        target_mac: Mac,
987        frame_dst: FrameDestination,
988    ) {
989        let buf = ArpPacketBuilder::new(op, sender_mac, sender_ipv4, target_mac, target_ipv4)
990            .into_serializer()
991            .serialize_vec_outer()
992            .unwrap();
993        let (hw, proto) = peek_arp_types(buf.as_ref()).unwrap();
994        assert_eq!(hw, ArpHardwareType::Ethernet);
995        assert_eq!(proto, ArpNetworkType::Ipv4);
996
997        handle_packet::<_, _, _, _>(
998            core_ctx,
999            bindings_ctx,
1000            FakeLinkDeviceId,
1001            sender_mac,
1002            frame_dst,
1003            buf,
1004        );
1005    }
1006
1007    // Validate that buf is an ARP packet with the specific op, local_ipv4,
1008    // remote_ipv4, local_mac and remote_mac.
1009    fn validate_arp_packet(
1010        mut buf: &[u8],
1011        op: ArpOp,
1012        local_ipv4: Ipv4Addr,
1013        remote_ipv4: Ipv4Addr,
1014        local_mac: Mac,
1015        remote_mac: Mac,
1016    ) {
1017        let packet = buf.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap();
1018        assert_eq!(packet.sender_hardware_address(), local_mac);
1019        assert_eq!(packet.target_hardware_address(), remote_mac);
1020        assert_eq!(packet.sender_protocol_address(), local_ipv4);
1021        assert_eq!(packet.target_protocol_address(), remote_ipv4);
1022        assert_eq!(packet.operation(), op);
1023    }
1024
1025    // Validate that we've sent `total_frames` frames in total, and that the
1026    // most recent one was sent to `dst` with the given ARP packet contents.
1027    fn validate_last_arp_packet(
1028        core_ctx: &FakeCoreCtxImpl,
1029        total_frames: usize,
1030        dst: Mac,
1031        op: ArpOp,
1032        local_ipv4: Ipv4Addr,
1033        remote_ipv4: Ipv4Addr,
1034        local_mac: Mac,
1035        remote_mac: Mac,
1036    ) {
1037        assert_eq!(core_ctx.frames().len(), total_frames);
1038        let (meta, frame) = &core_ctx.frames()[total_frames - 1];
1039        assert_eq!(meta.dst_addr, dst);
1040        validate_arp_packet(frame, op, local_ipv4, remote_ipv4, local_mac, remote_mac);
1041    }
1042
1043    #[test]
1044    fn test_receive_gratuitous_arp_request() {
1045        // Test that, when we receive a gratuitous ARP request, we cache the
1046        // sender's address information, and we do not send a response.
1047
1048        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1049        send_arp_packet(
1050            &mut core_ctx,
1051            &mut bindings_ctx,
1052            ArpOp::Request,
1053            TEST_REMOTE_IPV4,
1054            TEST_REMOTE_IPV4,
1055            TEST_REMOTE_MAC,
1056            TEST_INVALID_MAC,
1057            FrameDestination::Individual { local: false },
1058        );
1059
1060        // We should have cached the sender's address information.
1061        assert_dynamic_neighbor_with_addr(
1062            &mut core_ctx,
1063            FakeLinkDeviceId,
1064            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1065            TEST_REMOTE_MAC,
1066        );
1067        // Gratuitous ARPs should not prompt a response.
1068        assert_empty(core_ctx.frames().iter());
1069    }
1070
1071    #[test]
1072    fn test_receive_gratuitous_arp_response() {
1073        // Test that, when we receive a gratuitous ARP response, we cache the
1074        // sender's address information, and we do not send a response.
1075
1076        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1077        send_arp_packet(
1078            &mut core_ctx,
1079            &mut bindings_ctx,
1080            ArpOp::Response,
1081            TEST_REMOTE_IPV4,
1082            TEST_REMOTE_IPV4,
1083            TEST_REMOTE_MAC,
1084            TEST_REMOTE_MAC,
1085            FrameDestination::Individual { local: false },
1086        );
1087
1088        // We should have cached the sender's address information.
1089        assert_dynamic_neighbor_with_addr(
1090            &mut core_ctx,
1091            FakeLinkDeviceId,
1092            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1093            TEST_REMOTE_MAC,
1094        );
1095        // Gratuitous ARPs should not send a response.
1096        assert_empty(core_ctx.frames().iter());
1097    }
1098
1099    #[test]
1100    fn test_receive_gratuitous_arp_response_existing_request() {
1101        // Test that, if we have an outstanding request retry timer and receive
1102        // a gratuitous ARP for the same host, we cancel the timer and notify
1103        // the device layer.
1104
1105        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1106
1107        // Trigger link resolution.
1108        assert_neighbor_unknown(
1109            &mut core_ctx,
1110            FakeLinkDeviceId,
1111            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1112        );
1113        assert_eq!(
1114            NudHandler::send_ip_packet_to_neighbor(
1115                &mut core_ctx,
1116                &mut bindings_ctx,
1117                &FakeLinkDeviceId,
1118                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1119                Buf::new([1], ..),
1120                FakeTxMetadata::default(),
1121            ),
1122            Ok(())
1123        );
1124
1125        send_arp_packet(
1126            &mut core_ctx,
1127            &mut bindings_ctx,
1128            ArpOp::Response,
1129            TEST_REMOTE_IPV4,
1130            TEST_REMOTE_IPV4,
1131            TEST_REMOTE_MAC,
1132            TEST_REMOTE_MAC,
1133            FrameDestination::Individual { local: false },
1134        );
1135
1136        // The response should now be in our cache.
1137        assert_dynamic_neighbor_with_addr(
1138            &mut core_ctx,
1139            FakeLinkDeviceId,
1140            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1141            TEST_REMOTE_MAC,
1142        );
1143
1144        // Gratuitous ARPs should not send a response (the 1 frame is for the
1145        // original request).
1146        assert_eq!(core_ctx.frames().len(), 1);
1147    }
1148
1149    #[test_case(TEST_LOCAL_IPV4)]
1150    #[test_case(TEST_LOCAL_IPV4_2)]
1151    fn test_handle_arp_request(local_addr: Ipv4Addr) {
1152        // Test that, when we receive an ARP request, we cache the sender's
1153        // address information and send an ARP response.
1154
1155        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1156
1157        send_arp_packet(
1158            &mut core_ctx,
1159            &mut bindings_ctx,
1160            ArpOp::Request,
1161            TEST_REMOTE_IPV4,
1162            local_addr,
1163            TEST_REMOTE_MAC,
1164            TEST_LOCAL_MAC,
1165            FrameDestination::Individual { local: true },
1166        );
1167
1168        // Make sure we cached the sender's address information.
1169        assert_dynamic_neighbor_with_addr(
1170            &mut core_ctx,
1171            FakeLinkDeviceId,
1172            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1173            TEST_REMOTE_MAC,
1174        );
1175
1176        // We should have sent an ARP response.
1177        validate_last_arp_packet(
1178            &core_ctx,
1179            1,
1180            TEST_REMOTE_MAC,
1181            ArpOp::Response,
1182            local_addr,
1183            TEST_REMOTE_IPV4,
1184            TEST_LOCAL_MAC,
1185            TEST_REMOTE_MAC,
1186        );
1187    }
1188
1189    struct ArpHostConfig<'a> {
1190        name: &'a str,
1191        proto_addr: Ipv4Addr,
1192        hw_addr: Mac,
1193    }
1194
1195    #[test_case(ArpHostConfig {
1196                    name: "remote",
1197                    proto_addr: TEST_REMOTE_IPV4,
1198                    hw_addr: TEST_REMOTE_MAC
1199                },
1200                vec![]
1201    )]
1202    #[test_case(ArpHostConfig {
1203                    name: "requested_remote",
1204                    proto_addr: TEST_REMOTE_IPV4,
1205                    hw_addr: TEST_REMOTE_MAC
1206                },
1207                vec![
1208                    ArpHostConfig {
1209                        name: "non_requested_remote",
1210                        proto_addr: TEST_ANOTHER_REMOTE_IPV4,
1211                        hw_addr: TEST_REMOTE_MAC
1212                    }
1213                ]
1214    )]
1215    fn test_address_resolution(
1216        requested_remote_cfg: ArpHostConfig<'_>,
1217        other_remote_cfgs: Vec<ArpHostConfig<'_>>,
1218    ) {
1219        // Test a basic ARP resolution scenario.
1220        // We expect the following steps:
1221        // 1. When a lookup is performed and results in a cache miss, we send an
1222        //    ARP request and set a request retry timer.
1223        // 2. When the requested remote receives the request, it populates its cache with
1224        //    the local's information, and sends an ARP reply.
1225        // 3. Any non-requested remotes will neither populate their caches nor send ARP replies.
1226        // 4. When the reply is received, the timer is canceled, the table is
1227        //    updated, a new entry expiration timer is installed, and the device
1228        //    layer is notified of the resolution.
1229
1230        const LOCAL_HOST_CFG: ArpHostConfig<'_> =
1231            ArpHostConfig { name: "local", proto_addr: TEST_LOCAL_IPV4, hw_addr: TEST_LOCAL_MAC };
1232        let host_iter = other_remote_cfgs
1233            .iter()
1234            .chain(iter::once(&requested_remote_cfg))
1235            .chain(iter::once(&LOCAL_HOST_CFG));
1236
1237        let mut network = ArpNetworkSpec::new_network(
1238            {
1239                host_iter.clone().map(|cfg| {
1240                    let ArpHostConfig { name, proto_addr, hw_addr } = cfg;
1241                    let mut ctx = new_context();
1242                    let CtxPair { core_ctx, bindings_ctx: _ } = &mut ctx;
1243                    core_ctx.state.hw_addr = UnicastAddr::new(*hw_addr).unwrap();
1244                    core_ctx.state.proto_addrs = vec![*proto_addr];
1245                    (*name, ctx)
1246                })
1247            },
1248            |ctx: &str, meta: ArpFrameMetadata<_, _>| {
1249                host_iter
1250                    .clone()
1251                    .filter_map(|cfg| {
1252                        let ArpHostConfig { name, proto_addr: _, hw_addr: _ } = cfg;
1253                        if !ctx.eq(*name) { Some((*name, meta.clone(), None)) } else { None }
1254                    })
1255                    .collect::<Vec<_>>()
1256            },
1257        );
1258
1259        let ArpHostConfig {
1260            name: local_name,
1261            proto_addr: local_proto_addr,
1262            hw_addr: local_hw_addr,
1263        } = LOCAL_HOST_CFG;
1264
1265        let ArpHostConfig {
1266            name: requested_remote_name,
1267            proto_addr: requested_remote_proto_addr,
1268            hw_addr: requested_remote_hw_addr,
1269        } = requested_remote_cfg;
1270
1271        // Trigger link resolution.
1272        network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx }| {
1273            assert_neighbor_unknown(
1274                core_ctx,
1275                FakeLinkDeviceId,
1276                SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1277            );
1278            assert_eq!(
1279                NudHandler::send_ip_packet_to_neighbor(
1280                    core_ctx,
1281                    bindings_ctx,
1282                    &FakeLinkDeviceId,
1283                    SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1284                    Buf::new([1], ..),
1285                    FakeTxMetadata::default(),
1286                ),
1287                Ok(())
1288            );
1289
1290            // We should have sent an ARP request.
1291            validate_last_arp_packet(
1292                core_ctx,
1293                1,
1294                Mac::BROADCAST,
1295                ArpOp::Request,
1296                local_proto_addr,
1297                requested_remote_proto_addr,
1298                local_hw_addr,
1299                Mac::UNSPECIFIED,
1300            );
1301        });
1302        // Step once to deliver the ARP request to the remotes.
1303        let res = network.step();
1304        assert_eq!(res.timers_fired, 0);
1305
1306        // Our faked broadcast network should deliver frames to every host other
1307        // than the sender itself. These should include all non-participating remotes
1308        // and either the local or the participating remote, depending on who is
1309        // sending the packet.
1310        let expected_frames_sent_bcast = other_remote_cfgs.len() + 1;
1311        assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1312
1313        // The requested remote should have populated its ARP cache with the local's
1314        // information.
1315        network.with_context(requested_remote_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1316            assert_dynamic_neighbor_with_addr(
1317                core_ctx,
1318                FakeLinkDeviceId,
1319                SpecifiedAddr::new(local_proto_addr).unwrap(),
1320                LOCAL_HOST_CFG.hw_addr,
1321            );
1322
1323            // The requested remote should have sent an ARP response.
1324            validate_last_arp_packet(
1325                core_ctx,
1326                1,
1327                local_hw_addr,
1328                ArpOp::Response,
1329                requested_remote_proto_addr,
1330                local_proto_addr,
1331                requested_remote_hw_addr,
1332                local_hw_addr,
1333            );
1334        });
1335
1336        // Step once to deliver the ARP response to the local.
1337        let res = network.step();
1338        assert_eq!(res.timers_fired, 0);
1339        assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1340
1341        // The local should have populated its cache with the remote's
1342        // information.
1343        network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1344            assert_dynamic_neighbor_with_addr(
1345                core_ctx,
1346                FakeLinkDeviceId,
1347                SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1348                requested_remote_hw_addr,
1349            );
1350        });
1351
1352        other_remote_cfgs.iter().for_each(
1353            |ArpHostConfig { name: unrequested_remote_name, proto_addr: _, hw_addr: _ }| {
1354                // The non-requested_remote should not have populated its ARP cache.
1355                network.with_context(
1356                    *unrequested_remote_name,
1357                    |CtxPair { core_ctx, bindings_ctx: _ }| {
1358                        // The non-requested_remote should not have sent an ARP response.
1359                        assert_empty(core_ctx.frames().iter());
1360
1361                        assert_neighbor_unknown(
1362                            core_ctx,
1363                            FakeLinkDeviceId,
1364                            SpecifiedAddr::new(local_proto_addr).unwrap(),
1365                        );
1366                    },
1367                )
1368            },
1369        );
1370    }
1371
1372    #[test_case(FrameDestination::Individual { local: true }, true; "unicast to us is solicited")]
1373    #[test_case(
1374        FrameDestination::Individual { local: false },
1375        false;
1376        "unicast to other addr is unsolicited"
1377    )]
1378    #[test_case(FrameDestination::Multicast, false; "multicast reply is unsolicited")]
1379    #[test_case(FrameDestination::Broadcast, false; "broadcast reply is unsolicited")]
1380    fn only_unicast_reply_treated_as_solicited(
1381        frame_dst: FrameDestination,
1382        expect_solicited: bool,
1383    ) {
1384        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1385
1386        // Trigger link resolution.
1387        assert_neighbor_unknown(
1388            &mut core_ctx,
1389            FakeLinkDeviceId,
1390            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1391        );
1392        assert_eq!(
1393            NudHandler::send_ip_packet_to_neighbor(
1394                &mut core_ctx,
1395                &mut bindings_ctx,
1396                &FakeLinkDeviceId,
1397                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1398                Buf::new([1], ..),
1399                FakeTxMetadata::default(),
1400            ),
1401            Ok(())
1402        );
1403
1404        // Now send a confirmation with the specified frame destination.
1405        send_arp_packet(
1406            &mut core_ctx,
1407            &mut bindings_ctx,
1408            ArpOp::Response,
1409            TEST_REMOTE_IPV4,
1410            TEST_LOCAL_IPV4,
1411            TEST_REMOTE_MAC,
1412            TEST_LOCAL_MAC,
1413            frame_dst,
1414        );
1415
1416        // If the confirmation was interpreted as solicited, the entry should be
1417        // marked as REACHABLE; otherwise, it should have transitioned to STALE.
1418        let expected_state = if expect_solicited {
1419            DynamicNeighborState::Reachable(Reachable {
1420                link_address: TEST_REMOTE_MAC,
1421                last_confirmed_at: bindings_ctx.now(),
1422            })
1423        } else {
1424            DynamicNeighborState::Stale(Stale { link_address: TEST_REMOTE_MAC })
1425        };
1426        assert_dynamic_neighbor_state(
1427            &mut core_ctx,
1428            FakeLinkDeviceId,
1429            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1430            expected_state,
1431        );
1432    }
1433
1434    // Test that we ignore ARP packets that have our hardware address as the
1435    // sender hardware address.
1436    #[test]
1437    fn test_drop_echoed_arp_packet() {
1438        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1439
1440        // Receive an ARP packet that matches an ARP probe (as specified in
1441        // RFC 5227 section 2.1.1) that has been echoed back to ourselves.
1442        send_arp_packet(
1443            &mut core_ctx,
1444            &mut bindings_ctx,
1445            ArpOp::Request,
1446            Ipv4::UNSPECIFIED_ADDRESS, /* sender_ipv4 */
1447            TEST_LOCAL_IPV4,           /* target_ipv4 */
1448            TEST_LOCAL_MAC,            /* sender_mac */
1449            Mac::UNSPECIFIED,          /* target_mac */
1450            FrameDestination::Broadcast,
1451        );
1452
1453        // We should not have cached the sender's address information.
1454        assert_neighbor_unknown(
1455            &mut core_ctx,
1456            FakeLinkDeviceId,
1457            SpecifiedAddr::new(TEST_LOCAL_IPV4).unwrap(),
1458        );
1459
1460        // We should not have sent an ARP response.
1461        assert_eq!(core_ctx.frames().len(), 0);
1462    }
1463
1464    // Test sending an ARP probe as specified in Address Conflict Detection.
1465    #[test]
1466    fn test_send_arp_probe() {
1467        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1468
1469        const LOCAL_IP: Ipv4Addr = Ipv4::UNSPECIFIED_ADDRESS;
1470        send_arp_request(
1471            &mut core_ctx,
1472            &mut bindings_ctx,
1473            &FakeLinkDeviceId,
1474            LOCAL_IP,
1475            TEST_REMOTE_IPV4,
1476            None,
1477        );
1478
1479        // We should have sent 1 ARP Request.
1480        let (meta, frame) = assert_matches!(core_ctx.frames(), [frame] => frame);
1481        // The request should have been broadcast, with the destination MAC
1482        // left unspecified.
1483        assert_eq!(meta.dst_addr, Mac::BROADCAST);
1484        validate_arp_packet(
1485            frame,
1486            ArpOp::Request,
1487            LOCAL_IP,
1488            TEST_REMOTE_IPV4,
1489            TEST_LOCAL_MAC,
1490            Mac::UNSPECIFIED,
1491        );
1492    }
1493
1494    // Test receiving an ARP packet and dispatching it to the IP Layer.
1495    #[test_case(ArpOp::Request, TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, true; "dispatch_request")]
1496    #[test_case(ArpOp::Response, TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, true; "dispatch_reply")]
1497    #[test_case(ArpOp::Request, Ipv4::UNSPECIFIED_ADDRESS, TEST_LOCAL_IPV4, true; "dispatch_probe")]
1498    #[test_case(ArpOp::Other(99), TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, false; "ignore_other")]
1499    fn test_receive_arp_packet(
1500        op: ArpOp,
1501        sender_addr: Ipv4Addr,
1502        target_addr: Ipv4Addr,
1503        expect_dispatch: bool,
1504    ) {
1505        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1506
1507        send_arp_packet(
1508            &mut core_ctx,
1509            &mut bindings_ctx,
1510            op,
1511            sender_addr,
1512            target_addr,
1513            TEST_REMOTE_MAC,
1514            TEST_LOCAL_MAC,
1515            FrameDestination::Broadcast,
1516        );
1517
1518        let is_arp_probe = sender_addr == Ipv4::UNSPECIFIED_ADDRESS && op == ArpOp::Request;
1519
1520        if expect_dispatch {
1521            assert_eq!(
1522                &core_ctx.state.dispatched_arp_packets[..],
1523                [(sender_addr, target_addr, is_arp_probe)]
1524            );
1525        } else {
1526            assert_eq!(&core_ctx.state.dispatched_arp_packets[..], []);
1527        }
1528    }
1529
1530    #[test]
1531    fn test_ignore_duplicate_response_within_lock_time() {
1532        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1533
1534        // Trigger link resolution.
1535        assert_neighbor_unknown(
1536            &mut core_ctx,
1537            FakeLinkDeviceId,
1538            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1539        );
1540        assert_eq!(
1541            NudHandler::send_ip_packet_to_neighbor(
1542                &mut core_ctx,
1543                &mut bindings_ctx,
1544                &FakeLinkDeviceId,
1545                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1546                Buf::new([1], ..),
1547                FakeTxMetadata::default(),
1548            ),
1549            Ok(())
1550        );
1551
1552        let send_arp_response = |core_ctx: &mut _, bindings_ctx: &mut _, mac| {
1553            send_arp_packet(
1554                core_ctx,
1555                bindings_ctx,
1556                ArpOp::Response,
1557                TEST_REMOTE_IPV4,
1558                TEST_LOCAL_IPV4,
1559                mac,
1560                TEST_LOCAL_MAC,
1561                FrameDestination::Individual { local: true },
1562            );
1563        };
1564        let verify_addr = |core_ctx: &mut _, mac| {
1565            assert_dynamic_neighbor_with_addr(
1566                core_ctx,
1567                FakeLinkDeviceId,
1568                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1569                mac,
1570            );
1571        };
1572
1573        // Receive an ARP response.
1574        send_arp_response(&mut core_ctx, &mut bindings_ctx, TEST_REMOTE_MAC);
1575
1576        // Verify state is REACHABLE with TEST_REMOTE_MAC.
1577        verify_addr(&mut core_ctx, TEST_REMOTE_MAC);
1578
1579        // Receive another ARP response with a different MAC address shortly
1580        // after the first one. This should be ignored because it's within the
1581        // override lock time (FakeArpConfigCtx::override_lock_time returns 1s).
1582        const SPOOFED_MAC: Mac = Mac::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
1583        bindings_ctx.timers.instant.sleep(Duration::from_millis(100));
1584        send_arp_response(&mut core_ctx, &mut bindings_ctx, SPOOFED_MAC);
1585
1586        // Verify state is REACHABLE with the old MAC (TEST_REMOTE_MAC).
1587        verify_addr(&mut core_ctx, TEST_REMOTE_MAC);
1588
1589        // Receive the "spoofed" ARP response again after 1 second. Now it
1590        // should be accepted.
1591        bindings_ctx.timers.instant.sleep(ARP_OVERRIDE_LOCK_TIME);
1592        send_arp_response(&mut core_ctx, &mut bindings_ctx, SPOOFED_MAC);
1593
1594        // Verify state updated to REACHABLE with SPOOFED_MAC.
1595        verify_addr(&mut core_ctx, SPOOFED_MAC);
1596    }
1597
1598    #[test]
1599    fn test_gratuitous_arp_response_within_lock_time() {
1600        let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1601
1602        // Trigger link resolution.
1603        assert_neighbor_unknown(
1604            &mut core_ctx,
1605            FakeLinkDeviceId,
1606            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1607        );
1608        assert_eq!(
1609            NudHandler::send_ip_packet_to_neighbor(
1610                &mut core_ctx,
1611                &mut bindings_ctx,
1612                &FakeLinkDeviceId,
1613                SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1614                Buf::new([1], ..),
1615                FakeTxMetadata::default(),
1616            ),
1617            Ok(())
1618        );
1619
1620        // Receive an ARP response.
1621        send_arp_packet(
1622            &mut core_ctx,
1623            &mut bindings_ctx,
1624            ArpOp::Response,
1625            TEST_REMOTE_IPV4,
1626            TEST_LOCAL_IPV4,
1627            TEST_REMOTE_MAC,
1628            TEST_LOCAL_MAC,
1629            FrameDestination::Individual { local: true },
1630        );
1631
1632        // Verify state is REACHABLE with TEST_REMOTE_MAC.
1633        assert_dynamic_neighbor_state(
1634            &mut core_ctx,
1635            FakeLinkDeviceId,
1636            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1637            DynamicNeighborState::Reachable(Reachable {
1638                link_address: TEST_REMOTE_MAC,
1639                last_confirmed_at: bindings_ctx.now(),
1640            }),
1641        );
1642
1643        // Receive gratuitous ARP response with a different MAC address shortly
1644        // after the direct ARP response.
1645        const NEW_MAC: Mac = Mac::new([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
1646        bindings_ctx.timers.instant.sleep(Duration::from_millis(100));
1647        send_arp_packet(
1648            &mut core_ctx,
1649            &mut bindings_ctx,
1650            ArpOp::Response,
1651            TEST_REMOTE_IPV4,
1652            TEST_REMOTE_IPV4,
1653            NEW_MAC,
1654            NEW_MAC,
1655            FrameDestination::Individual { local: false },
1656        );
1657
1658        // Verify state is STALE with NEW_MAC.
1659        assert_dynamic_neighbor_state(
1660            &mut core_ctx,
1661            FakeLinkDeviceId,
1662            SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1663            DynamicNeighborState::Stale(Stale { link_address: NEW_MAC }),
1664        );
1665    }
1666}