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