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_echoed_packets: Counter,
57 pub rx_requests: Counter,
59 pub rx_responses: Counter,
61 pub rx_dropped_non_local_target: Counter,
64 pub tx_requests: Counter,
66 pub tx_requests_dropped_no_local_addr: Counter,
69 pub tx_responses: Counter,
71}
72
73pub trait ArpSenderContext<D: ArpDevice, BC: ArpBindingsContext<D, Self::DeviceId>>:
76 ArpConfigContext + DeviceIdContext<D>
77{
78 fn send_ip_packet_to_neighbor_link_addr<S>(
80 &mut self,
81 bindings_ctx: &mut BC,
82 dst_link_address: D::Address,
83 body: S,
84 meta: BC::TxMetadata,
85 ) -> Result<(), SendFrameError<S>>
86 where
87 S: Serializer,
88 S::Buffer: BufferMut;
89}
90
91pub trait ArpBindingsContext<D: ArpDevice, DeviceId>:
112 TimerContext
113 + LinkResolutionContext<D>
114 + EventContext<nud::Event<D::Address, DeviceId, Ipv4, <Self as InstantBindingsTypes>::Instant>>
115 + TxMetadataBindingsTypes
116{
117}
118
119impl<
120 DeviceId,
121 D: ArpDevice,
122 BC: TimerContext
123 + LinkResolutionContext<D>
124 + EventContext<
125 nud::Event<D::Address, DeviceId, Ipv4, <Self as InstantBindingsTypes>::Instant>,
126 > + TxMetadataBindingsTypes,
127 > ArpBindingsContext<D, DeviceId> for BC
128{
129}
130
131pub trait ArpContext<D: ArpDevice, BC: ArpBindingsContext<D, Self::DeviceId>>:
133 DeviceIdContext<D>
134 + SendFrameContext<BC, ArpFrameMetadata<D, Self::DeviceId>>
135 + CounterContext<ArpCounters>
136{
137 type ConfigCtx<'a>: ArpConfigContext;
139 type ArpSenderCtx<'a>: ArpSenderContext<D, BC, DeviceId = Self::DeviceId>;
141
142 fn with_arp_state_mut_and_sender_ctx<
145 O,
146 F: FnOnce(&mut ArpState<D, BC>, &mut Self::ArpSenderCtx<'_>) -> O,
147 >(
148 &mut self,
149 device_id: &Self::DeviceId,
150 cb: F,
151 ) -> O;
152
153 fn get_protocol_addr(&mut self, device_id: &Self::DeviceId) -> Option<Ipv4Addr>;
161
162 fn addr_on_interface(&mut self, device_id: &Self::DeviceId, addr: Ipv4Addr) -> bool;
166
167 fn get_hardware_addr(
169 &mut self,
170 bindings_ctx: &mut BC,
171 device_id: &Self::DeviceId,
172 ) -> UnicastAddr<D::Address>;
173
174 fn with_arp_state_mut<O, F: FnOnce(&mut ArpState<D, BC>, &mut Self::ConfigCtx<'_>) -> O>(
177 &mut self,
178 device_id: &Self::DeviceId,
179 cb: F,
180 ) -> O;
181
182 fn with_arp_state<O, F: FnOnce(&ArpState<D, BC>) -> O>(
184 &mut self,
185 device_id: &Self::DeviceId,
186 cb: F,
187 ) -> O;
188}
189
190pub trait ArpConfigContext {
193 fn retransmit_timeout(&mut self) -> NonZeroDuration {
197 NonZeroDuration::new(DEFAULT_ARP_REQUEST_PERIOD).unwrap()
198 }
199
200 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O;
202}
203
204#[derive(RefCast)]
207#[repr(transparent)]
208pub struct ArpNudCtx<CC>(CC);
209
210impl<D, CC> DeviceIdContext<D> for ArpNudCtx<CC>
211where
212 D: ArpDevice,
213 CC: DeviceIdContext<D>,
214{
215 type DeviceId = CC::DeviceId;
216 type WeakDeviceId = CC::WeakDeviceId;
217}
218
219impl<D, CC, BC> NudContext<Ipv4, D, BC> for ArpNudCtx<CC>
220where
221 D: ArpDevice,
222 BC: ArpBindingsContext<D, CC::DeviceId>,
223 CC: ArpContext<D, BC>,
224{
225 type ConfigCtx<'a> = ArpNudCtx<CC::ConfigCtx<'a>>;
226 type SenderCtx<'a> = ArpNudCtx<CC::ArpSenderCtx<'a>>;
227
228 fn with_nud_state_mut_and_sender_ctx<
229 O,
230 F: FnOnce(&mut NudState<Ipv4, D, BC>, &mut Self::SenderCtx<'_>) -> O,
231 >(
232 &mut self,
233 device_id: &Self::DeviceId,
234 cb: F,
235 ) -> O {
236 let Self(core_ctx) = self;
237 core_ctx.with_arp_state_mut_and_sender_ctx(device_id, |ArpState { nud }, core_ctx| {
238 cb(nud, ArpNudCtx::ref_cast_mut(core_ctx))
239 })
240 }
241
242 fn with_nud_state_mut<
243 O,
244 F: FnOnce(&mut NudState<Ipv4, D, BC>, &mut Self::ConfigCtx<'_>) -> O,
245 >(
246 &mut self,
247 device_id: &Self::DeviceId,
248 cb: F,
249 ) -> O {
250 let Self(core_ctx) = self;
251 core_ctx.with_arp_state_mut(device_id, |ArpState { nud }, core_ctx| {
252 cb(nud, ArpNudCtx::ref_cast_mut(core_ctx))
253 })
254 }
255
256 fn with_nud_state<O, F: FnOnce(&NudState<Ipv4, D, BC>) -> O>(
257 &mut self,
258 device_id: &Self::DeviceId,
259 cb: F,
260 ) -> O {
261 let Self(core_ctx) = self;
262 core_ctx.with_arp_state(device_id, |ArpState { nud }| cb(nud))
263 }
264
265 fn send_neighbor_solicitation(
266 &mut self,
267 bindings_ctx: &mut BC,
268 device_id: &Self::DeviceId,
269 lookup_addr: SpecifiedAddr<<Ipv4 as net_types::ip::Ip>::Addr>,
270 remote_link_addr: Option<<D as LinkDevice>::Address>,
271 ) {
272 let Self(core_ctx) = self;
273 send_arp_request(core_ctx, bindings_ctx, device_id, lookup_addr.get(), remote_link_addr)
274 }
275}
276
277impl<CC: ArpConfigContext> NudConfigContext<Ipv4> for ArpNudCtx<CC> {
278 fn retransmit_timeout(&mut self) -> NonZeroDuration {
279 let Self(core_ctx) = self;
280 core_ctx.retransmit_timeout()
281 }
282
283 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
284 let Self(core_ctx) = self;
285 core_ctx.with_nud_user_config(cb)
286 }
287}
288
289impl<D: ArpDevice, BC: ArpBindingsContext<D, CC::DeviceId>, CC: ArpSenderContext<D, BC>>
290 NudSenderContext<Ipv4, D, BC> for ArpNudCtx<CC>
291{
292 fn send_ip_packet_to_neighbor_link_addr<S>(
293 &mut self,
294 bindings_ctx: &mut BC,
295 dst_mac: D::Address,
296 body: S,
297 meta: BC::TxMetadata,
298 ) -> Result<(), SendFrameError<S>>
299 where
300 S: Serializer,
301 S::Buffer: BufferMut,
302 {
303 let Self(core_ctx) = self;
304 core_ctx.send_ip_packet_to_neighbor_link_addr(bindings_ctx, dst_mac, body, meta)
305 }
306}
307
308pub(crate) trait ArpPacketHandler<D: ArpDevice, BC>: DeviceIdContext<D> {
309 fn handle_packet<B: BufferMut + Debug>(
310 &mut self,
311 bindings_ctx: &mut BC,
312 device_id: Self::DeviceId,
313 frame_dst: FrameDestination,
314 buffer: B,
315 );
316}
317
318impl<
319 D: ArpDevice,
320 BC: ArpBindingsContext<D, CC::DeviceId>,
321 CC: ArpContext<D, BC>
322 + SendFrameContext<BC, ArpFrameMetadata<D, Self::DeviceId>>
323 + NudHandler<Ipv4, D, BC>
324 + CounterContext<ArpCounters>,
325 > ArpPacketHandler<D, BC> for CC
326{
327 fn handle_packet<B: BufferMut + Debug>(
329 &mut self,
330 bindings_ctx: &mut BC,
331 device_id: Self::DeviceId,
332 frame_dst: FrameDestination,
333 buffer: B,
334 ) {
335 handle_packet(self, bindings_ctx, device_id, frame_dst, buffer)
336 }
337}
338
339fn handle_packet<
340 D: ArpDevice,
341 BC: ArpBindingsContext<D, CC::DeviceId>,
342 B: BufferMut + Debug,
343 CC: ArpContext<D, BC>
344 + SendFrameContext<BC, ArpFrameMetadata<D, CC::DeviceId>>
345 + NudHandler<Ipv4, D, BC>
346 + CounterContext<ArpCounters>,
347>(
348 core_ctx: &mut CC,
349 bindings_ctx: &mut BC,
350 device_id: CC::DeviceId,
351 frame_dst: FrameDestination,
352 mut buffer: B,
353) {
354 core_ctx.counters().rx_packets.increment();
355 let packet = match buffer.parse::<ArpPacket<_, D::Address, Ipv4Addr>>() {
356 Ok(packet) => packet,
357 Err(err) => {
358 debug!("discarding malformed ARP packet: {}", err);
365 core_ctx.counters().rx_malformed_packets.increment();
366 return;
367 }
368 };
369
370 #[derive(Debug)]
371 enum ValidArpOp {
372 Request,
373 Response,
374 }
375
376 let op = match packet.operation() {
377 ArpOp::Request => {
378 core_ctx.counters().rx_requests.increment();
379 ValidArpOp::Request
380 }
381 ArpOp::Response => {
382 core_ctx.counters().rx_responses.increment();
383 ValidArpOp::Response
384 }
385 ArpOp::Other(o) => {
386 core_ctx.counters().rx_malformed_packets.increment();
387 debug!("dropping arp packet with op = {:?}", o);
388 return;
389 }
390 };
391
392 let sender_hw_addr = packet.sender_hardware_address();
400 if sender_hw_addr == *core_ctx.get_hardware_addr(bindings_ctx, &device_id) {
401 core_ctx.counters().rx_echoed_packets.increment();
402 debug!("dropping an echoed ARP packet: {op:?}");
403 return;
404 }
405
406 enum PacketKind {
407 Gratuitous,
408 AddressedToMe,
409 }
410
411 let sender_addr = packet.sender_protocol_address();
452 let target_addr = packet.target_protocol_address();
453
454 let garp = sender_addr == target_addr;
455 let targets_interface = core_ctx.addr_on_interface(&device_id, target_addr);
456 let (source, kind) = match (garp, targets_interface) {
457 (true, false) => {
458 (DynamicNeighborUpdateSource::Probe, PacketKind::Gratuitous)
486 }
487 (false, true) => {
488 let solicited = match frame_dst {
491 FrameDestination::Individual { local } => local,
492 FrameDestination::Broadcast | FrameDestination::Multicast => false,
493 };
494 let source = match op {
495 ValidArpOp::Request => DynamicNeighborUpdateSource::Probe,
496 ValidArpOp::Response => {
497 DynamicNeighborUpdateSource::Confirmation(ConfirmationFlags {
498 solicited_flag: solicited,
499 override_flag: false,
503 })
504 }
505 };
506 (source, PacketKind::AddressedToMe)
507 }
508 (false, false) => {
509 core_ctx.counters().rx_dropped_non_local_target.increment();
510 trace!(
511 "non-gratuitous ARP packet not targetting us; sender = {}, target={}",
512 sender_addr,
513 target_addr
514 );
515 return;
516 }
517 (true, true) => {
518 warn!(
519 "got gratuitous ARP packet with our address {target_addr} on device {device_id:?}, \
520 dropping...",
521 );
522 return;
523 }
524 };
525
526 if let Some(addr) = SpecifiedAddr::new(sender_addr) {
527 NudHandler::<Ipv4, D, _>::handle_neighbor_update(
528 core_ctx,
529 bindings_ctx,
530 &device_id,
531 addr,
532 sender_hw_addr,
533 source,
534 )
535 };
536
537 match kind {
538 PacketKind::Gratuitous => return,
539 PacketKind::AddressedToMe => match source {
540 DynamicNeighborUpdateSource::Probe => {
541 let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, &device_id);
542
543 core_ctx.counters().tx_responses.increment();
544 debug!("sending ARP response for {target_addr} to {sender_addr}");
545
546 SendFrameContext::send_frame(
547 core_ctx,
548 bindings_ctx,
549 ArpFrameMetadata { device_id, dst_addr: sender_hw_addr },
550 ArpPacketBuilder::new(
551 ArpOp::Response,
552 self_hw_addr.get(),
553 target_addr,
554 sender_hw_addr,
555 sender_addr,
556 )
557 .into_serializer_with(buffer),
558 )
559 .unwrap_or_else(|serializer| {
560 warn!(
561 "failed to send ARP response for {target_addr} to {sender_addr}: \
562 {serializer:?}"
563 )
564 });
565 }
566 DynamicNeighborUpdateSource::Confirmation(_flags) => {}
567 },
568 }
569}
570
571const DEFAULT_ARP_REQUEST_PERIOD: Duration = nud::RETRANS_TIMER_DEFAULT.get();
579
580fn send_arp_request<
581 D: ArpDevice,
582 BC: ArpBindingsContext<D, CC::DeviceId>,
583 CC: ArpContext<D, BC> + CounterContext<ArpCounters>,
584>(
585 core_ctx: &mut CC,
586 bindings_ctx: &mut BC,
587 device_id: &CC::DeviceId,
588 lookup_addr: Ipv4Addr,
589 remote_link_addr: Option<D::Address>,
590) {
591 if let Some(sender_protocol_addr) = core_ctx.get_protocol_addr(device_id) {
592 let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, device_id);
593 let dst_addr = remote_link_addr.unwrap_or(D::Address::BROADCAST);
594 core_ctx.counters().tx_requests.increment();
595 debug!("sending ARP request for {lookup_addr} to {dst_addr:?}");
596 SendFrameContext::send_frame(
597 core_ctx,
598 bindings_ctx,
599 ArpFrameMetadata { device_id: device_id.clone(), dst_addr },
600 ArpPacketBuilder::new(
601 ArpOp::Request,
602 self_hw_addr.get(),
603 sender_protocol_addr,
604 dst_addr,
608 lookup_addr,
609 )
610 .into_serializer(),
611 )
612 .unwrap_or_else(|serializer| {
613 warn!("failed to send ARP request for {lookup_addr} to {dst_addr:?}: {serializer:?}")
614 });
615 } else {
616 core_ctx.counters().tx_requests_dropped_no_local_addr.increment();
623 debug!("Not sending ARP request, since we don't know our local protocol address");
624 }
625}
626
627pub struct ArpState<D: ArpDevice, BT: NudBindingsTypes<D>> {
633 pub(crate) nud: NudState<Ipv4, D, BT>,
634}
635
636impl<D: ArpDevice, BC: NudBindingsTypes<D> + TimerContext> ArpState<D, BC> {
637 pub fn new<
639 DeviceId: WeakDeviceIdentifier,
640 CC: CoreTimerContext<ArpTimerId<D, DeviceId>, BC>,
641 >(
642 bindings_ctx: &mut BC,
643 device_id: DeviceId,
644 ) -> Self {
645 ArpState { nud: NudState::new::<_, CC>(bindings_ctx, device_id) }
646 }
647}
648
649#[cfg(test)]
650mod tests {
651 use alloc::vec;
652 use alloc::vec::Vec;
653 use core::iter;
654 use net_types::ip::Ip;
655
656 use net_types::ethernet::Mac;
657 use netstack3_base::socket::SocketIpAddr;
658 use netstack3_base::testutil::{
659 assert_empty, FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeLinkDeviceId,
660 FakeNetworkSpec, FakeTimerId, FakeTxMetadata, FakeWeakDeviceId, WithFakeFrameContext,
661 };
662 use netstack3_base::{CtxPair, InstantContext as _, IntoCoreTimerCtx, TimerHandler};
663 use netstack3_ip::nud::testutil::{
664 assert_dynamic_neighbor_state, assert_dynamic_neighbor_with_addr, assert_neighbor_unknown,
665 };
666 use netstack3_ip::nud::{
667 DelegateNudContext, DynamicNeighborState, NudCounters, NudIcmpContext, Reachable, Stale,
668 UseDelegateNudContext,
669 };
670 use packet::{Buf, ParseBuffer};
671 use packet_formats::arp::{peek_arp_types, ArpHardwareType, ArpNetworkType};
672 use packet_formats::ipv4::Ipv4FragmentType;
673 use test_case::test_case;
674
675 use super::*;
676 use crate::internal::ethernet::EthernetLinkDevice;
677
678 const TEST_LOCAL_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
679 const TEST_LOCAL_IPV4_2: Ipv4Addr = Ipv4Addr::new([4, 5, 6, 7]);
680 const TEST_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
681 const TEST_ANOTHER_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([9, 10, 11, 12]);
682 const TEST_LOCAL_MAC: Mac = Mac::new([0, 1, 2, 3, 4, 5]);
683 const TEST_REMOTE_MAC: Mac = Mac::new([6, 7, 8, 9, 10, 11]);
684 const TEST_INVALID_MAC: Mac = Mac::new([0, 0, 0, 0, 0, 0]);
685
686 struct FakeArpCtx {
689 proto_addrs: Vec<Ipv4Addr>,
690 hw_addr: UnicastAddr<Mac>,
691 arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
692 inner: FakeArpInnerCtx,
693 config: FakeArpConfigCtx,
694 counters: ArpCounters,
695 nud_counters: NudCounters<Ipv4>,
696 }
697
698 struct FakeArpInnerCtx;
700
701 struct FakeArpConfigCtx;
703
704 impl FakeArpCtx {
705 fn new(bindings_ctx: &mut FakeBindingsCtxImpl) -> FakeArpCtx {
706 FakeArpCtx {
707 proto_addrs: vec![TEST_LOCAL_IPV4, TEST_LOCAL_IPV4_2],
708 hw_addr: UnicastAddr::new(TEST_LOCAL_MAC).unwrap(),
709 arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
710 bindings_ctx,
711 FakeWeakDeviceId(FakeLinkDeviceId),
712 ),
713 inner: FakeArpInnerCtx,
714 config: FakeArpConfigCtx,
715 counters: Default::default(),
716 nud_counters: Default::default(),
717 }
718 }
719 }
720
721 type FakeBindingsCtxImpl = FakeBindingsCtx<
722 ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>,
723 nud::Event<Mac, FakeLinkDeviceId, Ipv4, FakeInstant>,
724 (),
725 (),
726 >;
727
728 type FakeCoreCtxImpl = FakeCoreCtx<
729 FakeArpCtx,
730 ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>,
731 FakeDeviceId,
732 >;
733
734 fn new_context() -> CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl> {
735 CtxPair::with_default_bindings_ctx(|bindings_ctx| {
736 FakeCoreCtxImpl::with_state(FakeArpCtx::new(bindings_ctx))
737 })
738 }
739
740 enum ArpNetworkSpec {}
741 impl FakeNetworkSpec for ArpNetworkSpec {
742 type Context = CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl>;
743 type TimerId = ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>;
744 type SendMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
745 type RecvMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
746
747 fn handle_frame(
748 ctx: &mut Self::Context,
749 ArpFrameMetadata { device_id, .. }: Self::RecvMeta,
750 data: Buf<Vec<u8>>,
751 ) {
752 let CtxPair { core_ctx, bindings_ctx } = ctx;
753 handle_packet(
754 core_ctx,
755 bindings_ctx,
756 device_id,
757 FrameDestination::Individual { local: true },
758 data,
759 )
760 }
761 fn handle_timer(ctx: &mut Self::Context, dispatch: Self::TimerId, timer: FakeTimerId) {
762 let CtxPair { core_ctx, bindings_ctx } = ctx;
763 TimerHandler::handle_timer(core_ctx, bindings_ctx, dispatch, timer)
764 }
765
766 fn process_queues(_ctx: &mut Self::Context) -> bool {
767 false
768 }
769
770 fn fake_frames(ctx: &mut Self::Context) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
771 &mut ctx.core_ctx
772 }
773 }
774
775 impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxImpl {
776 type DeviceId = FakeLinkDeviceId;
777 type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
778 }
779
780 impl DeviceIdContext<EthernetLinkDevice> for FakeArpInnerCtx {
781 type DeviceId = FakeLinkDeviceId;
782 type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
783 }
784
785 impl ArpContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
786 type ConfigCtx<'a> = FakeArpConfigCtx;
787
788 type ArpSenderCtx<'a> = FakeArpInnerCtx;
789
790 fn with_arp_state_mut_and_sender_ctx<
791 O,
792 F: FnOnce(
793 &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
794 &mut Self::ArpSenderCtx<'_>,
795 ) -> O,
796 >(
797 &mut self,
798 FakeLinkDeviceId: &FakeLinkDeviceId,
799 cb: F,
800 ) -> O {
801 let FakeArpCtx { arp_state, inner, .. } = &mut self.state;
802 cb(arp_state, inner)
803 }
804
805 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>) -> O>(
806 &mut self,
807 FakeLinkDeviceId: &FakeLinkDeviceId,
808 cb: F,
809 ) -> O {
810 cb(&self.state.arp_state)
811 }
812
813 fn addr_on_interface(&mut self, _device_id: &FakeLinkDeviceId, addr: Ipv4Addr) -> bool {
814 self.state.proto_addrs.iter().any(|&a| a == addr)
815 }
816
817 fn get_protocol_addr(&mut self, _device_id: &FakeLinkDeviceId) -> Option<Ipv4Addr> {
818 self.state.proto_addrs.first().copied()
819 }
820
821 fn get_hardware_addr(
822 &mut self,
823 _bindings_ctx: &mut FakeBindingsCtxImpl,
824 _device_id: &FakeLinkDeviceId,
825 ) -> UnicastAddr<Mac> {
826 self.state.hw_addr
827 }
828
829 fn with_arp_state_mut<
830 O,
831 F: FnOnce(
832 &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
833 &mut Self::ConfigCtx<'_>,
834 ) -> O,
835 >(
836 &mut self,
837 FakeLinkDeviceId: &FakeLinkDeviceId,
838 cb: F,
839 ) -> O {
840 let FakeArpCtx { arp_state, config, .. } = &mut self.state;
841 cb(arp_state, config)
842 }
843 }
844
845 impl UseDelegateNudContext for FakeArpCtx {}
846 impl DelegateNudContext<Ipv4> for FakeArpCtx {
847 type Delegate<T> = ArpNudCtx<T>;
848 }
849
850 impl NudIcmpContext<Ipv4, EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
851 fn send_icmp_dest_unreachable(
852 &mut self,
853 _bindings_ctx: &mut FakeBindingsCtxImpl,
854 _frame: Buf<Vec<u8>>,
855 _device_id: Option<&Self::DeviceId>,
856 _original_src: SocketIpAddr<Ipv4Addr>,
857 _original_dst: SocketIpAddr<Ipv4Addr>,
858 _metadata: (usize, Ipv4FragmentType),
859 ) {
860 panic!("send_icmp_dest_unreachable should not be called");
861 }
862 }
863
864 impl ArpConfigContext for FakeArpConfigCtx {
865 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
866 cb(&NudUserConfig::default())
867 }
868 }
869 impl ArpConfigContext for FakeArpInnerCtx {
870 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
871 cb(&NudUserConfig::default())
872 }
873 }
874
875 impl ArpSenderContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeArpInnerCtx {
876 fn send_ip_packet_to_neighbor_link_addr<S>(
877 &mut self,
878 _bindings_ctx: &mut FakeBindingsCtxImpl,
879 _dst_link_address: Mac,
880 _body: S,
881 _tx_meta: FakeTxMetadata,
882 ) -> Result<(), SendFrameError<S>> {
883 Ok(())
884 }
885 }
886
887 impl CounterContext<ArpCounters> for FakeArpCtx {
888 fn counters(&self) -> &ArpCounters {
889 &self.counters
890 }
891 }
892
893 impl CounterContext<NudCounters<Ipv4>> for FakeArpCtx {
894 fn counters(&self) -> &NudCounters<Ipv4> {
895 &self.nud_counters
896 }
897 }
898
899 fn send_arp_packet(
900 core_ctx: &mut FakeCoreCtxImpl,
901 bindings_ctx: &mut FakeBindingsCtxImpl,
902 op: ArpOp,
903 sender_ipv4: Ipv4Addr,
904 target_ipv4: Ipv4Addr,
905 sender_mac: Mac,
906 target_mac: Mac,
907 frame_dst: FrameDestination,
908 ) {
909 let buf = ArpPacketBuilder::new(op, sender_mac, sender_ipv4, target_mac, target_ipv4)
910 .into_serializer()
911 .serialize_vec_outer()
912 .unwrap();
913 let (hw, proto) = peek_arp_types(buf.as_ref()).unwrap();
914 assert_eq!(hw, ArpHardwareType::Ethernet);
915 assert_eq!(proto, ArpNetworkType::Ipv4);
916
917 handle_packet::<_, _, _, _>(core_ctx, bindings_ctx, FakeLinkDeviceId, frame_dst, buf);
918 }
919
920 fn validate_arp_packet(
923 mut buf: &[u8],
924 op: ArpOp,
925 local_ipv4: Ipv4Addr,
926 remote_ipv4: Ipv4Addr,
927 local_mac: Mac,
928 remote_mac: Mac,
929 ) {
930 let packet = buf.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap();
931 assert_eq!(packet.sender_hardware_address(), local_mac);
932 assert_eq!(packet.target_hardware_address(), remote_mac);
933 assert_eq!(packet.sender_protocol_address(), local_ipv4);
934 assert_eq!(packet.target_protocol_address(), remote_ipv4);
935 assert_eq!(packet.operation(), op);
936 }
937
938 fn validate_last_arp_packet(
941 core_ctx: &FakeCoreCtxImpl,
942 total_frames: usize,
943 dst: Mac,
944 op: ArpOp,
945 local_ipv4: Ipv4Addr,
946 remote_ipv4: Ipv4Addr,
947 local_mac: Mac,
948 remote_mac: Mac,
949 ) {
950 assert_eq!(core_ctx.frames().len(), total_frames);
951 let (meta, frame) = &core_ctx.frames()[total_frames - 1];
952 assert_eq!(meta.dst_addr, dst);
953 validate_arp_packet(frame, op, local_ipv4, remote_ipv4, local_mac, remote_mac);
954 }
955
956 #[test]
957 fn test_receive_gratuitous_arp_request() {
958 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
962 send_arp_packet(
963 &mut core_ctx,
964 &mut bindings_ctx,
965 ArpOp::Request,
966 TEST_REMOTE_IPV4,
967 TEST_REMOTE_IPV4,
968 TEST_REMOTE_MAC,
969 TEST_INVALID_MAC,
970 FrameDestination::Individual { local: false },
971 );
972
973 assert_dynamic_neighbor_with_addr(
975 &mut core_ctx,
976 FakeLinkDeviceId,
977 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
978 TEST_REMOTE_MAC,
979 );
980 assert_empty(core_ctx.frames().iter());
982 }
983
984 #[test]
985 fn test_receive_gratuitous_arp_response() {
986 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
990 send_arp_packet(
991 &mut core_ctx,
992 &mut bindings_ctx,
993 ArpOp::Response,
994 TEST_REMOTE_IPV4,
995 TEST_REMOTE_IPV4,
996 TEST_REMOTE_MAC,
997 TEST_REMOTE_MAC,
998 FrameDestination::Individual { local: false },
999 );
1000
1001 assert_dynamic_neighbor_with_addr(
1003 &mut core_ctx,
1004 FakeLinkDeviceId,
1005 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1006 TEST_REMOTE_MAC,
1007 );
1008 assert_empty(core_ctx.frames().iter());
1010 }
1011
1012 #[test]
1013 fn test_receive_gratuitous_arp_response_existing_request() {
1014 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1019
1020 assert_neighbor_unknown(
1022 &mut core_ctx,
1023 FakeLinkDeviceId,
1024 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1025 );
1026 assert_eq!(
1027 NudHandler::send_ip_packet_to_neighbor(
1028 &mut core_ctx,
1029 &mut bindings_ctx,
1030 &FakeLinkDeviceId,
1031 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1032 Buf::new([1], ..),
1033 FakeTxMetadata::default(),
1034 ),
1035 Ok(())
1036 );
1037
1038 send_arp_packet(
1039 &mut core_ctx,
1040 &mut bindings_ctx,
1041 ArpOp::Response,
1042 TEST_REMOTE_IPV4,
1043 TEST_REMOTE_IPV4,
1044 TEST_REMOTE_MAC,
1045 TEST_REMOTE_MAC,
1046 FrameDestination::Individual { local: false },
1047 );
1048
1049 assert_dynamic_neighbor_with_addr(
1051 &mut core_ctx,
1052 FakeLinkDeviceId,
1053 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1054 TEST_REMOTE_MAC,
1055 );
1056
1057 assert_eq!(core_ctx.frames().len(), 1);
1060 }
1061
1062 #[test_case(TEST_LOCAL_IPV4)]
1063 #[test_case(TEST_LOCAL_IPV4_2)]
1064 fn test_handle_arp_request(local_addr: Ipv4Addr) {
1065 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1069
1070 send_arp_packet(
1071 &mut core_ctx,
1072 &mut bindings_ctx,
1073 ArpOp::Request,
1074 TEST_REMOTE_IPV4,
1075 local_addr,
1076 TEST_REMOTE_MAC,
1077 TEST_LOCAL_MAC,
1078 FrameDestination::Individual { local: true },
1079 );
1080
1081 assert_dynamic_neighbor_with_addr(
1083 &mut core_ctx,
1084 FakeLinkDeviceId,
1085 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1086 TEST_REMOTE_MAC,
1087 );
1088
1089 validate_last_arp_packet(
1091 &core_ctx,
1092 1,
1093 TEST_REMOTE_MAC,
1094 ArpOp::Response,
1095 local_addr,
1096 TEST_REMOTE_IPV4,
1097 TEST_LOCAL_MAC,
1098 TEST_REMOTE_MAC,
1099 );
1100 }
1101
1102 struct ArpHostConfig<'a> {
1103 name: &'a str,
1104 proto_addr: Ipv4Addr,
1105 hw_addr: Mac,
1106 }
1107
1108 #[test_case(ArpHostConfig {
1109 name: "remote",
1110 proto_addr: TEST_REMOTE_IPV4,
1111 hw_addr: TEST_REMOTE_MAC
1112 },
1113 vec![]
1114 )]
1115 #[test_case(ArpHostConfig {
1116 name: "requested_remote",
1117 proto_addr: TEST_REMOTE_IPV4,
1118 hw_addr: TEST_REMOTE_MAC
1119 },
1120 vec![
1121 ArpHostConfig {
1122 name: "non_requested_remote",
1123 proto_addr: TEST_ANOTHER_REMOTE_IPV4,
1124 hw_addr: TEST_REMOTE_MAC
1125 }
1126 ]
1127 )]
1128 fn test_address_resolution(
1129 requested_remote_cfg: ArpHostConfig<'_>,
1130 other_remote_cfgs: Vec<ArpHostConfig<'_>>,
1131 ) {
1132 const LOCAL_HOST_CFG: ArpHostConfig<'_> =
1144 ArpHostConfig { name: "local", proto_addr: TEST_LOCAL_IPV4, hw_addr: TEST_LOCAL_MAC };
1145 let host_iter = other_remote_cfgs
1146 .iter()
1147 .chain(iter::once(&requested_remote_cfg))
1148 .chain(iter::once(&LOCAL_HOST_CFG));
1149
1150 let mut network = ArpNetworkSpec::new_network(
1151 {
1152 host_iter.clone().map(|cfg| {
1153 let ArpHostConfig { name, proto_addr, hw_addr } = cfg;
1154 let mut ctx = new_context();
1155 let CtxPair { core_ctx, bindings_ctx: _ } = &mut ctx;
1156 core_ctx.state.hw_addr = UnicastAddr::new(*hw_addr).unwrap();
1157 core_ctx.state.proto_addrs = vec![*proto_addr];
1158 (*name, ctx)
1159 })
1160 },
1161 |ctx: &str, meta: ArpFrameMetadata<_, _>| {
1162 host_iter
1163 .clone()
1164 .filter_map(|cfg| {
1165 let ArpHostConfig { name, proto_addr: _, hw_addr: _ } = cfg;
1166 if !ctx.eq(*name) {
1167 Some((*name, meta.clone(), None))
1168 } else {
1169 None
1170 }
1171 })
1172 .collect::<Vec<_>>()
1173 },
1174 );
1175
1176 let ArpHostConfig {
1177 name: local_name,
1178 proto_addr: local_proto_addr,
1179 hw_addr: local_hw_addr,
1180 } = LOCAL_HOST_CFG;
1181
1182 let ArpHostConfig {
1183 name: requested_remote_name,
1184 proto_addr: requested_remote_proto_addr,
1185 hw_addr: requested_remote_hw_addr,
1186 } = requested_remote_cfg;
1187
1188 network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx }| {
1190 assert_neighbor_unknown(
1191 core_ctx,
1192 FakeLinkDeviceId,
1193 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1194 );
1195 assert_eq!(
1196 NudHandler::send_ip_packet_to_neighbor(
1197 core_ctx,
1198 bindings_ctx,
1199 &FakeLinkDeviceId,
1200 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1201 Buf::new([1], ..),
1202 FakeTxMetadata::default(),
1203 ),
1204 Ok(())
1205 );
1206
1207 validate_last_arp_packet(
1209 core_ctx,
1210 1,
1211 Mac::BROADCAST,
1212 ArpOp::Request,
1213 local_proto_addr,
1214 requested_remote_proto_addr,
1215 local_hw_addr,
1216 Mac::BROADCAST,
1217 );
1218 });
1219 let res = network.step();
1221 assert_eq!(res.timers_fired, 0);
1222
1223 let expected_frames_sent_bcast = other_remote_cfgs.len() + 1;
1228 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1229
1230 network.with_context(requested_remote_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1233 assert_dynamic_neighbor_with_addr(
1234 core_ctx,
1235 FakeLinkDeviceId,
1236 SpecifiedAddr::new(local_proto_addr).unwrap(),
1237 LOCAL_HOST_CFG.hw_addr,
1238 );
1239
1240 validate_last_arp_packet(
1242 core_ctx,
1243 1,
1244 local_hw_addr,
1245 ArpOp::Response,
1246 requested_remote_proto_addr,
1247 local_proto_addr,
1248 requested_remote_hw_addr,
1249 local_hw_addr,
1250 );
1251 });
1252
1253 let res = network.step();
1255 assert_eq!(res.timers_fired, 0);
1256 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1257
1258 network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1261 assert_dynamic_neighbor_with_addr(
1262 core_ctx,
1263 FakeLinkDeviceId,
1264 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1265 requested_remote_hw_addr,
1266 );
1267 });
1268
1269 other_remote_cfgs.iter().for_each(
1270 |ArpHostConfig { name: unrequested_remote_name, proto_addr: _, hw_addr: _ }| {
1271 network.with_context(
1273 *unrequested_remote_name,
1274 |CtxPair { core_ctx, bindings_ctx: _ }| {
1275 assert_empty(core_ctx.frames().iter());
1277
1278 assert_neighbor_unknown(
1279 core_ctx,
1280 FakeLinkDeviceId,
1281 SpecifiedAddr::new(local_proto_addr).unwrap(),
1282 );
1283 },
1284 )
1285 },
1286 );
1287 }
1288
1289 #[test_case(FrameDestination::Individual { local: true }, true; "unicast to us is solicited")]
1290 #[test_case(
1291 FrameDestination::Individual { local: false },
1292 false;
1293 "unicast to other addr is unsolicited"
1294 )]
1295 #[test_case(FrameDestination::Multicast, false; "multicast reply is unsolicited")]
1296 #[test_case(FrameDestination::Broadcast, false; "broadcast reply is unsolicited")]
1297 fn only_unicast_reply_treated_as_solicited(
1298 frame_dst: FrameDestination,
1299 expect_solicited: bool,
1300 ) {
1301 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1302
1303 assert_neighbor_unknown(
1305 &mut core_ctx,
1306 FakeLinkDeviceId,
1307 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1308 );
1309 assert_eq!(
1310 NudHandler::send_ip_packet_to_neighbor(
1311 &mut core_ctx,
1312 &mut bindings_ctx,
1313 &FakeLinkDeviceId,
1314 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1315 Buf::new([1], ..),
1316 FakeTxMetadata::default(),
1317 ),
1318 Ok(())
1319 );
1320
1321 send_arp_packet(
1323 &mut core_ctx,
1324 &mut bindings_ctx,
1325 ArpOp::Response,
1326 TEST_REMOTE_IPV4,
1327 TEST_LOCAL_IPV4,
1328 TEST_REMOTE_MAC,
1329 TEST_LOCAL_MAC,
1330 frame_dst,
1331 );
1332
1333 let expected_state = if expect_solicited {
1336 DynamicNeighborState::Reachable(Reachable {
1337 link_address: TEST_REMOTE_MAC,
1338 last_confirmed_at: bindings_ctx.now(),
1339 })
1340 } else {
1341 DynamicNeighborState::Stale(Stale { link_address: TEST_REMOTE_MAC })
1342 };
1343 assert_dynamic_neighbor_state(
1344 &mut core_ctx,
1345 FakeLinkDeviceId,
1346 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1347 expected_state,
1348 );
1349 }
1350
1351 #[test]
1354 fn test_drop_echoed_arp_packet() {
1355 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1356
1357 send_arp_packet(
1360 &mut core_ctx,
1361 &mut bindings_ctx,
1362 ArpOp::Request,
1363 Ipv4::UNSPECIFIED_ADDRESS, TEST_LOCAL_IPV4, TEST_LOCAL_MAC, Mac::UNSPECIFIED, FrameDestination::Broadcast,
1368 );
1369
1370 assert_neighbor_unknown(
1372 &mut core_ctx,
1373 FakeLinkDeviceId,
1374 SpecifiedAddr::new(TEST_LOCAL_IPV4).unwrap(),
1375 );
1376
1377 assert_eq!(core_ctx.frames().len(), 0);
1379 }
1380}