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::{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
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: 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: D::Address,
84 body: S,
85 meta: BC::TxMetadata,
86 ) -> Result<(), SendFrameError<S>>
87 where
88 S: Serializer,
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: 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<<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: 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 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();
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 let is_arp_probe = sender_addr == Ipv4::UNSPECIFIED_ADDRESS
455 && packet.operation() == ArpOp::Request
456 && frame_dst == FrameDestination::Broadcast;
457
458 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 let garp = sender_addr == target_addr;
516 let (source, kind) = match (garp, targets_interface) {
517 (true, false) => {
518 (
546 DynamicNeighborUpdateSource::Probe { link_address: sender_hw_addr },
547 PacketKind::Gratuitous,
548 )
549 }
550 (false, true) => {
551 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 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
638pub 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 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
685pub 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 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 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 dispatched_arp_packets: Vec<(Ipv4Addr, Ipv4Addr, bool)>,
759 }
760
761 struct FakeArpInnerCtx;
763
764 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 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 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 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 assert_dynamic_neighbor_with_addr(
1062 &mut core_ctx,
1063 FakeLinkDeviceId,
1064 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1065 TEST_REMOTE_MAC,
1066 );
1067 assert_empty(core_ctx.frames().iter());
1069 }
1070
1071 #[test]
1072 fn test_receive_gratuitous_arp_response() {
1073 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 assert_dynamic_neighbor_with_addr(
1090 &mut core_ctx,
1091 FakeLinkDeviceId,
1092 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1093 TEST_REMOTE_MAC,
1094 );
1095 assert_empty(core_ctx.frames().iter());
1097 }
1098
1099 #[test]
1100 fn test_receive_gratuitous_arp_response_existing_request() {
1101 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1106
1107 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 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 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 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 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 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 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 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 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 let res = network.step();
1304 assert_eq!(res.timers_fired, 0);
1305
1306 let expected_frames_sent_bcast = other_remote_cfgs.len() + 1;
1311 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1312
1313 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 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 let res = network.step();
1338 assert_eq!(res.timers_fired, 0);
1339 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1340
1341 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 network.with_context(
1356 *unrequested_remote_name,
1357 |CtxPair { core_ctx, bindings_ctx: _ }| {
1358 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 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 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 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]
1437 fn test_drop_echoed_arp_packet() {
1438 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1439
1440 send_arp_packet(
1443 &mut core_ctx,
1444 &mut bindings_ctx,
1445 ArpOp::Request,
1446 Ipv4::UNSPECIFIED_ADDRESS, TEST_LOCAL_IPV4, TEST_LOCAL_MAC, Mac::UNSPECIFIED, FrameDestination::Broadcast,
1451 );
1452
1453 assert_neighbor_unknown(
1455 &mut core_ctx,
1456 FakeLinkDeviceId,
1457 SpecifiedAddr::new(TEST_LOCAL_IPV4).unwrap(),
1458 );
1459
1460 assert_eq!(core_ctx.frames().len(), 0);
1462 }
1463
1464 #[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 let (meta, frame) = assert_matches!(core_ctx.frames(), [frame] => frame);
1481 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_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 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 send_arp_response(&mut core_ctx, &mut bindings_ctx, TEST_REMOTE_MAC);
1575
1576 verify_addr(&mut core_ctx, TEST_REMOTE_MAC);
1578
1579 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_addr(&mut core_ctx, TEST_REMOTE_MAC);
1588
1589 bindings_ctx.timers.instant.sleep(ARP_OVERRIDE_LOCK_TIME);
1592 send_arp_response(&mut core_ctx, &mut bindings_ctx, SPOOFED_MAC);
1593
1594 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 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 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 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 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 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}