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
689 use assert_matches::assert_matches;
690 use net_types::ethernet::Mac;
691 use netstack3_base::socket::SocketIpAddr;
692 use netstack3_base::testutil::{
693 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeLinkDeviceId, FakeNetworkSpec,
694 FakeTimerId, FakeTxMetadata, FakeWeakDeviceId, WithFakeFrameContext, assert_empty,
695 };
696 use netstack3_base::{CtxPair, InstantContext as _, IntoCoreTimerCtx, TimerHandler};
697 use netstack3_ip::nud::testutil::{
698 assert_dynamic_neighbor_state, assert_dynamic_neighbor_with_addr, assert_neighbor_unknown,
699 };
700 use netstack3_ip::nud::{
701 DelegateNudContext, DynamicNeighborState, NudCounters, NudIcmpContext, Reachable, Stale,
702 UseDelegateNudContext,
703 };
704 use packet::{Buf, ParseBuffer};
705 use packet_formats::arp::{ArpHardwareType, ArpNetworkType, peek_arp_types};
706 use packet_formats::ipv4::Ipv4FragmentType;
707 use test_case::test_case;
708
709 use super::*;
710 use crate::internal::ethernet::EthernetLinkDevice;
711
712 const TEST_LOCAL_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
713 const TEST_LOCAL_IPV4_2: Ipv4Addr = Ipv4Addr::new([4, 5, 6, 7]);
714 const TEST_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
715 const TEST_ANOTHER_REMOTE_IPV4: Ipv4Addr = Ipv4Addr::new([9, 10, 11, 12]);
716 const TEST_LOCAL_MAC: Mac = Mac::new([0, 1, 2, 3, 4, 5]);
717 const TEST_REMOTE_MAC: Mac = Mac::new([6, 7, 8, 9, 10, 11]);
718 const TEST_INVALID_MAC: Mac = Mac::new([0, 0, 0, 0, 0, 0]);
719
720 struct FakeArpCtx {
723 proto_addrs: Vec<Ipv4Addr>,
724 hw_addr: UnicastAddr<Mac>,
725 arp_state: ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
726 inner: FakeArpInnerCtx,
727 config: FakeArpConfigCtx,
728 counters: ArpCounters,
729 nud_counters: NudCounters<Ipv4>,
730 dispatched_arp_packets: Vec<(Ipv4Addr, Ipv4Addr, bool)>,
733 }
734
735 struct FakeArpInnerCtx;
737
738 struct FakeArpConfigCtx;
740
741 impl FakeArpCtx {
742 fn new(bindings_ctx: &mut FakeBindingsCtxImpl) -> FakeArpCtx {
743 FakeArpCtx {
744 proto_addrs: vec![TEST_LOCAL_IPV4, TEST_LOCAL_IPV4_2],
745 hw_addr: UnicastAddr::new(TEST_LOCAL_MAC).unwrap(),
746 arp_state: ArpState::new::<_, IntoCoreTimerCtx>(
747 bindings_ctx,
748 FakeWeakDeviceId(FakeLinkDeviceId),
749 ),
750 inner: FakeArpInnerCtx,
751 config: FakeArpConfigCtx,
752 counters: Default::default(),
753 nud_counters: Default::default(),
754 dispatched_arp_packets: Default::default(),
755 }
756 }
757 }
758
759 type FakeBindingsCtxImpl = FakeBindingsCtx<
760 ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>,
761 nud::Event<Mac, FakeLinkDeviceId, Ipv4, FakeInstant>,
762 (),
763 (),
764 >;
765
766 type FakeCoreCtxImpl = FakeCoreCtx<
767 FakeArpCtx,
768 ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>,
769 FakeDeviceId,
770 >;
771
772 fn new_context() -> CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl> {
773 CtxPair::with_default_bindings_ctx(|bindings_ctx| {
774 FakeCoreCtxImpl::with_state(FakeArpCtx::new(bindings_ctx))
775 })
776 }
777
778 enum ArpNetworkSpec {}
779 impl FakeNetworkSpec for ArpNetworkSpec {
780 type Context = CtxPair<FakeCoreCtxImpl, FakeBindingsCtxImpl>;
781 type TimerId = ArpTimerId<EthernetLinkDevice, FakeWeakDeviceId<FakeLinkDeviceId>>;
782 type SendMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
783 type RecvMeta = ArpFrameMetadata<EthernetLinkDevice, FakeLinkDeviceId>;
784
785 fn handle_frame(
786 ctx: &mut Self::Context,
787 ArpFrameMetadata { device_id, .. }: Self::RecvMeta,
788 data: Buf<Vec<u8>>,
789 ) {
790 let CtxPair { core_ctx, bindings_ctx } = ctx;
791 handle_packet(
792 core_ctx,
793 bindings_ctx,
794 device_id,
795 FrameDestination::Individual { local: true },
796 data,
797 )
798 }
799 fn handle_timer(ctx: &mut Self::Context, dispatch: Self::TimerId, timer: FakeTimerId) {
800 let CtxPair { core_ctx, bindings_ctx } = ctx;
801 TimerHandler::handle_timer(core_ctx, bindings_ctx, dispatch, timer)
802 }
803
804 fn process_queues(_ctx: &mut Self::Context) -> bool {
805 false
806 }
807
808 fn fake_frames(ctx: &mut Self::Context) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
809 &mut ctx.core_ctx
810 }
811 }
812
813 impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxImpl {
814 type DeviceId = FakeLinkDeviceId;
815 type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
816 }
817
818 impl DeviceIdContext<EthernetLinkDevice> for FakeArpInnerCtx {
819 type DeviceId = FakeLinkDeviceId;
820 type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
821 }
822
823 impl ArpContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
824 type ConfigCtx<'a> = FakeArpConfigCtx;
825
826 type ArpSenderCtx<'a> = FakeArpInnerCtx;
827
828 fn with_arp_state_mut_and_sender_ctx<
829 O,
830 F: FnOnce(
831 &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
832 &mut Self::ArpSenderCtx<'_>,
833 ) -> O,
834 >(
835 &mut self,
836 FakeLinkDeviceId: &FakeLinkDeviceId,
837 cb: F,
838 ) -> O {
839 let FakeArpCtx { arp_state, inner, .. } = &mut self.state;
840 cb(arp_state, inner)
841 }
842
843 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>) -> O>(
844 &mut self,
845 FakeLinkDeviceId: &FakeLinkDeviceId,
846 cb: F,
847 ) -> O {
848 cb(&self.state.arp_state)
849 }
850
851 fn get_protocol_addr(&mut self, _device_id: &FakeLinkDeviceId) -> Option<Ipv4Addr> {
852 self.state.proto_addrs.first().copied()
853 }
854
855 fn get_hardware_addr(
856 &mut self,
857 _bindings_ctx: &mut FakeBindingsCtxImpl,
858 _device_id: &FakeLinkDeviceId,
859 ) -> UnicastAddr<Mac> {
860 self.state.hw_addr
861 }
862
863 fn with_arp_state_mut<
864 O,
865 F: FnOnce(
866 &mut ArpState<EthernetLinkDevice, FakeBindingsCtxImpl>,
867 &mut Self::ConfigCtx<'_>,
868 ) -> O,
869 >(
870 &mut self,
871 FakeLinkDeviceId: &FakeLinkDeviceId,
872 cb: F,
873 ) -> O {
874 let FakeArpCtx { arp_state, config, .. } = &mut self.state;
875 cb(arp_state, config)
876 }
877 }
878
879 impl ArpIpLayerContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
880 fn on_arp_packet(
881 &mut self,
882 _bindings_ctx: &mut FakeBindingsCtxImpl,
883 _device_id: &FakeLinkDeviceId,
884 sender_addr: Ipv4Addr,
885 target_addr: Ipv4Addr,
886 is_arp_probe: bool,
887 ) -> bool {
888 self.state.dispatched_arp_packets.push((sender_addr, target_addr, is_arp_probe));
889
890 self.state.proto_addrs.iter().any(|&a| a == target_addr)
891 }
892 }
893
894 impl UseDelegateNudContext for FakeArpCtx {}
895 impl DelegateNudContext<Ipv4> for FakeArpCtx {
896 type Delegate<T> = ArpNudCtx<T>;
897 }
898
899 impl NudIcmpContext<Ipv4, EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
900 fn send_icmp_dest_unreachable(
901 &mut self,
902 _bindings_ctx: &mut FakeBindingsCtxImpl,
903 _frame: Buf<Vec<u8>>,
904 _device_id: Option<&Self::DeviceId>,
905 _original_src: SocketIpAddr<Ipv4Addr>,
906 _original_dst: SocketIpAddr<Ipv4Addr>,
907 _metadata: (usize, Ipv4FragmentType),
908 ) {
909 panic!("send_icmp_dest_unreachable should not be called");
910 }
911 }
912
913 impl ArpConfigContext for FakeArpConfigCtx {
914 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
915 cb(&NudUserConfig::default())
916 }
917 }
918 impl ArpConfigContext for FakeArpInnerCtx {
919 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
920 cb(&NudUserConfig::default())
921 }
922 }
923
924 impl ArpSenderContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeArpInnerCtx {
925 fn send_ip_packet_to_neighbor_link_addr<S>(
926 &mut self,
927 _bindings_ctx: &mut FakeBindingsCtxImpl,
928 _dst_link_address: Mac,
929 _body: S,
930 _tx_meta: FakeTxMetadata,
931 ) -> Result<(), SendFrameError<S>> {
932 Ok(())
933 }
934 }
935
936 impl CounterContext<ArpCounters> for FakeArpCtx {
937 fn counters(&self) -> &ArpCounters {
938 &self.counters
939 }
940 }
941
942 impl CounterContext<NudCounters<Ipv4>> for FakeArpCtx {
943 fn counters(&self) -> &NudCounters<Ipv4> {
944 &self.nud_counters
945 }
946 }
947
948 fn send_arp_packet(
949 core_ctx: &mut FakeCoreCtxImpl,
950 bindings_ctx: &mut FakeBindingsCtxImpl,
951 op: ArpOp,
952 sender_ipv4: Ipv4Addr,
953 target_ipv4: Ipv4Addr,
954 sender_mac: Mac,
955 target_mac: Mac,
956 frame_dst: FrameDestination,
957 ) {
958 let buf = ArpPacketBuilder::new(op, sender_mac, sender_ipv4, target_mac, target_ipv4)
959 .into_serializer()
960 .serialize_vec_outer()
961 .unwrap();
962 let (hw, proto) = peek_arp_types(buf.as_ref()).unwrap();
963 assert_eq!(hw, ArpHardwareType::Ethernet);
964 assert_eq!(proto, ArpNetworkType::Ipv4);
965
966 handle_packet::<_, _, _, _>(core_ctx, bindings_ctx, FakeLinkDeviceId, frame_dst, buf);
967 }
968
969 fn validate_arp_packet(
972 mut buf: &[u8],
973 op: ArpOp,
974 local_ipv4: Ipv4Addr,
975 remote_ipv4: Ipv4Addr,
976 local_mac: Mac,
977 remote_mac: Mac,
978 ) {
979 let packet = buf.parse::<ArpPacket<_, Mac, Ipv4Addr>>().unwrap();
980 assert_eq!(packet.sender_hardware_address(), local_mac);
981 assert_eq!(packet.target_hardware_address(), remote_mac);
982 assert_eq!(packet.sender_protocol_address(), local_ipv4);
983 assert_eq!(packet.target_protocol_address(), remote_ipv4);
984 assert_eq!(packet.operation(), op);
985 }
986
987 fn validate_last_arp_packet(
990 core_ctx: &FakeCoreCtxImpl,
991 total_frames: usize,
992 dst: Mac,
993 op: ArpOp,
994 local_ipv4: Ipv4Addr,
995 remote_ipv4: Ipv4Addr,
996 local_mac: Mac,
997 remote_mac: Mac,
998 ) {
999 assert_eq!(core_ctx.frames().len(), total_frames);
1000 let (meta, frame) = &core_ctx.frames()[total_frames - 1];
1001 assert_eq!(meta.dst_addr, dst);
1002 validate_arp_packet(frame, op, local_ipv4, remote_ipv4, local_mac, remote_mac);
1003 }
1004
1005 #[test]
1006 fn test_receive_gratuitous_arp_request() {
1007 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1011 send_arp_packet(
1012 &mut core_ctx,
1013 &mut bindings_ctx,
1014 ArpOp::Request,
1015 TEST_REMOTE_IPV4,
1016 TEST_REMOTE_IPV4,
1017 TEST_REMOTE_MAC,
1018 TEST_INVALID_MAC,
1019 FrameDestination::Individual { local: false },
1020 );
1021
1022 assert_dynamic_neighbor_with_addr(
1024 &mut core_ctx,
1025 FakeLinkDeviceId,
1026 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1027 TEST_REMOTE_MAC,
1028 );
1029 assert_empty(core_ctx.frames().iter());
1031 }
1032
1033 #[test]
1034 fn test_receive_gratuitous_arp_response() {
1035 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1039 send_arp_packet(
1040 &mut core_ctx,
1041 &mut bindings_ctx,
1042 ArpOp::Response,
1043 TEST_REMOTE_IPV4,
1044 TEST_REMOTE_IPV4,
1045 TEST_REMOTE_MAC,
1046 TEST_REMOTE_MAC,
1047 FrameDestination::Individual { local: false },
1048 );
1049
1050 assert_dynamic_neighbor_with_addr(
1052 &mut core_ctx,
1053 FakeLinkDeviceId,
1054 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1055 TEST_REMOTE_MAC,
1056 );
1057 assert_empty(core_ctx.frames().iter());
1059 }
1060
1061 #[test]
1062 fn test_receive_gratuitous_arp_response_existing_request() {
1063 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1068
1069 assert_neighbor_unknown(
1071 &mut core_ctx,
1072 FakeLinkDeviceId,
1073 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1074 );
1075 assert_eq!(
1076 NudHandler::send_ip_packet_to_neighbor(
1077 &mut core_ctx,
1078 &mut bindings_ctx,
1079 &FakeLinkDeviceId,
1080 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1081 Buf::new([1], ..),
1082 FakeTxMetadata::default(),
1083 ),
1084 Ok(())
1085 );
1086
1087 send_arp_packet(
1088 &mut core_ctx,
1089 &mut bindings_ctx,
1090 ArpOp::Response,
1091 TEST_REMOTE_IPV4,
1092 TEST_REMOTE_IPV4,
1093 TEST_REMOTE_MAC,
1094 TEST_REMOTE_MAC,
1095 FrameDestination::Individual { local: false },
1096 );
1097
1098 assert_dynamic_neighbor_with_addr(
1100 &mut core_ctx,
1101 FakeLinkDeviceId,
1102 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1103 TEST_REMOTE_MAC,
1104 );
1105
1106 assert_eq!(core_ctx.frames().len(), 1);
1109 }
1110
1111 #[test_case(TEST_LOCAL_IPV4)]
1112 #[test_case(TEST_LOCAL_IPV4_2)]
1113 fn test_handle_arp_request(local_addr: Ipv4Addr) {
1114 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1118
1119 send_arp_packet(
1120 &mut core_ctx,
1121 &mut bindings_ctx,
1122 ArpOp::Request,
1123 TEST_REMOTE_IPV4,
1124 local_addr,
1125 TEST_REMOTE_MAC,
1126 TEST_LOCAL_MAC,
1127 FrameDestination::Individual { local: true },
1128 );
1129
1130 assert_dynamic_neighbor_with_addr(
1132 &mut core_ctx,
1133 FakeLinkDeviceId,
1134 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1135 TEST_REMOTE_MAC,
1136 );
1137
1138 validate_last_arp_packet(
1140 &core_ctx,
1141 1,
1142 TEST_REMOTE_MAC,
1143 ArpOp::Response,
1144 local_addr,
1145 TEST_REMOTE_IPV4,
1146 TEST_LOCAL_MAC,
1147 TEST_REMOTE_MAC,
1148 );
1149 }
1150
1151 struct ArpHostConfig<'a> {
1152 name: &'a str,
1153 proto_addr: Ipv4Addr,
1154 hw_addr: Mac,
1155 }
1156
1157 #[test_case(ArpHostConfig {
1158 name: "remote",
1159 proto_addr: TEST_REMOTE_IPV4,
1160 hw_addr: TEST_REMOTE_MAC
1161 },
1162 vec![]
1163 )]
1164 #[test_case(ArpHostConfig {
1165 name: "requested_remote",
1166 proto_addr: TEST_REMOTE_IPV4,
1167 hw_addr: TEST_REMOTE_MAC
1168 },
1169 vec![
1170 ArpHostConfig {
1171 name: "non_requested_remote",
1172 proto_addr: TEST_ANOTHER_REMOTE_IPV4,
1173 hw_addr: TEST_REMOTE_MAC
1174 }
1175 ]
1176 )]
1177 fn test_address_resolution(
1178 requested_remote_cfg: ArpHostConfig<'_>,
1179 other_remote_cfgs: Vec<ArpHostConfig<'_>>,
1180 ) {
1181 const LOCAL_HOST_CFG: ArpHostConfig<'_> =
1193 ArpHostConfig { name: "local", proto_addr: TEST_LOCAL_IPV4, hw_addr: TEST_LOCAL_MAC };
1194 let host_iter = other_remote_cfgs
1195 .iter()
1196 .chain(iter::once(&requested_remote_cfg))
1197 .chain(iter::once(&LOCAL_HOST_CFG));
1198
1199 let mut network = ArpNetworkSpec::new_network(
1200 {
1201 host_iter.clone().map(|cfg| {
1202 let ArpHostConfig { name, proto_addr, hw_addr } = cfg;
1203 let mut ctx = new_context();
1204 let CtxPair { core_ctx, bindings_ctx: _ } = &mut ctx;
1205 core_ctx.state.hw_addr = UnicastAddr::new(*hw_addr).unwrap();
1206 core_ctx.state.proto_addrs = vec![*proto_addr];
1207 (*name, ctx)
1208 })
1209 },
1210 |ctx: &str, meta: ArpFrameMetadata<_, _>| {
1211 host_iter
1212 .clone()
1213 .filter_map(|cfg| {
1214 let ArpHostConfig { name, proto_addr: _, hw_addr: _ } = cfg;
1215 if !ctx.eq(*name) { Some((*name, meta.clone(), None)) } else { None }
1216 })
1217 .collect::<Vec<_>>()
1218 },
1219 );
1220
1221 let ArpHostConfig {
1222 name: local_name,
1223 proto_addr: local_proto_addr,
1224 hw_addr: local_hw_addr,
1225 } = LOCAL_HOST_CFG;
1226
1227 let ArpHostConfig {
1228 name: requested_remote_name,
1229 proto_addr: requested_remote_proto_addr,
1230 hw_addr: requested_remote_hw_addr,
1231 } = requested_remote_cfg;
1232
1233 network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx }| {
1235 assert_neighbor_unknown(
1236 core_ctx,
1237 FakeLinkDeviceId,
1238 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1239 );
1240 assert_eq!(
1241 NudHandler::send_ip_packet_to_neighbor(
1242 core_ctx,
1243 bindings_ctx,
1244 &FakeLinkDeviceId,
1245 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1246 Buf::new([1], ..),
1247 FakeTxMetadata::default(),
1248 ),
1249 Ok(())
1250 );
1251
1252 validate_last_arp_packet(
1254 core_ctx,
1255 1,
1256 Mac::BROADCAST,
1257 ArpOp::Request,
1258 local_proto_addr,
1259 requested_remote_proto_addr,
1260 local_hw_addr,
1261 Mac::UNSPECIFIED,
1262 );
1263 });
1264 let res = network.step();
1266 assert_eq!(res.timers_fired, 0);
1267
1268 let expected_frames_sent_bcast = other_remote_cfgs.len() + 1;
1273 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1274
1275 network.with_context(requested_remote_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1278 assert_dynamic_neighbor_with_addr(
1279 core_ctx,
1280 FakeLinkDeviceId,
1281 SpecifiedAddr::new(local_proto_addr).unwrap(),
1282 LOCAL_HOST_CFG.hw_addr,
1283 );
1284
1285 validate_last_arp_packet(
1287 core_ctx,
1288 1,
1289 local_hw_addr,
1290 ArpOp::Response,
1291 requested_remote_proto_addr,
1292 local_proto_addr,
1293 requested_remote_hw_addr,
1294 local_hw_addr,
1295 );
1296 });
1297
1298 let res = network.step();
1300 assert_eq!(res.timers_fired, 0);
1301 assert_eq!(res.frames_sent, expected_frames_sent_bcast);
1302
1303 network.with_context(local_name, |CtxPair { core_ctx, bindings_ctx: _ }| {
1306 assert_dynamic_neighbor_with_addr(
1307 core_ctx,
1308 FakeLinkDeviceId,
1309 SpecifiedAddr::new(requested_remote_proto_addr).unwrap(),
1310 requested_remote_hw_addr,
1311 );
1312 });
1313
1314 other_remote_cfgs.iter().for_each(
1315 |ArpHostConfig { name: unrequested_remote_name, proto_addr: _, hw_addr: _ }| {
1316 network.with_context(
1318 *unrequested_remote_name,
1319 |CtxPair { core_ctx, bindings_ctx: _ }| {
1320 assert_empty(core_ctx.frames().iter());
1322
1323 assert_neighbor_unknown(
1324 core_ctx,
1325 FakeLinkDeviceId,
1326 SpecifiedAddr::new(local_proto_addr).unwrap(),
1327 );
1328 },
1329 )
1330 },
1331 );
1332 }
1333
1334 #[test_case(FrameDestination::Individual { local: true }, true; "unicast to us is solicited")]
1335 #[test_case(
1336 FrameDestination::Individual { local: false },
1337 false;
1338 "unicast to other addr is unsolicited"
1339 )]
1340 #[test_case(FrameDestination::Multicast, false; "multicast reply is unsolicited")]
1341 #[test_case(FrameDestination::Broadcast, false; "broadcast reply is unsolicited")]
1342 fn only_unicast_reply_treated_as_solicited(
1343 frame_dst: FrameDestination,
1344 expect_solicited: bool,
1345 ) {
1346 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1347
1348 assert_neighbor_unknown(
1350 &mut core_ctx,
1351 FakeLinkDeviceId,
1352 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1353 );
1354 assert_eq!(
1355 NudHandler::send_ip_packet_to_neighbor(
1356 &mut core_ctx,
1357 &mut bindings_ctx,
1358 &FakeLinkDeviceId,
1359 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1360 Buf::new([1], ..),
1361 FakeTxMetadata::default(),
1362 ),
1363 Ok(())
1364 );
1365
1366 send_arp_packet(
1368 &mut core_ctx,
1369 &mut bindings_ctx,
1370 ArpOp::Response,
1371 TEST_REMOTE_IPV4,
1372 TEST_LOCAL_IPV4,
1373 TEST_REMOTE_MAC,
1374 TEST_LOCAL_MAC,
1375 frame_dst,
1376 );
1377
1378 let expected_state = if expect_solicited {
1381 DynamicNeighborState::Reachable(Reachable {
1382 link_address: TEST_REMOTE_MAC,
1383 last_confirmed_at: bindings_ctx.now(),
1384 })
1385 } else {
1386 DynamicNeighborState::Stale(Stale { link_address: TEST_REMOTE_MAC })
1387 };
1388 assert_dynamic_neighbor_state(
1389 &mut core_ctx,
1390 FakeLinkDeviceId,
1391 SpecifiedAddr::new(TEST_REMOTE_IPV4).unwrap(),
1392 expected_state,
1393 );
1394 }
1395
1396 #[test]
1399 fn test_drop_echoed_arp_packet() {
1400 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1401
1402 send_arp_packet(
1405 &mut core_ctx,
1406 &mut bindings_ctx,
1407 ArpOp::Request,
1408 Ipv4::UNSPECIFIED_ADDRESS, TEST_LOCAL_IPV4, TEST_LOCAL_MAC, Mac::UNSPECIFIED, FrameDestination::Broadcast,
1413 );
1414
1415 assert_neighbor_unknown(
1417 &mut core_ctx,
1418 FakeLinkDeviceId,
1419 SpecifiedAddr::new(TEST_LOCAL_IPV4).unwrap(),
1420 );
1421
1422 assert_eq!(core_ctx.frames().len(), 0);
1424 }
1425
1426 #[test]
1428 fn test_send_arp_probe() {
1429 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1430
1431 const LOCAL_IP: Ipv4Addr = Ipv4::UNSPECIFIED_ADDRESS;
1432 send_arp_request(
1433 &mut core_ctx,
1434 &mut bindings_ctx,
1435 &FakeLinkDeviceId,
1436 LOCAL_IP,
1437 TEST_REMOTE_IPV4,
1438 None,
1439 );
1440
1441 let (meta, frame) = assert_matches!(core_ctx.frames(), [frame] => frame);
1443 assert_eq!(meta.dst_addr, Mac::BROADCAST);
1446 validate_arp_packet(
1447 frame,
1448 ArpOp::Request,
1449 LOCAL_IP,
1450 TEST_REMOTE_IPV4,
1451 TEST_LOCAL_MAC,
1452 Mac::UNSPECIFIED,
1453 );
1454 }
1455
1456 #[test_case(ArpOp::Request, TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, true; "dispatch_request")]
1458 #[test_case(ArpOp::Response, TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, true; "dispatch_reply")]
1459 #[test_case(ArpOp::Request, Ipv4::UNSPECIFIED_ADDRESS, TEST_LOCAL_IPV4, true; "dispatch_probe")]
1460 #[test_case(ArpOp::Other(99), TEST_REMOTE_IPV4, TEST_LOCAL_IPV4, false; "ignore_other")]
1461 fn test_receive_arp_packet(
1462 op: ArpOp,
1463 sender_addr: Ipv4Addr,
1464 target_addr: Ipv4Addr,
1465 expect_dispatch: bool,
1466 ) {
1467 let CtxPair { mut core_ctx, mut bindings_ctx } = new_context();
1468
1469 send_arp_packet(
1470 &mut core_ctx,
1471 &mut bindings_ctx,
1472 op,
1473 sender_addr,
1474 target_addr,
1475 TEST_REMOTE_MAC,
1476 TEST_LOCAL_MAC,
1477 FrameDestination::Broadcast,
1478 );
1479
1480 let is_arp_probe = sender_addr == Ipv4::UNSPECIFIED_ADDRESS && op == ArpOp::Request;
1481
1482 if expect_dispatch {
1483 assert_eq!(
1484 &core_ctx.state.dispatched_arp_packets[..],
1485 [(sender_addr, target_addr, is_arp_probe)]
1486 );
1487 } else {
1488 assert_eq!(&core_ctx.state.dispatched_arp_packets[..], []);
1489 }
1490 }
1491}