1use 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
29pub trait ArpDevice: LinkDevice<Address: HType> {}
33
34impl<L: LinkDevice<Address: HType>> ArpDevice for L {}
35
36pub(crate) type ArpTimerId<L, D> = NudTimerId<Ipv4, L, D>;
38
39#[cfg_attr(test, derive(Debug, PartialEq, Clone))]
41pub struct ArpFrameMetadata<D: ArpDevice, DeviceId> {
42 pub(super) device_id: DeviceId,
44 pub(super) dst_addr: NonMulticastAddr<D::Address>,
46}
47
48#[derive(Default)]
50pub struct ArpCounters {
51 pub rx_packets: Counter,
53 pub rx_malformed_packets: Counter,
55 pub rx_echoed_packets: Counter,
58 pub rx_requests: Counter,
60 pub rx_responses: Counter,
62 pub rx_dropped_non_local_target: Counter,
65 pub tx_requests: Counter,
67 pub tx_requests_dropped_no_local_addr: Counter,
70 pub tx_responses: Counter,
72}
73
74pub trait ArpSenderContext<D: ArpDevice, BC: ArpBindingsContext<D, Self::DeviceId>>:
77 ArpConfigContext + DeviceIdContext<D>
78{
79 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
92pub 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
132pub trait ArpContext<D: ArpDevice, BC: ArpBindingsContext<D, Self::DeviceId>>:
134 DeviceIdContext<D>
135 + SendFrameContext<BC, ArpFrameMetadata<D, Self::DeviceId>>
136 + CounterContext<ArpCounters>
137{
138 type ConfigCtx<'a>: ArpConfigContext;
140 type ArpSenderCtx<'a>: ArpSenderContext<D, BC, DeviceId = Self::DeviceId>;
142
143 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 fn get_protocol_addr(&mut self, device_id: &Self::DeviceId) -> Option<Ipv4Addr>;
162
163 fn get_hardware_addr(
165 &mut self,
166 bindings_ctx: &mut BC,
167 device_id: &Self::DeviceId,
168 ) -> UnicastAddr<D::Address>;
169
170 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 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
186pub trait ArpIpLayerContext<D: ArpDevice, BC>: DeviceIdContext<D> {
188 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
211pub trait ArpConfigContext {
214 fn retransmit_timeout(&mut self) -> NonZeroDuration {
218 self.with_nud_user_config(|c| c.retrans_timer)
219 }
220
221 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O;
223}
224
225#[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 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
315pub 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 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 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 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 let is_arp_probe = sender_addr == Ipv4::UNSPECIFIED_ADDRESS
459 && packet.operation() == ArpOp::Request
460 && frame_dst == FrameDestination::Broadcast;
461
462 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 let garp = sender_addr == target_addr;
520 let (source, kind) = match (garp, targets_interface) {
521 (true, false) => {
522 (
550 DynamicNeighborUpdateSource::Probe { link_address: sender_hw_addr },
551 PacketKind::Gratuitous,
552 )
553 }
554 (false, true) => {
555 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 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
645pub 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 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
695pub 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 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 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 dispatched_arp_packets: Vec<(Ipv4Addr, Ipv4Addr, bool)>,
771 }
772
773 struct FakeArpInnerCtx;
775
776 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 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 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 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 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 assert_empty(core_ctx.frames().iter());
1081 }
1082
1083 #[test]
1084 fn test_receive_gratuitous_arp_response() {
1085 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 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 assert_empty(core_ctx.frames().iter());
1109 }
1110
1111 #[test]
1112 fn test_receive_gratuitous_arp_response_existing_request() {
1113 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1118
1119 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 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 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 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 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 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 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 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 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 let res = network.step();
1316 assert_eq!(res.timers_fired, 0);
1317
1318 let expected_frames_sent_bcast = other_remote_cfgs.len() + 1;
1323 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1324
1325 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 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 let res = network.step();
1350 assert_eq!(res.timers_fired, 0);
1351 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1352
1353 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 network.with_context(
1368 *unrequested_remote_name,
1369 |CtxPair { core_ctx, bindings_ctx: _ }| {
1370 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 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 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 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]
1451 fn test_drop_echoed_arp_packet() {
1452 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1453
1454 send_arp_packet(
1457 &mut core_ctx,
1458 &mut bindings_ctx,
1459 ArpOp::Request,
1460 Ipv4::UNSPECIFIED_ADDRESS, TEST_LOCAL_IPV4, TEST_LOCAL_MAC, Mac::UNSPECIFIED, FrameDestination::Broadcast,
1465 );
1466
1467 assert_neighbor_unknown(
1469 &mut core_ctx,
1470 FakeLinkDeviceId,
1471 SpecifiedAddr::new(TEST_LOCAL_IPV4).unwrap(),
1472 );
1473
1474 assert_eq!(core_ctx.frames().len(), 0);
1476 }
1477
1478 #[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 let (meta, frame) = assert_matches!(core_ctx.frames(), [frame] => frame);
1495 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_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 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 send_arp_response(&mut core_ctx, &mut bindings_ctx, TEST_REMOTE_MAC);
1589
1590 verify_addr(&mut core_ctx, TEST_REMOTE_MAC);
1592
1593 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_addr(&mut core_ctx, TEST_REMOTE_MAC);
1602
1603 bindings_ctx.timers.instant.sleep(ARP_OVERRIDE_LOCK_TIME);
1606 send_arp_response(&mut core_ctx, &mut bindings_ctx, SPOOFED_MAC);
1607
1608 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 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 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 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 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 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}