1use alloc::collections::hash_map::DefaultHasher;
8use alloc::vec::Vec;
9use core::borrow::Borrow;
10use core::convert::Infallible as Never;
11use core::fmt::Debug;
12use core::hash::{Hash, Hasher};
13use core::marker::PhantomData;
14use core::num::{NonZeroU16, NonZeroU8, NonZeroUsize};
15use core::ops::RangeInclusive;
16
17use derivative::Derivative;
18use either::Either;
19use lock_order::lock::{DelegatedOrderedLockAccess, OrderedLockAccess, OrderedLockRef};
20use log::{debug, trace};
21use net_types::ip::{GenericOverIp, Ip, IpInvariant, IpVersion, IpVersionMarker, Ipv4, Ipv6};
22use net_types::{MulticastAddr, SpecifiedAddr, Witness, ZonedAddr};
23use netstack3_base::socket::{
24 AddrEntry, AddrIsMappedError, AddrVec, Bound, ConnAddr, ConnInfoAddr, ConnIpAddr, FoundSockets,
25 IncompatibleError, InsertError, Inserter, ListenerAddr, ListenerAddrInfo, ListenerIpAddr,
26 MaybeDualStack, NotDualStackCapableError, RemoveResult, SetDualStackEnabledError, ShutdownType,
27 SocketAddrType, SocketIpAddr, SocketMapAddrSpec, SocketMapAddrStateSpec,
28 SocketMapConflictPolicy, SocketMapStateSpec, SocketWritableListener,
29};
30use netstack3_base::socketmap::{IterShadows as _, SocketMap, Tagged};
31use netstack3_base::sync::{RwLock, StrongRc};
32use netstack3_base::{
33 AnyDevice, BidirectionalConverter, ContextPair, CoreTxMetadataContext, CounterContext,
34 DeviceIdContext, Inspector, InspectorDeviceExt, InstantContext, LocalAddressError, Mark,
35 MarkDomain, PortAllocImpl, ReferenceNotifiers, RemoveResourceResultWithContext,
36 ResourceCounterContext as _, RngContext, SocketError, StrongDeviceIdentifier,
37 WeakDeviceIdentifier, ZonedAddressError,
38};
39use netstack3_datagram::{
40 self as datagram, BoundSocketState as DatagramBoundSocketState,
41 BoundSocketStateType as DatagramBoundSocketStateType, BoundSockets as DatagramBoundSockets,
42 ConnectError, DatagramApi, DatagramBindingsTypes, DatagramBoundStateContext, DatagramFlowId,
43 DatagramIpSpecificSocketOptions, DatagramSocketMapSpec, DatagramSocketSet, DatagramSocketSpec,
44 DatagramSpecBoundStateContext, DatagramSpecStateContext, DatagramStateContext,
45 DualStackConnState, DualStackConverter, DualStackDatagramBoundStateContext,
46 DualStackDatagramSpecBoundStateContext, DualStackIpExt, EitherIpSocket, ExpectedConnError,
47 ExpectedUnboundError, InUseError, IpExt, IpOptions, MulticastMembershipInterfaceSelector,
48 NonDualStackConverter, NonDualStackDatagramBoundStateContext,
49 NonDualStackDatagramSpecBoundStateContext, SendError as DatagramSendError,
50 SetMulticastMembershipError, SocketInfo, SocketState as DatagramSocketState,
51 WrapOtherStackIpOptions, WrapOtherStackIpOptionsMut,
52};
53use netstack3_ip::socket::{
54 IpSockCreateAndSendError, IpSockCreationError, IpSockSendError, SocketHopLimits,
55};
56use netstack3_ip::{
57 HopLimits, IpHeaderInfo, IpTransportContext, LocalDeliveryPacketInfo,
58 MulticastMembershipHandler, ReceiveIpPacketMeta, TransparentLocalDelivery, TransportIpContext,
59 TransportReceiveError,
60};
61use netstack3_trace::trace_duration;
62use packet::{BufferMut, Nested, ParsablePacket, Serializer};
63use packet_formats::ip::{DscpAndEcn, IpProto, IpProtoExt};
64use packet_formats::udp::{UdpPacket, UdpPacketBuilder, UdpParseArgs};
65use thiserror::Error;
66
67use crate::internal::counters::{
68 CombinedUdpCounters, UdpCounterContext, UdpCountersWithSocket, UdpCountersWithoutSocket,
69};
70
71pub(crate) type UdpBoundSocketMap<I, D, BT> =
73 DatagramBoundSockets<I, D, UdpAddrSpec, UdpSocketMapStateSpec<I, D, BT>>;
74pub type UdpSocketTxMetadata<I, D, BT> = datagram::TxMetadata<I, D, Udp<BT>>;
76
77#[derive(Derivative, GenericOverIp)]
79#[generic_over_ip(I, Ip)]
80#[derivative(Default(bound = ""))]
81pub struct BoundSockets<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
82 bound_sockets: UdpBoundSocketMap<I, D, BT>,
83}
84
85#[derive(Derivative)]
87#[derivative(Default(bound = ""))]
88pub struct Sockets<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
89 bound: RwLock<BoundSockets<I, D, BT>>,
90 all_sockets: RwLock<UdpSocketSet<I, D, BT>>,
93}
94
95impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>
96 OrderedLockAccess<BoundSockets<I, D, BT>> for Sockets<I, D, BT>
97{
98 type Lock = RwLock<BoundSockets<I, D, BT>>;
99 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
100 OrderedLockRef::new(&self.bound)
101 }
102}
103
104impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>
105 OrderedLockAccess<UdpSocketSet<I, D, BT>> for Sockets<I, D, BT>
106{
107 type Lock = RwLock<UdpSocketSet<I, D, BT>>;
108 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
109 OrderedLockRef::new(&self.all_sockets)
110 }
111}
112
113#[derive(Derivative, GenericOverIp)]
117#[generic_over_ip(I, Ip)]
118#[derivative(Default(bound = ""))]
119pub struct UdpState<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
120 pub sockets: Sockets<I, D, BT>,
122 pub counters_with_socket: UdpCountersWithSocket<I>,
124 pub counters_without_socket: UdpCountersWithoutSocket<I>,
126}
127
128pub struct Udp<BT>(PhantomData<BT>, Never);
130
131#[cfg(test)]
133fn iter_receiving_addrs<I: IpExt, D: WeakDeviceIdentifier>(
134 addr: ConnIpAddr<I::Addr, NonZeroU16, UdpRemotePort>,
135 device: D,
136) -> impl Iterator<Item = AddrVec<I, D, UdpAddrSpec>> {
137 netstack3_base::socket::AddrVecIter::with_device(addr.into(), device)
138}
139
140fn check_posix_sharing<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
141 new_sharing: Sharing,
142 dest: AddrVec<I, D, UdpAddrSpec>,
143 socketmap: &SocketMap<AddrVec<I, D, UdpAddrSpec>, Bound<UdpSocketMapStateSpec<I, D, BT>>>,
144) -> Result<(), InsertError> {
145 if dest.iter_shadows().any(|a| {
148 socketmap.get(&a).is_some_and(|bound| {
149 !bound.tag(&a).to_sharing_options().is_shareable_with_new_state(new_sharing)
150 })
151 }) {
152 return Err(InsertError::ShadowAddrExists);
153 }
154
155 match &dest {
158 AddrVec::Conn(ConnAddr { ip: _, device: None }) | AddrVec::Listen(_) => {
159 if socketmap.descendant_counts(&dest).any(|(tag, _): &(_, NonZeroUsize)| {
160 !tag.to_sharing_options().is_shareable_with_new_state(new_sharing)
161 }) {
162 return Err(InsertError::ShadowerExists);
163 }
164 }
165 AddrVec::Conn(ConnAddr { ip: _, device: Some(_) }) => {
166 debug_assert_eq!(socketmap.descendant_counts(&dest).len(), 0)
169 }
170 }
171
172 fn conflict_exists<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
184 new_sharing: Sharing,
185 socketmap: &SocketMap<AddrVec<I, D, UdpAddrSpec>, Bound<UdpSocketMapStateSpec<I, D, BT>>>,
186 addr: impl Into<AddrVec<I, D, UdpAddrSpec>>,
187 mut is_conflicting: impl FnMut(&AddrVecTag) -> bool,
188 ) -> bool {
189 socketmap.descendant_counts(&addr.into()).any(|(tag, _): &(_, NonZeroUsize)| {
190 is_conflicting(tag)
191 && !tag.to_sharing_options().is_shareable_with_new_state(new_sharing)
192 })
193 }
194
195 let found_indirect_conflict = match dest {
196 AddrVec::Listen(ListenerAddr {
197 ip: ListenerIpAddr { addr: None, identifier },
198 device: Some(_device),
199 }) => {
200 conflict_exists(
206 new_sharing,
207 socketmap,
208 ListenerAddr { ip: ListenerIpAddr { addr: None, identifier }, device: None },
209 |AddrVecTag { has_device, addr_type, sharing: _ }| {
210 !*has_device
211 && match addr_type {
212 SocketAddrType::SpecificListener | SocketAddrType::Connected => true,
213 SocketAddrType::AnyListener => false,
214 }
215 },
216 )
217 }
218 AddrVec::Listen(ListenerAddr {
219 ip: ListenerIpAddr { addr: Some(ip), identifier },
220 device: Some(_device),
221 }) => {
222 conflict_exists(
228 new_sharing,
229 socketmap,
230 ListenerAddr { ip: ListenerIpAddr { addr: Some(ip), identifier }, device: None },
231 |AddrVecTag { has_device, addr_type, sharing: _ }| {
232 !*has_device
233 && match addr_type {
234 SocketAddrType::Connected => true,
235 SocketAddrType::AnyListener | SocketAddrType::SpecificListener => false,
236 }
237 },
238 )
239 }
240 AddrVec::Listen(ListenerAddr {
241 ip: ListenerIpAddr { addr: Some(_), identifier },
242 device: None,
243 }) => {
244 conflict_exists(
251 new_sharing,
252 socketmap,
253 ListenerAddr { ip: ListenerIpAddr { addr: None, identifier }, device: None },
254 |AddrVecTag { has_device, addr_type, sharing: _ }| {
255 *has_device
256 && match addr_type {
257 SocketAddrType::AnyListener => true,
258 SocketAddrType::SpecificListener | SocketAddrType::Connected => false,
259 }
260 },
261 )
262 }
263 AddrVec::Conn(ConnAddr {
264 ip: ConnIpAddr { local: (local_ip, local_identifier), remote: _ },
265 device: None,
266 }) => {
267 conflict_exists(
275 new_sharing,
276 socketmap,
277 ListenerAddr {
278 ip: ListenerIpAddr {
279 addr: Some(local_ip),
280 identifier: local_identifier.clone(),
281 },
282 device: None,
283 },
284 |AddrVecTag { has_device, addr_type, sharing: _ }| {
285 *has_device
286 && match addr_type {
287 SocketAddrType::SpecificListener => true,
288 SocketAddrType::AnyListener | SocketAddrType::Connected => false,
289 }
290 },
291 ) ||
292 conflict_exists(
305 new_sharing,
306 socketmap,
307 ListenerAddr {
308 ip: ListenerIpAddr { addr: None, identifier: local_identifier },
309 device: None,
310 },
311 |AddrVecTag { has_device, addr_type, sharing: _ }| {
312 *has_device
313 && match addr_type {
314 SocketAddrType::AnyListener => true,
315 SocketAddrType::SpecificListener | SocketAddrType::Connected => false,
316 }
317 },
318 )
319 }
320 AddrVec::Listen(ListenerAddr {
321 ip: ListenerIpAddr { addr: None, identifier: _ },
322 device: _,
323 }) => false,
324 AddrVec::Conn(ConnAddr { ip: _, device: Some(_device) }) => false,
325 };
326 if found_indirect_conflict {
327 Err(InsertError::IndirectConflict)
328 } else {
329 Ok(())
330 }
331}
332
333#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
335pub enum UdpRemotePort {
336 Set(NonZeroU16),
338 Unset,
374}
375
376impl From<NonZeroU16> for UdpRemotePort {
377 fn from(p: NonZeroU16) -> Self {
378 Self::Set(p)
379 }
380}
381
382impl From<u16> for UdpRemotePort {
383 fn from(p: u16) -> Self {
384 NonZeroU16::new(p).map(UdpRemotePort::from).unwrap_or(UdpRemotePort::Unset)
385 }
386}
387
388impl From<UdpRemotePort> for u16 {
389 fn from(p: UdpRemotePort) -> Self {
390 match p {
391 UdpRemotePort::Unset => 0,
392 UdpRemotePort::Set(p) => p.into(),
393 }
394 }
395}
396
397pub enum UdpAddrSpec {}
399
400impl SocketMapAddrSpec for UdpAddrSpec {
401 type RemoteIdentifier = UdpRemotePort;
402 type LocalIdentifier = NonZeroU16;
403}
404
405pub struct UdpSocketMapStateSpec<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
406 PhantomData<(I, D, BT)>,
407 Never,
408);
409
410impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> SocketMapStateSpec
411 for UdpSocketMapStateSpec<I, D, BT>
412{
413 type ListenerId = I::DualStackBoundSocketId<D, Udp<BT>>;
414 type ConnId = I::DualStackBoundSocketId<D, Udp<BT>>;
415
416 type AddrVecTag = AddrVecTag;
417
418 type ListenerSharingState = Sharing;
419 type ConnSharingState = Sharing;
420
421 type ListenerAddrState = AddrState<Self::ListenerId>;
422
423 type ConnAddrState = AddrState<Self::ConnId>;
424 fn listener_tag(
425 ListenerAddrInfo { has_device, specified_addr }: ListenerAddrInfo,
426 state: &Self::ListenerAddrState,
427 ) -> Self::AddrVecTag {
428 AddrVecTag {
429 has_device,
430 addr_type: specified_addr
431 .then_some(SocketAddrType::SpecificListener)
432 .unwrap_or(SocketAddrType::AnyListener),
433 sharing: state.to_sharing_options(),
434 }
435 }
436 fn connected_tag(has_device: bool, state: &Self::ConnAddrState) -> Self::AddrVecTag {
437 AddrVecTag {
438 has_device,
439 addr_type: SocketAddrType::Connected,
440 sharing: state.to_sharing_options(),
441 }
442 }
443}
444
445impl<AA, I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>
446 SocketMapConflictPolicy<AA, Sharing, I, D, UdpAddrSpec> for UdpSocketMapStateSpec<I, D, BT>
447where
448 AA: Into<AddrVec<I, D, UdpAddrSpec>> + Clone,
449{
450 fn check_insert_conflicts(
451 new_sharing_state: &Sharing,
452 addr: &AA,
453 socketmap: &SocketMap<AddrVec<I, D, UdpAddrSpec>, Bound<Self>>,
454 ) -> Result<(), InsertError> {
455 check_posix_sharing(*new_sharing_state, addr.clone().into(), socketmap)
456 }
457}
458
459#[derive(Clone, Derivative)]
461#[derivative(Default(bound = ""), Debug(bound = ""))]
462pub struct DualStackSocketState<D: WeakDeviceIdentifier> {
463 #[derivative(Default(value = "true"))]
466 dual_stack_enabled: bool,
467
468 socket_options: DatagramIpSpecificSocketOptions<Ipv4, D>,
470}
471
472pub enum UdpSerializeError {
474 RemotePortUnset,
477}
478
479impl<BT: UdpBindingsTypes> DatagramSocketSpec for Udp<BT> {
480 const NAME: &'static str = "UDP";
481 type AddrSpec = UdpAddrSpec;
482 type SocketId<I: IpExt, D: WeakDeviceIdentifier> = UdpSocketId<I, D, BT>;
483 type WeakSocketId<I: IpExt, D: WeakDeviceIdentifier> = WeakUdpSocketId<I, D, BT>;
484 type OtherStackIpOptions<I: IpExt, D: WeakDeviceIdentifier> =
485 I::OtherStackIpOptions<DualStackSocketState<D>>;
486 type ListenerIpAddr<I: IpExt> = I::DualStackListenerIpAddr<NonZeroU16>;
487 type ConnIpAddr<I: IpExt> = I::DualStackConnIpAddr<Self>;
488 type ConnStateExtra = ();
489 type ConnState<I: IpExt, D: WeakDeviceIdentifier> = I::DualStackConnState<D, Self>;
490 type SocketMapSpec<I: IpExt, D: WeakDeviceIdentifier> = UdpSocketMapStateSpec<I, D, BT>;
491 type SharingState = Sharing;
492
493 type Serializer<I: IpExt, B: BufferMut> = Nested<B, UdpPacketBuilder<I::Addr>>;
494 type SerializeError = UdpSerializeError;
495
496 type ExternalData<I: Ip> = BT::ExternalData<I>;
497 type Counters<I: Ip> = UdpCountersWithSocket<I>;
498 type SocketWritableListener = BT::SocketWritableListener;
499
500 fn ip_proto<I: IpProtoExt>() -> I::Proto {
501 IpProto::Udp.into()
502 }
503
504 fn make_bound_socket_map_id<I: IpExt, D: WeakDeviceIdentifier>(
505 s: &Self::SocketId<I, D>,
506 ) -> I::DualStackBoundSocketId<D, Udp<BT>> {
507 I::into_dual_stack_bound_socket_id(s.clone())
508 }
509
510 const FIXED_HEADER_SIZE: usize = packet_formats::udp::HEADER_BYTES;
511
512 fn make_packet<I: IpExt, B: BufferMut>(
513 body: B,
514 addr: &ConnIpAddr<I::Addr, NonZeroU16, UdpRemotePort>,
515 ) -> Result<Self::Serializer<I, B>, UdpSerializeError> {
516 let ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) } = addr;
517 let remote_port = match remote_port {
518 UdpRemotePort::Unset => return Err(UdpSerializeError::RemotePortUnset),
519 UdpRemotePort::Set(remote_port) => *remote_port,
520 };
521 Ok(body.encapsulate(UdpPacketBuilder::new(
522 local_ip.addr(),
523 remote_ip.addr(),
524 Some(*local_port),
525 remote_port,
526 )))
527 }
528
529 fn try_alloc_listen_identifier<I: IpExt, D: WeakDeviceIdentifier>(
530 rng: &mut impl RngContext,
531 is_available: impl Fn(NonZeroU16) -> Result<(), InUseError>,
532 ) -> Option<NonZeroU16> {
533 try_alloc_listen_port::<I, D, BT>(rng, is_available)
534 }
535
536 fn conn_info_from_state<I: IpExt, D: WeakDeviceIdentifier>(
537 state: &Self::ConnState<I, D>,
538 ) -> datagram::ConnInfo<I::Addr, D> {
539 let ConnAddr { ip, device } = I::conn_addr_from_state(state);
540 let ConnInfoAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) } =
541 ip.into();
542 datagram::ConnInfo::new(local_ip, local_port, remote_ip, remote_port.into(), || {
543 device.clone().expect("device must be bound for addresses that require zones")
545 })
546 }
547
548 fn try_alloc_local_id<I: IpExt, D: WeakDeviceIdentifier, BC: RngContext>(
549 bound: &UdpBoundSocketMap<I, D, BT>,
550 bindings_ctx: &mut BC,
551 flow: datagram::DatagramFlowId<I::Addr, UdpRemotePort>,
552 ) -> Option<NonZeroU16> {
553 let mut rng = bindings_ctx.rng();
554 netstack3_base::simple_randomized_port_alloc(&mut rng, &flow, &UdpPortAlloc(bound), &())
555 .map(|p| NonZeroU16::new(p).expect("ephemeral ports should be non-zero"))
556 }
557
558 fn upgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
559 id: &Self::WeakSocketId<I, D>,
560 ) -> Option<Self::SocketId<I, D>> {
561 id.upgrade()
562 }
563
564 fn downgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
565 id: &Self::SocketId<I, D>,
566 ) -> Self::WeakSocketId<I, D> {
567 UdpSocketId::downgrade(id)
568 }
569}
570
571impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>
572 DatagramSocketMapSpec<I, D, UdpAddrSpec> for UdpSocketMapStateSpec<I, D, BT>
573{
574 type BoundSocketId = I::DualStackBoundSocketId<D, Udp<BT>>;
575}
576
577enum LookupResult<'a, I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
578 Conn(
579 &'a I::DualStackBoundSocketId<D, Udp<BT>>,
580 ConnAddr<ConnIpAddr<I::Addr, NonZeroU16, UdpRemotePort>, D>,
581 ),
582 Listener(
583 &'a I::DualStackBoundSocketId<D, Udp<BT>>,
584 ListenerAddr<ListenerIpAddr<I::Addr, NonZeroU16>, D>,
585 ),
586}
587
588#[derive(Hash, Copy, Clone)]
589struct SocketSelectorParams<I: Ip, A: AsRef<I::Addr>> {
590 src_ip: I::Addr,
591 dst_ip: A,
592 src_port: u16,
593 dst_port: u16,
594 _ip: IpVersionMarker<I>,
595}
596
597#[derive(Debug, Eq, PartialEq)]
598pub struct LoadBalancedEntry<T> {
599 id: T,
600 reuse_addr: bool,
601}
602
603#[derive(Debug, Eq, PartialEq)]
604pub enum AddrState<T> {
605 Exclusive(T),
606 Shared {
607 priority: Vec<T>,
610
611 load_balanced: Vec<LoadBalancedEntry<T>>,
615 },
616}
617
618#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, Default)]
619pub struct Sharing {
620 reuse_addr: bool,
621 reuse_port: bool,
622}
623
624impl Sharing {
625 pub(crate) fn is_shareable_with_new_state(&self, new_state: Sharing) -> bool {
626 let Sharing { reuse_addr, reuse_port } = self;
627 let Sharing { reuse_addr: new_reuse_addr, reuse_port: new_reuse_port } = new_state;
628 (*reuse_addr && new_reuse_addr) || (*reuse_port && new_reuse_port)
629 }
630}
631
632#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
633pub struct AddrVecTag {
634 pub(crate) has_device: bool,
635 pub(crate) addr_type: SocketAddrType,
636 pub(crate) sharing: Sharing,
637}
638
639pub(crate) trait ToSharingOptions {
640 fn to_sharing_options(&self) -> Sharing;
641}
642
643impl ToSharingOptions for AddrVecTag {
644 fn to_sharing_options(&self) -> Sharing {
645 let AddrVecTag { has_device: _, addr_type: _, sharing } = self;
646 *sharing
647 }
648}
649
650impl<T> ToSharingOptions for AddrState<T> {
651 fn to_sharing_options(&self) -> Sharing {
652 match self {
653 AddrState::Exclusive(_) => Sharing { reuse_addr: false, reuse_port: false },
654 AddrState::Shared { priority, load_balanced } => {
655 let reuse_addr = load_balanced.iter().all(|e| e.reuse_addr);
658
659 let reuse_port = priority.is_empty();
662
663 Sharing { reuse_addr, reuse_port }
664 }
665 }
666 }
667}
668
669impl<T> ToSharingOptions for (T, Sharing) {
670 fn to_sharing_options(&self) -> Sharing {
671 let (_state, sharing) = self;
672 *sharing
673 }
674}
675
676pub struct SocketMapAddrInserter<'a, I> {
677 state: &'a mut AddrState<I>,
678 sharing_state: Sharing,
679}
680
681impl<'a, I> Inserter<I> for SocketMapAddrInserter<'a, I> {
682 fn insert(self, id: I) {
683 match self {
684 Self { state: _, sharing_state: Sharing { reuse_addr: false, reuse_port: false } }
685 | Self { state: AddrState::Exclusive(_), sharing_state: _ } => {
686 panic!("Can't insert entry in a non-shareable entry")
687 }
688
689 Self {
691 state: AddrState::Shared { priority, load_balanced: _ },
692 sharing_state: Sharing { reuse_addr: true, reuse_port: false },
693 } => priority.push(id),
694
695 Self {
697 state: AddrState::Shared { priority: _, load_balanced },
698 sharing_state: Sharing { reuse_addr, reuse_port: true },
699 } => load_balanced.push(LoadBalancedEntry { id, reuse_addr }),
700 }
701 }
702}
703
704impl<I: Debug + Eq> SocketMapAddrStateSpec for AddrState<I> {
705 type Id = I;
706 type SharingState = Sharing;
707 type Inserter<'a>
708 = SocketMapAddrInserter<'a, I>
709 where
710 I: 'a;
711
712 fn new(new_sharing_state: &Sharing, id: I) -> Self {
713 match new_sharing_state {
714 Sharing { reuse_addr: false, reuse_port: false } => Self::Exclusive(id),
715 Sharing { reuse_addr: true, reuse_port: false } => {
716 Self::Shared { priority: Vec::from([id]), load_balanced: Vec::new() }
717 }
718 Sharing { reuse_addr, reuse_port: true } => Self::Shared {
719 priority: Vec::new(),
720 load_balanced: Vec::from([LoadBalancedEntry { id, reuse_addr: *reuse_addr }]),
721 },
722 }
723 }
724
725 fn contains_id(&self, id: &Self::Id) -> bool {
726 match self {
727 Self::Exclusive(x) => id == x,
728 Self::Shared { priority, load_balanced } => {
729 priority.contains(id) || load_balanced.iter().any(|e| e.id == *id)
730 }
731 }
732 }
733
734 fn try_get_inserter<'a, 'b>(
735 &'b mut self,
736 new_sharing_state: &'a Sharing,
737 ) -> Result<SocketMapAddrInserter<'b, I>, IncompatibleError> {
738 self.could_insert(new_sharing_state)?;
739 Ok(SocketMapAddrInserter { state: self, sharing_state: *new_sharing_state })
740 }
741
742 fn could_insert(&self, new_sharing_state: &Sharing) -> Result<(), IncompatibleError> {
743 self.to_sharing_options()
744 .is_shareable_with_new_state(*new_sharing_state)
745 .then_some(())
746 .ok_or(IncompatibleError)
747 }
748
749 fn remove_by_id(&mut self, id: I) -> RemoveResult {
750 match self {
751 Self::Exclusive(_) => RemoveResult::IsLast,
752 Self::Shared { ref mut priority, ref mut load_balanced } => {
753 if let Some(pos) = priority.iter().position(|i| *i == id) {
754 let _removed: I = priority.remove(pos);
755 } else {
756 let pos = load_balanced
757 .iter()
758 .position(|e| e.id == id)
759 .expect("couldn't find ID to remove");
760 let _removed: LoadBalancedEntry<I> = load_balanced.remove(pos);
761 }
762 if priority.is_empty() && load_balanced.is_empty() {
763 RemoveResult::IsLast
764 } else {
765 RemoveResult::Success
766 }
767 }
768 }
769 }
770}
771
772impl<T> AddrState<T> {
773 fn select_receiver<I: Ip, A: AsRef<I::Addr> + Hash>(
774 &self,
775 selector: SocketSelectorParams<I, A>,
776 ) -> &T {
777 match self {
778 AddrState::Exclusive(id) => id,
779 AddrState::Shared { priority, load_balanced } => {
780 if let Some(id) = priority.last() {
781 id
782 } else {
783 let mut hasher = DefaultHasher::new();
784 selector.hash(&mut hasher);
785 let index: usize = hasher.finish() as usize % load_balanced.len();
786 &load_balanced[index].id
787 }
788 }
789 }
790 }
791
792 fn collect_all_ids(&self) -> impl Iterator<Item = &'_ T> {
793 match self {
794 AddrState::Exclusive(id) => Either::Left(core::iter::once(id)),
795 AddrState::Shared { priority, load_balanced } => {
796 Either::Right(priority.iter().chain(load_balanced.iter().map(|i| &i.id)))
797 }
798 }
799 }
800}
801
802fn lookup<'s, I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
808 bound: &'s DatagramBoundSockets<I, D, UdpAddrSpec, UdpSocketMapStateSpec<I, D, BT>>,
809 (src_ip, src_port): (Option<SocketIpAddr<I::Addr>>, Option<NonZeroU16>),
810 (dst_ip, dst_port): (SocketIpAddr<I::Addr>, NonZeroU16),
811 device: D,
812 broadcast: Option<I::BroadcastMarker>,
813) -> impl Iterator<Item = LookupResult<'s, I, D, BT>> + 's {
814 let matching_entries = bound.iter_receivers(
815 (src_ip, src_port.map(UdpRemotePort::from)),
816 (dst_ip, dst_port),
817 device,
818 broadcast,
819 );
820 match matching_entries {
821 None => Either::Left(None),
822 Some(FoundSockets::Single(entry)) => {
823 let selector = SocketSelectorParams::<I, SpecifiedAddr<I::Addr>> {
824 src_ip: src_ip.map_or(I::UNSPECIFIED_ADDRESS, SocketIpAddr::addr),
825 dst_ip: dst_ip.into(),
826 src_port: src_port.map_or(0, NonZeroU16::get),
827 dst_port: dst_port.get(),
828 _ip: IpVersionMarker::default(),
829 };
830 Either::Left(Some(match entry {
831 AddrEntry::Listen(state, l) => {
832 LookupResult::Listener(state.select_receiver(selector), l)
833 }
834 AddrEntry::Conn(state, c) => LookupResult::Conn(state.select_receiver(selector), c),
835 }))
836 }
837
838 Some(FoundSockets::Multicast(entries)) => {
839 Either::Right(entries.into_iter().flat_map(|entry| match entry {
840 AddrEntry::Listen(state, l) => Either::Left(
841 state.collect_all_ids().map(move |id| LookupResult::Listener(id, l.clone())),
842 ),
843 AddrEntry::Conn(state, c) => Either::Right(
844 state.collect_all_ids().map(move |id| LookupResult::Conn(id, c.clone())),
845 ),
846 }))
847 }
848 }
849 .into_iter()
850}
851
852fn try_alloc_listen_port<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
856 bindings_ctx: &mut impl RngContext,
857 is_available: impl Fn(NonZeroU16) -> Result<(), InUseError>,
858) -> Option<NonZeroU16> {
859 let mut port = UdpPortAlloc::<I, D, BT>::rand_ephemeral(&mut bindings_ctx.rng());
860 for _ in UdpPortAlloc::<I, D, BT>::EPHEMERAL_RANGE {
861 let tryport = NonZeroU16::new(port.get()).unwrap();
864 match is_available(tryport) {
865 Ok(()) => return Some(tryport),
866 Err(InUseError {}) => port.next(),
867 }
868 }
869 None
870}
871
872struct UdpPortAlloc<'a, I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
873 &'a UdpBoundSocketMap<I, D, BT>,
874);
875
876impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> PortAllocImpl
877 for UdpPortAlloc<'_, I, D, BT>
878{
879 const EPHEMERAL_RANGE: RangeInclusive<u16> = 49152..=65535;
880 type Id = DatagramFlowId<I::Addr, UdpRemotePort>;
881 type PortAvailableArg = ();
882
883 fn is_port_available(&self, id: &Self::Id, local_port: u16, (): &()) -> bool {
884 let Self(socketmap) = self;
885 let local_port = NonZeroU16::new(local_port).unwrap();
888 let DatagramFlowId { local_ip, remote_ip, remote_id } = id;
889 let conn = ConnAddr {
890 ip: ConnIpAddr { local: (*local_ip, local_port), remote: (*remote_ip, *remote_id) },
891 device: None,
892 };
893
894 AddrVec::from(conn).iter_shadows().all(|a| match &a {
897 AddrVec::Listen(l) => socketmap.listeners().get_by_addr(&l).is_none(),
898 AddrVec::Conn(c) => socketmap.conns().get_by_addr(&c).is_none(),
899 } && socketmap.get_shadower_counts(&a) == 0)
900 }
901}
902
903#[derive(GenericOverIp, Derivative)]
905#[derivative(Eq(bound = ""), PartialEq(bound = ""), Hash(bound = ""))]
906#[generic_over_ip(I, Ip)]
907pub struct UdpSocketId<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
908 datagram::StrongRc<I, D, Udp<BT>>,
909);
910
911impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> Clone for UdpSocketId<I, D, BT> {
912 #[cfg_attr(feature = "instrumented", track_caller)]
913 fn clone(&self) -> Self {
914 let Self(rc) = self;
915 Self(StrongRc::clone(rc))
916 }
917}
918
919impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>
920 From<datagram::StrongRc<I, D, Udp<BT>>> for UdpSocketId<I, D, BT>
921{
922 fn from(value: datagram::StrongRc<I, D, Udp<BT>>) -> Self {
923 Self(value)
924 }
925}
926
927impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>
928 Borrow<datagram::StrongRc<I, D, Udp<BT>>> for UdpSocketId<I, D, BT>
929{
930 fn borrow(&self) -> &datagram::StrongRc<I, D, Udp<BT>> {
931 let Self(rc) = self;
932 rc
933 }
934}
935
936impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> PartialEq<WeakUdpSocketId<I, D, BT>>
937 for UdpSocketId<I, D, BT>
938{
939 fn eq(&self, other: &WeakUdpSocketId<I, D, BT>) -> bool {
940 let Self(rc) = self;
941 let WeakUdpSocketId(weak) = other;
942 StrongRc::weak_ptr_eq(rc, weak)
943 }
944}
945
946impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> Debug for UdpSocketId<I, D, BT> {
947 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
948 let Self(rc) = self;
949 f.debug_tuple("UdpSocketId").field(&StrongRc::debug_id(rc)).finish()
950 }
951}
952
953impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>
954 DelegatedOrderedLockAccess<UdpSocketState<I, D, BT>> for UdpSocketId<I, D, BT>
955{
956 type Inner = datagram::ReferenceState<I, D, Udp<BT>>;
957 fn delegate_ordered_lock_access(&self) -> &Self::Inner {
958 let Self(rc) = self;
959 &*rc
960 }
961}
962
963impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> UdpSocketId<I, D, BT> {
964 #[cfg(any(test, feature = "testutils"))]
967 pub fn state(&self) -> &RwLock<UdpSocketState<I, D, BT>> {
968 let Self(rc) = self;
969 rc.state()
970 }
971
972 pub fn debug_references(&self) -> impl Debug {
974 let Self(rc) = self;
975 StrongRc::debug_references(rc)
976 }
977
978 pub fn downgrade(&self) -> WeakUdpSocketId<I, D, BT> {
980 let Self(rc) = self;
981 WeakUdpSocketId(StrongRc::downgrade(rc))
982 }
983
984 pub fn external_data(&self) -> &BT::ExternalData<I> {
986 let Self(rc) = self;
987 rc.external_data()
988 }
989
990 pub fn counters(&self) -> &UdpCountersWithSocket<I> {
992 let Self(rc) = self;
993 rc.counters()
994 }
995}
996
997#[derive(GenericOverIp, Derivative)]
999#[derivative(Eq(bound = ""), PartialEq(bound = ""), Hash(bound = ""), Clone(bound = ""))]
1000#[generic_over_ip(I, Ip)]
1001pub struct WeakUdpSocketId<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
1002 datagram::WeakRc<I, D, Udp<BT>>,
1003);
1004
1005impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> PartialEq<UdpSocketId<I, D, BT>>
1006 for WeakUdpSocketId<I, D, BT>
1007{
1008 fn eq(&self, other: &UdpSocketId<I, D, BT>) -> bool {
1009 PartialEq::eq(other, self)
1010 }
1011}
1012
1013impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> Debug for WeakUdpSocketId<I, D, BT> {
1014 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1015 let Self(rc) = self;
1016 f.debug_tuple("WeakUdpSocketId").field(&rc.debug_id()).finish()
1017 }
1018}
1019
1020impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> WeakUdpSocketId<I, D, BT> {
1021 #[cfg_attr(feature = "instrumented", track_caller)]
1022 pub fn upgrade(&self) -> Option<UdpSocketId<I, D, BT>> {
1023 let Self(rc) = self;
1024 rc.upgrade().map(UdpSocketId)
1025 }
1026}
1027
1028pub type UdpSocketSet<I, D, BT> = DatagramSocketSet<I, D, Udp<BT>>;
1030pub type UdpSocketState<I, D, BT> = DatagramSocketState<I, D, Udp<BT>>;
1032
1033#[derive(Debug, GenericOverIp, Clone, PartialEq, Eq)]
1035#[generic_over_ip(I, Ip)]
1036pub struct UdpPacketMeta<I: Ip> {
1037 pub src_ip: I::Addr,
1039
1040 pub src_port: Option<NonZeroU16>,
1042
1043 pub dst_ip: I::Addr,
1045
1046 pub dst_port: NonZeroU16,
1048
1049 pub dscp_and_ecn: DscpAndEcn,
1051}
1052
1053impl UdpPacketMeta<Ipv4> {
1054 fn to_ipv6_mapped(&self) -> UdpPacketMeta<Ipv6> {
1055 let Self { dst_ip, dst_port, src_ip, src_port, dscp_and_ecn } = self;
1056 UdpPacketMeta {
1057 dst_ip: dst_ip.to_ipv6_mapped().get(),
1058 dst_port: *dst_port,
1059 src_ip: src_ip.to_ipv6_mapped().get(),
1060 src_port: *src_port,
1061 dscp_and_ecn: *dscp_and_ecn,
1062 }
1063 }
1064}
1065
1066pub trait UdpReceiveBindingsContext<I: IpExt, D: StrongDeviceIdentifier>: UdpBindingsTypes {
1068 fn receive_udp<B: BufferMut>(
1070 &mut self,
1071 id: &UdpSocketId<I, D::Weak, Self>,
1072 device_id: &D,
1073 meta: UdpPacketMeta<I>,
1074 body: &B,
1075 );
1076}
1077
1078pub trait UdpBindingsTypes: DatagramBindingsTypes + Sized + 'static {
1091 type ExternalData<I: Ip>: Debug + Send + Sync + 'static;
1093 type SocketWritableListener: SocketWritableListener + Debug + Send + Sync + 'static;
1095}
1096
1097pub trait UdpBindingsContext<I: IpExt, D: StrongDeviceIdentifier>:
1099 InstantContext
1100 + RngContext
1101 + UdpReceiveBindingsContext<I, D>
1102 + ReferenceNotifiers
1103 + UdpBindingsTypes
1104{
1105}
1106impl<
1107 I: IpExt,
1108 BC: InstantContext
1109 + RngContext
1110 + UdpReceiveBindingsContext<I, D>
1111 + ReferenceNotifiers
1112 + UdpBindingsTypes,
1113 D: StrongDeviceIdentifier,
1114 > UdpBindingsContext<I, D> for BC
1115{
1116}
1117
1118pub trait BoundStateContext<I: IpExt, BC: UdpBindingsContext<I, Self::DeviceId>>:
1120 DeviceIdContext<AnyDevice> + UdpStateContext
1121{
1122 type IpSocketsCtx<'a>: TransportIpContext<I, BC>
1124 + MulticastMembershipHandler<I, BC>
1125 + CoreTxMetadataContext<UdpSocketTxMetadata<I, Self::WeakDeviceId, BC>, BC>
1126 + DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
1127
1128 type DualStackContext: DualStackDatagramBoundStateContext<
1130 I,
1131 BC,
1132 Udp<BC>,
1133 DeviceId = Self::DeviceId,
1134 WeakDeviceId = Self::WeakDeviceId,
1135 >;
1136 type NonDualStackContext: NonDualStackDatagramBoundStateContext<
1138 I,
1139 BC,
1140 Udp<BC>,
1141 DeviceId = Self::DeviceId,
1142 WeakDeviceId = Self::WeakDeviceId,
1143 >;
1144
1145 fn with_bound_sockets<
1147 O,
1148 F: FnOnce(&mut Self::IpSocketsCtx<'_>, &BoundSockets<I, Self::WeakDeviceId, BC>) -> O,
1149 >(
1150 &mut self,
1151 cb: F,
1152 ) -> O;
1153
1154 fn with_bound_sockets_mut<
1156 O,
1157 F: FnOnce(&mut Self::IpSocketsCtx<'_>, &mut BoundSockets<I, Self::WeakDeviceId, BC>) -> O,
1158 >(
1159 &mut self,
1160 cb: F,
1161 ) -> O;
1162
1163 fn dual_stack_context(
1165 &mut self,
1166 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext>;
1167
1168 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
1170 &mut self,
1171 cb: F,
1172 ) -> O;
1173}
1174
1175pub trait StateContext<I: IpExt, BC: UdpBindingsContext<I, Self::DeviceId>>:
1177 DeviceIdContext<AnyDevice>
1178{
1179 type SocketStateCtx<'a>: BoundStateContext<I, BC>
1181 + DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
1182 + UdpStateContext;
1183
1184 fn with_all_sockets_mut<O, F: FnOnce(&mut UdpSocketSet<I, Self::WeakDeviceId, BC>) -> O>(
1187 &mut self,
1188 cb: F,
1189 ) -> O;
1190
1191 fn with_all_sockets<O, F: FnOnce(&UdpSocketSet<I, Self::WeakDeviceId, BC>) -> O>(
1194 &mut self,
1195 cb: F,
1196 ) -> O;
1197
1198 fn with_bound_state_context<O, F: FnOnce(&mut Self::SocketStateCtx<'_>) -> O>(
1200 &mut self,
1201 cb: F,
1202 ) -> O;
1203
1204 fn with_socket_state<
1207 O,
1208 F: FnOnce(&mut Self::SocketStateCtx<'_>, &UdpSocketState<I, Self::WeakDeviceId, BC>) -> O,
1209 >(
1210 &mut self,
1211 id: &UdpSocketId<I, Self::WeakDeviceId, BC>,
1212 cb: F,
1213 ) -> O;
1214
1215 fn with_socket_state_mut<
1217 O,
1218 F: FnOnce(&mut Self::SocketStateCtx<'_>, &mut UdpSocketState<I, Self::WeakDeviceId, BC>) -> O,
1219 >(
1220 &mut self,
1221 id: &UdpSocketId<I, Self::WeakDeviceId, BC>,
1222 cb: F,
1223 ) -> O;
1224
1225 fn for_each_socket<
1227 F: FnMut(
1228 &mut Self::SocketStateCtx<'_>,
1229 &UdpSocketId<I, Self::WeakDeviceId, BC>,
1230 &UdpSocketState<I, Self::WeakDeviceId, BC>,
1231 ),
1232 >(
1233 &mut self,
1234 cb: F,
1235 );
1236}
1237
1238pub trait UdpStateContext {}
1246
1247pub trait DualStackBoundStateContext<I: IpExt, BC: UdpBindingsContext<I, Self::DeviceId>>:
1249 DeviceIdContext<AnyDevice>
1250{
1251 type IpSocketsCtx<'a>: TransportIpContext<I, BC>
1253 + DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
1254 + CoreTxMetadataContext<UdpSocketTxMetadata<I, Self::WeakDeviceId, BC>, BC>
1255 + TransportIpContext<I::OtherVersion, BC>
1257 + CoreTxMetadataContext<UdpSocketTxMetadata<I::OtherVersion, Self::WeakDeviceId, BC>, BC>;
1258
1259 fn with_both_bound_sockets_mut<
1262 O,
1263 F: FnOnce(
1264 &mut Self::IpSocketsCtx<'_>,
1265 &mut BoundSockets<I, Self::WeakDeviceId, BC>,
1266 &mut BoundSockets<I::OtherVersion, Self::WeakDeviceId, BC>,
1267 ) -> O,
1268 >(
1269 &mut self,
1270 cb: F,
1271 ) -> O;
1272
1273 fn with_other_bound_sockets_mut<
1276 O,
1277 F: FnOnce(
1278 &mut Self::IpSocketsCtx<'_>,
1279 &mut BoundSockets<I::OtherVersion, Self::WeakDeviceId, BC>,
1280 ) -> O,
1281 >(
1282 &mut self,
1283 cb: F,
1284 ) -> O;
1285
1286 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
1288 &mut self,
1289 cb: F,
1290 ) -> O;
1291}
1292
1293pub trait NonDualStackBoundStateContext<I: IpExt, BC: UdpBindingsContext<I, Self::DeviceId>>:
1295 DeviceIdContext<AnyDevice>
1296{
1297}
1298
1299pub enum UdpIpTransportContext {}
1301
1302fn receive_ip_packet<
1303 I: IpExt,
1304 B: BufferMut,
1305 H: IpHeaderInfo<I>,
1306 BC: UdpBindingsContext<I, CC::DeviceId> + UdpBindingsContext<I::OtherVersion, CC::DeviceId>,
1307 CC: StateContext<I, BC>
1308 + StateContext<I::OtherVersion, BC>
1309 + UdpCounterContext<I, CC::WeakDeviceId, BC>
1310 + UdpCounterContext<I::OtherVersion, CC::WeakDeviceId, BC>,
1311>(
1312 core_ctx: &mut CC,
1313 bindings_ctx: &mut BC,
1314 device: &CC::DeviceId,
1315 src_ip: I::RecvSrcAddr,
1316 dst_ip: SpecifiedAddr<I::Addr>,
1317 mut buffer: B,
1318 info: &LocalDeliveryPacketInfo<I, H>,
1319) -> Result<(), (B, TransportReceiveError)> {
1320 let LocalDeliveryPacketInfo { meta, header_info, marks: _ } = info;
1321 let ReceiveIpPacketMeta { broadcast, transparent_override } = meta;
1322
1323 trace_duration!(c"udp::receive_ip_packet");
1324 CounterContext::<UdpCountersWithoutSocket<I>>::counters(core_ctx).rx.increment();
1325 trace!("received UDP packet: {:x?}", buffer.as_mut());
1326 let src_ip: I::Addr = src_ip.into_addr();
1327
1328 let packet = if let Ok(packet) =
1329 buffer.parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(src_ip, dst_ip.get()))
1330 {
1331 packet
1332 } else {
1333 CounterContext::<UdpCountersWithoutSocket<I>>::counters(core_ctx).rx_malformed.increment();
1336 return Ok(());
1337 };
1338
1339 let src_ip = if let Some(src_ip) = SpecifiedAddr::new(src_ip) {
1340 match src_ip.try_into() {
1341 Ok(addr) => Some(addr),
1342 Err(AddrIsMappedError {}) => {
1343 CounterContext::<UdpCountersWithoutSocket<I>>::counters(core_ctx)
1344 .rx_mapped_addr
1345 .increment();
1346 trace!("udp::receive_ip_packet: mapped source address");
1347 return Ok(());
1348 }
1349 }
1350 } else {
1351 None
1352 };
1353
1354 let dst_port = packet.dst_port();
1355 let (delivery_ip, delivery_port, require_transparent) = match transparent_override {
1356 Some(TransparentLocalDelivery { addr, port }) => (*addr, *port, true),
1357 None => (dst_ip, dst_port, false),
1358 };
1359
1360 let delivery_ip = match delivery_ip.try_into() {
1361 Ok(addr) => addr,
1362 Err(AddrIsMappedError {}) => {
1363 CounterContext::<UdpCountersWithoutSocket<I>>::counters(core_ctx)
1364 .rx_mapped_addr
1365 .increment();
1366 trace!("udp::receive_ip_packet: mapped destination address");
1367 return Ok(());
1368 }
1369 };
1370
1371 let src_port = packet.src_port();
1372 let parse_meta = ParsablePacket::<_, UdpParseArgs<I::Addr>>::parse_metadata(&packet);
1375
1376 const MAX_EXPECTED_IDS: usize = 16;
1380
1381 type Recipients<Id> = smallvec::SmallVec<[Id; MAX_EXPECTED_IDS]>;
1387
1388 let recipients = StateContext::<I, _>::with_bound_state_context(core_ctx, |core_ctx| {
1389 let device_weak = device.downgrade();
1390 DatagramBoundStateContext::<_, _, Udp<_>>::with_bound_sockets(
1391 core_ctx,
1392 |_core_ctx, bound_sockets| {
1393 lookup(
1394 bound_sockets,
1395 (src_ip, src_port),
1396 (delivery_ip, delivery_port),
1397 device_weak,
1398 *broadcast,
1399 )
1400 .map(|result| match result {
1401 LookupResult::Conn(id, _) | LookupResult::Listener(id, _) => id.clone(),
1402 })
1403 .collect::<Recipients<_>>()
1405 },
1406 )
1407 });
1408
1409 let meta = UdpPacketMeta {
1410 src_ip: src_ip.map_or(I::UNSPECIFIED_ADDRESS, SocketIpAddr::addr),
1411 src_port,
1412 dst_ip: *dst_ip,
1413 dst_port,
1414 dscp_and_ecn: header_info.dscp_and_ecn(),
1415 };
1416 let was_delivered = recipients.into_iter().fold(false, |was_delivered, lookup_result| {
1417 let delivered = try_dual_stack_deliver::<I, B, BC, CC>(
1418 core_ctx,
1419 bindings_ctx,
1420 lookup_result,
1421 device,
1422 &meta,
1423 require_transparent,
1424 &buffer,
1425 );
1426 was_delivered | delivered
1427 });
1428
1429 if !was_delivered {
1430 buffer.undo_parse(parse_meta);
1431 CounterContext::<UdpCountersWithoutSocket<I>>::counters(core_ctx)
1432 .rx_unknown_dest_port
1433 .increment();
1434 Err((buffer, TransportReceiveError::PortUnreachable))
1435 } else {
1436 Ok(())
1437 }
1438}
1439
1440fn try_deliver<
1442 I: IpExt,
1443 CC: StateContext<I, BC> + UdpCounterContext<I, CC::WeakDeviceId, BC>,
1444 BC: UdpBindingsContext<I, CC::DeviceId>,
1445 B: BufferMut,
1446>(
1447 core_ctx: &mut CC,
1448 bindings_ctx: &mut BC,
1449 id: &UdpSocketId<I, CC::WeakDeviceId, BC>,
1450 device_id: &CC::DeviceId,
1451 meta: UdpPacketMeta<I>,
1452 require_transparent: bool,
1453 buffer: &B,
1454) -> bool {
1455 let delivered = core_ctx.with_socket_state(&id, |core_ctx, state| {
1456 let should_deliver = match state {
1457 DatagramSocketState::Bound(DatagramBoundSocketState {
1458 socket_type,
1459 original_bound_addr: _,
1460 }) => match socket_type {
1461 DatagramBoundSocketStateType::Connected { state, sharing: _ } => {
1462 match BoundStateContext::dual_stack_context(core_ctx) {
1463 MaybeDualStack::DualStack(dual_stack) => {
1464 match dual_stack.ds_converter().convert(state) {
1465 DualStackConnState::ThisStack(state) => state.should_receive(),
1466 DualStackConnState::OtherStack(state) => state.should_receive(),
1467 }
1468 }
1469 MaybeDualStack::NotDualStack(not_dual_stack) => {
1470 not_dual_stack.nds_converter().convert(state).should_receive()
1471 }
1472 }
1473 }
1474 DatagramBoundSocketStateType::Listener { state: _, sharing: _ } => true,
1475 },
1476 DatagramSocketState::Unbound(_) => true,
1477 };
1478
1479 if should_deliver {
1480 if require_transparent {
1481 let (ip_options, _device) = state.get_options_device(core_ctx);
1482 if !ip_options.transparent() {
1485 return false;
1486 }
1487 }
1488
1489 bindings_ctx.receive_udp(id, device_id, meta, buffer);
1490 }
1491 should_deliver
1492 });
1493
1494 if delivered {
1495 core_ctx.increment_both(id, |c| &c.rx_delivered);
1496 }
1497 delivered
1498}
1499
1500fn try_dual_stack_deliver<
1502 I: IpExt,
1503 B: BufferMut,
1504 BC: UdpBindingsContext<I, CC::DeviceId> + UdpBindingsContext<I::OtherVersion, CC::DeviceId>,
1505 CC: StateContext<I, BC>
1506 + StateContext<I::OtherVersion, BC>
1507 + UdpCounterContext<I, CC::WeakDeviceId, BC>
1508 + UdpCounterContext<I::OtherVersion, CC::WeakDeviceId, BC>,
1509>(
1510 core_ctx: &mut CC,
1511 bindings_ctx: &mut BC,
1512 socket: I::DualStackBoundSocketId<CC::WeakDeviceId, Udp<BC>>,
1513 device_id: &CC::DeviceId,
1514 meta: &UdpPacketMeta<I>,
1515 require_transparent: bool,
1516 buffer: &B,
1517) -> bool {
1518 #[derive(GenericOverIp)]
1519 #[generic_over_ip(I, Ip)]
1520 struct Inputs<'a, I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
1521 meta: &'a UdpPacketMeta<I>,
1522 socket: I::DualStackBoundSocketId<D, Udp<BT>>,
1523 }
1524
1525 struct Outputs<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
1526 meta: UdpPacketMeta<I>,
1527 socket: UdpSocketId<I, D, BT>,
1528 }
1529
1530 #[derive(GenericOverIp)]
1531 #[generic_over_ip(I, Ip)]
1532 enum DualStackOutputs<I: DualStackIpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
1533 CurrentStack(Outputs<I, D, BT>),
1534 OtherStack(Outputs<I::OtherVersion, D, BT>),
1535 }
1536
1537 let dual_stack_outputs = I::map_ip(
1538 Inputs { meta, socket },
1539 |Inputs { meta, socket }| match socket {
1540 EitherIpSocket::V4(socket) => {
1541 DualStackOutputs::CurrentStack(Outputs { meta: meta.clone(), socket })
1542 }
1543 EitherIpSocket::V6(socket) => {
1544 DualStackOutputs::OtherStack(Outputs { meta: meta.to_ipv6_mapped(), socket })
1545 }
1546 },
1547 |Inputs { meta, socket }| {
1548 DualStackOutputs::CurrentStack(Outputs { meta: meta.clone(), socket })
1549 },
1550 );
1551
1552 match dual_stack_outputs {
1553 DualStackOutputs::CurrentStack(Outputs { meta, socket }) => try_deliver(
1554 core_ctx,
1555 bindings_ctx,
1556 &socket,
1557 device_id,
1558 meta,
1559 require_transparent,
1560 buffer,
1561 ),
1562 DualStackOutputs::OtherStack(Outputs { meta, socket }) => try_deliver(
1563 core_ctx,
1564 bindings_ctx,
1565 &socket,
1566 device_id,
1567 meta,
1568 require_transparent,
1569 buffer,
1570 ),
1571 }
1572}
1573
1574pub trait UseUdpIpTransportContextBlanket {}
1583
1584impl<
1585 I: IpExt,
1586 BC: UdpBindingsContext<I, CC::DeviceId> + UdpBindingsContext<I::OtherVersion, CC::DeviceId>,
1587 CC: StateContext<I, BC>
1588 + StateContext<I::OtherVersion, BC>
1589 + UseUdpIpTransportContextBlanket
1590 + UdpCounterContext<I, CC::WeakDeviceId, BC>
1591 + UdpCounterContext<I::OtherVersion, CC::WeakDeviceId, BC>,
1592 > IpTransportContext<I, BC, CC> for UdpIpTransportContext
1593{
1594 fn receive_icmp_error(
1595 core_ctx: &mut CC,
1596 _bindings_ctx: &mut BC,
1597 _device: &CC::DeviceId,
1598 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
1599 original_dst_ip: SpecifiedAddr<I::Addr>,
1600 _original_udp_packet: &[u8],
1601 err: I::ErrorCode,
1602 ) {
1603 CounterContext::<UdpCountersWithoutSocket<I>>::counters(core_ctx).rx_icmp_error.increment();
1604 debug!(
1608 "UDP received ICMP error {:?} from {:?} to {:?}",
1609 err, original_dst_ip, original_src_ip
1610 );
1611 }
1612
1613 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1614 core_ctx: &mut CC,
1615 bindings_ctx: &mut BC,
1616 device: &CC::DeviceId,
1617 src_ip: I::RecvSrcAddr,
1618 dst_ip: SpecifiedAddr<I::Addr>,
1619 buffer: B,
1620 info: &LocalDeliveryPacketInfo<I, H>,
1621 ) -> Result<(), (B, TransportReceiveError)> {
1622 receive_ip_packet::<I, _, _, _, _>(
1623 core_ctx,
1624 bindings_ctx,
1625 device,
1626 src_ip,
1627 dst_ip,
1628 buffer,
1629 info,
1630 )
1631 }
1632}
1633
1634#[derive(Error, Copy, Clone, Debug, Eq, PartialEq)]
1636pub enum SendToError {
1637 #[error("not writeable")]
1639 NotWriteable,
1640 #[error("could not create a temporary connection socket: {0}")]
1643 CreateSock(IpSockCreationError),
1644 #[error("could not send via temporary socket: {0}")]
1647 Send(IpSockSendError),
1648 #[error("zone error: {0}")]
1650 Zone(ZonedAddressError),
1651 #[error("the remote port was unset")]
1654 RemotePortUnset,
1655 #[error("the remote ip was unexpectedly an ipv4-mapped-ipv6 address")]
1658 RemoteUnexpectedlyMapped,
1659 #[error("the remote ip was unexpectedly not an ipv4-mapped-ipv6 address")]
1662 RemoteUnexpectedlyNonMapped,
1663 #[error("send buffer full")]
1665 SendBufferFull,
1666 #[error("invalid message length")]
1668 InvalidLength,
1669}
1670
1671pub struct UdpApi<I: Ip, C>(C, IpVersionMarker<I>);
1673
1674impl<I: Ip, C> UdpApi<I, C> {
1675 pub fn new(ctx: C) -> Self {
1677 Self(ctx, IpVersionMarker::new())
1678 }
1679}
1680
1681type UdpApiSocketId<I, C> = UdpSocketId<
1686 I,
1687 <<C as ContextPair>::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId,
1688 <C as ContextPair>::BindingsContext,
1689>;
1690
1691impl<I, C> UdpApi<I, C>
1692where
1693 I: IpExt,
1694 C: ContextPair,
1695 C::CoreContext: StateContext<I, C::BindingsContext>
1696 + UdpCounterContext<
1697 I,
1698 <C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId,
1699 C::BindingsContext,
1700 >
1701 + DatagramStateContext<I, C::BindingsContext, Udp<C::BindingsContext>>,
1704 C::BindingsContext:
1705 UdpBindingsContext<I, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
1706{
1707 fn core_ctx(&mut self) -> &mut C::CoreContext {
1708 let Self(pair, IpVersionMarker { .. }) = self;
1709 pair.core_ctx()
1710 }
1711
1712 #[cfg(test)]
1713 fn contexts(&mut self) -> (&mut C::CoreContext, &mut C::BindingsContext) {
1714 let Self(pair, IpVersionMarker { .. }) = self;
1715 pair.contexts()
1716 }
1717
1718 fn datagram(&mut self) -> &mut DatagramApi<I, C, Udp<C::BindingsContext>> {
1719 let Self(pair, IpVersionMarker { .. }) = self;
1720 DatagramApi::wrap(pair)
1721 }
1722
1723 pub fn create(&mut self) -> UdpApiSocketId<I, C>
1725 where
1726 <C::BindingsContext as UdpBindingsTypes>::ExternalData<I>: Default,
1727 <C::BindingsContext as UdpBindingsTypes>::SocketWritableListener: Default,
1728 {
1729 self.create_with(Default::default(), Default::default())
1730 }
1731
1732 pub fn create_with(
1734 &mut self,
1735 external_data: <C::BindingsContext as UdpBindingsTypes>::ExternalData<I>,
1736 writable_listener: <C::BindingsContext as UdpBindingsTypes>::SocketWritableListener,
1737 ) -> UdpApiSocketId<I, C> {
1738 self.datagram().create(external_data, writable_listener)
1739 }
1740
1741 pub fn connect(
1760 &mut self,
1761 id: &UdpApiSocketId<I, C>,
1762 remote_ip: Option<
1763 ZonedAddr<
1764 SpecifiedAddr<I::Addr>,
1765 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId,
1766 >,
1767 >,
1768 remote_port: UdpRemotePort,
1769 ) -> Result<(), ConnectError> {
1770 debug!("connect on {id:?} to {remote_ip:?}:{remote_port:?}");
1771 self.datagram().connect(id, remote_ip, remote_port, ())
1772 }
1773
1774 pub fn set_device(
1780 &mut self,
1781 id: &UdpApiSocketId<I, C>,
1782 device_id: Option<&<C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
1783 ) -> Result<(), SocketError> {
1784 debug!("set device on {id:?} to {device_id:?}");
1785 self.datagram().set_device(id, device_id)
1786 }
1787
1788 pub fn get_bound_device(
1790 &mut self,
1791 id: &UdpApiSocketId<I, C>,
1792 ) -> Option<<C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId> {
1793 self.datagram().get_bound_device(id)
1794 }
1795
1796 pub fn set_dual_stack_enabled(
1805 &mut self,
1806 id: &UdpApiSocketId<I, C>,
1807 enabled: bool,
1808 ) -> Result<(), SetDualStackEnabledError> {
1809 self.datagram()
1810 .with_other_stack_ip_options_mut_if_unbound(id, |other_stack| {
1811 I::map_ip(
1812 (enabled, WrapOtherStackIpOptionsMut(other_stack)),
1813 |(_enabled, _v4)| Err(SetDualStackEnabledError::NotCapable),
1814 |(enabled, WrapOtherStackIpOptionsMut(other_stack))| {
1815 let DualStackSocketState { dual_stack_enabled, .. } = other_stack;
1816 *dual_stack_enabled = enabled;
1817 Ok(())
1818 },
1819 )
1820 })
1821 .map_err(|ExpectedUnboundError| {
1822 match I::VERSION {
1825 IpVersion::V4 => SetDualStackEnabledError::NotCapable,
1826 IpVersion::V6 => SetDualStackEnabledError::SocketIsBound,
1827 }
1828 })?
1829 }
1830
1831 pub fn get_dual_stack_enabled(
1840 &mut self,
1841 id: &UdpApiSocketId<I, C>,
1842 ) -> Result<bool, NotDualStackCapableError> {
1843 self.datagram().with_other_stack_ip_options(id, |other_stack| {
1844 I::map_ip(
1845 WrapOtherStackIpOptions(other_stack),
1846 |_v4| Err(NotDualStackCapableError),
1847 |WrapOtherStackIpOptions(other_stack)| {
1848 let DualStackSocketState { dual_stack_enabled, .. } = other_stack;
1849 Ok(*dual_stack_enabled)
1850 },
1851 )
1852 })
1853 }
1854
1855 pub fn set_posix_reuse_addr(
1861 &mut self,
1862 id: &UdpApiSocketId<I, C>,
1863 reuse_addr: bool,
1864 ) -> Result<(), ExpectedUnboundError> {
1865 self.datagram().update_sharing(id, |sharing| {
1866 sharing.reuse_addr = reuse_addr;
1867 })
1868 }
1869
1870 pub fn get_posix_reuse_addr(&mut self, id: &UdpApiSocketId<I, C>) -> bool {
1872 self.datagram().get_sharing(id).reuse_addr
1873 }
1874
1875 pub fn set_posix_reuse_port(
1881 &mut self,
1882 id: &UdpApiSocketId<I, C>,
1883 reuse_port: bool,
1884 ) -> Result<(), ExpectedUnboundError> {
1885 self.datagram().update_sharing(id, |sharing| {
1886 sharing.reuse_port = reuse_port;
1887 })
1888 }
1889
1890 pub fn get_posix_reuse_port(&mut self, id: &UdpApiSocketId<I, C>) -> bool {
1892 self.datagram().get_sharing(id).reuse_port
1893 }
1894
1895 pub fn set_multicast_membership(
1902 &mut self,
1903 id: &UdpApiSocketId<I, C>,
1904 multicast_group: MulticastAddr<I::Addr>,
1905 interface: MulticastMembershipInterfaceSelector<
1906 I::Addr,
1907 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId,
1908 >,
1909 want_membership: bool,
1910 ) -> Result<(), SetMulticastMembershipError> {
1911 debug!(
1912 "set multicast membership on {id:?} for group {multicast_group:?} with interface \
1913 selector: {interface:?}: want_membership={want_membership}"
1914 );
1915 self.datagram().set_multicast_membership(id, multicast_group, interface, want_membership)
1916 }
1917
1918 pub fn set_unicast_hop_limit(
1927 &mut self,
1928 id: &UdpApiSocketId<I, C>,
1929 unicast_hop_limit: Option<NonZeroU8>,
1930 ip_version: IpVersion,
1931 ) -> Result<(), NotDualStackCapableError> {
1932 if ip_version == I::VERSION {
1933 return Ok(self
1934 .datagram()
1935 .update_ip_hop_limit(id, SocketHopLimits::set_unicast(unicast_hop_limit)));
1936 }
1937 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
1938 I::map_ip(
1939 (IpInvariant(unicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack)),
1940 |(IpInvariant(_unicast_hop_limit), _v4)| Err(NotDualStackCapableError),
1941 |(IpInvariant(unicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack))| {
1942 let DualStackSocketState {
1943 socket_options:
1944 DatagramIpSpecificSocketOptions {
1945 hop_limits: SocketHopLimits { unicast, multicast: _, version: _ },
1946 ..
1947 },
1948 ..
1949 } = other_stack;
1950 *unicast = unicast_hop_limit;
1951 Ok(())
1952 },
1953 )
1954 })
1955 }
1956
1957 pub fn set_multicast_hop_limit(
1966 &mut self,
1967 id: &UdpApiSocketId<I, C>,
1968 multicast_hop_limit: Option<NonZeroU8>,
1969 ip_version: IpVersion,
1970 ) -> Result<(), NotDualStackCapableError> {
1971 if ip_version == I::VERSION {
1972 return Ok(self
1973 .datagram()
1974 .update_ip_hop_limit(id, SocketHopLimits::set_multicast(multicast_hop_limit)));
1975 }
1976 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
1977 I::map_ip(
1978 (IpInvariant(multicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack)),
1979 |(IpInvariant(_multicast_hop_limit), _v4)| Err(NotDualStackCapableError),
1980 |(IpInvariant(multicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack))| {
1981 let DualStackSocketState {
1982 socket_options:
1983 DatagramIpSpecificSocketOptions {
1984 hop_limits: SocketHopLimits { unicast: _, multicast, version: _ },
1985 ..
1986 },
1987 ..
1988 } = other_stack;
1989 *multicast = multicast_hop_limit;
1990 Ok(())
1991 },
1992 )
1993 })
1994 }
1995
1996 pub fn get_unicast_hop_limit(
2005 &mut self,
2006 id: &UdpApiSocketId<I, C>,
2007 ip_version: IpVersion,
2008 ) -> Result<NonZeroU8, NotDualStackCapableError> {
2009 if ip_version == I::VERSION {
2010 return Ok(self.datagram().get_ip_hop_limits(id).unicast);
2011 }
2012 self.datagram().with_other_stack_ip_options_and_default_hop_limits(
2013 id,
2014 |other_stack, default_hop_limits| {
2015 I::map_ip_in(
2016 (WrapOtherStackIpOptions(other_stack), IpInvariant(default_hop_limits)),
2017 |_v4| Err(NotDualStackCapableError),
2018 |(
2019 WrapOtherStackIpOptions(other_stack),
2020 IpInvariant(HopLimits { unicast: default_unicast, multicast: _ }),
2021 )| {
2022 let DualStackSocketState {
2023 socket_options:
2024 DatagramIpSpecificSocketOptions {
2025 hop_limits:
2026 SocketHopLimits { unicast, multicast: _, version: _ },
2027 ..
2028 },
2029 ..
2030 } = other_stack;
2031 Ok(unicast.unwrap_or(default_unicast))
2032 },
2033 )
2034 },
2035 )?
2036 }
2037
2038 pub fn get_multicast_hop_limit(
2047 &mut self,
2048 id: &UdpApiSocketId<I, C>,
2049 ip_version: IpVersion,
2050 ) -> Result<NonZeroU8, NotDualStackCapableError> {
2051 if ip_version == I::VERSION {
2052 return Ok(self.datagram().get_ip_hop_limits(id).multicast);
2053 }
2054 self.datagram().with_other_stack_ip_options_and_default_hop_limits(
2055 id,
2056 |other_stack, default_hop_limits| {
2057 I::map_ip_in(
2058 (WrapOtherStackIpOptions(other_stack), IpInvariant(default_hop_limits)),
2059 |_v4| Err(NotDualStackCapableError),
2060 |(
2061 WrapOtherStackIpOptions(other_stack),
2062 IpInvariant(HopLimits { unicast: _, multicast: default_multicast }),
2063 )| {
2064 let DualStackSocketState {
2065 socket_options:
2066 DatagramIpSpecificSocketOptions {
2067 hop_limits:
2068 SocketHopLimits { unicast: _, multicast, version: _ },
2069 ..
2070 },
2071 ..
2072 } = other_stack;
2073 Ok(multicast.unwrap_or(default_multicast))
2074 },
2075 )
2076 },
2077 )?
2078 }
2079
2080 pub fn get_multicast_interface(
2082 &mut self,
2083 id: &UdpApiSocketId<I, C>,
2084 ip_version: IpVersion,
2085 ) -> Result<
2086 Option<<C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId>,
2087 NotDualStackCapableError,
2088 > {
2089 if ip_version == I::VERSION {
2090 return Ok(self.datagram().get_multicast_interface(id));
2091 };
2092
2093 self.datagram().with_other_stack_ip_options(id, |other_stack| {
2094 I::map_ip_in(
2095 WrapOtherStackIpOptions(other_stack),
2096 |_v4| Err(NotDualStackCapableError),
2097 |WrapOtherStackIpOptions(other_stack)| {
2098 Ok(other_stack.socket_options.multicast_interface.clone())
2099 },
2100 )
2101 })
2102 }
2103
2104 pub fn set_multicast_interface(
2106 &mut self,
2107 id: &UdpApiSocketId<I, C>,
2108 interface: Option<&<C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
2109 ip_version: IpVersion,
2110 ) -> Result<(), NotDualStackCapableError> {
2111 if ip_version == I::VERSION {
2112 self.datagram().set_multicast_interface(id, interface);
2113 return Ok(());
2114 };
2115
2116 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
2117 I::map_ip(
2118 (IpInvariant(interface), WrapOtherStackIpOptionsMut(other_stack)),
2119 |(IpInvariant(_interface), _v4)| Err(NotDualStackCapableError),
2120 |(IpInvariant(interface), WrapOtherStackIpOptionsMut(other_stack))| {
2121 other_stack.socket_options.multicast_interface =
2122 interface.map(|device| device.downgrade());
2123 Ok(())
2124 },
2125 )
2126 })
2127 }
2128
2129 pub fn get_transparent(&mut self, id: &UdpApiSocketId<I, C>) -> bool {
2131 self.datagram().get_ip_transparent(id)
2132 }
2133
2134 pub fn set_transparent(&mut self, id: &UdpApiSocketId<I, C>, value: bool) {
2136 self.datagram().set_ip_transparent(id, value)
2137 }
2138
2139 pub fn get_mark(&mut self, id: &UdpApiSocketId<I, C>, domain: MarkDomain) -> Mark {
2141 self.datagram().get_mark(id, domain)
2142 }
2143
2144 pub fn set_mark(&mut self, id: &UdpApiSocketId<I, C>, domain: MarkDomain, mark: Mark) {
2146 self.datagram().set_mark(id, domain, mark)
2147 }
2148
2149 pub fn get_broadcast(&mut self, id: &UdpApiSocketId<I, C>) -> bool {
2151 self.datagram().with_both_stacks_ip_options(id, |this_stack, other_stack| {
2152 I::map_ip_in(
2153 (this_stack, WrapOtherStackIpOptions(other_stack)),
2154 |(this_stack, _)| this_stack.allow_broadcast.is_some(),
2155 |(_, WrapOtherStackIpOptions(other_stack))| {
2156 other_stack.socket_options.allow_broadcast.is_some()
2157 },
2158 )
2159 })
2160 }
2161
2162 pub fn set_broadcast(&mut self, id: &UdpApiSocketId<I, C>, value: bool) {
2164 self.datagram().with_both_stacks_ip_options_mut(id, |this_stack, other_stack| {
2165 let value = value.then_some(());
2166 I::map_ip_in(
2167 (this_stack, WrapOtherStackIpOptionsMut(other_stack)),
2168 |(this_stack, _)| this_stack.allow_broadcast = value,
2169 |(_, WrapOtherStackIpOptionsMut(other_stack))| {
2170 other_stack.socket_options.allow_broadcast = value;
2171 },
2172 )
2173 })
2174 }
2175
2176 pub fn get_multicast_loop(
2178 &mut self,
2179 id: &UdpApiSocketId<I, C>,
2180 ip_version: IpVersion,
2181 ) -> Result<bool, NotDualStackCapableError> {
2182 if ip_version == I::VERSION {
2183 return Ok(self.datagram().get_multicast_loop(id));
2184 };
2185
2186 self.datagram().with_other_stack_ip_options(id, |other_stack| {
2187 I::map_ip_in(
2188 WrapOtherStackIpOptions(other_stack),
2189 |_v4| Err(NotDualStackCapableError),
2190 |WrapOtherStackIpOptions(other_stack)| {
2191 Ok(other_stack.socket_options.multicast_loop)
2192 },
2193 )
2194 })
2195 }
2196
2197 pub fn set_multicast_loop(
2199 &mut self,
2200 id: &UdpApiSocketId<I, C>,
2201 value: bool,
2202 ip_version: IpVersion,
2203 ) -> Result<(), NotDualStackCapableError> {
2204 if ip_version == I::VERSION {
2205 self.datagram().set_multicast_loop(id, value);
2206 return Ok(());
2207 };
2208
2209 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
2210 I::map_ip(
2211 (IpInvariant(value), WrapOtherStackIpOptionsMut(other_stack)),
2212 |(IpInvariant(_interface), _v4)| Err(NotDualStackCapableError),
2213 |(IpInvariant(value), WrapOtherStackIpOptionsMut(other_stack))| {
2214 other_stack.socket_options.multicast_loop = value;
2215 Ok(())
2216 },
2217 )
2218 })
2219 }
2220
2221 pub fn get_dscp_and_ecn(
2223 &mut self,
2224 id: &UdpApiSocketId<I, C>,
2225 ip_version: IpVersion,
2226 ) -> Result<DscpAndEcn, NotDualStackCapableError> {
2227 if ip_version == I::VERSION {
2228 return Ok(self.datagram().get_dscp_and_ecn(id));
2229 };
2230
2231 self.datagram().with_other_stack_ip_options(id, |other_stack| {
2232 I::map_ip_in(
2233 WrapOtherStackIpOptions(other_stack),
2234 |_v4| Err(NotDualStackCapableError),
2235 |WrapOtherStackIpOptions(other_stack)| Ok(other_stack.socket_options.dscp_and_ecn),
2236 )
2237 })
2238 }
2239
2240 pub fn set_dscp_and_ecn(
2242 &mut self,
2243 id: &UdpApiSocketId<I, C>,
2244 value: DscpAndEcn,
2245 ip_version: IpVersion,
2246 ) -> Result<(), NotDualStackCapableError> {
2247 if ip_version == I::VERSION {
2248 self.datagram().set_dscp_and_ecn(id, value);
2249 return Ok(());
2250 };
2251
2252 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
2253 I::map_ip(
2254 (IpInvariant(value), WrapOtherStackIpOptionsMut(other_stack)),
2255 |(IpInvariant(_interface), _v4)| Err(NotDualStackCapableError),
2256 |(IpInvariant(value), WrapOtherStackIpOptionsMut(other_stack))| {
2257 other_stack.socket_options.dscp_and_ecn = value;
2258 Ok(())
2259 },
2260 )
2261 })
2262 }
2263
2264 pub fn set_send_buffer(&mut self, id: &UdpApiSocketId<I, C>, size: usize) {
2266 self.datagram().set_send_buffer(id, size)
2267 }
2268
2269 pub fn send_buffer(&mut self, id: &UdpApiSocketId<I, C>) -> usize {
2271 self.datagram().send_buffer(id)
2272 }
2273
2274 #[cfg(any(test, feature = "testutils"))]
2276 pub fn send_buffer_available(&mut self, id: &UdpApiSocketId<I, C>) -> usize {
2277 self.datagram().send_buffer_available(id)
2278 }
2279
2280 pub fn disconnect(&mut self, id: &UdpApiSocketId<I, C>) -> Result<(), ExpectedConnError> {
2289 debug!("disconnect {id:?}");
2290 self.datagram().disconnect_connected(id)
2291 }
2292
2293 pub fn shutdown(
2299 &mut self,
2300 id: &UdpApiSocketId<I, C>,
2301 which: ShutdownType,
2302 ) -> Result<(), ExpectedConnError> {
2303 debug!("shutdown {id:?} {which:?}");
2304 self.datagram().shutdown_connected(id, which)
2305 }
2306
2307 pub fn get_shutdown(&mut self, id: &UdpApiSocketId<I, C>) -> Option<ShutdownType> {
2312 self.datagram().get_shutdown_connected(id)
2313 }
2314
2315 pub fn close(
2317 &mut self,
2318 id: UdpApiSocketId<I, C>,
2319 ) -> RemoveResourceResultWithContext<
2320 <C::BindingsContext as UdpBindingsTypes>::ExternalData<I>,
2321 C::BindingsContext,
2322 > {
2323 debug!("close {id:?}");
2324 self.datagram().close(id)
2325 }
2326
2327 pub fn get_info(
2330 &mut self,
2331 id: &UdpApiSocketId<I, C>,
2332 ) -> SocketInfo<I::Addr, <C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId> {
2333 self.datagram().get_info(id)
2334 }
2335
2336 pub fn listen(
2353 &mut self,
2354 id: &UdpApiSocketId<I, C>,
2355 addr: Option<
2356 ZonedAddr<
2357 SpecifiedAddr<I::Addr>,
2358 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId,
2359 >,
2360 >,
2361 port: Option<NonZeroU16>,
2362 ) -> Result<(), Either<ExpectedUnboundError, LocalAddressError>> {
2363 debug!("listen on {id:?} on {addr:?}:{port:?}");
2364 self.datagram().listen(id, addr, port)
2365 }
2366
2367 pub fn send<B: BufferMut>(
2375 &mut self,
2376 id: &UdpApiSocketId<I, C>,
2377 body: B,
2378 ) -> Result<(), Either<SendError, ExpectedConnError>> {
2379 self.core_ctx().increment_both(id, |c| &c.tx);
2380 self.datagram().send_conn(id, body).map_err(|err| {
2381 self.core_ctx().increment_both(id, |c| &c.tx_error);
2382 match err {
2383 DatagramSendError::NotConnected => Either::Right(ExpectedConnError),
2384 DatagramSendError::NotWriteable => Either::Left(SendError::NotWriteable),
2385 DatagramSendError::SendBufferFull => Either::Left(SendError::SendBufferFull),
2386 DatagramSendError::InvalidLength => Either::Left(SendError::InvalidLength),
2387 DatagramSendError::IpSock(err) => Either::Left(SendError::IpSock(err)),
2388 DatagramSendError::SerializeError(err) => match err {
2389 UdpSerializeError::RemotePortUnset => Either::Left(SendError::RemotePortUnset),
2390 },
2391 }
2392 })
2393 }
2394
2395 pub fn send_to<B: BufferMut>(
2406 &mut self,
2407 id: &UdpApiSocketId<I, C>,
2408 remote_ip: Option<
2409 ZonedAddr<
2410 SpecifiedAddr<I::Addr>,
2411 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId,
2412 >,
2413 >,
2414 remote_port: UdpRemotePort,
2415 body: B,
2416 ) -> Result<(), Either<LocalAddressError, SendToError>> {
2417 match remote_port {
2419 UdpRemotePort::Unset => return Err(Either::Right(SendToError::RemotePortUnset)),
2420 UdpRemotePort::Set(_) => {}
2421 }
2422
2423 self.core_ctx().increment_both(id, |c| &c.tx);
2424 self.datagram().send_to(id, remote_ip, remote_port, body).map_err(|e| {
2425 self.core_ctx().increment_both(id, |c| &c.tx_error);
2426 match e {
2427 Either::Left(e) => Either::Left(e),
2428 Either::Right(e) => {
2429 let err = match e {
2430 datagram::SendToError::SerializeError(err) => match err {
2431 UdpSerializeError::RemotePortUnset => SendToError::RemotePortUnset,
2432 },
2433 datagram::SendToError::NotWriteable => SendToError::NotWriteable,
2434 datagram::SendToError::SendBufferFull => SendToError::SendBufferFull,
2435 datagram::SendToError::InvalidLength => SendToError::InvalidLength,
2436 datagram::SendToError::Zone(e) => SendToError::Zone(e),
2437 datagram::SendToError::CreateAndSend(e) => match e {
2438 IpSockCreateAndSendError::Send(e) => SendToError::Send(e),
2439 IpSockCreateAndSendError::Create(e) => SendToError::CreateSock(e),
2440 },
2441 datagram::SendToError::RemoteUnexpectedlyMapped => {
2442 SendToError::RemoteUnexpectedlyMapped
2443 }
2444 datagram::SendToError::RemoteUnexpectedlyNonMapped => {
2445 SendToError::RemoteUnexpectedlyNonMapped
2446 }
2447 };
2448 Either::Right(err)
2449 }
2450 }
2451 })
2452 }
2453
2454 pub fn collect_all_sockets(&mut self) -> Vec<UdpApiSocketId<I, C>> {
2457 self.datagram().collect_all_sockets()
2458 }
2459
2460 pub fn inspect<N>(&mut self, inspector: &mut N)
2462 where
2463 N: Inspector
2464 + InspectorDeviceExt<<C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId>,
2465 for<'a> N::ChildInspector<'a>:
2466 InspectorDeviceExt<<C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId>,
2467 {
2468 DatagramStateContext::for_each_socket(self.core_ctx(), |_ctx, socket_id, socket_state| {
2469 inspector.record_debug_child(socket_id, |inspector| {
2470 socket_state.record_common_info(inspector);
2471 inspector.record_child("Counters", |inspector| {
2472 inspector.delegate_inspectable(&CombinedUdpCounters {
2473 with_socket: socket_id.counters(),
2474 without_socket: None,
2475 });
2476 });
2477 });
2478 });
2479 }
2480}
2481
2482#[derive(Copy, Clone, Debug, Eq, PartialEq, GenericOverIp)]
2484#[generic_over_ip()]
2485pub enum SendError {
2486 NotWriteable,
2488 IpSock(IpSockSendError),
2490 RemotePortUnset,
2493 SendBufferFull,
2495 InvalidLength,
2497}
2498
2499impl<I: IpExt, BC: UdpBindingsContext<I, CC::DeviceId>, CC: StateContext<I, BC>>
2500 DatagramSpecStateContext<I, CC, BC> for Udp<BC>
2501{
2502 type SocketsStateCtx<'a> = CC::SocketStateCtx<'a>;
2503
2504 fn with_all_sockets_mut<O, F: FnOnce(&mut UdpSocketSet<I, CC::WeakDeviceId, BC>) -> O>(
2505 core_ctx: &mut CC,
2506 cb: F,
2507 ) -> O {
2508 StateContext::with_all_sockets_mut(core_ctx, cb)
2509 }
2510
2511 fn with_all_sockets<O, F: FnOnce(&UdpSocketSet<I, CC::WeakDeviceId, BC>) -> O>(
2512 core_ctx: &mut CC,
2513 cb: F,
2514 ) -> O {
2515 StateContext::with_all_sockets(core_ctx, cb)
2516 }
2517
2518 fn with_socket_state<
2519 O,
2520 F: FnOnce(&mut Self::SocketsStateCtx<'_>, &UdpSocketState<I, CC::WeakDeviceId, BC>) -> O,
2521 >(
2522 core_ctx: &mut CC,
2523 id: &UdpSocketId<I, CC::WeakDeviceId, BC>,
2524 cb: F,
2525 ) -> O {
2526 StateContext::with_socket_state(core_ctx, id, cb)
2527 }
2528
2529 fn with_socket_state_mut<
2530 O,
2531 F: FnOnce(&mut Self::SocketsStateCtx<'_>, &mut UdpSocketState<I, CC::WeakDeviceId, BC>) -> O,
2532 >(
2533 core_ctx: &mut CC,
2534 id: &UdpSocketId<I, CC::WeakDeviceId, BC>,
2535 cb: F,
2536 ) -> O {
2537 StateContext::with_socket_state_mut(core_ctx, id, cb)
2538 }
2539
2540 fn for_each_socket<
2541 F: FnMut(
2542 &mut Self::SocketsStateCtx<'_>,
2543 &UdpSocketId<I, CC::WeakDeviceId, BC>,
2544 &UdpSocketState<I, CC::WeakDeviceId, BC>,
2545 ),
2546 >(
2547 core_ctx: &mut CC,
2548 cb: F,
2549 ) {
2550 StateContext::for_each_socket(core_ctx, cb)
2551 }
2552}
2553
2554impl<
2555 I: IpExt,
2556 BC: UdpBindingsContext<I, CC::DeviceId>,
2557 CC: BoundStateContext<I, BC> + UdpStateContext,
2558 > DatagramSpecBoundStateContext<I, CC, BC> for Udp<BC>
2559{
2560 type IpSocketsCtx<'a> = CC::IpSocketsCtx<'a>;
2561
2562 fn with_bound_sockets<
2563 O,
2564 F: FnOnce(
2565 &mut Self::IpSocketsCtx<'_>,
2566 &DatagramBoundSockets<
2567 I,
2568 CC::WeakDeviceId,
2569 UdpAddrSpec,
2570 UdpSocketMapStateSpec<I, CC::WeakDeviceId, BC>,
2571 >,
2572 ) -> O,
2573 >(
2574 core_ctx: &mut CC,
2575 cb: F,
2576 ) -> O {
2577 core_ctx.with_bound_sockets(|core_ctx, BoundSockets { bound_sockets }| {
2578 cb(core_ctx, bound_sockets)
2579 })
2580 }
2581
2582 fn with_bound_sockets_mut<
2583 O,
2584 F: FnOnce(
2585 &mut Self::IpSocketsCtx<'_>,
2586 &mut DatagramBoundSockets<
2587 I,
2588 CC::WeakDeviceId,
2589 UdpAddrSpec,
2590 UdpSocketMapStateSpec<I, CC::WeakDeviceId, BC>,
2591 >,
2592 ) -> O,
2593 >(
2594 core_ctx: &mut CC,
2595 cb: F,
2596 ) -> O {
2597 core_ctx.with_bound_sockets_mut(|core_ctx, BoundSockets { bound_sockets }| {
2598 cb(core_ctx, bound_sockets)
2599 })
2600 }
2601
2602 type DualStackContext = CC::DualStackContext;
2603 type NonDualStackContext = CC::NonDualStackContext;
2604 fn dual_stack_context(
2605 core_ctx: &mut CC,
2606 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
2607 BoundStateContext::dual_stack_context(core_ctx)
2608 }
2609
2610 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
2611 core_ctx: &mut CC,
2612 cb: F,
2613 ) -> O {
2614 core_ctx.with_transport_context(cb)
2615 }
2616}
2617
2618impl<
2619 BC: UdpBindingsContext<Ipv6, CC::DeviceId> + UdpBindingsContext<Ipv4, CC::DeviceId>,
2620 CC: DualStackBoundStateContext<Ipv6, BC> + UdpStateContext,
2621 > DualStackDatagramSpecBoundStateContext<Ipv6, CC, BC> for Udp<BC>
2622{
2623 type IpSocketsCtx<'a> = CC::IpSocketsCtx<'a>;
2624 fn dual_stack_enabled(
2625 _core_ctx: &CC,
2626 state: &impl AsRef<IpOptions<Ipv6, CC::WeakDeviceId, Udp<BC>>>,
2627 ) -> bool {
2628 let DualStackSocketState { dual_stack_enabled, .. } = state.as_ref().other_stack();
2629 *dual_stack_enabled
2630 }
2631
2632 fn to_other_socket_options<'a>(
2633 _core_ctx: &CC,
2634 state: &'a IpOptions<Ipv6, CC::WeakDeviceId, Udp<BC>>,
2635 ) -> &'a DatagramIpSpecificSocketOptions<Ipv4, CC::WeakDeviceId> {
2636 &state.other_stack().socket_options
2637 }
2638
2639 fn ds_converter(_core_ctx: &CC) -> impl DualStackConverter<Ipv6, CC::WeakDeviceId, Self> {
2640 ()
2641 }
2642
2643 fn to_other_bound_socket_id(
2644 _core_ctx: &CC,
2645 id: &UdpSocketId<Ipv6, CC::WeakDeviceId, BC>,
2646 ) -> EitherIpSocket<CC::WeakDeviceId, Udp<BC>> {
2647 EitherIpSocket::V6(id.clone())
2648 }
2649
2650 fn with_both_bound_sockets_mut<
2651 O,
2652 F: FnOnce(
2653 &mut Self::IpSocketsCtx<'_>,
2654 &mut UdpBoundSocketMap<Ipv6, CC::WeakDeviceId, BC>,
2655 &mut UdpBoundSocketMap<Ipv4, CC::WeakDeviceId, BC>,
2656 ) -> O,
2657 >(
2658 core_ctx: &mut CC,
2659 cb: F,
2660 ) -> O {
2661 core_ctx.with_both_bound_sockets_mut(
2662 |core_ctx,
2663 BoundSockets { bound_sockets: bound_first },
2664 BoundSockets { bound_sockets: bound_second }| {
2665 cb(core_ctx, bound_first, bound_second)
2666 },
2667 )
2668 }
2669
2670 fn with_other_bound_sockets_mut<
2671 O,
2672 F: FnOnce(
2673 &mut Self::IpSocketsCtx<'_>,
2674 &mut UdpBoundSocketMap<Ipv4, CC::WeakDeviceId, BC>,
2675 ) -> O,
2676 >(
2677 core_ctx: &mut CC,
2678 cb: F,
2679 ) -> O {
2680 core_ctx.with_other_bound_sockets_mut(|core_ctx, BoundSockets { bound_sockets }| {
2681 cb(core_ctx, bound_sockets)
2682 })
2683 }
2684
2685 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
2686 core_ctx: &mut CC,
2687 cb: F,
2688 ) -> O {
2689 core_ctx.with_transport_context(|core_ctx| cb(core_ctx))
2690 }
2691}
2692
2693impl<
2694 BC: UdpBindingsContext<Ipv4, CC::DeviceId>,
2695 CC: BoundStateContext<Ipv4, BC> + NonDualStackBoundStateContext<Ipv4, BC> + UdpStateContext,
2696 > NonDualStackDatagramSpecBoundStateContext<Ipv4, CC, BC> for Udp<BC>
2697{
2698 fn nds_converter(_core_ctx: &CC) -> impl NonDualStackConverter<Ipv4, CC::WeakDeviceId, Self> {
2699 ()
2700 }
2701}
2702
2703#[cfg(test)]
2704mod tests {
2705 use alloc::borrow::ToOwned;
2706 use alloc::collections::{HashMap, HashSet};
2707 use alloc::vec;
2708 use core::convert::TryInto as _;
2709 use core::ops::{Deref, DerefMut};
2710
2711 use assert_matches::assert_matches;
2712 use ip_test_macro::ip_test;
2713 use itertools::Itertools as _;
2714 use net_declare::{net_ip_v4 as ip_v4, net_ip_v6};
2715 use net_types::ip::{
2716 IpAddr, IpAddress, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr, Ipv6SourceAddr,
2717 };
2718 use net_types::{
2719 AddrAndZone, LinkLocalAddr, MulticastAddr, Scope as _, ScopeableAddress as _, ZonedAddr,
2720 };
2721 use netstack3_base::socket::{SocketIpAddrExt as _, StrictlyZonedAddr};
2722 use netstack3_base::sync::PrimaryRc;
2723 use netstack3_base::testutil::{
2724 set_logger_for_test, FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeReferencyDeviceId,
2725 FakeSocketWritableListener, FakeStrongDeviceId, FakeWeakDeviceId, MultipleDevicesId,
2726 TestIpExt as _,
2727 };
2728 use netstack3_base::{
2729 CtxPair, RemoteAddressError, ResourceCounterContext, SendFrameErrorReason,
2730 UninstantiableWrapper,
2731 };
2732 use netstack3_datagram::MulticastInterfaceSelector;
2733 use netstack3_ip::device::IpDeviceStateIpExt;
2734 use netstack3_ip::socket::testutil::{FakeDeviceConfig, FakeDualStackIpSocketCtx};
2735 use netstack3_ip::testutil::{DualStackSendIpPacketMeta, FakeIpHeaderInfo};
2736 use netstack3_ip::{IpPacketDestination, ResolveRouteError, SendIpPacketMeta};
2737 use packet::Buf;
2738 use test_case::test_case;
2739
2740 use crate::internal::counters::testutil::{
2741 CounterExpectationsWithSocket, CounterExpectationsWithoutSocket,
2742 };
2743
2744 use super::*;
2745
2746 #[derive(Debug, Derivative, PartialEq)]
2748 #[derivative(Default(bound = ""))]
2749 struct SocketReceived<I: Ip> {
2750 packets: Vec<ReceivedPacket<I>>,
2751 }
2752
2753 #[derive(Debug, PartialEq)]
2754 struct ReceivedPacket<I: Ip> {
2755 meta: UdpPacketMeta<I>,
2756 body: Vec<u8>,
2757 }
2758
2759 impl<D: FakeStrongDeviceId> FakeUdpCoreCtx<D> {
2760 fn new_with_device<I: TestIpExt>(device: D) -> Self {
2761 Self::with_local_remote_ip_addrs_and_device(
2762 vec![local_ip::<I>()],
2763 vec![remote_ip::<I>()],
2764 device,
2765 )
2766 }
2767
2768 fn with_local_remote_ip_addrs_and_device<A: Into<SpecifiedAddr<IpAddr>>>(
2769 local_ips: Vec<A>,
2770 remote_ips: Vec<A>,
2771 device: D,
2772 ) -> Self {
2773 Self::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
2774 device,
2775 local_ips,
2776 remote_ips,
2777 }]))
2778 }
2779
2780 fn with_ip_socket_ctx_state(state: FakeDualStackIpSocketCtx<D>) -> Self {
2781 Self {
2782 all_sockets: Default::default(),
2783 bound_sockets: FakeUdpBoundSocketsCtx {
2784 bound_sockets: Default::default(),
2785 ip_socket_ctx: InnerIpSocketCtx::with_state(state),
2786 },
2787 }
2788 }
2789 }
2790
2791 impl FakeUdpCoreCtx<FakeDeviceId> {
2792 fn new_fake_device<I: TestIpExt>() -> Self {
2793 Self::new_with_device::<I>(FakeDeviceId)
2794 }
2795
2796 fn with_local_remote_ip_addrs<A: Into<SpecifiedAddr<IpAddr>>>(
2797 local_ips: Vec<A>,
2798 remote_ips: Vec<A>,
2799 ) -> Self {
2800 Self::with_local_remote_ip_addrs_and_device(local_ips, remote_ips, FakeDeviceId)
2801 }
2802 }
2803
2804 type FakeUdpCtx<D> = CtxPair<FakeUdpCoreCtx<D>, FakeUdpBindingsCtx<D>>;
2806
2807 #[derive(Derivative)]
2808 #[derivative(Default(bound = ""))]
2809 struct FakeBoundSockets<D: StrongDeviceIdentifier> {
2810 v4: BoundSockets<Ipv4, D::Weak, FakeUdpBindingsCtx<D>>,
2811 v6: BoundSockets<Ipv6, D::Weak, FakeUdpBindingsCtx<D>>,
2812 }
2813
2814 impl<D: StrongDeviceIdentifier> FakeBoundSockets<D> {
2815 fn bound_sockets<I: IpExt>(&self) -> &BoundSockets<I, D::Weak, FakeUdpBindingsCtx<D>> {
2816 I::map_ip_out(self, |state| &state.v4, |state| &state.v6)
2817 }
2818
2819 fn bound_sockets_mut<I: IpExt>(
2820 &mut self,
2821 ) -> &mut BoundSockets<I, D::Weak, FakeUdpBindingsCtx<D>> {
2822 I::map_ip_out(self, |state| &mut state.v4, |state| &mut state.v6)
2823 }
2824 }
2825
2826 struct FakeUdpBoundSocketsCtx<D: FakeStrongDeviceId> {
2827 bound_sockets: FakeBoundSockets<D>,
2828 ip_socket_ctx: InnerIpSocketCtx<D>,
2829 }
2830
2831 type FakeUdpBindingsCtx<D> = FakeBindingsCtx<(), (), FakeBindingsCtxState<D>, ()>;
2833
2834 type InnerIpSocketCtx<D> =
2837 FakeCoreCtx<FakeDualStackIpSocketCtx<D>, DualStackSendIpPacketMeta<D>, D>;
2838
2839 type UdpFakeDeviceCtx = FakeUdpCtx<FakeDeviceId>;
2840 type UdpFakeDeviceCoreCtx = FakeUdpCoreCtx<FakeDeviceId>;
2841
2842 #[derive(Derivative)]
2843 #[derivative(Default(bound = ""))]
2844 struct FakeBindingsCtxState<D: StrongDeviceIdentifier> {
2845 received_v4:
2846 HashMap<WeakUdpSocketId<Ipv4, D::Weak, FakeUdpBindingsCtx<D>>, SocketReceived<Ipv4>>,
2847 received_v6:
2848 HashMap<WeakUdpSocketId<Ipv6, D::Weak, FakeUdpBindingsCtx<D>>, SocketReceived<Ipv6>>,
2849 }
2850
2851 impl<D: StrongDeviceIdentifier> FakeBindingsCtxState<D> {
2852 fn received<I: TestIpExt>(
2853 &self,
2854 ) -> &HashMap<WeakUdpSocketId<I, D::Weak, FakeUdpBindingsCtx<D>>, SocketReceived<I>>
2855 {
2856 #[derive(GenericOverIp)]
2857 #[generic_over_ip(I, Ip)]
2858 struct Wrap<'a, I: TestIpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
2859 &'a HashMap<WeakUdpSocketId<I, D, BT>, SocketReceived<I>>,
2860 );
2861 let Wrap(map) = I::map_ip_out(
2862 self,
2863 |state| Wrap(&state.received_v4),
2864 |state| Wrap(&state.received_v6),
2865 );
2866 map
2867 }
2868
2869 fn received_mut<I: IpExt>(
2870 &mut self,
2871 ) -> &mut HashMap<WeakUdpSocketId<I, D::Weak, FakeUdpBindingsCtx<D>>, SocketReceived<I>>
2872 {
2873 #[derive(GenericOverIp)]
2874 #[generic_over_ip(I, Ip)]
2875 struct Wrap<'a, I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
2876 &'a mut HashMap<WeakUdpSocketId<I, D, BT>, SocketReceived<I>>,
2877 );
2878 let Wrap(map) = I::map_ip_out(
2879 self,
2880 |state| Wrap(&mut state.received_v4),
2881 |state| Wrap(&mut state.received_v6),
2882 );
2883 map
2884 }
2885
2886 fn socket_data<I: TestIpExt>(
2887 &self,
2888 ) -> HashMap<WeakUdpSocketId<I, D::Weak, FakeUdpBindingsCtx<D>>, Vec<&'_ [u8]>> {
2889 self.received::<I>()
2890 .iter()
2891 .map(|(id, SocketReceived { packets })| {
2892 (
2893 id.clone(),
2894 packets.iter().map(|ReceivedPacket { meta: _, body }| &body[..]).collect(),
2895 )
2896 })
2897 .collect()
2898 }
2899 }
2900
2901 impl<I: IpExt, D: StrongDeviceIdentifier> UdpReceiveBindingsContext<I, D>
2902 for FakeUdpBindingsCtx<D>
2903 {
2904 fn receive_udp<B: BufferMut>(
2905 &mut self,
2906 id: &UdpSocketId<I, D::Weak, Self>,
2907 _device_id: &D,
2908 meta: UdpPacketMeta<I>,
2909 body: &B,
2910 ) {
2911 self.state
2912 .received_mut::<I>()
2913 .entry(id.downgrade())
2914 .or_default()
2915 .packets
2916 .push(ReceivedPacket { meta, body: body.as_ref().to_owned() })
2917 }
2918 }
2919
2920 impl<D: StrongDeviceIdentifier> UdpBindingsTypes for FakeUdpBindingsCtx<D> {
2921 type ExternalData<I: Ip> = ();
2922 type SocketWritableListener = FakeSocketWritableListener;
2923 }
2924
2925 impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> UdpSocketId<I, D, BT> {
2927 fn get(&self) -> impl Deref<Target = UdpSocketState<I, D, BT>> + '_ {
2928 self.state().read()
2929 }
2930
2931 fn get_mut(&self) -> impl DerefMut<Target = UdpSocketState<I, D, BT>> + '_ {
2932 self.state().write()
2933 }
2934 }
2935
2936 impl<D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeUdpCoreCtx<D> {
2937 type DeviceId = D;
2938 type WeakDeviceId = FakeWeakDeviceId<D>;
2939 }
2940
2941 impl<D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeUdpBoundSocketsCtx<D> {
2942 type DeviceId = D;
2943 type WeakDeviceId = FakeWeakDeviceId<D>;
2944 }
2945
2946 impl<I: TestIpExt, D: FakeStrongDeviceId> StateContext<I, FakeUdpBindingsCtx<D>>
2947 for FakeUdpCoreCtx<D>
2948 {
2949 type SocketStateCtx<'a> = FakeUdpBoundSocketsCtx<D>;
2950
2951 fn with_all_sockets_mut<
2952 O,
2953 F: FnOnce(&mut UdpSocketSet<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>) -> O,
2954 >(
2955 &mut self,
2956 cb: F,
2957 ) -> O {
2958 cb(self.all_sockets.socket_set_mut())
2959 }
2960
2961 fn with_all_sockets<
2962 O,
2963 F: FnOnce(&UdpSocketSet<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>) -> O,
2964 >(
2965 &mut self,
2966 cb: F,
2967 ) -> O {
2968 cb(self.all_sockets.socket_set())
2969 }
2970
2971 fn with_socket_state<
2972 O,
2973 F: FnOnce(
2974 &mut Self::SocketStateCtx<'_>,
2975 &UdpSocketState<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
2976 ) -> O,
2977 >(
2978 &mut self,
2979 id: &UdpSocketId<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
2980 cb: F,
2981 ) -> O {
2982 cb(&mut self.bound_sockets, &id.get())
2983 }
2984
2985 fn with_socket_state_mut<
2986 O,
2987 F: FnOnce(
2988 &mut Self::SocketStateCtx<'_>,
2989 &mut UdpSocketState<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
2990 ) -> O,
2991 >(
2992 &mut self,
2993 id: &UdpSocketId<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
2994 cb: F,
2995 ) -> O {
2996 cb(&mut self.bound_sockets, &mut id.get_mut())
2997 }
2998
2999 fn with_bound_state_context<O, F: FnOnce(&mut Self::SocketStateCtx<'_>) -> O>(
3000 &mut self,
3001 cb: F,
3002 ) -> O {
3003 cb(&mut self.bound_sockets)
3004 }
3005
3006 fn for_each_socket<
3007 F: FnMut(
3008 &mut Self::SocketStateCtx<'_>,
3009 &UdpSocketId<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3010 &UdpSocketState<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3011 ),
3012 >(
3013 &mut self,
3014 mut cb: F,
3015 ) {
3016 self.all_sockets.socket_set().keys().for_each(|id| {
3017 let id = UdpSocketId::from(id.clone());
3018 cb(&mut self.bound_sockets, &id, &id.get());
3019 })
3020 }
3021 }
3022
3023 impl<I: TestIpExt, D: FakeStrongDeviceId> BoundStateContext<I, FakeUdpBindingsCtx<D>>
3024 for FakeUdpBoundSocketsCtx<D>
3025 {
3026 type IpSocketsCtx<'a> = InnerIpSocketCtx<D>;
3027 type DualStackContext = I::UdpDualStackBoundStateContext<D>;
3028 type NonDualStackContext = I::UdpNonDualStackBoundStateContext<D>;
3029
3030 fn with_bound_sockets<
3031 O,
3032 F: FnOnce(
3033 &mut Self::IpSocketsCtx<'_>,
3034 &BoundSockets<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3035 ) -> O,
3036 >(
3037 &mut self,
3038 cb: F,
3039 ) -> O {
3040 let Self { bound_sockets, ip_socket_ctx } = self;
3041 cb(ip_socket_ctx, bound_sockets.bound_sockets())
3042 }
3043
3044 fn with_bound_sockets_mut<
3045 O,
3046 F: FnOnce(
3047 &mut Self::IpSocketsCtx<'_>,
3048 &mut BoundSockets<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3049 ) -> O,
3050 >(
3051 &mut self,
3052 cb: F,
3053 ) -> O {
3054 let Self { bound_sockets, ip_socket_ctx } = self;
3055 cb(ip_socket_ctx, bound_sockets.bound_sockets_mut())
3056 }
3057
3058 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
3059 &mut self,
3060 cb: F,
3061 ) -> O {
3062 cb(&mut self.ip_socket_ctx)
3063 }
3064
3065 fn dual_stack_context(
3066 &mut self,
3067 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
3068 struct Wrap<'a, I: TestIpExt, D: FakeStrongDeviceId + 'static>(
3069 MaybeDualStack<
3070 &'a mut I::UdpDualStackBoundStateContext<D>,
3071 &'a mut I::UdpNonDualStackBoundStateContext<D>,
3072 >,
3073 );
3074 impl<'a, I: TestIpExt, NewIp: TestIpExt, D: FakeStrongDeviceId + 'static>
3076 GenericOverIp<NewIp> for Wrap<'a, I, D>
3077 {
3078 type Type = Wrap<'a, NewIp, D>;
3079 }
3080
3081 let Wrap(context) = I::map_ip_out(
3082 self,
3083 |this| Wrap(MaybeDualStack::NotDualStack(this)),
3084 |this| Wrap(MaybeDualStack::DualStack(this)),
3085 );
3086 context
3087 }
3088 }
3089
3090 impl<D: FakeStrongDeviceId + 'static> UdpStateContext for FakeUdpBoundSocketsCtx<D> {}
3091
3092 impl<D: FakeStrongDeviceId> NonDualStackBoundStateContext<Ipv4, FakeUdpBindingsCtx<D>>
3093 for FakeUdpBoundSocketsCtx<D>
3094 {
3095 }
3096
3097 impl<D: FakeStrongDeviceId> DualStackBoundStateContext<Ipv6, FakeUdpBindingsCtx<D>>
3098 for FakeUdpBoundSocketsCtx<D>
3099 {
3100 type IpSocketsCtx<'a> = InnerIpSocketCtx<D>;
3101
3102 fn with_both_bound_sockets_mut<
3103 O,
3104 F: FnOnce(
3105 &mut Self::IpSocketsCtx<'_>,
3106 &mut BoundSockets<Ipv6, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3107 &mut BoundSockets<Ipv4, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3108 ) -> O,
3109 >(
3110 &mut self,
3111 cb: F,
3112 ) -> O {
3113 let Self { ip_socket_ctx, bound_sockets: FakeBoundSockets { v4, v6 } } = self;
3114 cb(ip_socket_ctx, v6, v4)
3115 }
3116
3117 fn with_other_bound_sockets_mut<
3118 O,
3119 F: FnOnce(
3120 &mut Self::IpSocketsCtx<'_>,
3121 &mut BoundSockets<Ipv4, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3122 ) -> O,
3123 >(
3124 &mut self,
3125 cb: F,
3126 ) -> O {
3127 DualStackBoundStateContext::with_both_bound_sockets_mut(
3128 self,
3129 |core_ctx, _bound, other_bound| cb(core_ctx, other_bound),
3130 )
3131 }
3132
3133 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
3134 &mut self,
3135 cb: F,
3136 ) -> O {
3137 cb(&mut self.ip_socket_ctx)
3138 }
3139 }
3140
3141 impl<I: IpExt + IpDeviceStateIpExt + TestIpExt, D: FakeStrongDeviceId>
3143 IpTransportContext<I, FakeUdpBindingsCtx<D>, FakeUdpCoreCtx<D>> for UdpIpTransportContext
3144 {
3145 fn receive_icmp_error(
3146 _core_ctx: &mut FakeUdpCoreCtx<D>,
3147 _bindings_ctx: &mut FakeUdpBindingsCtx<D>,
3148 _device: &D,
3149 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3150 _original_dst_ip: SpecifiedAddr<I::Addr>,
3151 _original_udp_packet: &[u8],
3152 _err: I::ErrorCode,
3153 ) {
3154 unimplemented!()
3155 }
3156
3157 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
3158 core_ctx: &mut FakeUdpCoreCtx<D>,
3159 bindings_ctx: &mut FakeUdpBindingsCtx<D>,
3160 device: &D,
3161 src_ip: I::RecvSrcAddr,
3162 dst_ip: SpecifiedAddr<I::Addr>,
3163 buffer: B,
3164 info: &LocalDeliveryPacketInfo<I, H>,
3165 ) -> Result<(), (B, TransportReceiveError)> {
3166 receive_ip_packet::<I, _, _, _, _>(
3167 core_ctx,
3168 bindings_ctx,
3169 device,
3170 src_ip,
3171 dst_ip,
3172 buffer,
3173 info,
3174 )
3175 }
3176 }
3177
3178 #[derive(Derivative)]
3179 #[derivative(Default(bound = ""))]
3180 struct FakeDualStackSocketState<D: StrongDeviceIdentifier> {
3181 v4: UdpSocketSet<Ipv4, D::Weak, FakeUdpBindingsCtx<D>>,
3182 v6: UdpSocketSet<Ipv6, D::Weak, FakeUdpBindingsCtx<D>>,
3183 udpv4_counters_with_socket: UdpCountersWithSocket<Ipv4>,
3184 udpv6_counters_with_socket: UdpCountersWithSocket<Ipv6>,
3185 udpv4_counters_without_socket: UdpCountersWithoutSocket<Ipv4>,
3186 udpv6_counters_without_socket: UdpCountersWithoutSocket<Ipv6>,
3187 }
3188
3189 impl<D: StrongDeviceIdentifier> FakeDualStackSocketState<D> {
3190 fn socket_set<I: IpExt>(&self) -> &UdpSocketSet<I, D::Weak, FakeUdpBindingsCtx<D>> {
3191 I::map_ip_out(self, |dual| &dual.v4, |dual| &dual.v6)
3192 }
3193
3194 fn socket_set_mut<I: IpExt>(
3195 &mut self,
3196 ) -> &mut UdpSocketSet<I, D::Weak, FakeUdpBindingsCtx<D>> {
3197 I::map_ip_out(self, |dual| &mut dual.v4, |dual| &mut dual.v6)
3198 }
3199
3200 fn udp_counters_with_socket<I: Ip>(&self) -> &UdpCountersWithSocket<I> {
3201 I::map_ip_out(
3202 self,
3203 |dual| &dual.udpv4_counters_with_socket,
3204 |dual| &dual.udpv6_counters_with_socket,
3205 )
3206 }
3207 fn udp_counters_without_socket<I: Ip>(&self) -> &UdpCountersWithoutSocket<I> {
3208 I::map_ip_out(
3209 self,
3210 |dual| &dual.udpv4_counters_without_socket,
3211 |dual| &dual.udpv6_counters_without_socket,
3212 )
3213 }
3214 }
3215 struct FakeUdpCoreCtx<D: FakeStrongDeviceId> {
3216 bound_sockets: FakeUdpBoundSocketsCtx<D>,
3217 all_sockets: FakeDualStackSocketState<D>,
3220 }
3221
3222 impl<I: Ip, D: FakeStrongDeviceId> CounterContext<UdpCountersWithSocket<I>> for FakeUdpCoreCtx<D> {
3223 fn counters(&self) -> &UdpCountersWithSocket<I> {
3224 &self.all_sockets.udp_counters_with_socket()
3225 }
3226 }
3227
3228 impl<I: Ip, D: FakeStrongDeviceId> CounterContext<UdpCountersWithoutSocket<I>>
3229 for FakeUdpCoreCtx<D>
3230 {
3231 fn counters(&self) -> &UdpCountersWithoutSocket<I> {
3232 &self.all_sockets.udp_counters_without_socket()
3233 }
3234 }
3235
3236 impl<I: DualStackIpExt, D: FakeStrongDeviceId>
3237 ResourceCounterContext<
3238 UdpSocketId<I, FakeWeakDeviceId<D>, FakeUdpBindingsCtx<D>>,
3239 UdpCountersWithSocket<I>,
3240 > for FakeUdpCoreCtx<D>
3241 {
3242 fn per_resource_counters<'a>(
3243 &'a self,
3244 resource: &'a UdpSocketId<I, FakeWeakDeviceId<D>, FakeUdpBindingsCtx<D>>,
3245 ) -> &'a UdpCountersWithSocket<I> {
3246 resource.counters()
3247 }
3248 }
3249
3250 fn local_ip<I: TestIpExt>() -> SpecifiedAddr<I::Addr> {
3251 I::get_other_ip_address(1)
3252 }
3253
3254 fn remote_ip<I: TestIpExt>() -> SpecifiedAddr<I::Addr> {
3255 I::get_other_ip_address(2)
3256 }
3257
3258 trait BaseTestIpExt: netstack3_base::testutil::TestIpExt + IpExt + IpDeviceStateIpExt {
3259 type UdpDualStackBoundStateContext<D: FakeStrongDeviceId + 'static>:
3260 DualStackDatagramBoundStateContext<Self, FakeUdpBindingsCtx<D>, Udp<FakeUdpBindingsCtx<D>>, DeviceId=D, WeakDeviceId=D::Weak>;
3261 type UdpNonDualStackBoundStateContext<D: FakeStrongDeviceId + 'static>:
3262 NonDualStackDatagramBoundStateContext<Self, FakeUdpBindingsCtx<D>, Udp<FakeUdpBindingsCtx<D>>, DeviceId=D, WeakDeviceId=D::Weak>;
3263 fn into_recv_src_addr(addr: Self::Addr) -> Self::RecvSrcAddr;
3264 }
3265
3266 impl BaseTestIpExt for Ipv4 {
3267 type UdpDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
3268 UninstantiableWrapper<FakeUdpBoundSocketsCtx<D>>;
3269
3270 type UdpNonDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
3271 FakeUdpBoundSocketsCtx<D>;
3272
3273 fn into_recv_src_addr(addr: Ipv4Addr) -> Ipv4SourceAddr {
3274 Ipv4SourceAddr::new(addr).unwrap_or_else(|| panic!("{addr} is not a valid source addr"))
3275 }
3276 }
3277
3278 impl BaseTestIpExt for Ipv6 {
3279 type UdpDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
3280 FakeUdpBoundSocketsCtx<D>;
3281 type UdpNonDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
3282 UninstantiableWrapper<FakeUdpBoundSocketsCtx<D>>;
3283
3284 fn into_recv_src_addr(addr: Ipv6Addr) -> Ipv6SourceAddr {
3285 Ipv6SourceAddr::new(addr).unwrap_or_else(|| panic!("{addr} is not a valid source addr"))
3286 }
3287 }
3288
3289 trait TestIpExt: BaseTestIpExt<OtherVersion: BaseTestIpExt> {}
3290 impl<I: BaseTestIpExt<OtherVersion: BaseTestIpExt>> TestIpExt for I {}
3291
3292 fn receive_udp_packet<
3294 I: TestIpExt,
3295 D: FakeStrongDeviceId,
3296 CC: DeviceIdContext<AnyDevice, DeviceId = D>,
3297 >(
3298 core_ctx: &mut CC,
3299 bindings_ctx: &mut FakeUdpBindingsCtx<D>,
3300 device: D,
3301 meta: UdpPacketMeta<I>,
3302 body: &[u8],
3303 ) -> Result<(), TransportReceiveError>
3304 where
3305 UdpIpTransportContext: IpTransportContext<I, FakeUdpBindingsCtx<D>, CC>,
3306 {
3307 let UdpPacketMeta { src_ip, src_port, dst_ip, dst_port, dscp_and_ecn } = meta;
3308 let builder = UdpPacketBuilder::new(src_ip, dst_ip, src_port, dst_port);
3309
3310 let buffer = Buf::new(body.to_owned(), ..)
3311 .encapsulate(builder)
3312 .serialize_vec_outer()
3313 .unwrap()
3314 .into_inner();
3315 <UdpIpTransportContext as IpTransportContext<I, _, _>>::receive_ip_packet(
3316 core_ctx,
3317 bindings_ctx,
3318 &device,
3319 I::into_recv_src_addr(src_ip),
3320 SpecifiedAddr::new(dst_ip).unwrap(),
3321 buffer,
3322 &LocalDeliveryPacketInfo {
3323 header_info: FakeIpHeaderInfo { dscp_and_ecn, ..Default::default() },
3324 ..Default::default()
3325 },
3326 )
3327 .map_err(|(_buffer, e)| e)
3328 }
3329
3330 const LOCAL_PORT: NonZeroU16 = NonZeroU16::new(100).unwrap();
3331 const OTHER_LOCAL_PORT: NonZeroU16 = LOCAL_PORT.checked_add(1).unwrap();
3332 const REMOTE_PORT: NonZeroU16 = NonZeroU16::new(200).unwrap();
3333 const OTHER_REMOTE_PORT: NonZeroU16 = REMOTE_PORT.checked_add(1).unwrap();
3334
3335 fn conn_addr<I>(
3336 device: Option<FakeWeakDeviceId<FakeDeviceId>>,
3337 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>
3338 where
3339 I: TestIpExt,
3340 {
3341 let local_ip = SocketIpAddr::try_from(local_ip::<I>()).unwrap();
3342 let remote_ip = SocketIpAddr::try_from(remote_ip::<I>()).unwrap();
3343 ConnAddr {
3344 ip: ConnIpAddr {
3345 local: (local_ip, LOCAL_PORT),
3346 remote: (remote_ip, REMOTE_PORT.into()),
3347 },
3348 device,
3349 }
3350 .into()
3351 }
3352
3353 fn local_listener<I>(
3354 device: Option<FakeWeakDeviceId<FakeDeviceId>>,
3355 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>
3356 where
3357 I: TestIpExt,
3358 {
3359 let local_ip = SocketIpAddr::try_from(local_ip::<I>()).unwrap();
3360 ListenerAddr { ip: ListenerIpAddr { identifier: LOCAL_PORT, addr: Some(local_ip) }, device }
3361 .into()
3362 }
3363
3364 fn wildcard_listener<I>(
3365 device: Option<FakeWeakDeviceId<FakeDeviceId>>,
3366 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>
3367 where
3368 I: TestIpExt,
3369 {
3370 ListenerAddr { ip: ListenerIpAddr { identifier: LOCAL_PORT, addr: None }, device }.into()
3371 }
3372
3373 #[track_caller]
3374 fn assert_counters<
3375 'a,
3376 I: IpExt,
3377 D: WeakDeviceIdentifier,
3378 BT: UdpBindingsTypes,
3379 CC: UdpCounterContext<I, D, BT>,
3380 >(
3381 core_ctx: &CC,
3382 with_socket_expects: CounterExpectationsWithSocket,
3383 without_socket_expects: CounterExpectationsWithoutSocket,
3384 per_socket_expects: impl IntoIterator<
3385 Item = (&'a UdpSocketId<I, D, BT>, CounterExpectationsWithSocket),
3386 >,
3387 ) {
3388 assert_eq!(
3389 CounterExpectationsWithSocket::from(
3390 CounterContext::<UdpCountersWithSocket<I>>::counters(core_ctx).as_ref()
3391 ),
3392 with_socket_expects
3393 );
3394 assert_eq!(
3395 CounterExpectationsWithoutSocket::from(
3396 CounterContext::<UdpCountersWithoutSocket<I>>::counters(core_ctx).as_ref()
3397 ),
3398 without_socket_expects
3399 );
3400 for (id, expects) in per_socket_expects.into_iter() {
3401 assert_eq!(
3402 CounterExpectationsWithSocket::from(core_ctx.per_resource_counters(id).as_ref()),
3403 expects
3404 );
3405 }
3406 }
3407
3408 #[ip_test(I)]
3409 #[test_case(conn_addr(Some(FakeWeakDeviceId(FakeDeviceId))), [
3410 conn_addr(None), local_listener(Some(FakeWeakDeviceId(FakeDeviceId))), local_listener(None),
3411 wildcard_listener(Some(FakeWeakDeviceId(FakeDeviceId))), wildcard_listener(None)
3412 ]; "conn with device")]
3413 #[test_case(local_listener(Some(FakeWeakDeviceId(FakeDeviceId))),
3414 [local_listener(None), wildcard_listener(Some(FakeWeakDeviceId(FakeDeviceId))), wildcard_listener(None)];
3415 "local listener with device")]
3416 #[test_case(wildcard_listener(Some(FakeWeakDeviceId(FakeDeviceId))), [wildcard_listener(None)];
3417 "wildcard listener with device")]
3418 #[test_case(conn_addr(None), [local_listener(None), wildcard_listener(None)]; "conn no device")]
3419 #[test_case(local_listener(None), [wildcard_listener(None)]; "local listener no device")]
3420 #[test_case(wildcard_listener(None), []; "wildcard listener no device")]
3421 fn test_udp_addr_vec_iter_shadows_conn<I: IpExt, D: WeakDeviceIdentifier, const N: usize>(
3422 addr: AddrVec<I, D, UdpAddrSpec>,
3423 expected_shadows: [AddrVec<I, D, UdpAddrSpec>; N],
3424 ) {
3425 assert_eq!(addr.iter_shadows().collect::<HashSet<_>>(), HashSet::from(expected_shadows));
3426 }
3427
3428 #[ip_test(I)]
3429 fn test_iter_receiving_addrs<I: TestIpExt>() {
3430 let addr = ConnIpAddr {
3431 local: (SocketIpAddr::try_from(local_ip::<I>()).unwrap(), LOCAL_PORT),
3432 remote: (SocketIpAddr::try_from(remote_ip::<I>()).unwrap(), REMOTE_PORT.into()),
3433 };
3434 assert_eq!(
3435 iter_receiving_addrs::<I, _>(addr, FakeWeakDeviceId(FakeDeviceId)).collect::<Vec<_>>(),
3436 vec![
3437 conn_addr(Some(FakeWeakDeviceId(FakeDeviceId))),
3439 conn_addr(None),
3441 local_listener(Some(FakeWeakDeviceId(FakeDeviceId))),
3442 local_listener(None),
3444 wildcard_listener(Some(FakeWeakDeviceId(FakeDeviceId))),
3445 wildcard_listener(None)
3447 ]
3448 );
3449 }
3450
3451 #[ip_test(I)]
3457 fn test_listen_udp<I: TestIpExt>() {
3458 set_logger_for_test();
3459 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3460 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3461 let local_ip = local_ip::<I>();
3462 let remote_ip = remote_ip::<I>();
3463 let socket = api.create();
3464 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3466 .expect("listen_udp failed");
3467
3468 let body = [1, 2, 3, 4, 5];
3470 let (core_ctx, bindings_ctx) = api.contexts();
3471 let meta = UdpPacketMeta::<I> {
3472 src_ip: remote_ip.get(),
3473 src_port: Some(REMOTE_PORT),
3474 dst_ip: local_ip.get(),
3475 dst_port: LOCAL_PORT,
3476 dscp_and_ecn: DscpAndEcn::default(),
3477 };
3478 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta.clone(), &body[..])
3479 .expect("receive udp packet should succeed");
3480
3481 assert_eq!(
3482 bindings_ctx.state.received::<I>(),
3483 &HashMap::from([(
3484 socket.downgrade(),
3485 SocketReceived { packets: vec![ReceivedPacket { meta, body: body.into() }] }
3486 )])
3487 );
3488
3489 api.send_to(
3491 &socket,
3492 Some(ZonedAddr::Unzoned(remote_ip)),
3493 REMOTE_PORT.into(),
3494 Buf::new(body.to_vec(), ..),
3495 )
3496 .expect("send_to suceeded");
3497
3498 api.send_to(
3500 &socket,
3501 Some(ZonedAddr::Unzoned(remote_ip)),
3502 REMOTE_PORT.into(),
3503 Buf::new(body.to_vec(), ..),
3504 )
3505 .expect("send_to succeeded");
3506 let frames = api.core_ctx().bound_sockets.ip_socket_ctx.frames();
3507 assert_eq!(frames.len(), 2);
3508 let check_frame =
3509 |(meta, frame_body): &(DualStackSendIpPacketMeta<FakeDeviceId>, Vec<u8>)| {
3510 let SendIpPacketMeta {
3511 device: _,
3512 src_ip,
3513 dst_ip,
3514 destination,
3515 proto,
3516 ttl: _,
3517 mtu: _,
3518 dscp_and_ecn: _,
3519 } = meta.try_as::<I>().unwrap();
3520 assert_eq!(destination, &IpPacketDestination::Neighbor(remote_ip));
3521 assert_eq!(src_ip, &local_ip);
3522 assert_eq!(dst_ip, &remote_ip);
3523 assert_eq!(proto, &IpProto::Udp.into());
3524 let mut buf = &frame_body[..];
3525 let udp_packet =
3526 UdpPacket::parse(&mut buf, UdpParseArgs::new(src_ip.get(), dst_ip.get()))
3527 .expect("Parsed sent UDP packet");
3528 assert_eq!(udp_packet.src_port().unwrap(), LOCAL_PORT);
3529 assert_eq!(udp_packet.dst_port(), REMOTE_PORT);
3530 assert_eq!(udp_packet.body(), &body[..]);
3531 };
3532 check_frame(&frames[0]);
3533 check_frame(&frames[1]);
3534 }
3535
3536 #[ip_test(I)]
3541 fn test_udp_drop<I: TestIpExt>() {
3542 set_logger_for_test();
3543 let UdpFakeDeviceCtx { mut core_ctx, mut bindings_ctx } =
3544 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3545 let local_ip = local_ip::<I>();
3546 let remote_ip = remote_ip::<I>();
3547
3548 let meta = UdpPacketMeta::<I> {
3549 src_ip: remote_ip.get(),
3550 src_port: Some(REMOTE_PORT),
3551 dst_ip: local_ip.get(),
3552 dst_port: LOCAL_PORT,
3553 dscp_and_ecn: DscpAndEcn::default(),
3554 };
3555 let body = [1, 2, 3, 4, 5];
3556 assert_matches!(
3557 receive_udp_packet(&mut core_ctx, &mut bindings_ctx, FakeDeviceId, meta, &body[..]),
3558 Err(TransportReceiveError::PortUnreachable)
3559 );
3560 assert_eq!(&bindings_ctx.state.socket_data::<I>(), &HashMap::new());
3561 }
3562
3563 #[ip_test(I)]
3568 fn test_udp_conn_basic<I: TestIpExt>() {
3569 set_logger_for_test();
3570 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3571 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3572 let local_ip = local_ip::<I>();
3573 let remote_ip = remote_ip::<I>();
3574 let socket = api.create();
3575 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3577 .expect("listen_udp failed");
3578 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
3579 .expect("connect failed");
3580
3581 let meta = UdpPacketMeta::<I> {
3583 src_ip: remote_ip.get(),
3584 src_port: Some(REMOTE_PORT),
3585 dst_ip: local_ip.get(),
3586 dst_port: LOCAL_PORT,
3587 dscp_and_ecn: DscpAndEcn::default(),
3588 };
3589 let body = [1, 2, 3, 4, 5];
3590 let (core_ctx, bindings_ctx) = api.contexts();
3591 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta, &body[..])
3592 .expect("receive udp packet should succeed");
3593
3594 assert_eq!(
3595 bindings_ctx.state.socket_data(),
3596 HashMap::from([(socket.downgrade(), vec![&body[..]])])
3597 );
3598
3599 api.send(&socket, Buf::new(body.to_vec(), ..)).expect("send_udp_conn returned an error");
3601
3602 let (meta, frame_body) =
3603 assert_matches!(api.core_ctx().bound_sockets.ip_socket_ctx.frames(), [frame] => frame);
3604 let SendIpPacketMeta {
3606 device: _,
3607 src_ip,
3608 dst_ip,
3609 destination,
3610 proto,
3611 ttl: _,
3612 mtu: _,
3613 dscp_and_ecn: _,
3614 } = meta.try_as::<I>().unwrap();
3615 assert_eq!(destination, &IpPacketDestination::Neighbor(remote_ip));
3616 assert_eq!(src_ip, &local_ip);
3617 assert_eq!(dst_ip, &remote_ip);
3618 assert_eq!(proto, &IpProto::Udp.into());
3619 let mut buf = &frame_body[..];
3620 let udp_packet = UdpPacket::parse(&mut buf, UdpParseArgs::new(src_ip.get(), dst_ip.get()))
3621 .expect("Parsed sent UDP packet");
3622 assert_eq!(udp_packet.src_port().unwrap(), LOCAL_PORT);
3623 assert_eq!(udp_packet.dst_port(), REMOTE_PORT);
3624 assert_eq!(udp_packet.body(), &body[..]);
3625
3626 let expects_with_socket =
3627 || CounterExpectationsWithSocket { rx_delivered: 1, tx: 1, ..Default::default() };
3628 assert_counters(
3629 api.core_ctx(),
3630 expects_with_socket(),
3631 CounterExpectationsWithoutSocket { rx: 1, ..Default::default() },
3632 [(&socket, expects_with_socket())],
3633 )
3634 }
3635
3636 #[ip_test(I)]
3639 fn test_udp_conn_unroutable<I: TestIpExt>() {
3640 set_logger_for_test();
3641 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3642 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3643 let remote_ip = I::get_other_ip_address(127);
3645 let unbound = api.create();
3647 let conn_err = api
3648 .connect(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
3649 .unwrap_err();
3650
3651 assert_eq!(conn_err, ConnectError::Ip(ResolveRouteError::Unreachable.into()));
3652 }
3653
3654 #[ip_test(I)]
3657 fn test_udp_conn_cannot_bind<I: TestIpExt>() {
3658 set_logger_for_test();
3659 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3660 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3661
3662 let remote_ip = remote_ip::<I>();
3664 let unbound = api.create();
3666 let result = api.listen(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), Some(LOCAL_PORT));
3667
3668 assert_eq!(result, Err(Either::Right(LocalAddressError::CannotBindToAddress)));
3669 }
3670
3671 #[test]
3672 fn test_udp_conn_picks_link_local_source_address() {
3673 set_logger_for_test();
3674 set_logger_for_test();
3678 let local_ip = SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap();
3679 let remote_ip = SpecifiedAddr::new(net_ip_v6!("1:2:3:4::")).unwrap();
3680 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
3681 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![remote_ip]),
3682 );
3683 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
3684 let socket = api.create();
3685 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
3686 .expect("can connect");
3687
3688 let info = api.get_info(&socket);
3689 let (conn_local_ip, conn_remote_ip) = assert_matches!(
3690 info,
3691 SocketInfo::Connected(datagram::ConnInfo {
3692 local_ip: conn_local_ip,
3693 remote_ip: conn_remote_ip,
3694 local_identifier: _,
3695 remote_identifier: _,
3696 }) => (conn_local_ip, conn_remote_ip)
3697 );
3698 assert_eq!(
3699 conn_local_ip,
3700 StrictlyZonedAddr::new_with_zone(local_ip, || FakeWeakDeviceId(FakeDeviceId)),
3701 );
3702 assert_eq!(conn_remote_ip, StrictlyZonedAddr::new_unzoned_or_panic(remote_ip));
3703
3704 assert_eq!(
3707 api.set_device(&socket, None),
3708 Err(SocketError::Local(LocalAddressError::Zone(ZonedAddressError::DeviceZoneMismatch)))
3709 );
3710 }
3711
3712 #[ip_test(I)]
3713 #[test_case(
3714 true,
3715 Err(IpSockCreationError::Route(ResolveRouteError::Unreachable).into()); "remove device")]
3716 #[test_case(false, Ok(()); "dont remove device")]
3717 fn test_udp_conn_device_removed<I: TestIpExt>(
3718 remove_device: bool,
3719 expected: Result<(), ConnectError>,
3720 ) {
3721 set_logger_for_test();
3722 let device = FakeReferencyDeviceId::default();
3723 let mut ctx =
3724 FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_with_device::<I>(device.clone()));
3725 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3726
3727 let unbound = api.create();
3728 api.set_device(&unbound, Some(&device)).unwrap();
3729
3730 if remove_device {
3731 device.mark_removed();
3732 }
3733
3734 let remote_ip = remote_ip::<I>();
3735 assert_eq!(
3736 api.connect(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into()),
3737 expected,
3738 );
3739 }
3740
3741 #[ip_test(I)]
3744 fn test_udp_conn_exhausted<I: TestIpExt>() {
3745 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3747 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3748
3749 let local_ip = local_ip::<I>();
3750 for port_num in FakePortAlloc::<I>::EPHEMERAL_RANGE {
3752 let socket = api.create();
3753 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), NonZeroU16::new(port_num))
3754 .unwrap();
3755 }
3756
3757 let remote_ip = remote_ip::<I>();
3758 let unbound = api.create();
3759 let conn_err = api
3760 .connect(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
3761 .unwrap_err();
3762
3763 assert_eq!(conn_err, ConnectError::CouldNotAllocateLocalPort);
3764 }
3765
3766 #[ip_test(I)]
3767 fn test_connect_success<I: TestIpExt>() {
3768 set_logger_for_test();
3769 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3770 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3771
3772 let local_ip = local_ip::<I>();
3773 let remote_ip = remote_ip::<I>();
3774 let multicast_addr = I::get_multicast_addr(3);
3775 let socket = api.create();
3776
3777 api.set_posix_reuse_port(&socket, true).expect("is unbound");
3779 api.set_multicast_membership(
3780 &socket,
3781 multicast_addr,
3782 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
3783 true,
3784 )
3785 .expect("join multicast group should succeed");
3786
3787 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3788 .expect("Initial call to listen_udp was expected to succeed");
3789
3790 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
3791 .expect("connect should succeed");
3792
3793 assert!(api.get_posix_reuse_port(&socket));
3796 assert_eq!(
3797 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
3798 HashMap::from([((FakeDeviceId, multicast_addr), NonZeroUsize::new(1).unwrap())])
3799 );
3800 assert_eq!(
3801 api.set_multicast_membership(
3802 &socket,
3803 multicast_addr,
3804 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
3805 true
3806 ),
3807 Err(SetMulticastMembershipError::GroupAlreadyJoined)
3808 );
3809 }
3810
3811 #[ip_test(I)]
3812 fn test_connect_fails<I: TestIpExt>() {
3813 set_logger_for_test();
3814 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3815 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3816 let local_ip = local_ip::<I>();
3817 let remote_ip = I::get_other_ip_address(127);
3818 let multicast_addr = I::get_multicast_addr(3);
3819 let socket = api.create();
3820
3821 api.set_posix_reuse_port(&socket, true).expect("is unbound");
3823 api.set_multicast_membership(
3824 &socket,
3825 multicast_addr,
3826 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
3827 true,
3828 )
3829 .expect("join multicast group should succeed");
3830
3831 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3833 .expect("Initial call to listen_udp was expected to succeed");
3834
3835 assert_matches!(
3836 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into()),
3837 Err(ConnectError::Ip(IpSockCreationError::Route(ResolveRouteError::Unreachable)))
3838 );
3839
3840 assert!(api.get_posix_reuse_port(&socket));
3842 assert_eq!(
3843 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
3844 HashMap::from([((FakeDeviceId, multicast_addr), NonZeroUsize::new(1).unwrap())])
3845 );
3846 assert_eq!(
3847 api.set_multicast_membership(
3848 &socket,
3849 multicast_addr,
3850 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
3851 true
3852 ),
3853 Err(SetMulticastMembershipError::GroupAlreadyJoined)
3854 );
3855 }
3856
3857 #[ip_test(I)]
3858 fn test_reconnect_udp_conn_success<I: TestIpExt>() {
3859 set_logger_for_test();
3860
3861 let local_ip = local_ip::<I>();
3862 let remote_ip = remote_ip::<I>();
3863 let other_remote_ip = I::get_other_ip_address(3);
3864
3865 let mut ctx =
3866 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
3867 vec![local_ip],
3868 vec![remote_ip, other_remote_ip],
3869 ));
3870 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3871
3872 let socket = api.create();
3873 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3874 .expect("listen should succeed");
3875
3876 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
3877 .expect("connect was expected to succeed");
3878
3879 api.connect(&socket, Some(ZonedAddr::Unzoned(other_remote_ip)), OTHER_REMOTE_PORT.into())
3880 .expect("connect should succeed");
3881 assert_eq!(
3882 api.get_info(&socket),
3883 SocketInfo::Connected(datagram::ConnInfo {
3884 local_ip: StrictlyZonedAddr::new_unzoned_or_panic(local_ip),
3885 local_identifier: LOCAL_PORT,
3886 remote_ip: StrictlyZonedAddr::new_unzoned_or_panic(other_remote_ip),
3887 remote_identifier: OTHER_REMOTE_PORT.into(),
3888 })
3889 );
3890 }
3891
3892 #[ip_test(I)]
3893 fn test_reconnect_udp_conn_fails<I: TestIpExt>() {
3894 set_logger_for_test();
3895 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3896 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3897 let local_ip = local_ip::<I>();
3898 let remote_ip = remote_ip::<I>();
3899 let other_remote_ip = I::get_other_ip_address(3);
3900
3901 let socket = api.create();
3902 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3903 .expect("listen should succeed");
3904
3905 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
3906 .expect("connect was expected to succeed");
3907 let error = api
3908 .connect(&socket, Some(ZonedAddr::Unzoned(other_remote_ip)), OTHER_REMOTE_PORT.into())
3909 .expect_err("connect should fail");
3910 assert_matches!(
3911 error,
3912 ConnectError::Ip(IpSockCreationError::Route(ResolveRouteError::Unreachable))
3913 );
3914
3915 assert_eq!(
3916 api.get_info(&socket),
3917 SocketInfo::Connected(datagram::ConnInfo {
3918 local_ip: StrictlyZonedAddr::new_unzoned_or_panic(local_ip),
3919 local_identifier: LOCAL_PORT,
3920 remote_ip: StrictlyZonedAddr::new_unzoned_or_panic(remote_ip),
3921 remote_identifier: REMOTE_PORT.into()
3922 })
3923 );
3924 }
3925
3926 #[ip_test(I)]
3927 fn test_send_to<I: TestIpExt>() {
3928 set_logger_for_test();
3929
3930 let local_ip = local_ip::<I>();
3931 let remote_ip = remote_ip::<I>();
3932 let other_remote_ip = I::get_other_ip_address(3);
3933
3934 let mut ctx =
3935 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
3936 vec![local_ip],
3937 vec![remote_ip, other_remote_ip],
3938 ));
3939 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3940
3941 let socket = api.create();
3942 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3943 .expect("listen should succeed");
3944 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
3945 .expect("connect should succeed");
3946
3947 let body = [1, 2, 3, 4, 5];
3948 api.send_to(
3950 &socket,
3951 Some(ZonedAddr::Unzoned(other_remote_ip)),
3952 REMOTE_PORT.into(),
3953 Buf::new(body.to_vec(), ..),
3954 )
3955 .expect("send_to failed");
3956
3957 let info = api.get_info(&socket);
3959 let info = assert_matches!(info, SocketInfo::Connected(info) => info);
3960 assert_eq!(info.local_ip.into_inner(), ZonedAddr::Unzoned(local_ip));
3961 assert_eq!(info.remote_ip.into_inner(), ZonedAddr::Unzoned(remote_ip));
3962 assert_eq!(info.remote_identifier, u16::from(REMOTE_PORT));
3963
3964 let (meta, frame_body) =
3966 assert_matches!(api.core_ctx().bound_sockets.ip_socket_ctx.frames(), [frame] => frame);
3967 let SendIpPacketMeta {
3968 device: _,
3969 src_ip,
3970 dst_ip,
3971 destination,
3972 proto,
3973 ttl: _,
3974 mtu: _,
3975 dscp_and_ecn: _,
3976 } = meta.try_as::<I>().unwrap();
3977
3978 assert_eq!(destination, &IpPacketDestination::Neighbor(other_remote_ip));
3979 assert_eq!(src_ip, &local_ip);
3980 assert_eq!(dst_ip, &other_remote_ip);
3981 assert_eq!(proto, &I::Proto::from(IpProto::Udp));
3982 let mut buf = &frame_body[..];
3983 let udp_packet = UdpPacket::parse(&mut buf, UdpParseArgs::new(src_ip.get(), dst_ip.get()))
3984 .expect("Parsed sent UDP packet");
3985 assert_eq!(udp_packet.src_port().unwrap(), LOCAL_PORT);
3986 assert_eq!(udp_packet.dst_port(), REMOTE_PORT);
3987 assert_eq!(udp_packet.body(), &body[..]);
3988 }
3989
3990 #[ip_test(I)]
3994 fn test_send_udp_conn_failure<I: TestIpExt>() {
3995 set_logger_for_test();
3996 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3997 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3998 let remote_ip = remote_ip::<I>();
3999 let socket = api.create();
4001 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4002 .expect("connect failed");
4003
4004 api.core_ctx().bound_sockets.ip_socket_ctx.frames.set_should_error_for_frame(
4006 |_frame_meta| Some(SendFrameErrorReason::SizeConstraintsViolation),
4007 );
4008
4009 let send_err = api.send(&socket, Buf::new(Vec::new(), ..)).unwrap_err();
4011 assert_eq!(send_err, Either::Left(SendError::IpSock(IpSockSendError::Mtu)));
4012
4013 let expects_with_socket =
4014 || CounterExpectationsWithSocket { tx: 1, tx_error: 1, ..Default::default() };
4015 assert_counters(
4016 api.core_ctx(),
4017 expects_with_socket(),
4018 Default::default(),
4019 [(&socket, expects_with_socket())],
4020 )
4021 }
4022
4023 #[ip_test(I)]
4024 fn test_send_udp_conn_device_removed<I: TestIpExt>() {
4025 set_logger_for_test();
4026 let device = FakeReferencyDeviceId::default();
4027 let mut ctx =
4028 FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_with_device::<I>(device.clone()));
4029 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4030 let remote_ip = remote_ip::<I>();
4031 let socket = api.create();
4032 api.set_device(&socket, Some(&device)).unwrap();
4033 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4034 .expect("connect failed");
4035
4036 for (device_removed, expected_res) in [
4037 (false, Ok(())),
4038 (
4039 true,
4040 Err(Either::Left(SendError::IpSock(IpSockSendError::Unroutable(
4041 ResolveRouteError::Unreachable,
4042 )))),
4043 ),
4044 ] {
4045 if device_removed {
4046 device.mark_removed();
4047 }
4048
4049 assert_eq!(api.send(&socket, Buf::new(Vec::new(), ..)), expected_res)
4050 }
4051 }
4052
4053 #[ip_test(I)]
4054 #[test_case(false, ShutdownType::Send; "shutdown send then send")]
4055 #[test_case(false, ShutdownType::SendAndReceive; "shutdown both then send")]
4056 #[test_case(true, ShutdownType::Send; "shutdown send then sendto")]
4057 #[test_case(true, ShutdownType::SendAndReceive; "shutdown both then sendto")]
4058 fn test_send_udp_after_shutdown<I: TestIpExt>(send_to: bool, shutdown: ShutdownType) {
4059 set_logger_for_test();
4060
4061 #[derive(Debug)]
4062 struct NotWriteableError;
4063
4064 let send = |remote_ip, api: &mut UdpApi<_, _>, id| -> Result<(), NotWriteableError> {
4065 match remote_ip {
4066 Some(remote_ip) => api.send_to(
4067 id,
4068 Some(remote_ip),
4069 REMOTE_PORT.into(),
4070 Buf::new(Vec::new(), ..),
4071 )
4072 .map_err(
4073 |e| assert_matches!(e, Either::Right(SendToError::NotWriteable) => NotWriteableError)
4074 ),
4075 None => api.send(
4076 id,
4077 Buf::new(Vec::new(), ..),
4078 )
4079 .map_err(|e| assert_matches!(e, Either::Left(SendError::NotWriteable) => NotWriteableError)),
4080 }
4081 };
4082
4083 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4084 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4085
4086 let remote_ip = ZonedAddr::Unzoned(remote_ip::<I>());
4087 let send_to_ip = send_to.then_some(remote_ip);
4088
4089 let socket = api.create();
4090 api.connect(&socket, Some(remote_ip), REMOTE_PORT.into()).expect("connect failed");
4091
4092 send(send_to_ip, &mut api, &socket).expect("can send");
4093 api.shutdown(&socket, shutdown).expect("is connected");
4094
4095 assert_matches!(send(send_to_ip, &mut api, &socket), Err(NotWriteableError));
4096 }
4097
4098 #[ip_test(I)]
4099 #[test_case(ShutdownType::Receive; "receive")]
4100 #[test_case(ShutdownType::SendAndReceive; "both")]
4101 fn test_marked_for_receive_shutdown<I: TestIpExt>(which: ShutdownType) {
4102 set_logger_for_test();
4103
4104 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4105 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4106
4107 let socket = api.create();
4108 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip::<I>())), Some(LOCAL_PORT))
4109 .expect("can bind");
4110 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip::<I>())), REMOTE_PORT.into())
4111 .expect("can connect");
4112
4113 let meta = UdpPacketMeta::<I> {
4117 src_ip: remote_ip::<I>().get(),
4118 src_port: Some(REMOTE_PORT),
4119 dst_ip: local_ip::<I>().get(),
4120 dst_port: LOCAL_PORT,
4121 dscp_and_ecn: DscpAndEcn::default(),
4122 };
4123 let packet = [1, 1, 1, 1];
4124 let (core_ctx, bindings_ctx) = api.contexts();
4125
4126 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta.clone(), &packet[..])
4127 .expect("receive udp packet should succeed");
4128
4129 assert_eq!(
4130 bindings_ctx.state.socket_data(),
4131 HashMap::from([(socket.downgrade(), vec![&packet[..]])])
4132 );
4133 api.shutdown(&socket, which).expect("is connected");
4134 let (core_ctx, bindings_ctx) = api.contexts();
4135 assert_matches!(
4136 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta.clone(), &packet[..]),
4137 Err(TransportReceiveError::PortUnreachable)
4138 );
4139 assert_eq!(
4140 bindings_ctx.state.socket_data(),
4141 HashMap::from([(socket.downgrade(), vec![&packet[..]])])
4142 );
4143
4144 api.shutdown(&socket, ShutdownType::Send).expect("is connected");
4146 let (core_ctx, bindings_ctx) = api.contexts();
4147 assert_matches!(
4148 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta, &packet[..]),
4149 Err(TransportReceiveError::PortUnreachable)
4150 );
4151 assert_eq!(
4152 bindings_ctx.state.socket_data(),
4153 HashMap::from([(socket.downgrade(), vec![&packet[..]])])
4154 );
4155 }
4156
4157 #[ip_test(I)]
4160 fn test_udp_demux<I: TestIpExt>() {
4161 set_logger_for_test();
4162 let local_ip = local_ip::<I>();
4163 let remote_ip_a = I::get_other_ip_address(70);
4164 let remote_ip_b = I::get_other_ip_address(72);
4165 let local_port_a = NonZeroU16::new(100).unwrap();
4166 let local_port_b = NonZeroU16::new(101).unwrap();
4167 let local_port_c = NonZeroU16::new(102).unwrap();
4168 let local_port_d = NonZeroU16::new(103).unwrap();
4169
4170 let mut ctx =
4171 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
4172 vec![local_ip],
4173 vec![remote_ip_a, remote_ip_b],
4174 ));
4175 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4176
4177 let [conn1, conn2] = [remote_ip_a, remote_ip_b].map(|remote_ip| {
4181 let socket = api.create();
4182 api.set_posix_reuse_port(&socket, true).expect("is unbound");
4183 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(local_port_d))
4184 .expect("listen_udp failed");
4185 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4186 .expect("connect failed");
4187 socket
4188 });
4189 let list1 = api.create();
4190 api.listen(&list1, Some(ZonedAddr::Unzoned(local_ip)), Some(local_port_a))
4191 .expect("listen_udp failed");
4192 let list2 = api.create();
4193 api.listen(&list2, Some(ZonedAddr::Unzoned(local_ip)), Some(local_port_b))
4194 .expect("listen_udp failed");
4195 let wildcard_list = api.create();
4196 api.listen(&wildcard_list, None, Some(local_port_c)).expect("listen_udp failed");
4197
4198 let mut expectations = HashMap::<WeakUdpSocketId<I, _, _>, SocketReceived<I>>::new();
4199 let meta = UdpPacketMeta {
4202 src_ip: remote_ip_a.get(),
4203 src_port: Some(REMOTE_PORT),
4204 dst_ip: local_ip.get(),
4205 dst_port: local_port_d,
4206 dscp_and_ecn: DscpAndEcn::default(),
4207 };
4208 let body_conn1 = [1, 1, 1, 1];
4209 let (core_ctx, bindings_ctx) = api.contexts();
4210 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta.clone(), &body_conn1[..])
4211 .expect("receive udp packet should succeed");
4212 expectations
4213 .entry(conn1.downgrade())
4214 .or_default()
4215 .packets
4216 .push(ReceivedPacket { meta: meta, body: body_conn1.into() });
4217 assert_eq!(bindings_ctx.state.received(), &expectations);
4218
4219 let meta = UdpPacketMeta {
4220 src_ip: remote_ip_b.get(),
4221 src_port: Some(REMOTE_PORT),
4222 dst_ip: local_ip.get(),
4223 dst_port: local_port_d,
4224 dscp_and_ecn: DscpAndEcn::default(),
4225 };
4226 let body_conn2 = [2, 2, 2, 2];
4227 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta.clone(), &body_conn2[..])
4228 .expect("receive udp packet should succeed");
4229 expectations
4230 .entry(conn2.downgrade())
4231 .or_default()
4232 .packets
4233 .push(ReceivedPacket { meta: meta, body: body_conn2.into() });
4234 assert_eq!(bindings_ctx.state.received(), &expectations);
4235
4236 let meta = UdpPacketMeta {
4237 src_ip: remote_ip_a.get(),
4238 src_port: Some(REMOTE_PORT),
4239 dst_ip: local_ip.get(),
4240 dst_port: local_port_a,
4241 dscp_and_ecn: DscpAndEcn::default(),
4242 };
4243 let body_list1 = [3, 3, 3, 3];
4244 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta.clone(), &body_list1[..])
4245 .expect("receive udp packet should succeed");
4246 expectations
4247 .entry(list1.downgrade())
4248 .or_default()
4249 .packets
4250 .push(ReceivedPacket { meta: meta, body: body_list1.into() });
4251 assert_eq!(bindings_ctx.state.received(), &expectations);
4252
4253 let meta = UdpPacketMeta {
4254 src_ip: remote_ip_a.get(),
4255 src_port: Some(REMOTE_PORT),
4256 dst_ip: local_ip.get(),
4257 dst_port: local_port_b,
4258 dscp_and_ecn: DscpAndEcn::default(),
4259 };
4260 let body_list2 = [4, 4, 4, 4];
4261 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta.clone(), &body_list2[..])
4262 .expect("receive udp packet should succeed");
4263 expectations
4264 .entry(list2.downgrade())
4265 .or_default()
4266 .packets
4267 .push(ReceivedPacket { meta: meta, body: body_list2.into() });
4268 assert_eq!(bindings_ctx.state.received(), &expectations);
4269
4270 let meta = UdpPacketMeta {
4271 src_ip: remote_ip_a.get(),
4272 src_port: Some(REMOTE_PORT),
4273 dst_ip: local_ip.get(),
4274 dst_port: local_port_c,
4275 dscp_and_ecn: DscpAndEcn::default(),
4276 };
4277 let body_wildcard_list = [5, 5, 5, 5];
4278 receive_udp_packet(
4279 core_ctx,
4280 bindings_ctx,
4281 FakeDeviceId,
4282 meta.clone(),
4283 &body_wildcard_list[..],
4284 )
4285 .expect("receive udp packet should succeed");
4286 expectations
4287 .entry(wildcard_list.downgrade())
4288 .or_default()
4289 .packets
4290 .push(ReceivedPacket { meta: meta, body: body_wildcard_list.into() });
4291 assert_eq!(bindings_ctx.state.received(), &expectations);
4292 }
4293
4294 #[ip_test(I)]
4296 fn test_wildcard_listeners<I: TestIpExt>() {
4297 set_logger_for_test();
4298 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4299 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4300 let local_ip_a = I::get_other_ip_address(1);
4301 let local_ip_b = I::get_other_ip_address(2);
4302 let remote_ip_a = I::get_other_ip_address(70);
4303 let remote_ip_b = I::get_other_ip_address(72);
4304 let listener = api.create();
4305 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen_udp failed");
4306
4307 let body = [1, 2, 3, 4, 5];
4308 let (core_ctx, bindings_ctx) = api.contexts();
4309 let meta_1 = UdpPacketMeta {
4310 src_ip: remote_ip_a.get(),
4311 src_port: Some(REMOTE_PORT),
4312 dst_ip: local_ip_a.get(),
4313 dst_port: LOCAL_PORT,
4314 dscp_and_ecn: DscpAndEcn::default(),
4315 };
4316 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta_1.clone(), &body[..])
4317 .expect("receive udp packet should succeed");
4318
4319 let meta_2 = UdpPacketMeta {
4321 src_ip: remote_ip_b.get(),
4322 src_port: Some(REMOTE_PORT),
4323 dst_ip: local_ip_b.get(),
4324 dst_port: LOCAL_PORT,
4325 dscp_and_ecn: DscpAndEcn::default(),
4326 };
4327 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta_2.clone(), &body[..])
4328 .expect("receive udp packet should succeed");
4329
4330 assert_eq!(
4332 bindings_ctx.state.received::<I>(),
4333 &HashMap::from([(
4334 listener.downgrade(),
4335 SocketReceived {
4336 packets: vec![
4337 ReceivedPacket { meta: meta_1, body: body.into() },
4338 ReceivedPacket { meta: meta_2, body: body.into() }
4339 ]
4340 }
4341 )])
4342 );
4343 }
4344
4345 #[ip_test(I)]
4346 fn test_receive_source_port_zero_on_listener<I: TestIpExt>() {
4347 set_logger_for_test();
4348 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4349 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4350 let listener = api.create();
4351 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen_udp failed");
4352
4353 let body = [];
4354 let meta = UdpPacketMeta::<I> {
4355 src_ip: I::TEST_ADDRS.remote_ip.get(),
4356 src_port: None,
4357 dst_ip: I::TEST_ADDRS.local_ip.get(),
4358 dst_port: LOCAL_PORT,
4359 dscp_and_ecn: DscpAndEcn::default(),
4360 };
4361
4362 let (core_ctx, bindings_ctx) = api.contexts();
4363 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta.clone(), &body[..])
4364 .expect("receive udp packet should succeed");
4365 assert_eq!(
4367 bindings_ctx.state.received(),
4368 &HashMap::from([(
4369 listener.downgrade(),
4370 SocketReceived { packets: vec![ReceivedPacket { meta, body: vec![] }] }
4371 )])
4372 );
4373 }
4374
4375 #[ip_test(I)]
4376 fn test_receive_source_addr_unspecified_on_listener<I: TestIpExt>() {
4377 set_logger_for_test();
4378 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4379 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4380 let listener = api.create();
4381 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen_udp failed");
4382
4383 let meta = UdpPacketMeta::<I> {
4384 src_ip: I::UNSPECIFIED_ADDRESS,
4385 src_port: Some(REMOTE_PORT),
4386 dst_ip: I::TEST_ADDRS.local_ip.get(),
4387 dst_port: LOCAL_PORT,
4388 dscp_and_ecn: DscpAndEcn::default(),
4389 };
4390 let body = [];
4391 let (core_ctx, bindings_ctx) = api.contexts();
4392 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta, &body[..])
4393 .expect("receive udp packet should succeed");
4394 assert_eq!(
4396 bindings_ctx.state.socket_data(),
4397 HashMap::from([(listener.downgrade(), vec![&body[..]])])
4398 );
4399 }
4400
4401 #[ip_test(I)]
4402 #[test_case(NonZeroU16::new(u16::MAX).unwrap(), Ok(NonZeroU16::new(u16::MAX).unwrap()); "ephemeral available")]
4403 #[test_case(NonZeroU16::new(100).unwrap(), Err(LocalAddressError::FailedToAllocateLocalPort);
4404 "no ephemeral available")]
4405 fn test_bind_picked_port_all_others_taken<I: TestIpExt>(
4406 available_port: NonZeroU16,
4407 expected_result: Result<NonZeroU16, LocalAddressError>,
4408 ) {
4409 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4411 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4412
4413 for port in 1..=u16::MAX {
4414 let port = NonZeroU16::new(port).unwrap();
4415 if port == available_port {
4416 continue;
4417 }
4418 let unbound = api.create();
4419 api.listen(&unbound, None, Some(port)).expect("uncontested bind");
4420 }
4421
4422 let socket = api.create();
4425 let result = api
4426 .listen(&socket, None, None)
4427 .map(|()| {
4428 let info = api.get_info(&socket);
4429 assert_matches!(info, SocketInfo::Listener(info) => info.local_identifier)
4430 })
4431 .map_err(Either::unwrap_right);
4432 assert_eq!(result, expected_result);
4433 }
4434
4435 #[ip_test(I)]
4436 fn test_receive_multicast_packet<I: TestIpExt>() {
4437 set_logger_for_test();
4438 let local_ip = local_ip::<I>();
4439 let remote_ip = I::get_other_ip_address(70);
4440 let multicast_addr = I::get_multicast_addr(0);
4441 let multicast_addr_other = I::get_multicast_addr(1);
4442
4443 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
4444 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![remote_ip]),
4445 );
4446 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4447
4448 let any_listener = {
4451 let socket = api.create();
4452 api.set_posix_reuse_port(&socket, true).expect("is unbound");
4453 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen_udp failed");
4454 socket
4455 };
4456
4457 let specific_listeners = [(); 2].map(|()| {
4458 let socket = api.create();
4459 api.set_posix_reuse_port(&socket, true).expect("is unbound");
4460 api.listen(
4461 &socket,
4462 Some(ZonedAddr::Unzoned(multicast_addr.into_specified())),
4463 Some(LOCAL_PORT),
4464 )
4465 .expect("listen_udp failed");
4466 socket
4467 });
4468
4469 let (core_ctx, bindings_ctx) = api.contexts();
4470 let mut receive_packet = |body, local_ip: MulticastAddr<I::Addr>| {
4471 let meta = UdpPacketMeta::<I> {
4472 src_ip: remote_ip.get(),
4473 src_port: Some(REMOTE_PORT),
4474 dst_ip: local_ip.get(),
4475 dst_port: LOCAL_PORT,
4476 dscp_and_ecn: DscpAndEcn::default(),
4477 };
4478 let body = [body];
4479 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta, &body)
4480 .expect("receive udp packet should succeed")
4481 };
4482
4483 receive_packet(1, multicast_addr);
4485 receive_packet(2, multicast_addr);
4486
4487 receive_packet(3, multicast_addr_other);
4489
4490 assert_eq!(
4491 bindings_ctx.state.socket_data(),
4492 HashMap::from([
4493 (specific_listeners[0].downgrade(), vec![[1].as_slice(), &[2]]),
4494 (specific_listeners[1].downgrade(), vec![&[1], &[2]]),
4495 (any_listener.downgrade(), vec![&[1], &[2], &[3]]),
4496 ]),
4497 );
4498
4499 assert_counters(
4500 api.core_ctx(),
4501 CounterExpectationsWithSocket { rx_delivered: 7, ..Default::default() },
4502 CounterExpectationsWithoutSocket { rx: 3, ..Default::default() },
4503 [
4504 (
4505 &any_listener,
4506 CounterExpectationsWithSocket { rx_delivered: 3, ..Default::default() },
4507 ),
4508 (
4509 &specific_listeners[0],
4510 CounterExpectationsWithSocket { rx_delivered: 2, ..Default::default() },
4511 ),
4512 (
4513 &specific_listeners[1],
4514 CounterExpectationsWithSocket { rx_delivered: 2, ..Default::default() },
4515 ),
4516 ],
4517 )
4518 }
4519
4520 type UdpMultipleDevicesCtx = FakeUdpCtx<MultipleDevicesId>;
4521 type UdpMultipleDevicesCoreCtx = FakeUdpCoreCtx<MultipleDevicesId>;
4522 type UdpMultipleDevicesBindingsCtx = FakeUdpBindingsCtx<MultipleDevicesId>;
4523
4524 impl FakeUdpCoreCtx<MultipleDevicesId> {
4525 fn new_multiple_devices<I: TestIpExt>() -> Self {
4526 let remote_ips = vec![I::get_other_remote_ip_address(1)];
4527 Self::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
4528 MultipleDevicesId::all().into_iter().enumerate().map(|(i, device)| {
4529 FakeDeviceConfig {
4530 device,
4531 local_ips: vec![Self::local_ip(i)],
4532 remote_ips: remote_ips.clone(),
4533 }
4534 }),
4535 ))
4536 }
4537
4538 fn local_ip<A: IpAddress>(index: usize) -> SpecifiedAddr<A>
4539 where
4540 A::Version: TestIpExt,
4541 {
4542 A::Version::get_other_ip_address((index + 1).try_into().unwrap())
4543 }
4544 }
4545
4546 #[ip_test(I)]
4549 fn test_bound_to_device_receive<I: TestIpExt>() {
4550 set_logger_for_test();
4551 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
4552 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
4553 );
4554 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4555 let bound_first_device = api.create();
4556 api.listen(
4557 &bound_first_device,
4558 Some(ZonedAddr::Unzoned(local_ip::<I>())),
4559 Some(LOCAL_PORT),
4560 )
4561 .expect("listen should succeed");
4562 api.connect(
4563 &bound_first_device,
4564 Some(ZonedAddr::Unzoned(I::get_other_remote_ip_address(1))),
4565 REMOTE_PORT.into(),
4566 )
4567 .expect("connect should succeed");
4568 api.set_device(&bound_first_device, Some(&MultipleDevicesId::A))
4569 .expect("bind should succeed");
4570
4571 let bound_second_device = api.create();
4572 api.set_device(&bound_second_device, Some(&MultipleDevicesId::B)).unwrap();
4573 api.listen(&bound_second_device, None, Some(LOCAL_PORT)).expect("listen should succeed");
4574
4575 let meta = UdpPacketMeta::<I> {
4578 src_ip: I::get_other_remote_ip_address(1).get(),
4579 src_port: Some(REMOTE_PORT),
4580 dst_ip: local_ip::<I>().get(),
4581 dst_port: LOCAL_PORT,
4582 dscp_and_ecn: DscpAndEcn::default(),
4583 };
4584 let body = [1, 2, 3, 4, 5];
4585 let (core_ctx, bindings_ctx) = api.contexts();
4586 receive_udp_packet(core_ctx, bindings_ctx, MultipleDevicesId::A, meta.clone(), &body[..])
4587 .expect("receive udp packet should succeed");
4588
4589 receive_udp_packet(core_ctx, bindings_ctx, MultipleDevicesId::B, meta, &body[..])
4592 .expect("receive udp packet should succeed");
4593 assert_eq!(
4594 bindings_ctx.state.socket_data(),
4595 HashMap::from([
4596 (bound_first_device.downgrade(), vec![&body[..]]),
4597 (bound_second_device.downgrade(), vec![&body[..]])
4598 ])
4599 );
4600 }
4601
4602 #[ip_test(I)]
4605 fn test_bound_to_device_send<I: TestIpExt>() {
4606 set_logger_for_test();
4607 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
4608 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
4609 );
4610 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4611 let bound_on_devices = MultipleDevicesId::all().map(|device| {
4612 let socket = api.create();
4613 api.set_device(&socket, Some(&device)).unwrap();
4614 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen should succeed");
4615 socket
4616 });
4617
4618 let body = [1, 2, 3, 4, 5];
4620 for socket in bound_on_devices {
4621 api.send_to(
4622 &socket,
4623 Some(ZonedAddr::Unzoned(I::get_other_remote_ip_address(1))),
4624 REMOTE_PORT.into(),
4625 Buf::new(body.to_vec(), ..),
4626 )
4627 .expect("send should succeed");
4628 }
4629
4630 let mut received_devices = api
4631 .core_ctx()
4632 .bound_sockets
4633 .ip_socket_ctx
4634 .frames()
4635 .iter()
4636 .map(|(meta, _body)| {
4637 let SendIpPacketMeta {
4638 device,
4639 src_ip: _,
4640 dst_ip,
4641 destination: _,
4642 proto,
4643 ttl: _,
4644 mtu: _,
4645 dscp_and_ecn: _,
4646 } = meta.try_as::<I>().unwrap();
4647 assert_eq!(proto, &IpProto::Udp.into());
4648 assert_eq!(dst_ip, &I::get_other_remote_ip_address(1));
4649 *device
4650 })
4651 .collect::<Vec<_>>();
4652 received_devices.sort();
4653 assert_eq!(received_devices, &MultipleDevicesId::all());
4654 }
4655
4656 fn receive_packet_on<I: TestIpExt>(
4657 core_ctx: &mut UdpMultipleDevicesCoreCtx,
4658 bindings_ctx: &mut UdpMultipleDevicesBindingsCtx,
4659 device: MultipleDevicesId,
4660 ) -> Result<(), TransportReceiveError> {
4661 let meta = UdpPacketMeta::<I> {
4662 src_ip: I::get_other_remote_ip_address(1).get(),
4663 src_port: Some(REMOTE_PORT),
4664 dst_ip: local_ip::<I>().get(),
4665 dst_port: LOCAL_PORT,
4666 dscp_and_ecn: DscpAndEcn::default(),
4667 };
4668 const BODY: [u8; 5] = [1, 2, 3, 4, 5];
4669 receive_udp_packet(core_ctx, bindings_ctx, device, meta, &BODY[..])
4670 }
4671
4672 #[ip_test(I)]
4674 fn test_bind_unbind_device<I: TestIpExt>() {
4675 set_logger_for_test();
4676 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
4677 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
4678 );
4679 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4680
4681 let socket = api.create();
4683 api.set_device(&socket, Some(&MultipleDevicesId::A)).unwrap();
4684 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen failed");
4685
4686 let (core_ctx, bindings_ctx) = api.contexts();
4688 assert_matches!(
4689 receive_packet_on::<I>(core_ctx, bindings_ctx, MultipleDevicesId::B),
4690 Err(TransportReceiveError::PortUnreachable)
4691 );
4692 let received = &bindings_ctx.state.socket_data::<I>();
4693 assert_eq!(received, &HashMap::new());
4694
4695 api.set_device(&socket, None).expect("clearing bound device failed");
4697 let (core_ctx, bindings_ctx) = api.contexts();
4698 receive_packet_on::<I>(core_ctx, bindings_ctx, MultipleDevicesId::B)
4699 .expect("receive udp packet should succeed");
4700 let received = bindings_ctx.state.received::<I>().iter().collect::<Vec<_>>();
4701 let (rx_socket, socket_received) =
4702 assert_matches!(received[..], [(rx_socket, packets)] => (rx_socket, packets));
4703 assert_eq!(rx_socket, &socket);
4704 assert_matches!(socket_received.packets[..], [_]);
4705 }
4706
4707 #[ip_test(I)]
4709 fn test_unbind_device_fails<I: TestIpExt>() {
4710 set_logger_for_test();
4711 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
4712 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
4713 );
4714 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4715
4716 let bound_on_devices = MultipleDevicesId::all().map(|device| {
4717 let socket = api.create();
4718 api.set_device(&socket, Some(&device)).unwrap();
4719 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen should succeed");
4720 socket
4721 });
4722
4723 for socket in bound_on_devices {
4726 assert_matches!(
4727 api.set_device(&socket, None),
4728 Err(SocketError::Local(LocalAddressError::AddressInUse))
4729 );
4730 }
4731 }
4732
4733 #[ip_test(I)]
4736 fn test_bind_conn_socket_device_fails<I: TestIpExt>() {
4737 set_logger_for_test();
4738 let device_configs = HashMap::from(
4739 [(MultipleDevicesId::A, 1), (MultipleDevicesId::B, 2)].map(|(device, i)| {
4740 (
4741 device,
4742 FakeDeviceConfig {
4743 device,
4744 local_ips: vec![I::get_other_ip_address(i)],
4745 remote_ips: vec![I::get_other_remote_ip_address(i)],
4746 },
4747 )
4748 }),
4749 );
4750 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
4751 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
4752 device_configs.iter().map(|(_, v)| v).cloned(),
4753 )),
4754 );
4755 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4756 let socket = api.create();
4757 api.connect(
4758 &socket,
4759 Some(ZonedAddr::Unzoned(device_configs[&MultipleDevicesId::A].remote_ips[0])),
4760 REMOTE_PORT.into(),
4761 )
4762 .expect("connect should succeed");
4763
4764 assert_matches!(
4768 api.set_device(&socket, Some(&MultipleDevicesId::B)),
4769 Err(SocketError::Remote(RemoteAddressError::NoRoute))
4770 );
4771
4772 api.set_device(&socket, Some(&MultipleDevicesId::A)).expect("routing picked A already");
4774 }
4775
4776 #[ip_test(I)]
4777 fn test_bound_device_receive_multicast_packet<I: TestIpExt>() {
4778 set_logger_for_test();
4779 let remote_ip = I::get_other_ip_address(1);
4780 let multicast_addr = I::get_multicast_addr(0);
4781
4782 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
4783 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
4784 );
4785 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4786
4787 let bound_on_devices = MultipleDevicesId::all().map(|device| {
4791 let listener = api.create();
4792 api.set_device(&listener, Some(&device)).unwrap();
4793 api.set_posix_reuse_port(&listener, true).expect("is unbound");
4794 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen should succeed");
4795
4796 (device, listener)
4797 });
4798
4799 let listener = api.create();
4800 api.set_posix_reuse_port(&listener, true).expect("is unbound");
4801 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen should succeed");
4802
4803 fn index_for_device(id: MultipleDevicesId) -> u8 {
4804 match id {
4805 MultipleDevicesId::A => 0,
4806 MultipleDevicesId::B => 1,
4807 MultipleDevicesId::C => 2,
4808 }
4809 }
4810
4811 let (core_ctx, bindings_ctx) = api.contexts();
4812 let mut receive_packet = |remote_ip: SpecifiedAddr<I::Addr>, device: MultipleDevicesId| {
4813 let meta = UdpPacketMeta::<I> {
4814 src_ip: remote_ip.get(),
4815 src_port: Some(REMOTE_PORT),
4816 dst_ip: multicast_addr.get(),
4817 dst_port: LOCAL_PORT,
4818 dscp_and_ecn: DscpAndEcn::default(),
4819 };
4820 let body = vec![index_for_device(device)];
4821 receive_udp_packet(core_ctx, bindings_ctx, device, meta, &body)
4822 .expect("receive udp packet should succeed")
4823 };
4824
4825 for device in MultipleDevicesId::all() {
4829 receive_packet(remote_ip, device);
4830 }
4831
4832 let per_socket_data = bindings_ctx.state.socket_data();
4833 for (device, listener) in bound_on_devices {
4834 assert_eq!(per_socket_data[&listener.downgrade()], vec![&[index_for_device(device)]]);
4835 }
4836 let expected_listener_data = &MultipleDevicesId::all().map(|d| vec![index_for_device(d)]);
4837 assert_eq!(&per_socket_data[&listener.downgrade()], expected_listener_data);
4838 }
4839
4840 #[ip_test(I)]
4842 fn test_conn_unspecified_local_ip<I: TestIpExt>() {
4843 set_logger_for_test();
4844 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4845 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4846 let socket = api.create();
4847 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen_udp failed");
4848 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip::<I>())), REMOTE_PORT.into())
4849 .expect("connect failed");
4850 let info = api.get_info(&socket);
4851 assert_eq!(
4852 info,
4853 SocketInfo::Connected(datagram::ConnInfo {
4854 local_ip: StrictlyZonedAddr::new_unzoned_or_panic(local_ip::<I>()),
4855 local_identifier: LOCAL_PORT,
4856 remote_ip: StrictlyZonedAddr::new_unzoned_or_panic(remote_ip::<I>()),
4857 remote_identifier: REMOTE_PORT.into(),
4858 })
4859 );
4860 }
4861
4862 #[ip_test(I)]
4863 fn test_multicast_sendto<I: TestIpExt>() {
4864 set_logger_for_test();
4865
4866 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
4867 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
4868 );
4869
4870 for device in MultipleDevicesId::all().iter() {
4872 ctx.core_ctx
4873 .bound_sockets
4874 .ip_socket_ctx
4875 .state
4876 .add_subnet_route(*device, I::MULTICAST_SUBNET);
4877 }
4878
4879 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4880 let socket = api.create();
4881
4882 for (i, target_device) in MultipleDevicesId::all().iter().enumerate() {
4883 api.set_multicast_interface(&socket, Some(&target_device), I::VERSION)
4884 .expect("bind should succeed");
4885
4886 let multicast_ip = I::get_multicast_addr(i.try_into().unwrap());
4887 api.send_to(
4888 &socket,
4889 Some(ZonedAddr::Unzoned(multicast_ip.into())),
4890 REMOTE_PORT.into(),
4891 Buf::new(b"packet".to_vec(), ..),
4892 )
4893 .expect("send should succeed");
4894
4895 let packets = api.core_ctx().bound_sockets.ip_socket_ctx.take_frames();
4896 assert_eq!(packets.len(), 1usize);
4897 for (meta, _body) in packets {
4898 let meta = meta.try_as::<I>().unwrap();
4899 assert_eq!(meta.device, *target_device);
4900 assert_eq!(meta.proto, IpProto::Udp.into());
4901 assert_eq!(meta.src_ip, UdpMultipleDevicesCoreCtx::local_ip(i));
4902 assert_eq!(meta.dst_ip, multicast_ip.into());
4903 assert_eq!(meta.destination, IpPacketDestination::Multicast(multicast_ip));
4904 }
4905 }
4906 }
4907
4908 #[ip_test(I)]
4909 fn test_multicast_send<I: TestIpExt>() {
4910 set_logger_for_test();
4911
4912 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
4913 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
4914 );
4915
4916 for device in MultipleDevicesId::all().iter() {
4918 ctx.core_ctx
4919 .bound_sockets
4920 .ip_socket_ctx
4921 .state
4922 .add_subnet_route(*device, I::MULTICAST_SUBNET);
4923 }
4924
4925 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4926 let multicast_ip = I::get_multicast_addr(42);
4927
4928 for (i, target_device) in MultipleDevicesId::all().iter().enumerate() {
4929 let socket = api.create();
4930
4931 api.set_multicast_interface(&socket, Some(&target_device), I::VERSION)
4932 .expect("set_multicast_interface should succeed");
4933
4934 api.connect(&socket, Some(ZonedAddr::Unzoned(multicast_ip.into())), REMOTE_PORT.into())
4935 .expect("send should succeed");
4936
4937 api.send(&socket, Buf::new(b"packet".to_vec(), ..)).expect("send should succeed");
4938
4939 let packets = api.core_ctx().bound_sockets.ip_socket_ctx.take_frames();
4940 assert_eq!(packets.len(), 1usize);
4941 for (meta, _body) in packets {
4942 let meta = meta.try_as::<I>().unwrap();
4943 assert_eq!(meta.device, *target_device);
4944 assert_eq!(meta.proto, IpProto::Udp.into());
4945 assert_eq!(meta.src_ip, UdpMultipleDevicesCoreCtx::local_ip(i));
4946 assert_eq!(meta.dst_ip, multicast_ip.into());
4947 assert_eq!(meta.destination, IpPacketDestination::Multicast(multicast_ip));
4948 }
4949 }
4950 }
4951
4952 #[ip_test(I)]
4957 fn test_udp_local_port_alloc<I: TestIpExt>() {
4958 let local_ip = local_ip::<I>();
4959 let ip_a = I::get_other_ip_address(100);
4960 let ip_b = I::get_other_ip_address(200);
4961
4962 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
4963 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![ip_a, ip_b]),
4964 );
4965 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4966
4967 let conn_a = api.create();
4968 api.connect(&conn_a, Some(ZonedAddr::Unzoned(ip_a)), REMOTE_PORT.into())
4969 .expect("connect failed");
4970 let conn_b = api.create();
4971 api.connect(&conn_b, Some(ZonedAddr::Unzoned(ip_b)), REMOTE_PORT.into())
4972 .expect("connect failed");
4973 let conn_c = api.create();
4974 api.connect(&conn_c, Some(ZonedAddr::Unzoned(ip_a)), OTHER_REMOTE_PORT.into())
4975 .expect("connect failed");
4976 let conn_d = api.create();
4977 api.connect(&conn_d, Some(ZonedAddr::Unzoned(ip_a)), REMOTE_PORT.into())
4978 .expect("connect failed");
4979 let valid_range = &FakePortAlloc::<I>::EPHEMERAL_RANGE;
4980 let mut get_conn_port = |id| {
4981 let info = api.get_info(&id);
4982 let info = assert_matches!(info, SocketInfo::Connected(info) => info);
4983 let datagram::ConnInfo {
4984 local_ip: _,
4985 local_identifier,
4986 remote_ip: _,
4987 remote_identifier: _,
4988 } = info;
4989 local_identifier
4990 };
4991 let port_a = get_conn_port(conn_a).get();
4992 let port_b = get_conn_port(conn_b).get();
4993 let port_c = get_conn_port(conn_c).get();
4994 let port_d = get_conn_port(conn_d).get();
4995 assert!(valid_range.contains(&port_a));
4996 assert!(valid_range.contains(&port_b));
4997 assert!(valid_range.contains(&port_c));
4998 assert!(valid_range.contains(&port_d));
4999 assert_ne!(port_a, port_b);
5000 assert_ne!(port_a, port_c);
5001 assert_ne!(port_a, port_d);
5002 }
5003
5004 #[ip_test(I)]
5006 fn test_udp_retry_listen_after_removing_conflict<I: TestIpExt>() {
5007 set_logger_for_test();
5008 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5009 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5010
5011 let listen_unbound = |api: &mut UdpApi<_, _>, socket: &UdpSocketId<_, _, _>| {
5012 api.listen(socket, Some(ZonedAddr::Unzoned(local_ip::<I>())), Some(LOCAL_PORT))
5013 };
5014
5015 let listener = api.create();
5017 listen_unbound(&mut api, &listener)
5018 .expect("Initial call to listen_udp was expected to succeed");
5019
5020 let unbound = api.create();
5022 assert_eq!(
5023 listen_unbound(&mut api, &unbound),
5024 Err(Either::Right(LocalAddressError::AddressInUse))
5025 );
5026
5027 api.close(listener).into_removed();
5030
5031 listen_unbound(&mut api, &unbound).expect("listen should succeed");
5032 }
5033
5034 #[ip_test(I)]
5039 fn test_udp_listen_port_alloc<I: TestIpExt>() {
5040 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5041 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5042 let local_ip = local_ip::<I>();
5043
5044 let wildcard_list = api.create();
5045 api.listen(&wildcard_list, None, None).expect("listen_udp failed");
5046 let specified_list = api.create();
5047 api.listen(&specified_list, Some(ZonedAddr::Unzoned(local_ip)), None)
5048 .expect("listen_udp failed");
5049 let mut get_listener_port = |id| {
5050 let info = api.get_info(&id);
5051 let info = assert_matches!(info, SocketInfo::Listener(info) => info);
5052 let datagram::ListenerInfo { local_ip: _, local_identifier } = info;
5053 local_identifier
5054 };
5055 let wildcard_port = get_listener_port(wildcard_list);
5056 let specified_port = get_listener_port(specified_list);
5057 assert!(FakePortAlloc::<I>::EPHEMERAL_RANGE.contains(&wildcard_port.get()));
5058 assert!(FakePortAlloc::<I>::EPHEMERAL_RANGE.contains(&specified_port.get()));
5059 assert_ne!(wildcard_port, specified_port);
5060 }
5061
5062 #[ip_test(I)]
5063 fn test_bind_multiple_reuse_port<I: TestIpExt>() {
5064 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5065 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5066 let listeners = [(), ()].map(|()| {
5067 let socket = api.create();
5068 api.set_posix_reuse_port(&socket, true).expect("is unbound");
5069 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen_udp failed");
5070 socket
5071 });
5072
5073 for listener in listeners {
5074 assert_eq!(
5075 api.get_info(&listener),
5076 SocketInfo::Listener(datagram::ListenerInfo {
5077 local_ip: None,
5078 local_identifier: LOCAL_PORT
5079 })
5080 );
5081 }
5082 }
5083
5084 #[ip_test(I)]
5085 fn test_set_unset_reuse_port_unbound<I: TestIpExt>() {
5086 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5087 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5088 let unbound = api.create();
5089 api.set_posix_reuse_port(&unbound, true).expect("is unbound");
5090 api.set_posix_reuse_port(&unbound, false).expect("is unbound");
5091 api.listen(&unbound, None, Some(LOCAL_PORT)).expect("listen_udp failed");
5092
5093 assert_eq!(
5096 {
5097 let unbound = api.create();
5098 api.listen(&unbound, None, Some(LOCAL_PORT))
5099 },
5100 Err(Either::Right(LocalAddressError::AddressInUse))
5101 );
5102 }
5103
5104 #[ip_test(I)]
5105 #[test_case(bind_as_listener)]
5106 #[test_case(bind_as_connected)]
5107 fn test_set_unset_reuse_port_bound<I: TestIpExt>(
5108 set_up_socket: impl FnOnce(
5109 &mut UdpMultipleDevicesCtx,
5110 &UdpSocketId<
5111 I,
5112 FakeWeakDeviceId<MultipleDevicesId>,
5113 FakeUdpBindingsCtx<MultipleDevicesId>,
5114 >,
5115 ),
5116 ) {
5117 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5118 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5119 );
5120 let socket = UdpApi::<I, _>::new(ctx.as_mut()).create();
5121 set_up_socket(&mut ctx, &socket);
5122
5123 assert_matches!(
5126 UdpApi::<I, _>::new(ctx.as_mut()).set_posix_reuse_port(&socket, false),
5127 Err(ExpectedUnboundError)
5128 )
5129 }
5130
5131 #[ip_test(I)]
5133 fn test_remove_udp_conn<I: TestIpExt>() {
5134 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5135 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5136
5137 let local_ip = ZonedAddr::Unzoned(local_ip::<I>());
5138 let remote_ip = ZonedAddr::Unzoned(remote_ip::<I>());
5139 let socket = api.create();
5140 api.listen(&socket, Some(local_ip), Some(LOCAL_PORT)).unwrap();
5141 api.connect(&socket, Some(remote_ip), REMOTE_PORT.into()).expect("connect failed");
5142 api.close(socket).into_removed();
5143 }
5144
5145 #[ip_test(I)]
5147 fn test_remove_udp_listener<I: TestIpExt>() {
5148 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5149 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5150 let local_ip = ZonedAddr::Unzoned(local_ip::<I>());
5151
5152 let specified = api.create();
5154 api.listen(&specified, Some(local_ip), Some(LOCAL_PORT)).expect("listen_udp failed");
5155 api.close(specified).into_removed();
5156
5157 let wildcard = api.create();
5159 api.listen(&wildcard, None, Some(LOCAL_PORT)).expect("listen_udp failed");
5160 api.close(wildcard).into_removed();
5161 }
5162
5163 fn try_join_leave_multicast<I: TestIpExt>(
5164 mcast_addr: MulticastAddr<I::Addr>,
5165 interface: MulticastMembershipInterfaceSelector<I::Addr, MultipleDevicesId>,
5166 set_up_ctx: impl FnOnce(&mut UdpMultipleDevicesCtx),
5167 set_up_socket: impl FnOnce(
5168 &mut UdpMultipleDevicesCtx,
5169 &UdpSocketId<
5170 I,
5171 FakeWeakDeviceId<MultipleDevicesId>,
5172 FakeUdpBindingsCtx<MultipleDevicesId>,
5173 >,
5174 ),
5175 ) -> (
5176 Result<(), SetMulticastMembershipError>,
5177 HashMap<(MultipleDevicesId, MulticastAddr<I::Addr>), NonZeroUsize>,
5178 ) {
5179 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5180 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5181 );
5182 set_up_ctx(&mut ctx);
5183
5184 let socket = UdpApi::<I, _>::new(ctx.as_mut()).create();
5185 set_up_socket(&mut ctx, &socket);
5186 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5187 let result = api.set_multicast_membership(&socket, mcast_addr, interface, true);
5188
5189 let memberships_snapshot =
5190 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>();
5191 if let Ok(()) = result {
5192 api.set_multicast_membership(&socket, mcast_addr, interface, false)
5193 .expect("leaving group failed");
5194 }
5195 assert_eq!(
5196 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5197 HashMap::default()
5198 );
5199
5200 (result, memberships_snapshot)
5201 }
5202
5203 fn leave_unbound<I: TestIpExt>(
5204 _ctx: &mut UdpMultipleDevicesCtx,
5205 _unbound: &UdpSocketId<
5206 I,
5207 FakeWeakDeviceId<MultipleDevicesId>,
5208 FakeUdpBindingsCtx<MultipleDevicesId>,
5209 >,
5210 ) {
5211 }
5212
5213 fn bind_as_listener<I: TestIpExt>(
5214 ctx: &mut UdpMultipleDevicesCtx,
5215 unbound: &UdpSocketId<
5216 I,
5217 FakeWeakDeviceId<MultipleDevicesId>,
5218 FakeUdpBindingsCtx<MultipleDevicesId>,
5219 >,
5220 ) {
5221 UdpApi::<I, _>::new(ctx.as_mut())
5222 .listen(unbound, Some(ZonedAddr::Unzoned(local_ip::<I>())), Some(LOCAL_PORT))
5223 .expect("listen should succeed")
5224 }
5225
5226 fn bind_as_connected<I: TestIpExt>(
5227 ctx: &mut UdpMultipleDevicesCtx,
5228 unbound: &UdpSocketId<
5229 I,
5230 FakeWeakDeviceId<MultipleDevicesId>,
5231 FakeUdpBindingsCtx<MultipleDevicesId>,
5232 >,
5233 ) {
5234 UdpApi::<I, _>::new(ctx.as_mut())
5235 .connect(
5236 unbound,
5237 Some(ZonedAddr::Unzoned(I::get_other_remote_ip_address(1))),
5238 REMOTE_PORT.into(),
5239 )
5240 .expect("connect should succeed")
5241 }
5242
5243 fn iface_id<A: IpAddress>(
5244 id: MultipleDevicesId,
5245 ) -> MulticastMembershipInterfaceSelector<A, MultipleDevicesId> {
5246 MulticastInterfaceSelector::Interface(id).into()
5247 }
5248 fn iface_addr<A: IpAddress>(
5249 addr: SpecifiedAddr<A>,
5250 ) -> MulticastMembershipInterfaceSelector<A, MultipleDevicesId> {
5251 MulticastInterfaceSelector::LocalAddress(addr).into()
5252 }
5253
5254 #[ip_test(I)]
5255 #[test_case(iface_id(MultipleDevicesId::A), leave_unbound::<I>; "device_no_addr_unbound")]
5256 #[test_case(iface_addr(local_ip::<I>()), leave_unbound::<I>; "addr_no_device_unbound")]
5257 #[test_case(MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute, leave_unbound::<I>;
5258 "any_interface_unbound")]
5259 #[test_case(iface_id(MultipleDevicesId::A), bind_as_listener::<I>; "device_no_addr_listener")]
5260 #[test_case(iface_addr(local_ip::<I>()), bind_as_listener::<I>; "addr_no_device_listener")]
5261 #[test_case(MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute, bind_as_listener::<I>;
5262 "any_interface_listener")]
5263 #[test_case(iface_id(MultipleDevicesId::A), bind_as_connected::<I>; "device_no_addr_connected")]
5264 #[test_case(iface_addr(local_ip::<I>()), bind_as_connected::<I>; "addr_no_device_connected")]
5265 #[test_case(MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute, bind_as_connected::<I>;
5266 "any_interface_connected")]
5267 fn test_join_leave_multicast_succeeds<I: TestIpExt>(
5268 interface: MulticastMembershipInterfaceSelector<I::Addr, MultipleDevicesId>,
5269 set_up_socket: impl FnOnce(
5270 &mut UdpMultipleDevicesCtx,
5271 &UdpSocketId<
5272 I,
5273 FakeWeakDeviceId<MultipleDevicesId>,
5274 FakeUdpBindingsCtx<MultipleDevicesId>,
5275 >,
5276 ),
5277 ) {
5278 let mcast_addr = I::get_multicast_addr(3);
5279
5280 let set_up_ctx = |ctx: &mut UdpMultipleDevicesCtx| {
5281 match interface {
5284 MulticastMembershipInterfaceSelector::Specified(_) => {}
5285 MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute => {
5286 ctx.core_ctx
5287 .bound_sockets
5288 .ip_socket_ctx
5289 .state
5290 .add_route(MultipleDevicesId::A, mcast_addr.into_specified().into());
5291 }
5292 }
5293 };
5294
5295 let (result, ip_options) =
5296 try_join_leave_multicast(mcast_addr, interface, set_up_ctx, set_up_socket);
5297 assert_eq!(result, Ok(()));
5298 assert_eq!(
5299 ip_options,
5300 HashMap::from([((MultipleDevicesId::A, mcast_addr), NonZeroUsize::new(1).unwrap())])
5301 );
5302 }
5303
5304 #[ip_test(I)]
5305 #[test_case(leave_unbound::<I>; "unbound")]
5306 #[test_case(bind_as_listener::<I>; "listener")]
5307 #[test_case(bind_as_connected::<I>; "connected")]
5308 fn test_join_multicast_fails_without_route<I: TestIpExt>(
5309 set_up_socket: impl FnOnce(
5310 &mut UdpMultipleDevicesCtx,
5311 &UdpSocketId<
5312 I,
5313 FakeWeakDeviceId<MultipleDevicesId>,
5314 FakeUdpBindingsCtx<MultipleDevicesId>,
5315 >,
5316 ),
5317 ) {
5318 let mcast_addr = I::get_multicast_addr(3);
5319
5320 let (result, ip_options) = try_join_leave_multicast(
5321 mcast_addr,
5322 MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute,
5323 |_: &mut UdpMultipleDevicesCtx| { },
5324 set_up_socket,
5325 );
5326 assert_eq!(result, Err(SetMulticastMembershipError::NoDeviceAvailable));
5327 assert_eq!(ip_options, HashMap::new());
5328 }
5329
5330 #[ip_test(I)]
5331 #[test_case(MultipleDevicesId::A, Some(local_ip::<I>()), leave_unbound, Ok(());
5332 "with_ip_unbound")]
5333 #[test_case(MultipleDevicesId::A, None, leave_unbound, Ok(());
5334 "without_ip_unbound")]
5335 #[test_case(MultipleDevicesId::A, Some(local_ip::<I>()), bind_as_listener, Ok(());
5336 "with_ip_listener")]
5337 #[test_case(MultipleDevicesId::A, Some(local_ip::<I>()), bind_as_connected, Ok(());
5338 "with_ip_connected")]
5339 fn test_join_leave_multicast_interface_inferred_from_bound_device<I: TestIpExt>(
5340 bound_device: MultipleDevicesId,
5341 interface_addr: Option<SpecifiedAddr<I::Addr>>,
5342 set_up_socket: impl FnOnce(
5343 &mut UdpMultipleDevicesCtx,
5344 &UdpSocketId<
5345 I,
5346 FakeWeakDeviceId<MultipleDevicesId>,
5347 FakeUdpBindingsCtx<MultipleDevicesId>,
5348 >,
5349 ),
5350 expected_result: Result<(), SetMulticastMembershipError>,
5351 ) {
5352 let mcast_addr = I::get_multicast_addr(3);
5353 let (result, ip_options) = try_join_leave_multicast(
5354 mcast_addr,
5355 interface_addr
5356 .map(MulticastInterfaceSelector::LocalAddress)
5357 .map(Into::into)
5358 .unwrap_or(MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute),
5359 |_: &mut UdpMultipleDevicesCtx| { },
5360 |ctx, unbound| {
5361 UdpApi::<I, _>::new(ctx.as_mut())
5362 .set_device(&unbound, Some(&bound_device))
5363 .unwrap();
5364 set_up_socket(ctx, &unbound)
5365 },
5366 );
5367 assert_eq!(result, expected_result);
5368 assert_eq!(
5369 ip_options,
5370 expected_result.map_or(HashMap::default(), |()| HashMap::from([(
5371 (bound_device, mcast_addr),
5372 NonZeroUsize::new(1).unwrap()
5373 )]))
5374 );
5375 }
5376
5377 #[ip_test(I)]
5378 fn test_multicast_membership_with_removed_device<I: TestIpExt>() {
5379 let device = FakeReferencyDeviceId::default();
5380 let mut ctx =
5381 FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_with_device::<I>(device.clone()));
5382 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5383
5384 let unbound = api.create();
5385 api.set_device(&unbound, Some(&device)).unwrap();
5386
5387 device.mark_removed();
5388
5389 let group = I::get_multicast_addr(4);
5390 assert_eq!(
5391 api.set_multicast_membership(
5392 &unbound,
5393 group,
5394 MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute,
5396 true,
5397 ),
5398 Err(SetMulticastMembershipError::DeviceDoesNotExist),
5399 );
5400
5401 assert_eq!(
5407 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5408 HashMap::default(),
5409 );
5410 }
5411
5412 #[ip_test(I)]
5413 fn test_remove_udp_unbound_leaves_multicast_groups<I: TestIpExt>() {
5414 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5415 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5416 );
5417 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5418
5419 let unbound = api.create();
5420 let group = I::get_multicast_addr(4);
5421 api.set_multicast_membership(
5422 &unbound,
5423 group,
5424 MulticastInterfaceSelector::LocalAddress(local_ip::<I>()).into(),
5425 true,
5426 )
5427 .expect("join group failed");
5428
5429 assert_eq!(
5430 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5431 HashMap::from([((MultipleDevicesId::A, group), NonZeroUsize::new(1).unwrap())])
5432 );
5433
5434 api.close(unbound).into_removed();
5435 assert_eq!(
5436 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5437 HashMap::default()
5438 );
5439 }
5440
5441 #[ip_test(I)]
5442 fn test_remove_udp_listener_leaves_multicast_groups<I: TestIpExt>() {
5443 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5444 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5445 );
5446 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5447 let local_ip = local_ip::<I>();
5448
5449 let socket = api.create();
5450 let first_group = I::get_multicast_addr(4);
5451 api.set_multicast_membership(
5452 &socket,
5453 first_group,
5454 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
5455 true,
5456 )
5457 .expect("join group failed");
5458
5459 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
5460 .expect("listen_udp failed");
5461 let second_group = I::get_multicast_addr(5);
5462 api.set_multicast_membership(
5463 &socket,
5464 second_group,
5465 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
5466 true,
5467 )
5468 .expect("join group failed");
5469
5470 assert_eq!(
5471 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5472 HashMap::from([
5473 ((MultipleDevicesId::A, first_group), NonZeroUsize::new(1).unwrap()),
5474 ((MultipleDevicesId::A, second_group), NonZeroUsize::new(1).unwrap())
5475 ])
5476 );
5477
5478 api.close(socket).into_removed();
5479 assert_eq!(
5480 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5481 HashMap::default()
5482 );
5483 }
5484
5485 #[ip_test(I)]
5486 fn test_remove_udp_connected_leaves_multicast_groups<I: TestIpExt>() {
5487 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5488 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5489 );
5490 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5491 let local_ip = local_ip::<I>();
5492
5493 let socket = api.create();
5494 let first_group = I::get_multicast_addr(4);
5495 api.set_multicast_membership(
5496 &socket,
5497 first_group,
5498 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
5499 true,
5500 )
5501 .expect("join group failed");
5502
5503 api.connect(
5504 &socket,
5505 Some(ZonedAddr::Unzoned(I::get_other_remote_ip_address(1))),
5506 REMOTE_PORT.into(),
5507 )
5508 .expect("connect failed");
5509
5510 let second_group = I::get_multicast_addr(5);
5511 api.set_multicast_membership(
5512 &socket,
5513 second_group,
5514 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
5515 true,
5516 )
5517 .expect("join group failed");
5518
5519 assert_eq!(
5520 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5521 HashMap::from([
5522 ((MultipleDevicesId::A, first_group), NonZeroUsize::new(1).unwrap()),
5523 ((MultipleDevicesId::A, second_group), NonZeroUsize::new(1).unwrap())
5524 ])
5525 );
5526
5527 api.close(socket).into_removed();
5528 assert_eq!(
5529 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5530 HashMap::default()
5531 );
5532 }
5533
5534 #[ip_test(I)]
5535 #[should_panic(expected = "listen again failed")]
5536 fn test_listen_udp_removes_unbound<I: TestIpExt>() {
5537 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5538 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5539 let local_ip = local_ip::<I>();
5540 let socket = api.create();
5541
5542 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
5543 .expect("listen_udp failed");
5544
5545 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(OTHER_LOCAL_PORT))
5548 .expect("listen again failed");
5549 }
5550
5551 #[ip_test(I)]
5552 fn test_get_conn_info<I: TestIpExt>() {
5553 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5554 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5555 let local_ip = ZonedAddr::Unzoned(local_ip::<I>());
5556 let remote_ip = ZonedAddr::Unzoned(remote_ip::<I>());
5557 let socket = api.create();
5559 api.listen(&socket, Some(local_ip), Some(LOCAL_PORT)).expect("listen_udp failed");
5560 api.connect(&socket, Some(remote_ip), REMOTE_PORT.into()).expect("connect failed");
5561 let info = api.get_info(&socket);
5562 let info = assert_matches!(info, SocketInfo::Connected(info) => info);
5563 assert_eq!(info.local_ip.into_inner(), local_ip.map_zone(FakeWeakDeviceId));
5564 assert_eq!(info.local_identifier, LOCAL_PORT);
5565 assert_eq!(info.remote_ip.into_inner(), remote_ip.map_zone(FakeWeakDeviceId));
5566 assert_eq!(info.remote_identifier, u16::from(REMOTE_PORT));
5567 }
5568
5569 #[ip_test(I)]
5570 fn test_get_listener_info<I: TestIpExt>() {
5571 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5572 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5573 let local_ip = ZonedAddr::Unzoned(local_ip::<I>());
5574
5575 let specified = api.create();
5577 api.listen(&specified, Some(local_ip), Some(LOCAL_PORT)).expect("listen_udp failed");
5578 let info = api.get_info(&specified);
5579 let info = assert_matches!(info, SocketInfo::Listener(info) => info);
5580 assert_eq!(info.local_ip.unwrap().into_inner(), local_ip.map_zone(FakeWeakDeviceId));
5581 assert_eq!(info.local_identifier, LOCAL_PORT);
5582
5583 let wildcard = api.create();
5585 api.listen(&wildcard, None, Some(OTHER_LOCAL_PORT)).expect("listen_udp failed");
5586 let info = api.get_info(&wildcard);
5587 let info = assert_matches!(info, SocketInfo::Listener(info) => info);
5588 assert_eq!(info.local_ip, None);
5589 assert_eq!(info.local_identifier, OTHER_LOCAL_PORT);
5590 }
5591
5592 #[ip_test(I)]
5593 fn test_get_reuse_port<I: TestIpExt>() {
5594 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5595 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5596 let first = api.create();
5597 assert_eq!(api.get_posix_reuse_port(&first), false);
5598
5599 api.set_posix_reuse_port(&first, true).expect("is unbound");
5600
5601 assert_eq!(api.get_posix_reuse_port(&first), true);
5602
5603 api.listen(&first, Some(ZonedAddr::Unzoned(local_ip::<I>())), None).expect("listen failed");
5604 assert_eq!(api.get_posix_reuse_port(&first), true);
5605 api.close(first).into_removed();
5606
5607 let second = api.create();
5608 api.set_posix_reuse_port(&second, true).expect("is unbound");
5609 api.connect(&second, Some(ZonedAddr::Unzoned(remote_ip::<I>())), REMOTE_PORT.into())
5610 .expect("connect failed");
5611
5612 assert_eq!(api.get_posix_reuse_port(&second), true);
5613 }
5614
5615 #[ip_test(I)]
5616 fn test_get_bound_device_unbound<I: TestIpExt>() {
5617 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5618 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5619 let unbound = api.create();
5620
5621 assert_eq!(api.get_bound_device(&unbound), None);
5622
5623 api.set_device(&unbound, Some(&FakeDeviceId)).unwrap();
5624 assert_eq!(api.get_bound_device(&unbound), Some(FakeWeakDeviceId(FakeDeviceId)));
5625 }
5626
5627 #[ip_test(I)]
5628 fn test_get_bound_device_listener<I: TestIpExt>() {
5629 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5630 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5631 let socket = api.create();
5632
5633 api.set_device(&socket, Some(&FakeDeviceId)).unwrap();
5634 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip::<I>())), Some(LOCAL_PORT))
5635 .expect("failed to listen");
5636 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
5637
5638 api.set_device(&socket, None).expect("failed to set device");
5639 assert_eq!(api.get_bound_device(&socket), None);
5640 }
5641
5642 #[ip_test(I)]
5643 fn test_get_bound_device_connected<I: TestIpExt>() {
5644 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5645 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5646 let socket = api.create();
5647 api.set_device(&socket, Some(&FakeDeviceId)).unwrap();
5648 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip::<I>())), REMOTE_PORT.into())
5649 .expect("failed to connect");
5650 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
5651 api.set_device(&socket, None).expect("failed to set device");
5652 assert_eq!(api.get_bound_device(&socket), None);
5653 }
5654
5655 #[ip_test(I)]
5656 fn test_listen_udp_forwards_errors<I: TestIpExt>() {
5657 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5658 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5659 let remote_ip = remote_ip::<I>();
5660
5661 let unbound = api.create();
5663 let listen_err = api
5664 .listen(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), Some(LOCAL_PORT))
5665 .expect_err("listen_udp unexpectedly succeeded");
5666 assert_eq!(listen_err, Either::Right(LocalAddressError::CannotBindToAddress));
5667
5668 let unbound = api.create();
5669 let _ = api.listen(&unbound, None, Some(OTHER_LOCAL_PORT)).expect("listen_udp failed");
5670 let unbound = api.create();
5671 let listen_err = api
5672 .listen(&unbound, None, Some(OTHER_LOCAL_PORT))
5673 .expect_err("listen_udp unexpectedly succeeded");
5674 assert_eq!(listen_err, Either::Right(LocalAddressError::AddressInUse));
5675 }
5676
5677 const IPV6_LINK_LOCAL_ADDR: Ipv6Addr = net_ip_v6!("fe80::1234");
5678 #[test_case(IPV6_LINK_LOCAL_ADDR, IPV6_LINK_LOCAL_ADDR; "unicast")]
5679 #[test_case(IPV6_LINK_LOCAL_ADDR, MulticastAddr::new(net_ip_v6!("ff02::1234")).unwrap().get(); "multicast")]
5680 fn test_listen_udp_ipv6_link_local_requires_zone(
5681 interface_addr: Ipv6Addr,
5682 bind_addr: Ipv6Addr,
5683 ) {
5684 type I = Ipv6;
5685 let interface_addr = LinkLocalAddr::new(interface_addr).unwrap().into_specified();
5686
5687 let mut ctx =
5688 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
5689 vec![interface_addr],
5690 vec![remote_ip::<I>()],
5691 ));
5692 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5693
5694 let bind_addr = LinkLocalAddr::new(bind_addr).unwrap().into_specified();
5695 assert!(bind_addr.scope().can_have_zone());
5696
5697 let unbound = api.create();
5698 let result = api.listen(&unbound, Some(ZonedAddr::Unzoned(bind_addr)), Some(LOCAL_PORT));
5699 assert_eq!(
5700 result,
5701 Err(Either::Right(LocalAddressError::Zone(ZonedAddressError::RequiredZoneNotProvided)))
5702 );
5703 }
5704
5705 #[test_case(MultipleDevicesId::A, Ok(()); "matching")]
5706 #[test_case(MultipleDevicesId::B, Err(LocalAddressError::Zone(ZonedAddressError::DeviceZoneMismatch)); "not matching")]
5707 fn test_listen_udp_ipv6_link_local_with_bound_device_set(
5708 zone_id: MultipleDevicesId,
5709 expected_result: Result<(), LocalAddressError>,
5710 ) {
5711 type I = Ipv6;
5712 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
5713 assert!(ll_addr.scope().can_have_zone());
5714
5715 let remote_ips = vec![remote_ip::<I>()];
5716 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5717 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
5718 [(MultipleDevicesId::A, ll_addr), (MultipleDevicesId::B, local_ip::<I>())].map(
5719 |(device, local_ip)| FakeDeviceConfig {
5720 device,
5721 local_ips: vec![local_ip],
5722 remote_ips: remote_ips.clone(),
5723 },
5724 ),
5725 )),
5726 );
5727 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5728
5729 let socket = api.create();
5730 api.set_device(&socket, Some(&MultipleDevicesId::A)).unwrap();
5731
5732 let result = api
5733 .listen(
5734 &socket,
5735 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, zone_id).unwrap())),
5736 Some(LOCAL_PORT),
5737 )
5738 .map_err(Either::unwrap_right);
5739 assert_eq!(result, expected_result);
5740 }
5741
5742 #[test_case(MultipleDevicesId::A, Ok(()); "matching")]
5743 #[test_case(MultipleDevicesId::B, Err(LocalAddressError::AddressMismatch); "not matching")]
5744 fn test_listen_udp_ipv6_link_local_with_zone_requires_addr_assigned_to_device(
5745 zone_id: MultipleDevicesId,
5746 expected_result: Result<(), LocalAddressError>,
5747 ) {
5748 type I = Ipv6;
5749 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
5750 assert!(ll_addr.scope().can_have_zone());
5751
5752 let remote_ips = vec![remote_ip::<I>()];
5753 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5754 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
5755 [(MultipleDevicesId::A, ll_addr), (MultipleDevicesId::B, local_ip::<I>())].map(
5756 |(device, local_ip)| FakeDeviceConfig {
5757 device,
5758 local_ips: vec![local_ip],
5759 remote_ips: remote_ips.clone(),
5760 },
5761 ),
5762 )),
5763 );
5764 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5765
5766 let socket = api.create();
5767 let result = api
5768 .listen(
5769 &socket,
5770 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, zone_id).unwrap())),
5771 Some(LOCAL_PORT),
5772 )
5773 .map_err(Either::unwrap_right);
5774 assert_eq!(result, expected_result);
5775 }
5776
5777 #[test_case(None, Err(LocalAddressError::Zone(ZonedAddressError::DeviceZoneMismatch)); "clear device")]
5778 #[test_case(Some(MultipleDevicesId::A), Ok(()); "set same device")]
5779 #[test_case(Some(MultipleDevicesId::B),
5780 Err(LocalAddressError::Zone(ZonedAddressError::DeviceZoneMismatch)); "change device")]
5781 fn test_listen_udp_ipv6_listen_link_local_update_bound_device(
5782 new_device: Option<MultipleDevicesId>,
5783 expected_result: Result<(), LocalAddressError>,
5784 ) {
5785 type I = Ipv6;
5786 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
5787 assert!(ll_addr.scope().can_have_zone());
5788
5789 let remote_ips = vec![remote_ip::<I>()];
5790 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5791 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
5792 [(MultipleDevicesId::A, ll_addr), (MultipleDevicesId::B, local_ip::<I>())].map(
5793 |(device, local_ip)| FakeDeviceConfig {
5794 device,
5795 local_ips: vec![local_ip],
5796 remote_ips: remote_ips.clone(),
5797 },
5798 ),
5799 )),
5800 );
5801 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5802
5803 let socket = api.create();
5804 api.listen(
5805 &socket,
5806 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, MultipleDevicesId::A).unwrap())),
5807 Some(LOCAL_PORT),
5808 )
5809 .expect("listen failed");
5810
5811 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(MultipleDevicesId::A)));
5812
5813 assert_eq!(
5814 api.set_device(&socket, new_device.as_ref()),
5815 expected_result.map_err(SocketError::Local),
5816 );
5817 }
5818
5819 #[test_case(None; "bind all IPs")]
5820 #[test_case(Some(ZonedAddr::Unzoned(local_ip::<Ipv6>())); "bind unzoned")]
5821 #[test_case(Some(ZonedAddr::Zoned(AddrAndZone::new(SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap(),
5822 MultipleDevicesId::A).unwrap())); "bind with same zone")]
5823 fn test_udp_ipv6_connect_with_unzoned(
5824 bound_addr: Option<ZonedAddr<SpecifiedAddr<Ipv6Addr>, MultipleDevicesId>>,
5825 ) {
5826 let remote_ips = vec![remote_ip::<Ipv6>()];
5827
5828 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5829 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new([
5830 FakeDeviceConfig {
5831 device: MultipleDevicesId::A,
5832 local_ips: vec![
5833 local_ip::<Ipv6>(),
5834 SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap(),
5835 ],
5836 remote_ips: remote_ips.clone(),
5837 },
5838 FakeDeviceConfig {
5839 device: MultipleDevicesId::B,
5840 local_ips: vec![SpecifiedAddr::new(net_ip_v6!("fe80::2")).unwrap()],
5841 remote_ips: remote_ips,
5842 },
5843 ])),
5844 );
5845 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
5846
5847 let socket = api.create();
5848
5849 api.listen(&socket, bound_addr, Some(LOCAL_PORT)).unwrap();
5850
5851 assert_matches!(
5852 api.connect(
5853 &socket,
5854 Some(ZonedAddr::Unzoned(remote_ip::<Ipv6>())),
5855 REMOTE_PORT.into(),
5856 ),
5857 Ok(())
5858 );
5859 }
5860
5861 #[test]
5862 fn test_udp_ipv6_connect_zoned_get_info() {
5863 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
5864 assert!(ll_addr.must_have_zone());
5865
5866 let remote_ips = vec![remote_ip::<Ipv6>()];
5867 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5868 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
5869 [(MultipleDevicesId::A, ll_addr), (MultipleDevicesId::B, local_ip::<Ipv6>())].map(
5870 |(device, local_ip)| FakeDeviceConfig {
5871 device,
5872 local_ips: vec![local_ip],
5873 remote_ips: remote_ips.clone(),
5874 },
5875 ),
5876 )),
5877 );
5878
5879 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
5880 let socket = api.create();
5881 api.set_device(&socket, Some(&MultipleDevicesId::A)).unwrap();
5882
5883 let zoned_local_addr =
5884 ZonedAddr::Zoned(AddrAndZone::new(ll_addr, MultipleDevicesId::A).unwrap());
5885 api.listen(&socket, Some(zoned_local_addr), Some(LOCAL_PORT)).unwrap();
5886
5887 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip::<Ipv6>())), REMOTE_PORT.into())
5888 .expect("connect should succeed");
5889
5890 assert_eq!(
5891 api.get_info(&socket),
5892 SocketInfo::Connected(datagram::ConnInfo {
5893 local_ip: StrictlyZonedAddr::new_with_zone(ll_addr, || FakeWeakDeviceId(
5894 MultipleDevicesId::A
5895 )),
5896 local_identifier: LOCAL_PORT,
5897 remote_ip: StrictlyZonedAddr::new_unzoned_or_panic(remote_ip::<Ipv6>()),
5898 remote_identifier: REMOTE_PORT.into(),
5899 })
5900 );
5901 }
5902
5903 #[test_case(ZonedAddr::Zoned(AddrAndZone::new(SpecifiedAddr::new(net_ip_v6!("fe80::2")).unwrap(),
5904 MultipleDevicesId::B).unwrap()),
5905 Err(ConnectError::Zone(ZonedAddressError::DeviceZoneMismatch));
5906 "connect to different zone")]
5907 #[test_case(ZonedAddr::Unzoned(SpecifiedAddr::new(net_ip_v6!("fe80::3")).unwrap()),
5908 Ok(FakeWeakDeviceId(MultipleDevicesId::A)); "connect implicit zone")]
5909 fn test_udp_ipv6_bind_zoned(
5910 remote_addr: ZonedAddr<SpecifiedAddr<Ipv6Addr>, MultipleDevicesId>,
5911 expected: Result<FakeWeakDeviceId<MultipleDevicesId>, ConnectError>,
5912 ) {
5913 let remote_ips = vec![SpecifiedAddr::new(net_ip_v6!("fe80::3")).unwrap()];
5914
5915 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5916 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new([
5917 FakeDeviceConfig {
5918 device: MultipleDevicesId::A,
5919 local_ips: vec![SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap()],
5920 remote_ips: remote_ips.clone(),
5921 },
5922 FakeDeviceConfig {
5923 device: MultipleDevicesId::B,
5924 local_ips: vec![SpecifiedAddr::new(net_ip_v6!("fe80::2")).unwrap()],
5925 remote_ips: remote_ips,
5926 },
5927 ])),
5928 );
5929
5930 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
5931
5932 let socket = api.create();
5933
5934 api.listen(
5935 &socket,
5936 Some(ZonedAddr::Zoned(
5937 AddrAndZone::new(
5938 SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap(),
5939 MultipleDevicesId::A,
5940 )
5941 .unwrap(),
5942 )),
5943 Some(LOCAL_PORT),
5944 )
5945 .unwrap();
5946
5947 let result = api
5948 .connect(&socket, Some(remote_addr), REMOTE_PORT.into())
5949 .map(|()| api.get_bound_device(&socket).unwrap());
5950 assert_eq!(result, expected);
5951 }
5952
5953 #[ip_test(I)]
5954 fn test_listen_udp_loopback_no_zone_is_required<I: TestIpExt>() {
5955 let loopback_addr = I::LOOPBACK_ADDRESS;
5956 let remote_ips = vec![remote_ip::<I>()];
5957
5958 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5959 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
5960 [(MultipleDevicesId::A, loopback_addr), (MultipleDevicesId::B, local_ip::<I>())]
5961 .map(|(device, local_ip)| FakeDeviceConfig {
5962 device,
5963 local_ips: vec![local_ip],
5964 remote_ips: remote_ips.clone(),
5965 }),
5966 )),
5967 );
5968 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5969
5970 let unbound = api.create();
5971 api.set_device(&unbound, Some(&MultipleDevicesId::A)).unwrap();
5972
5973 let result =
5974 api.listen(&unbound, Some(ZonedAddr::Unzoned(loopback_addr)), Some(LOCAL_PORT));
5975 assert_matches!(result, Ok(_));
5976 }
5977
5978 #[test_case(None, true, Ok(()); "connected success")]
5979 #[test_case(None, false, Ok(()); "listening success")]
5980 #[test_case(Some(MultipleDevicesId::A), true, Ok(()); "conn bind same device")]
5981 #[test_case(Some(MultipleDevicesId::A), false, Ok(()); "listen bind same device")]
5982 #[test_case(
5983 Some(MultipleDevicesId::B),
5984 true,
5985 Err(SendToError::Zone(ZonedAddressError::DeviceZoneMismatch));
5986 "conn bind different device")]
5987 #[test_case(
5988 Some(MultipleDevicesId::B),
5989 false,
5990 Err(SendToError::Zone(ZonedAddressError::DeviceZoneMismatch));
5991 "listen bind different device")]
5992 fn test_udp_ipv6_send_to_zoned(
5993 bind_device: Option<MultipleDevicesId>,
5994 connect: bool,
5995 expected: Result<(), SendToError>,
5996 ) {
5997 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
5998 assert!(ll_addr.must_have_zone());
5999 let conn_remote_ip = Ipv6::get_other_remote_ip_address(1);
6000
6001 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6002 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6003 [
6004 (MultipleDevicesId::A, Ipv6::get_other_ip_address(1)),
6005 (MultipleDevicesId::B, Ipv6::get_other_ip_address(2)),
6006 ]
6007 .map(|(device, local_ip)| FakeDeviceConfig {
6008 device,
6009 local_ips: vec![local_ip],
6010 remote_ips: vec![ll_addr, conn_remote_ip],
6011 }),
6012 )),
6013 );
6014
6015 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6016 let socket = api.create();
6017
6018 if let Some(device) = bind_device {
6019 api.set_device(&socket, Some(&device)).unwrap();
6020 }
6021
6022 let send_to_remote_addr =
6023 ZonedAddr::Zoned(AddrAndZone::new(ll_addr, MultipleDevicesId::A).unwrap());
6024 let result = if connect {
6025 api.connect(&socket, Some(ZonedAddr::Unzoned(conn_remote_ip)), REMOTE_PORT.into())
6026 .expect("connect should succeed");
6027 api.send_to(
6028 &socket,
6029 Some(send_to_remote_addr),
6030 REMOTE_PORT.into(),
6031 Buf::new(Vec::new(), ..),
6032 )
6033 } else {
6034 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen should succeed");
6035 api.send_to(
6036 &socket,
6037 Some(send_to_remote_addr),
6038 REMOTE_PORT.into(),
6039 Buf::new(Vec::new(), ..),
6040 )
6041 };
6042
6043 assert_eq!(result.map_err(|err| assert_matches!(err, Either::Right(e) => e)), expected);
6044 }
6045
6046 #[test_case(true; "connected")]
6047 #[test_case(false; "listening")]
6048 fn test_udp_ipv6_bound_zoned_send_to_zoned(connect: bool) {
6049 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::5678")).unwrap().into_specified();
6050 let device_a_local_ip = net_ip_v6!("fe80::1111");
6051 let conn_remote_ip = Ipv6::get_other_remote_ip_address(1);
6052
6053 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6054 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6055 [
6056 (MultipleDevicesId::A, device_a_local_ip),
6057 (MultipleDevicesId::B, net_ip_v6!("fe80::2222")),
6058 ]
6059 .map(|(device, local_ip)| FakeDeviceConfig {
6060 device,
6061 local_ips: vec![LinkLocalAddr::new(local_ip).unwrap().into_specified()],
6062 remote_ips: vec![ll_addr, conn_remote_ip],
6063 }),
6064 )),
6065 );
6066 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6067
6068 let socket = api.create();
6069 api.listen(
6070 &socket,
6071 Some(ZonedAddr::Zoned(
6072 AddrAndZone::new(
6073 SpecifiedAddr::new(device_a_local_ip).unwrap(),
6074 MultipleDevicesId::A,
6075 )
6076 .unwrap(),
6077 )),
6078 Some(LOCAL_PORT),
6079 )
6080 .expect("listen should succeed");
6081
6082 let send_to_remote_addr =
6085 ZonedAddr::Zoned(AddrAndZone::new(ll_addr, MultipleDevicesId::B).unwrap());
6086
6087 let result = if connect {
6088 api.connect(&socket, Some(ZonedAddr::Unzoned(conn_remote_ip)), REMOTE_PORT.into())
6089 .expect("connect should succeed");
6090 api.send_to(
6091 &socket,
6092 Some(send_to_remote_addr),
6093 REMOTE_PORT.into(),
6094 Buf::new(Vec::new(), ..),
6095 )
6096 } else {
6097 api.send_to(
6098 &socket,
6099 Some(send_to_remote_addr),
6100 REMOTE_PORT.into(),
6101 Buf::new(Vec::new(), ..),
6102 )
6103 };
6104
6105 assert_matches!(
6106 result,
6107 Err(Either::Right(SendToError::Zone(ZonedAddressError::DeviceZoneMismatch)))
6108 );
6109 }
6110
6111 #[test_case(None; "removes implicit")]
6112 #[test_case(Some(FakeDeviceId); "preserves implicit")]
6113 fn test_connect_disconnect_affects_bound_device(bind_device: Option<FakeDeviceId>) {
6114 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6117 assert!(ll_addr.must_have_zone());
6118
6119 let local_ip = local_ip::<Ipv6>();
6120 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
6121 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![ll_addr]),
6122 );
6123 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6124
6125 let socket = api.create();
6126 api.set_device(&socket, bind_device.as_ref()).unwrap();
6127
6128 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT)).unwrap();
6129 api.connect(
6130 &socket,
6131 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, FakeDeviceId).unwrap())),
6132 REMOTE_PORT.into(),
6133 )
6134 .expect("connect should succeed");
6135
6136 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6137
6138 api.disconnect(&socket).expect("was connected");
6139
6140 assert_eq!(api.get_bound_device(&socket), bind_device.map(FakeWeakDeviceId));
6141 }
6142
6143 #[test]
6144 fn test_bind_zoned_addr_connect_disconnect() {
6145 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6148 assert!(ll_addr.must_have_zone());
6149
6150 let remote_ip = remote_ip::<Ipv6>();
6151 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
6152 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![ll_addr], vec![remote_ip]),
6153 );
6154
6155 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6156
6157 let socket = api.create();
6158 api.listen(
6159 &socket,
6160 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, FakeDeviceId).unwrap())),
6161 Some(LOCAL_PORT),
6162 )
6163 .unwrap();
6164 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
6165 .expect("connect should succeed");
6166
6167 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6168
6169 api.disconnect(&socket).expect("was connected");
6170 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6171 }
6172
6173 #[test]
6174 fn test_bind_device_after_connect_persists_after_disconnect() {
6175 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6178 assert!(ll_addr.must_have_zone());
6179
6180 let local_ip = local_ip::<Ipv6>();
6181 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
6182 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![ll_addr]),
6183 );
6184 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6185 let socket = api.create();
6186 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT)).unwrap();
6187 api.connect(
6188 &socket,
6189 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, FakeDeviceId).unwrap())),
6190 REMOTE_PORT.into(),
6191 )
6192 .expect("connect should succeed");
6193
6194 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6195
6196 api.set_device(&socket, Some(&FakeDeviceId)).expect("binding same device should succeed");
6200
6201 api.disconnect(&socket).expect("was connected");
6202 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6203 }
6204
6205 #[ip_test(I)]
6206 fn test_remove_udp_unbound<I: TestIpExt>() {
6207 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6208 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6209 let unbound = api.create();
6210 api.close(unbound).into_removed();
6211 }
6212
6213 #[ip_test(I)]
6214 fn test_hop_limits_used_for_sending_packets<I: TestIpExt>() {
6215 let some_multicast_addr: MulticastAddr<I::Addr> = I::map_ip(
6216 (),
6217 |()| Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
6218 |()| MulticastAddr::new(net_ip_v6!("ff0e::1")).unwrap(),
6219 );
6220
6221 let mut ctx =
6222 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
6223 vec![local_ip::<I>()],
6224 vec![remote_ip::<I>(), some_multicast_addr.into_specified()],
6225 ));
6226 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6227 let listener = api.create();
6228
6229 const UNICAST_HOPS: NonZeroU8 = NonZeroU8::new(23).unwrap();
6230 const MULTICAST_HOPS: NonZeroU8 = NonZeroU8::new(98).unwrap();
6231 api.set_unicast_hop_limit(&listener, Some(UNICAST_HOPS), I::VERSION).unwrap();
6232 api.set_multicast_hop_limit(&listener, Some(MULTICAST_HOPS), I::VERSION).unwrap();
6233
6234 api.listen(&listener, None, None).expect("listen failed");
6235
6236 let mut send_and_get_ttl = |remote_ip| {
6237 api.send_to(
6238 &listener,
6239 Some(ZonedAddr::Unzoned(remote_ip)),
6240 REMOTE_PORT.into(),
6241 Buf::new(vec![], ..),
6242 )
6243 .expect("send failed");
6244
6245 let (meta, _body) = api.core_ctx().bound_sockets.ip_socket_ctx.frames().last().unwrap();
6246 let SendIpPacketMeta { dst_ip, ttl, .. } = meta.try_as::<I>().unwrap();
6247 assert_eq!(*dst_ip, remote_ip);
6248 *ttl
6249 };
6250
6251 assert_eq!(send_and_get_ttl(some_multicast_addr.into_specified()), Some(MULTICAST_HOPS));
6252 assert_eq!(send_and_get_ttl(remote_ip::<I>()), Some(UNICAST_HOPS));
6253 }
6254
6255 const DUAL_STACK_ANY_ADDR: Ipv6Addr = net_ip_v6!("::");
6256 const DUAL_STACK_V4_ANY_ADDR: Ipv6Addr = net_ip_v6!("::FFFF:0.0.0.0");
6257
6258 #[derive(Copy, Clone, Debug)]
6259 enum DualStackBindAddr {
6260 Any,
6261 V4Any,
6262 V4Specific,
6263 }
6264
6265 impl DualStackBindAddr {
6266 const fn v6_addr(&self) -> Option<Ipv6Addr> {
6267 match self {
6268 Self::Any => Some(DUAL_STACK_ANY_ADDR),
6269 Self::V4Any => Some(DUAL_STACK_V4_ANY_ADDR),
6270 Self::V4Specific => None,
6271 }
6272 }
6273 }
6274 const V4_LOCAL_IP: Ipv4Addr = ip_v4!("192.168.1.10");
6275 const V4_LOCAL_IP_MAPPED: Ipv6Addr = net_ip_v6!("::ffff:192.168.1.10");
6276 const V6_LOCAL_IP: Ipv6Addr = net_ip_v6!("2201::1");
6277 const V6_REMOTE_IP: SpecifiedAddr<Ipv6Addr> =
6278 unsafe { SpecifiedAddr::new_unchecked(net_ip_v6!("2001:db8::1")) };
6279 const V4_REMOTE_IP_MAPPED: SpecifiedAddr<Ipv6Addr> =
6280 unsafe { SpecifiedAddr::new_unchecked(net_ip_v6!("::FFFF:192.0.2.1")) };
6281
6282 fn get_dual_stack_context<
6283 'a,
6284 BC: UdpBindingsTypes + 'a,
6285 CC: DatagramBoundStateContext<Ipv6, BC, Udp<BC>>,
6286 >(
6287 core_ctx: &'a mut CC,
6288 ) -> &'a mut CC::DualStackContext {
6289 match core_ctx.dual_stack_context() {
6290 MaybeDualStack::NotDualStack(_) => unreachable!("UDP is a dual stack enabled protocol"),
6291 MaybeDualStack::DualStack(ds) => ds,
6292 }
6293 }
6294
6295 #[test_case(DualStackBindAddr::Any; "dual-stack")]
6296 #[test_case(DualStackBindAddr::V4Any; "v4 any")]
6297 #[test_case(DualStackBindAddr::V4Specific; "v4 specific")]
6298 fn dual_stack_delivery(bind_addr: DualStackBindAddr) {
6299 const REMOTE_IP: Ipv4Addr = ip_v4!("8.8.8.8");
6300 const REMOTE_IP_MAPPED: Ipv6Addr = net_ip_v6!("::ffff:8.8.8.8");
6301 let bind_addr = bind_addr.v6_addr().unwrap_or(V4_LOCAL_IP_MAPPED);
6302 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6303 vec![SpecifiedAddr::new(V4_LOCAL_IP).unwrap()],
6304 vec![SpecifiedAddr::new(REMOTE_IP).unwrap()],
6305 ));
6306
6307 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6308 let listener = api.create();
6309 api.listen(
6310 &listener,
6311 SpecifiedAddr::new(bind_addr).map(|a| ZonedAddr::Unzoned(a)),
6312 Some(LOCAL_PORT),
6313 )
6314 .expect("can bind");
6315
6316 const BODY: &[u8] = b"abcde";
6317 let (core_ctx, bindings_ctx) = api.contexts();
6318 receive_udp_packet(
6319 core_ctx,
6320 bindings_ctx,
6321 FakeDeviceId,
6322 UdpPacketMeta::<Ipv4> {
6323 src_ip: REMOTE_IP,
6324 src_port: Some(REMOTE_PORT),
6325 dst_ip: V4_LOCAL_IP,
6326 dst_port: LOCAL_PORT,
6327 dscp_and_ecn: DscpAndEcn::default(),
6328 },
6329 BODY,
6330 )
6331 .expect("receive udp packet should succeed");
6332
6333 assert_eq!(
6334 bindings_ctx.state.received::<Ipv6>(),
6335 &HashMap::from([(
6336 listener.downgrade(),
6337 SocketReceived {
6338 packets: vec![ReceivedPacket {
6339 body: BODY.into(),
6340 meta: UdpPacketMeta::<Ipv6> {
6341 src_ip: REMOTE_IP_MAPPED,
6342 src_port: Some(REMOTE_PORT),
6343 dst_ip: V4_LOCAL_IP_MAPPED,
6344 dst_port: LOCAL_PORT,
6345 dscp_and_ecn: DscpAndEcn::default(),
6346 }
6347 }]
6348 }
6349 )])
6350 );
6351 }
6352
6353 #[test_case(DualStackBindAddr::Any, true; "dual-stack any bind v4 first")]
6354 #[test_case(DualStackBindAddr::V4Any, true; "v4 any bind v4 first")]
6355 #[test_case(DualStackBindAddr::V4Specific, true; "v4 specific bind v4 first")]
6356 #[test_case(DualStackBindAddr::Any, false; "dual-stack any bind v4 second")]
6357 #[test_case(DualStackBindAddr::V4Any, false; "v4 any bind v4 second")]
6358 #[test_case(DualStackBindAddr::V4Specific, false; "v4 specific bind v4 second")]
6359 fn dual_stack_bind_conflict(bind_addr: DualStackBindAddr, bind_v4_first: bool) {
6360 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6361 vec![SpecifiedAddr::new(V4_LOCAL_IP).unwrap()],
6362 vec![],
6363 ));
6364
6365 let v4_listener = UdpApi::<Ipv4, _>::new(ctx.as_mut()).create();
6366 let v6_listener = UdpApi::<Ipv6, _>::new(ctx.as_mut()).create();
6367
6368 let bind_v4 = |mut api: UdpApi<Ipv4, _>| {
6369 api.listen(
6370 &v4_listener,
6371 SpecifiedAddr::new(V4_LOCAL_IP).map(|a| ZonedAddr::Unzoned(a)),
6372 Some(LOCAL_PORT),
6373 )
6374 };
6375 let bind_v6 = |mut api: UdpApi<Ipv6, _>| {
6376 api.listen(
6377 &v6_listener,
6378 SpecifiedAddr::new(bind_addr.v6_addr().unwrap_or(V4_LOCAL_IP_MAPPED))
6379 .map(ZonedAddr::Unzoned),
6380 Some(LOCAL_PORT),
6381 )
6382 };
6383
6384 let second_bind_error = if bind_v4_first {
6385 bind_v4(UdpApi::<Ipv4, _>::new(ctx.as_mut())).expect("no conflict");
6386 bind_v6(UdpApi::<Ipv6, _>::new(ctx.as_mut())).expect_err("should conflict")
6387 } else {
6388 bind_v6(UdpApi::<Ipv6, _>::new(ctx.as_mut())).expect("no conflict");
6389 bind_v4(UdpApi::<Ipv4, _>::new(ctx.as_mut())).expect_err("should conflict")
6390 };
6391 assert_eq!(second_bind_error, Either::Right(LocalAddressError::AddressInUse));
6392 }
6393
6394 #[test_case(IpVersion::V4; "v4_is_constrained")]
6398 #[test_case(IpVersion::V6; "v6_is_constrained")]
6399 fn dual_stack_local_port_alloc(ip_version_with_constrained_ports: IpVersion) {
6400 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6401 vec![
6402 SpecifiedAddr::new(V4_LOCAL_IP.to_ip_addr()).unwrap(),
6403 SpecifiedAddr::new(V6_LOCAL_IP.to_ip_addr()).unwrap(),
6404 ],
6405 vec![],
6406 ));
6407
6408 const AVAILABLE_PORT: NonZeroU16 = NonZeroU16::new(54321).unwrap();
6410
6411 for port in 1..=u16::MAX {
6413 let port = NonZeroU16::new(port).unwrap();
6414 if port == AVAILABLE_PORT {
6415 continue;
6416 }
6417 match ip_version_with_constrained_ports {
6418 IpVersion::V4 => {
6419 let mut api = UdpApi::<Ipv4, _>::new(ctx.as_mut());
6420 let listener = api.create();
6421 api.listen(
6422 &listener,
6423 SpecifiedAddr::new(V4_LOCAL_IP).map(|a| ZonedAddr::Unzoned(a)),
6424 Some(port),
6425 )
6426 .expect("listen v4 should succeed")
6427 }
6428 IpVersion::V6 => {
6429 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6430 let listener = api.create();
6431 api.listen(
6432 &listener,
6433 SpecifiedAddr::new(V6_LOCAL_IP).map(|a| ZonedAddr::Unzoned(a)),
6434 Some(port),
6435 )
6436 .expect("listen v6 should succeed")
6437 }
6438 }
6439 }
6440
6441 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6444 let listener = api.create();
6445 api.listen(&listener, None, None).expect("dualstack listen should succeed");
6446 let port = assert_matches!(api.get_info(&listener), SocketInfo::Listener(info) => info.local_identifier);
6447 assert_eq!(port, AVAILABLE_PORT);
6448 }
6449
6450 #[test_case(DualStackBindAddr::V4Any; "v4 any")]
6451 #[test_case(DualStackBindAddr::V4Specific; "v4 specific")]
6452 fn dual_stack_enable(bind_addr: DualStackBindAddr) {
6453 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6454 vec![SpecifiedAddr::new(V4_LOCAL_IP).unwrap()],
6455 vec![],
6456 ));
6457 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6458
6459 let bind_addr = bind_addr.v6_addr().unwrap_or(V4_LOCAL_IP_MAPPED);
6460 let listener = api.create();
6461
6462 assert_eq!(api.get_dual_stack_enabled(&listener), Ok(true));
6463 api.set_dual_stack_enabled(&listener, false).expect("can set dual-stack enabled");
6464
6465 assert_eq!(
6468 api.listen(
6469 &listener,
6470 SpecifiedAddr::new(bind_addr).map(|a| ZonedAddr::Unzoned(a)),
6471 Some(LOCAL_PORT),
6472 ),
6473 Err(Either::Right(LocalAddressError::CannotBindToAddress))
6474 );
6475 api.set_dual_stack_enabled(&listener, true).expect("can set dual-stack enabled");
6476 assert_eq!(
6478 api.listen(
6479 &listener,
6480 SpecifiedAddr::new(bind_addr).map(|a| ZonedAddr::Unzoned(a)),
6481 Some(LOCAL_PORT),
6482 ),
6483 Ok(())
6484 );
6485 }
6486
6487 #[test]
6488 fn dual_stack_bind_unassigned_v4_address() {
6489 const NOT_ASSIGNED_MAPPED: Ipv6Addr = net_ip_v6!("::ffff:8.8.8.8");
6490 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6491 vec![SpecifiedAddr::new(V4_LOCAL_IP).unwrap()],
6492 vec![],
6493 ));
6494 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6495
6496 let listener = api.create();
6497 assert_eq!(
6498 api.listen(
6499 &listener,
6500 SpecifiedAddr::new(NOT_ASSIGNED_MAPPED).map(|a| ZonedAddr::Unzoned(a)),
6501 Some(LOCAL_PORT),
6502 ),
6503 Err(Either::Right(LocalAddressError::CannotBindToAddress))
6504 );
6505 }
6506
6507 #[test]
6512 fn dual_stack_connect_cleans_up_existing_listener() {
6513 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6514 vec![Ipv6::TEST_ADDRS.local_ip],
6515 vec![Ipv6::TEST_ADDRS.remote_ip],
6516 ));
6517
6518 const DUAL_STACK_ANY_ADDR: Option<ZonedAddr<SpecifiedAddr<Ipv6Addr>, FakeDeviceId>> = None;
6519
6520 fn assert_listeners(core_ctx: &mut FakeUdpCoreCtx<FakeDeviceId>, expect_present: bool) {
6521 const V4_LISTENER_ADDR: ListenerAddr<
6522 ListenerIpAddr<Ipv4Addr, NonZeroU16>,
6523 FakeWeakDeviceId<FakeDeviceId>,
6524 > = ListenerAddr {
6525 ip: ListenerIpAddr { addr: None, identifier: LOCAL_PORT },
6526 device: None,
6527 };
6528 const V6_LISTENER_ADDR: ListenerAddr<
6529 ListenerIpAddr<Ipv6Addr, NonZeroU16>,
6530 FakeWeakDeviceId<FakeDeviceId>,
6531 > = ListenerAddr {
6532 ip: ListenerIpAddr { addr: None, identifier: LOCAL_PORT },
6533 device: None,
6534 };
6535
6536 DualStackBoundStateContext::with_both_bound_sockets_mut(
6537 get_dual_stack_context(&mut core_ctx.bound_sockets),
6538 |_core_ctx, v6_sockets, v4_sockets| {
6539 let v4 = v4_sockets.bound_sockets.listeners().get_by_addr(&V4_LISTENER_ADDR);
6540 let v6 = v6_sockets.bound_sockets.listeners().get_by_addr(&V6_LISTENER_ADDR);
6541 if expect_present {
6542 assert_matches!(v4, Some(_));
6543 assert_matches!(v6, Some(_));
6544 } else {
6545 assert_matches!(v4, None);
6546 assert_matches!(v6, None);
6547 }
6548 },
6549 );
6550 }
6551
6552 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6555 let socket = api.create();
6556 assert_eq!(api.listen(&socket, DUAL_STACK_ANY_ADDR, Some(LOCAL_PORT)), Ok(()));
6557 assert_listeners(api.core_ctx(), true);
6558
6559 assert_eq!(
6562 api.connect(
6563 &socket,
6564 Some(ZonedAddr::Unzoned(Ipv6::TEST_ADDRS.remote_ip)),
6565 REMOTE_PORT.into(),
6566 ),
6567 Ok(())
6568 );
6569 assert_matches!(api.get_info(&socket), SocketInfo::Connected(_));
6570 assert_listeners(api.core_ctx(), false);
6571 }
6572
6573 #[test_case(net_ip_v6!("::"), true; "dual stack any")]
6574 #[test_case(net_ip_v6!("::"), false; "v6 any")]
6575 #[test_case(net_ip_v6!("::ffff:0.0.0.0"), true; "v4 unspecified")]
6576 #[test_case(V4_LOCAL_IP_MAPPED, true; "v4 specified")]
6577 #[test_case(V6_LOCAL_IP, true; "v6 specified dual stack enabled")]
6578 #[test_case(V6_LOCAL_IP, false; "v6 specified dual stack disabled")]
6579 fn dual_stack_get_info(bind_addr: Ipv6Addr, enable_dual_stack: bool) {
6580 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs::<
6581 SpecifiedAddr<IpAddr>,
6582 >(
6583 vec![
6584 SpecifiedAddr::new(V4_LOCAL_IP).unwrap().into(),
6585 SpecifiedAddr::new(V6_LOCAL_IP).unwrap().into(),
6586 ],
6587 vec![],
6588 ));
6589 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6590
6591 let listener = api.create();
6592 api.set_dual_stack_enabled(&listener, enable_dual_stack)
6593 .expect("can set dual-stack enabled");
6594 let bind_addr = SpecifiedAddr::new(bind_addr);
6595 assert_eq!(
6596 api.listen(&listener, bind_addr.map(|a| ZonedAddr::Unzoned(a)), Some(LOCAL_PORT),),
6597 Ok(())
6598 );
6599
6600 assert_eq!(
6601 api.get_info(&listener),
6602 SocketInfo::Listener(datagram::ListenerInfo {
6603 local_ip: bind_addr.map(StrictlyZonedAddr::new_unzoned_or_panic),
6604 local_identifier: LOCAL_PORT,
6605 })
6606 );
6607 }
6608
6609 #[test_case(net_ip_v6!("::"), true; "dual stack any")]
6610 #[test_case(net_ip_v6!("::"), false; "v6 any")]
6611 #[test_case(net_ip_v6!("::ffff:0.0.0.0"), true; "v4 unspecified")]
6612 #[test_case(V4_LOCAL_IP_MAPPED, true; "v4 specified")]
6613 #[test_case(V6_LOCAL_IP, true; "v6 specified dual stack enabled")]
6614 #[test_case(V6_LOCAL_IP, false; "v6 specified dual stack disabled")]
6615 fn dual_stack_remove_listener(bind_addr: Ipv6Addr, enable_dual_stack: bool) {
6616 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs::<
6620 SpecifiedAddr<IpAddr>,
6621 >(
6622 vec![
6623 SpecifiedAddr::new(V4_LOCAL_IP).unwrap().into(),
6624 SpecifiedAddr::new(V6_LOCAL_IP).unwrap().into(),
6625 ],
6626 vec![],
6627 ));
6628 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6629
6630 let mut bind_listener = || {
6631 let listener = api.create();
6632 api.set_dual_stack_enabled(&listener, enable_dual_stack)
6633 .expect("can set dual-stack enabled");
6634 let bind_addr = SpecifiedAddr::new(bind_addr);
6635 assert_eq!(
6636 api.listen(&listener, bind_addr.map(|a| ZonedAddr::Unzoned(a)), Some(LOCAL_PORT)),
6637 Ok(())
6638 );
6639
6640 api.close(listener).into_removed();
6641 };
6642
6643 bind_listener();
6645 bind_listener();
6648 }
6649
6650 #[test_case(V6_REMOTE_IP, true; "This stack with dualstack enabled")]
6651 #[test_case(V6_REMOTE_IP, false; "This stack with dualstack disabled")]
6652 #[test_case(V4_REMOTE_IP_MAPPED, true; "other stack with dualstack enabled")]
6653 fn dualstack_remove_connected(remote_ip: SpecifiedAddr<Ipv6Addr>, enable_dual_stack: bool) {
6654 let mut ctx = datagram::testutil::setup_fake_ctx_with_dualstack_conn_addrs(
6658 Ipv6::UNSPECIFIED_ADDRESS.to_ip_addr(),
6659 remote_ip.into(),
6660 [FakeDeviceId {}],
6661 |device_configs| {
6662 FakeUdpCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6663 device_configs,
6664 ))
6665 },
6666 );
6667 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6668
6669 let mut bind_connected = || {
6670 let socket = api.create();
6671 api.set_dual_stack_enabled(&socket, enable_dual_stack)
6672 .expect("can set dual-stack enabled");
6673 assert_eq!(
6674 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into(),),
6675 Ok(())
6676 );
6677
6678 api.close(socket).into_removed();
6679 };
6680
6681 bind_connected();
6683 bind_connected();
6686 }
6687
6688 #[test_case(false, V6_REMOTE_IP, Ok(());
6689 "connect to this stack with dualstack disabled")]
6690 #[test_case(true, V6_REMOTE_IP, Ok(());
6691 "connect to this stack with dualstack enabled")]
6692 #[test_case(false, V4_REMOTE_IP_MAPPED, Err(ConnectError::RemoteUnexpectedlyMapped);
6693 "connect to other stack with dualstack disabled")]
6694 #[test_case(true, V4_REMOTE_IP_MAPPED, Ok(());
6695 "connect to other stack with dualstack enabled")]
6696 fn dualstack_connect_unbound(
6697 enable_dual_stack: bool,
6698 remote_ip: SpecifiedAddr<Ipv6Addr>,
6699 expected_outcome: Result<(), ConnectError>,
6700 ) {
6701 let mut ctx = datagram::testutil::setup_fake_ctx_with_dualstack_conn_addrs(
6702 Ipv6::UNSPECIFIED_ADDRESS.to_ip_addr(),
6703 remote_ip.into(),
6704 [FakeDeviceId {}],
6705 |device_configs| {
6706 FakeUdpCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6707 device_configs,
6708 ))
6709 },
6710 );
6711 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6712
6713 let socket = api.create();
6714
6715 api.set_dual_stack_enabled(&socket, enable_dual_stack).expect("can set dual-stack enabled");
6716
6717 assert_eq!(
6718 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into()),
6719 expected_outcome
6720 );
6721
6722 if expected_outcome.is_ok() {
6723 assert_matches!(
6724 api.get_info(&socket),
6725 SocketInfo::Connected(datagram::ConnInfo{
6726 local_ip: _,
6727 local_identifier: _,
6728 remote_ip: found_remote_ip,
6729 remote_identifier: found_remote_port,
6730 }) if found_remote_ip.addr() == remote_ip &&
6731 found_remote_port == u16::from(REMOTE_PORT)
6732 );
6733 assert_eq!(api.disconnect(&socket), Ok(()));
6735 }
6736
6737 assert_eq!(api.get_info(&socket), SocketInfo::Unbound);
6739 }
6740
6741 #[test_case(V6_LOCAL_IP, V6_REMOTE_IP, Ok(());
6742 "listener in this stack connected in this stack")]
6743 #[test_case(V6_LOCAL_IP, V4_REMOTE_IP_MAPPED, Err(ConnectError::RemoteUnexpectedlyMapped);
6744 "listener in this stack connected in other stack")]
6745 #[test_case(Ipv6::UNSPECIFIED_ADDRESS, V6_REMOTE_IP, Ok(());
6746 "listener in both stacks connected in this stack")]
6747 #[test_case(Ipv6::UNSPECIFIED_ADDRESS, V4_REMOTE_IP_MAPPED, Ok(());
6748 "listener in both stacks connected in other stack")]
6749 #[test_case(V4_LOCAL_IP_MAPPED, V6_REMOTE_IP,
6750 Err(ConnectError::RemoteUnexpectedlyNonMapped);
6751 "listener in other stack connected in this stack")]
6752 #[test_case(V4_LOCAL_IP_MAPPED, V4_REMOTE_IP_MAPPED, Ok(());
6753 "listener in other stack connected in other stack")]
6754 fn dualstack_connect_listener(
6755 local_ip: Ipv6Addr,
6756 remote_ip: SpecifiedAddr<Ipv6Addr>,
6757 expected_outcome: Result<(), ConnectError>,
6758 ) {
6759 let mut ctx = datagram::testutil::setup_fake_ctx_with_dualstack_conn_addrs(
6760 local_ip.to_ip_addr(),
6761 remote_ip.into(),
6762 [FakeDeviceId {}],
6763 |device_configs| {
6764 FakeUdpCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6765 device_configs,
6766 ))
6767 },
6768 );
6769 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6770 let socket = api.create();
6771
6772 assert_eq!(
6773 api.listen(
6774 &socket,
6775 SpecifiedAddr::new(local_ip).map(|local_ip| ZonedAddr::Unzoned(local_ip)),
6776 Some(LOCAL_PORT),
6777 ),
6778 Ok(())
6779 );
6780
6781 assert_eq!(
6782 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into()),
6783 expected_outcome
6784 );
6785
6786 if expected_outcome.is_ok() {
6787 assert_matches!(
6788 api.get_info(&socket),
6789 SocketInfo::Connected(datagram::ConnInfo{
6790 local_ip: _,
6791 local_identifier: _,
6792 remote_ip: found_remote_ip,
6793 remote_identifier: found_remote_port,
6794 }) if found_remote_ip.addr() == remote_ip &&
6795 found_remote_port == u16::from(REMOTE_PORT)
6796 );
6797 assert_eq!(api.disconnect(&socket), Ok(()));
6799 }
6800
6801 assert_matches!(
6803 api.get_info(&socket),
6804 SocketInfo::Listener(datagram::ListenerInfo {
6805 local_ip: found_local_ip,
6806 local_identifier: found_local_port,
6807 }) if found_local_port == LOCAL_PORT &&
6808 local_ip == found_local_ip.map(
6809 |a| a.addr().get()
6810 ).unwrap_or(Ipv6::UNSPECIFIED_ADDRESS)
6811 );
6812 }
6813
6814 #[test_case(V6_REMOTE_IP, V6_REMOTE_IP, Ok(());
6815 "connected in this stack reconnected in this stack")]
6816 #[test_case(V6_REMOTE_IP, V4_REMOTE_IP_MAPPED, Err(ConnectError::RemoteUnexpectedlyMapped);
6817 "connected in this stack reconnected in other stack")]
6818 #[test_case(V4_REMOTE_IP_MAPPED, V6_REMOTE_IP,
6819 Err(ConnectError::RemoteUnexpectedlyNonMapped);
6820 "connected in other stack reconnected in this stack")]
6821 #[test_case(V4_REMOTE_IP_MAPPED, V4_REMOTE_IP_MAPPED, Ok(());
6822 "connected in other stack reconnected in other stack")]
6823 fn dualstack_connect_connected(
6824 original_remote_ip: SpecifiedAddr<Ipv6Addr>,
6825 new_remote_ip: SpecifiedAddr<Ipv6Addr>,
6826 expected_outcome: Result<(), ConnectError>,
6827 ) {
6828 let mut ctx = datagram::testutil::setup_fake_ctx_with_dualstack_conn_addrs(
6829 Ipv6::UNSPECIFIED_ADDRESS.to_ip_addr(),
6830 original_remote_ip.into(),
6831 [FakeDeviceId {}],
6832 |device_configs| {
6833 FakeUdpCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6834 device_configs,
6835 ))
6836 },
6837 );
6838
6839 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6840 let socket = api.create();
6841
6842 assert_eq!(
6843 api.connect(&socket, Some(ZonedAddr::Unzoned(original_remote_ip)), REMOTE_PORT.into(),),
6844 Ok(())
6845 );
6846
6847 assert_eq!(
6848 api.connect(
6849 &socket,
6850 Some(ZonedAddr::Unzoned(new_remote_ip)),
6851 OTHER_REMOTE_PORT.into(),
6852 ),
6853 expected_outcome
6854 );
6855
6856 let (expected_remote_ip, expected_remote_port) = if expected_outcome.is_ok() {
6857 (new_remote_ip, OTHER_REMOTE_PORT)
6858 } else {
6859 (original_remote_ip, REMOTE_PORT)
6861 };
6862 assert_matches!(
6863 api.get_info(&socket),
6864 SocketInfo::Connected(datagram::ConnInfo{
6865 local_ip: _,
6866 local_identifier: _,
6867 remote_ip: found_remote_ip,
6868 remote_identifier: found_remote_port,
6869 }) if found_remote_ip.addr() == expected_remote_ip &&
6870 found_remote_port == u16::from(expected_remote_port)
6871 );
6872
6873 assert_eq!(api.disconnect(&socket), Ok(()));
6875 assert_eq!(api.get_info(&socket), SocketInfo::Unbound);
6876 }
6877
6878 type FakeBoundSocketMap<I> =
6879 UdpBoundSocketMap<I, FakeWeakDeviceId<FakeDeviceId>, FakeUdpBindingsCtx<FakeDeviceId>>;
6880 type FakePortAlloc<'a, I> =
6881 UdpPortAlloc<'a, I, FakeWeakDeviceId<FakeDeviceId>, FakeUdpBindingsCtx<FakeDeviceId>>;
6882
6883 fn listen<I: IpExt>(
6884 ip: I::Addr,
6885 port: u16,
6886 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec> {
6887 let addr = SpecifiedAddr::new(ip).map(|a| SocketIpAddr::try_from(a).unwrap());
6888 let port = NonZeroU16::new(port).expect("port must be nonzero");
6889 AddrVec::Listen(ListenerAddr {
6890 ip: ListenerIpAddr { addr, identifier: port },
6891 device: None,
6892 })
6893 }
6894
6895 fn listen_device<I: IpExt>(
6896 ip: I::Addr,
6897 port: u16,
6898 device: FakeWeakDeviceId<FakeDeviceId>,
6899 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec> {
6900 let addr = SpecifiedAddr::new(ip).map(|a| SocketIpAddr::try_from(a).unwrap());
6901 let port = NonZeroU16::new(port).expect("port must be nonzero");
6902 AddrVec::Listen(ListenerAddr {
6903 ip: ListenerIpAddr { addr, identifier: port },
6904 device: Some(device),
6905 })
6906 }
6907
6908 fn conn<I: IpExt>(
6909 local_ip: I::Addr,
6910 local_port: u16,
6911 remote_ip: I::Addr,
6912 remote_port: u16,
6913 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec> {
6914 let local_ip = SocketIpAddr::new(local_ip).expect("addr must be specified & non-mapped");
6915 let local_port = NonZeroU16::new(local_port).expect("port must be nonzero");
6916 let remote_ip = SocketIpAddr::new(remote_ip).expect("addr must be specified & non-mapped");
6917 let remote_port = NonZeroU16::new(remote_port).expect("port must be nonzero").into();
6918 AddrVec::Conn(ConnAddr {
6919 ip: ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) },
6920 device: None,
6921 })
6922 }
6923
6924 const EXCLUSIVE: Sharing = Sharing { reuse_addr: false, reuse_port: false };
6925 const REUSE_ADDR: Sharing = Sharing { reuse_addr: true, reuse_port: false };
6926 const REUSE_PORT: Sharing = Sharing { reuse_addr: false, reuse_port: true };
6927 const REUSE_ADDR_PORT: Sharing = Sharing { reuse_addr: true, reuse_port: true };
6928
6929 #[test_case([
6930 (listen(ip_v4!("0.0.0.0"), 1), EXCLUSIVE),
6931 (listen(ip_v4!("0.0.0.0"), 2), EXCLUSIVE)],
6932 Ok(()); "listen_any_ip_different_port")]
6933 #[test_case([
6934 (listen(ip_v4!("0.0.0.0"), 1), EXCLUSIVE),
6935 (listen(ip_v4!("0.0.0.0"), 1), EXCLUSIVE)],
6936 Err(InsertError::Exists); "any_ip_same_port")]
6937 #[test_case([
6938 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
6939 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE)],
6940 Err(InsertError::Exists); "listen_same_specific_ip")]
6941 #[test_case([
6942 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
6943 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR)],
6944 Ok(()); "listen_same_specific_ip_reuse_addr")]
6945 #[test_case([
6946 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
6947 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT)],
6948 Ok(()); "listen_same_specific_ip_reuse_port")]
6949 #[test_case([
6950 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
6951 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR)],
6952 Ok(()); "listen_same_specific_ip_reuse_addr_port_and_reuse_addr")]
6953 #[test_case([
6954 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
6955 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT)],
6956 Ok(()); "listen_same_specific_ip_reuse_addr_and_reuse_addr_port")]
6957 #[test_case([
6958 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
6959 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT)],
6960 Ok(()); "listen_same_specific_ip_reuse_addr_port_and_reuse_port")]
6961 #[test_case([
6962 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
6963 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT)],
6964 Ok(()); "listen_same_specific_ip_reuse_port_and_reuse_addr_port")]
6965 #[test_case([
6966 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
6967 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT)],
6968 Ok(()); "listen_same_specific_ip_reuse_addr_port_and_reuse_addr_port")]
6969 #[test_case([
6970 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
6971 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR)],
6972 Err(InsertError::Exists); "listen_same_specific_ip_exclusive_reuse_addr")]
6973 #[test_case([
6974 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
6975 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE)],
6976 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_exclusive")]
6977 #[test_case([
6978 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
6979 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT)],
6980 Err(InsertError::Exists); "listen_same_specific_ip_exclusive_reuse_port")]
6981 #[test_case([
6982 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
6983 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE)],
6984 Err(InsertError::Exists); "listen_same_specific_ip_reuse_port_exclusive")]
6985 #[test_case([
6986 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
6987 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT)],
6988 Err(InsertError::Exists); "listen_same_specific_ip_exclusive_reuse_addr_port")]
6989 #[test_case([
6990 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
6991 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE)],
6992 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_port_exclusive")]
6993 #[test_case([
6994 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
6995 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR)],
6996 Err(InsertError::Exists); "listen_same_specific_ip_reuse_port_reuse_addr")]
6997 #[test_case([
6998 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
6999 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT)],
7000 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_reuse_port")]
7001 #[test_case([
7002 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7003 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7004 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),],
7005 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_port_and_reuse_port_and_reuse_addr")]
7006 #[test_case([
7007 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7008 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
7009 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),],
7010 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_port_and_reuse_addr_and_reuse_port")]
7011 #[test_case([
7012 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7013 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), REUSE_PORT)],
7014 Ok(()); "conn_shadows_listener_reuse_port")]
7015 #[test_case([
7016 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7017 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE)],
7018 Err(InsertError::ShadowAddrExists); "conn_shadows_listener_exclusive")]
7019 #[test_case([
7020 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7021 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), REUSE_PORT)],
7022 Err(InsertError::ShadowAddrExists); "conn_shadows_listener_exclusive_reuse_port")]
7023 #[test_case([
7024 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7025 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE)],
7026 Err(InsertError::ShadowAddrExists); "conn_shadows_listener_reuse_port_exclusive")]
7027 #[test_case([
7028 (listen_device(ip_v4!("1.1.1.1"), 1, FakeWeakDeviceId(FakeDeviceId)), EXCLUSIVE),
7029 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE)],
7030 Err(InsertError::IndirectConflict); "conn_indirect_conflict_specific_listener")]
7031 #[test_case([
7032 (listen_device(ip_v4!("0.0.0.0"), 1, FakeWeakDeviceId(FakeDeviceId)), EXCLUSIVE),
7033 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE)],
7034 Err(InsertError::IndirectConflict); "conn_indirect_conflict_any_listener")]
7035 #[test_case([
7036 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE),
7037 (listen_device(ip_v4!("1.1.1.1"), 1, FakeWeakDeviceId(FakeDeviceId)), EXCLUSIVE)],
7038 Err(InsertError::IndirectConflict); "specific_listener_indirect_conflict_conn")]
7039 #[test_case([
7040 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE),
7041 (listen_device(ip_v4!("0.0.0.0"), 1, FakeWeakDeviceId(FakeDeviceId)), EXCLUSIVE)],
7042 Err(InsertError::IndirectConflict); "any_listener_indirect_conflict_conn")]
7043 fn bind_sequence<
7044 C: IntoIterator<Item = (AddrVec<Ipv4, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>, Sharing)>,
7045 >(
7046 spec: C,
7047 expected: Result<(), InsertError>,
7048 ) {
7049 let mut primary_ids = Vec::new();
7050
7051 let mut create_socket = || {
7052 let primary = datagram::testutil::create_primary_id((), Default::default());
7053 let id = UdpSocketId(PrimaryRc::clone_strong(&primary));
7054 primary_ids.push(primary);
7055 id
7056 };
7057
7058 let mut map = FakeBoundSocketMap::<Ipv4>::default();
7059 let mut spec = spec.into_iter().peekable();
7060 let mut try_insert = |(addr, options)| match addr {
7061 AddrVec::Conn(c) => map
7062 .conns_mut()
7063 .try_insert(c, options, EitherIpSocket::V4(create_socket()))
7064 .map(|_| ())
7065 .map_err(|(e, _)| e),
7066 AddrVec::Listen(l) => map
7067 .listeners_mut()
7068 .try_insert(l, options, EitherIpSocket::V4(create_socket()))
7069 .map(|_| ())
7070 .map_err(|(e, _)| e),
7071 };
7072 let last = loop {
7073 let one_spec = spec.next().expect("empty list of test cases");
7074 if spec.peek().is_none() {
7075 break one_spec;
7076 } else {
7077 try_insert(one_spec).expect("intermediate bind failed")
7078 }
7079 };
7080
7081 let result = try_insert(last);
7082 assert_eq!(result, expected);
7083 }
7084
7085 #[test_case([
7086 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7087 (listen(ip_v4!("2.2.2.2"), 2), EXCLUSIVE),
7088 ]; "distinct")]
7089 #[test_case([
7090 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7091 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7092 ]; "listen_reuse_port")]
7093 #[test_case([
7094 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 3), REUSE_PORT),
7095 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 3), REUSE_PORT),
7096 ]; "conn_reuse_port")]
7097 fn remove_sequence<I>(spec: I)
7098 where
7099 I: IntoIterator<
7100 Item = (AddrVec<Ipv4, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>, Sharing),
7101 >,
7102 I::IntoIter: ExactSizeIterator,
7103 {
7104 enum Socket<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes, LI, RI> {
7105 Listener(UdpSocketId<I, D, BT>, ListenerAddr<ListenerIpAddr<I::Addr, LI>, D>),
7106 Conn(UdpSocketId<I, D, BT>, ConnAddr<ConnIpAddr<I::Addr, LI, RI>, D>),
7107 }
7108 let spec = spec.into_iter();
7109 let spec_len = spec.len();
7110
7111 let mut primary_ids = Vec::new();
7112
7113 let mut create_socket = || {
7114 let primary = datagram::testutil::create_primary_id((), Default::default());
7115 let id = UdpSocketId(PrimaryRc::clone_strong(&primary));
7116 primary_ids.push(primary);
7117 id
7118 };
7119
7120 for spec in spec.permutations(spec_len) {
7121 let mut map = FakeBoundSocketMap::<Ipv4>::default();
7122 let sockets = spec
7123 .into_iter()
7124 .map(|(addr, options)| match addr {
7125 AddrVec::Conn(c) => map
7126 .conns_mut()
7127 .try_insert(c, options, EitherIpSocket::V4(create_socket()))
7128 .map(|entry| {
7129 Socket::Conn(
7130 assert_matches!(entry.id(), EitherIpSocket::V4(id) => id.clone()),
7131 entry.get_addr().clone(),
7132 )
7133 })
7134 .expect("insert_failed"),
7135 AddrVec::Listen(l) => map
7136 .listeners_mut()
7137 .try_insert(l, options, EitherIpSocket::V4(create_socket()))
7138 .map(|entry| {
7139 Socket::Listener(
7140 assert_matches!(entry.id(), EitherIpSocket::V4(id) => id.clone()),
7141 entry.get_addr().clone(),
7142 )
7143 })
7144 .expect("insert_failed"),
7145 })
7146 .collect::<Vec<_>>();
7147
7148 for socket in sockets {
7149 match socket {
7150 Socket::Listener(l, addr) => {
7151 assert_matches!(
7152 map.listeners_mut().remove(&EitherIpSocket::V4(l), &addr),
7153 Ok(())
7154 );
7155 }
7156 Socket::Conn(c, addr) => {
7157 assert_matches!(
7158 map.conns_mut().remove(&EitherIpSocket::V4(c), &addr),
7159 Ok(())
7160 );
7161 }
7162 }
7163 }
7164 }
7165 }
7166
7167 enum OriginalSocketState {
7168 Unbound,
7169 Listener,
7170 Connected,
7171 }
7172
7173 impl OriginalSocketState {
7174 fn create_socket<I, C>(&self, api: &mut UdpApi<I, C>) -> UdpApiSocketId<I, C>
7175 where
7176 I: TestIpExt,
7177 C: ContextPair,
7178 C::CoreContext: StateContext<I, C::BindingsContext>
7179 + UdpCounterContext<
7180 I,
7181 <C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId,
7182 C::BindingsContext,
7183 >,
7184 C::BindingsContext:
7185 UdpBindingsContext<I, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
7186 <C::BindingsContext as UdpBindingsTypes>::ExternalData<I>: Default,
7187 <C::BindingsContext as UdpBindingsTypes>::SocketWritableListener: Default,
7188 {
7189 let socket = api.create();
7190 match self {
7191 OriginalSocketState::Unbound => {}
7192 OriginalSocketState::Listener => {
7193 api.listen(
7194 &socket,
7195 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)),
7196 Some(LOCAL_PORT),
7197 )
7198 .expect("listen should succeed");
7199 }
7200 OriginalSocketState::Connected => {
7201 api.connect(
7202 &socket,
7203 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
7204 UdpRemotePort::Set(REMOTE_PORT),
7205 )
7206 .expect("connect should succeed");
7207 }
7208 }
7209 socket
7210 }
7211 }
7212
7213 #[test_case(OriginalSocketState::Unbound; "unbound")]
7214 #[test_case(OriginalSocketState::Listener; "listener")]
7215 #[test_case(OriginalSocketState::Connected; "connected")]
7216 fn set_get_dual_stack_enabled_v4(original_state: OriginalSocketState) {
7217 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
7218 vec![Ipv4::TEST_ADDRS.local_ip],
7219 vec![Ipv4::TEST_ADDRS.remote_ip],
7220 ));
7221 let mut api = UdpApi::<Ipv4, _>::new(ctx.as_mut());
7222 let socket = original_state.create_socket(&mut api);
7223
7224 for enabled in [true, false] {
7225 assert_eq!(
7226 api.set_dual_stack_enabled(&socket, enabled),
7227 Err(SetDualStackEnabledError::NotCapable)
7228 );
7229 assert_eq!(api.get_dual_stack_enabled(&socket), Err(NotDualStackCapableError));
7230 }
7231 }
7232
7233 #[test_case(OriginalSocketState::Unbound, Ok(()); "unbound")]
7234 #[test_case(OriginalSocketState::Listener, Err(SetDualStackEnabledError::SocketIsBound);
7235 "listener")]
7236 #[test_case(OriginalSocketState::Connected, Err(SetDualStackEnabledError::SocketIsBound);
7237 "connected")]
7238 fn set_get_dual_stack_enabled_v6(
7239 original_state: OriginalSocketState,
7240 expected_result: Result<(), SetDualStackEnabledError>,
7241 ) {
7242 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
7243 vec![Ipv6::TEST_ADDRS.local_ip],
7244 vec![Ipv6::TEST_ADDRS.remote_ip],
7245 ));
7246 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7247 let socket = original_state.create_socket(&mut api);
7248
7249 const ORIGINALLY_ENABLED: bool = true;
7251 assert_eq!(api.get_dual_stack_enabled(&socket), Ok(ORIGINALLY_ENABLED));
7252
7253 for enabled in [false, true] {
7254 assert_eq!(api.set_dual_stack_enabled(&socket, enabled), expected_result);
7255 let expect_enabled = match expected_result {
7256 Ok(_) => enabled,
7257 Err(_) => ORIGINALLY_ENABLED,
7259 };
7260 assert_eq!(api.get_dual_stack_enabled(&socket), Ok(expect_enabled));
7261 }
7262 }
7263
7264 #[ip_test(I)]
7265 #[test_case::test_matrix(
7266 [MarkDomain::Mark1, MarkDomain::Mark2],
7267 [None, Some(0), Some(1)]
7268 )]
7269 fn udp_socket_marks<I: TestIpExt>(domain: MarkDomain, mark: Option<u32>) {
7270 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
7271 vec![I::TEST_ADDRS.local_ip],
7272 vec![I::TEST_ADDRS.remote_ip],
7273 ));
7274 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
7275 let socket = api.create();
7276
7277 assert_eq!(api.get_mark(&socket, domain), Mark(None));
7279
7280 let mark = Mark(mark);
7281 api.set_mark(&socket, domain, mark);
7283 assert_eq!(api.get_mark(&socket, domain), mark);
7284 }
7285}