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