1#![cfg(any(test, feature = "testutils"))]
8
9pub use netstack3_base::testutil::{FakeDeviceId, TestIpExt};
10pub use netstack3_filter::testutil::new_filter_egress_ip_packet;
11
12use alloc::borrow::ToOwned;
13use alloc::sync::Arc;
14use alloc::vec;
15use alloc::vec::Vec;
16
17use core::borrow::Borrow;
18use core::convert::Infallible as Never;
19use core::fmt::Debug;
20use core::hash::Hash;
21use core::ops::{Deref, DerefMut};
22use core::time::Duration;
23
24use derivative::Derivative;
25use net_types::ethernet::Mac;
26use net_types::ip::{
27 AddrSubnet, AddrSubnetEither, GenericOverIp, Ip, IpAddr, IpAddress, IpInvariant, IpVersion,
28 Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Mtu, Subnet, SubnetEither,
29};
30use net_types::{MulticastAddr, SpecifiedAddr, UnicastAddr, Witness as _};
31use netstack3_base::sync::{DynDebugReferences, Mutex};
32use netstack3_base::testutil::{
33 AlwaysDefaultsSettingsContext, FakeAtomicInstant, FakeCryptoRng, FakeFrameCtx, FakeInstant,
34 FakeNetwork, FakeNetworkLinks, FakeNetworkSpec, FakeSocketWritableListener, FakeTimerCtx,
35 FakeTimerCtxExt, FakeTimerId, MonotonicIdentifier, TestAddrs, WithFakeFrameContext,
36 WithFakeTimerContext,
37};
38use netstack3_base::{
39 AddressResolutionFailed, CtxPair, DeferredResourceRemovalContext, EventContext,
40 FrameDestination, InstantBindingsTypes, InstantContext, IpDeviceAddr, LinkDevice, MarkDomain,
41 Marks, MatcherBindingsTypes, NetworkParsingContext, NotFoundError, ReferenceNotifiers,
42 RemoveResourceResult, RngContext, TimerBindingsTypes, TimerContext, TimerHandler,
43 TxMetadataBindingsTypes, WorkQueueReport,
44};
45use netstack3_datagram::PendingDatagramSocketError;
46use netstack3_device::ethernet::{
47 EthernetCreationProperties, EthernetDeviceEvent, EthernetDeviceId, EthernetLinkDevice,
48 EthernetWeakDeviceId, RecvEthernetFrameMeta,
49};
50use netstack3_device::loopback::{LoopbackCreationProperties, LoopbackDevice, LoopbackDeviceId};
51use netstack3_device::pure_ip::{PureIpDeviceId, PureIpWeakDeviceId};
52use netstack3_device::queue::{ReceiveQueueBindingsContext, TransmitQueueBindingsContext};
53use netstack3_device::socket::{
54 DeviceSocketBindingsContext, DeviceSocketTypes, ReceiveFrameError, SocketId,
55};
56use netstack3_device::testutil::IPV6_MIN_IMPLIED_MAX_FRAME_SIZE;
57use netstack3_device::{
58 self as device, DeviceBufferBindingsTypes, DeviceId, DeviceLayerEventDispatcher,
59 DeviceLayerStateTypes, DeviceLayerTypes, DeviceProvider, DeviceSendFrameError, WeakDeviceId,
60 for_any_device_id,
61};
62use netstack3_filter::testutil::NoOpSocketOpsFilter;
63use netstack3_filter::{FilterTimerId, SocketOpsFilter, SocketOpsFilterBindingContext};
64use netstack3_hashmap::HashMap;
65use netstack3_icmp_echo::{
66 IcmpEchoBindingsContext, IcmpEchoBindingsTypes, IcmpSocketId, ReceiveIcmpEchoError,
67};
68use netstack3_ip::device::{
69 IpDeviceConfiguration, IpDeviceConfigurationUpdate, IpDeviceEvent,
70 Ipv4DeviceConfigurationUpdate, Ipv6DeviceConfigurationUpdate,
71};
72use netstack3_ip::nud::{self, LinkResolutionContext, LinkResolutionNotifier};
73use netstack3_ip::raw::{
74 RawIpSocketId, RawIpSocketsBindingsContext, RawIpSocketsBindingsTypes, ReceivePacketError,
75};
76use netstack3_ip::{
77 self as ip, AddRouteError, AddableEntryEither, AddableMetric, DeviceIpLayerMetadata,
78 IpLayerEvent, IpLayerTimerId, IpRoutingBindingsTypes, MarksBindingsContext, RawMetric,
79 ResolveRouteError, ResolvedRoute, RoutableIpAddr, RouterAdvertisementEvent,
80};
81use netstack3_tcp::testutil::{ClientBuffers, ProvidedBuffers, RingBuffer, TestSendBuffer};
82use netstack3_tcp::{BufferSizes, TcpBindingsTypes};
83use netstack3_udp::{
84 ReceiveUdpError, UdpBindingsTypes, UdpPacketMeta, UdpReceiveBindingsContext, UdpSocketId,
85};
86use packet::{Buf, BufferMut};
87use zerocopy::SplitByteSlice;
88
89use crate::api::CoreApi;
90use crate::context::UnlockedCoreCtx;
91use crate::context::prelude::*;
92use crate::state::{StackState, StackStateBuilder};
93use crate::time::{TimerId, TimerIdInner};
94use crate::{BindingsContext, BindingsTypes, CoreTxMetadata, IpExt};
95
96pub const DEFAULT_INTERFACE_METRIC: RawMetric = RawMetric(100);
98
99pub type Ctx<BT> = CtxPair<StackState<BT>, BT>;
101
102pub trait CtxPairExt<BC: BindingsContext> {
104 fn contexts(&mut self) -> (UnlockedCoreCtx<'_, BC>, &mut BC);
109
110 fn core_api(&mut self) -> CoreApi<'_, &mut BC> {
112 let (core_ctx, bindings_ctx) = self.contexts();
113 CoreApi::new(CtxPair { core_ctx, bindings_ctx })
114 }
115
116 fn core_ctx(&self) -> UnlockedCoreCtx<'_, BC>;
118
119 fn test_api(&mut self) -> TestApi<'_, BC> {
121 let (core_ctx, bindings_ctx) = self.contexts();
122 TestApi(core_ctx, bindings_ctx)
123 }
124
125 fn trigger_next_timer<Id>(&mut self) -> Option<Id>
127 where
128 BC: FakeTimerCtxExt<Id>,
129 for<'a> UnlockedCoreCtx<'a, BC>: TimerHandler<BC, Id>,
130 {
131 let (mut core_ctx, bindings_ctx) = self.contexts();
132 bindings_ctx.trigger_next_timer(&mut core_ctx)
133 }
134
135 fn trigger_timers_for<Id>(&mut self, duration: Duration) -> Vec<Id>
137 where
138 BC: FakeTimerCtxExt<Id>,
139 for<'a> UnlockedCoreCtx<'a, BC>: TimerHandler<BC, Id>,
140 {
141 let (mut core_ctx, bindings_ctx) = self.contexts();
142 bindings_ctx.trigger_timers_for(duration, &mut core_ctx)
143 }
144
145 fn trigger_timers_until_instant<Id>(&mut self, instant: FakeInstant) -> Vec<Id>
147 where
148 BC: FakeTimerCtxExt<Id>,
149 for<'a> UnlockedCoreCtx<'a, BC>: TimerHandler<BC, Id>,
150 {
151 let (mut core_ctx, bindings_ctx) = self.contexts();
152 bindings_ctx.trigger_timers_until_instant(instant, &mut core_ctx)
153 }
154
155 fn trigger_timers_until_and_expect_unordered<Id, I: IntoIterator<Item = Id>>(
157 &mut self,
158 instant: FakeInstant,
159 timers: I,
160 ) where
161 Id: Debug + Hash + Eq,
162 BC: FakeTimerCtxExt<Id>,
163 for<'a> UnlockedCoreCtx<'a, BC>: TimerHandler<BC, Id>,
164 {
165 let (mut core_ctx, bindings_ctx) = self.contexts();
166 bindings_ctx.trigger_timers_until_and_expect_unordered(instant, timers, &mut core_ctx)
167 }
168}
169
170impl<CC, BC> CtxPairExt<BC> for CtxPair<CC, BC>
171where
172 CC: Borrow<StackState<BC>>,
173 BC: BindingsContext,
174{
175 fn contexts(&mut self) -> (UnlockedCoreCtx<'_, BC>, &mut BC) {
176 let Self { core_ctx, bindings_ctx } = self;
177 (UnlockedCoreCtx::new(CC::borrow(core_ctx)), bindings_ctx)
178 }
179
180 fn core_ctx(&self) -> UnlockedCoreCtx<'_, BC> {
181 UnlockedCoreCtx::new(CC::borrow(&self.core_ctx))
182 }
183}
184
185pub struct TestApi<'a, BT: BindingsTypes>(UnlockedCoreCtx<'a, BT>, &'a mut BT);
187
188impl<'l, BC> TestApi<'l, BC>
189where
190 BC: BindingsContext,
191{
192 fn contexts(&mut self) -> (&mut UnlockedCoreCtx<'l, BC>, &mut BC) {
193 let Self(core_ctx, bindings_ctx) = self;
194 (core_ctx, bindings_ctx)
195 }
196
197 fn core_api(&mut self) -> CoreApi<'_, &mut BC> {
198 let (core_ctx, bindings_ctx) = self.contexts();
199 let core_ctx = core_ctx.as_owned();
200 CoreApi::new(CtxPair { core_ctx, bindings_ctx })
201 }
202
203 #[netstack3_macros::context_ip_bounds(A::Version, BC, crate)]
205 pub fn join_ip_multicast<A: IpAddress>(
206 &mut self,
207 device: &DeviceId<BC>,
208 multicast_addr: MulticastAddr<A>,
209 ) where
210 A::Version: IpExt,
211 {
212 let (core_ctx, bindings_ctx) = self.contexts();
213 ip::device::join_ip_multicast::<A::Version, _, _>(
214 core_ctx,
215 bindings_ctx,
216 device,
217 multicast_addr,
218 );
219 }
220
221 #[netstack3_macros::context_ip_bounds(A::Version, BC, crate)]
223 pub fn leave_ip_multicast<A: IpAddress>(
224 &mut self,
225 device: &DeviceId<BC>,
226 multicast_addr: MulticastAddr<A>,
227 ) where
228 A::Version: IpExt,
229 {
230 let (core_ctx, bindings_ctx) = self.contexts();
231 ip::device::leave_ip_multicast::<A::Version, _, _>(
232 core_ctx,
233 bindings_ctx,
234 device,
235 multicast_addr,
236 );
237 }
238
239 #[netstack3_macros::context_ip_bounds(A::Version, BC, crate)]
241 pub fn is_in_ip_multicast<A: IpAddress>(
242 &mut self,
243 device: &DeviceId<BC>,
244 addr: MulticastAddr<A>,
245 ) -> bool
246 where
247 A::Version: IpExt,
248 {
249 use ip::{
250 AddressStatus, IpDeviceIngressStateContext, IpLayerIpExt, Ipv4PresentAddressStatus,
251 Ipv6PresentAddressStatus,
252 };
253
254 let (core_ctx, _) = self.contexts();
255 let addr_status = IpDeviceIngressStateContext::<A::Version>::address_status_for_device(
256 core_ctx,
257 addr.into_specified(),
258 device,
259 );
260 let status = match addr_status {
261 AddressStatus::Present(p) => p,
262 AddressStatus::Unassigned => return false,
263 };
264 #[derive(GenericOverIp)]
265 #[generic_over_ip(I, Ip)]
266 struct Wrap<I: IpLayerIpExt>(I::AddressStatus);
267 A::Version::map_ip(
268 Wrap(status),
269 |Wrap(v4)| match v4 {
270 Ipv4PresentAddressStatus::Multicast => true,
271 Ipv4PresentAddressStatus::LimitedBroadcast
272 | Ipv4PresentAddressStatus::SubnetBroadcast
273 | Ipv4PresentAddressStatus::LoopbackSubnet
274 | Ipv4PresentAddressStatus::UnicastAssigned
275 | Ipv4PresentAddressStatus::UnicastTentative => false,
276 },
277 |Wrap(v6)| match v6 {
278 Ipv6PresentAddressStatus::Multicast => true,
279 Ipv6PresentAddressStatus::UnicastAssigned
280 | Ipv6PresentAddressStatus::UnicastTentative => false,
281 },
282 )
283 }
284
285 pub fn receive_ip_packet<I: Ip, B: BufferMut>(
290 &mut self,
291 device: &DeviceId<BC>,
292 frame_dst: Option<FrameDestination>,
293 buffer: B,
294 ) {
295 self.receive_ip_packet_with_marks::<I, B>(device, frame_dst, buffer, Default::default())
296 }
297
298 pub fn receive_ip_packet_with_marks<I: Ip, B: BufferMut>(
303 &mut self,
304 device: &DeviceId<BC>,
305 frame_dst: Option<FrameDestination>,
306 buffer: B,
307 marks: Marks,
308 ) {
309 let (core_ctx, bindings_ctx) = self.contexts();
310 match I::VERSION {
311 IpVersion::V4 => ip::receive_ipv4_packet(
312 core_ctx,
313 bindings_ctx,
314 device,
315 frame_dst,
316 DeviceIpLayerMetadata::with_marks(marks),
317 NetworkParsingContext::default(),
320 buffer,
321 ),
322 IpVersion::V6 => ip::receive_ipv6_packet(
323 core_ctx,
324 bindings_ctx,
325 device,
326 frame_dst,
327 DeviceIpLayerMetadata::with_marks(marks),
328 NetworkParsingContext::default(),
331 buffer,
332 ),
333 }
334 }
335
336 pub fn add_route(
338 &mut self,
339 entry: AddableEntryEither<DeviceId<BC>>,
340 ) -> Result<(), AddRouteError> {
341 let (core_ctx, _bindings_ctx) = self.contexts();
342 match entry {
343 AddableEntryEither::V4(entry) => ip::testutil::add_route::<Ipv4, _, _>(core_ctx, entry),
344 AddableEntryEither::V6(entry) => ip::testutil::add_route::<Ipv6, _, _>(core_ctx, entry),
345 }
346 }
347
348 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
350 pub fn set_rules<I: IpExt>(&mut self, rules: Vec<netstack3_ip::Rule<I, DeviceId<BC>, BC>>) {
351 let (core_ctx, _bindings_ctx) = self.contexts();
352 ip::testutil::set_rules(core_ctx, rules)
353 }
354
355 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
357 pub fn resolve_route_with_src_addr<I: IpExt>(
358 &mut self,
359 src_ip: IpDeviceAddr<I::Addr>,
360 dst_ip: Option<RoutableIpAddr<I::Addr>>,
361 ) -> Result<ResolvedRoute<I, DeviceId<BC>>, ResolveRouteError> {
362 let (core_ctx, _bindings_ctx) = self.contexts();
363 ip::resolve_output_route_to_destination(
364 core_ctx,
365 None,
366 Some((src_ip, ip::NonLocalSrcAddrPolicy::Deny)),
367 dst_ip,
368 &Default::default(),
369 )
370 }
371
372 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
374 pub fn resolve_route_with_marks<I: IpExt>(
375 &mut self,
376 dst_ip: Option<RoutableIpAddr<I::Addr>>,
377 marks: &Marks,
378 ) -> Result<ResolvedRoute<I, DeviceId<BC>>, ResolveRouteError> {
379 let (core_ctx, _bindings_ctx) = self.contexts();
380 ip::resolve_output_route_to_destination(core_ctx, None, None, dst_ip, marks)
381 }
382
383 pub fn del_routes_to_subnet(
386 &mut self,
387 subnet: net_types::ip::SubnetEither,
388 ) -> Result<(), NotFoundError> {
389 let (core_ctx, _bindings_ctx) = self.contexts();
390 match subnet {
391 SubnetEither::V4(subnet) => {
392 ip::testutil::del_routes_to_subnet::<Ipv4, _, _>(core_ctx, subnet)
393 }
394 SubnetEither::V6(subnet) => {
395 ip::testutil::del_routes_to_subnet::<Ipv6, _, _>(core_ctx, subnet)
396 }
397 }
398 }
399
400 pub fn del_device_routes(&mut self, device: &DeviceId<BC>) {
402 let (core_ctx, _bindings_ctx) = self.contexts();
403 ip::testutil::del_device_routes::<Ipv4, _, _>(core_ctx, device);
404 ip::testutil::del_device_routes::<Ipv6, _, _>(core_ctx, device);
405 }
406
407 pub fn clear_routes_and_remove_device<D: Into<DeviceId<BC>>>(&mut self, device: D) {
409 let device = device.into();
410 self.del_device_routes(&device);
411
412 for_any_device_id!(DeviceId, DeviceProvider, D, device,
413 device => match self.core_api().device::<D>().remove_device(device) {
414 RemoveResourceResult::Removed(_external_state) => {}
415 RemoveResourceResult::Deferred(_reference_receiver) => {
416 panic!("failed to remove device")
417 }
418 });
419 }
420
421 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
424 pub fn set_ip_device_enabled<I: IpExt>(
425 &mut self,
426 device: &DeviceId<BC>,
427 enabled: bool,
428 ) -> bool {
429 let update =
430 IpDeviceConfigurationUpdate { ip_enabled: Some(enabled), ..Default::default() };
431 let prev =
432 self.core_api().device_ip::<I>().update_configuration(device, update.into()).unwrap();
433 prev.as_ref().ip_enabled.unwrap()
434 }
435
436 pub fn enable_device(&mut self, device: &DeviceId<BC>) {
438 let _was_enabled: bool = self.set_ip_device_enabled::<Ipv4>(device, true);
439 let _was_enabled: bool = self.set_ip_device_enabled::<Ipv6>(device, true);
440 }
441
442 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
444 pub fn set_unicast_forwarding_enabled<I: IpExt>(
445 &mut self,
446 device: &DeviceId<BC>,
447 enabled: bool,
448 ) {
449 let _config = self
450 .core_api()
451 .device_ip::<I>()
452 .update_configuration(
453 device,
454 IpDeviceConfigurationUpdate {
455 unicast_forwarding_enabled: Some(enabled),
456 ..Default::default()
457 }
458 .into(),
459 )
460 .unwrap();
461 }
462
463 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
465 pub fn set_multicast_forwarding_enabled<I: IpExt>(
466 &mut self,
467 device: &DeviceId<BC>,
468 enabled: bool,
469 ) {
470 let _config = self
471 .core_api()
472 .device_ip::<I>()
473 .update_configuration(
474 device,
475 IpDeviceConfigurationUpdate {
476 multicast_forwarding_enabled: Some(enabled),
477 ..Default::default()
478 }
479 .into(),
480 )
481 .unwrap();
482 }
483
484 #[netstack3_macros::context_ip_bounds(I, BC, crate)]
486 pub fn is_unicast_forwarding_enabled<I: IpExt>(&mut self, device: &DeviceId<BC>) -> bool {
487 let configuration = self.core_api().device_ip::<I>().get_configuration(device);
488 let IpDeviceConfiguration { unicast_forwarding_enabled, .. } = configuration.as_ref();
489 *unicast_forwarding_enabled
490 }
491
492 pub fn add_loopback(&mut self) -> LoopbackDeviceId<BC>
494 where
495 <BC as DeviceLayerStateTypes>::DeviceIdentifier: Default,
496 <BC as DeviceLayerStateTypes>::LoopbackDeviceState: Default,
497 {
498 let loopback_id = self.core_api().device::<LoopbackDevice>().add_device_with_default_state(
499 LoopbackCreationProperties { mtu: Mtu::new(u32::MAX) },
500 DEFAULT_INTERFACE_METRIC,
501 );
502 let device_id: DeviceId<_> = loopback_id.clone().into();
503 self.enable_device(&device_id);
504
505 self.core_api()
506 .device_ip::<Ipv4>()
507 .add_ip_addr_subnet(
508 &device_id,
509 AddrSubnet::from_witness(Ipv4::LOOPBACK_ADDRESS, Ipv4::LOOPBACK_SUBNET.prefix())
510 .unwrap(),
511 )
512 .unwrap();
513
514 self.core_api()
515 .device_ip::<Ipv6>()
516 .add_ip_addr_subnet(
517 &device_id,
518 AddrSubnet::from_witness(Ipv6::LOOPBACK_ADDRESS, Ipv6::LOOPBACK_SUBNET.prefix())
519 .unwrap(),
520 )
521 .unwrap();
522 loopback_id
523 }
524}
525
526impl<'a> TestApi<'a, FakeBindingsCtx> {
527 pub fn handle_queued_rx_packets(&mut self) -> bool {
530 let mut handled = false;
531 loop {
532 let (_, bindings_ctx) = self.contexts();
533 let rx_available = core::mem::take(&mut bindings_ctx.state_mut().rx_available);
534 if rx_available.len() == 0 {
535 break handled;
536 }
537 handled = true;
538 for id in rx_available.into_iter() {
539 loop {
540 match self.core_api().receive_queue().handle_queued_frames(&id) {
541 WorkQueueReport::AllDone => break,
542 WorkQueueReport::Pending => (),
543 }
544 }
545 }
546 }
547 }
548}
549
550#[derive(Default)]
551pub struct FakeBindingsCtxState {
553 icmpv4_replies:
554 HashMap<IcmpSocketId<Ipv4, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
555 icmpv6_replies:
556 HashMap<IcmpSocketId<Ipv6, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
557 udpv4_received:
558 HashMap<UdpSocketId<Ipv4, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
559 udpv6_received:
560 HashMap<UdpSocketId<Ipv6, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>,
561 pub rx_available: Vec<LoopbackDeviceId<FakeBindingsCtx>>,
563 pub tx_available: Vec<DeviceId<FakeBindingsCtx>>,
565 #[cfg(loom)]
567 pub deferred_receivers: Vec<loom_notifiers::LoomReceiver>,
568}
569
570impl FakeBindingsCtxState {
571 pub(crate) fn udp_state_mut<I: IpExt>(
572 &mut self,
573 ) -> &mut HashMap<UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>, Vec<Vec<u8>>>
574 {
575 #[derive(GenericOverIp)]
576 #[generic_over_ip(I, Ip)]
577 struct Wrapper<'a, I: IpExt>(
578 &'a mut HashMap<
579 UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
580 Vec<Vec<u8>>,
581 >,
582 );
583 let Wrapper(map) = I::map_ip_out::<_, Wrapper<'_, I>>(
584 self,
585 |this| Wrapper(&mut this.udpv4_received),
586 |this| Wrapper(&mut this.udpv6_received),
587 );
588 map
589 }
590}
591
592pub type FakeCtx = Ctx<FakeBindingsCtx>;
594pub type FakeCoreCtx = StackState<FakeBindingsCtx>;
596
597type InnerFakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<
598 TimerId<FakeBindingsCtx>,
599 DispatchedEvent,
600 FakeBindingsCtxState,
601 DispatchedFrame,
602>;
603
604#[derive(Default, Clone)]
606pub struct FakeBindingsCtx(Arc<Mutex<InnerFakeBindingsCtx>>);
607
608struct Wrapper<S, Callback, CallbackMut>(S, Callback, CallbackMut);
618
619impl<T: ?Sized, S: Deref, Callback: for<'a> Fn(&'a <S as Deref>::Target) -> &'a T, CallbackMut>
620 Deref for Wrapper<S, Callback, CallbackMut>
621{
622 type Target = T;
623
624 fn deref(&self) -> &T {
625 let Self(guard, f, _) = self;
626 let target = guard.deref();
627 f(target)
628 }
629}
630
631impl<
632 T: ?Sized,
633 S: DerefMut,
634 Callback: for<'a> Fn(&'a <S as Deref>::Target) -> &'a T,
635 CallbackMut: for<'a> Fn(&'a mut <S as Deref>::Target) -> &'a mut T,
636> DerefMut for Wrapper<S, Callback, CallbackMut>
637{
638 fn deref_mut(&mut self) -> &mut T {
639 let Self(guard, _, f) = self;
640 let target = guard.deref_mut();
641 f(target)
642 }
643}
644
645impl FakeBindingsCtx {
646 fn with_inner<F: FnOnce(&InnerFakeBindingsCtx) -> O, O>(&self, f: F) -> O {
647 let Self(this) = self;
648 let locked = this.lock();
649 f(&*locked)
650 }
651
652 fn with_inner_mut<F: FnOnce(&mut InnerFakeBindingsCtx) -> O, O>(&self, f: F) -> O {
653 let Self(this) = self;
654 let mut locked = this.lock();
655 f(&mut *locked)
656 }
657
658 pub fn timer_ctx(&self) -> impl Deref<Target = FakeTimerCtx<TimerId<Self>>> + '_ {
660 fn get_timers<'a>(
663 i: &'a InnerFakeBindingsCtx,
664 ) -> &'a FakeTimerCtx<TimerId<FakeBindingsCtx>> {
665 &i.timers
666 }
667 Wrapper(self.0.lock(), get_timers, ())
668 }
669
670 pub fn state_mut(&mut self) -> impl DerefMut<Target = FakeBindingsCtxState> + '_ {
672 fn get_state<'a>(i: &'a InnerFakeBindingsCtx) -> &'a FakeBindingsCtxState {
675 &i.state
676 }
677 fn get_state_mut<'a>(i: &'a mut InnerFakeBindingsCtx) -> &'a mut FakeBindingsCtxState {
678 &mut i.state
679 }
680 Wrapper(self.0.lock(), get_state, get_state_mut)
681 }
682
683 pub fn copy_ethernet_frames(
689 &mut self,
690 ) -> Vec<(EthernetWeakDeviceId<FakeBindingsCtx>, Vec<u8>)> {
691 self.with_inner_mut(|ctx| {
692 ctx.frames
693 .frames()
694 .iter()
695 .map(|(meta, frame)| match meta {
696 DispatchedFrame::Ethernet(eth) => (eth.clone(), frame.clone()),
697 DispatchedFrame::PureIp(ip) => panic!("unexpected IP packet {ip:?}: {frame:?}"),
698 })
699 .collect()
700 })
701 }
702
703 pub fn take_ethernet_frames(
709 &mut self,
710 ) -> Vec<(EthernetWeakDeviceId<FakeBindingsCtx>, Vec<u8>)> {
711 self.with_inner_mut(|ctx| {
712 ctx.frames
713 .take_frames()
714 .into_iter()
715 .map(|(meta, frame)| match meta {
716 DispatchedFrame::Ethernet(eth) => (eth, frame),
717 DispatchedFrame::PureIp(ip) => panic!("unexpected IP packet {ip:?}: {frame:?}"),
718 })
719 .collect()
720 })
721 }
722
723 pub fn take_ip_frames(&mut self) -> Vec<(PureIpDeviceAndIpVersion<FakeBindingsCtx>, Vec<u8>)> {
729 self.with_inner_mut(|ctx| {
730 ctx.frames
731 .take_frames()
732 .into_iter()
733 .map(|(meta, frame)| match meta {
734 DispatchedFrame::Ethernet(eth) => {
735 panic!("unexpected Ethernet frame {eth:?}: {frame:?}")
736 }
737 DispatchedFrame::PureIp(ip) => (ip, frame),
738 })
739 .collect()
740 })
741 }
742
743 pub fn take_events(&mut self) -> Vec<DispatchedEvent> {
745 self.with_inner_mut(|ctx| ctx.events.take())
746 }
747
748 pub fn take_icmp_replies<I: IpExt>(
750 &mut self,
751 conn: &IcmpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
752 ) -> Vec<Vec<u8>> {
753 I::map_ip_in(
754 (IpInvariant(self), conn),
755 |(IpInvariant(this), conn)| this.state_mut().icmpv4_replies.remove(conn),
756 |(IpInvariant(this), conn)| this.state_mut().icmpv6_replies.remove(conn),
757 )
758 .unwrap_or_else(Vec::default)
759 }
760
761 pub fn take_udp_received<I: IpExt>(
763 &mut self,
764 conn: &UdpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
765 ) -> Vec<Vec<u8>> {
766 self.state_mut().udp_state_mut::<I>().remove(conn).unwrap_or_else(Vec::default)
767 }
768
769 pub fn seed_rng(&self, seed: u128) {
771 self.with_inner_mut(|ctx| {
772 ctx.rng = FakeCryptoRng::new_xorshift(seed);
773 })
774 }
775
776 pub fn sleep(&self, duration: Duration) {
778 self.with_inner_mut(|ctx| ctx.timers.instant.sleep(duration));
779 }
780}
781
782impl MatcherBindingsTypes for FakeBindingsCtx {
783 type DeviceClass = ();
784 type BindingsPacketMatcher = Never;
785}
786
787impl DeviceBufferBindingsTypes for FakeBindingsCtx {
788 type TxBuffer = packet::Buf<Vec<u8>>;
789 type TxAllocator = netstack3_device::queue::BufVecU8Allocator;
790}
791
792impl SocketOpsFilterBindingContext<DeviceId<FakeBindingsCtx>> for FakeBindingsCtx {
793 fn socket_ops_filter(&self) -> impl SocketOpsFilter<DeviceId<FakeBindingsCtx>> {
794 NoOpSocketOpsFilter
795 }
796}
797
798impl WithFakeTimerContext<TimerId<FakeBindingsCtx>> for FakeBindingsCtx {
799 fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId<FakeBindingsCtx>>) -> O>(
800 &self,
801 f: F,
802 ) -> O {
803 self.with_inner(|ctx| f(&ctx.timers))
804 }
805
806 fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId<FakeBindingsCtx>>) -> O>(
807 &mut self,
808 f: F,
809 ) -> O {
810 self.with_inner_mut(|ctx| f(&mut ctx.timers))
811 }
812}
813
814impl WithFakeFrameContext<DispatchedFrame> for FakeBindingsCtx {
815 fn with_fake_frame_ctx_mut<O, F: FnOnce(&mut FakeFrameCtx<DispatchedFrame>) -> O>(
816 &mut self,
817 f: F,
818 ) -> O {
819 self.with_inner_mut(|ctx| f(&mut ctx.frames))
820 }
821}
822
823impl InstantBindingsTypes for FakeBindingsCtx {
824 type Instant = FakeInstant;
825 type AtomicInstant = FakeAtomicInstant;
826}
827
828impl InstantContext for FakeBindingsCtx {
829 fn now(&self) -> FakeInstant {
830 self.with_inner(|ctx| ctx.now())
831 }
832}
833
834impl TimerBindingsTypes for FakeBindingsCtx {
835 type Timer = <FakeTimerCtx<TimerId<Self>> as TimerBindingsTypes>::Timer;
836 type DispatchId = TimerId<Self>;
837 type UniqueTimerId = <FakeTimerCtx<TimerId<Self>> as TimerBindingsTypes>::UniqueTimerId;
838}
839
840impl TimerContext for FakeBindingsCtx {
841 fn new_timer(&mut self, id: Self::DispatchId) -> Self::Timer {
842 self.with_inner_mut(|ctx| ctx.new_timer(id))
843 }
844
845 fn schedule_timer_instant(
846 &mut self,
847 time: Self::Instant,
848 timer: &mut Self::Timer,
849 ) -> Option<Self::Instant> {
850 match timer.dispatch_id.0 {
854 TimerIdInner::IpLayer(IpLayerTimerId::FilterTimerv4(FilterTimerId::ConntrackGc(_)))
855 | TimerIdInner::IpLayer(IpLayerTimerId::FilterTimerv6(FilterTimerId::ConntrackGc(_))) =>
856 {
857 return None;
858 }
859 _ => {}
860 }
861 self.with_inner_mut(|ctx| ctx.schedule_timer_instant(time, timer))
862 }
863
864 fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
865 self.with_inner_mut(|ctx| ctx.cancel_timer(timer))
866 }
867
868 fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
869 self.with_inner_mut(|ctx| ctx.scheduled_instant(timer))
870 }
871
872 fn unique_timer_id(&self, timer: &Self::Timer) -> Self::UniqueTimerId {
873 self.with_inner_mut(|ctx| ctx.unique_timer_id(timer))
874 }
875}
876
877impl TxMetadataBindingsTypes for FakeBindingsCtx {
878 type TxMetadata = CoreTxMetadata<Self>;
879}
880
881impl RngContext for FakeBindingsCtx {
882 type Rng<'a> = FakeCryptoRng;
883
884 fn rng(&mut self) -> Self::Rng<'_> {
885 let Self(this) = self;
886 this.lock().rng()
887 }
888}
889
890impl<T: Into<DispatchedEvent>> EventContext<T> for FakeBindingsCtx {
891 fn on_event(&mut self, event: T) {
892 self.with_inner_mut(|ctx| ctx.events.on_event(event.into()))
893 }
894}
895
896impl TcpBindingsTypes for FakeBindingsCtx {
897 type ReceiveBuffer = Arc<Mutex<RingBuffer>>;
898
899 type SendBuffer = TestSendBuffer;
900
901 type ReturnedBuffers = ClientBuffers;
902
903 type ListenerNotifierOrProvidedBuffers = ProvidedBuffers;
904
905 fn new_passive_open_buffers(
906 buffer_sizes: BufferSizes,
907 ) -> (Self::ReceiveBuffer, Self::SendBuffer, Self::ReturnedBuffers) {
908 let client = ClientBuffers::new(buffer_sizes);
909 (
910 Arc::clone(&client.receive),
911 TestSendBuffer::new(Arc::clone(&client.send), RingBuffer::default()),
912 client,
913 )
914 }
915}
916
917impl IpRoutingBindingsTypes for FakeBindingsCtx {
918 type RoutingTableId = ();
919}
920
921impl MarksBindingsContext for FakeBindingsCtx {
922 fn marks_to_keep_on_egress() -> &'static [MarkDomain] {
923 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark1];
924 &MARKS
925 }
926
927 fn marks_to_set_on_ingress() -> &'static [MarkDomain] {
928 const MARKS: [MarkDomain; 1] = [MarkDomain::Mark2];
929 &MARKS
930 }
931}
932
933#[cfg(not(loom))]
934mod fake_notifiers {
935 use core::convert::Infallible as Never;
936
937 use super::*;
938
939 impl ReferenceNotifiers for FakeBindingsCtx {
940 type ReferenceReceiver<T: 'static> = Never;
941
942 type ReferenceNotifier<T: Send + 'static> = Never;
943
944 fn new_reference_notifier<T: Send + 'static>(
945 debug_references: DynDebugReferences,
946 ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
947 panic!(
951 "FakeBindingsCtx can't create deferred reference notifiers for type {}: \
952 debug_references={debug_references:?}",
953 core::any::type_name::<T>()
954 );
955 }
956 }
957
958 impl DeferredResourceRemovalContext for FakeBindingsCtx {
959 fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
960 match receiver {}
961 }
962 }
963}
964
965#[cfg(loom)]
968mod loom_notifiers {
969 use super::*;
970
971 use core::sync::atomic::{self, AtomicBool};
972 use netstack3_sync::rc::Notifier;
973
974 #[derive(Debug)]
975 pub struct LoomNotifier(Arc<AtomicBool>);
976
977 #[derive(Debug)]
978 pub struct LoomReceiver {
979 pub debug_refs: DynDebugReferences,
980 pub signal: Arc<AtomicBool>,
981 }
982
983 impl LoomReceiver {
984 #[track_caller]
985 pub fn assert_signalled(&self) {
986 let Self { debug_refs, signal } = self;
987 assert!(signal.load(atomic::Ordering::SeqCst), "pending references: {debug_refs:?}")
988 }
989 }
990
991 impl<T> Notifier<T> for LoomNotifier {
992 fn notify(&mut self, _data: T) {
993 let Self(signal) = self;
994 signal.store(true, atomic::Ordering::SeqCst);
995 }
996 }
997
998 impl ReferenceNotifiers for FakeBindingsCtx {
999 type ReferenceReceiver<T: 'static> = LoomReceiver;
1000 type ReferenceNotifier<T: Send + 'static> = LoomNotifier;
1001
1002 fn new_reference_notifier<T: Send + 'static>(
1003 debug_refs: DynDebugReferences,
1004 ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
1005 let signal = Arc::new(AtomicBool::default());
1006 (LoomNotifier(Arc::clone(&signal)), LoomReceiver { debug_refs, signal })
1007 }
1008 }
1009
1010 impl DeferredResourceRemovalContext for FakeBindingsCtx {
1011 fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
1012 self.state_mut().deferred_receivers.push(receiver);
1013 }
1014 }
1015}
1016
1017#[derive(Debug)]
1019pub struct NoOpLinkResolutionNotifier;
1020
1021impl<D: LinkDevice> LinkResolutionContext<D> for FakeBindingsCtx {
1022 type Notifier = NoOpLinkResolutionNotifier;
1023}
1024
1025impl<D: LinkDevice> LinkResolutionNotifier<D> for NoOpLinkResolutionNotifier {
1026 type Observer = ();
1027
1028 fn new() -> (Self, Self::Observer) {
1029 (NoOpLinkResolutionNotifier, ())
1030 }
1031
1032 fn notify(self, _result: Result<D::Address, AddressResolutionFailed>) {}
1033}
1034
1035#[derive(Clone)]
1036struct DeviceConfig {
1037 mac: UnicastAddr<Mac>,
1038 addr_subnet: Option<AddrSubnetEither>,
1039 ipv4_config: Option<Ipv4DeviceConfigurationUpdate>,
1040 ipv6_config: Option<Ipv6DeviceConfigurationUpdate>,
1041}
1042
1043#[derive(Clone, Default)]
1050pub struct FakeCtxBuilder {
1051 devices: Vec<DeviceConfig>,
1052 arp_table_entries: Vec<(usize, SpecifiedAddr<Ipv4Addr>, UnicastAddr<Mac>)>,
1054 ndp_table_entries: Vec<(usize, UnicastAddr<Ipv6Addr>, UnicastAddr<Mac>)>,
1055 device_routes: Vec<(SubnetEither, usize)>,
1057}
1058
1059impl FakeCtxBuilder {
1060 pub fn with_addrs<A: IpAddress>(addrs: TestAddrs<A>) -> FakeCtxBuilder {
1062 assert!(addrs.subnet.contains(&addrs.local_ip));
1063 assert!(addrs.subnet.contains(&addrs.remote_ip));
1064
1065 let mut builder = FakeCtxBuilder::default();
1066 builder.devices.push(DeviceConfig {
1067 mac: addrs.local_mac,
1068 addr_subnet: Some(
1069 AddrSubnetEither::new(addrs.local_ip.get().into(), addrs.subnet.prefix()).unwrap(),
1070 ),
1071 ipv4_config: None,
1072 ipv6_config: None,
1073 });
1074
1075 match addrs.remote_ip.into() {
1076 IpAddr::V4(ip) => builder.arp_table_entries.push((0, ip, addrs.remote_mac)),
1077 IpAddr::V6(ip) => builder.ndp_table_entries.push((
1078 0,
1079 UnicastAddr::new(ip.get()).unwrap(),
1080 addrs.remote_mac,
1081 )),
1082 };
1083
1084 builder.ndp_table_entries.push((
1087 0,
1088 addrs.remote_mac.to_ipv6_link_local().addr().get(),
1089 addrs.remote_mac,
1090 ));
1091
1092 builder.device_routes.push((addrs.subnet.into(), 0));
1093 builder
1094 }
1095
1096 pub fn add_device(&mut self, mac: UnicastAddr<Mac>) -> usize {
1101 let idx = self.devices.len();
1102 self.devices.push(DeviceConfig {
1103 mac,
1104 addr_subnet: None,
1105 ipv4_config: None,
1106 ipv6_config: None,
1107 });
1108 idx
1109 }
1110
1111 pub fn add_device_with_config(
1116 &mut self,
1117 mac: UnicastAddr<Mac>,
1118 ipv4_config: Ipv4DeviceConfigurationUpdate,
1119 ipv6_config: Ipv6DeviceConfigurationUpdate,
1120 ) -> usize {
1121 let idx = self.devices.len();
1122 self.devices.push(DeviceConfig {
1123 mac,
1124 addr_subnet: None,
1125 ipv4_config: Some(ipv4_config),
1126 ipv6_config: Some(ipv6_config),
1127 });
1128 idx
1129 }
1130
1131 pub fn add_device_with_ip<A: IpAddress>(
1136 &mut self,
1137 mac: UnicastAddr<Mac>,
1138 ip: A,
1139 subnet: Subnet<A>,
1140 ) -> usize {
1141 assert!(subnet.contains(&ip));
1142 let idx = self.devices.len();
1143 self.devices.push(DeviceConfig {
1144 mac,
1145 addr_subnet: Some(AddrSubnetEither::new(ip.into(), subnet.prefix()).unwrap()),
1146 ipv4_config: None,
1147 ipv6_config: None,
1148 });
1149 self.device_routes.push((subnet.into(), idx));
1150 idx
1151 }
1152
1153 pub fn add_device_with_ip_and_config<A: IpAddress>(
1161 &mut self,
1162 mac: UnicastAddr<Mac>,
1163 ip: A,
1164 subnet: Subnet<A>,
1165 ipv4_config: Ipv4DeviceConfigurationUpdate,
1166 ipv6_config: Ipv6DeviceConfigurationUpdate,
1167 ) -> usize {
1168 assert!(subnet.contains(&ip));
1169 let idx = self.devices.len();
1170 self.devices.push(DeviceConfig {
1171 mac,
1172 addr_subnet: Some(AddrSubnetEither::new(ip.into(), subnet.prefix()).unwrap()),
1173 ipv4_config: Some(ipv4_config),
1174 ipv6_config: Some(ipv6_config),
1175 });
1176 self.device_routes.push((subnet.into(), idx));
1177 idx
1178 }
1179
1180 pub fn add_arp_table_entry(
1182 &mut self,
1183 device: usize,
1184 ip: SpecifiedAddr<Ipv4Addr>,
1186 mac: UnicastAddr<Mac>,
1187 ) {
1188 self.arp_table_entries.push((device, ip, mac));
1189 }
1190
1191 pub fn add_ndp_table_entry(
1193 &mut self,
1194 device: usize,
1195 ip: UnicastAddr<Ipv6Addr>,
1197 mac: UnicastAddr<Mac>,
1198 ) {
1199 self.ndp_table_entries.push((device, ip, mac));
1200 }
1201
1202 pub fn add_arp_or_ndp_table_entry<A: IpAddress>(
1205 &mut self,
1206 device: usize,
1207 ip: SpecifiedAddr<A>,
1209 mac: UnicastAddr<Mac>,
1210 ) {
1211 match ip.into() {
1212 IpAddr::V4(ip) => self.add_arp_table_entry(device, ip, mac),
1213 IpAddr::V6(ip) => {
1214 self.add_ndp_table_entry(device, UnicastAddr::new(ip.get()).unwrap(), mac)
1215 }
1216 }
1217 }
1218
1219 pub fn build(self) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1221 self.build_with_modifications(|_| {})
1222 }
1223
1224 pub fn build_with_modifications<F: FnOnce(&mut StackStateBuilder)>(
1228 self,
1229 f: F,
1230 ) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1231 let mut stack_builder = StackStateBuilder::default();
1232 f(&mut stack_builder);
1233 self.build_with(stack_builder)
1234 }
1235
1236 pub fn build_with(
1239 self,
1240 state_builder: StackStateBuilder,
1241 ) -> (FakeCtx, Vec<EthernetDeviceId<FakeBindingsCtx>>) {
1242 let mut ctx = Ctx::new_with_builder(state_builder);
1243
1244 let FakeCtxBuilder { devices, arp_table_entries, ndp_table_entries, device_routes } = self;
1245 let idx_to_device_id: Vec<_> = devices
1246 .into_iter()
1247 .map(|DeviceConfig { mac, addr_subnet: ip_and_subnet, ipv4_config, ipv6_config }| {
1248 let eth_id =
1249 ctx.core_api().device::<EthernetLinkDevice>().add_device_with_default_state(
1250 EthernetCreationProperties {
1251 mac: mac,
1252 max_frame_size: IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
1253 tx_offload_spec: Default::default(),
1254 },
1255 DEFAULT_INTERFACE_METRIC,
1256 );
1257 let id = eth_id.clone().into();
1258 if let Some(ipv4_config) = ipv4_config {
1259 let _previous = ctx
1260 .core_api()
1261 .device_ip::<Ipv4>()
1262 .update_configuration(&id, ipv4_config)
1263 .unwrap();
1264 }
1265 if let Some(ipv6_config) = ipv6_config {
1266 let _previous = ctx
1267 .core_api()
1268 .device_ip::<Ipv6>()
1269 .update_configuration(&id, ipv6_config)
1270 .unwrap();
1271 }
1272 ctx.test_api().enable_device(&id);
1273 match ip_and_subnet {
1274 Some(addr_sub) => {
1275 ctx.core_api().device_ip_any().add_ip_addr_subnet(&id, addr_sub).unwrap();
1276 }
1277 None => {}
1278 }
1279 eth_id
1280 })
1281 .collect();
1282 for (idx, ip, mac) in arp_table_entries {
1283 let device = &idx_to_device_id[idx];
1284 ctx.core_api()
1285 .neighbor::<Ipv4, EthernetLinkDevice>()
1286 .insert_static_entry(&device, ip.get(), mac.get())
1287 .expect("error inserting static ARP entry");
1288 }
1289 for (idx, ip, mac) in ndp_table_entries {
1290 let device = &idx_to_device_id[idx];
1291 ctx.core_api()
1292 .neighbor::<Ipv6, EthernetLinkDevice>()
1293 .insert_static_entry(&device, ip.get(), mac.get())
1294 .expect("error inserting static NDP entry");
1295 }
1296
1297 for (subnet, idx) in device_routes {
1298 let device = &idx_to_device_id[idx];
1299 ctx.test_api()
1300 .add_route(AddableEntryEither::without_gateway(
1301 subnet,
1302 device.clone().into(),
1303 AddableMetric::ExplicitMetric(RawMetric(0)),
1304 ))
1305 .expect("add device route");
1306 }
1307
1308 (ctx, idx_to_device_id)
1309 }
1310}
1311
1312pub enum FakeCtxNetworkSpec {}
1316
1317impl FakeNetworkSpec for FakeCtxNetworkSpec {
1318 type Context = FakeCtx;
1319 type TimerId = TimerId<FakeBindingsCtx>;
1320 type SendMeta = DispatchedFrame;
1321 type RecvMeta = EthernetDeviceId<FakeBindingsCtx>;
1322 fn handle_frame(ctx: &mut FakeCtx, device_id: Self::RecvMeta, data: Buf<Vec<u8>>) {
1323 ctx.core_api().device::<EthernetLinkDevice>().receive_frame(
1324 RecvEthernetFrameMeta { device_id, parsing_context: NetworkParsingContext::default() },
1325 data,
1326 )
1327 }
1328 fn handle_timer(ctx: &mut FakeCtx, dispatch: Self::TimerId, timer: FakeTimerId) {
1329 ctx.core_api().handle_timer(dispatch, timer)
1330 }
1331 fn process_queues(ctx: &mut FakeCtx) -> bool {
1332 ctx.test_api().handle_queued_rx_packets()
1333 }
1334 fn fake_frames(ctx: &mut FakeCtx) -> &mut impl WithFakeFrameContext<Self::SendMeta> {
1335 &mut ctx.bindings_ctx
1336 }
1337}
1338
1339impl<I: IpExt> UdpReceiveBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1340 fn receive_udp(
1341 &mut self,
1342 id: &UdpSocketId<I, WeakDeviceId<Self>, FakeBindingsCtx>,
1343 _device_id: &DeviceId<Self>,
1344 _meta: UdpPacketMeta<I>,
1345 body: &[u8],
1346 ) -> Result<(), ReceiveUdpError> {
1347 let mut state = self.state_mut();
1348 let received =
1349 (&mut *state).udp_state_mut::<I>().entry(id.clone()).or_insert_with(Vec::default);
1350 received.push(body.to_owned());
1351 Ok(())
1352 }
1353
1354 fn on_socket_error(
1355 &mut self,
1356 _id: &UdpSocketId<I, WeakDeviceId<Self>, FakeBindingsCtx>,
1357 _err: PendingDatagramSocketError,
1358 ) {
1359 }
1360}
1361
1362impl UdpBindingsTypes for FakeBindingsCtx {
1363 type ExternalData<I: Ip> = ();
1364 type SocketWritableListener = FakeSocketWritableListener;
1365}
1366
1367impl<I: IpExt> IcmpEchoBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1368 fn receive_icmp_echo_reply<B: BufferMut>(
1369 &mut self,
1370 conn: &IcmpSocketId<I, WeakDeviceId<FakeBindingsCtx>, FakeBindingsCtx>,
1371 _device: &DeviceId<Self>,
1372 _src_ip: I::Addr,
1373 _dst_ip: I::Addr,
1374 _id: u16,
1375 data: B,
1376 ) -> Result<(), ReceiveIcmpEchoError> {
1377 I::map_ip_in(
1378 (IpInvariant(self.state_mut()), conn.clone()),
1379 |(IpInvariant(mut state), conn)| {
1380 let replies = state.icmpv4_replies.entry(conn).or_insert_with(Vec::default);
1381 replies.push(data.as_ref().to_owned());
1382 },
1383 |(IpInvariant(mut state), conn)| {
1384 let replies = state.icmpv6_replies.entry(conn).or_insert_with(Vec::default);
1385 replies.push(data.as_ref().to_owned());
1386 },
1387 );
1388 Ok(())
1389 }
1390}
1391
1392impl IcmpEchoBindingsTypes for FakeBindingsCtx {
1393 type ExternalData<I: Ip> = ();
1394 type SocketWritableListener = FakeSocketWritableListener;
1395}
1396
1397impl DeviceSocketTypes for FakeBindingsCtx {
1398 type SocketState<D: Send + Sync + Debug> = Mutex<Vec<(WeakDeviceId<FakeBindingsCtx>, Vec<u8>)>>;
1399}
1400
1401impl RawIpSocketsBindingsTypes for FakeBindingsCtx {
1402 type RawIpSocketState<I: Ip> = ();
1403}
1404
1405impl DeviceSocketBindingsContext<DeviceId<Self>> for FakeBindingsCtx {
1406 fn receive_frame(
1407 &self,
1408 socket_id: &SocketId<Self>,
1409 device: &DeviceId<Self>,
1410 _frame: device::socket::Frame<&[u8]>,
1411 raw_frame: &[u8],
1412 ) -> Result<(), ReceiveFrameError> {
1413 let state = socket_id.socket_state();
1414 state.lock().push((device.downgrade(), raw_frame.into()));
1415 Ok(())
1416 }
1417}
1418
1419impl<I: IpExt> RawIpSocketsBindingsContext<I, DeviceId<Self>> for FakeBindingsCtx {
1420 fn receive_packet<B: SplitByteSlice>(
1421 &self,
1422 _socket: &RawIpSocketId<I, WeakDeviceId<Self>, Self>,
1423 _packet: &I::Packet<B>,
1424 _device: &DeviceId<Self>,
1425 ) -> Result<(), ReceivePacketError> {
1426 unimplemented!()
1427 }
1428}
1429
1430impl DeviceLayerStateTypes for FakeBindingsCtx {
1431 type LoopbackDeviceState = ();
1432 type EthernetDeviceState = ();
1433 type BlackholeDeviceState = ();
1434 type PureIpDeviceState = ();
1435 type DeviceIdentifier = MonotonicIdentifier;
1436}
1437
1438impl ReceiveQueueBindingsContext<LoopbackDeviceId<Self>> for FakeBindingsCtx {
1439 fn wake_rx_task(&mut self, device: &LoopbackDeviceId<FakeBindingsCtx>) {
1440 self.state_mut().rx_available.push(device.clone());
1441 }
1442}
1443
1444impl<D: Clone + Into<DeviceId<Self>>> TransmitQueueBindingsContext<D> for FakeBindingsCtx {
1445 fn wake_tx_task(&mut self, device: &D) {
1446 self.state_mut().tx_available.push(device.clone().into());
1447 }
1448}
1449
1450impl DeviceLayerEventDispatcher for FakeBindingsCtx {
1451 type DequeueContext = ();
1452
1453 fn send_ethernet_frame(
1454 &mut self,
1455 device: &EthernetDeviceId<FakeBindingsCtx>,
1456 frame: Buf<Vec<u8>>,
1457 _dequeue_context: Option<&mut Self::DequeueContext>,
1458 ) -> Result<(), DeviceSendFrameError> {
1459 let frame_meta = DispatchedFrame::Ethernet(device.downgrade());
1460 self.with_inner_mut(|ctx| ctx.frames.push(frame_meta, frame.into_inner()));
1461 Ok(())
1462 }
1463
1464 fn send_ip_packet(
1465 &mut self,
1466 device: &PureIpDeviceId<FakeBindingsCtx>,
1467 packet: Buf<Vec<u8>>,
1468 ip_version: IpVersion,
1469 _dequeue_context: Option<&mut Self::DequeueContext>,
1470 ) -> Result<(), DeviceSendFrameError> {
1471 let frame_meta = DispatchedFrame::PureIp(PureIpDeviceAndIpVersion {
1472 device: device.downgrade(),
1473 version: ip_version,
1474 });
1475 self.with_inner_mut(|ctx| ctx.frames.push(frame_meta, packet.into_inner()));
1476 Ok(())
1477 }
1478}
1479
1480impl AlwaysDefaultsSettingsContext for FakeBindingsCtx {}
1481
1482#[derive(Debug, Eq, PartialEq, Hash, GenericOverIp)]
1484#[generic_over_ip()]
1485#[allow(missing_docs)]
1486pub enum DispatchedEvent {
1487 IpDeviceIpv4(IpDeviceEvent<WeakDeviceId<FakeBindingsCtx>, Ipv4, FakeInstant>),
1488 IpDeviceIpv6(IpDeviceEvent<WeakDeviceId<FakeBindingsCtx>, Ipv6, FakeInstant>),
1489 IpLayerIpv4(IpLayerEvent<WeakDeviceId<FakeBindingsCtx>, Ipv4>),
1490 IpLayerIpv6(IpLayerEvent<WeakDeviceId<FakeBindingsCtx>, Ipv6>),
1491 NeighborIpv4(nud::Event<Mac, EthernetWeakDeviceId<FakeBindingsCtx>, Ipv4, FakeInstant>),
1492 NeighborIpv6(nud::Event<Mac, EthernetWeakDeviceId<FakeBindingsCtx>, Ipv6, FakeInstant>),
1493 RouterAdvertisement(RouterAdvertisementEvent<WeakDeviceId<FakeBindingsCtx>>),
1494 EthernetDevice(EthernetDeviceEvent<EthernetWeakDeviceId<FakeBindingsCtx>>),
1495}
1496
1497#[derive(Derivative)]
1499#[derivative(Debug(bound = ""))]
1500#[allow(missing_docs)]
1501pub struct PureIpDeviceAndIpVersion<BT: DeviceLayerTypes> {
1502 pub device: PureIpWeakDeviceId<BT>,
1503 pub version: IpVersion,
1504}
1505
1506#[derive(Debug)]
1508pub enum DispatchedFrame {
1509 Ethernet(EthernetWeakDeviceId<FakeBindingsCtx>),
1511 PureIp(PureIpDeviceAndIpVersion<FakeBindingsCtx>),
1513}
1514
1515impl<I: Ip> From<IpDeviceEvent<DeviceId<FakeBindingsCtx>, I, FakeInstant>> for DispatchedEvent {
1516 fn from(e: IpDeviceEvent<DeviceId<FakeBindingsCtx>, I, FakeInstant>) -> DispatchedEvent {
1517 let e = e.map_device(|d| d.downgrade());
1518 I::map_ip(e, |e| DispatchedEvent::IpDeviceIpv4(e), |e| DispatchedEvent::IpDeviceIpv6(e))
1519 }
1520}
1521
1522impl<I: IpExt> From<IpLayerEvent<DeviceId<FakeBindingsCtx>, I>> for DispatchedEvent {
1523 fn from(e: IpLayerEvent<DeviceId<FakeBindingsCtx>, I>) -> DispatchedEvent {
1524 let e = e.map_device(|d| d.downgrade());
1525 I::map_ip(e, |e| DispatchedEvent::IpLayerIpv4(e), |e| DispatchedEvent::IpLayerIpv6(e))
1526 }
1527}
1528
1529impl<I: Ip> From<nud::Event<Mac, EthernetDeviceId<FakeBindingsCtx>, I, FakeInstant>>
1530 for DispatchedEvent
1531{
1532 fn from(
1533 e: nud::Event<Mac, EthernetDeviceId<FakeBindingsCtx>, I, FakeInstant>,
1534 ) -> DispatchedEvent {
1535 let e = e.map_device(|d| d.downgrade());
1536 I::map_ip(e, |e| DispatchedEvent::NeighborIpv4(e), |e| DispatchedEvent::NeighborIpv6(e))
1537 }
1538}
1539
1540impl From<EthernetDeviceEvent<EthernetDeviceId<FakeBindingsCtx>>> for DispatchedEvent {
1541 fn from(e: EthernetDeviceEvent<EthernetDeviceId<FakeBindingsCtx>>) -> DispatchedEvent {
1542 let e = e.map_device(|d| d.downgrade());
1543 DispatchedEvent::EthernetDevice(e)
1544 }
1545}
1546
1547impl From<RouterAdvertisementEvent<DeviceId<FakeBindingsCtx>>> for DispatchedEvent {
1548 fn from(e: RouterAdvertisementEvent<DeviceId<FakeBindingsCtx>>) -> DispatchedEvent {
1549 let e = e.map_device(|d| d.downgrade());
1550 DispatchedEvent::RouterAdvertisement(e)
1551 }
1552}
1553
1554pub fn new_simple_fake_network<CtxId: Copy + Debug + Hash + Eq>(
1560 a_id: CtxId,
1561 a: FakeCtx,
1562 a_device_id: EthernetWeakDeviceId<FakeBindingsCtx>,
1563 b_id: CtxId,
1564 b: FakeCtx,
1565 b_device_id: EthernetWeakDeviceId<FakeBindingsCtx>,
1566) -> FakeNetwork<
1567 FakeCtxNetworkSpec,
1568 CtxId,
1569 impl FakeNetworkLinks<DispatchedFrame, EthernetDeviceId<FakeBindingsCtx>, CtxId>,
1570> {
1571 let contexts = vec![(a_id, a), (b_id, b)].into_iter();
1572 FakeNetwork::new(contexts, move |net, _frame: DispatchedFrame| {
1573 if net == a_id {
1574 b_device_id
1575 .upgrade()
1576 .map(|device_id| (b_id, device_id, None))
1577 .into_iter()
1578 .collect::<Vec<_>>()
1579 } else {
1580 a_device_id
1581 .upgrade()
1582 .map(|device_id| (a_id, device_id, None))
1583 .into_iter()
1584 .collect::<Vec<_>>()
1585 }
1586 })
1587}