1use alloc::fmt::Debug;
8use core::time::Duration;
9
10use log::{debug, trace, warn};
11use net_types::ip::{Ipv4, Ipv4Addr};
12use net_types::{SpecifiedAddr, UnicastAddr, Witness as _};
13use netstack3_base::{
14 CoreTimerContext, Counter, CounterContext, DeviceIdContext, EventContext, FrameDestination,
15 InstantBindingsTypes, LinkDevice, SendFrameContext, SendFrameError, TimerContext,
16 TxMetadataBindingsTypes, WeakDeviceIdentifier,
17};
18use netstack3_ip::nud::{
19 self, ConfirmationFlags, DynamicNeighborUpdateSource, LinkResolutionContext, NudBindingsTypes,
20 NudConfigContext, NudContext, NudHandler, NudSenderContext, NudState, NudTimerId,
21 NudUserConfig,
22};
23use packet::{BufferMut, InnerPacketBuilder, Serializer};
24use packet_formats::arp::{ArpOp, ArpPacket, ArpPacketBuilder, HType};
25use packet_formats::utils::NonZeroDuration;
26use ref_cast::RefCast;
27
28pub trait ArpDevice: LinkDevice<Address: HType> {}
32
33impl<L: LinkDevice<Address: HType>> ArpDevice for L {}
34
35pub(crate) type ArpTimerId<L, D> = NudTimerId<Ipv4, L, D>;
37
38#[cfg_attr(test, derive(Debug, PartialEq, Clone))]
40pub struct ArpFrameMetadata<D: ArpDevice, DeviceId> {
41 pub(super) device_id: DeviceId,
43 pub(super) dst_addr: D::Address,
45}
46
47#[derive(Default)]
49pub struct ArpCounters {
50 pub rx_packets: Counter,
52 pub rx_malformed_packets: Counter,
54 pub rx_requests: Counter,
56 pub rx_responses: Counter,
58 pub rx_dropped_non_local_target: Counter,
61 pub tx_requests: Counter,
63 pub tx_requests_dropped_no_local_addr: Counter,
66 pub tx_responses: Counter,
68}
69
70pub trait ArpSenderContext<D: ArpDevice, BC: ArpBindingsContext<D, Self::DeviceId>>:
73 ArpConfigContext + DeviceIdContext<D>
74{
75 fn send_ip_packet_to_neighbor_link_addr<S>(
77 &mut self,
78 bindings_ctx: &mut BC,
79 dst_link_address: D::Address,
80 body: S,
81 meta: BC::TxMetadata,
82 ) -> Result<(), SendFrameError<S>>
83 where
84 S: Serializer,
85 S::Buffer: BufferMut;
86}
87
88pub trait ArpBindingsContext<D: ArpDevice, DeviceId>:
109 TimerContext
110 + LinkResolutionContext<D>
111 + EventContext<nud::Event<D::Address, DeviceId, Ipv4, <Self as InstantBindingsTypes>::Instant>>
112 + TxMetadataBindingsTypes
113{
114}
115
116impl<
117 DeviceId,
118 D: ArpDevice,
119 BC: TimerContext
120 + LinkResolutionContext<D>
121 + EventContext<
122 nud::Event<D::Address, DeviceId, Ipv4, <Self as InstantBindingsTypes>::Instant>,
123 > + TxMetadataBindingsTypes,
124 > ArpBindingsContext<D, DeviceId> for BC
125{
126}
127
128pub trait ArpContext<D: ArpDevice, BC: ArpBindingsContext<D, Self::DeviceId>>:
130 DeviceIdContext<D>
131 + SendFrameContext<BC, ArpFrameMetadata<D, Self::DeviceId>>
132 + CounterContext<ArpCounters>
133{
134 type ConfigCtx<'a>: ArpConfigContext;
136 type ArpSenderCtx<'a>: ArpSenderContext<D, BC, DeviceId = Self::DeviceId>;
138
139 fn with_arp_state_mut_and_sender_ctx<
142 O,
143 F: FnOnce(&mut ArpState<D, BC>, &mut Self::ArpSenderCtx<'_>) -> O,
144 >(
145 &mut self,
146 device_id: &Self::DeviceId,
147 cb: F,
148 ) -> O;
149
150 fn get_protocol_addr(&mut self, device_id: &Self::DeviceId) -> Option<Ipv4Addr>;
158
159 fn addr_on_interface(&mut self, device_id: &Self::DeviceId, addr: Ipv4Addr) -> bool;
163
164 fn get_hardware_addr(
166 &mut self,
167 bindings_ctx: &mut BC,
168 device_id: &Self::DeviceId,
169 ) -> UnicastAddr<D::Address>;
170
171 fn with_arp_state_mut<O, F: FnOnce(&mut ArpState<D, BC>, &mut Self::ConfigCtx<'_>) -> O>(
174 &mut self,
175 device_id: &Self::DeviceId,
176 cb: F,
177 ) -> O;
178
179 fn with_arp_state<O, F: FnOnce(&ArpState<D, BC>) -> O>(
181 &mut self,
182 device_id: &Self::DeviceId,
183 cb: F,
184 ) -> O;
185}
186
187pub trait ArpConfigContext {
190 fn retransmit_timeout(&mut self) -> NonZeroDuration {
194 NonZeroDuration::new(DEFAULT_ARP_REQUEST_PERIOD).unwrap()
195 }
196
197 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O;
199}
200
201#[derive(RefCast)]
204#[repr(transparent)]
205pub struct ArpNudCtx<CC>(CC);
206
207impl<D, CC> DeviceIdContext<D> for ArpNudCtx<CC>
208where
209 D: ArpDevice,
210 CC: DeviceIdContext<D>,
211{
212 type DeviceId = CC::DeviceId;
213 type WeakDeviceId = CC::WeakDeviceId;
214}
215
216impl<D, CC, BC> NudContext<Ipv4, D, BC> for ArpNudCtx<CC>
217where
218 D: ArpDevice,
219 BC: ArpBindingsContext<D, CC::DeviceId>,
220 CC: ArpContext<D, BC>,
221{
222 type ConfigCtx<'a> = ArpNudCtx<CC::ConfigCtx<'a>>;
223 type SenderCtx<'a> = ArpNudCtx<CC::ArpSenderCtx<'a>>;
224
225 fn with_nud_state_mut_and_sender_ctx<
226 O,
227 F: FnOnce(&mut NudState<Ipv4, D, BC>, &mut Self::SenderCtx<'_>) -> O,
228 >(
229 &mut self,
230 device_id: &Self::DeviceId,
231 cb: F,
232 ) -> O {
233 let Self(core_ctx) = self;
234 core_ctx.with_arp_state_mut_and_sender_ctx(device_id, |ArpState { nud }, core_ctx| {
235 cb(nud, ArpNudCtx::ref_cast_mut(core_ctx))
236 })
237 }
238
239 fn with_nud_state_mut<
240 O,
241 F: FnOnce(&mut NudState<Ipv4, D, BC>, &mut Self::ConfigCtx<'_>) -> O,
242 >(
243 &mut self,
244 device_id: &Self::DeviceId,
245 cb: F,
246 ) -> O {
247 let Self(core_ctx) = self;
248 core_ctx.with_arp_state_mut(device_id, |ArpState { nud }, core_ctx| {
249 cb(nud, ArpNudCtx::ref_cast_mut(core_ctx))
250 })
251 }
252
253 fn with_nud_state<O, F: FnOnce(&NudState<Ipv4, D, BC>) -> O>(
254 &mut self,
255 device_id: &Self::DeviceId,
256 cb: F,
257 ) -> O {
258 let Self(core_ctx) = self;
259 core_ctx.with_arp_state(device_id, |ArpState { nud }| cb(nud))
260 }
261
262 fn send_neighbor_solicitation(
263 &mut self,
264 bindings_ctx: &mut BC,
265 device_id: &Self::DeviceId,
266 lookup_addr: SpecifiedAddr<<Ipv4 as net_types::ip::Ip>::Addr>,
267 remote_link_addr: Option<<D as LinkDevice>::Address>,
268 ) {
269 let Self(core_ctx) = self;
270 send_arp_request(core_ctx, bindings_ctx, device_id, lookup_addr.get(), remote_link_addr)
271 }
272}
273
274impl<CC: ArpConfigContext> NudConfigContext<Ipv4> for ArpNudCtx<CC> {
275 fn retransmit_timeout(&mut self) -> NonZeroDuration {
276 let Self(core_ctx) = self;
277 core_ctx.retransmit_timeout()
278 }
279
280 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
281 let Self(core_ctx) = self;
282 core_ctx.with_nud_user_config(cb)
283 }
284}
285
286impl<D: ArpDevice, BC: ArpBindingsContext<D, CC::DeviceId>, CC: ArpSenderContext<D, BC>>
287 NudSenderContext<Ipv4, D, BC> for ArpNudCtx<CC>
288{
289 fn send_ip_packet_to_neighbor_link_addr<S>(
290 &mut self,
291 bindings_ctx: &mut BC,
292 dst_mac: D::Address,
293 body: S,
294 meta: BC::TxMetadata,
295 ) -> Result<(), SendFrameError<S>>
296 where
297 S: Serializer,
298 S::Buffer: BufferMut,
299 {
300 let Self(core_ctx) = self;
301 core_ctx.send_ip_packet_to_neighbor_link_addr(bindings_ctx, dst_mac, body, meta)
302 }
303}
304
305pub(crate) trait ArpPacketHandler<D: ArpDevice, BC>: DeviceIdContext<D> {
306 fn handle_packet<B: BufferMut + Debug>(
307 &mut self,
308 bindings_ctx: &mut BC,
309 device_id: Self::DeviceId,
310 frame_dst: FrameDestination,
311 buffer: B,
312 );
313}
314
315impl<
316 D: ArpDevice,
317 BC: ArpBindingsContext<D, CC::DeviceId>,
318 CC: ArpContext<D, BC>
319 + SendFrameContext<BC, ArpFrameMetadata<D, Self::DeviceId>>
320 + NudHandler<Ipv4, D, BC>
321 + CounterContext<ArpCounters>,
322 > ArpPacketHandler<D, BC> for CC
323{
324 fn handle_packet<B: BufferMut + Debug>(
326 &mut self,
327 bindings_ctx: &mut BC,
328 device_id: Self::DeviceId,
329 frame_dst: FrameDestination,
330 buffer: B,
331 ) {
332 handle_packet(self, bindings_ctx, device_id, frame_dst, buffer)
333 }
334}
335
336fn handle_packet<
337 D: ArpDevice,
338 BC: ArpBindingsContext<D, CC::DeviceId>,
339 B: BufferMut + Debug,
340 CC: ArpContext<D, BC>
341 + SendFrameContext<BC, ArpFrameMetadata<D, CC::DeviceId>>
342 + NudHandler<Ipv4, D, BC>
343 + CounterContext<ArpCounters>,
344>(
345 core_ctx: &mut CC,
346 bindings_ctx: &mut BC,
347 device_id: CC::DeviceId,
348 frame_dst: FrameDestination,
349 mut buffer: B,
350) {
351 core_ctx.counters().rx_packets.increment();
352 let packet = match buffer.parse::<ArpPacket<_, D::Address, Ipv4Addr>>() {
354 Ok(packet) => packet,
355 Err(err) => {
356 debug!("discarding malformed ARP packet: {}", err);
363 core_ctx.counters().rx_malformed_packets.increment();
364 return;
365 }
366 };
367
368 enum ValidArpOp {
369 Request,
370 Response,
371 }
372
373 let op = match packet.operation() {
374 ArpOp::Request => {
375 core_ctx.counters().rx_requests.increment();
376 ValidArpOp::Request
377 }
378 ArpOp::Response => {
379 core_ctx.counters().rx_responses.increment();
380 ValidArpOp::Response
381 }
382 ArpOp::Other(o) => {
383 core_ctx.counters().rx_malformed_packets.increment();
384 debug!("dropping arp packet with op = {:?}", o);
385 return;
386 }
387 };
388
389 enum PacketKind {
390 Gratuitous,
391 AddressedToMe,
392 }
393
394 let sender_addr = packet.sender_protocol_address();
435 let target_addr = packet.target_protocol_address();
436
437 let garp = sender_addr == target_addr;
438 let targets_interface = core_ctx.addr_on_interface(&device_id, target_addr);
439 let (source, kind) = match (garp, targets_interface) {
440 (true, false) => {
441 (DynamicNeighborUpdateSource::Probe, PacketKind::Gratuitous)
469 }
470 (false, true) => {
471 let solicited = match frame_dst {
474 FrameDestination::Individual { local } => local,
475 FrameDestination::Broadcast | FrameDestination::Multicast => false,
476 };
477 let source = match op {
478 ValidArpOp::Request => DynamicNeighborUpdateSource::Probe,
479 ValidArpOp::Response => {
480 DynamicNeighborUpdateSource::Confirmation(ConfirmationFlags {
481 solicited_flag: solicited,
482 override_flag: false,
486 })
487 }
488 };
489 (source, PacketKind::AddressedToMe)
490 }
491 (false, false) => {
492 core_ctx.counters().rx_dropped_non_local_target.increment();
493 trace!(
494 "non-gratuitous ARP packet not targetting us; sender = {}, target={}",
495 sender_addr,
496 target_addr
497 );
498 return;
499 }
500 (true, true) => {
501 warn!(
502 "got gratuitous ARP packet with our address {target_addr} on device {device_id:?}, \
503 dropping...",
504 );
505 return;
506 }
507 };
508
509 let sender_hw_addr = packet.sender_hardware_address();
510 if let Some(addr) = SpecifiedAddr::new(sender_addr) {
511 NudHandler::<Ipv4, D, _>::handle_neighbor_update(
512 core_ctx,
513 bindings_ctx,
514 &device_id,
515 addr,
516 sender_hw_addr,
517 source,
518 )
519 };
520
521 match kind {
522 PacketKind::Gratuitous => return,
523 PacketKind::AddressedToMe => match source {
524 DynamicNeighborUpdateSource::Probe => {
525 let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, &device_id);
526
527 core_ctx.counters().tx_responses.increment();
528 debug!("sending ARP response for {target_addr} to {sender_addr}");
529
530 SendFrameContext::send_frame(
531 core_ctx,
532 bindings_ctx,
533 ArpFrameMetadata { device_id, dst_addr: sender_hw_addr },
534 ArpPacketBuilder::new(
535 ArpOp::Response,
536 self_hw_addr.get(),
537 target_addr,
538 sender_hw_addr,
539 sender_addr,
540 )
541 .into_serializer_with(buffer),
542 )
543 .unwrap_or_else(|serializer| {
544 warn!(
545 "failed to send ARP response for {target_addr} to {sender_addr}: \
546 {serializer:?}"
547 )
548 });
549 }
550 DynamicNeighborUpdateSource::Confirmation(_flags) => {}
551 },
552 }
553}
554
555const DEFAULT_ARP_REQUEST_PERIOD: Duration = nud::RETRANS_TIMER_DEFAULT.get();
563
564fn send_arp_request<
565 D: ArpDevice,
566 BC: ArpBindingsContext<D, CC::DeviceId>,
567 CC: ArpContext<D, BC> + CounterContext<ArpCounters>,
568>(
569 core_ctx: &mut CC,
570 bindings_ctx: &mut BC,
571 device_id: &CC::DeviceId,
572 lookup_addr: Ipv4Addr,
573 remote_link_addr: Option<D::Address>,
574) {
575 if let Some(sender_protocol_addr) = core_ctx.get_protocol_addr(device_id) {
576 let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, device_id);
577 let dst_addr = remote_link_addr.unwrap_or(D::Address::BROADCAST);
578 core_ctx.counters().tx_requests.increment();
579 debug!("sending ARP request for {lookup_addr} to {dst_addr:?}");
580 SendFrameContext::send_frame(
581 core_ctx,
582 bindings_ctx,
583 ArpFrameMetadata { device_id: device_id.clone(), dst_addr },
584 ArpPacketBuilder::new(
585 ArpOp::Request,
586 self_hw_addr.get(),
587 sender_protocol_addr,
588 dst_addr,
592 lookup_addr,
593 )
594 .into_serializer(),
595 )
596 .unwrap_or_else(|serializer| {
597 warn!("failed to send ARP request for {lookup_addr} to {dst_addr:?}: {serializer:?}")
598 });
599 } else {
600 core_ctx.counters().tx_requests_dropped_no_local_addr.increment();
607 debug!("Not sending ARP request, since we don't know our local protocol address");
608 }
609}
610
611pub struct ArpState<D: ArpDevice, BT: NudBindingsTypes<D>> {
617 pub(crate) nud: NudState<Ipv4, D, BT>,
618}
619
620impl<D: ArpDevice, BC: NudBindingsTypes<D> + TimerContext> ArpState<D, BC> {
621 pub fn new<
623 DeviceId: WeakDeviceIdentifier,
624 CC: CoreTimerContext<ArpTimerId<D, DeviceId>, BC>,
625 >(
626 bindings_ctx: &mut BC,
627 device_id: DeviceId,
628 ) -> Self {
629 ArpState { nud: NudState::new::<_, CC>(bindings_ctx, device_id) }
630 }
631}
632
633#[cfg(test)]
634mod tests {
635 use alloc::vec;
636 use alloc::vec::Vec;
637 use core::iter;
638
639 use net_types::ethernet::Mac;
640 use netstack3_base::socket::SocketIpAddr;
641 use netstack3_base::testutil::{
642 assert_empty, FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeLinkDeviceId,
643 FakeNetworkSpec, FakeTimerId, FakeTxMetadata, FakeWeakDeviceId, WithFakeFrameContext,
644 };
645 use netstack3_base::{CtxPair, InstantContext as _, IntoCoreTimerCtx, TimerHandler};
646 use netstack3_ip::nud::testutil::{
647 assert_dynamic_neighbor_state, assert_dynamic_neighbor_with_addr, assert_neighbor_unknown,
648 };
649 use netstack3_ip::nud::{
650 DelegateNudContext, DynamicNeighborState, NudCounters, NudIcmpContext, Reachable, Stale,
651 UseDelegateNudContext,
652 };
653 use packet::{Buf, ParseBuffer};
654 use packet_formats::arp::{peek_arp_types, ArpHardwareType, ArpNetworkType};
655 use packet_formats::ipv4::Ipv4FragmentType;
656 use test_case::test_case;
657
658 use super::*;
659 use crate::internal::ethernet::EthernetLinkDevice;
660
661 const TEST_LOCAL_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
662 const TEST_LOCAL_IPV4_2: Ipv4Addr = Ipv4Addr::new([4, 5, 6, 7]);
663 const TEST_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
664 const TEST_ANOTHER_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([9, 10, 11, 12]);
665 const TEST_LOCAL_MAC: Mac = Mac::new([0, 1, 2, 3, 4, 5]);
666 const TEST_REMOTE_MAC: Mac = Mac::new([6, 7, 8, 9, 10, 11]);
667 const TEST_INVALID_MAC: Mac = Mac::new([0, 0, 0, 0, 0, 0]);
668
669 struct FakeArpCtx {
672 proto_addrs: Vec<Ipv4Addr>,
673 hw_addr: UnicastAddr<Mac>,
674 arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
675 inner: FakeArpInnerCtx,
676 config: FakeArpConfigCtx,
677 counters: ArpCounters,
678 nud_counters: NudCounters<Ipv4>,
679 }
680
681 struct FakeArpInnerCtx;
683
684 struct FakeArpConfigCtx;
686
687 impl FakeArpCtx {
688 fn new(bindings_ctx: &mut FakeBindingsCtxImpl) -> FakeArpCtx {
689 FakeArpCtx {
690 proto_addrs: vec![TEST_LOCAL_IPV4, TEST_LOCAL_IPV4_2],
691 hw_addr: UnicastAddr::new(TEST_LOCAL_MAC).unwrap(),
692 arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
693 bindings_ctx,
694 FakeWeakDeviceId(FakeLinkDeviceId),
695 ),
696 inner: FakeArpInnerCtx,
697 config: FakeArpConfigCtx,
698 counters: Default::default(),
699 nud_counters: Default::default(),
700 }
701 }
702 }
703
704 type FakeBindingsCtxImpl = FakeBindingsCtx<
705 ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>,
706 nud::Event<Mac, FakeLinkDeviceId, Ipv4, FakeInstant>,
707 (),
708 (),
709 >;
710
711 type FakeCoreCtxImpl = FakeCoreCtx<
712 FakeArpCtx,
713 ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>,
714 FakeDeviceId,
715 >;
716
717 fn new_context() -> CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl> {
718 CtxPair::with_default_bindings_ctx(|bindings_ctx| {
719 FakeCoreCtxImpl::with_state(FakeArpCtx::new(bindings_ctx))
720 })
721 }
722
723 enum ArpNetworkSpec {}
724 impl FakeNetworkSpec for ArpNetworkSpec {
725 type Context = CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl>;
726 type TimerId = ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>;
727 type SendMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
728 type RecvMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
729
730 fn handle_frame(
731 ctx: &mut Self::Context,
732 ArpFrameMetadata { device_id, .. }: Self::RecvMeta,
733 data: Buf<Vec<u8>>,
734 ) {
735 let CtxPair { core_ctx, bindings_ctx } = ctx;
736 handle_packet(
737 core_ctx,
738 bindings_ctx,
739 device_id,
740 FrameDestination::Individual { local: true },
741 data,
742 )
743 }
744 fn handle_timer(ctx: &mut Self::Context, dispatch: Self::TimerId, timer: FakeTimerId) {
745 let CtxPair { core_ctx, bindings_ctx } = ctx;
746 TimerHandler::handle_timer(core_ctx, bindings_ctx, dispatch, timer)
747 }
748
749 fn process_queues(_ctx: &mut Self::Context) -> bool {
750 false
751 }
752
753 fn fake_frames(ctx: &mut Self::Context) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
754 &mut ctx.core_ctx
755 }
756 }
757
758 impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxImpl {
759 type DeviceId = FakeLinkDeviceId;
760 type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
761 }
762
763 impl DeviceIdContext<EthernetLinkDevice> for FakeArpInnerCtx {
764 type DeviceId = FakeLinkDeviceId;
765 type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
766 }
767
768 impl ArpContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
769 type ConfigCtx<'a> = FakeArpConfigCtx;
770
771 type ArpSenderCtx<'a> = FakeArpInnerCtx;
772
773 fn with_arp_state_mut_and_sender_ctx<
774 O,
775 F: FnOnce(
776 &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
777 &mut Self::ArpSenderCtx<'_>,
778 ) -> O,
779 >(
780 &mut self,
781 FakeLinkDeviceId: &FakeLinkDeviceId,
782 cb: F,
783 ) -> O {
784 let FakeArpCtx { arp_state, inner, .. } = &mut self.state;
785 cb(arp_state, inner)
786 }
787
788 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>) -> O>(
789 &mut self,
790 FakeLinkDeviceId: &FakeLinkDeviceId,
791 cb: F,
792 ) -> O {
793 cb(&self.state.arp_state)
794 }
795
796 fn addr_on_interface(&mut self, _device_id: &FakeLinkDeviceId, addr: Ipv4Addr) -> bool {
797 self.state.proto_addrs.iter().any(|&a| a == addr)
798 }
799
800 fn get_protocol_addr(&mut self, _device_id: &FakeLinkDeviceId) -> Option<Ipv4Addr> {
801 self.state.proto_addrs.first().copied()
802 }
803
804 fn get_hardware_addr(
805 &mut self,
806 _bindings_ctx: &mut FakeBindingsCtxImpl,
807 _device_id: &FakeLinkDeviceId,
808 ) -> UnicastAddr<Mac> {
809 self.state.hw_addr
810 }
811
812 fn with_arp_state_mut<
813 O,
814 F: FnOnce(
815 &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
816 &mut Self::ConfigCtx<'_>,
817 ) -> O,
818 >(
819 &mut self,
820 FakeLinkDeviceId: &FakeLinkDeviceId,
821 cb: F,
822 ) -> O {
823 let FakeArpCtx { arp_state, config, .. } = &mut self.state;
824 cb(arp_state, config)
825 }
826 }
827
828 impl UseDelegateNudContext for FakeArpCtx {}
829 impl DelegateNudContext<Ipv4> for FakeArpCtx {
830 type Delegate<T> = ArpNudCtx<T>;
831 }
832
833 impl NudIcmpContext<Ipv4, EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
834 fn send_icmp_dest_unreachable(
835 &mut self,
836 _bindings_ctx: &mut FakeBindingsCtxImpl,
837 _frame: Buf<Vec<u8>>,
838 _device_id: Option<&Self::DeviceId>,
839 _original_src: SocketIpAddr<Ipv4Addr>,
840 _original_dst: SocketIpAddr<Ipv4Addr>,
841 _metadata: (usize, Ipv4FragmentType),
842 ) {
843 panic!("send_icmp_dest_unreachable should not be called");
844 }
845 }
846
847 impl ArpConfigContext for FakeArpConfigCtx {
848 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
849 cb(&NudUserConfig::default())
850 }
851 }
852 impl ArpConfigContext for FakeArpInnerCtx {
853 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
854 cb(&NudUserConfig::default())
855 }
856 }
857
858 impl ArpSenderContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeArpInnerCtx {
859 fn send_ip_packet_to_neighbor_link_addr<S>(
860 &mut self,
861 _bindings_ctx: &mut FakeBindingsCtxImpl,
862 _dst_link_address: Mac,
863 _body: S,
864 _tx_meta: FakeTxMetadata,
865 ) -> Result<(), SendFrameError<S>> {
866 Ok(())
867 }
868 }
869
870 impl CounterContext<ArpCounters> for FakeArpCtx {
871 fn counters(&self) -> &ArpCounters {
872 &self.counters
873 }
874 }
875
876 impl CounterContext<NudCounters<Ipv4>> for FakeArpCtx {
877 fn counters(&self) -> &NudCounters<Ipv4> {
878 &self.nud_counters
879 }
880 }
881
882 fn send_arp_packet(
883 core_ctx: &mut FakeCoreCtxImpl,
884 bindings_ctx: &mut FakeBindingsCtxImpl,
885 op: ArpOp,
886 sender_ipv4: Ipv4Addr,
887 target_ipv4: Ipv4Addr,
888 sender_mac: Mac,
889 target_mac: Mac,
890 frame_dst: FrameDestination,
891 ) {
892 let buf = ArpPacketBuilder::new(op, sender_mac, sender_ipv4, target_mac, target_ipv4)
893 .into_serializer()
894 .serialize_vec_outer()
895 .unwrap();
896 let (hw, proto) = peek_arp_types(buf.as_ref()).unwrap();
897 assert_eq!(hw, ArpHardwareType::Ethernet);
898 assert_eq!(proto, ArpNetworkType::Ipv4);
899
900 handle_packet::<_, _, _, _>(core_ctx, bindings_ctx, FakeLinkDeviceId, frame_dst, buf);
901 }
902
903 fn validate_arp_packet(
906 mut buf: &[u8],
907 op: ArpOp,
908 local_ipv4: Ipv4Addr,
909 remote_ipv4: Ipv4Addr,
910 local_mac: Mac,
911 remote_mac: Mac,
912 ) {
913 let packet = buf.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap();
914 assert_eq!(packet.sender_hardware_address(), local_mac);
915 assert_eq!(packet.target_hardware_address(), remote_mac);
916 assert_eq!(packet.sender_protocol_address(), local_ipv4);
917 assert_eq!(packet.target_protocol_address(), remote_ipv4);
918 assert_eq!(packet.operation(), op);
919 }
920
921 fn validate_last_arp_packet(
924 core_ctx: &FakeCoreCtxImpl,
925 total_frames: usize,
926 dst: Mac,
927 op: ArpOp,
928 local_ipv4: Ipv4Addr,
929 remote_ipv4: Ipv4Addr,
930 local_mac: Mac,
931 remote_mac: Mac,
932 ) {
933 assert_eq!(core_ctx.frames().len(), total_frames);
934 let (meta, frame) = &core_ctx.frames()[total_frames - 1];
935 assert_eq!(meta.dst_addr, dst);
936 validate_arp_packet(frame, op, local_ipv4, remote_ipv4, local_mac, remote_mac);
937 }
938
939 #[test]
940 fn test_receive_gratuitous_arp_request() {
941 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
945 send_arp_packet(
946 &mut core_ctx,
947 &mut bindings_ctx,
948 ArpOp::Request,
949 TEST_REMOTE_IPV4,
950 TEST_REMOTE_IPV4,
951 TEST_REMOTE_MAC,
952 TEST_INVALID_MAC,
953 FrameDestination::Individual { local: false },
954 );
955
956 assert_dynamic_neighbor_with_addr(
958 &mut core_ctx,
959 FakeLinkDeviceId,
960 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
961 TEST_REMOTE_MAC,
962 );
963 assert_empty(core_ctx.frames().iter());
965 }
966
967 #[test]
968 fn test_receive_gratuitous_arp_response() {
969 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
973 send_arp_packet(
974 &mut core_ctx,
975 &mut bindings_ctx,
976 ArpOp::Response,
977 TEST_REMOTE_IPV4,
978 TEST_REMOTE_IPV4,
979 TEST_REMOTE_MAC,
980 TEST_REMOTE_MAC,
981 FrameDestination::Individual { local: false },
982 );
983
984 assert_dynamic_neighbor_with_addr(
986 &mut core_ctx,
987 FakeLinkDeviceId,
988 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
989 TEST_REMOTE_MAC,
990 );
991 assert_empty(core_ctx.frames().iter());
993 }
994
995 #[test]
996 fn test_receive_gratuitous_arp_response_existing_request() {
997 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1002
1003 assert_neighbor_unknown(
1005 &mut core_ctx,
1006 FakeLinkDeviceId,
1007 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1008 );
1009 assert_eq!(
1010 NudHandler::send_ip_packet_to_neighbor(
1011 &mut core_ctx,
1012 &mut bindings_ctx,
1013 &FakeLinkDeviceId,
1014 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1015 Buf::new([1], ..),
1016 FakeTxMetadata::default(),
1017 ),
1018 Ok(())
1019 );
1020
1021 send_arp_packet(
1022 &mut core_ctx,
1023 &mut bindings_ctx,
1024 ArpOp::Response,
1025 TEST_REMOTE_IPV4,
1026 TEST_REMOTE_IPV4,
1027 TEST_REMOTE_MAC,
1028 TEST_REMOTE_MAC,
1029 FrameDestination::Individual { local: false },
1030 );
1031
1032 assert_dynamic_neighbor_with_addr(
1034 &mut core_ctx,
1035 FakeLinkDeviceId,
1036 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1037 TEST_REMOTE_MAC,
1038 );
1039
1040 assert_eq!(core_ctx.frames().len(), 1);
1043 }
1044
1045 #[test_case(TEST_LOCAL_IPV4)]
1046 #[test_case(TEST_LOCAL_IPV4_2)]
1047 fn test_handle_arp_request(local_addr: Ipv4Addr) {
1048 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1052
1053 send_arp_packet(
1054 &mut core_ctx,
1055 &mut bindings_ctx,
1056 ArpOp::Request,
1057 TEST_REMOTE_IPV4,
1058 local_addr,
1059 TEST_REMOTE_MAC,
1060 TEST_LOCAL_MAC,
1061 FrameDestination::Individual { local: true },
1062 );
1063
1064 assert_dynamic_neighbor_with_addr(
1066 &mut core_ctx,
1067 FakeLinkDeviceId,
1068 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1069 TEST_REMOTE_MAC,
1070 );
1071
1072 validate_last_arp_packet(
1074 &core_ctx,
1075 1,
1076 TEST_REMOTE_MAC,
1077 ArpOp::Response,
1078 local_addr,
1079 TEST_REMOTE_IPV4,
1080 TEST_LOCAL_MAC,
1081 TEST_REMOTE_MAC,
1082 );
1083 }
1084
1085 struct ArpHostConfig<'a> {
1086 name: &'a str,
1087 proto_addr: Ipv4Addr,
1088 hw_addr: Mac,
1089 }
1090
1091 #[test_case(ArpHostConfig {
1092 name: "remote",
1093 proto_addr: TEST_REMOTE_IPV4,
1094 hw_addr: TEST_REMOTE_MAC
1095 },
1096 vec![]
1097 )]
1098 #[test_case(ArpHostConfig {
1099 name: "requested_remote",
1100 proto_addr: TEST_REMOTE_IPV4,
1101 hw_addr: TEST_REMOTE_MAC
1102 },
1103 vec![
1104 ArpHostConfig {
1105 name: "non_requested_remote",
1106 proto_addr: TEST_ANOTHER_REMOTE_IPV4,
1107 hw_addr: TEST_REMOTE_MAC
1108 }
1109 ]
1110 )]
1111 fn test_address_resolution(
1112 requested_remote_cfg: ArpHostConfig<'_>,
1113 other_remote_cfgs: Vec<ArpHostConfig<'_>>,
1114 ) {
1115 const LOCAL_HOST_CFG: ArpHostConfig<'_> =
1127 ArpHostConfig { name: "local", proto_addr: TEST_LOCAL_IPV4, hw_addr: TEST_LOCAL_MAC };
1128 let host_iter = other_remote_cfgs
1129 .iter()
1130 .chain(iter::once(&requested_remote_cfg))
1131 .chain(iter::once(&LOCAL_HOST_CFG));
1132
1133 let mut network = ArpNetworkSpec::new_network(
1134 {
1135 host_iter.clone().map(|cfg| {
1136 let ArpHostConfig { name, proto_addr, hw_addr } = cfg;
1137 let mut ctx = new_context();
1138 let CtxPair { core_ctx, bindings_ctx: _ } = &mut ctx;
1139 core_ctx.state.hw_addr = UnicastAddr::new(*hw_addr).unwrap();
1140 core_ctx.state.proto_addrs = vec![*proto_addr];
1141 (*name, ctx)
1142 })
1143 },
1144 |ctx: &str, meta: ArpFrameMetadata<_, _>| {
1145 host_iter
1146 .clone()
1147 .filter_map(|cfg| {
1148 let ArpHostConfig { name, proto_addr: _, hw_addr: _ } = cfg;
1149 if !ctx.eq(*name) {
1150 Some((*name, meta.clone(), None))
1151 } else {
1152 None
1153 }
1154 })
1155 .collect::<Vec<_>>()
1156 },
1157 );
1158
1159 let ArpHostConfig {
1160 name: local_name,
1161 proto_addr: local_proto_addr,
1162 hw_addr: local_hw_addr,
1163 } = LOCAL_HOST_CFG;
1164
1165 let ArpHostConfig {
1166 name: requested_remote_name,
1167 proto_addr: requested_remote_proto_addr,
1168 hw_addr: requested_remote_hw_addr,
1169 } = requested_remote_cfg;
1170
1171 network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx }| {
1173 assert_neighbor_unknown(
1174 core_ctx,
1175 FakeLinkDeviceId,
1176 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1177 );
1178 assert_eq!(
1179 NudHandler::send_ip_packet_to_neighbor(
1180 core_ctx,
1181 bindings_ctx,
1182 &FakeLinkDeviceId,
1183 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1184 Buf::new([1], ..),
1185 FakeTxMetadata::default(),
1186 ),
1187 Ok(())
1188 );
1189
1190 validate_last_arp_packet(
1192 core_ctx,
1193 1,
1194 Mac::BROADCAST,
1195 ArpOp::Request,
1196 local_proto_addr,
1197 requested_remote_proto_addr,
1198 local_hw_addr,
1199 Mac::BROADCAST,
1200 );
1201 });
1202 let res = network.step();
1204 assert_eq!(res.timers_fired, 0);
1205
1206 let expected_frames_sent_bcast = other_remote_cfgs.len() + 1;
1211 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1212
1213 network.with_context(requested_remote_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1216 assert_dynamic_neighbor_with_addr(
1217 core_ctx,
1218 FakeLinkDeviceId,
1219 SpecifiedAddr::new(local_proto_addr).unwrap(),
1220 LOCAL_HOST_CFG.hw_addr,
1221 );
1222
1223 validate_last_arp_packet(
1225 core_ctx,
1226 1,
1227 local_hw_addr,
1228 ArpOp::Response,
1229 requested_remote_proto_addr,
1230 local_proto_addr,
1231 requested_remote_hw_addr,
1232 local_hw_addr,
1233 );
1234 });
1235
1236 let res = network.step();
1238 assert_eq!(res.timers_fired, 0);
1239 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1240
1241 network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1244 assert_dynamic_neighbor_with_addr(
1245 core_ctx,
1246 FakeLinkDeviceId,
1247 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1248 requested_remote_hw_addr,
1249 );
1250 });
1251
1252 other_remote_cfgs.iter().for_each(
1253 |ArpHostConfig { name: unrequested_remote_name, proto_addr: _, hw_addr: _ }| {
1254 network.with_context(
1256 *unrequested_remote_name,
1257 |CtxPair { core_ctx, bindings_ctx: _ }| {
1258 assert_empty(core_ctx.frames().iter());
1260
1261 assert_neighbor_unknown(
1262 core_ctx,
1263 FakeLinkDeviceId,
1264 SpecifiedAddr::new(local_proto_addr).unwrap(),
1265 );
1266 },
1267 )
1268 },
1269 );
1270 }
1271
1272 #[test_case(FrameDestination::Individual { local: true }, true; "unicast to us is solicited")]
1273 #[test_case(
1274 FrameDestination::Individual { local: false },
1275 false;
1276 "unicast to other addr is unsolicited"
1277 )]
1278 #[test_case(FrameDestination::Multicast, false; "multicast reply is unsolicited")]
1279 #[test_case(FrameDestination::Broadcast, false; "broadcast reply is unsolicited")]
1280 fn only_unicast_reply_treated_as_solicited(
1281 frame_dst: FrameDestination,
1282 expect_solicited: bool,
1283 ) {
1284 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1285
1286 assert_neighbor_unknown(
1288 &mut core_ctx,
1289 FakeLinkDeviceId,
1290 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1291 );
1292 assert_eq!(
1293 NudHandler::send_ip_packet_to_neighbor(
1294 &mut core_ctx,
1295 &mut bindings_ctx,
1296 &FakeLinkDeviceId,
1297 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1298 Buf::new([1], ..),
1299 FakeTxMetadata::default(),
1300 ),
1301 Ok(())
1302 );
1303
1304 send_arp_packet(
1306 &mut core_ctx,
1307 &mut bindings_ctx,
1308 ArpOp::Response,
1309 TEST_REMOTE_IPV4,
1310 TEST_LOCAL_IPV4,
1311 TEST_REMOTE_MAC,
1312 TEST_LOCAL_MAC,
1313 frame_dst,
1314 );
1315
1316 let expected_state = if expect_solicited {
1319 DynamicNeighborState::Reachable(Reachable {
1320 link_address: TEST_REMOTE_MAC,
1321 last_confirmed_at: bindings_ctx.now(),
1322 })
1323 } else {
1324 DynamicNeighborState::Stale(Stale { link_address: TEST_REMOTE_MAC })
1325 };
1326 assert_dynamic_neighbor_state(
1327 &mut core_ctx,
1328 FakeLinkDeviceId,
1329 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1330 expected_state,
1331 );
1332 }
1333}