1use alloc::fmt::Debug;
8use core::time::Duration;
9
10use log::{debug, trace, warn};
11use net_types::ip::{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 get_hardware_addr(
164 &mut self,
165 bindings_ctx: &mut BC,
166 device_id: &Self::DeviceId,
167 ) -> UnicastAddr<D::Address>;
168
169 fn with_arp_state_mut<O, F: FnOnce(&mut ArpState<D, BC>, &mut Self::ConfigCtx<'_>) -> O>(
172 &mut self,
173 device_id: &Self::DeviceId,
174 cb: F,
175 ) -> O;
176
177 fn with_arp_state<O, F: FnOnce(&ArpState<D, BC>) -> O>(
179 &mut self,
180 device_id: &Self::DeviceId,
181 cb: F,
182 ) -> O;
183}
184
185pub trait ArpIpLayerContext<D: ArpDevice, BC>: DeviceIdContext<D> {
187 fn on_arp_packet(
195 &mut self,
196 bindings_ctx: &mut BC,
197 device: &Self::DeviceId,
198 sender_addr: Ipv4Addr,
199 target_addr: Ipv4Addr,
200 is_arp_probe: bool,
201 ) -> bool;
202}
203
204pub trait ArpConfigContext {
207 fn retransmit_timeout(&mut self) -> NonZeroDuration {
211 NonZeroDuration::new(DEFAULT_ARP_REQUEST_PERIOD).unwrap()
212 }
213
214 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O;
216}
217
218#[derive(RefCast)]
221#[repr(transparent)]
222pub struct ArpNudCtx<CC>(CC);
223
224impl<D, CC> DeviceIdContext<D> for ArpNudCtx<CC>
225where
226 D: ArpDevice,
227 CC: DeviceIdContext<D>,
228{
229 type DeviceId = CC::DeviceId;
230 type WeakDeviceId = CC::WeakDeviceId;
231}
232
233impl<D, CC, BC> NudContext<Ipv4, D, BC> for ArpNudCtx<CC>
234where
235 D: ArpDevice,
236 BC: ArpBindingsContext<D, CC::DeviceId>,
237 CC: ArpContext<D, BC>,
238{
239 type ConfigCtx<'a> = ArpNudCtx<CC::ConfigCtx<'a>>;
240 type SenderCtx<'a> = ArpNudCtx<CC::ArpSenderCtx<'a>>;
241
242 fn with_nud_state_mut_and_sender_ctx<
243 O,
244 F: FnOnce(&mut NudState<Ipv4, D, BC>, &mut Self::SenderCtx<'_>) -> 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_and_sender_ctx(device_id, |ArpState { nud }, core_ctx| {
252 cb(nud, ArpNudCtx::ref_cast_mut(core_ctx))
253 })
254 }
255
256 fn with_nud_state_mut<
257 O,
258 F: FnOnce(&mut NudState<Ipv4, D, BC>, &mut Self::ConfigCtx<'_>) -> O,
259 >(
260 &mut self,
261 device_id: &Self::DeviceId,
262 cb: F,
263 ) -> O {
264 let Self(core_ctx) = self;
265 core_ctx.with_arp_state_mut(device_id, |ArpState { nud }, core_ctx| {
266 cb(nud, ArpNudCtx::ref_cast_mut(core_ctx))
267 })
268 }
269
270 fn with_nud_state<O, F: FnOnce(&NudState<Ipv4, D, BC>) -> O>(
271 &mut self,
272 device_id: &Self::DeviceId,
273 cb: F,
274 ) -> O {
275 let Self(core_ctx) = self;
276 core_ctx.with_arp_state(device_id, |ArpState { nud }| cb(nud))
277 }
278
279 fn send_neighbor_solicitation(
280 &mut self,
281 bindings_ctx: &mut BC,
282 device_id: &Self::DeviceId,
283 lookup_addr: SpecifiedAddr<<Ipv4 as net_types::ip::Ip>::Addr>,
284 remote_link_addr: Option<<D as LinkDevice>::Address>,
285 ) {
286 let Self(core_ctx) = self;
287
288 if let Some(sender_addr) = core_ctx.get_protocol_addr(device_id) {
289 send_arp_request(
290 core_ctx,
291 bindings_ctx,
292 device_id,
293 sender_addr,
294 *lookup_addr,
295 remote_link_addr,
296 );
297 } else {
298 core_ctx.counters().tx_requests_dropped_no_local_addr.increment();
303 debug!("Not sending ARP request, since we don't know our local protocol address");
304 }
305 }
306}
307
308impl<CC: ArpConfigContext> NudConfigContext<Ipv4> for ArpNudCtx<CC> {
309 fn retransmit_timeout(&mut self) -> NonZeroDuration {
310 let Self(core_ctx) = self;
311 core_ctx.retransmit_timeout()
312 }
313
314 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
315 let Self(core_ctx) = self;
316 core_ctx.with_nud_user_config(cb)
317 }
318}
319
320impl<D: ArpDevice, BC: ArpBindingsContext<D, CC::DeviceId>, CC: ArpSenderContext<D, BC>>
321 NudSenderContext<Ipv4, D, BC> for ArpNudCtx<CC>
322{
323 fn send_ip_packet_to_neighbor_link_addr<S>(
324 &mut self,
325 bindings_ctx: &mut BC,
326 dst_mac: D::Address,
327 body: S,
328 meta: BC::TxMetadata,
329 ) -> Result<(), SendFrameError<S>>
330 where
331 S: Serializer,
332 S::Buffer: BufferMut,
333 {
334 let Self(core_ctx) = self;
335 core_ctx.send_ip_packet_to_neighbor_link_addr(bindings_ctx, dst_mac, body, meta)
336 }
337}
338
339pub(crate) trait ArpPacketHandler<D: ArpDevice, BC>: DeviceIdContext<D> {
340 fn handle_packet<B: BufferMut + Debug>(
341 &mut self,
342 bindings_ctx: &mut BC,
343 device_id: Self::DeviceId,
344 frame_dst: FrameDestination,
345 buffer: B,
346 );
347}
348
349impl<
350 D: ArpDevice,
351 BC: ArpBindingsContext<D, CC::DeviceId>,
352 CC: ArpContext<D, BC> + ArpIpLayerContext<D, BC> + NudHandler<Ipv4, D, BC>,
353> ArpPacketHandler<D, BC> for CC
354{
355 fn handle_packet<B: BufferMut + Debug>(
357 &mut self,
358 bindings_ctx: &mut BC,
359 device_id: Self::DeviceId,
360 frame_dst: FrameDestination,
361 buffer: B,
362 ) {
363 handle_packet(self, bindings_ctx, device_id, frame_dst, buffer)
364 }
365}
366
367fn handle_packet<
368 D: ArpDevice,
369 BC: ArpBindingsContext<D, CC::DeviceId>,
370 B: BufferMut + Debug,
371 CC: ArpContext<D, BC> + ArpIpLayerContext<D, BC> + NudHandler<Ipv4, D, BC>,
372>(
373 core_ctx: &mut CC,
374 bindings_ctx: &mut BC,
375 device_id: CC::DeviceId,
376 frame_dst: FrameDestination,
377 mut buffer: B,
378) {
379 core_ctx.counters().rx_packets.increment();
380 let packet = match buffer.parse::<ArpPacket<_, D::Address, Ipv4Addr>>() {
381 Ok(packet) => packet,
382 Err(err) => {
383 debug!("discarding malformed ARP packet: {}", err);
390 core_ctx.counters().rx_malformed_packets.increment();
391 return;
392 }
393 };
394
395 #[derive(Debug)]
396 enum ValidArpOp {
397 Request,
398 Response,
399 }
400
401 let op = match packet.operation() {
402 ArpOp::Request => {
403 core_ctx.counters().rx_requests.increment();
404 ValidArpOp::Request
405 }
406 ArpOp::Response => {
407 core_ctx.counters().rx_responses.increment();
408 ValidArpOp::Response
409 }
410 ArpOp::Other(o) => {
411 core_ctx.counters().rx_malformed_packets.increment();
412 debug!("dropping arp packet with op = {:?}", o);
413 return;
414 }
415 };
416
417 let sender_hw_addr = packet.sender_hardware_address();
425 if sender_hw_addr == *core_ctx.get_hardware_addr(bindings_ctx, &device_id) {
426 core_ctx.counters().rx_echoed_packets.increment();
427 debug!("dropping an echoed ARP packet: {op:?}");
428 return;
429 }
430
431 let sender_addr = packet.sender_protocol_address();
432 let target_addr = packet.target_protocol_address();
433
434 let is_arp_probe = sender_addr == Ipv4::UNSPECIFIED_ADDRESS
438 && packet.operation() == ArpOp::Request
439 && frame_dst == FrameDestination::Broadcast;
440
441 let targets_interface =
444 core_ctx.on_arp_packet(bindings_ctx, &device_id, sender_addr, target_addr, is_arp_probe);
445
446 enum PacketKind {
447 Gratuitous,
448 AddressedToMe,
449 }
450
451 let garp = sender_addr == target_addr;
492 let (source, kind) = match (garp, targets_interface) {
493 (true, false) => {
494 (
522 DynamicNeighborUpdateSource::Probe { link_address: sender_hw_addr },
523 PacketKind::Gratuitous,
524 )
525 }
526 (false, true) => {
527 let solicited = match frame_dst {
530 FrameDestination::Individual { local } => local,
531 FrameDestination::Broadcast | FrameDestination::Multicast => false,
532 };
533 let source = match op {
534 ValidArpOp::Request => {
535 DynamicNeighborUpdateSource::Probe { link_address: sender_hw_addr }
536 }
537 ValidArpOp::Response => {
538 DynamicNeighborUpdateSource::Confirmation {
539 link_address: Some(sender_hw_addr),
540 flags: ConfirmationFlags {
541 solicited_flag: solicited,
542 override_flag: true,
547 },
548 }
549 }
550 };
551 (source, PacketKind::AddressedToMe)
552 }
553 (false, false) => {
554 core_ctx.counters().rx_dropped_non_local_target.increment();
555 trace!(
556 "non-gratuitous ARP packet not targetting us; sender = {}, target={}",
557 sender_addr, target_addr
558 );
559 return;
560 }
561 (true, true) => {
562 warn!(
563 "got gratuitous ARP packet with our address {target_addr} on device {device_id:?}, \
564 dropping...",
565 );
566 return;
567 }
568 };
569
570 if let Some(addr) = SpecifiedAddr::new(sender_addr) {
571 NudHandler::<Ipv4, D, _>::handle_neighbor_update(
572 core_ctx,
573 bindings_ctx,
574 &device_id,
575 addr,
576 source,
577 )
578 };
579
580 match kind {
581 PacketKind::Gratuitous => return,
582 PacketKind::AddressedToMe => match source {
583 DynamicNeighborUpdateSource::Probe { .. } => {
584 let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, &device_id);
585
586 core_ctx.counters().tx_responses.increment();
587 debug!("sending ARP response for {target_addr} to {sender_addr}");
588
589 SendFrameContext::send_frame(
590 core_ctx,
591 bindings_ctx,
592 ArpFrameMetadata { device_id, dst_addr: sender_hw_addr },
593 ArpPacketBuilder::new(
594 ArpOp::Response,
595 self_hw_addr.get(),
596 target_addr,
597 sender_hw_addr,
598 sender_addr,
599 )
600 .into_serializer_with(buffer),
601 )
602 .unwrap_or_else(|serializer| {
603 warn!(
604 "failed to send ARP response for {target_addr} to {sender_addr}: \
605 {serializer:?}"
606 )
607 });
608 }
609 DynamicNeighborUpdateSource::Confirmation { .. } => {}
610 },
611 }
612}
613
614const DEFAULT_ARP_REQUEST_PERIOD: Duration = nud::IPV6_RETRANS_TIMER_DEFAULT.get();
622
623pub fn send_arp_request<
628 D: ArpDevice,
629 BC: ArpBindingsContext<D, CC::DeviceId>,
630 CC: ArpContext<D, BC> + CounterContext<ArpCounters>,
631>(
632 core_ctx: &mut CC,
633 bindings_ctx: &mut BC,
634 device_id: &CC::DeviceId,
635 sender_addr: Ipv4Addr,
636 lookup_addr: Ipv4Addr,
637 remote_link_addr: Option<D::Address>,
638) {
639 let self_hw_addr = core_ctx.get_hardware_addr(bindings_ctx, device_id);
640 let dst_addr = remote_link_addr.unwrap_or(D::Address::BROADCAST);
641 core_ctx.counters().tx_requests.increment();
642 debug!("sending ARP request for {lookup_addr} to {dst_addr:?}");
643 SendFrameContext::send_frame(
644 core_ctx,
645 bindings_ctx,
646 ArpFrameMetadata { device_id: device_id.clone(), dst_addr },
647 ArpPacketBuilder::new(
648 ArpOp::Request,
649 self_hw_addr.get(),
650 sender_addr,
651 remote_link_addr.unwrap_or(D::Address::UNSPECIFIED),
661 lookup_addr,
662 )
663 .into_serializer(),
664 )
665 .unwrap_or_else(|serializer| {
666 warn!("failed to send ARP request for {lookup_addr} to {dst_addr:?}: {serializer:?}")
667 });
668}
669
670pub struct ArpState<D: ArpDevice, BT: NudBindingsTypes<D>> {
676 pub(crate) nud: NudState<Ipv4, D, BT>,
677}
678
679impl<D: ArpDevice, BC: NudBindingsTypes<D> + TimerContext> ArpState<D, BC> {
680 pub fn new<
682 DeviceId: WeakDeviceIdentifier,
683 CC: CoreTimerContext<ArpTimerId<D, DeviceId>, BC>,
684 >(
685 bindings_ctx: &mut BC,
686 device_id: DeviceId,
687 ) -> Self {
688 ArpState { nud: NudState::new::<_, CC>(bindings_ctx, device_id) }
689 }
690}
691
692#[cfg(test)]
693mod tests {
694 use alloc::vec;
695 use alloc::vec::Vec;
696 use core::iter;
697 use net_types::ip::Ip;
698
699 use assert_matches::assert_matches;
700 use net_types::ethernet::Mac;
701 use netstack3_base::socket::SocketIpAddr;
702 use netstack3_base::testutil::{
703 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeLinkDeviceId, FakeNetworkSpec,
704 FakeTimerId, FakeTxMetadata, FakeWeakDeviceId, WithFakeFrameContext, assert_empty,
705 };
706 use netstack3_base::{CtxPair, InstantContext as _, IntoCoreTimerCtx, TimerHandler};
707 use netstack3_ip::nud::testutil::{
708 assert_dynamic_neighbor_state, assert_dynamic_neighbor_with_addr, assert_neighbor_unknown,
709 };
710 use netstack3_ip::nud::{
711 DelegateNudContext, DynamicNeighborState, NudCounters, NudIcmpContext, Reachable, Stale,
712 UseDelegateNudContext,
713 };
714 use packet::{Buf, ParseBuffer};
715 use packet_formats::arp::{ArpHardwareType, ArpNetworkType, peek_arp_types};
716 use packet_formats::ipv4::Ipv4FragmentType;
717 use test_case::test_case;
718
719 use super::*;
720 use crate::internal::ethernet::EthernetLinkDevice;
721
722 const TEST_LOCAL_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
723 const TEST_LOCAL_IPV4_2: Ipv4Addr = Ipv4Addr::new([4, 5, 6, 7]);
724 const TEST_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
725 const TEST_ANOTHER_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([9, 10, 11, 12]);
726 const TEST_LOCAL_MAC: Mac = Mac::new([0, 1, 2, 3, 4, 5]);
727 const TEST_REMOTE_MAC: Mac = Mac::new([6, 7, 8, 9, 10, 11]);
728 const TEST_INVALID_MAC: Mac = Mac::new([0, 0, 0, 0, 0, 0]);
729
730 struct FakeArpCtx {
733 proto_addrs: Vec<Ipv4Addr>,
734 hw_addr: UnicastAddr<Mac>,
735 arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
736 inner: FakeArpInnerCtx,
737 config: FakeArpConfigCtx,
738 counters: ArpCounters,
739 nud_counters: NudCounters<Ipv4>,
740 dispatched_arp_packets: Vec<(Ipv4Addr, Ipv4Addr, bool)>,
743 }
744
745 struct FakeArpInnerCtx;
747
748 struct FakeArpConfigCtx;
750
751 impl FakeArpCtx {
752 fn new(bindings_ctx: &mut FakeBindingsCtxImpl) -> FakeArpCtx {
753 FakeArpCtx {
754 proto_addrs: vec![TEST_LOCAL_IPV4, TEST_LOCAL_IPV4_2],
755 hw_addr: UnicastAddr::new(TEST_LOCAL_MAC).unwrap(),
756 arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
757 bindings_ctx,
758 FakeWeakDeviceId(FakeLinkDeviceId),
759 ),
760 inner: FakeArpInnerCtx,
761 config: FakeArpConfigCtx,
762 counters: Default::default(),
763 nud_counters: Default::default(),
764 dispatched_arp_packets: Default::default(),
765 }
766 }
767 }
768
769 type FakeBindingsCtxImpl = FakeBindingsCtx<
770 ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>,
771 nud::Event<Mac, FakeLinkDeviceId, Ipv4, FakeInstant>,
772 (),
773 (),
774 >;
775
776 type FakeCoreCtxImpl = FakeCoreCtx<
777 FakeArpCtx,
778 ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>,
779 FakeDeviceId,
780 >;
781
782 fn new_context() -> CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl> {
783 CtxPair::with_default_bindings_ctx(|bindings_ctx| {
784 FakeCoreCtxImpl::with_state(FakeArpCtx::new(bindings_ctx))
785 })
786 }
787
788 enum ArpNetworkSpec {}
789 impl FakeNetworkSpec for ArpNetworkSpec {
790 type Context = CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl>;
791 type TimerId = ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>;
792 type SendMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
793 type RecvMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
794
795 fn handle_frame(
796 ctx: &mut Self::Context,
797 ArpFrameMetadata { device_id, .. }: Self::RecvMeta,
798 data: Buf<Vec<u8>>,
799 ) {
800 let CtxPair { core_ctx, bindings_ctx } = ctx;
801 handle_packet(
802 core_ctx,
803 bindings_ctx,
804 device_id,
805 FrameDestination::Individual { local: true },
806 data,
807 )
808 }
809 fn handle_timer(ctx: &mut Self::Context, dispatch: Self::TimerId, timer: FakeTimerId) {
810 let CtxPair { core_ctx, bindings_ctx } = ctx;
811 TimerHandler::handle_timer(core_ctx, bindings_ctx, dispatch, timer)
812 }
813
814 fn process_queues(_ctx: &mut Self::Context) -> bool {
815 false
816 }
817
818 fn fake_frames(ctx: &mut Self::Context) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
819 &mut ctx.core_ctx
820 }
821 }
822
823 impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxImpl {
824 type DeviceId = FakeLinkDeviceId;
825 type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
826 }
827
828 impl DeviceIdContext<EthernetLinkDevice> for FakeArpInnerCtx {
829 type DeviceId = FakeLinkDeviceId;
830 type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
831 }
832
833 impl ArpContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
834 type ConfigCtx<'a> = FakeArpConfigCtx;
835
836 type ArpSenderCtx<'a> = FakeArpInnerCtx;
837
838 fn with_arp_state_mut_and_sender_ctx<
839 O,
840 F: FnOnce(
841 &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
842 &mut Self::ArpSenderCtx<'_>,
843 ) -> O,
844 >(
845 &mut self,
846 FakeLinkDeviceId: &FakeLinkDeviceId,
847 cb: F,
848 ) -> O {
849 let FakeArpCtx { arp_state, inner, .. } = &mut self.state;
850 cb(arp_state, inner)
851 }
852
853 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>) -> O>(
854 &mut self,
855 FakeLinkDeviceId: &FakeLinkDeviceId,
856 cb: F,
857 ) -> O {
858 cb(&self.state.arp_state)
859 }
860
861 fn get_protocol_addr(&mut self, _device_id: &FakeLinkDeviceId) -> Option<Ipv4Addr> {
862 self.state.proto_addrs.first().copied()
863 }
864
865 fn get_hardware_addr(
866 &mut self,
867 _bindings_ctx: &mut FakeBindingsCtxImpl,
868 _device_id: &FakeLinkDeviceId,
869 ) -> UnicastAddr<Mac> {
870 self.state.hw_addr
871 }
872
873 fn with_arp_state_mut<
874 O,
875 F: FnOnce(
876 &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
877 &mut Self::ConfigCtx<'_>,
878 ) -> O,
879 >(
880 &mut self,
881 FakeLinkDeviceId: &FakeLinkDeviceId,
882 cb: F,
883 ) -> O {
884 let FakeArpCtx { arp_state, config, .. } = &mut self.state;
885 cb(arp_state, config)
886 }
887 }
888
889 impl ArpIpLayerContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
890 fn on_arp_packet(
891 &mut self,
892 _bindings_ctx: &mut FakeBindingsCtxImpl,
893 _device_id: &FakeLinkDeviceId,
894 sender_addr: Ipv4Addr,
895 target_addr: Ipv4Addr,
896 is_arp_probe: bool,
897 ) -> bool {
898 self.state.dispatched_arp_packets.push((sender_addr, target_addr, is_arp_probe));
899
900 self.state.proto_addrs.iter().any(|&a| a == target_addr)
901 }
902 }
903
904 impl UseDelegateNudContext for FakeArpCtx {}
905 impl DelegateNudContext<Ipv4> for FakeArpCtx {
906 type Delegate<T> = ArpNudCtx<T>;
907 }
908
909 impl NudIcmpContext<Ipv4, EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
910 fn send_icmp_dest_unreachable(
911 &mut self,
912 _bindings_ctx: &mut FakeBindingsCtxImpl,
913 _frame: Buf<Vec<u8>>,
914 _device_id: Option<&Self::DeviceId>,
915 _original_src: SocketIpAddr<Ipv4Addr>,
916 _original_dst: SocketIpAddr<Ipv4Addr>,
917 _metadata: (usize, Ipv4FragmentType),
918 ) {
919 panic!("send_icmp_dest_unreachable should not be called");
920 }
921 }
922
923 impl ArpConfigContext for FakeArpConfigCtx {
924 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
925 cb(&NudUserConfig::default())
926 }
927 }
928 impl ArpConfigContext for FakeArpInnerCtx {
929 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
930 cb(&NudUserConfig::default())
931 }
932 }
933
934 impl ArpSenderContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeArpInnerCtx {
935 fn send_ip_packet_to_neighbor_link_addr<S>(
936 &mut self,
937 _bindings_ctx: &mut FakeBindingsCtxImpl,
938 _dst_link_address: Mac,
939 _body: S,
940 _tx_meta: FakeTxMetadata,
941 ) -> Result<(), SendFrameError<S>> {
942 Ok(())
943 }
944 }
945
946 impl CounterContext<ArpCounters> for FakeArpCtx {
947 fn counters(&self) -> &ArpCounters {
948 &self.counters
949 }
950 }
951
952 impl CounterContext<NudCounters<Ipv4>> for FakeArpCtx {
953 fn counters(&self) -> &NudCounters<Ipv4> {
954 &self.nud_counters
955 }
956 }
957
958 fn send_arp_packet(
959 core_ctx: &mut FakeCoreCtxImpl,
960 bindings_ctx: &mut FakeBindingsCtxImpl,
961 op: ArpOp,
962 sender_ipv4: Ipv4Addr,
963 target_ipv4: Ipv4Addr,
964 sender_mac: Mac,
965 target_mac: Mac,
966 frame_dst: FrameDestination,
967 ) {
968 let buf = ArpPacketBuilder::new(op, sender_mac, sender_ipv4, target_mac, target_ipv4)
969 .into_serializer()
970 .serialize_vec_outer()
971 .unwrap();
972 let (hw, proto) = peek_arp_types(buf.as_ref()).unwrap();
973 assert_eq!(hw, ArpHardwareType::Ethernet);
974 assert_eq!(proto, ArpNetworkType::Ipv4);
975
976 handle_packet::<_, _, _, _>(core_ctx, bindings_ctx, FakeLinkDeviceId, frame_dst, buf);
977 }
978
979 fn validate_arp_packet(
982 mut buf: &[u8],
983 op: ArpOp,
984 local_ipv4: Ipv4Addr,
985 remote_ipv4: Ipv4Addr,
986 local_mac: Mac,
987 remote_mac: Mac,
988 ) {
989 let packet = buf.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap();
990 assert_eq!(packet.sender_hardware_address(), local_mac);
991 assert_eq!(packet.target_hardware_address(), remote_mac);
992 assert_eq!(packet.sender_protocol_address(), local_ipv4);
993 assert_eq!(packet.target_protocol_address(), remote_ipv4);
994 assert_eq!(packet.operation(), op);
995 }
996
997 fn validate_last_arp_packet(
1000 core_ctx: &FakeCoreCtxImpl,
1001 total_frames: usize,
1002 dst: Mac,
1003 op: ArpOp,
1004 local_ipv4: Ipv4Addr,
1005 remote_ipv4: Ipv4Addr,
1006 local_mac: Mac,
1007 remote_mac: Mac,
1008 ) {
1009 assert_eq!(core_ctx.frames().len(), total_frames);
1010 let (meta, frame) = &core_ctx.frames()[total_frames - 1];
1011 assert_eq!(meta.dst_addr, dst);
1012 validate_arp_packet(frame, op, local_ipv4, remote_ipv4, local_mac, remote_mac);
1013 }
1014
1015 #[test]
1016 fn test_receive_gratuitous_arp_request() {
1017 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1021 send_arp_packet(
1022 &mut core_ctx,
1023 &mut bindings_ctx,
1024 ArpOp::Request,
1025 TEST_REMOTE_IPV4,
1026 TEST_REMOTE_IPV4,
1027 TEST_REMOTE_MAC,
1028 TEST_INVALID_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 assert_empty(core_ctx.frames().iter());
1041 }
1042
1043 #[test]
1044 fn test_receive_gratuitous_arp_response() {
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::Response,
1053 TEST_REMOTE_IPV4,
1054 TEST_REMOTE_IPV4,
1055 TEST_REMOTE_MAC,
1056 TEST_REMOTE_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_existing_request() {
1073 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1078
1079 assert_neighbor_unknown(
1081 &mut core_ctx,
1082 FakeLinkDeviceId,
1083 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1084 );
1085 assert_eq!(
1086 NudHandler::send_ip_packet_to_neighbor(
1087 &mut core_ctx,
1088 &mut bindings_ctx,
1089 &FakeLinkDeviceId,
1090 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1091 Buf::new([1], ..),
1092 FakeTxMetadata::default(),
1093 ),
1094 Ok(())
1095 );
1096
1097 send_arp_packet(
1098 &mut core_ctx,
1099 &mut bindings_ctx,
1100 ArpOp::Response,
1101 TEST_REMOTE_IPV4,
1102 TEST_REMOTE_IPV4,
1103 TEST_REMOTE_MAC,
1104 TEST_REMOTE_MAC,
1105 FrameDestination::Individual { local: false },
1106 );
1107
1108 assert_dynamic_neighbor_with_addr(
1110 &mut core_ctx,
1111 FakeLinkDeviceId,
1112 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1113 TEST_REMOTE_MAC,
1114 );
1115
1116 assert_eq!(core_ctx.frames().len(), 1);
1119 }
1120
1121 #[test_case(TEST_LOCAL_IPV4)]
1122 #[test_case(TEST_LOCAL_IPV4_2)]
1123 fn test_handle_arp_request(local_addr: Ipv4Addr) {
1124 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1128
1129 send_arp_packet(
1130 &mut core_ctx,
1131 &mut bindings_ctx,
1132 ArpOp::Request,
1133 TEST_REMOTE_IPV4,
1134 local_addr,
1135 TEST_REMOTE_MAC,
1136 TEST_LOCAL_MAC,
1137 FrameDestination::Individual { local: true },
1138 );
1139
1140 assert_dynamic_neighbor_with_addr(
1142 &mut core_ctx,
1143 FakeLinkDeviceId,
1144 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1145 TEST_REMOTE_MAC,
1146 );
1147
1148 validate_last_arp_packet(
1150 &core_ctx,
1151 1,
1152 TEST_REMOTE_MAC,
1153 ArpOp::Response,
1154 local_addr,
1155 TEST_REMOTE_IPV4,
1156 TEST_LOCAL_MAC,
1157 TEST_REMOTE_MAC,
1158 );
1159 }
1160
1161 struct ArpHostConfig<'a> {
1162 name: &'a str,
1163 proto_addr: Ipv4Addr,
1164 hw_addr: Mac,
1165 }
1166
1167 #[test_case(ArpHostConfig {
1168 name: "remote",
1169 proto_addr: TEST_REMOTE_IPV4,
1170 hw_addr: TEST_REMOTE_MAC
1171 },
1172 vec![]
1173 )]
1174 #[test_case(ArpHostConfig {
1175 name: "requested_remote",
1176 proto_addr: TEST_REMOTE_IPV4,
1177 hw_addr: TEST_REMOTE_MAC
1178 },
1179 vec![
1180 ArpHostConfig {
1181 name: "non_requested_remote",
1182 proto_addr: TEST_ANOTHER_REMOTE_IPV4,
1183 hw_addr: TEST_REMOTE_MAC
1184 }
1185 ]
1186 )]
1187 fn test_address_resolution(
1188 requested_remote_cfg: ArpHostConfig<'_>,
1189 other_remote_cfgs: Vec<ArpHostConfig<'_>>,
1190 ) {
1191 const LOCAL_HOST_CFG: ArpHostConfig<'_> =
1203 ArpHostConfig { name: "local", proto_addr: TEST_LOCAL_IPV4, hw_addr: TEST_LOCAL_MAC };
1204 let host_iter = other_remote_cfgs
1205 .iter()
1206 .chain(iter::once(&requested_remote_cfg))
1207 .chain(iter::once(&LOCAL_HOST_CFG));
1208
1209 let mut network = ArpNetworkSpec::new_network(
1210 {
1211 host_iter.clone().map(|cfg| {
1212 let ArpHostConfig { name, proto_addr, hw_addr } = cfg;
1213 let mut ctx = new_context();
1214 let CtxPair { core_ctx, bindings_ctx: _ } = &mut ctx;
1215 core_ctx.state.hw_addr = UnicastAddr::new(*hw_addr).unwrap();
1216 core_ctx.state.proto_addrs = vec![*proto_addr];
1217 (*name, ctx)
1218 })
1219 },
1220 |ctx: &str, meta: ArpFrameMetadata<_, _>| {
1221 host_iter
1222 .clone()
1223 .filter_map(|cfg| {
1224 let ArpHostConfig { name, proto_addr: _, hw_addr: _ } = cfg;
1225 if !ctx.eq(*name) { Some((*name, meta.clone(), None)) } else { None }
1226 })
1227 .collect::<Vec<_>>()
1228 },
1229 );
1230
1231 let ArpHostConfig {
1232 name: local_name,
1233 proto_addr: local_proto_addr,
1234 hw_addr: local_hw_addr,
1235 } = LOCAL_HOST_CFG;
1236
1237 let ArpHostConfig {
1238 name: requested_remote_name,
1239 proto_addr: requested_remote_proto_addr,
1240 hw_addr: requested_remote_hw_addr,
1241 } = requested_remote_cfg;
1242
1243 network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx }| {
1245 assert_neighbor_unknown(
1246 core_ctx,
1247 FakeLinkDeviceId,
1248 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1249 );
1250 assert_eq!(
1251 NudHandler::send_ip_packet_to_neighbor(
1252 core_ctx,
1253 bindings_ctx,
1254 &FakeLinkDeviceId,
1255 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1256 Buf::new([1], ..),
1257 FakeTxMetadata::default(),
1258 ),
1259 Ok(())
1260 );
1261
1262 validate_last_arp_packet(
1264 core_ctx,
1265 1,
1266 Mac::BROADCAST,
1267 ArpOp::Request,
1268 local_proto_addr,
1269 requested_remote_proto_addr,
1270 local_hw_addr,
1271 Mac::UNSPECIFIED,
1272 );
1273 });
1274 let res = network.step();
1276 assert_eq!(res.timers_fired, 0);
1277
1278 let expected_frames_sent_bcast = other_remote_cfgs.len() + 1;
1283 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1284
1285 network.with_context(requested_remote_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1288 assert_dynamic_neighbor_with_addr(
1289 core_ctx,
1290 FakeLinkDeviceId,
1291 SpecifiedAddr::new(local_proto_addr).unwrap(),
1292 LOCAL_HOST_CFG.hw_addr,
1293 );
1294
1295 validate_last_arp_packet(
1297 core_ctx,
1298 1,
1299 local_hw_addr,
1300 ArpOp::Response,
1301 requested_remote_proto_addr,
1302 local_proto_addr,
1303 requested_remote_hw_addr,
1304 local_hw_addr,
1305 );
1306 });
1307
1308 let res = network.step();
1310 assert_eq!(res.timers_fired, 0);
1311 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1312
1313 network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1316 assert_dynamic_neighbor_with_addr(
1317 core_ctx,
1318 FakeLinkDeviceId,
1319 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1320 requested_remote_hw_addr,
1321 );
1322 });
1323
1324 other_remote_cfgs.iter().for_each(
1325 |ArpHostConfig { name: unrequested_remote_name, proto_addr: _, hw_addr: _ }| {
1326 network.with_context(
1328 *unrequested_remote_name,
1329 |CtxPair { core_ctx, bindings_ctx: _ }| {
1330 assert_empty(core_ctx.frames().iter());
1332
1333 assert_neighbor_unknown(
1334 core_ctx,
1335 FakeLinkDeviceId,
1336 SpecifiedAddr::new(local_proto_addr).unwrap(),
1337 );
1338 },
1339 )
1340 },
1341 );
1342 }
1343
1344 #[test_case(FrameDestination::Individual { local: true }, true; "unicast to us is solicited")]
1345 #[test_case(
1346 FrameDestination::Individual { local: false },
1347 false;
1348 "unicast to other addr is unsolicited"
1349 )]
1350 #[test_case(FrameDestination::Multicast, false; "multicast reply is unsolicited")]
1351 #[test_case(FrameDestination::Broadcast, false; "broadcast reply is unsolicited")]
1352 fn only_unicast_reply_treated_as_solicited(
1353 frame_dst: FrameDestination,
1354 expect_solicited: bool,
1355 ) {
1356 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1357
1358 assert_neighbor_unknown(
1360 &mut core_ctx,
1361 FakeLinkDeviceId,
1362 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1363 );
1364 assert_eq!(
1365 NudHandler::send_ip_packet_to_neighbor(
1366 &mut core_ctx,
1367 &mut bindings_ctx,
1368 &FakeLinkDeviceId,
1369 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1370 Buf::new([1], ..),
1371 FakeTxMetadata::default(),
1372 ),
1373 Ok(())
1374 );
1375
1376 send_arp_packet(
1378 &mut core_ctx,
1379 &mut bindings_ctx,
1380 ArpOp::Response,
1381 TEST_REMOTE_IPV4,
1382 TEST_LOCAL_IPV4,
1383 TEST_REMOTE_MAC,
1384 TEST_LOCAL_MAC,
1385 frame_dst,
1386 );
1387
1388 let expected_state = if expect_solicited {
1391 DynamicNeighborState::Reachable(Reachable {
1392 link_address: TEST_REMOTE_MAC,
1393 last_confirmed_at: bindings_ctx.now(),
1394 })
1395 } else {
1396 DynamicNeighborState::Stale(Stale { link_address: TEST_REMOTE_MAC })
1397 };
1398 assert_dynamic_neighbor_state(
1399 &mut core_ctx,
1400 FakeLinkDeviceId,
1401 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1402 expected_state,
1403 );
1404 }
1405
1406 #[test]
1409 fn test_drop_echoed_arp_packet() {
1410 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1411
1412 send_arp_packet(
1415 &mut core_ctx,
1416 &mut bindings_ctx,
1417 ArpOp::Request,
1418 Ipv4::UNSPECIFIED_ADDRESS, TEST_LOCAL_IPV4, TEST_LOCAL_MAC, Mac::UNSPECIFIED, FrameDestination::Broadcast,
1423 );
1424
1425 assert_neighbor_unknown(
1427 &mut core_ctx,
1428 FakeLinkDeviceId,
1429 SpecifiedAddr::new(TEST_LOCAL_IPV4).unwrap(),
1430 );
1431
1432 assert_eq!(core_ctx.frames().len(), 0);
1434 }
1435
1436 #[test]
1438 fn test_send_arp_probe() {
1439 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1440
1441 const LOCAL_IP: Ipv4Addr = Ipv4::UNSPECIFIED_ADDRESS;
1442 send_arp_request(
1443 &mut core_ctx,
1444 &mut bindings_ctx,
1445 &FakeLinkDeviceId,
1446 LOCAL_IP,
1447 TEST_REMOTE_IPV4,
1448 None,
1449 );
1450
1451 let (meta, frame) = assert_matches!(core_ctx.frames(), [frame] => frame);
1453 assert_eq!(meta.dst_addr, Mac::BROADCAST);
1456 validate_arp_packet(
1457 frame,
1458 ArpOp::Request,
1459 LOCAL_IP,
1460 TEST_REMOTE_IPV4,
1461 TEST_LOCAL_MAC,
1462 Mac::UNSPECIFIED,
1463 );
1464 }
1465
1466 #[test_case(ArpOp::Request, TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, true; "dispatch_request")]
1468 #[test_case(ArpOp::Response, TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, true; "dispatch_reply")]
1469 #[test_case(ArpOp::Request, Ipv4::UNSPECIFIED_ADDRESS, TEST_LOCAL_IPV4, true; "dispatch_probe")]
1470 #[test_case(ArpOp::Other(99), TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, false; "ignore_other")]
1471 fn test_receive_arp_packet(
1472 op: ArpOp,
1473 sender_addr: Ipv4Addr,
1474 target_addr: Ipv4Addr,
1475 expect_dispatch: bool,
1476 ) {
1477 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1478
1479 send_arp_packet(
1480 &mut core_ctx,
1481 &mut bindings_ctx,
1482 op,
1483 sender_addr,
1484 target_addr,
1485 TEST_REMOTE_MAC,
1486 TEST_LOCAL_MAC,
1487 FrameDestination::Broadcast,
1488 );
1489
1490 let is_arp_probe = sender_addr == Ipv4::UNSPECIFIED_ADDRESS && op == ArpOp::Request;
1491
1492 if expect_dispatch {
1493 assert_eq!(
1494 &core_ctx.state.dispatched_arp_packets[..],
1495 [(sender_addr, target_addr, is_arp_probe)]
1496 );
1497 } else {
1498 assert_eq!(&core_ctx.state.dispatched_arp_packets[..], []);
1499 }
1500 }
1501}