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, BoundDatagramSocketMap, BoundSocketState as DatagramBoundSocketState,
41 BoundSocketStateType as DatagramBoundSocketStateType, ConnInfo, ConnectError, DatagramApi,
42 DatagramBindingsTypes, DatagramBoundStateContext, DatagramFlowId,
43 DatagramIpSpecificSocketOptions, DatagramSocketMapSpec, DatagramSocketSet, DatagramSocketSpec,
44 DatagramSpecBoundStateContext, DatagramSpecStateContext, DatagramStateContext,
45 DualStackBaseIpExt, DualStackConnState, DualStackConverter, DualStackDatagramBoundStateContext,
46 DualStackDatagramSpecBoundStateContext, DualStackIpExt, EitherIpSocket, ExpectedConnError,
47 ExpectedUnboundError, InUseError, IpExt, IpOptions, ListenerInfo,
48 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::icmp::IcmpError;
57use netstack3_ip::socket::{
58 IpSockCreateAndSendError, IpSockCreationError, IpSockSendError, SocketHopLimits,
59};
60use netstack3_ip::{
61 HopLimits, IpHeaderInfo, IpTransportContext, LocalDeliveryPacketInfo,
62 MulticastMembershipHandler, ReceiveIpPacketMeta, SocketMetadata, TransparentLocalDelivery,
63 TransportIpContext,
64};
65use netstack3_trace::trace_duration;
66use packet::{BufferMut, FragmentedByteSlice, Nested, PacketBuilder, ParsablePacket, ParseBuffer};
67use packet_formats::ip::{DscpAndEcn, IpProto, IpProtoExt};
68use packet_formats::udp::{UdpPacket, UdpPacketBuilder, UdpPacketRaw, UdpParseArgs};
69use thiserror::Error;
70
71use crate::internal::counters::{
72 CombinedUdpCounters, UdpCounterContext, UdpCountersWithSocket, UdpCountersWithoutSocket,
73};
74use crate::internal::diagnostics::{UdpSocketDiagnosticTuple, UdpSocketDiagnostics};
75use crate::internal::settings::UdpSettings;
76
77pub(crate) type UdpBoundSocketMap<I, D, BT> = BoundDatagramSocketMap<I, D, Udp<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 UdpBoundSocketMap<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, I::IcmpError)> {
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, I::IcmpError::port_unreachable()))
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) => {
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(_) => true,
1616 },
1617 DatagramSocketStateInner::Unbound(_) => true,
1618 };
1619
1620 if !should_deliver {
1621 return None;
1622 }
1623
1624 if require_transparent && !state.options().transparent() {
1627 return None;
1628 }
1629
1630 let [ip_prefix, ip_options] = header_info.as_bytes();
1631 let [udp_header, data] = packet.as_bytes();
1632 let mut slices = [ip_prefix, ip_options, udp_header, data];
1633 let data = FragmentedByteSlice::new(&mut slices);
1634 let filter_result = bindings_ctx.socket_ops_filter().on_ingress(
1635 I::VERSION,
1636 data,
1637 device_id,
1638 id.socket_cookie(),
1639 state.options().marks(),
1640 );
1641
1642 match filter_result {
1643 SocketIngressFilterResult::Accept => {
1644 Some(bindings_ctx.receive_udp(id, device_id, meta, packet.body()))
1645 }
1646 SocketIngressFilterResult::Drop => None,
1647 }
1648 });
1649
1650 match delivered {
1651 None => false,
1652 Some(result) => {
1653 core_ctx.increment_both(id, |c| &c.rx_delivered);
1654 match result {
1655 Ok(()) => {}
1656 Err(ReceiveUdpError::QueueFull) => {
1657 core_ctx.increment_both(id, |c| &c.rx_queue_full);
1658 }
1659 }
1660 true
1661 }
1662 }
1663}
1664
1665fn try_dual_stack_deliver<
1667 I: IpExt,
1668 BC: UdpBindingsContext<I, CC::DeviceId> + UdpBindingsContext<I::OtherVersion, CC::DeviceId>,
1669 CC: StateContext<I, BC>
1670 + StateContext<I::OtherVersion, BC>
1671 + UdpCounterContext<I, CC::WeakDeviceId, BC>
1672 + UdpCounterContext<I::OtherVersion, CC::WeakDeviceId, BC>,
1673 H: IpHeaderInfo<I>,
1674>(
1675 core_ctx: &mut CC,
1676 bindings_ctx: &mut BC,
1677 socket: I::DualStackBoundSocketId<CC::WeakDeviceId, Udp<BC>>,
1678 device_id: &CC::DeviceId,
1679 meta: &UdpPacketMeta<I>,
1680 require_transparent: bool,
1681 header_info: &H,
1682 packet: UdpPacket<&[u8]>,
1683) -> bool {
1684 #[derive(GenericOverIp)]
1685 #[generic_over_ip(I, Ip)]
1686 struct Inputs<'a, I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
1687 meta: &'a UdpPacketMeta<I>,
1688 socket: I::DualStackBoundSocketId<D, Udp<BT>>,
1689 }
1690
1691 struct Outputs<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
1692 meta: UdpPacketMeta<I>,
1693 socket: UdpSocketId<I, D, BT>,
1694 }
1695
1696 #[derive(GenericOverIp)]
1697 #[generic_over_ip(I, Ip)]
1698 enum DualStackOutputs<I: DualStackIpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> {
1699 CurrentStack(Outputs<I, D, BT>),
1700 OtherStack(Outputs<I::OtherVersion, D, BT>),
1701 }
1702
1703 let dual_stack_outputs = I::map_ip(
1704 Inputs { meta, socket },
1705 |Inputs { meta, socket }| match socket {
1706 EitherIpSocket::V4(socket) => {
1707 DualStackOutputs::CurrentStack(Outputs { meta: meta.clone(), socket })
1708 }
1709 EitherIpSocket::V6(socket) => {
1710 DualStackOutputs::OtherStack(Outputs { meta: meta.to_ipv6_mapped(), socket })
1711 }
1712 },
1713 |Inputs { meta, socket }| {
1714 DualStackOutputs::CurrentStack(Outputs { meta: meta.clone(), socket })
1715 },
1716 );
1717
1718 match dual_stack_outputs {
1719 DualStackOutputs::CurrentStack(Outputs { meta, socket }) => try_deliver(
1720 core_ctx,
1721 bindings_ctx,
1722 &socket,
1723 device_id,
1724 meta,
1725 require_transparent,
1726 header_info,
1727 packet,
1728 ),
1729 DualStackOutputs::OtherStack(Outputs { meta, socket }) => try_deliver(
1730 core_ctx,
1731 bindings_ctx,
1732 &socket,
1733 device_id,
1734 meta,
1735 require_transparent,
1736 header_info,
1737 packet,
1738 ),
1739 }
1740}
1741
1742pub trait UseUdpIpTransportContextBlanket {}
1751
1752pub type DualStackUdpSocketId<I, D, BT> =
1754 <I as DualStackBaseIpExt>::DualStackBoundSocketId<D, Udp<BT>>;
1755
1756impl<
1757 I: IpExt,
1758 BC: UdpBindingsContext<I, CC::DeviceId> + UdpBindingsContext<I::OtherVersion, CC::DeviceId>,
1759 CC: StateContext<I, BC>
1760 + StateContext<I::OtherVersion, BC>
1761 + UseUdpIpTransportContextBlanket
1762 + UdpCounterContext<I, CC::WeakDeviceId, BC>
1763 + UdpCounterContext<I::OtherVersion, CC::WeakDeviceId, BC>,
1764> IpTransportContext<I, BC, CC> for UdpIpTransportContext
1765{
1766 type EarlyDemuxSocket = DualStackUdpSocketId<I, CC::WeakDeviceId, BC>;
1767
1768 fn early_demux<B: ParseBuffer>(
1769 core_ctx: &mut CC,
1770 device: &CC::DeviceId,
1771 src_ip: I::Addr,
1772 dst_ip: I::Addr,
1773 buffer: B,
1774 ) -> Option<Self::EarlyDemuxSocket> {
1775 early_demux_ip_packet::<I, _, _, _>(core_ctx, device, src_ip, dst_ip, buffer)
1776 }
1777
1778 fn receive_icmp_error(
1779 core_ctx: &mut CC,
1780 _bindings_ctx: &mut BC,
1781 _device: &CC::DeviceId,
1782 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
1783 original_dst_ip: SpecifiedAddr<I::Addr>,
1784 _original_udp_packet: &[u8],
1785 err: I::ErrorCode,
1786 ) {
1787 CounterContext::<UdpCountersWithoutSocket<I>>::counters(core_ctx).rx_icmp_error.increment();
1788 debug!(
1792 "UDP received ICMP error {:?} from {:?} to {:?}",
1793 err, original_dst_ip, original_src_ip
1794 );
1795 }
1796
1797 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
1798 core_ctx: &mut CC,
1799 bindings_ctx: &mut BC,
1800 device: &CC::DeviceId,
1801 src_ip: I::RecvSrcAddr,
1802 dst_ip: SpecifiedAddr<I::Addr>,
1803 buffer: B,
1804 info: &LocalDeliveryPacketInfo<I, H>,
1805 early_demux_socket: Option<Self::EarlyDemuxSocket>,
1806 ) -> Result<(), (B, I::IcmpError)> {
1807 receive_ip_packet::<I, _, _, _, _>(
1808 core_ctx,
1809 bindings_ctx,
1810 device,
1811 src_ip,
1812 dst_ip,
1813 buffer,
1814 info,
1815 early_demux_socket,
1816 )
1817 }
1818}
1819
1820#[derive(Error, Copy, Clone, Debug, Eq, PartialEq)]
1822pub enum SendToError {
1823 #[error("not writeable")]
1825 NotWriteable,
1826 #[error("could not create a temporary connection socket: {0}")]
1829 CreateSock(#[from] IpSockCreationError),
1830 #[error("could not send via temporary socket: {0}")]
1833 Send(#[from] IpSockSendError),
1834 #[error("zone error: {0}")]
1836 Zone(#[from] ZonedAddressError),
1837 #[error("the remote port was unset")]
1840 RemotePortUnset,
1841 #[error("the remote ip was unexpectedly an ipv4-mapped-ipv6 address")]
1844 RemoteUnexpectedlyMapped,
1845 #[error("the remote ip was unexpectedly not an ipv4-mapped-ipv6 address")]
1848 RemoteUnexpectedlyNonMapped,
1849 #[error("send buffer full")]
1851 SendBufferFull,
1852 #[error("invalid message length")]
1854 InvalidLength,
1855}
1856
1857pub struct UdpApi<I: Ip, C>(C, IpVersionMarker<I>);
1859
1860impl<I: Ip, C> UdpApi<I, C> {
1861 pub fn new(ctx: C) -> Self {
1863 Self(ctx, IpVersionMarker::new())
1864 }
1865}
1866
1867type UdpApiSocketId<I, C> = UdpSocketId<
1872 I,
1873 <<C as ContextPair>::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId,
1874 <C as ContextPair>::BindingsContext,
1875>;
1876
1877impl<I, C> UdpApi<I, C>
1878where
1879 I: IpExt,
1880 C: ContextPair,
1881 C::CoreContext: StateContext<I, C::BindingsContext>
1882 + UdpCounterContext<
1883 I,
1884 <C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId,
1885 C::BindingsContext,
1886 >
1887 + DatagramStateContext<I, C::BindingsContext, Udp<C::BindingsContext>>,
1890 C::BindingsContext:
1891 UdpBindingsContext<I, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
1892 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId: netstack3_base::InterfaceProperties<
1893 <C::BindingsContext as MatcherBindingsTypes>::DeviceClass,
1894 >,
1895{
1896 fn core_ctx(&mut self) -> &mut C::CoreContext {
1897 let Self(pair, IpVersionMarker { .. }) = self;
1898 pair.core_ctx()
1899 }
1900
1901 #[cfg(test)]
1902 fn contexts(&mut self) -> (&mut C::CoreContext, &mut C::BindingsContext) {
1903 let Self(pair, IpVersionMarker { .. }) = self;
1904 pair.contexts()
1905 }
1906
1907 pub fn bound_sockets_diagnostics<M, E>(&mut self, matcher: &M, results: &mut E)
1909 where
1910 M: IpSocketPropertiesMatcher<<C::BindingsContext as MatcherBindingsTypes>::DeviceClass>
1911 + ?Sized,
1912 E: Extend<UdpSocketDiagnostics<I>>,
1913 {
1914 DatagramStateContext::for_each_socket(self.core_ctx(), |ctx, id, state| {
1915 if !matcher
1916 .matches_ip_socket(&netstack3_datagram::SocketStateForMatching::new(state, id, ctx))
1917 {
1918 return;
1919 }
1920
1921 let udp_state = match state.to_socket_info() {
1922 SocketInfo::Unbound => return,
1925 SocketInfo::Listener(ListenerInfo { local_ip, local_identifier }) => {
1926 UdpSocketDiagnosticTuple::Bound {
1927 src_addr: local_ip.map(|ip| ip.into_inner().addr().get()),
1928 src_port: local_identifier,
1929 }
1930 }
1931 SocketInfo::Connected(ConnInfo {
1932 local_ip,
1933 local_identifier,
1934 remote_ip,
1935 remote_identifier,
1936 }) => UdpSocketDiagnosticTuple::Connected {
1937 src_addr: local_ip.into_inner().addr().get(),
1938 src_port: local_identifier,
1939 dst_addr: remote_ip.into_inner().addr().get(),
1940 dst_port: remote_identifier,
1941 },
1942 };
1943
1944 let options = state.options();
1945
1946 results.extend(core::iter::once(UdpSocketDiagnostics {
1947 state: udp_state,
1948 cookie: id.socket_cookie(),
1949 marks: *options.marks(),
1950 }));
1951 });
1952 }
1953
1954 pub fn disconnect_bound<M>(&mut self, _matcher: &M) -> usize
1959 where
1960 M: IpSocketPropertiesMatcher<<C::BindingsContext as MatcherBindingsTypes>::DeviceClass>
1961 + ?Sized,
1962 {
1963 0
1965 }
1966
1967 fn datagram(&mut self) -> &mut DatagramApi<I, C, Udp<C::BindingsContext>> {
1968 let Self(pair, IpVersionMarker { .. }) = self;
1969 DatagramApi::wrap(pair)
1970 }
1971
1972 pub fn create(&mut self) -> UdpApiSocketId<I, C>
1974 where
1975 <C::BindingsContext as UdpBindingsTypes>::ExternalData<I>: Default,
1976 <C::BindingsContext as UdpBindingsTypes>::SocketWritableListener: Default,
1977 {
1978 self.create_with(Default::default(), Default::default())
1979 }
1980
1981 pub fn create_with(
1983 &mut self,
1984 external_data: <C::BindingsContext as UdpBindingsTypes>::ExternalData<I>,
1985 writable_listener: <C::BindingsContext as UdpBindingsTypes>::SocketWritableListener,
1986 ) -> UdpApiSocketId<I, C> {
1987 self.datagram().create(external_data, writable_listener)
1988 }
1989
1990 pub fn connect(
2009 &mut self,
2010 id: &UdpApiSocketId<I, C>,
2011 remote_ip: Option<
2012 ZonedAddr<
2013 SpecifiedAddr<I::Addr>,
2014 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId,
2015 >,
2016 >,
2017 remote_port: UdpRemotePort,
2018 ) -> Result<(), ConnectError> {
2019 debug!("connect on {id:?} to {remote_ip:?}:{remote_port:?}");
2020 self.datagram().connect(id, remote_ip, remote_port, ())
2021 }
2022
2023 pub fn set_device(
2029 &mut self,
2030 id: &UdpApiSocketId<I, C>,
2031 device_id: Option<&<C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
2032 ) -> Result<(), SocketError> {
2033 debug!("set device on {id:?} to {device_id:?}");
2034 self.datagram().set_device(id, device_id)
2035 }
2036
2037 pub fn get_bound_device(
2039 &mut self,
2040 id: &UdpApiSocketId<I, C>,
2041 ) -> Option<<C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId> {
2042 self.datagram().get_bound_device(id)
2043 }
2044
2045 pub fn set_dual_stack_enabled(
2054 &mut self,
2055 id: &UdpApiSocketId<I, C>,
2056 enabled: bool,
2057 ) -> Result<(), SetDualStackEnabledError> {
2058 self.datagram()
2059 .with_other_stack_ip_options_mut_if_unbound(id, |other_stack| {
2060 I::map_ip(
2061 (enabled, WrapOtherStackIpOptionsMut(other_stack)),
2062 |(_enabled, _v4)| Err(NotDualStackCapableError.into()),
2063 |(enabled, WrapOtherStackIpOptionsMut(other_stack))| {
2064 let DualStackSocketState { dual_stack_enabled, .. } = other_stack;
2065 *dual_stack_enabled = enabled;
2066 Ok(())
2067 },
2068 )
2069 })
2070 .map_err(|ExpectedUnboundError| {
2071 match I::VERSION {
2074 IpVersion::V4 => NotDualStackCapableError.into(),
2075 IpVersion::V6 => SetDualStackEnabledError::SocketIsBound,
2076 }
2077 })?
2078 }
2079
2080 pub fn get_dual_stack_enabled(
2089 &mut self,
2090 id: &UdpApiSocketId<I, C>,
2091 ) -> Result<bool, NotDualStackCapableError> {
2092 self.datagram().with_other_stack_ip_options(id, |other_stack| {
2093 I::map_ip(
2094 WrapOtherStackIpOptions(other_stack),
2095 |_v4| Err(NotDualStackCapableError),
2096 |WrapOtherStackIpOptions(other_stack)| {
2097 let DualStackSocketState { dual_stack_enabled, .. } = other_stack;
2098 Ok(*dual_stack_enabled)
2099 },
2100 )
2101 })
2102 }
2103
2104 pub fn set_posix_reuse_addr(
2110 &mut self,
2111 id: &UdpApiSocketId<I, C>,
2112 reuse_addr: bool,
2113 ) -> Result<(), ExpectedUnboundError> {
2114 self.datagram().update_sharing(id, |sharing| {
2115 sharing.reuse_addr = reuse_addr;
2116 })
2117 }
2118
2119 pub fn get_posix_reuse_addr(&mut self, id: &UdpApiSocketId<I, C>) -> bool {
2121 self.datagram().get_sharing(id).reuse_addr
2122 }
2123
2124 pub fn set_posix_reuse_port(
2130 &mut self,
2131 id: &UdpApiSocketId<I, C>,
2132 reuse_port: ReusePortOption,
2133 ) -> Result<(), ExpectedUnboundError> {
2134 self.datagram().update_sharing(id, |sharing| {
2135 sharing.reuse_port = reuse_port;
2136 })
2137 }
2138
2139 pub fn get_posix_reuse_port(&mut self, id: &UdpApiSocketId<I, C>) -> bool {
2141 self.datagram().get_sharing(id).reuse_port.is_enabled()
2142 }
2143
2144 pub fn set_multicast_membership(
2151 &mut self,
2152 id: &UdpApiSocketId<I, C>,
2153 multicast_group: MulticastAddr<I::Addr>,
2154 interface: MulticastMembershipInterfaceSelector<
2155 I::Addr,
2156 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId,
2157 >,
2158 want_membership: bool,
2159 ) -> Result<(), SetMulticastMembershipError> {
2160 debug!(
2161 "set multicast membership on {id:?} for group {multicast_group:?} with interface \
2162 selector: {interface:?}: want_membership={want_membership}"
2163 );
2164 self.datagram().set_multicast_membership(id, multicast_group, interface, want_membership)
2165 }
2166
2167 pub fn set_unicast_hop_limit(
2176 &mut self,
2177 id: &UdpApiSocketId<I, C>,
2178 unicast_hop_limit: Option<NonZeroU8>,
2179 ip_version: IpVersion,
2180 ) -> Result<(), NotDualStackCapableError> {
2181 if ip_version == I::VERSION {
2182 return Ok(self
2183 .datagram()
2184 .update_ip_hop_limit(id, SocketHopLimits::set_unicast(unicast_hop_limit)));
2185 }
2186 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
2187 I::map_ip(
2188 (IpInvariant(unicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack)),
2189 |(IpInvariant(_unicast_hop_limit), _v4)| Err(NotDualStackCapableError),
2190 |(IpInvariant(unicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack))| {
2191 let DualStackSocketState {
2192 socket_options:
2193 DatagramIpSpecificSocketOptions {
2194 hop_limits: SocketHopLimits { unicast, multicast: _, version: _ },
2195 ..
2196 },
2197 ..
2198 } = other_stack;
2199 *unicast = unicast_hop_limit;
2200 Ok(())
2201 },
2202 )
2203 })
2204 }
2205
2206 pub fn set_multicast_hop_limit(
2215 &mut self,
2216 id: &UdpApiSocketId<I, C>,
2217 multicast_hop_limit: Option<NonZeroU8>,
2218 ip_version: IpVersion,
2219 ) -> Result<(), NotDualStackCapableError> {
2220 if ip_version == I::VERSION {
2221 return Ok(self
2222 .datagram()
2223 .update_ip_hop_limit(id, SocketHopLimits::set_multicast(multicast_hop_limit)));
2224 }
2225 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
2226 I::map_ip(
2227 (IpInvariant(multicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack)),
2228 |(IpInvariant(_multicast_hop_limit), _v4)| Err(NotDualStackCapableError),
2229 |(IpInvariant(multicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack))| {
2230 let DualStackSocketState {
2231 socket_options:
2232 DatagramIpSpecificSocketOptions {
2233 hop_limits: SocketHopLimits { unicast: _, multicast, version: _ },
2234 ..
2235 },
2236 ..
2237 } = other_stack;
2238 *multicast = multicast_hop_limit;
2239 Ok(())
2240 },
2241 )
2242 })
2243 }
2244
2245 pub fn get_unicast_hop_limit(
2254 &mut self,
2255 id: &UdpApiSocketId<I, C>,
2256 ip_version: IpVersion,
2257 ) -> Result<NonZeroU8, NotDualStackCapableError> {
2258 if ip_version == I::VERSION {
2259 return Ok(self.datagram().get_ip_hop_limits(id).unicast);
2260 }
2261 self.datagram().with_other_stack_ip_options_and_default_hop_limits(
2262 id,
2263 |other_stack, default_hop_limits| {
2264 I::map_ip_in(
2265 (WrapOtherStackIpOptions(other_stack), IpInvariant(default_hop_limits)),
2266 |_v4| Err(NotDualStackCapableError),
2267 |(
2268 WrapOtherStackIpOptions(other_stack),
2269 IpInvariant(HopLimits { unicast: default_unicast, multicast: _ }),
2270 )| {
2271 let DualStackSocketState {
2272 socket_options:
2273 DatagramIpSpecificSocketOptions {
2274 hop_limits:
2275 SocketHopLimits { unicast, multicast: _, version: _ },
2276 ..
2277 },
2278 ..
2279 } = other_stack;
2280 Ok(unicast.unwrap_or(default_unicast))
2281 },
2282 )
2283 },
2284 )?
2285 }
2286
2287 pub fn get_multicast_hop_limit(
2296 &mut self,
2297 id: &UdpApiSocketId<I, C>,
2298 ip_version: IpVersion,
2299 ) -> Result<NonZeroU8, NotDualStackCapableError> {
2300 if ip_version == I::VERSION {
2301 return Ok(self.datagram().get_ip_hop_limits(id).multicast);
2302 }
2303 self.datagram().with_other_stack_ip_options_and_default_hop_limits(
2304 id,
2305 |other_stack, default_hop_limits| {
2306 I::map_ip_in(
2307 (WrapOtherStackIpOptions(other_stack), IpInvariant(default_hop_limits)),
2308 |_v4| Err(NotDualStackCapableError),
2309 |(
2310 WrapOtherStackIpOptions(other_stack),
2311 IpInvariant(HopLimits { unicast: _, multicast: default_multicast }),
2312 )| {
2313 let DualStackSocketState {
2314 socket_options:
2315 DatagramIpSpecificSocketOptions {
2316 hop_limits:
2317 SocketHopLimits { unicast: _, multicast, version: _ },
2318 ..
2319 },
2320 ..
2321 } = other_stack;
2322 Ok(multicast.unwrap_or(default_multicast))
2323 },
2324 )
2325 },
2326 )?
2327 }
2328
2329 pub fn get_multicast_interface(
2331 &mut self,
2332 id: &UdpApiSocketId<I, C>,
2333 ip_version: IpVersion,
2334 ) -> Result<
2335 Option<<C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId>,
2336 NotDualStackCapableError,
2337 > {
2338 if ip_version == I::VERSION {
2339 return Ok(self.datagram().get_multicast_interface(id));
2340 };
2341
2342 self.datagram().with_other_stack_ip_options(id, |other_stack| {
2343 I::map_ip_in(
2344 WrapOtherStackIpOptions(other_stack),
2345 |_v4| Err(NotDualStackCapableError),
2346 |WrapOtherStackIpOptions(other_stack)| {
2347 Ok(other_stack.socket_options.multicast_interface.clone())
2348 },
2349 )
2350 })
2351 }
2352
2353 pub fn set_multicast_interface(
2355 &mut self,
2356 id: &UdpApiSocketId<I, C>,
2357 interface: Option<&<C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
2358 ip_version: IpVersion,
2359 ) -> Result<(), NotDualStackCapableError> {
2360 if ip_version == I::VERSION {
2361 self.datagram().set_multicast_interface(id, interface);
2362 return Ok(());
2363 };
2364
2365 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
2366 I::map_ip(
2367 (IpInvariant(interface), WrapOtherStackIpOptionsMut(other_stack)),
2368 |(IpInvariant(_interface), _v4)| Err(NotDualStackCapableError),
2369 |(IpInvariant(interface), WrapOtherStackIpOptionsMut(other_stack))| {
2370 other_stack.socket_options.multicast_interface =
2371 interface.map(|device| device.downgrade());
2372 Ok(())
2373 },
2374 )
2375 })
2376 }
2377
2378 pub fn get_transparent(&mut self, id: &UdpApiSocketId<I, C>) -> bool {
2380 self.datagram().get_ip_transparent(id)
2381 }
2382
2383 pub fn set_transparent(&mut self, id: &UdpApiSocketId<I, C>, value: bool) {
2385 self.datagram().set_ip_transparent(id, value)
2386 }
2387
2388 pub fn get_mark(&mut self, id: &UdpApiSocketId<I, C>, domain: MarkDomain) -> Mark {
2390 self.datagram().get_mark(id, domain)
2391 }
2392
2393 pub fn set_mark(&mut self, id: &UdpApiSocketId<I, C>, domain: MarkDomain, mark: Mark) {
2395 self.datagram().set_mark(id, domain, mark)
2396 }
2397
2398 pub fn get_broadcast(&mut self, id: &UdpApiSocketId<I, C>) -> bool {
2400 self.datagram().with_both_stacks_ip_options(id, |this_stack, other_stack| {
2401 I::map_ip_in(
2402 (this_stack, WrapOtherStackIpOptions(other_stack)),
2403 |(this_stack, _)| this_stack.allow_broadcast.is_some(),
2404 |(_, WrapOtherStackIpOptions(other_stack))| {
2405 other_stack.socket_options.allow_broadcast.is_some()
2406 },
2407 )
2408 })
2409 }
2410
2411 pub fn set_broadcast(&mut self, id: &UdpApiSocketId<I, C>, value: bool) {
2413 self.datagram().with_both_stacks_ip_options_mut(id, |this_stack, other_stack| {
2414 let value = value.then_some(());
2415 I::map_ip_in(
2416 (this_stack, WrapOtherStackIpOptionsMut(other_stack)),
2417 |(this_stack, _)| this_stack.allow_broadcast = value,
2418 |(_, WrapOtherStackIpOptionsMut(other_stack))| {
2419 other_stack.socket_options.allow_broadcast = value;
2420 },
2421 )
2422 })
2423 }
2424
2425 pub fn get_multicast_loop(
2427 &mut self,
2428 id: &UdpApiSocketId<I, C>,
2429 ip_version: IpVersion,
2430 ) -> Result<bool, NotDualStackCapableError> {
2431 if ip_version == I::VERSION {
2432 return Ok(self.datagram().get_multicast_loop(id));
2433 };
2434
2435 self.datagram().with_other_stack_ip_options(id, |other_stack| {
2436 I::map_ip_in(
2437 WrapOtherStackIpOptions(other_stack),
2438 |_v4| Err(NotDualStackCapableError),
2439 |WrapOtherStackIpOptions(other_stack)| {
2440 Ok(other_stack.socket_options.multicast_loop)
2441 },
2442 )
2443 })
2444 }
2445
2446 pub fn set_multicast_loop(
2448 &mut self,
2449 id: &UdpApiSocketId<I, C>,
2450 value: bool,
2451 ip_version: IpVersion,
2452 ) -> Result<(), NotDualStackCapableError> {
2453 if ip_version == I::VERSION {
2454 self.datagram().set_multicast_loop(id, value);
2455 return Ok(());
2456 };
2457
2458 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
2459 I::map_ip(
2460 (IpInvariant(value), WrapOtherStackIpOptionsMut(other_stack)),
2461 |(IpInvariant(_interface), _v4)| Err(NotDualStackCapableError),
2462 |(IpInvariant(value), WrapOtherStackIpOptionsMut(other_stack))| {
2463 other_stack.socket_options.multicast_loop = value;
2464 Ok(())
2465 },
2466 )
2467 })
2468 }
2469
2470 pub fn get_dscp_and_ecn(
2472 &mut self,
2473 id: &UdpApiSocketId<I, C>,
2474 ip_version: IpVersion,
2475 ) -> Result<DscpAndEcn, NotDualStackCapableError> {
2476 if ip_version == I::VERSION {
2477 return Ok(self.datagram().get_dscp_and_ecn(id));
2478 };
2479
2480 self.datagram().with_other_stack_ip_options(id, |other_stack| {
2481 I::map_ip_in(
2482 WrapOtherStackIpOptions(other_stack),
2483 |_v4| Err(NotDualStackCapableError),
2484 |WrapOtherStackIpOptions(other_stack)| Ok(other_stack.socket_options.dscp_and_ecn),
2485 )
2486 })
2487 }
2488
2489 pub fn set_dscp_and_ecn(
2491 &mut self,
2492 id: &UdpApiSocketId<I, C>,
2493 value: DscpAndEcn,
2494 ip_version: IpVersion,
2495 ) -> Result<(), NotDualStackCapableError> {
2496 if ip_version == I::VERSION {
2497 self.datagram().set_dscp_and_ecn(id, value);
2498 return Ok(());
2499 };
2500
2501 self.datagram().with_other_stack_ip_options_mut(id, |other_stack| {
2502 I::map_ip(
2503 (IpInvariant(value), WrapOtherStackIpOptionsMut(other_stack)),
2504 |(IpInvariant(_interface), _v4)| Err(NotDualStackCapableError),
2505 |(IpInvariant(value), WrapOtherStackIpOptionsMut(other_stack))| {
2506 other_stack.socket_options.dscp_and_ecn = value;
2507 Ok(())
2508 },
2509 )
2510 })
2511 }
2512
2513 pub fn set_send_buffer(&mut self, id: &UdpApiSocketId<I, C>, size: usize) {
2515 self.datagram().set_send_buffer(id, size)
2516 }
2517
2518 pub fn send_buffer(&mut self, id: &UdpApiSocketId<I, C>) -> usize {
2520 self.datagram().send_buffer(id)
2521 }
2522
2523 #[cfg(any(test, feature = "testutils"))]
2525 pub fn send_buffer_available(&mut self, id: &UdpApiSocketId<I, C>) -> usize {
2526 self.datagram().send_buffer_available(id)
2527 }
2528
2529 pub fn disconnect(&mut self, id: &UdpApiSocketId<I, C>) -> Result<(), ExpectedConnError> {
2538 debug!("disconnect {id:?}");
2539 self.datagram().disconnect_connected(id)
2540 }
2541
2542 pub fn shutdown(
2548 &mut self,
2549 id: &UdpApiSocketId<I, C>,
2550 which: ShutdownType,
2551 ) -> Result<(), ExpectedConnError> {
2552 debug!("shutdown {id:?} {which:?}");
2553 self.datagram().shutdown_connected(id, which)
2554 }
2555
2556 pub fn get_shutdown(&mut self, id: &UdpApiSocketId<I, C>) -> Option<ShutdownType> {
2561 self.datagram().get_shutdown_connected(id)
2562 }
2563
2564 pub fn close(
2566 &mut self,
2567 id: UdpApiSocketId<I, C>,
2568 ) -> RemoveResourceResultWithContext<
2569 <C::BindingsContext as UdpBindingsTypes>::ExternalData<I>,
2570 C::BindingsContext,
2571 > {
2572 debug!("close {id:?}");
2573 self.datagram().close(id)
2574 }
2575
2576 pub fn get_info(
2579 &mut self,
2580 id: &UdpApiSocketId<I, C>,
2581 ) -> SocketInfo<I::Addr, <C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId> {
2582 self.datagram().get_info(id)
2583 }
2584
2585 pub fn listen(
2602 &mut self,
2603 id: &UdpApiSocketId<I, C>,
2604 addr: Option<
2605 ZonedAddr<
2606 SpecifiedAddr<I::Addr>,
2607 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId,
2608 >,
2609 >,
2610 port: Option<NonZeroU16>,
2611 ) -> Result<(), Either<ExpectedUnboundError, LocalAddressError>> {
2612 debug!("listen on {id:?} on {addr:?}:{port:?}");
2613 self.datagram().listen(id, addr, port)
2614 }
2615
2616 pub fn send<B: BufferMut>(
2624 &mut self,
2625 id: &UdpApiSocketId<I, C>,
2626 body: B,
2627 ) -> Result<(), Either<SendError, ExpectedConnError>> {
2628 self.core_ctx().increment_both(id, |c| &c.tx);
2629 self.datagram().send_conn(id, body).map_err(|err| {
2630 self.core_ctx().increment_both(id, |c| &c.tx_error);
2631 match err {
2632 DatagramSendError::NotConnected => Either::Right(ExpectedConnError),
2633 DatagramSendError::NotWriteable => Either::Left(SendError::NotWriteable),
2634 DatagramSendError::SendBufferFull => Either::Left(SendError::SendBufferFull),
2635 DatagramSendError::InvalidLength => Either::Left(SendError::InvalidLength),
2636 DatagramSendError::IpSock(err) => Either::Left(SendError::IpSock(err)),
2637 DatagramSendError::SerializeError(err) => match err {
2638 UdpSerializeError::RemotePortUnset => Either::Left(SendError::RemotePortUnset),
2639 },
2640 }
2641 })
2642 }
2643
2644 pub fn send_to<B: BufferMut>(
2655 &mut self,
2656 id: &UdpApiSocketId<I, C>,
2657 remote_ip: Option<
2658 ZonedAddr<
2659 SpecifiedAddr<I::Addr>,
2660 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId,
2661 >,
2662 >,
2663 remote_port: UdpRemotePort,
2664 body: B,
2665 ) -> Result<(), Either<LocalAddressError, SendToError>> {
2666 match remote_port {
2668 UdpRemotePort::Unset => return Err(Either::Right(SendToError::RemotePortUnset)),
2669 UdpRemotePort::Set(_) => {}
2670 }
2671
2672 self.core_ctx().increment_both(id, |c| &c.tx);
2673 self.datagram().send_to(id, remote_ip, remote_port, body).map_err(|e| {
2674 self.core_ctx().increment_both(id, |c| &c.tx_error);
2675 match e {
2676 Either::Left(e) => Either::Left(e),
2677 Either::Right(e) => {
2678 let err = match e {
2679 datagram::SendToError::SerializeError(err) => match err {
2680 UdpSerializeError::RemotePortUnset => SendToError::RemotePortUnset,
2681 },
2682 datagram::SendToError::NotWriteable => SendToError::NotWriteable,
2683 datagram::SendToError::SendBufferFull => SendToError::SendBufferFull,
2684 datagram::SendToError::InvalidLength => SendToError::InvalidLength,
2685 datagram::SendToError::Zone(e) => SendToError::Zone(e),
2686 datagram::SendToError::CreateAndSend(e) => match e {
2687 IpSockCreateAndSendError::Send(e) => SendToError::Send(e),
2688 IpSockCreateAndSendError::Create(e) => SendToError::CreateSock(e),
2689 },
2690 datagram::SendToError::RemoteUnexpectedlyMapped => {
2691 SendToError::RemoteUnexpectedlyMapped
2692 }
2693 datagram::SendToError::RemoteUnexpectedlyNonMapped => {
2694 SendToError::RemoteUnexpectedlyNonMapped
2695 }
2696 };
2697 Either::Right(err)
2698 }
2699 }
2700 })
2701 }
2702
2703 pub fn collect_all_sockets(&mut self) -> Vec<UdpApiSocketId<I, C>> {
2706 self.datagram().collect_all_sockets()
2707 }
2708
2709 pub fn inspect<N>(&mut self, inspector: &mut N)
2711 where
2712 N: Inspector
2713 + InspectorDeviceExt<<C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId>,
2714 for<'a> N::ChildInspector<'a>:
2715 InspectorDeviceExt<<C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId>,
2716 {
2717 DatagramStateContext::for_each_socket(self.core_ctx(), |_ctx, socket_id, socket_state| {
2718 inspector.record_debug_child(socket_id, |inspector| {
2719 socket_state.record_common_info(inspector);
2720 inspector.record_child("Counters", |inspector| {
2721 inspector.delegate_inspectable(&CombinedUdpCounters {
2722 with_socket: socket_id.counters(),
2723 without_socket: None,
2724 });
2725 });
2726 });
2727 });
2728 }
2729}
2730
2731#[derive(Copy, Clone, Debug, Eq, PartialEq, GenericOverIp, Error)]
2733#[generic_over_ip()]
2734pub enum SendError {
2735 #[error("socket not writable")]
2737 NotWriteable,
2738 #[error("packet couldn't be sent: {0}")]
2740 IpSock(#[from] IpSockSendError),
2741 #[error("remote port unset")]
2744 RemotePortUnset,
2745 #[error("send buffer is full")]
2747 SendBufferFull,
2748 #[error("invalid message length")]
2750 InvalidLength,
2751}
2752
2753impl<I: IpExt, BC: UdpBindingsContext<I, CC::DeviceId>, CC: StateContext<I, BC>>
2754 DatagramSpecStateContext<I, CC, BC> for Udp<BC>
2755{
2756 type SocketsStateCtx<'a> = CC::SocketStateCtx<'a>;
2757
2758 fn with_all_sockets_mut<O, F: FnOnce(&mut UdpSocketSet<I, CC::WeakDeviceId, BC>) -> O>(
2759 core_ctx: &mut CC,
2760 cb: F,
2761 ) -> O {
2762 StateContext::with_all_sockets_mut(core_ctx, cb)
2763 }
2764
2765 fn with_all_sockets<O, F: FnOnce(&UdpSocketSet<I, CC::WeakDeviceId, BC>) -> O>(
2766 core_ctx: &mut CC,
2767 cb: F,
2768 ) -> O {
2769 StateContext::with_all_sockets(core_ctx, cb)
2770 }
2771
2772 fn with_socket_state<
2773 O,
2774 F: FnOnce(&mut Self::SocketsStateCtx<'_>, &UdpSocketState<I, CC::WeakDeviceId, BC>) -> O,
2775 >(
2776 core_ctx: &mut CC,
2777 id: &UdpSocketId<I, CC::WeakDeviceId, BC>,
2778 cb: F,
2779 ) -> O {
2780 StateContext::with_socket_state(core_ctx, id, cb)
2781 }
2782
2783 fn with_socket_state_mut<
2784 O,
2785 F: FnOnce(&mut Self::SocketsStateCtx<'_>, &mut UdpSocketState<I, CC::WeakDeviceId, BC>) -> O,
2786 >(
2787 core_ctx: &mut CC,
2788 id: &UdpSocketId<I, CC::WeakDeviceId, BC>,
2789 cb: F,
2790 ) -> O {
2791 StateContext::with_socket_state_mut(core_ctx, id, cb)
2792 }
2793
2794 fn for_each_socket<
2795 F: FnMut(
2796 &mut Self::SocketsStateCtx<'_>,
2797 &UdpSocketId<I, CC::WeakDeviceId, BC>,
2798 &UdpSocketState<I, CC::WeakDeviceId, BC>,
2799 ),
2800 >(
2801 core_ctx: &mut CC,
2802 cb: F,
2803 ) {
2804 StateContext::for_each_socket(core_ctx, cb)
2805 }
2806}
2807
2808impl<
2809 I: IpExt,
2810 BC: UdpBindingsContext<I, CC::DeviceId>,
2811 CC: BoundStateContext<I, BC> + UdpStateContext,
2812> DatagramSpecBoundStateContext<I, CC, BC> for Udp<BC>
2813{
2814 type IpSocketsCtx<'a> = CC::IpSocketsCtx<'a>;
2815
2816 fn with_bound_sockets<O, F>(core_ctx: &mut CC, cb: F) -> O
2817 where
2818 F: FnOnce(&mut Self::IpSocketsCtx<'_>, &UdpBoundSocketMap<I, CC::WeakDeviceId, BC>) -> O,
2819 {
2820 core_ctx.with_bound_sockets(|core_ctx, BoundSockets { bound_sockets }| {
2821 cb(core_ctx, bound_sockets)
2822 })
2823 }
2824
2825 fn with_bound_sockets_mut<O, F>(core_ctx: &mut CC, cb: F) -> O
2826 where
2827 F: FnOnce(
2828 &mut Self::IpSocketsCtx<'_>,
2829 &mut UdpBoundSocketMap<I, CC::WeakDeviceId, BC>,
2830 ) -> O,
2831 {
2832 core_ctx.with_bound_sockets_mut(|core_ctx, BoundSockets { bound_sockets }| {
2833 cb(core_ctx, bound_sockets)
2834 })
2835 }
2836
2837 type DualStackContext = CC::DualStackContext;
2838 type NonDualStackContext = CC::NonDualStackContext;
2839 fn dual_stack_context_mut(
2840 core_ctx: &mut CC,
2841 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
2842 BoundStateContext::dual_stack_context_mut(core_ctx)
2843 }
2844
2845 fn dual_stack_context(
2846 core_ctx: &CC,
2847 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext> {
2848 BoundStateContext::dual_stack_context(core_ctx)
2849 }
2850
2851 fn with_transport_context<O, F>(core_ctx: &mut CC, cb: F) -> O
2852 where
2853 F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O,
2854 {
2855 core_ctx.with_transport_context(cb)
2856 }
2857}
2858
2859impl<
2860 BC: UdpBindingsContext<Ipv6, CC::DeviceId> + UdpBindingsContext<Ipv4, CC::DeviceId>,
2861 CC: DualStackBoundStateContext<Ipv6, BC> + UdpStateContext,
2862> DualStackDatagramSpecBoundStateContext<Ipv6, CC, BC> for Udp<BC>
2863{
2864 type IpSocketsCtx<'a> = CC::IpSocketsCtx<'a>;
2865 fn dual_stack_enabled(
2866 _core_ctx: &CC,
2867 ip_options: &IpOptions<Ipv6, CC::WeakDeviceId, Udp<BC>>,
2868 ) -> bool {
2869 let DualStackSocketState { dual_stack_enabled, .. } = ip_options.other_stack();
2870 *dual_stack_enabled
2871 }
2872
2873 fn to_other_socket_options<'a>(
2874 _core_ctx: &CC,
2875 state: &'a IpOptions<Ipv6, CC::WeakDeviceId, Udp<BC>>,
2876 ) -> &'a DatagramIpSpecificSocketOptions<Ipv4, CC::WeakDeviceId> {
2877 &state.other_stack().socket_options
2878 }
2879
2880 fn ds_converter(_core_ctx: &CC) -> impl DualStackConverter<Ipv6, CC::WeakDeviceId, Self> {
2881 ()
2882 }
2883
2884 fn to_other_bound_socket_id(
2885 _core_ctx: &CC,
2886 id: &UdpSocketId<Ipv6, CC::WeakDeviceId, BC>,
2887 ) -> EitherIpSocket<CC::WeakDeviceId, Udp<BC>> {
2888 EitherIpSocket::V6(id.clone())
2889 }
2890
2891 fn with_both_bound_sockets_mut<O, F>(core_ctx: &mut CC, cb: F) -> O
2892 where
2893 F: FnOnce(
2894 &mut Self::IpSocketsCtx<'_>,
2895 &mut UdpBoundSocketMap<Ipv6, CC::WeakDeviceId, BC>,
2896 &mut UdpBoundSocketMap<Ipv4, CC::WeakDeviceId, BC>,
2897 ) -> O,
2898 {
2899 core_ctx.with_both_bound_sockets_mut(
2900 |core_ctx,
2901 BoundSockets { bound_sockets: bound_first },
2902 BoundSockets { bound_sockets: bound_second }| {
2903 cb(core_ctx, bound_first, bound_second)
2904 },
2905 )
2906 }
2907
2908 fn with_other_bound_sockets_mut<
2909 O,
2910 F: FnOnce(
2911 &mut Self::IpSocketsCtx<'_>,
2912 &mut UdpBoundSocketMap<Ipv4, CC::WeakDeviceId, BC>,
2913 ) -> O,
2914 >(
2915 core_ctx: &mut CC,
2916 cb: F,
2917 ) -> O {
2918 core_ctx.with_other_bound_sockets_mut(|core_ctx, BoundSockets { bound_sockets }| {
2919 cb(core_ctx, bound_sockets)
2920 })
2921 }
2922
2923 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
2924 core_ctx: &mut CC,
2925 cb: F,
2926 ) -> O {
2927 core_ctx.with_transport_context(|core_ctx| cb(core_ctx))
2928 }
2929}
2930
2931impl<
2932 BC: UdpBindingsContext<Ipv4, CC::DeviceId>,
2933 CC: BoundStateContext<Ipv4, BC> + NonDualStackBoundStateContext<Ipv4, BC> + UdpStateContext,
2934> NonDualStackDatagramSpecBoundStateContext<Ipv4, CC, BC> for Udp<BC>
2935{
2936 fn nds_converter(_core_ctx: &CC) -> impl NonDualStackConverter<Ipv4, CC::WeakDeviceId, Self> {
2937 ()
2938 }
2939}
2940
2941#[cfg(test)]
2942pub(crate) mod testutils {
2943 use alloc::borrow::ToOwned;
2944 use alloc::vec;
2945 use core::ops::{Deref, DerefMut};
2946 use netstack3_ip::IpLayerIpExt;
2947
2948 use net_types::ip::{IpAddr, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr, Ipv6SourceAddr};
2949 use netstack3_base::testutil::{
2950 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeSocketWritableListener, FakeStrongDeviceId,
2951 FakeWeakDeviceId,
2952 };
2953 use netstack3_base::{CtxPair, ResourceCounterContext, UninstantiableWrapper};
2954 use netstack3_hashmap::HashMap;
2955 use netstack3_ip::device::IpDeviceStateIpExt;
2956 use netstack3_ip::socket::testutil::{FakeDeviceConfig, FakeDualStackIpSocketCtx};
2957 use netstack3_ip::testutil::DualStackSendIpPacketMeta;
2958
2959 use super::*;
2960 #[derive(Debug, Derivative, PartialEq)]
2962 #[derivative(Default(bound = ""))]
2963 pub(crate) struct SocketReceived<I: Ip> {
2964 pub(crate) packets: Vec<ReceivedPacket<I>>,
2965 #[derivative(Default(value = "usize::MAX"))]
2966 pub(crate) max_size: usize,
2967 }
2968
2969 #[derive(Debug, PartialEq)]
2970 pub(crate) struct ReceivedPacket<I: Ip> {
2971 pub(crate) meta: UdpPacketMeta<I>,
2972 pub(crate) body: Vec<u8>,
2973 }
2974
2975 impl<D: FakeStrongDeviceId> FakeUdpCoreCtx<D> {
2976 pub(crate) fn new_with_device<I: TestIpExt>(device: D) -> Self {
2977 Self::with_local_remote_ip_addrs_and_device(
2978 vec![local_ip::<I>()],
2979 vec![remote_ip::<I>()],
2980 device,
2981 )
2982 }
2983
2984 fn with_local_remote_ip_addrs_and_device<A: Into<SpecifiedAddr<IpAddr>>>(
2985 local_ips: Vec<A>,
2986 remote_ips: Vec<A>,
2987 device: D,
2988 ) -> Self {
2989 Self::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
2990 device,
2991 local_ips,
2992 remote_ips,
2993 }]))
2994 }
2995
2996 pub(crate) fn with_ip_socket_ctx_state(state: FakeDualStackIpSocketCtx<D>) -> Self {
2997 Self {
2998 all_sockets: Default::default(),
2999 bound_sockets: FakeUdpBoundSocketsCtx {
3000 bound_sockets: Default::default(),
3001 ip_socket_ctx: InnerIpSocketCtx::with_state(state),
3002 },
3003 }
3004 }
3005 }
3006
3007 impl FakeUdpCoreCtx<FakeDeviceId> {
3008 pub(crate) fn new_fake_device<I: TestIpExt>() -> Self {
3009 Self::new_with_device::<I>(FakeDeviceId)
3010 }
3011
3012 pub(crate) fn with_local_remote_ip_addrs<A: Into<SpecifiedAddr<IpAddr>>>(
3013 local_ips: Vec<A>,
3014 remote_ips: Vec<A>,
3015 ) -> Self {
3016 Self::with_local_remote_ip_addrs_and_device(local_ips, remote_ips, FakeDeviceId)
3017 }
3018 }
3019
3020 pub(crate) type FakeUdpCtx<D> = CtxPair<FakeUdpCoreCtx<D>, FakeUdpBindingsCtx<D>>;
3022
3023 #[derive(Derivative)]
3024 #[derivative(Default(bound = ""))]
3025 pub(crate) struct FakeBoundSockets<D: StrongDeviceIdentifier> {
3026 v4: BoundSockets<Ipv4, D::Weak, FakeUdpBindingsCtx<D>>,
3027 v6: BoundSockets<Ipv6, D::Weak, FakeUdpBindingsCtx<D>>,
3028 }
3029
3030 impl<D: StrongDeviceIdentifier> FakeBoundSockets<D> {
3031 fn bound_sockets<I: IpExt>(&self) -> &BoundSockets<I, D::Weak, FakeUdpBindingsCtx<D>> {
3032 I::map_ip_out(self, |state| &state.v4, |state| &state.v6)
3033 }
3034
3035 fn bound_sockets_mut<I: IpExt>(
3036 &mut self,
3037 ) -> &mut BoundSockets<I, D::Weak, FakeUdpBindingsCtx<D>> {
3038 I::map_ip_out(self, |state| &mut state.v4, |state| &mut state.v6)
3039 }
3040 }
3041
3042 pub(crate) struct FakeUdpBoundSocketsCtx<D: FakeStrongDeviceId> {
3043 pub(crate) bound_sockets: FakeBoundSockets<D>,
3044 pub(crate) ip_socket_ctx: InnerIpSocketCtx<D>,
3045 }
3046
3047 pub(crate) type FakeUdpBindingsCtx<D> = FakeBindingsCtx<(), (), FakeBindingsCtxState<D>, ()>;
3049
3050 type InnerIpSocketCtx<D> =
3053 FakeCoreCtx<FakeDualStackIpSocketCtx<D>, DualStackSendIpPacketMeta<D>, D>;
3054
3055 pub(crate) type UdpFakeDeviceCtx = FakeUdpCtx<FakeDeviceId>;
3056 pub(crate) type UdpFakeDeviceCoreCtx = FakeUdpCoreCtx<FakeDeviceId>;
3057
3058 #[derive(Derivative)]
3059 #[derivative(Default(bound = ""))]
3060 pub(crate) struct FakeBindingsCtxState<D: StrongDeviceIdentifier> {
3061 received_v4:
3062 HashMap<WeakUdpSocketId<Ipv4, D::Weak, FakeUdpBindingsCtx<D>>, SocketReceived<Ipv4>>,
3063 received_v6:
3064 HashMap<WeakUdpSocketId<Ipv6, D::Weak, FakeUdpBindingsCtx<D>>, SocketReceived<Ipv6>>,
3065 }
3066
3067 impl<D: StrongDeviceIdentifier> FakeBindingsCtxState<D> {
3068 pub(crate) fn received<I: TestIpExt>(
3069 &self,
3070 ) -> &HashMap<WeakUdpSocketId<I, D::Weak, FakeUdpBindingsCtx<D>>, SocketReceived<I>>
3071 {
3072 #[derive(GenericOverIp)]
3073 #[generic_over_ip(I, Ip)]
3074 struct Wrap<'a, I: TestIpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
3075 &'a HashMap<WeakUdpSocketId<I, D, BT>, SocketReceived<I>>,
3076 );
3077 let Wrap(map) = I::map_ip_out(
3078 self,
3079 |state| Wrap(&state.received_v4),
3080 |state| Wrap(&state.received_v6),
3081 );
3082 map
3083 }
3084
3085 pub(crate) fn received_mut<I: IpExt>(
3086 &mut self,
3087 ) -> &mut HashMap<WeakUdpSocketId<I, D::Weak, FakeUdpBindingsCtx<D>>, SocketReceived<I>>
3088 {
3089 #[derive(GenericOverIp)]
3090 #[generic_over_ip(I, Ip)]
3091 struct Wrap<'a, I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes>(
3092 &'a mut HashMap<WeakUdpSocketId<I, D, BT>, SocketReceived<I>>,
3093 );
3094 let Wrap(map) = I::map_ip_out(
3095 self,
3096 |state| Wrap(&mut state.received_v4),
3097 |state| Wrap(&mut state.received_v6),
3098 );
3099 map
3100 }
3101
3102 pub(crate) fn socket_data<I: TestIpExt>(
3103 &self,
3104 ) -> HashMap<WeakUdpSocketId<I, D::Weak, FakeUdpBindingsCtx<D>>, Vec<&'_ [u8]>> {
3105 self.received::<I>()
3106 .iter()
3107 .map(|(id, SocketReceived { packets, .. })| {
3108 (
3109 id.clone(),
3110 packets.iter().map(|ReceivedPacket { meta: _, body }| &body[..]).collect(),
3111 )
3112 })
3113 .collect()
3114 }
3115 }
3116
3117 impl<I: IpExt, D: StrongDeviceIdentifier> UdpReceiveBindingsContext<I, D>
3118 for FakeUdpBindingsCtx<D>
3119 {
3120 fn receive_udp(
3121 &mut self,
3122 id: &UdpSocketId<I, D::Weak, Self>,
3123 _device_id: &D,
3124 meta: UdpPacketMeta<I>,
3125 body: &[u8],
3126 ) -> Result<(), ReceiveUdpError> {
3127 let SocketReceived { packets, max_size } =
3128 self.state.received_mut::<I>().entry(id.downgrade()).or_default();
3129 if packets.len() < *max_size {
3130 packets.push(ReceivedPacket { meta, body: body.to_owned() });
3131 Ok(())
3132 } else {
3133 Err(ReceiveUdpError::QueueFull)
3134 }
3135 }
3136 }
3137
3138 impl<D: StrongDeviceIdentifier> UdpBindingsTypes for FakeUdpBindingsCtx<D> {
3139 type ExternalData<I: Ip> = ();
3140 type SocketWritableListener = FakeSocketWritableListener;
3141 }
3142
3143 impl<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes> UdpSocketId<I, D, BT> {
3145 fn get(&self) -> impl Deref<Target = UdpSocketState<I, D, BT>> + '_ {
3146 self.state().read()
3147 }
3148
3149 fn get_mut(&self) -> impl DerefMut<Target = UdpSocketState<I, D, BT>> + '_ {
3150 self.state().write()
3151 }
3152 }
3153
3154 impl<D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeUdpCoreCtx<D> {
3155 type DeviceId = D;
3156 type WeakDeviceId = FakeWeakDeviceId<D>;
3157 }
3158
3159 impl<D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeUdpBoundSocketsCtx<D> {
3160 type DeviceId = D;
3161 type WeakDeviceId = FakeWeakDeviceId<D>;
3162 }
3163
3164 impl<I: TestIpExt, D: FakeStrongDeviceId> StateContext<I, FakeUdpBindingsCtx<D>>
3165 for FakeUdpCoreCtx<D>
3166 {
3167 type SocketStateCtx<'a> = FakeUdpBoundSocketsCtx<D>;
3168
3169 fn with_all_sockets_mut<
3170 O,
3171 F: FnOnce(&mut UdpSocketSet<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>) -> O,
3172 >(
3173 &mut self,
3174 cb: F,
3175 ) -> O {
3176 cb(self.all_sockets.socket_set_mut())
3177 }
3178
3179 fn with_all_sockets<
3180 O,
3181 F: FnOnce(&UdpSocketSet<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>) -> O,
3182 >(
3183 &mut self,
3184 cb: F,
3185 ) -> O {
3186 cb(self.all_sockets.socket_set())
3187 }
3188
3189 fn with_socket_state<
3190 O,
3191 F: FnOnce(
3192 &mut Self::SocketStateCtx<'_>,
3193 &UdpSocketState<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3194 ) -> O,
3195 >(
3196 &mut self,
3197 id: &UdpSocketId<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3198 cb: F,
3199 ) -> O {
3200 cb(&mut self.bound_sockets, &id.get())
3201 }
3202
3203 fn with_socket_state_mut<
3204 O,
3205 F: FnOnce(
3206 &mut Self::SocketStateCtx<'_>,
3207 &mut UdpSocketState<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3208 ) -> O,
3209 >(
3210 &mut self,
3211 id: &UdpSocketId<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3212 cb: F,
3213 ) -> O {
3214 cb(&mut self.bound_sockets, &mut id.get_mut())
3215 }
3216
3217 fn with_bound_state_context<O, F: FnOnce(&mut Self::SocketStateCtx<'_>) -> O>(
3218 &mut self,
3219 cb: F,
3220 ) -> O {
3221 cb(&mut self.bound_sockets)
3222 }
3223
3224 fn for_each_socket<
3225 F: FnMut(
3226 &mut Self::SocketStateCtx<'_>,
3227 &UdpSocketId<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3228 &UdpSocketState<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3229 ),
3230 >(
3231 &mut self,
3232 mut cb: F,
3233 ) {
3234 self.all_sockets.socket_set().keys().for_each(|id| {
3235 let id = UdpSocketId::from(id.clone());
3236 cb(&mut self.bound_sockets, &id, &id.get());
3237 })
3238 }
3239 }
3240
3241 impl<I: TestIpExt, D: FakeStrongDeviceId> BoundStateContext<I, FakeUdpBindingsCtx<D>>
3242 for FakeUdpBoundSocketsCtx<D>
3243 {
3244 type IpSocketsCtx<'a> = InnerIpSocketCtx<D>;
3245 type DualStackContext = I::UdpDualStackBoundStateContext<D>;
3246 type NonDualStackContext = I::UdpNonDualStackBoundStateContext<D>;
3247
3248 fn with_bound_sockets<
3249 O,
3250 F: FnOnce(
3251 &mut Self::IpSocketsCtx<'_>,
3252 &BoundSockets<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3253 ) -> O,
3254 >(
3255 &mut self,
3256 cb: F,
3257 ) -> O {
3258 let Self { bound_sockets, ip_socket_ctx } = self;
3259 cb(ip_socket_ctx, bound_sockets.bound_sockets())
3260 }
3261
3262 fn with_bound_sockets_mut<
3263 O,
3264 F: FnOnce(
3265 &mut Self::IpSocketsCtx<'_>,
3266 &mut BoundSockets<I, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3267 ) -> O,
3268 >(
3269 &mut self,
3270 cb: F,
3271 ) -> O {
3272 let Self { bound_sockets, ip_socket_ctx } = self;
3273 cb(ip_socket_ctx, bound_sockets.bound_sockets_mut())
3274 }
3275
3276 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
3277 &mut self,
3278 cb: F,
3279 ) -> O {
3280 cb(&mut self.ip_socket_ctx)
3281 }
3282
3283 fn dual_stack_context(
3284 &self,
3285 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext> {
3286 struct Wrap<'a, I: TestIpExt, D: FakeStrongDeviceId + 'static>(
3287 MaybeDualStack<
3288 &'a I::UdpDualStackBoundStateContext<D>,
3289 &'a I::UdpNonDualStackBoundStateContext<D>,
3290 >,
3291 );
3292 impl<'a, I: TestIpExt, NewIp: TestIpExt, D: FakeStrongDeviceId + 'static>
3294 GenericOverIp<NewIp> for Wrap<'a, I, D>
3295 {
3296 type Type = Wrap<'a, NewIp, D>;
3297 }
3298
3299 let Wrap(context) = I::map_ip_out(
3300 self,
3301 |this| Wrap(MaybeDualStack::NotDualStack(this)),
3302 |this| Wrap(MaybeDualStack::DualStack(this)),
3303 );
3304 context
3305 }
3306
3307 fn dual_stack_context_mut(
3308 &mut self,
3309 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
3310 struct Wrap<'a, I: TestIpExt, D: FakeStrongDeviceId + 'static>(
3311 MaybeDualStack<
3312 &'a mut I::UdpDualStackBoundStateContext<D>,
3313 &'a mut 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
3332 impl<D: FakeStrongDeviceId + 'static> UdpStateContext for FakeUdpBoundSocketsCtx<D> {}
3333
3334 impl<D: FakeStrongDeviceId> NonDualStackBoundStateContext<Ipv4, FakeUdpBindingsCtx<D>>
3335 for FakeUdpBoundSocketsCtx<D>
3336 {
3337 }
3338
3339 impl<D: FakeStrongDeviceId> DualStackBoundStateContext<Ipv6, FakeUdpBindingsCtx<D>>
3340 for FakeUdpBoundSocketsCtx<D>
3341 {
3342 type IpSocketsCtx<'a> = InnerIpSocketCtx<D>;
3343
3344 fn with_both_bound_sockets_mut<
3345 O,
3346 F: FnOnce(
3347 &mut Self::IpSocketsCtx<'_>,
3348 &mut BoundSockets<Ipv6, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3349 &mut BoundSockets<Ipv4, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3350 ) -> O,
3351 >(
3352 &mut self,
3353 cb: F,
3354 ) -> O {
3355 let Self { ip_socket_ctx, bound_sockets: FakeBoundSockets { v4, v6 } } = self;
3356 cb(ip_socket_ctx, v6, v4)
3357 }
3358
3359 fn with_other_bound_sockets_mut<
3360 O,
3361 F: FnOnce(
3362 &mut Self::IpSocketsCtx<'_>,
3363 &mut BoundSockets<Ipv4, Self::WeakDeviceId, FakeUdpBindingsCtx<D>>,
3364 ) -> O,
3365 >(
3366 &mut self,
3367 cb: F,
3368 ) -> O {
3369 DualStackBoundStateContext::with_both_bound_sockets_mut(
3370 self,
3371 |core_ctx, _bound, other_bound| cb(core_ctx, other_bound),
3372 )
3373 }
3374
3375 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
3376 &mut self,
3377 cb: F,
3378 ) -> O {
3379 cb(&mut self.ip_socket_ctx)
3380 }
3381 }
3382
3383 impl<I: IpLayerIpExt + TestIpExt, D: FakeStrongDeviceId>
3385 IpTransportContext<I, FakeUdpBindingsCtx<D>, FakeUdpCoreCtx<D>> for UdpIpTransportContext
3386 {
3387 type EarlyDemuxSocket = DualStackUdpSocketId<I, D::Weak, FakeUdpBindingsCtx<D>>;
3388
3389 fn early_demux<B: ParseBuffer>(
3390 core_ctx: &mut FakeUdpCoreCtx<D>,
3391 device: &D,
3392 src_ip: I::Addr,
3393 dst_ip: I::Addr,
3394 buffer: B,
3395 ) -> Option<Self::EarlyDemuxSocket> {
3396 early_demux_ip_packet::<I, _, _, _>(core_ctx, device, src_ip, dst_ip, buffer)
3397 }
3398
3399 fn receive_icmp_error(
3400 _core_ctx: &mut FakeUdpCoreCtx<D>,
3401 _bindings_ctx: &mut FakeUdpBindingsCtx<D>,
3402 _device: &D,
3403 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3404 _original_dst_ip: SpecifiedAddr<I::Addr>,
3405 _original_udp_packet: &[u8],
3406 _err: I::ErrorCode,
3407 ) {
3408 unimplemented!()
3409 }
3410
3411 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
3412 core_ctx: &mut FakeUdpCoreCtx<D>,
3413 bindings_ctx: &mut FakeUdpBindingsCtx<D>,
3414 device: &D,
3415 src_ip: I::RecvSrcAddr,
3416 dst_ip: SpecifiedAddr<I::Addr>,
3417 buffer: B,
3418 info: &LocalDeliveryPacketInfo<I, H>,
3419 early_demux_socket: Option<Self::EarlyDemuxSocket>,
3420 ) -> Result<(), (B, I::IcmpError)> {
3421 receive_ip_packet::<I, _, _, _, _>(
3422 core_ctx,
3423 bindings_ctx,
3424 device,
3425 src_ip,
3426 dst_ip,
3427 buffer,
3428 info,
3429 early_demux_socket,
3430 )
3431 }
3432 }
3433
3434 #[derive(Derivative)]
3435 #[derivative(Default(bound = ""))]
3436 pub(crate) struct FakeDualStackSocketState<D: StrongDeviceIdentifier> {
3437 v4: UdpSocketSet<Ipv4, D::Weak, FakeUdpBindingsCtx<D>>,
3438 v6: UdpSocketSet<Ipv6, D::Weak, FakeUdpBindingsCtx<D>>,
3439 udpv4_counters_with_socket: UdpCountersWithSocket<Ipv4>,
3440 udpv6_counters_with_socket: UdpCountersWithSocket<Ipv6>,
3441 udpv4_counters_without_socket: UdpCountersWithoutSocket<Ipv4>,
3442 udpv6_counters_without_socket: UdpCountersWithoutSocket<Ipv6>,
3443 }
3444
3445 impl<D: StrongDeviceIdentifier> FakeDualStackSocketState<D> {
3446 fn socket_set<I: IpExt>(&self) -> &UdpSocketSet<I, D::Weak, FakeUdpBindingsCtx<D>> {
3447 I::map_ip_out(self, |dual| &dual.v4, |dual| &dual.v6)
3448 }
3449
3450 fn socket_set_mut<I: IpExt>(
3451 &mut self,
3452 ) -> &mut UdpSocketSet<I, D::Weak, FakeUdpBindingsCtx<D>> {
3453 I::map_ip_out(self, |dual| &mut dual.v4, |dual| &mut dual.v6)
3454 }
3455
3456 fn udp_counters_with_socket<I: Ip>(&self) -> &UdpCountersWithSocket<I> {
3457 I::map_ip_out(
3458 self,
3459 |dual| &dual.udpv4_counters_with_socket,
3460 |dual| &dual.udpv6_counters_with_socket,
3461 )
3462 }
3463 fn udp_counters_without_socket<I: Ip>(&self) -> &UdpCountersWithoutSocket<I> {
3464 I::map_ip_out(
3465 self,
3466 |dual| &dual.udpv4_counters_without_socket,
3467 |dual| &dual.udpv6_counters_without_socket,
3468 )
3469 }
3470 }
3471 pub(crate) struct FakeUdpCoreCtx<D: FakeStrongDeviceId> {
3472 pub(crate) bound_sockets: FakeUdpBoundSocketsCtx<D>,
3473 pub(crate) all_sockets: FakeDualStackSocketState<D>,
3476 }
3477
3478 impl<I: Ip, D: FakeStrongDeviceId> CounterContext<UdpCountersWithSocket<I>> for FakeUdpCoreCtx<D> {
3479 fn counters(&self) -> &UdpCountersWithSocket<I> {
3480 &self.all_sockets.udp_counters_with_socket()
3481 }
3482 }
3483
3484 impl<I: Ip, D: FakeStrongDeviceId> CounterContext<UdpCountersWithoutSocket<I>>
3485 for FakeUdpCoreCtx<D>
3486 {
3487 fn counters(&self) -> &UdpCountersWithoutSocket<I> {
3488 &self.all_sockets.udp_counters_without_socket()
3489 }
3490 }
3491
3492 impl<I: DualStackIpExt, D: FakeStrongDeviceId>
3493 ResourceCounterContext<
3494 UdpSocketId<I, FakeWeakDeviceId<D>, FakeUdpBindingsCtx<D>>,
3495 UdpCountersWithSocket<I>,
3496 > for FakeUdpCoreCtx<D>
3497 {
3498 fn per_resource_counters<'a>(
3499 &'a self,
3500 resource: &'a UdpSocketId<I, FakeWeakDeviceId<D>, FakeUdpBindingsCtx<D>>,
3501 ) -> &'a UdpCountersWithSocket<I> {
3502 resource.counters()
3503 }
3504 }
3505
3506 pub(crate) fn local_ip<I: TestIpExt>() -> SpecifiedAddr<I::Addr> {
3507 I::get_other_ip_address(1)
3508 }
3509
3510 pub(crate) fn remote_ip<I: TestIpExt>() -> SpecifiedAddr<I::Addr> {
3511 I::get_other_ip_address(2)
3512 }
3513
3514 pub(crate) trait BaseTestIpExt:
3515 netstack3_base::testutil::TestIpExt + IpExt + IpDeviceStateIpExt
3516 {
3517 type UdpDualStackBoundStateContext<D: FakeStrongDeviceId + 'static>:
3518 DualStackDatagramBoundStateContext<Self, FakeUdpBindingsCtx<D>, Udp<FakeUdpBindingsCtx<D>>, DeviceId=D, WeakDeviceId=D::Weak>;
3519 type UdpNonDualStackBoundStateContext<D: FakeStrongDeviceId + 'static>:
3520 NonDualStackDatagramBoundStateContext<Self, FakeUdpBindingsCtx<D>, Udp<FakeUdpBindingsCtx<D>>, DeviceId=D, WeakDeviceId=D::Weak>;
3521 fn into_recv_src_addr(addr: Self::Addr) -> Self::RecvSrcAddr;
3522 }
3523
3524 impl BaseTestIpExt for Ipv4 {
3525 type UdpDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
3526 UninstantiableWrapper<FakeUdpBoundSocketsCtx<D>>;
3527
3528 type UdpNonDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
3529 FakeUdpBoundSocketsCtx<D>;
3530
3531 fn into_recv_src_addr(addr: Ipv4Addr) -> Ipv4SourceAddr {
3532 Ipv4SourceAddr::new(addr).unwrap_or_else(|| panic!("{addr} is not a valid source addr"))
3533 }
3534 }
3535
3536 impl BaseTestIpExt for Ipv6 {
3537 type UdpDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
3538 FakeUdpBoundSocketsCtx<D>;
3539 type UdpNonDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
3540 UninstantiableWrapper<FakeUdpBoundSocketsCtx<D>>;
3541
3542 fn into_recv_src_addr(addr: Ipv6Addr) -> Ipv6SourceAddr {
3543 Ipv6SourceAddr::new(addr).unwrap_or_else(|| panic!("{addr} is not a valid source addr"))
3544 }
3545 }
3546
3547 pub(crate) trait TestIpExt: BaseTestIpExt<OtherVersion: BaseTestIpExt> {}
3548 impl<I: BaseTestIpExt<OtherVersion: BaseTestIpExt>> TestIpExt for I {}
3549}
3550
3551#[cfg(test)]
3552mod tests {
3553 use alloc::borrow::ToOwned;
3554 use alloc::vec;
3555 use core::convert::TryInto as _;
3556 use core::num::NonZeroU16;
3557
3558 use assert_matches::assert_matches;
3559 use ip_test_macro::ip_test;
3560 use itertools::Itertools as _;
3561 use net_declare::{net_ip_v4 as ip_v4, net_ip_v6};
3562 use net_types::ip::{IpAddr, IpAddress, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
3563 use net_types::{
3564 AddrAndZone, LinkLocalAddr, MulticastAddr, Scope as _, ScopeableAddress as _, ZonedAddr,
3565 };
3566 use netstack3_base::socket::{SocketIpAddrExt as _, StrictlyZonedAddr};
3567 use netstack3_base::sync::PrimaryRc;
3568 use netstack3_base::testutil::{
3569 FakeDeviceId, FakeReferencyDeviceId, FakeStrongDeviceId, FakeWeakDeviceId,
3570 MultipleDevicesId, TestIpExt as _, set_logger_for_test,
3571 };
3572 use netstack3_base::{
3573 CounterCollection, Mark, MarkDomain, RemoteAddressError, SendFrameErrorReason,
3574 };
3575 use netstack3_datagram::MulticastInterfaceSelector;
3576 use netstack3_hashmap::{HashMap, HashSet};
3577 use netstack3_ip::socket::testutil::{FakeDeviceConfig, FakeDualStackIpSocketCtx};
3578 use netstack3_ip::testutil::{DualStackSendIpPacketMeta, FakeIpHeaderInfo};
3579 use netstack3_ip::{IpLayerIpExt, IpPacketDestination, ResolveRouteError, SendIpPacketMeta};
3580 use packet::{Buf, Serializer};
3581 use test_case::test_case;
3582
3583 use crate::internal::counters::testutil::{
3584 CounterExpectationsWithSocket, CounterExpectationsWithoutSocket,
3585 };
3586
3587 use super::testutils::{
3588 FakeUdpBindingsCtx, FakeUdpCoreCtx, FakeUdpCtx, ReceivedPacket, SocketReceived, TestIpExt,
3589 UdpFakeDeviceCoreCtx, UdpFakeDeviceCtx, local_ip, remote_ip,
3590 };
3591 use super::*;
3592
3593 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
3594 enum EarlyDemuxMode {
3595 Enabled,
3596 Disabled,
3597 }
3598 use EarlyDemuxMode::{Disabled as NoEarlyDemux, Enabled as WithEarlyDemux};
3599
3600 fn receive_udp_packet<I, D, CC>(
3602 core_ctx: &mut CC,
3603 bindings_ctx: &mut FakeUdpBindingsCtx<D>,
3604 device: D,
3605 meta: UdpPacketMeta<I>,
3606 body: &[u8],
3607 early_demux_mode: EarlyDemuxMode,
3608 ) -> Result<(), I::IcmpError>
3609 where
3610 UdpIpTransportContext: IpTransportContext<I, FakeUdpBindingsCtx<D>, CC>,
3611 I: IpLayerIpExt + TestIpExt,
3612 D: FakeStrongDeviceId,
3613 CC: DeviceIdContext<AnyDevice, DeviceId = D>,
3614 {
3615 let UdpPacketMeta { src_ip, src_port, dst_ip, dst_port, dscp_and_ecn } = meta;
3616 let builder = UdpPacketBuilder::new(src_ip, dst_ip, src_port, dst_port);
3617
3618 let buffer = builder
3619 .wrap_body(Buf::new(body.to_owned(), ..))
3620 .serialize_vec_outer()
3621 .unwrap()
3622 .into_inner();
3623
3624 let early_demux_socket = match early_demux_mode {
3625 EarlyDemuxMode::Enabled => {
3626 <UdpIpTransportContext as IpTransportContext<I, _, _>>::early_demux(
3627 core_ctx,
3628 &device,
3629 src_ip,
3630 dst_ip,
3631 buffer.as_ref(),
3632 )
3633 }
3634 EarlyDemuxMode::Disabled => None,
3635 };
3636
3637 <UdpIpTransportContext as IpTransportContext<I, _, _>>::receive_ip_packet(
3638 core_ctx,
3639 bindings_ctx,
3640 &device,
3641 I::into_recv_src_addr(src_ip),
3642 SpecifiedAddr::new(dst_ip).unwrap(),
3643 buffer,
3644 &LocalDeliveryPacketInfo {
3645 header_info: FakeIpHeaderInfo { dscp_and_ecn, ..Default::default() },
3646 ..Default::default()
3647 },
3648 early_demux_socket,
3649 )
3650 .map_err(|(_buffer, e)| e)
3651 }
3652
3653 const LOCAL_PORT: NonZeroU16 = NonZeroU16::new(100).unwrap();
3654 const OTHER_LOCAL_PORT: NonZeroU16 = LOCAL_PORT.checked_add(1).unwrap();
3655 const REMOTE_PORT: NonZeroU16 = NonZeroU16::new(200).unwrap();
3656 const OTHER_REMOTE_PORT: NonZeroU16 = REMOTE_PORT.checked_add(1).unwrap();
3657
3658 fn conn_addr<I>(
3659 device: Option<FakeWeakDeviceId<FakeDeviceId>>,
3660 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>
3661 where
3662 I: TestIpExt,
3663 {
3664 let local_ip = SocketIpAddr::try_from(local_ip::<I>()).unwrap();
3665 let remote_ip = SocketIpAddr::try_from(remote_ip::<I>()).unwrap();
3666 ConnAddr {
3667 ip: ConnIpAddr {
3668 local: (local_ip, LOCAL_PORT),
3669 remote: (remote_ip, REMOTE_PORT.into()),
3670 },
3671 device,
3672 }
3673 .into()
3674 }
3675
3676 fn local_listener<I>(
3677 device: Option<FakeWeakDeviceId<FakeDeviceId>>,
3678 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>
3679 where
3680 I: TestIpExt,
3681 {
3682 let local_ip = SocketIpAddr::try_from(local_ip::<I>()).unwrap();
3683 ListenerAddr { ip: ListenerIpAddr { identifier: LOCAL_PORT, addr: Some(local_ip) }, device }
3684 .into()
3685 }
3686
3687 fn wildcard_listener<I>(
3688 device: Option<FakeWeakDeviceId<FakeDeviceId>>,
3689 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>
3690 where
3691 I: TestIpExt,
3692 {
3693 ListenerAddr { ip: ListenerIpAddr { identifier: LOCAL_PORT, addr: None }, device }.into()
3694 }
3695
3696 #[track_caller]
3697 fn assert_counters<
3698 'a,
3699 I: IpExt,
3700 D: WeakDeviceIdentifier,
3701 BT: UdpBindingsTypes,
3702 CC: UdpCounterContext<I, D, BT>,
3703 >(
3704 core_ctx: &CC,
3705 with_socket_expects: CounterExpectationsWithSocket,
3706 without_socket_expects: CounterExpectationsWithoutSocket,
3707 per_socket_expects: impl IntoIterator<
3708 Item = (&'a UdpSocketId<I, D, BT>, CounterExpectationsWithSocket),
3709 >,
3710 ) {
3711 assert_eq!(
3712 CounterContext::<UdpCountersWithSocket<I>>::counters(core_ctx).cast(),
3713 with_socket_expects
3714 );
3715 assert_eq!(
3716 CounterContext::<UdpCountersWithoutSocket<I>>::counters(core_ctx).cast(),
3717 without_socket_expects
3718 );
3719 for (id, expects) in per_socket_expects.into_iter() {
3720 assert_eq!(core_ctx.per_resource_counters(id).cast(), expects);
3721 }
3722 }
3723
3724 #[ip_test(I)]
3725 #[test_case(conn_addr(Some(FakeWeakDeviceId(FakeDeviceId))), [
3726 conn_addr(None), local_listener(Some(FakeWeakDeviceId(FakeDeviceId))), local_listener(None),
3727 wildcard_listener(Some(FakeWeakDeviceId(FakeDeviceId))), wildcard_listener(None)
3728 ]; "conn with device")]
3729 #[test_case(local_listener(Some(FakeWeakDeviceId(FakeDeviceId))),
3730 [local_listener(None), wildcard_listener(Some(FakeWeakDeviceId(FakeDeviceId))), wildcard_listener(None)];
3731 "local listener with device")]
3732 #[test_case(wildcard_listener(Some(FakeWeakDeviceId(FakeDeviceId))), [wildcard_listener(None)];
3733 "wildcard listener with device")]
3734 #[test_case(conn_addr(None), [local_listener(None), wildcard_listener(None)]; "conn no device")]
3735 #[test_case(local_listener(None), [wildcard_listener(None)]; "local listener no device")]
3736 #[test_case(wildcard_listener(None), []; "wildcard listener no device")]
3737 fn test_udp_addr_vec_iter_shadows_conn<I: IpExt, D: WeakDeviceIdentifier, const N: usize>(
3738 addr: AddrVec<I, D, UdpAddrSpec>,
3739 expected_shadows: [AddrVec<I, D, UdpAddrSpec>; N],
3740 ) {
3741 assert_eq!(addr.iter_shadows().collect::<HashSet<_>>(), HashSet::from(expected_shadows));
3742 }
3743
3744 #[ip_test(I)]
3745 fn test_iter_receiving_addrs<I: TestIpExt>() {
3746 let addr = ConnIpAddr {
3747 local: (SocketIpAddr::try_from(local_ip::<I>()).unwrap(), LOCAL_PORT),
3748 remote: (SocketIpAddr::try_from(remote_ip::<I>()).unwrap(), REMOTE_PORT.into()),
3749 };
3750 assert_eq!(
3751 iter_receiving_addrs::<I, _>(addr, FakeWeakDeviceId(FakeDeviceId)).collect::<Vec<_>>(),
3752 vec![
3753 conn_addr(Some(FakeWeakDeviceId(FakeDeviceId))),
3755 conn_addr(None),
3757 local_listener(Some(FakeWeakDeviceId(FakeDeviceId))),
3758 local_listener(None),
3760 wildcard_listener(Some(FakeWeakDeviceId(FakeDeviceId))),
3761 wildcard_listener(None)
3763 ]
3764 );
3765 }
3766
3767 #[ip_test(I)]
3773 fn test_listen_udp<I: TestIpExt>() {
3774 set_logger_for_test();
3775 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3776 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3777 let local_ip = local_ip::<I>();
3778 let remote_ip = remote_ip::<I>();
3779 let socket = api.create();
3780 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3782 .expect("listen_udp failed");
3783
3784 let body = [1, 2, 3, 4, 5];
3786 let (core_ctx, bindings_ctx) = api.contexts();
3787 let meta = UdpPacketMeta::<I> {
3788 src_ip: remote_ip.get(),
3789 src_port: Some(REMOTE_PORT),
3790 dst_ip: local_ip.get(),
3791 dst_port: LOCAL_PORT,
3792 dscp_and_ecn: DscpAndEcn::default(),
3793 };
3794 receive_udp_packet(
3795 core_ctx,
3796 bindings_ctx,
3797 FakeDeviceId,
3798 meta.clone(),
3799 &body[..],
3800 WithEarlyDemux,
3801 )
3802 .expect("receive udp packet should succeed");
3803
3804 assert_eq!(
3805 bindings_ctx.state.received::<I>(),
3806 &HashMap::from([(
3807 socket.downgrade(),
3808 SocketReceived {
3809 packets: vec![ReceivedPacket { meta, body: body.into() }],
3810 max_size: usize::MAX
3811 }
3812 )])
3813 );
3814
3815 api.send_to(
3817 &socket,
3818 Some(ZonedAddr::Unzoned(remote_ip)),
3819 REMOTE_PORT.into(),
3820 Buf::new(body.to_vec(), ..),
3821 )
3822 .expect("send_to suceeded");
3823
3824 api.send_to(
3826 &socket,
3827 Some(ZonedAddr::Unzoned(remote_ip)),
3828 REMOTE_PORT.into(),
3829 Buf::new(body.to_vec(), ..),
3830 )
3831 .expect("send_to succeeded");
3832 let frames = api.core_ctx().bound_sockets.ip_socket_ctx.frames();
3833 assert_eq!(frames.len(), 2);
3834 let check_frame =
3835 |(meta, frame_body): &(DualStackSendIpPacketMeta<FakeDeviceId>, Vec<u8>)| {
3836 let SendIpPacketMeta {
3837 device: _,
3838 src_ip,
3839 dst_ip,
3840 destination,
3841 proto,
3842 ttl: _,
3843 mtu: _,
3844 dscp_and_ecn: _,
3845 } = meta.try_as::<I>().unwrap();
3846 assert_eq!(destination, &IpPacketDestination::Neighbor(remote_ip));
3847 assert_eq!(src_ip, &local_ip);
3848 assert_eq!(dst_ip, &remote_ip);
3849 assert_eq!(proto, &IpProto::Udp.into());
3850 let mut buf = &frame_body[..];
3851 let udp_packet =
3852 UdpPacket::parse(&mut buf, UdpParseArgs::new(src_ip.get(), dst_ip.get()))
3853 .expect("Parsed sent UDP packet");
3854 assert_eq!(udp_packet.src_port().unwrap(), LOCAL_PORT);
3855 assert_eq!(udp_packet.dst_port(), REMOTE_PORT);
3856 assert_eq!(udp_packet.body(), &body[..]);
3857 };
3858 check_frame(&frames[0]);
3859 check_frame(&frames[1]);
3860 }
3861
3862 #[ip_test(I)]
3863 fn test_receive_udp_queue_full<I: TestIpExt>() {
3864 set_logger_for_test();
3865 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3866 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3867 let local_ip = local_ip::<I>();
3868 let remote_ip = remote_ip::<I>();
3869 let socket = api.create();
3870
3871 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3873 .expect("listen_udp failed");
3874
3875 let (core_ctx, bindings_ctx) = api.contexts();
3876 {
3878 let received =
3879 bindings_ctx.state.received_mut::<I>().entry(socket.downgrade()).or_default();
3880 received.max_size = 0;
3881 }
3882
3883 let body = [1, 2, 3, 4, 5];
3885 let meta = UdpPacketMeta::<I> {
3886 src_ip: remote_ip.get(),
3887 src_port: Some(REMOTE_PORT),
3888 dst_ip: local_ip.get(),
3889 dst_port: LOCAL_PORT,
3890 dscp_and_ecn: DscpAndEcn::default(),
3891 };
3892 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta, &body[..], WithEarlyDemux)
3893 .expect("receive udp packet should succeed");
3894
3895 assert_counters(
3896 api.core_ctx(),
3897 CounterExpectationsWithSocket {
3898 rx_delivered: 1,
3899 rx_queue_full: 1,
3900 ..Default::default()
3901 },
3902 CounterExpectationsWithoutSocket { rx: 1, ..Default::default() },
3903 [(
3904 &socket,
3905 CounterExpectationsWithSocket {
3906 rx_delivered: 1,
3907 rx_queue_full: 1,
3908 ..Default::default()
3909 },
3910 )],
3911 )
3912 }
3913
3914 #[ip_test(I)]
3919 fn test_udp_drop<I: TestIpExt>() {
3920 set_logger_for_test();
3921 let UdpFakeDeviceCtx { mut core_ctx, mut bindings_ctx } =
3922 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3923 let local_ip = local_ip::<I>();
3924 let remote_ip = remote_ip::<I>();
3925
3926 let meta = UdpPacketMeta::<I> {
3927 src_ip: remote_ip.get(),
3928 src_port: Some(REMOTE_PORT),
3929 dst_ip: local_ip.get(),
3930 dst_port: LOCAL_PORT,
3931 dscp_and_ecn: DscpAndEcn::default(),
3932 };
3933 let body = [1, 2, 3, 4, 5];
3934 assert_eq!(
3935 receive_udp_packet(
3936 &mut core_ctx,
3937 &mut bindings_ctx,
3938 FakeDeviceId,
3939 meta,
3940 &body[..],
3941 WithEarlyDemux,
3942 ),
3943 Err(I::IcmpError::port_unreachable())
3944 );
3945 assert_eq!(&bindings_ctx.state.socket_data::<I>(), &HashMap::new());
3946 }
3947
3948 #[ip_test(I)]
3953 #[test_case(EarlyDemuxMode::Enabled; "with early demux")]
3954 #[test_case(EarlyDemuxMode::Disabled; "without early demux")]
3955 fn test_udp_conn_basic<I: TestIpExt>(early_demux_mode: EarlyDemuxMode) {
3956 set_logger_for_test();
3957 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
3958 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
3959 let local_ip = local_ip::<I>();
3960 let remote_ip = remote_ip::<I>();
3961 let socket = api.create();
3962 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
3964 .expect("listen_udp failed");
3965 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
3966 .expect("connect failed");
3967
3968 let meta = UdpPacketMeta::<I> {
3970 src_ip: remote_ip.get(),
3971 src_port: Some(REMOTE_PORT),
3972 dst_ip: local_ip.get(),
3973 dst_port: LOCAL_PORT,
3974 dscp_and_ecn: DscpAndEcn::default(),
3975 };
3976 let body = [1, 2, 3, 4, 5];
3977 let (core_ctx, bindings_ctx) = api.contexts();
3978 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta, &body[..], early_demux_mode)
3979 .expect("receive udp packet should succeed");
3980
3981 assert_eq!(
3982 bindings_ctx.state.socket_data(),
3983 HashMap::from([(socket.downgrade(), vec![&body[..]])])
3984 );
3985
3986 api.send(&socket, Buf::new(body.to_vec(), ..)).expect("send_udp_conn returned an error");
3988
3989 let (meta, frame_body) =
3990 assert_matches!(api.core_ctx().bound_sockets.ip_socket_ctx.frames(), [frame] => frame);
3991 let SendIpPacketMeta {
3993 device: _,
3994 src_ip,
3995 dst_ip,
3996 destination,
3997 proto,
3998 ttl: _,
3999 mtu: _,
4000 dscp_and_ecn: _,
4001 } = meta.try_as::<I>().unwrap();
4002 assert_eq!(destination, &IpPacketDestination::Neighbor(remote_ip));
4003 assert_eq!(src_ip, &local_ip);
4004 assert_eq!(dst_ip, &remote_ip);
4005 assert_eq!(proto, &IpProto::Udp.into());
4006 let mut buf = &frame_body[..];
4007 let udp_packet = UdpPacket::parse(&mut buf, UdpParseArgs::new(src_ip.get(), dst_ip.get()))
4008 .expect("Parsed sent UDP packet");
4009 assert_eq!(udp_packet.src_port().unwrap(), LOCAL_PORT);
4010 assert_eq!(udp_packet.dst_port(), REMOTE_PORT);
4011 assert_eq!(udp_packet.body(), &body[..]);
4012
4013 let expects_with_socket =
4014 || CounterExpectationsWithSocket { rx_delivered: 1, tx: 1, ..Default::default() };
4015 assert_counters(
4016 api.core_ctx(),
4017 expects_with_socket(),
4018 CounterExpectationsWithoutSocket { rx: 1, ..Default::default() },
4019 [(&socket, expects_with_socket())],
4020 )
4021 }
4022
4023 #[ip_test(I)]
4026 fn test_udp_conn_unroutable<I: TestIpExt>() {
4027 set_logger_for_test();
4028 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4029 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4030 let remote_ip = I::get_other_ip_address(127);
4032 let unbound = api.create();
4034 let conn_err = api
4035 .connect(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4036 .unwrap_err();
4037
4038 assert_eq!(conn_err, ConnectError::Ip(ResolveRouteError::Unreachable.into()));
4039 }
4040
4041 #[ip_test(I)]
4044 fn test_udp_conn_cannot_bind<I: TestIpExt>() {
4045 set_logger_for_test();
4046 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4047 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4048
4049 let remote_ip = remote_ip::<I>();
4051 let unbound = api.create();
4053 let result = api.listen(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), Some(LOCAL_PORT));
4054
4055 assert_eq!(result, Err(Either::Right(LocalAddressError::CannotBindToAddress)));
4056 }
4057
4058 #[test]
4059 fn test_udp_conn_picks_link_local_source_address() {
4060 set_logger_for_test();
4061 set_logger_for_test();
4065 let local_ip = SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap();
4066 let remote_ip = SpecifiedAddr::new(net_ip_v6!("1:2:3:4::")).unwrap();
4067 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
4068 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![remote_ip]),
4069 );
4070 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
4071 let socket = api.create();
4072 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4073 .expect("can connect");
4074
4075 let info = api.get_info(&socket);
4076 let (conn_local_ip, conn_remote_ip) = assert_matches!(
4077 info,
4078 SocketInfo::Connected(datagram::ConnInfo {
4079 local_ip: conn_local_ip,
4080 remote_ip: conn_remote_ip,
4081 local_identifier: _,
4082 remote_identifier: _,
4083 }) => (conn_local_ip, conn_remote_ip)
4084 );
4085 assert_eq!(
4086 conn_local_ip,
4087 StrictlyZonedAddr::new_with_zone(local_ip, || FakeWeakDeviceId(FakeDeviceId)),
4088 );
4089 assert_eq!(conn_remote_ip, StrictlyZonedAddr::new_unzoned_or_panic(remote_ip));
4090
4091 assert_eq!(
4094 api.set_device(&socket, None),
4095 Err(SocketError::Local(LocalAddressError::Zone(ZonedAddressError::DeviceZoneMismatch)))
4096 );
4097 }
4098
4099 #[ip_test(I)]
4100 #[test_case(
4101 true,
4102 Err(IpSockCreationError::Route(ResolveRouteError::Unreachable).into()); "remove device")]
4103 #[test_case(false, Ok(()); "dont remove device")]
4104 fn test_udp_conn_device_removed<I: TestIpExt>(
4105 remove_device: bool,
4106 expected: Result<(), ConnectError>,
4107 ) {
4108 set_logger_for_test();
4109 let device = FakeReferencyDeviceId::default();
4110 let mut ctx =
4111 FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_with_device::<I>(device.clone()));
4112 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4113
4114 let unbound = api.create();
4115 api.set_device(&unbound, Some(&device)).unwrap();
4116
4117 if remove_device {
4118 device.mark_removed();
4119 }
4120
4121 let remote_ip = remote_ip::<I>();
4122 assert_eq!(
4123 api.connect(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into()),
4124 expected,
4125 );
4126 }
4127
4128 #[ip_test(I)]
4131 fn test_udp_conn_exhausted<I: TestIpExt>() {
4132 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4134 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4135
4136 let local_ip = local_ip::<I>();
4137 for port_num in FakePortAlloc::<I>::EPHEMERAL_RANGE {
4139 let socket = api.create();
4140 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), NonZeroU16::new(port_num))
4141 .unwrap();
4142 }
4143
4144 let remote_ip = remote_ip::<I>();
4145 let unbound = api.create();
4146 let conn_err = api
4147 .connect(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4148 .unwrap_err();
4149
4150 assert_eq!(conn_err, ConnectError::CouldNotAllocateLocalPort);
4151 }
4152
4153 #[ip_test(I)]
4154 fn test_connect_success<I: TestIpExt>() {
4155 set_logger_for_test();
4156 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4157 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4158
4159 let local_ip = local_ip::<I>();
4160 let remote_ip = remote_ip::<I>();
4161 let multicast_addr = I::get_multicast_addr(3);
4162 let socket = api.create();
4163 let sharing_domain = SharingDomain::new(1);
4164
4165 api.set_posix_reuse_port(&socket, ReusePortOption::Enabled(sharing_domain))
4167 .expect("is unbound");
4168 api.set_multicast_membership(
4169 &socket,
4170 multicast_addr,
4171 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
4172 true,
4173 )
4174 .expect("join multicast group should succeed");
4175
4176 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
4177 .expect("Initial call to listen_udp was expected to succeed");
4178
4179 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4180 .expect("connect should succeed");
4181
4182 assert!(api.get_posix_reuse_port(&socket));
4185 assert_eq!(
4186 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
4187 HashMap::from([((FakeDeviceId, multicast_addr), NonZeroUsize::new(1).unwrap())])
4188 );
4189 assert_eq!(
4190 api.set_multicast_membership(
4191 &socket,
4192 multicast_addr,
4193 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
4194 true
4195 ),
4196 Err(SetMulticastMembershipError::GroupAlreadyJoined)
4197 );
4198 }
4199
4200 #[ip_test(I)]
4201 fn test_connect_fails<I: TestIpExt>() {
4202 set_logger_for_test();
4203 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4204 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4205 let local_ip = local_ip::<I>();
4206 let remote_ip = I::get_other_ip_address(127);
4207 let multicast_addr = I::get_multicast_addr(3);
4208 let socket = api.create();
4209
4210 let sharing_domain = SharingDomain::new(1);
4212 api.set_posix_reuse_port(&socket, ReusePortOption::Enabled(sharing_domain))
4213 .expect("is unbound");
4214 api.set_multicast_membership(
4215 &socket,
4216 multicast_addr,
4217 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
4218 true,
4219 )
4220 .expect("join multicast group should succeed");
4221
4222 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
4224 .expect("Initial call to listen_udp was expected to succeed");
4225
4226 assert_matches!(
4227 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into()),
4228 Err(ConnectError::Ip(IpSockCreationError::Route(ResolveRouteError::Unreachable)))
4229 );
4230
4231 assert!(api.get_posix_reuse_port(&socket));
4233 assert_eq!(
4234 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
4235 HashMap::from([((FakeDeviceId, multicast_addr), NonZeroUsize::new(1).unwrap())])
4236 );
4237 assert_eq!(
4238 api.set_multicast_membership(
4239 &socket,
4240 multicast_addr,
4241 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
4242 true
4243 ),
4244 Err(SetMulticastMembershipError::GroupAlreadyJoined)
4245 );
4246 }
4247
4248 #[ip_test(I)]
4249 fn test_reconnect_udp_conn_success<I: TestIpExt>() {
4250 set_logger_for_test();
4251
4252 let local_ip = local_ip::<I>();
4253 let remote_ip = remote_ip::<I>();
4254 let other_remote_ip = I::get_other_ip_address(3);
4255
4256 let mut ctx =
4257 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
4258 vec![local_ip],
4259 vec![remote_ip, other_remote_ip],
4260 ));
4261 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4262
4263 let socket = api.create();
4264 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
4265 .expect("listen should succeed");
4266
4267 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4268 .expect("connect was expected to succeed");
4269
4270 api.connect(&socket, Some(ZonedAddr::Unzoned(other_remote_ip)), OTHER_REMOTE_PORT.into())
4271 .expect("connect should succeed");
4272 assert_eq!(
4273 api.get_info(&socket),
4274 SocketInfo::Connected(datagram::ConnInfo {
4275 local_ip: StrictlyZonedAddr::new_unzoned_or_panic(local_ip),
4276 local_identifier: LOCAL_PORT,
4277 remote_ip: StrictlyZonedAddr::new_unzoned_or_panic(other_remote_ip),
4278 remote_identifier: OTHER_REMOTE_PORT.into(),
4279 })
4280 );
4281 }
4282
4283 #[ip_test(I)]
4284 fn test_reconnect_udp_conn_fails<I: TestIpExt>() {
4285 set_logger_for_test();
4286 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4287 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4288 let local_ip = local_ip::<I>();
4289 let remote_ip = remote_ip::<I>();
4290 let other_remote_ip = I::get_other_ip_address(3);
4291
4292 let socket = api.create();
4293 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
4294 .expect("listen should succeed");
4295
4296 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4297 .expect("connect was expected to succeed");
4298 let error = api
4299 .connect(&socket, Some(ZonedAddr::Unzoned(other_remote_ip)), OTHER_REMOTE_PORT.into())
4300 .expect_err("connect should fail");
4301 assert_matches!(
4302 error,
4303 ConnectError::Ip(IpSockCreationError::Route(ResolveRouteError::Unreachable))
4304 );
4305
4306 assert_eq!(
4307 api.get_info(&socket),
4308 SocketInfo::Connected(datagram::ConnInfo {
4309 local_ip: StrictlyZonedAddr::new_unzoned_or_panic(local_ip),
4310 local_identifier: LOCAL_PORT,
4311 remote_ip: StrictlyZonedAddr::new_unzoned_or_panic(remote_ip),
4312 remote_identifier: REMOTE_PORT.into()
4313 })
4314 );
4315 }
4316
4317 #[ip_test(I)]
4318 fn test_send_to<I: TestIpExt>() {
4319 set_logger_for_test();
4320
4321 let local_ip = local_ip::<I>();
4322 let remote_ip = remote_ip::<I>();
4323 let other_remote_ip = I::get_other_ip_address(3);
4324
4325 let mut ctx =
4326 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
4327 vec![local_ip],
4328 vec![remote_ip, other_remote_ip],
4329 ));
4330 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4331
4332 let socket = api.create();
4333 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
4334 .expect("listen should succeed");
4335 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4336 .expect("connect should succeed");
4337
4338 let body = [1, 2, 3, 4, 5];
4339 api.send_to(
4341 &socket,
4342 Some(ZonedAddr::Unzoned(other_remote_ip)),
4343 REMOTE_PORT.into(),
4344 Buf::new(body.to_vec(), ..),
4345 )
4346 .expect("send_to failed");
4347
4348 let info = api.get_info(&socket);
4350 let info = assert_matches!(info, SocketInfo::Connected(info) => info);
4351 assert_eq!(info.local_ip.into_inner(), ZonedAddr::Unzoned(local_ip));
4352 assert_eq!(info.remote_ip.into_inner(), ZonedAddr::Unzoned(remote_ip));
4353 assert_eq!(info.remote_identifier, u16::from(REMOTE_PORT));
4354
4355 let (meta, frame_body) =
4357 assert_matches!(api.core_ctx().bound_sockets.ip_socket_ctx.frames(), [frame] => frame);
4358 let SendIpPacketMeta {
4359 device: _,
4360 src_ip,
4361 dst_ip,
4362 destination,
4363 proto,
4364 ttl: _,
4365 mtu: _,
4366 dscp_and_ecn: _,
4367 } = meta.try_as::<I>().unwrap();
4368
4369 assert_eq!(destination, &IpPacketDestination::Neighbor(other_remote_ip));
4370 assert_eq!(src_ip, &local_ip);
4371 assert_eq!(dst_ip, &other_remote_ip);
4372 assert_eq!(proto, &I::Proto::from(IpProto::Udp));
4373 let mut buf = &frame_body[..];
4374 let udp_packet = UdpPacket::parse(&mut buf, UdpParseArgs::new(src_ip.get(), dst_ip.get()))
4375 .expect("Parsed sent UDP packet");
4376 assert_eq!(udp_packet.src_port().unwrap(), LOCAL_PORT);
4377 assert_eq!(udp_packet.dst_port(), REMOTE_PORT);
4378 assert_eq!(udp_packet.body(), &body[..]);
4379 }
4380
4381 #[ip_test(I)]
4385 fn test_send_udp_conn_failure<I: TestIpExt>() {
4386 set_logger_for_test();
4387 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4388 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4389 let remote_ip = remote_ip::<I>();
4390 let socket = api.create();
4392 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4393 .expect("connect failed");
4394
4395 api.core_ctx().bound_sockets.ip_socket_ctx.frames.set_should_error_for_frame(
4397 |_frame_meta| Some(SendFrameErrorReason::SizeConstraintsViolation),
4398 );
4399
4400 let send_err = api.send(&socket, Buf::new(Vec::new(), ..)).unwrap_err();
4402 assert_eq!(send_err, Either::Left(SendError::IpSock(IpSockSendError::Mtu)));
4403
4404 let expects_with_socket =
4405 || CounterExpectationsWithSocket { tx: 1, tx_error: 1, ..Default::default() };
4406 assert_counters(
4407 api.core_ctx(),
4408 expects_with_socket(),
4409 Default::default(),
4410 [(&socket, expects_with_socket())],
4411 )
4412 }
4413
4414 #[ip_test(I)]
4415 fn test_send_udp_conn_device_removed<I: TestIpExt>() {
4416 set_logger_for_test();
4417 let device = FakeReferencyDeviceId::default();
4418 let mut ctx =
4419 FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_with_device::<I>(device.clone()));
4420 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4421 let remote_ip = remote_ip::<I>();
4422 let socket = api.create();
4423 api.set_device(&socket, Some(&device)).unwrap();
4424 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4425 .expect("connect failed");
4426
4427 for (device_removed, expected_res) in [
4428 (false, Ok(())),
4429 (
4430 true,
4431 Err(Either::Left(SendError::IpSock(IpSockSendError::Unroutable(
4432 ResolveRouteError::Unreachable,
4433 )))),
4434 ),
4435 ] {
4436 if device_removed {
4437 device.mark_removed();
4438 }
4439
4440 assert_eq!(api.send(&socket, Buf::new(Vec::new(), ..)), expected_res)
4441 }
4442 }
4443
4444 #[ip_test(I)]
4445 #[test_case(false, ShutdownType::Send; "shutdown send then send")]
4446 #[test_case(false, ShutdownType::SendAndReceive; "shutdown both then send")]
4447 #[test_case(true, ShutdownType::Send; "shutdown send then sendto")]
4448 #[test_case(true, ShutdownType::SendAndReceive; "shutdown both then sendto")]
4449 fn test_send_udp_after_shutdown<I: TestIpExt>(send_to: bool, shutdown: ShutdownType) {
4450 set_logger_for_test();
4451
4452 #[derive(Debug)]
4453 struct NotWriteableError;
4454
4455 let send = |remote_ip, api: &mut UdpApi<_, _>, id| -> Result<(), NotWriteableError> {
4456 match remote_ip {
4457 Some(remote_ip) => api.send_to(
4458 id,
4459 Some(remote_ip),
4460 REMOTE_PORT.into(),
4461 Buf::new(Vec::new(), ..),
4462 )
4463 .map_err(
4464 |e| assert_matches!(e, Either::Right(SendToError::NotWriteable) => NotWriteableError)
4465 ),
4466 None => api.send(
4467 id,
4468 Buf::new(Vec::new(), ..),
4469 )
4470 .map_err(|e| assert_matches!(e, Either::Left(SendError::NotWriteable) => NotWriteableError)),
4471 }
4472 };
4473
4474 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4475 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4476
4477 let remote_ip = ZonedAddr::Unzoned(remote_ip::<I>());
4478 let send_to_ip = send_to.then_some(remote_ip);
4479
4480 let socket = api.create();
4481 api.connect(&socket, Some(remote_ip), REMOTE_PORT.into()).expect("connect failed");
4482
4483 send(send_to_ip, &mut api, &socket).expect("can send");
4484 api.shutdown(&socket, shutdown).expect("is connected");
4485
4486 assert_matches!(send(send_to_ip, &mut api, &socket), Err(NotWriteableError));
4487 }
4488
4489 #[ip_test(I)]
4490 #[test_case::test_matrix(
4491 [ShutdownType::Receive, ShutdownType::SendAndReceive],
4492 [EarlyDemuxMode::Enabled, EarlyDemuxMode::Disabled]
4493 )]
4494 fn test_marked_for_receive_shutdown<I: TestIpExt>(
4495 which: ShutdownType,
4496 early_demux_mode: EarlyDemuxMode,
4497 ) {
4498 set_logger_for_test();
4499
4500 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4501 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4502
4503 let socket = api.create();
4504 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip::<I>())), Some(LOCAL_PORT))
4505 .expect("can bind");
4506 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip::<I>())), REMOTE_PORT.into())
4507 .expect("can connect");
4508
4509 let meta = UdpPacketMeta::<I> {
4513 src_ip: remote_ip::<I>().get(),
4514 src_port: Some(REMOTE_PORT),
4515 dst_ip: local_ip::<I>().get(),
4516 dst_port: LOCAL_PORT,
4517 dscp_and_ecn: DscpAndEcn::default(),
4518 };
4519 let packet = [1, 1, 1, 1];
4520 let (core_ctx, bindings_ctx) = api.contexts();
4521
4522 receive_udp_packet(
4523 core_ctx,
4524 bindings_ctx,
4525 FakeDeviceId,
4526 meta.clone(),
4527 &packet[..],
4528 early_demux_mode,
4529 )
4530 .expect("receive udp packet should succeed");
4531
4532 assert_eq!(
4533 bindings_ctx.state.socket_data(),
4534 HashMap::from([(socket.downgrade(), vec![&packet[..]])])
4535 );
4536 api.shutdown(&socket, which).expect("is connected");
4537 let (core_ctx, bindings_ctx) = api.contexts();
4538 assert_eq!(
4539 receive_udp_packet(
4540 core_ctx,
4541 bindings_ctx,
4542 FakeDeviceId,
4543 meta.clone(),
4544 &packet[..],
4545 early_demux_mode
4546 ),
4547 Err(I::IcmpError::port_unreachable())
4548 );
4549 assert_eq!(
4550 bindings_ctx.state.socket_data(),
4551 HashMap::from([(socket.downgrade(), vec![&packet[..]])])
4552 );
4553
4554 api.shutdown(&socket, ShutdownType::Send).expect("is connected");
4556 let (core_ctx, bindings_ctx) = api.contexts();
4557 assert_eq!(
4558 receive_udp_packet(
4559 core_ctx,
4560 bindings_ctx,
4561 FakeDeviceId,
4562 meta,
4563 &packet[..],
4564 early_demux_mode
4565 ),
4566 Err(I::IcmpError::port_unreachable())
4567 );
4568 assert_eq!(
4569 bindings_ctx.state.socket_data(),
4570 HashMap::from([(socket.downgrade(), vec![&packet[..]])])
4571 );
4572 }
4573
4574 #[ip_test(I)]
4577 #[test_case(WithEarlyDemux; "with early demux")]
4578 #[test_case(NoEarlyDemux; "without early demux")]
4579 fn test_udp_demux<I: TestIpExt>(early_demux_mode: EarlyDemuxMode) {
4580 set_logger_for_test();
4581 let local_ip = local_ip::<I>();
4582 let remote_ip_a = I::get_other_ip_address(70);
4583 let remote_ip_b = I::get_other_ip_address(72);
4584 let local_port_a = NonZeroU16::new(100).unwrap();
4585 let local_port_b = NonZeroU16::new(101).unwrap();
4586 let local_port_c = NonZeroU16::new(102).unwrap();
4587 let local_port_d = NonZeroU16::new(103).unwrap();
4588
4589 let mut ctx =
4590 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
4591 vec![local_ip],
4592 vec![remote_ip_a, remote_ip_b],
4593 ));
4594 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4595
4596 let sharing_domain = SharingDomain::new(1);
4597
4598 let [conn1, conn2] = [remote_ip_a, remote_ip_b].map(|remote_ip| {
4602 let socket = api.create();
4603 api.set_posix_reuse_port(&socket, ReusePortOption::Enabled(sharing_domain))
4604 .expect("is unbound");
4605 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(local_port_d))
4606 .expect("listen_udp failed");
4607 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
4608 .expect("connect failed");
4609 socket
4610 });
4611 let list1 = api.create();
4612 api.listen(&list1, Some(ZonedAddr::Unzoned(local_ip)), Some(local_port_a))
4613 .expect("listen_udp failed");
4614 let list2 = api.create();
4615 api.listen(&list2, Some(ZonedAddr::Unzoned(local_ip)), Some(local_port_b))
4616 .expect("listen_udp failed");
4617 let wildcard_list = api.create();
4618 api.listen(&wildcard_list, None, Some(local_port_c)).expect("listen_udp failed");
4619
4620 let mut expectations = HashMap::<WeakUdpSocketId<I, _, _>, SocketReceived<I>>::new();
4621 let meta = UdpPacketMeta {
4624 src_ip: remote_ip_a.get(),
4625 src_port: Some(REMOTE_PORT),
4626 dst_ip: local_ip.get(),
4627 dst_port: local_port_d,
4628 dscp_and_ecn: DscpAndEcn::default(),
4629 };
4630 let body_conn1 = [1, 1, 1, 1];
4631 let (core_ctx, bindings_ctx) = api.contexts();
4632 receive_udp_packet(
4633 core_ctx,
4634 bindings_ctx,
4635 FakeDeviceId,
4636 meta.clone(),
4637 &body_conn1[..],
4638 early_demux_mode,
4639 )
4640 .expect("receive udp packet should succeed");
4641 expectations
4642 .entry(conn1.downgrade())
4643 .or_default()
4644 .packets
4645 .push(ReceivedPacket { meta: meta, body: body_conn1.into() });
4646 assert_eq!(bindings_ctx.state.received(), &expectations);
4647
4648 let meta = UdpPacketMeta {
4649 src_ip: remote_ip_b.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_conn2 = [2, 2, 2, 2];
4656 receive_udp_packet(
4657 core_ctx,
4658 bindings_ctx,
4659 FakeDeviceId,
4660 meta.clone(),
4661 &body_conn2[..],
4662 early_demux_mode,
4663 )
4664 .expect("receive udp packet should succeed");
4665 expectations
4666 .entry(conn2.downgrade())
4667 .or_default()
4668 .packets
4669 .push(ReceivedPacket { meta: meta, body: body_conn2.into() });
4670 assert_eq!(bindings_ctx.state.received(), &expectations);
4671
4672 let meta = UdpPacketMeta {
4673 src_ip: remote_ip_a.get(),
4674 src_port: Some(REMOTE_PORT),
4675 dst_ip: local_ip.get(),
4676 dst_port: local_port_a,
4677 dscp_and_ecn: DscpAndEcn::default(),
4678 };
4679 let body_list1 = [3, 3, 3, 3];
4680 receive_udp_packet(
4681 core_ctx,
4682 bindings_ctx,
4683 FakeDeviceId,
4684 meta.clone(),
4685 &body_list1[..],
4686 early_demux_mode,
4687 )
4688 .expect("receive udp packet should succeed");
4689 expectations
4690 .entry(list1.downgrade())
4691 .or_default()
4692 .packets
4693 .push(ReceivedPacket { meta: meta, body: body_list1.into() });
4694 assert_eq!(bindings_ctx.state.received(), &expectations);
4695
4696 let meta = UdpPacketMeta {
4697 src_ip: remote_ip_a.get(),
4698 src_port: Some(REMOTE_PORT),
4699 dst_ip: local_ip.get(),
4700 dst_port: local_port_b,
4701 dscp_and_ecn: DscpAndEcn::default(),
4702 };
4703 let body_list2 = [4, 4, 4, 4];
4704 receive_udp_packet(
4705 core_ctx,
4706 bindings_ctx,
4707 FakeDeviceId,
4708 meta.clone(),
4709 &body_list2[..],
4710 early_demux_mode,
4711 )
4712 .expect("receive udp packet should succeed");
4713 expectations
4714 .entry(list2.downgrade())
4715 .or_default()
4716 .packets
4717 .push(ReceivedPacket { meta: meta, body: body_list2.into() });
4718 assert_eq!(bindings_ctx.state.received(), &expectations);
4719
4720 let meta = UdpPacketMeta {
4721 src_ip: remote_ip_a.get(),
4722 src_port: Some(REMOTE_PORT),
4723 dst_ip: local_ip.get(),
4724 dst_port: local_port_c,
4725 dscp_and_ecn: DscpAndEcn::default(),
4726 };
4727 let body_wildcard_list = [5, 5, 5, 5];
4728 receive_udp_packet(
4729 core_ctx,
4730 bindings_ctx,
4731 FakeDeviceId,
4732 meta.clone(),
4733 &body_wildcard_list[..],
4734 early_demux_mode,
4735 )
4736 .expect("receive udp packet should succeed");
4737 expectations
4738 .entry(wildcard_list.downgrade())
4739 .or_default()
4740 .packets
4741 .push(ReceivedPacket { meta: meta, body: body_wildcard_list.into() });
4742 assert_eq!(bindings_ctx.state.received(), &expectations);
4743 }
4744
4745 #[ip_test(I)]
4747 #[test_case(WithEarlyDemux; "with early demux")]
4748 #[test_case(NoEarlyDemux; "without early demux")]
4749 fn test_wildcard_listeners<I: TestIpExt>(early_demux_mode: EarlyDemuxMode) {
4750 set_logger_for_test();
4751 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4752 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4753 let local_ip_a = I::get_other_ip_address(1);
4754 let local_ip_b = I::get_other_ip_address(2);
4755 let remote_ip_a = I::get_other_ip_address(70);
4756 let remote_ip_b = I::get_other_ip_address(72);
4757 let listener = api.create();
4758 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen_udp failed");
4759
4760 let body = [1, 2, 3, 4, 5];
4761 let (core_ctx, bindings_ctx) = api.contexts();
4762 let meta_1 = UdpPacketMeta {
4763 src_ip: remote_ip_a.get(),
4764 src_port: Some(REMOTE_PORT),
4765 dst_ip: local_ip_a.get(),
4766 dst_port: LOCAL_PORT,
4767 dscp_and_ecn: DscpAndEcn::default(),
4768 };
4769 receive_udp_packet(
4770 core_ctx,
4771 bindings_ctx,
4772 FakeDeviceId,
4773 meta_1.clone(),
4774 &body[..],
4775 early_demux_mode,
4776 )
4777 .expect("receive udp packet should succeed");
4778
4779 let meta_2 = UdpPacketMeta {
4781 src_ip: remote_ip_b.get(),
4782 src_port: Some(REMOTE_PORT),
4783 dst_ip: local_ip_b.get(),
4784 dst_port: LOCAL_PORT,
4785 dscp_and_ecn: DscpAndEcn::default(),
4786 };
4787 receive_udp_packet(
4788 core_ctx,
4789 bindings_ctx,
4790 FakeDeviceId,
4791 meta_2.clone(),
4792 &body[..],
4793 early_demux_mode,
4794 )
4795 .expect("receive udp packet should succeed");
4796
4797 assert_eq!(
4799 bindings_ctx.state.received::<I>(),
4800 &HashMap::from([(
4801 listener.downgrade(),
4802 SocketReceived {
4803 packets: vec![
4804 ReceivedPacket { meta: meta_1, body: body.into() },
4805 ReceivedPacket { meta: meta_2, body: body.into() }
4806 ],
4807 max_size: usize::MAX,
4808 }
4809 )])
4810 );
4811 }
4812
4813 #[ip_test(I)]
4814 #[test_case(WithEarlyDemux; "with early demux")]
4815 #[test_case(NoEarlyDemux; "without early demux")]
4816 fn test_receive_source_port_zero_on_listener<I: TestIpExt>(early_demux_mode: EarlyDemuxMode) {
4817 set_logger_for_test();
4818 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4819 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4820 let listener = api.create();
4821 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen_udp failed");
4822
4823 let body = [];
4824 let meta = UdpPacketMeta::<I> {
4825 src_ip: I::TEST_ADDRS.remote_ip.get(),
4826 src_port: None,
4827 dst_ip: I::TEST_ADDRS.local_ip.get(),
4828 dst_port: LOCAL_PORT,
4829 dscp_and_ecn: DscpAndEcn::default(),
4830 };
4831
4832 let (core_ctx, bindings_ctx) = api.contexts();
4833 receive_udp_packet(
4834 core_ctx,
4835 bindings_ctx,
4836 FakeDeviceId,
4837 meta.clone(),
4838 &body[..],
4839 early_demux_mode,
4840 )
4841 .expect("receive udp packet should succeed");
4842 assert_eq!(
4844 bindings_ctx.state.received(),
4845 &HashMap::from([(
4846 listener.downgrade(),
4847 SocketReceived {
4848 packets: vec![ReceivedPacket { meta, body: vec![] }],
4849 max_size: usize::MAX
4850 }
4851 )])
4852 );
4853 }
4854
4855 #[ip_test(I)]
4856 #[test_case(WithEarlyDemux; "with early demux")]
4857 #[test_case(NoEarlyDemux; "without early demux")]
4858 fn test_receive_source_addr_unspecified_on_listener<I: TestIpExt>(
4859 early_demux_mode: EarlyDemuxMode,
4860 ) {
4861 set_logger_for_test();
4862 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4863 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4864 let listener = api.create();
4865 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen_udp failed");
4866
4867 let meta = UdpPacketMeta::<I> {
4868 src_ip: I::UNSPECIFIED_ADDRESS,
4869 src_port: Some(REMOTE_PORT),
4870 dst_ip: I::TEST_ADDRS.local_ip.get(),
4871 dst_port: LOCAL_PORT,
4872 dscp_and_ecn: DscpAndEcn::default(),
4873 };
4874 let body = [];
4875 let (core_ctx, bindings_ctx) = api.contexts();
4876 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta, &body[..], early_demux_mode)
4877 .expect("receive udp packet should succeed");
4878 assert_eq!(
4880 bindings_ctx.state.socket_data(),
4881 HashMap::from([(listener.downgrade(), vec![&body[..]])])
4882 );
4883 }
4884
4885 #[ip_test(I)]
4886 #[test_case(NonZeroU16::new(u16::MAX).unwrap(), Ok(NonZeroU16::new(u16::MAX).unwrap()); "ephemeral available")]
4887 #[test_case(NonZeroU16::new(100).unwrap(), Err(LocalAddressError::FailedToAllocateLocalPort);
4888 "no ephemeral available")]
4889 fn test_bind_picked_port_all_others_taken<I: TestIpExt>(
4890 available_port: NonZeroU16,
4891 expected_result: Result<NonZeroU16, LocalAddressError>,
4892 ) {
4893 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
4895 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4896
4897 for port in 1..=u16::MAX {
4898 let port = NonZeroU16::new(port).unwrap();
4899 if port == available_port {
4900 continue;
4901 }
4902 let unbound = api.create();
4903 api.listen(&unbound, None, Some(port)).expect("uncontested bind");
4904 }
4905
4906 let socket = api.create();
4909 let result = api
4910 .listen(&socket, None, None)
4911 .map(|()| {
4912 let info = api.get_info(&socket);
4913 assert_matches!(info, SocketInfo::Listener(info) => info.local_identifier)
4914 })
4915 .map_err(Either::unwrap_right);
4916 assert_eq!(result, expected_result);
4917 }
4918
4919 #[ip_test(I)]
4920 #[test_case(WithEarlyDemux; "with early demux")]
4921 #[test_case(NoEarlyDemux; "without early demux")]
4922 fn test_receive_multicast_packet<I: TestIpExt>(early_demux_mode: EarlyDemuxMode) {
4923 set_logger_for_test();
4924 let local_ip = local_ip::<I>();
4925 let remote_ip = I::get_other_ip_address(70);
4926 let multicast_addr = I::get_multicast_addr(0);
4927 let multicast_addr_other = I::get_multicast_addr(1);
4928
4929 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
4930 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![remote_ip]),
4931 );
4932 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
4933
4934 let sharing_domain = SharingDomain::new(1);
4935
4936 let any_listener = {
4939 let socket = api.create();
4940 api.set_posix_reuse_port(&socket, ReusePortOption::Enabled(sharing_domain))
4941 .expect("is unbound");
4942 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen_udp failed");
4943 socket
4944 };
4945
4946 let specific_listeners = [(); 2].map(|()| {
4947 let socket = api.create();
4948 api.set_posix_reuse_port(&socket, ReusePortOption::Enabled(sharing_domain))
4949 .expect("is unbound");
4950 api.listen(
4951 &socket,
4952 Some(ZonedAddr::Unzoned(multicast_addr.into_specified())),
4953 Some(LOCAL_PORT),
4954 )
4955 .expect("listen_udp failed");
4956 socket
4957 });
4958
4959 let (core_ctx, bindings_ctx) = api.contexts();
4960 let mut receive_packet = |body, local_ip: MulticastAddr<I::Addr>| {
4961 let meta = UdpPacketMeta::<I> {
4962 src_ip: remote_ip.get(),
4963 src_port: Some(REMOTE_PORT),
4964 dst_ip: local_ip.get(),
4965 dst_port: LOCAL_PORT,
4966 dscp_and_ecn: DscpAndEcn::default(),
4967 };
4968 let body = [body];
4969 receive_udp_packet(core_ctx, bindings_ctx, FakeDeviceId, meta, &body, early_demux_mode)
4970 .expect("receive udp packet should succeed")
4971 };
4972
4973 receive_packet(1, multicast_addr);
4975 receive_packet(2, multicast_addr);
4976
4977 receive_packet(3, multicast_addr_other);
4979
4980 assert_eq!(
4981 bindings_ctx.state.socket_data(),
4982 HashMap::from([
4983 (specific_listeners[0].downgrade(), vec![[1].as_slice(), &[2]]),
4984 (specific_listeners[1].downgrade(), vec![&[1], &[2]]),
4985 (any_listener.downgrade(), vec![&[1], &[2], &[3]]),
4986 ]),
4987 );
4988
4989 assert_counters(
4990 api.core_ctx(),
4991 CounterExpectationsWithSocket { rx_delivered: 7, ..Default::default() },
4992 CounterExpectationsWithoutSocket { rx: 3, ..Default::default() },
4993 [
4994 (
4995 &any_listener,
4996 CounterExpectationsWithSocket { rx_delivered: 3, ..Default::default() },
4997 ),
4998 (
4999 &specific_listeners[0],
5000 CounterExpectationsWithSocket { rx_delivered: 2, ..Default::default() },
5001 ),
5002 (
5003 &specific_listeners[1],
5004 CounterExpectationsWithSocket { rx_delivered: 2, ..Default::default() },
5005 ),
5006 ],
5007 )
5008 }
5009
5010 type UdpMultipleDevicesCtx = FakeUdpCtx<MultipleDevicesId>;
5011 type UdpMultipleDevicesCoreCtx = FakeUdpCoreCtx<MultipleDevicesId>;
5012 type UdpMultipleDevicesBindingsCtx = FakeUdpBindingsCtx<MultipleDevicesId>;
5013
5014 impl FakeUdpCoreCtx<MultipleDevicesId> {
5015 fn new_multiple_devices<I: TestIpExt>() -> Self {
5016 let remote_ips = vec![I::get_other_remote_ip_address(1)];
5017 Self::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
5018 MultipleDevicesId::all().into_iter().enumerate().map(|(i, device)| {
5019 FakeDeviceConfig {
5020 device,
5021 local_ips: vec![Self::local_ip(i)],
5022 remote_ips: remote_ips.clone(),
5023 }
5024 }),
5025 ))
5026 }
5027
5028 fn local_ip<A: IpAddress>(index: usize) -> SpecifiedAddr<A>
5029 where
5030 A::Version: TestIpExt,
5031 {
5032 A::Version::get_other_ip_address((index + 1).try_into().unwrap())
5033 }
5034 }
5035
5036 #[ip_test(I)]
5039 #[test_case(WithEarlyDemux; "with early demux")]
5040 #[test_case(NoEarlyDemux; "without early demux")]
5041 fn test_bound_to_device_receive<I: TestIpExt>(early_demux_mode: EarlyDemuxMode) {
5042 set_logger_for_test();
5043 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5044 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5045 );
5046 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5047 let bound_first_device = api.create();
5048 api.listen(
5049 &bound_first_device,
5050 Some(ZonedAddr::Unzoned(local_ip::<I>())),
5051 Some(LOCAL_PORT),
5052 )
5053 .expect("listen should succeed");
5054 api.connect(
5055 &bound_first_device,
5056 Some(ZonedAddr::Unzoned(I::get_other_remote_ip_address(1))),
5057 REMOTE_PORT.into(),
5058 )
5059 .expect("connect should succeed");
5060 api.set_device(&bound_first_device, Some(&MultipleDevicesId::A))
5061 .expect("bind should succeed");
5062
5063 let bound_second_device = api.create();
5064 api.set_device(&bound_second_device, Some(&MultipleDevicesId::B)).unwrap();
5065 api.listen(&bound_second_device, None, Some(LOCAL_PORT)).expect("listen should succeed");
5066
5067 let meta = UdpPacketMeta::<I> {
5070 src_ip: I::get_other_remote_ip_address(1).get(),
5071 src_port: Some(REMOTE_PORT),
5072 dst_ip: local_ip::<I>().get(),
5073 dst_port: LOCAL_PORT,
5074 dscp_and_ecn: DscpAndEcn::default(),
5075 };
5076 let body = [1, 2, 3, 4, 5];
5077 let (core_ctx, bindings_ctx) = api.contexts();
5078 receive_udp_packet(
5079 core_ctx,
5080 bindings_ctx,
5081 MultipleDevicesId::A,
5082 meta.clone(),
5083 &body[..],
5084 early_demux_mode,
5085 )
5086 .expect("receive udp packet should succeed");
5087
5088 receive_udp_packet(
5091 core_ctx,
5092 bindings_ctx,
5093 MultipleDevicesId::B,
5094 meta,
5095 &body[..],
5096 early_demux_mode,
5097 )
5098 .expect("receive udp packet should succeed");
5099 assert_eq!(
5100 bindings_ctx.state.socket_data(),
5101 HashMap::from([
5102 (bound_first_device.downgrade(), vec![&body[..]]),
5103 (bound_second_device.downgrade(), vec![&body[..]])
5104 ])
5105 );
5106 }
5107
5108 #[ip_test(I)]
5111 fn test_bound_to_device_send<I: TestIpExt>() {
5112 set_logger_for_test();
5113 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5114 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5115 );
5116 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5117 let bound_on_devices = MultipleDevicesId::all().map(|device| {
5118 let socket = api.create();
5119 api.set_device(&socket, Some(&device)).unwrap();
5120 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen should succeed");
5121 socket
5122 });
5123
5124 let body = [1, 2, 3, 4, 5];
5126 for socket in bound_on_devices {
5127 api.send_to(
5128 &socket,
5129 Some(ZonedAddr::Unzoned(I::get_other_remote_ip_address(1))),
5130 REMOTE_PORT.into(),
5131 Buf::new(body.to_vec(), ..),
5132 )
5133 .expect("send should succeed");
5134 }
5135
5136 let mut received_devices = api
5137 .core_ctx()
5138 .bound_sockets
5139 .ip_socket_ctx
5140 .frames()
5141 .iter()
5142 .map(|(meta, _body)| {
5143 let SendIpPacketMeta {
5144 device,
5145 src_ip: _,
5146 dst_ip,
5147 destination: _,
5148 proto,
5149 ttl: _,
5150 mtu: _,
5151 dscp_and_ecn: _,
5152 } = meta.try_as::<I>().unwrap();
5153 assert_eq!(proto, &IpProto::Udp.into());
5154 assert_eq!(dst_ip, &I::get_other_remote_ip_address(1));
5155 *device
5156 })
5157 .collect::<Vec<_>>();
5158 received_devices.sort();
5159 assert_eq!(received_devices, &MultipleDevicesId::all());
5160 }
5161
5162 fn receive_packet_on<I: TestIpExt>(
5163 core_ctx: &mut UdpMultipleDevicesCoreCtx,
5164 bindings_ctx: &mut UdpMultipleDevicesBindingsCtx,
5165 device: MultipleDevicesId,
5166 early_demux_mode: EarlyDemuxMode,
5167 ) -> Result<(), I::IcmpError> {
5168 let meta = UdpPacketMeta::<I> {
5169 src_ip: I::get_other_remote_ip_address(1).get(),
5170 src_port: Some(REMOTE_PORT),
5171 dst_ip: local_ip::<I>().get(),
5172 dst_port: LOCAL_PORT,
5173 dscp_and_ecn: DscpAndEcn::default(),
5174 };
5175 const BODY: [u8; 5] = [1, 2, 3, 4, 5];
5176 receive_udp_packet(core_ctx, bindings_ctx, device, meta, &BODY[..], early_demux_mode)
5177 }
5178
5179 #[ip_test(I)]
5181 #[test_case(WithEarlyDemux; "with early demux")]
5182 #[test_case(NoEarlyDemux; "without early demux")]
5183 fn test_bind_unbind_device<I: TestIpExt>(early_demux_mode: EarlyDemuxMode) {
5184 set_logger_for_test();
5185 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5186 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5187 );
5188 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5189
5190 let socket = api.create();
5192 api.set_device(&socket, Some(&MultipleDevicesId::A)).unwrap();
5193 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen failed");
5194
5195 let (core_ctx, bindings_ctx) = api.contexts();
5197 assert_eq!(
5198 receive_packet_on::<I>(core_ctx, bindings_ctx, MultipleDevicesId::B, early_demux_mode),
5199 Err(I::IcmpError::port_unreachable())
5200 );
5201 let received = &bindings_ctx.state.socket_data::<I>();
5202 assert_eq!(received, &HashMap::new());
5203
5204 api.set_device(&socket, None).expect("clearing bound device failed");
5206 let (core_ctx, bindings_ctx) = api.contexts();
5207 receive_packet_on::<I>(core_ctx, bindings_ctx, MultipleDevicesId::B, early_demux_mode)
5208 .expect("receive udp packet should succeed");
5209 let received = bindings_ctx.state.received::<I>().iter().collect::<Vec<_>>();
5210 let (rx_socket, socket_received) =
5211 assert_matches!(received[..], [(rx_socket, packets)] => (rx_socket, packets));
5212 assert_eq!(rx_socket, &socket);
5213 assert_matches!(socket_received.packets[..], [_]);
5214 }
5215
5216 #[ip_test(I)]
5218 fn test_unbind_device_fails<I: TestIpExt>() {
5219 set_logger_for_test();
5220 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5221 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5222 );
5223 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5224
5225 let bound_on_devices = MultipleDevicesId::all().map(|device| {
5226 let socket = api.create();
5227 api.set_device(&socket, Some(&device)).unwrap();
5228 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen should succeed");
5229 socket
5230 });
5231
5232 for socket in bound_on_devices {
5235 assert_matches!(
5236 api.set_device(&socket, None),
5237 Err(SocketError::Local(LocalAddressError::AddressInUse))
5238 );
5239 }
5240 }
5241
5242 #[ip_test(I)]
5245 fn test_bind_conn_socket_device_fails<I: TestIpExt>() {
5246 set_logger_for_test();
5247 let device_configs = HashMap::from(
5248 [(MultipleDevicesId::A, 1), (MultipleDevicesId::B, 2)].map(|(device, i)| {
5249 (
5250 device,
5251 FakeDeviceConfig {
5252 device,
5253 local_ips: vec![I::get_other_ip_address(i)],
5254 remote_ips: vec![I::get_other_remote_ip_address(i)],
5255 },
5256 )
5257 }),
5258 );
5259 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5260 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
5261 device_configs.iter().map(|(_, v)| v).cloned(),
5262 )),
5263 );
5264 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5265 let socket = api.create();
5266 api.connect(
5267 &socket,
5268 Some(ZonedAddr::Unzoned(device_configs[&MultipleDevicesId::A].remote_ips[0])),
5269 REMOTE_PORT.into(),
5270 )
5271 .expect("connect should succeed");
5272
5273 assert_matches!(
5277 api.set_device(&socket, Some(&MultipleDevicesId::B)),
5278 Err(SocketError::Remote(RemoteAddressError::NoRoute))
5279 );
5280
5281 api.set_device(&socket, Some(&MultipleDevicesId::A)).expect("routing picked A already");
5283 }
5284
5285 #[ip_test(I)]
5286 #[test_case(WithEarlyDemux; "with early demux")]
5287 #[test_case(NoEarlyDemux; "without early demux")]
5288 fn test_bound_device_receive_multicast_packet<I: TestIpExt>(early_demux_mode: EarlyDemuxMode) {
5289 set_logger_for_test();
5290 let remote_ip = I::get_other_ip_address(1);
5291 let multicast_addr = I::get_multicast_addr(0);
5292
5293 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5294 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5295 );
5296 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5297
5298 let sharing_domain = SharingDomain::new(1);
5299
5300 let bound_on_devices = MultipleDevicesId::all().map(|device| {
5304 let listener = api.create();
5305 api.set_device(&listener, Some(&device)).unwrap();
5306 api.set_posix_reuse_port(&listener, ReusePortOption::Enabled(sharing_domain))
5307 .expect("is unbound");
5308 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen should succeed");
5309
5310 (device, listener)
5311 });
5312
5313 let listener = api.create();
5314 api.set_posix_reuse_port(&listener, ReusePortOption::Enabled(sharing_domain))
5315 .expect("is unbound");
5316 api.listen(&listener, None, Some(LOCAL_PORT)).expect("listen should succeed");
5317
5318 fn index_for_device(id: MultipleDevicesId) -> u8 {
5319 match id {
5320 MultipleDevicesId::A => 0,
5321 MultipleDevicesId::B => 1,
5322 MultipleDevicesId::C => 2,
5323 }
5324 }
5325
5326 let (core_ctx, bindings_ctx) = api.contexts();
5327 let mut receive_packet = |remote_ip: SpecifiedAddr<I::Addr>, device: MultipleDevicesId| {
5328 let meta = UdpPacketMeta::<I> {
5329 src_ip: remote_ip.get(),
5330 src_port: Some(REMOTE_PORT),
5331 dst_ip: multicast_addr.get(),
5332 dst_port: LOCAL_PORT,
5333 dscp_and_ecn: DscpAndEcn::default(),
5334 };
5335 let body = vec![index_for_device(device)];
5336 receive_udp_packet(core_ctx, bindings_ctx, device, meta, &body, early_demux_mode)
5337 .expect("receive udp packet should succeed")
5338 };
5339
5340 for device in MultipleDevicesId::all() {
5344 receive_packet(remote_ip, device);
5345 }
5346
5347 let per_socket_data = bindings_ctx.state.socket_data();
5348 for (device, listener) in bound_on_devices {
5349 assert_eq!(per_socket_data[&listener.downgrade()], vec![&[index_for_device(device)]]);
5350 }
5351 let expected_listener_data = &MultipleDevicesId::all().map(|d| vec![index_for_device(d)]);
5352 assert_eq!(&per_socket_data[&listener.downgrade()], expected_listener_data);
5353 }
5354
5355 #[ip_test(I)]
5357 fn test_conn_unspecified_local_ip<I: TestIpExt>() {
5358 set_logger_for_test();
5359 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5360 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5361 let socket = api.create();
5362 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen_udp failed");
5363 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip::<I>())), REMOTE_PORT.into())
5364 .expect("connect failed");
5365 let info = api.get_info(&socket);
5366 assert_eq!(
5367 info,
5368 SocketInfo::Connected(datagram::ConnInfo {
5369 local_ip: StrictlyZonedAddr::new_unzoned_or_panic(local_ip::<I>()),
5370 local_identifier: LOCAL_PORT,
5371 remote_ip: StrictlyZonedAddr::new_unzoned_or_panic(remote_ip::<I>()),
5372 remote_identifier: REMOTE_PORT.into(),
5373 })
5374 );
5375 }
5376
5377 #[ip_test(I)]
5378 fn test_multicast_sendto<I: TestIpExt>() {
5379 set_logger_for_test();
5380
5381 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5382 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5383 );
5384
5385 for device in MultipleDevicesId::all().iter() {
5387 ctx.core_ctx
5388 .bound_sockets
5389 .ip_socket_ctx
5390 .state
5391 .add_subnet_route(*device, I::MULTICAST_SUBNET);
5392 }
5393
5394 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5395 let socket = api.create();
5396
5397 for (i, target_device) in MultipleDevicesId::all().iter().enumerate() {
5398 api.set_multicast_interface(&socket, Some(&target_device), I::VERSION)
5399 .expect("bind should succeed");
5400
5401 let multicast_ip = I::get_multicast_addr(i.try_into().unwrap());
5402 api.send_to(
5403 &socket,
5404 Some(ZonedAddr::Unzoned(multicast_ip.into())),
5405 REMOTE_PORT.into(),
5406 Buf::new(b"packet".to_vec(), ..),
5407 )
5408 .expect("send should succeed");
5409
5410 let packets = api.core_ctx().bound_sockets.ip_socket_ctx.take_frames();
5411 assert_eq!(packets.len(), 1usize);
5412 for (meta, _body) in packets {
5413 let meta = meta.try_as::<I>().unwrap();
5414 assert_eq!(meta.device, *target_device);
5415 assert_eq!(meta.proto, IpProto::Udp.into());
5416 assert_eq!(meta.src_ip, UdpMultipleDevicesCoreCtx::local_ip(i));
5417 assert_eq!(meta.dst_ip, multicast_ip.into());
5418 assert_eq!(meta.destination, IpPacketDestination::Multicast(multicast_ip));
5419 }
5420 }
5421 }
5422
5423 #[ip_test(I)]
5424 fn test_multicast_send<I: TestIpExt>() {
5425 set_logger_for_test();
5426
5427 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5428 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5429 );
5430
5431 for device in MultipleDevicesId::all().iter() {
5433 ctx.core_ctx
5434 .bound_sockets
5435 .ip_socket_ctx
5436 .state
5437 .add_subnet_route(*device, I::MULTICAST_SUBNET);
5438 }
5439
5440 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5441 let multicast_ip = I::get_multicast_addr(42);
5442
5443 for (i, target_device) in MultipleDevicesId::all().iter().enumerate() {
5444 let socket = api.create();
5445
5446 api.set_multicast_interface(&socket, Some(&target_device), I::VERSION)
5447 .expect("set_multicast_interface should succeed");
5448
5449 api.connect(&socket, Some(ZonedAddr::Unzoned(multicast_ip.into())), REMOTE_PORT.into())
5450 .expect("send should succeed");
5451
5452 api.send(&socket, Buf::new(b"packet".to_vec(), ..)).expect("send should succeed");
5453
5454 let packets = api.core_ctx().bound_sockets.ip_socket_ctx.take_frames();
5455 assert_eq!(packets.len(), 1usize);
5456 for (meta, _body) in packets {
5457 let meta = meta.try_as::<I>().unwrap();
5458 assert_eq!(meta.device, *target_device);
5459 assert_eq!(meta.proto, IpProto::Udp.into());
5460 assert_eq!(meta.src_ip, UdpMultipleDevicesCoreCtx::local_ip(i));
5461 assert_eq!(meta.dst_ip, multicast_ip.into());
5462 assert_eq!(meta.destination, IpPacketDestination::Multicast(multicast_ip));
5463 }
5464 }
5465 }
5466
5467 #[ip_test(I)]
5472 fn test_udp_local_port_alloc<I: TestIpExt>() {
5473 let local_ip = local_ip::<I>();
5474 let ip_a = I::get_other_ip_address(100);
5475 let ip_b = I::get_other_ip_address(200);
5476
5477 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
5478 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![ip_a, ip_b]),
5479 );
5480 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5481
5482 let conn_a = api.create();
5483 api.connect(&conn_a, Some(ZonedAddr::Unzoned(ip_a)), REMOTE_PORT.into())
5484 .expect("connect failed");
5485 let conn_b = api.create();
5486 api.connect(&conn_b, Some(ZonedAddr::Unzoned(ip_b)), REMOTE_PORT.into())
5487 .expect("connect failed");
5488 let conn_c = api.create();
5489 api.connect(&conn_c, Some(ZonedAddr::Unzoned(ip_a)), OTHER_REMOTE_PORT.into())
5490 .expect("connect failed");
5491 let conn_d = api.create();
5492 api.connect(&conn_d, Some(ZonedAddr::Unzoned(ip_a)), REMOTE_PORT.into())
5493 .expect("connect failed");
5494 let valid_range = &FakePortAlloc::<I>::EPHEMERAL_RANGE;
5495 let mut get_conn_port = |id| {
5496 let info = api.get_info(&id);
5497 let info = assert_matches!(info, SocketInfo::Connected(info) => info);
5498 let datagram::ConnInfo {
5499 local_ip: _,
5500 local_identifier,
5501 remote_ip: _,
5502 remote_identifier: _,
5503 } = info;
5504 local_identifier
5505 };
5506 let port_a = get_conn_port(conn_a).get();
5507 let port_b = get_conn_port(conn_b).get();
5508 let port_c = get_conn_port(conn_c).get();
5509 let port_d = get_conn_port(conn_d).get();
5510 assert!(valid_range.contains(&port_a));
5511 assert!(valid_range.contains(&port_b));
5512 assert!(valid_range.contains(&port_c));
5513 assert!(valid_range.contains(&port_d));
5514 assert_ne!(port_a, port_b);
5515 assert_ne!(port_a, port_c);
5516 assert_ne!(port_a, port_d);
5517 }
5518
5519 #[ip_test(I)]
5521 fn test_udp_retry_listen_after_removing_conflict<I: TestIpExt>() {
5522 set_logger_for_test();
5523 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5524 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5525
5526 let listen_unbound = |api: &mut UdpApi<_, _>, socket: &UdpSocketId<_, _, _>| {
5527 api.listen(socket, Some(ZonedAddr::Unzoned(local_ip::<I>())), Some(LOCAL_PORT))
5528 };
5529
5530 let listener = api.create();
5532 listen_unbound(&mut api, &listener)
5533 .expect("Initial call to listen_udp was expected to succeed");
5534
5535 let unbound = api.create();
5537 assert_eq!(
5538 listen_unbound(&mut api, &unbound),
5539 Err(Either::Right(LocalAddressError::AddressInUse))
5540 );
5541
5542 api.close(listener).into_removed();
5545
5546 listen_unbound(&mut api, &unbound).expect("listen should succeed");
5547 }
5548
5549 #[ip_test(I)]
5554 fn test_udp_listen_port_alloc<I: TestIpExt>() {
5555 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5556 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5557 let local_ip = local_ip::<I>();
5558
5559 let wildcard_list = api.create();
5560 api.listen(&wildcard_list, None, None).expect("listen_udp failed");
5561 let specified_list = api.create();
5562 api.listen(&specified_list, Some(ZonedAddr::Unzoned(local_ip)), None)
5563 .expect("listen_udp failed");
5564 let mut get_listener_port = |id| {
5565 let info = api.get_info(&id);
5566 let info = assert_matches!(info, SocketInfo::Listener(info) => info);
5567 let datagram::ListenerInfo { local_ip: _, local_identifier } = info;
5568 local_identifier
5569 };
5570 let wildcard_port = get_listener_port(wildcard_list);
5571 let specified_port = get_listener_port(specified_list);
5572 assert!(FakePortAlloc::<I>::EPHEMERAL_RANGE.contains(&wildcard_port.get()));
5573 assert!(FakePortAlloc::<I>::EPHEMERAL_RANGE.contains(&specified_port.get()));
5574 assert_ne!(wildcard_port, specified_port);
5575 }
5576
5577 #[ip_test(I)]
5578 fn test_bind_multiple_reuse_port<I: TestIpExt>() {
5579 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5580 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5581 let listeners = [(), ()].map(|()| {
5582 let socket = api.create();
5583 let sharing_domain = SharingDomain::new(1);
5584 api.set_posix_reuse_port(&socket, ReusePortOption::Enabled(sharing_domain))
5585 .expect("is unbound");
5586 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen_udp failed");
5587 socket
5588 });
5589
5590 for listener in listeners {
5591 assert_eq!(
5592 api.get_info(&listener),
5593 SocketInfo::Listener(datagram::ListenerInfo {
5594 local_ip: None,
5595 local_identifier: LOCAL_PORT
5596 })
5597 );
5598 }
5599 }
5600
5601 #[ip_test(I)]
5602 fn test_set_unset_reuse_port_unbound<I: TestIpExt>() {
5603 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5604 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5605 let unbound = api.create();
5606 let sharing_domain = SharingDomain::new(1);
5607 api.set_posix_reuse_port(&unbound, ReusePortOption::Enabled(sharing_domain))
5608 .expect("is unbound");
5609 api.set_posix_reuse_port(&unbound, ReusePortOption::Disabled).expect("is unbound");
5610 api.listen(&unbound, None, Some(LOCAL_PORT)).expect("listen_udp failed");
5611
5612 assert_eq!(
5615 {
5616 let unbound = api.create();
5617 api.listen(&unbound, None, Some(LOCAL_PORT))
5618 },
5619 Err(Either::Right(LocalAddressError::AddressInUse))
5620 );
5621 }
5622
5623 #[ip_test(I)]
5624 #[test_case(bind_as_listener)]
5625 #[test_case(bind_as_connected)]
5626 fn test_set_unset_reuse_port_bound<I: TestIpExt>(
5627 set_up_socket: impl FnOnce(
5628 &mut UdpMultipleDevicesCtx,
5629 &UdpSocketId<
5630 I,
5631 FakeWeakDeviceId<MultipleDevicesId>,
5632 FakeUdpBindingsCtx<MultipleDevicesId>,
5633 >,
5634 ),
5635 ) {
5636 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5637 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5638 );
5639 let socket = UdpApi::<I, _>::new(ctx.as_mut()).create();
5640 set_up_socket(&mut ctx, &socket);
5641
5642 assert_matches!(
5645 UdpApi::<I, _>::new(ctx.as_mut())
5646 .set_posix_reuse_port(&socket, ReusePortOption::Disabled),
5647 Err(ExpectedUnboundError)
5648 )
5649 }
5650
5651 #[ip_test(I)]
5653 fn test_remove_udp_conn<I: TestIpExt>() {
5654 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5655 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5656
5657 let local_ip = ZonedAddr::Unzoned(local_ip::<I>());
5658 let remote_ip = ZonedAddr::Unzoned(remote_ip::<I>());
5659 let socket = api.create();
5660 api.listen(&socket, Some(local_ip), Some(LOCAL_PORT)).unwrap();
5661 api.connect(&socket, Some(remote_ip), REMOTE_PORT.into()).expect("connect failed");
5662 api.close(socket).into_removed();
5663 }
5664
5665 #[ip_test(I)]
5667 fn test_remove_udp_listener<I: TestIpExt>() {
5668 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
5669 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5670 let local_ip = ZonedAddr::Unzoned(local_ip::<I>());
5671
5672 let specified = api.create();
5674 api.listen(&specified, Some(local_ip), Some(LOCAL_PORT)).expect("listen_udp failed");
5675 api.close(specified).into_removed();
5676
5677 let wildcard = api.create();
5679 api.listen(&wildcard, None, Some(LOCAL_PORT)).expect("listen_udp failed");
5680 api.close(wildcard).into_removed();
5681 }
5682
5683 fn try_join_leave_multicast<I: TestIpExt>(
5684 mcast_addr: MulticastAddr<I::Addr>,
5685 interface: MulticastMembershipInterfaceSelector<I::Addr, MultipleDevicesId>,
5686 set_up_ctx: impl FnOnce(&mut UdpMultipleDevicesCtx),
5687 set_up_socket: impl FnOnce(
5688 &mut UdpMultipleDevicesCtx,
5689 &UdpSocketId<
5690 I,
5691 FakeWeakDeviceId<MultipleDevicesId>,
5692 FakeUdpBindingsCtx<MultipleDevicesId>,
5693 >,
5694 ),
5695 ) -> (
5696 Result<(), SetMulticastMembershipError>,
5697 HashMap<(MultipleDevicesId, MulticastAddr<I::Addr>), NonZeroUsize>,
5698 ) {
5699 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5700 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5701 );
5702 set_up_ctx(&mut ctx);
5703
5704 let socket = UdpApi::<I, _>::new(ctx.as_mut()).create();
5705 set_up_socket(&mut ctx, &socket);
5706 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5707 let result = api.set_multicast_membership(&socket, mcast_addr, interface, true);
5708
5709 let memberships_snapshot =
5710 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>();
5711 if let Ok(()) = result {
5712 api.set_multicast_membership(&socket, mcast_addr, interface, false)
5713 .expect("leaving group failed");
5714 }
5715 assert_eq!(
5716 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5717 HashMap::default()
5718 );
5719
5720 (result, memberships_snapshot)
5721 }
5722
5723 fn leave_unbound<I: TestIpExt>(
5724 _ctx: &mut UdpMultipleDevicesCtx,
5725 _unbound: &UdpSocketId<
5726 I,
5727 FakeWeakDeviceId<MultipleDevicesId>,
5728 FakeUdpBindingsCtx<MultipleDevicesId>,
5729 >,
5730 ) {
5731 }
5732
5733 fn bind_as_listener<I: TestIpExt>(
5734 ctx: &mut UdpMultipleDevicesCtx,
5735 unbound: &UdpSocketId<
5736 I,
5737 FakeWeakDeviceId<MultipleDevicesId>,
5738 FakeUdpBindingsCtx<MultipleDevicesId>,
5739 >,
5740 ) {
5741 UdpApi::<I, _>::new(ctx.as_mut())
5742 .listen(unbound, Some(ZonedAddr::Unzoned(local_ip::<I>())), Some(LOCAL_PORT))
5743 .expect("listen should succeed")
5744 }
5745
5746 fn bind_as_connected<I: TestIpExt>(
5747 ctx: &mut UdpMultipleDevicesCtx,
5748 unbound: &UdpSocketId<
5749 I,
5750 FakeWeakDeviceId<MultipleDevicesId>,
5751 FakeUdpBindingsCtx<MultipleDevicesId>,
5752 >,
5753 ) {
5754 UdpApi::<I, _>::new(ctx.as_mut())
5755 .connect(
5756 unbound,
5757 Some(ZonedAddr::Unzoned(I::get_other_remote_ip_address(1))),
5758 REMOTE_PORT.into(),
5759 )
5760 .expect("connect should succeed")
5761 }
5762
5763 fn iface_id<A: IpAddress>(
5764 id: MultipleDevicesId,
5765 ) -> MulticastMembershipInterfaceSelector<A, MultipleDevicesId> {
5766 MulticastInterfaceSelector::Interface(id).into()
5767 }
5768 fn iface_addr<A: IpAddress>(
5769 addr: SpecifiedAddr<A>,
5770 ) -> MulticastMembershipInterfaceSelector<A, MultipleDevicesId> {
5771 MulticastInterfaceSelector::LocalAddress(addr).into()
5772 }
5773
5774 #[ip_test(I)]
5775 #[test_case(iface_id(MultipleDevicesId::A), leave_unbound::<I>; "device_no_addr_unbound")]
5776 #[test_case(iface_addr(local_ip::<I>()), leave_unbound::<I>; "addr_no_device_unbound")]
5777 #[test_case(MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute, leave_unbound::<I>;
5778 "any_interface_unbound")]
5779 #[test_case(iface_id(MultipleDevicesId::A), bind_as_listener::<I>; "device_no_addr_listener")]
5780 #[test_case(iface_addr(local_ip::<I>()), bind_as_listener::<I>; "addr_no_device_listener")]
5781 #[test_case(MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute, bind_as_listener::<I>;
5782 "any_interface_listener")]
5783 #[test_case(iface_id(MultipleDevicesId::A), bind_as_connected::<I>; "device_no_addr_connected")]
5784 #[test_case(iface_addr(local_ip::<I>()), bind_as_connected::<I>; "addr_no_device_connected")]
5785 #[test_case(MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute, bind_as_connected::<I>;
5786 "any_interface_connected")]
5787 fn test_join_leave_multicast_succeeds<I: TestIpExt>(
5788 interface: MulticastMembershipInterfaceSelector<I::Addr, MultipleDevicesId>,
5789 set_up_socket: impl FnOnce(
5790 &mut UdpMultipleDevicesCtx,
5791 &UdpSocketId<
5792 I,
5793 FakeWeakDeviceId<MultipleDevicesId>,
5794 FakeUdpBindingsCtx<MultipleDevicesId>,
5795 >,
5796 ),
5797 ) {
5798 let mcast_addr = I::get_multicast_addr(3);
5799
5800 let set_up_ctx = |ctx: &mut UdpMultipleDevicesCtx| {
5801 match interface {
5804 MulticastMembershipInterfaceSelector::Specified(_) => {}
5805 MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute => {
5806 ctx.core_ctx
5807 .bound_sockets
5808 .ip_socket_ctx
5809 .state
5810 .add_route(MultipleDevicesId::A, mcast_addr.into_specified().into());
5811 }
5812 }
5813 };
5814
5815 let (result, ip_options) =
5816 try_join_leave_multicast(mcast_addr, interface, set_up_ctx, set_up_socket);
5817 assert_eq!(result, Ok(()));
5818 assert_eq!(
5819 ip_options,
5820 HashMap::from([((MultipleDevicesId::A, mcast_addr), NonZeroUsize::new(1).unwrap())])
5821 );
5822 }
5823
5824 #[ip_test(I)]
5825 #[test_case(leave_unbound::<I>; "unbound")]
5826 #[test_case(bind_as_listener::<I>; "listener")]
5827 #[test_case(bind_as_connected::<I>; "connected")]
5828 fn test_join_multicast_fails_without_route<I: TestIpExt>(
5829 set_up_socket: impl FnOnce(
5830 &mut UdpMultipleDevicesCtx,
5831 &UdpSocketId<
5832 I,
5833 FakeWeakDeviceId<MultipleDevicesId>,
5834 FakeUdpBindingsCtx<MultipleDevicesId>,
5835 >,
5836 ),
5837 ) {
5838 let mcast_addr = I::get_multicast_addr(3);
5839
5840 let (result, ip_options) = try_join_leave_multicast(
5841 mcast_addr,
5842 MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute,
5843 |_: &mut UdpMultipleDevicesCtx| { },
5844 set_up_socket,
5845 );
5846 assert_eq!(result, Err(SetMulticastMembershipError::NoDeviceAvailable));
5847 assert_eq!(ip_options, HashMap::new());
5848 }
5849
5850 #[ip_test(I)]
5851 #[test_case(MultipleDevicesId::A, Some(local_ip::<I>()), leave_unbound, Ok(());
5852 "with_ip_unbound")]
5853 #[test_case(MultipleDevicesId::A, None, leave_unbound, Ok(());
5854 "without_ip_unbound")]
5855 #[test_case(MultipleDevicesId::A, Some(local_ip::<I>()), bind_as_listener, Ok(());
5856 "with_ip_listener")]
5857 #[test_case(MultipleDevicesId::A, Some(local_ip::<I>()), bind_as_connected, Ok(());
5858 "with_ip_connected")]
5859 fn test_join_leave_multicast_interface_inferred_from_bound_device<I: TestIpExt>(
5860 bound_device: MultipleDevicesId,
5861 interface_addr: Option<SpecifiedAddr<I::Addr>>,
5862 set_up_socket: impl FnOnce(
5863 &mut UdpMultipleDevicesCtx,
5864 &UdpSocketId<
5865 I,
5866 FakeWeakDeviceId<MultipleDevicesId>,
5867 FakeUdpBindingsCtx<MultipleDevicesId>,
5868 >,
5869 ),
5870 expected_result: Result<(), SetMulticastMembershipError>,
5871 ) {
5872 let mcast_addr = I::get_multicast_addr(3);
5873 let (result, ip_options) = try_join_leave_multicast(
5874 mcast_addr,
5875 interface_addr
5876 .map(MulticastInterfaceSelector::LocalAddress)
5877 .map(Into::into)
5878 .unwrap_or(MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute),
5879 |_: &mut UdpMultipleDevicesCtx| { },
5880 |ctx, unbound| {
5881 UdpApi::<I, _>::new(ctx.as_mut())
5882 .set_device(&unbound, Some(&bound_device))
5883 .unwrap();
5884 set_up_socket(ctx, &unbound)
5885 },
5886 );
5887 assert_eq!(result, expected_result);
5888 assert_eq!(
5889 ip_options,
5890 expected_result.map_or_else(
5891 |_| HashMap::default(),
5892 |()| HashMap::from([((bound_device, mcast_addr), NonZeroUsize::new(1).unwrap())])
5893 )
5894 );
5895 }
5896
5897 #[ip_test(I)]
5898 fn test_multicast_membership_with_removed_device<I: TestIpExt>() {
5899 let device = FakeReferencyDeviceId::default();
5900 let mut ctx =
5901 FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_with_device::<I>(device.clone()));
5902 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5903
5904 let unbound = api.create();
5905 api.set_device(&unbound, Some(&device)).unwrap();
5906
5907 device.mark_removed();
5908
5909 let group = I::get_multicast_addr(4);
5910 assert_eq!(
5911 api.set_multicast_membership(
5912 &unbound,
5913 group,
5914 MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute,
5916 true,
5917 ),
5918 Err(SetMulticastMembershipError::DeviceDoesNotExist),
5919 );
5920
5921 assert_eq!(
5927 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5928 HashMap::default(),
5929 );
5930 }
5931
5932 #[ip_test(I)]
5933 fn test_remove_udp_unbound_leaves_multicast_groups<I: TestIpExt>() {
5934 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5935 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5936 );
5937 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5938
5939 let unbound = api.create();
5940 let group = I::get_multicast_addr(4);
5941 api.set_multicast_membership(
5942 &unbound,
5943 group,
5944 MulticastInterfaceSelector::LocalAddress(local_ip::<I>()).into(),
5945 true,
5946 )
5947 .expect("join group failed");
5948
5949 assert_eq!(
5950 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5951 HashMap::from([((MultipleDevicesId::A, group), NonZeroUsize::new(1).unwrap())])
5952 );
5953
5954 api.close(unbound).into_removed();
5955 assert_eq!(
5956 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5957 HashMap::default()
5958 );
5959 }
5960
5961 #[ip_test(I)]
5962 fn test_remove_udp_listener_leaves_multicast_groups<I: TestIpExt>() {
5963 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
5964 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
5965 );
5966 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
5967 let local_ip = local_ip::<I>();
5968
5969 let socket = api.create();
5970 let first_group = I::get_multicast_addr(4);
5971 api.set_multicast_membership(
5972 &socket,
5973 first_group,
5974 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
5975 true,
5976 )
5977 .expect("join group failed");
5978
5979 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
5980 .expect("listen_udp failed");
5981 let second_group = I::get_multicast_addr(5);
5982 api.set_multicast_membership(
5983 &socket,
5984 second_group,
5985 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
5986 true,
5987 )
5988 .expect("join group failed");
5989
5990 assert_eq!(
5991 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
5992 HashMap::from([
5993 ((MultipleDevicesId::A, first_group), NonZeroUsize::new(1).unwrap()),
5994 ((MultipleDevicesId::A, second_group), NonZeroUsize::new(1).unwrap())
5995 ])
5996 );
5997
5998 api.close(socket).into_removed();
5999 assert_eq!(
6000 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
6001 HashMap::default()
6002 );
6003 }
6004
6005 #[ip_test(I)]
6006 fn test_remove_udp_connected_leaves_multicast_groups<I: TestIpExt>() {
6007 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6008 UdpMultipleDevicesCoreCtx::new_multiple_devices::<I>(),
6009 );
6010 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6011 let local_ip = local_ip::<I>();
6012
6013 let socket = api.create();
6014 let first_group = I::get_multicast_addr(4);
6015 api.set_multicast_membership(
6016 &socket,
6017 first_group,
6018 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
6019 true,
6020 )
6021 .expect("join group failed");
6022
6023 api.connect(
6024 &socket,
6025 Some(ZonedAddr::Unzoned(I::get_other_remote_ip_address(1))),
6026 REMOTE_PORT.into(),
6027 )
6028 .expect("connect failed");
6029
6030 let second_group = I::get_multicast_addr(5);
6031 api.set_multicast_membership(
6032 &socket,
6033 second_group,
6034 MulticastInterfaceSelector::LocalAddress(local_ip).into(),
6035 true,
6036 )
6037 .expect("join group failed");
6038
6039 assert_eq!(
6040 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
6041 HashMap::from([
6042 ((MultipleDevicesId::A, first_group), NonZeroUsize::new(1).unwrap()),
6043 ((MultipleDevicesId::A, second_group), NonZeroUsize::new(1).unwrap())
6044 ])
6045 );
6046
6047 api.close(socket).into_removed();
6048 assert_eq!(
6049 api.core_ctx().bound_sockets.ip_socket_ctx.state.multicast_memberships::<I>(),
6050 HashMap::default()
6051 );
6052 }
6053
6054 #[ip_test(I)]
6055 #[should_panic(expected = "listen again failed")]
6056 fn test_listen_udp_removes_unbound<I: TestIpExt>() {
6057 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6058 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6059 let local_ip = local_ip::<I>();
6060 let socket = api.create();
6061
6062 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
6063 .expect("listen_udp failed");
6064
6065 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(OTHER_LOCAL_PORT))
6068 .expect("listen again failed");
6069 }
6070
6071 #[ip_test(I)]
6072 fn test_get_conn_info<I: TestIpExt>() {
6073 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6074 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6075 let local_ip = ZonedAddr::Unzoned(local_ip::<I>());
6076 let remote_ip = ZonedAddr::Unzoned(remote_ip::<I>());
6077 let socket = api.create();
6079 api.listen(&socket, Some(local_ip), Some(LOCAL_PORT)).expect("listen_udp failed");
6080 api.connect(&socket, Some(remote_ip), REMOTE_PORT.into()).expect("connect failed");
6081 let info = api.get_info(&socket);
6082 let info = assert_matches!(info, SocketInfo::Connected(info) => info);
6083 assert_eq!(info.local_ip.into_inner(), local_ip.map_zone(FakeWeakDeviceId));
6084 assert_eq!(info.local_identifier, LOCAL_PORT);
6085 assert_eq!(info.remote_ip.into_inner(), remote_ip.map_zone(FakeWeakDeviceId));
6086 assert_eq!(info.remote_identifier, u16::from(REMOTE_PORT));
6087 }
6088
6089 #[ip_test(I)]
6090 fn test_get_listener_info<I: TestIpExt>() {
6091 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6092 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6093 let local_ip = ZonedAddr::Unzoned(local_ip::<I>());
6094
6095 let specified = api.create();
6097 api.listen(&specified, Some(local_ip), Some(LOCAL_PORT)).expect("listen_udp failed");
6098 let info = api.get_info(&specified);
6099 let info = assert_matches!(info, SocketInfo::Listener(info) => info);
6100 assert_eq!(info.local_ip.unwrap().into_inner(), local_ip.map_zone(FakeWeakDeviceId));
6101 assert_eq!(info.local_identifier, LOCAL_PORT);
6102
6103 let wildcard = api.create();
6105 api.listen(&wildcard, None, Some(OTHER_LOCAL_PORT)).expect("listen_udp failed");
6106 let info = api.get_info(&wildcard);
6107 let info = assert_matches!(info, SocketInfo::Listener(info) => info);
6108 assert_eq!(info.local_ip, None);
6109 assert_eq!(info.local_identifier, OTHER_LOCAL_PORT);
6110 }
6111
6112 #[ip_test(I)]
6113 fn test_get_reuse_port<I: TestIpExt>() {
6114 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6115 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6116 let first = api.create();
6117 assert_eq!(api.get_posix_reuse_port(&first), false);
6118
6119 let sharing_domain = SharingDomain::new(1);
6120 api.set_posix_reuse_port(&first, ReusePortOption::Enabled(sharing_domain))
6121 .expect("is unbound");
6122
6123 assert_eq!(api.get_posix_reuse_port(&first), true);
6124
6125 api.listen(&first, Some(ZonedAddr::Unzoned(local_ip::<I>())), None).expect("listen failed");
6126 assert_eq!(api.get_posix_reuse_port(&first), true);
6127 api.close(first).into_removed();
6128
6129 let second = api.create();
6130 api.set_posix_reuse_port(&second, ReusePortOption::Enabled(sharing_domain))
6131 .expect("is unbound");
6132 api.connect(&second, Some(ZonedAddr::Unzoned(remote_ip::<I>())), REMOTE_PORT.into())
6133 .expect("connect failed");
6134
6135 assert_eq!(api.get_posix_reuse_port(&second), true);
6136 }
6137
6138 #[ip_test(I)]
6139 fn test_get_bound_device_unbound<I: TestIpExt>() {
6140 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6141 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6142 let unbound = api.create();
6143
6144 assert_eq!(api.get_bound_device(&unbound), None);
6145
6146 api.set_device(&unbound, Some(&FakeDeviceId)).unwrap();
6147 assert_eq!(api.get_bound_device(&unbound), Some(FakeWeakDeviceId(FakeDeviceId)));
6148 }
6149
6150 #[ip_test(I)]
6151 fn test_get_bound_device_listener<I: TestIpExt>() {
6152 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6153 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6154 let socket = api.create();
6155
6156 api.set_device(&socket, Some(&FakeDeviceId)).unwrap();
6157 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip::<I>())), Some(LOCAL_PORT))
6158 .expect("failed to listen");
6159 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6160
6161 api.set_device(&socket, None).expect("failed to set device");
6162 assert_eq!(api.get_bound_device(&socket), None);
6163 }
6164
6165 #[ip_test(I)]
6166 fn test_get_bound_device_connected<I: TestIpExt>() {
6167 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6168 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6169 let socket = api.create();
6170 api.set_device(&socket, Some(&FakeDeviceId)).unwrap();
6171 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip::<I>())), REMOTE_PORT.into())
6172 .expect("failed to connect");
6173 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6174 api.set_device(&socket, None).expect("failed to set device");
6175 assert_eq!(api.get_bound_device(&socket), None);
6176 }
6177
6178 #[ip_test(I)]
6179 fn test_listen_udp_forwards_errors<I: TestIpExt>() {
6180 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6181 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6182 let remote_ip = remote_ip::<I>();
6183
6184 let unbound = api.create();
6186 let listen_err = api
6187 .listen(&unbound, Some(ZonedAddr::Unzoned(remote_ip)), Some(LOCAL_PORT))
6188 .expect_err("listen_udp unexpectedly succeeded");
6189 assert_eq!(listen_err, Either::Right(LocalAddressError::CannotBindToAddress));
6190
6191 let unbound = api.create();
6192 let _ = api.listen(&unbound, None, Some(OTHER_LOCAL_PORT)).expect("listen_udp failed");
6193 let unbound = api.create();
6194 let listen_err = api
6195 .listen(&unbound, None, Some(OTHER_LOCAL_PORT))
6196 .expect_err("listen_udp unexpectedly succeeded");
6197 assert_eq!(listen_err, Either::Right(LocalAddressError::AddressInUse));
6198 }
6199
6200 const IPV6_LINK_LOCAL_ADDR: Ipv6Addr = net_ip_v6!("fe80::1234");
6201 #[test_case(IPV6_LINK_LOCAL_ADDR, IPV6_LINK_LOCAL_ADDR; "unicast")]
6202 #[test_case(IPV6_LINK_LOCAL_ADDR, MulticastAddr::new(net_ip_v6!("ff02::1234")).unwrap().get(); "multicast")]
6203 fn test_listen_udp_ipv6_link_local_requires_zone(
6204 interface_addr: Ipv6Addr,
6205 bind_addr: Ipv6Addr,
6206 ) {
6207 type I = Ipv6;
6208 let interface_addr = LinkLocalAddr::new(interface_addr).unwrap().into_specified();
6209
6210 let mut ctx =
6211 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
6212 vec![interface_addr],
6213 vec![remote_ip::<I>()],
6214 ));
6215 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6216
6217 let bind_addr = LinkLocalAddr::new(bind_addr).unwrap().into_specified();
6218 assert!(bind_addr.scope().can_have_zone());
6219
6220 let unbound = api.create();
6221 let result = api.listen(&unbound, Some(ZonedAddr::Unzoned(bind_addr)), Some(LOCAL_PORT));
6222 assert_eq!(
6223 result,
6224 Err(Either::Right(LocalAddressError::Zone(ZonedAddressError::RequiredZoneNotProvided)))
6225 );
6226 }
6227
6228 #[test_case(MultipleDevicesId::A, Ok(()); "matching")]
6229 #[test_case(MultipleDevicesId::B, Err(LocalAddressError::Zone(ZonedAddressError::DeviceZoneMismatch)); "not matching")]
6230 fn test_listen_udp_ipv6_link_local_with_bound_device_set(
6231 zone_id: MultipleDevicesId,
6232 expected_result: Result<(), LocalAddressError>,
6233 ) {
6234 type I = Ipv6;
6235 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6236 assert!(ll_addr.scope().can_have_zone());
6237
6238 let remote_ips = vec![remote_ip::<I>()];
6239 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6240 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6241 [(MultipleDevicesId::A, ll_addr), (MultipleDevicesId::B, local_ip::<I>())].map(
6242 |(device, local_ip)| FakeDeviceConfig {
6243 device,
6244 local_ips: vec![local_ip],
6245 remote_ips: remote_ips.clone(),
6246 },
6247 ),
6248 )),
6249 );
6250 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6251
6252 let socket = api.create();
6253 api.set_device(&socket, Some(&MultipleDevicesId::A)).unwrap();
6254
6255 let result = api
6256 .listen(
6257 &socket,
6258 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, zone_id).unwrap())),
6259 Some(LOCAL_PORT),
6260 )
6261 .map_err(Either::unwrap_right);
6262 assert_eq!(result, expected_result);
6263 }
6264
6265 #[test_case(MultipleDevicesId::A, Ok(()); "matching")]
6266 #[test_case(MultipleDevicesId::B, Err(LocalAddressError::AddressMismatch); "not matching")]
6267 fn test_listen_udp_ipv6_link_local_with_zone_requires_addr_assigned_to_device(
6268 zone_id: MultipleDevicesId,
6269 expected_result: Result<(), LocalAddressError>,
6270 ) {
6271 type I = Ipv6;
6272 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6273 assert!(ll_addr.scope().can_have_zone());
6274
6275 let remote_ips = vec![remote_ip::<I>()];
6276 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6277 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6278 [(MultipleDevicesId::A, ll_addr), (MultipleDevicesId::B, local_ip::<I>())].map(
6279 |(device, local_ip)| FakeDeviceConfig {
6280 device,
6281 local_ips: vec![local_ip],
6282 remote_ips: remote_ips.clone(),
6283 },
6284 ),
6285 )),
6286 );
6287 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6288
6289 let socket = api.create();
6290 let result = api
6291 .listen(
6292 &socket,
6293 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, zone_id).unwrap())),
6294 Some(LOCAL_PORT),
6295 )
6296 .map_err(Either::unwrap_right);
6297 assert_eq!(result, expected_result);
6298 }
6299
6300 #[test_case(None, Err(LocalAddressError::Zone(ZonedAddressError::DeviceZoneMismatch)); "clear device")]
6301 #[test_case(Some(MultipleDevicesId::A), Ok(()); "set same device")]
6302 #[test_case(Some(MultipleDevicesId::B),
6303 Err(LocalAddressError::Zone(ZonedAddressError::DeviceZoneMismatch)); "change device")]
6304 fn test_listen_udp_ipv6_listen_link_local_update_bound_device(
6305 new_device: Option<MultipleDevicesId>,
6306 expected_result: Result<(), LocalAddressError>,
6307 ) {
6308 type I = Ipv6;
6309 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6310 assert!(ll_addr.scope().can_have_zone());
6311
6312 let remote_ips = vec![remote_ip::<I>()];
6313 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6314 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6315 [(MultipleDevicesId::A, ll_addr), (MultipleDevicesId::B, local_ip::<I>())].map(
6316 |(device, local_ip)| FakeDeviceConfig {
6317 device,
6318 local_ips: vec![local_ip],
6319 remote_ips: remote_ips.clone(),
6320 },
6321 ),
6322 )),
6323 );
6324 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6325
6326 let socket = api.create();
6327 api.listen(
6328 &socket,
6329 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, MultipleDevicesId::A).unwrap())),
6330 Some(LOCAL_PORT),
6331 )
6332 .expect("listen failed");
6333
6334 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(MultipleDevicesId::A)));
6335
6336 assert_eq!(
6337 api.set_device(&socket, new_device.as_ref()),
6338 expected_result.map_err(SocketError::Local),
6339 );
6340 }
6341
6342 #[test_case(None; "bind all IPs")]
6343 #[test_case(Some(ZonedAddr::Unzoned(local_ip::<Ipv6>())); "bind unzoned")]
6344 #[test_case(Some(ZonedAddr::Zoned(AddrAndZone::new(SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap(),
6345 MultipleDevicesId::A).unwrap())); "bind with same zone")]
6346 fn test_udp_ipv6_connect_with_unzoned(
6347 bound_addr: Option<ZonedAddr<SpecifiedAddr<Ipv6Addr>, MultipleDevicesId>>,
6348 ) {
6349 let remote_ips = vec![remote_ip::<Ipv6>()];
6350
6351 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6352 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new([
6353 FakeDeviceConfig {
6354 device: MultipleDevicesId::A,
6355 local_ips: vec![
6356 local_ip::<Ipv6>(),
6357 SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap(),
6358 ],
6359 remote_ips: remote_ips.clone(),
6360 },
6361 FakeDeviceConfig {
6362 device: MultipleDevicesId::B,
6363 local_ips: vec![SpecifiedAddr::new(net_ip_v6!("fe80::2")).unwrap()],
6364 remote_ips: remote_ips,
6365 },
6366 ])),
6367 );
6368 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6369
6370 let socket = api.create();
6371
6372 api.listen(&socket, bound_addr, Some(LOCAL_PORT)).unwrap();
6373
6374 assert_matches!(
6375 api.connect(
6376 &socket,
6377 Some(ZonedAddr::Unzoned(remote_ip::<Ipv6>())),
6378 REMOTE_PORT.into(),
6379 ),
6380 Ok(())
6381 );
6382 }
6383
6384 #[test]
6385 fn test_udp_ipv6_connect_zoned_get_info() {
6386 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6387 assert!(ll_addr.must_have_zone());
6388
6389 let remote_ips = vec![remote_ip::<Ipv6>()];
6390 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6391 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6392 [(MultipleDevicesId::A, ll_addr), (MultipleDevicesId::B, local_ip::<Ipv6>())].map(
6393 |(device, local_ip)| FakeDeviceConfig {
6394 device,
6395 local_ips: vec![local_ip],
6396 remote_ips: remote_ips.clone(),
6397 },
6398 ),
6399 )),
6400 );
6401
6402 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6403 let socket = api.create();
6404 api.set_device(&socket, Some(&MultipleDevicesId::A)).unwrap();
6405
6406 let zoned_local_addr =
6407 ZonedAddr::Zoned(AddrAndZone::new(ll_addr, MultipleDevicesId::A).unwrap());
6408 api.listen(&socket, Some(zoned_local_addr), Some(LOCAL_PORT)).unwrap();
6409
6410 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip::<Ipv6>())), REMOTE_PORT.into())
6411 .expect("connect should succeed");
6412
6413 assert_eq!(
6414 api.get_info(&socket),
6415 SocketInfo::Connected(datagram::ConnInfo {
6416 local_ip: StrictlyZonedAddr::new_with_zone(ll_addr, || FakeWeakDeviceId(
6417 MultipleDevicesId::A
6418 )),
6419 local_identifier: LOCAL_PORT,
6420 remote_ip: StrictlyZonedAddr::new_unzoned_or_panic(remote_ip::<Ipv6>()),
6421 remote_identifier: REMOTE_PORT.into(),
6422 })
6423 );
6424 }
6425
6426 #[test_case(ZonedAddr::Zoned(AddrAndZone::new(SpecifiedAddr::new(net_ip_v6!("fe80::2")).unwrap(),
6427 MultipleDevicesId::B).unwrap()),
6428 Err(ConnectError::Zone(ZonedAddressError::DeviceZoneMismatch));
6429 "connect to different zone")]
6430 #[test_case(ZonedAddr::Unzoned(SpecifiedAddr::new(net_ip_v6!("fe80::3")).unwrap()),
6431 Ok(FakeWeakDeviceId(MultipleDevicesId::A)); "connect implicit zone")]
6432 fn test_udp_ipv6_bind_zoned(
6433 remote_addr: ZonedAddr<SpecifiedAddr<Ipv6Addr>, MultipleDevicesId>,
6434 expected: Result<FakeWeakDeviceId<MultipleDevicesId>, ConnectError>,
6435 ) {
6436 let remote_ips = vec![SpecifiedAddr::new(net_ip_v6!("fe80::3")).unwrap()];
6437
6438 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6439 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new([
6440 FakeDeviceConfig {
6441 device: MultipleDevicesId::A,
6442 local_ips: vec![SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap()],
6443 remote_ips: remote_ips.clone(),
6444 },
6445 FakeDeviceConfig {
6446 device: MultipleDevicesId::B,
6447 local_ips: vec![SpecifiedAddr::new(net_ip_v6!("fe80::2")).unwrap()],
6448 remote_ips: remote_ips,
6449 },
6450 ])),
6451 );
6452
6453 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6454
6455 let socket = api.create();
6456
6457 api.listen(
6458 &socket,
6459 Some(ZonedAddr::Zoned(
6460 AddrAndZone::new(
6461 SpecifiedAddr::new(net_ip_v6!("fe80::1")).unwrap(),
6462 MultipleDevicesId::A,
6463 )
6464 .unwrap(),
6465 )),
6466 Some(LOCAL_PORT),
6467 )
6468 .unwrap();
6469
6470 let result = api
6471 .connect(&socket, Some(remote_addr), REMOTE_PORT.into())
6472 .map(|()| api.get_bound_device(&socket).unwrap());
6473 assert_eq!(result, expected);
6474 }
6475
6476 #[ip_test(I)]
6477 fn test_listen_udp_loopback_no_zone_is_required<I: TestIpExt>() {
6478 let loopback_addr = I::LOOPBACK_ADDRESS;
6479 let remote_ips = vec![remote_ip::<I>()];
6480
6481 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6482 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6483 [(MultipleDevicesId::A, loopback_addr), (MultipleDevicesId::B, local_ip::<I>())]
6484 .map(|(device, local_ip)| FakeDeviceConfig {
6485 device,
6486 local_ips: vec![local_ip],
6487 remote_ips: remote_ips.clone(),
6488 }),
6489 )),
6490 );
6491 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6492
6493 let unbound = api.create();
6494 api.set_device(&unbound, Some(&MultipleDevicesId::A)).unwrap();
6495
6496 let result =
6497 api.listen(&unbound, Some(ZonedAddr::Unzoned(loopback_addr)), Some(LOCAL_PORT));
6498 assert_matches!(result, Ok(_));
6499 }
6500
6501 #[test_case(None, true, Ok(()); "connected success")]
6502 #[test_case(None, false, Ok(()); "listening success")]
6503 #[test_case(Some(MultipleDevicesId::A), true, Ok(()); "conn bind same device")]
6504 #[test_case(Some(MultipleDevicesId::A), false, Ok(()); "listen bind same device")]
6505 #[test_case(
6506 Some(MultipleDevicesId::B),
6507 true,
6508 Err(SendToError::Zone(ZonedAddressError::DeviceZoneMismatch));
6509 "conn bind different device")]
6510 #[test_case(
6511 Some(MultipleDevicesId::B),
6512 false,
6513 Err(SendToError::Zone(ZonedAddressError::DeviceZoneMismatch));
6514 "listen bind different device")]
6515 fn test_udp_ipv6_send_to_zoned(
6516 bind_device: Option<MultipleDevicesId>,
6517 connect: bool,
6518 expected: Result<(), SendToError>,
6519 ) {
6520 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6521 assert!(ll_addr.must_have_zone());
6522 let conn_remote_ip = Ipv6::get_other_remote_ip_address(1);
6523
6524 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6525 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6526 [
6527 (MultipleDevicesId::A, Ipv6::get_other_ip_address(1)),
6528 (MultipleDevicesId::B, Ipv6::get_other_ip_address(2)),
6529 ]
6530 .map(|(device, local_ip)| FakeDeviceConfig {
6531 device,
6532 local_ips: vec![local_ip],
6533 remote_ips: vec![ll_addr, conn_remote_ip],
6534 }),
6535 )),
6536 );
6537
6538 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6539 let socket = api.create();
6540
6541 if let Some(device) = bind_device {
6542 api.set_device(&socket, Some(&device)).unwrap();
6543 }
6544
6545 let send_to_remote_addr =
6546 ZonedAddr::Zoned(AddrAndZone::new(ll_addr, MultipleDevicesId::A).unwrap());
6547 let result = if connect {
6548 api.connect(&socket, Some(ZonedAddr::Unzoned(conn_remote_ip)), REMOTE_PORT.into())
6549 .expect("connect should succeed");
6550 api.send_to(
6551 &socket,
6552 Some(send_to_remote_addr),
6553 REMOTE_PORT.into(),
6554 Buf::new(Vec::new(), ..),
6555 )
6556 } else {
6557 api.listen(&socket, None, Some(LOCAL_PORT)).expect("listen should succeed");
6558 api.send_to(
6559 &socket,
6560 Some(send_to_remote_addr),
6561 REMOTE_PORT.into(),
6562 Buf::new(Vec::new(), ..),
6563 )
6564 };
6565
6566 assert_eq!(result.map_err(|err| assert_matches!(err, Either::Right(e) => e)), expected);
6567 }
6568
6569 #[test_case(true; "connected")]
6570 #[test_case(false; "listening")]
6571 fn test_udp_ipv6_bound_zoned_send_to_zoned(connect: bool) {
6572 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::5678")).unwrap().into_specified();
6573 let device_a_local_ip = net_ip_v6!("fe80::1111");
6574 let conn_remote_ip = Ipv6::get_other_remote_ip_address(1);
6575
6576 let mut ctx = UdpMultipleDevicesCtx::with_core_ctx(
6577 UdpMultipleDevicesCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
6578 [
6579 (MultipleDevicesId::A, device_a_local_ip),
6580 (MultipleDevicesId::B, net_ip_v6!("fe80::2222")),
6581 ]
6582 .map(|(device, local_ip)| FakeDeviceConfig {
6583 device,
6584 local_ips: vec![LinkLocalAddr::new(local_ip).unwrap().into_specified()],
6585 remote_ips: vec![ll_addr, conn_remote_ip],
6586 }),
6587 )),
6588 );
6589 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6590
6591 let socket = api.create();
6592 api.listen(
6593 &socket,
6594 Some(ZonedAddr::Zoned(
6595 AddrAndZone::new(
6596 SpecifiedAddr::new(device_a_local_ip).unwrap(),
6597 MultipleDevicesId::A,
6598 )
6599 .unwrap(),
6600 )),
6601 Some(LOCAL_PORT),
6602 )
6603 .expect("listen should succeed");
6604
6605 let send_to_remote_addr =
6608 ZonedAddr::Zoned(AddrAndZone::new(ll_addr, MultipleDevicesId::B).unwrap());
6609
6610 let result = if connect {
6611 api.connect(&socket, Some(ZonedAddr::Unzoned(conn_remote_ip)), REMOTE_PORT.into())
6612 .expect("connect should succeed");
6613 api.send_to(
6614 &socket,
6615 Some(send_to_remote_addr),
6616 REMOTE_PORT.into(),
6617 Buf::new(Vec::new(), ..),
6618 )
6619 } else {
6620 api.send_to(
6621 &socket,
6622 Some(send_to_remote_addr),
6623 REMOTE_PORT.into(),
6624 Buf::new(Vec::new(), ..),
6625 )
6626 };
6627
6628 assert_matches!(
6629 result,
6630 Err(Either::Right(SendToError::Zone(ZonedAddressError::DeviceZoneMismatch)))
6631 );
6632 }
6633
6634 #[test_case(None; "removes implicit")]
6635 #[test_case(Some(FakeDeviceId); "preserves implicit")]
6636 fn test_connect_disconnect_affects_bound_device(bind_device: Option<FakeDeviceId>) {
6637 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6640 assert!(ll_addr.must_have_zone());
6641
6642 let local_ip = local_ip::<Ipv6>();
6643 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
6644 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![ll_addr]),
6645 );
6646 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6647
6648 let socket = api.create();
6649 api.set_device(&socket, bind_device.as_ref()).unwrap();
6650
6651 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT)).unwrap();
6652 api.connect(
6653 &socket,
6654 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, FakeDeviceId).unwrap())),
6655 REMOTE_PORT.into(),
6656 )
6657 .expect("connect should succeed");
6658
6659 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6660
6661 api.disconnect(&socket).expect("was connected");
6662
6663 assert_eq!(api.get_bound_device(&socket), bind_device.map(FakeWeakDeviceId));
6664 }
6665
6666 #[test]
6667 fn test_bind_zoned_addr_connect_disconnect() {
6668 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6671 assert!(ll_addr.must_have_zone());
6672
6673 let remote_ip = remote_ip::<Ipv6>();
6674 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
6675 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![ll_addr], vec![remote_ip]),
6676 );
6677
6678 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6679
6680 let socket = api.create();
6681 api.listen(
6682 &socket,
6683 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, FakeDeviceId).unwrap())),
6684 Some(LOCAL_PORT),
6685 )
6686 .unwrap();
6687 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
6688 .expect("connect should succeed");
6689
6690 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6691
6692 api.disconnect(&socket).expect("was connected");
6693 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6694 }
6695
6696 #[test]
6697 fn test_bind_device_after_connect_persists_after_disconnect() {
6698 let ll_addr = LinkLocalAddr::new(net_ip_v6!("fe80::1234")).unwrap().into_specified();
6701 assert!(ll_addr.must_have_zone());
6702
6703 let local_ip = local_ip::<Ipv6>();
6704 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(
6705 UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(vec![local_ip], vec![ll_addr]),
6706 );
6707 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6708 let socket = api.create();
6709 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT)).unwrap();
6710 api.connect(
6711 &socket,
6712 Some(ZonedAddr::Zoned(AddrAndZone::new(ll_addr, FakeDeviceId).unwrap())),
6713 REMOTE_PORT.into(),
6714 )
6715 .expect("connect should succeed");
6716
6717 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6718
6719 api.set_device(&socket, Some(&FakeDeviceId)).expect("binding same device should succeed");
6723
6724 api.disconnect(&socket).expect("was connected");
6725 assert_eq!(api.get_bound_device(&socket), Some(FakeWeakDeviceId(FakeDeviceId)));
6726 }
6727
6728 #[ip_test(I)]
6729 fn test_remove_udp_unbound<I: TestIpExt>() {
6730 let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
6731 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6732 let unbound = api.create();
6733 api.close(unbound).into_removed();
6734 }
6735
6736 #[ip_test(I)]
6737 fn test_hop_limits_used_for_sending_packets<I: TestIpExt>() {
6738 let some_multicast_addr: MulticastAddr<I::Addr> = I::map_ip(
6739 (),
6740 |()| Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
6741 |()| MulticastAddr::new(net_ip_v6!("ff0e::1")).unwrap(),
6742 );
6743
6744 let mut ctx =
6745 UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::with_local_remote_ip_addrs(
6746 vec![local_ip::<I>()],
6747 vec![remote_ip::<I>(), some_multicast_addr.into_specified()],
6748 ));
6749 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
6750 let listener = api.create();
6751
6752 const UNICAST_HOPS: NonZeroU8 = NonZeroU8::new(23).unwrap();
6753 const MULTICAST_HOPS: NonZeroU8 = NonZeroU8::new(98).unwrap();
6754 api.set_unicast_hop_limit(&listener, Some(UNICAST_HOPS), I::VERSION).unwrap();
6755 api.set_multicast_hop_limit(&listener, Some(MULTICAST_HOPS), I::VERSION).unwrap();
6756
6757 api.listen(&listener, None, None).expect("listen failed");
6758
6759 let mut send_and_get_ttl = |remote_ip| {
6760 api.send_to(
6761 &listener,
6762 Some(ZonedAddr::Unzoned(remote_ip)),
6763 REMOTE_PORT.into(),
6764 Buf::new(vec![], ..),
6765 )
6766 .expect("send failed");
6767
6768 let (meta, _body) = api.core_ctx().bound_sockets.ip_socket_ctx.frames().last().unwrap();
6769 let SendIpPacketMeta { dst_ip, ttl, .. } = meta.try_as::<I>().unwrap();
6770 assert_eq!(*dst_ip, remote_ip);
6771 *ttl
6772 };
6773
6774 assert_eq!(send_and_get_ttl(some_multicast_addr.into_specified()), Some(MULTICAST_HOPS));
6775 assert_eq!(send_and_get_ttl(remote_ip::<I>()), Some(UNICAST_HOPS));
6776 }
6777
6778 const DUAL_STACK_ANY_ADDR: Ipv6Addr = net_ip_v6!("::");
6779 const DUAL_STACK_V4_ANY_ADDR: Ipv6Addr = net_ip_v6!("::FFFF:0.0.0.0");
6780
6781 #[derive(Copy, Clone, Debug)]
6782 enum DualStackBindAddr {
6783 Any,
6784 V4Any,
6785 V4Specific,
6786 }
6787
6788 impl DualStackBindAddr {
6789 const fn v6_addr(&self) -> Option<Ipv6Addr> {
6790 match self {
6791 Self::Any => Some(DUAL_STACK_ANY_ADDR),
6792 Self::V4Any => Some(DUAL_STACK_V4_ANY_ADDR),
6793 Self::V4Specific => None,
6794 }
6795 }
6796 }
6797 const V4_LOCAL_IP: Ipv4Addr = ip_v4!("192.168.1.10");
6798 const V4_LOCAL_IP_MAPPED: Ipv6Addr = net_ip_v6!("::ffff:192.168.1.10");
6799 const V6_LOCAL_IP: Ipv6Addr = net_ip_v6!("2201::1");
6800 const V6_REMOTE_IP: SpecifiedAddr<Ipv6Addr> =
6801 unsafe { SpecifiedAddr::new_unchecked(net_ip_v6!("2001:db8::1")) };
6802 const V4_REMOTE_IP_MAPPED: SpecifiedAddr<Ipv6Addr> =
6803 unsafe { SpecifiedAddr::new_unchecked(net_ip_v6!("::FFFF:192.0.2.1")) };
6804
6805 fn get_dual_stack_context<
6806 'a,
6807 BC: UdpBindingsTypes + 'a,
6808 CC: DatagramBoundStateContext<Ipv6, BC, Udp<BC>>,
6809 >(
6810 core_ctx: &'a mut CC,
6811 ) -> &'a mut CC::DualStackContext {
6812 match core_ctx.dual_stack_context_mut() {
6813 MaybeDualStack::NotDualStack(_) => unreachable!("UDP is a dual stack enabled protocol"),
6814 MaybeDualStack::DualStack(ds) => ds,
6815 }
6816 }
6817
6818 #[test_case::test_matrix(
6819 [DualStackBindAddr::Any, DualStackBindAddr::V4Any, DualStackBindAddr::V4Specific],
6820 [WithEarlyDemux, NoEarlyDemux]
6821 )]
6822 fn dual_stack_delivery(bind_addr: DualStackBindAddr, early_demux_mode: EarlyDemuxMode) {
6823 const REMOTE_IP: Ipv4Addr = ip_v4!("8.8.8.8");
6824 const REMOTE_IP_MAPPED: Ipv6Addr = net_ip_v6!("::ffff:8.8.8.8");
6825 let bind_addr = bind_addr.v6_addr().unwrap_or(V4_LOCAL_IP_MAPPED);
6826 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6827 vec![SpecifiedAddr::new(V4_LOCAL_IP).unwrap()],
6828 vec![SpecifiedAddr::new(REMOTE_IP).unwrap()],
6829 ));
6830
6831 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6832 let listener = api.create();
6833 api.listen(
6834 &listener,
6835 SpecifiedAddr::new(bind_addr).map(|a| ZonedAddr::Unzoned(a)),
6836 Some(LOCAL_PORT),
6837 )
6838 .expect("can bind");
6839
6840 const BODY: &[u8] = b"abcde";
6841 let (core_ctx, bindings_ctx) = api.contexts();
6842 receive_udp_packet(
6843 core_ctx,
6844 bindings_ctx,
6845 FakeDeviceId,
6846 UdpPacketMeta::<Ipv4> {
6847 src_ip: REMOTE_IP,
6848 src_port: Some(REMOTE_PORT),
6849 dst_ip: V4_LOCAL_IP,
6850 dst_port: LOCAL_PORT,
6851 dscp_and_ecn: DscpAndEcn::default(),
6852 },
6853 BODY,
6854 early_demux_mode,
6855 )
6856 .expect("receive udp packet should succeed");
6857
6858 assert_eq!(
6859 bindings_ctx.state.received::<Ipv6>(),
6860 &HashMap::from([(
6861 listener.downgrade(),
6862 SocketReceived {
6863 packets: vec![ReceivedPacket {
6864 body: BODY.into(),
6865 meta: UdpPacketMeta::<Ipv6> {
6866 src_ip: REMOTE_IP_MAPPED,
6867 src_port: Some(REMOTE_PORT),
6868 dst_ip: V4_LOCAL_IP_MAPPED,
6869 dst_port: LOCAL_PORT,
6870 dscp_and_ecn: DscpAndEcn::default(),
6871 }
6872 }],
6873 max_size: usize::MAX,
6874 }
6875 )])
6876 );
6877 }
6878
6879 #[test_case(DualStackBindAddr::Any, true; "dual-stack any bind v4 first")]
6880 #[test_case(DualStackBindAddr::V4Any, true; "v4 any bind v4 first")]
6881 #[test_case(DualStackBindAddr::V4Specific, true; "v4 specific bind v4 first")]
6882 #[test_case(DualStackBindAddr::Any, false; "dual-stack any bind v4 second")]
6883 #[test_case(DualStackBindAddr::V4Any, false; "v4 any bind v4 second")]
6884 #[test_case(DualStackBindAddr::V4Specific, false; "v4 specific bind v4 second")]
6885 fn dual_stack_bind_conflict(bind_addr: DualStackBindAddr, bind_v4_first: bool) {
6886 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6887 vec![SpecifiedAddr::new(V4_LOCAL_IP).unwrap()],
6888 vec![],
6889 ));
6890
6891 let v4_listener = UdpApi::<Ipv4, _>::new(ctx.as_mut()).create();
6892 let v6_listener = UdpApi::<Ipv6, _>::new(ctx.as_mut()).create();
6893
6894 let bind_v4 = |mut api: UdpApi<Ipv4, _>| {
6895 api.listen(
6896 &v4_listener,
6897 SpecifiedAddr::new(V4_LOCAL_IP).map(|a| ZonedAddr::Unzoned(a)),
6898 Some(LOCAL_PORT),
6899 )
6900 };
6901 let bind_v6 = |mut api: UdpApi<Ipv6, _>| {
6902 api.listen(
6903 &v6_listener,
6904 SpecifiedAddr::new(bind_addr.v6_addr().unwrap_or(V4_LOCAL_IP_MAPPED))
6905 .map(ZonedAddr::Unzoned),
6906 Some(LOCAL_PORT),
6907 )
6908 };
6909
6910 let second_bind_error = if bind_v4_first {
6911 bind_v4(UdpApi::<Ipv4, _>::new(ctx.as_mut())).expect("no conflict");
6912 bind_v6(UdpApi::<Ipv6, _>::new(ctx.as_mut())).expect_err("should conflict")
6913 } else {
6914 bind_v6(UdpApi::<Ipv6, _>::new(ctx.as_mut())).expect("no conflict");
6915 bind_v4(UdpApi::<Ipv4, _>::new(ctx.as_mut())).expect_err("should conflict")
6916 };
6917 assert_eq!(second_bind_error, Either::Right(LocalAddressError::AddressInUse));
6918 }
6919
6920 #[test_case(IpVersion::V4; "v4_is_constrained")]
6924 #[test_case(IpVersion::V6; "v6_is_constrained")]
6925 fn dual_stack_local_port_alloc(ip_version_with_constrained_ports: IpVersion) {
6926 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6927 vec![
6928 SpecifiedAddr::new(V4_LOCAL_IP.to_ip_addr()).unwrap(),
6929 SpecifiedAddr::new(V6_LOCAL_IP.to_ip_addr()).unwrap(),
6930 ],
6931 vec![],
6932 ));
6933
6934 const AVAILABLE_PORT: NonZeroU16 = NonZeroU16::new(54321).unwrap();
6936
6937 for port in 1..=u16::MAX {
6939 let port = NonZeroU16::new(port).unwrap();
6940 if port == AVAILABLE_PORT {
6941 continue;
6942 }
6943 match ip_version_with_constrained_ports {
6944 IpVersion::V4 => {
6945 let mut api = UdpApi::<Ipv4, _>::new(ctx.as_mut());
6946 let listener = api.create();
6947 api.listen(
6948 &listener,
6949 SpecifiedAddr::new(V4_LOCAL_IP).map(|a| ZonedAddr::Unzoned(a)),
6950 Some(port),
6951 )
6952 .expect("listen v4 should succeed")
6953 }
6954 IpVersion::V6 => {
6955 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6956 let listener = api.create();
6957 api.listen(
6958 &listener,
6959 SpecifiedAddr::new(V6_LOCAL_IP).map(|a| ZonedAddr::Unzoned(a)),
6960 Some(port),
6961 )
6962 .expect("listen v6 should succeed")
6963 }
6964 }
6965 }
6966
6967 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6970 let listener = api.create();
6971 api.listen(&listener, None, None).expect("dualstack listen should succeed");
6972 let port = assert_matches!(api.get_info(&listener), SocketInfo::Listener(info) => info.local_identifier);
6973 assert_eq!(port, AVAILABLE_PORT);
6974 }
6975
6976 #[test_case(DualStackBindAddr::V4Any; "v4 any")]
6977 #[test_case(DualStackBindAddr::V4Specific; "v4 specific")]
6978 fn dual_stack_enable(bind_addr: DualStackBindAddr) {
6979 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
6980 vec![SpecifiedAddr::new(V4_LOCAL_IP).unwrap()],
6981 vec![],
6982 ));
6983 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
6984
6985 let bind_addr = bind_addr.v6_addr().unwrap_or(V4_LOCAL_IP_MAPPED);
6986 let listener = api.create();
6987
6988 assert_eq!(api.get_dual_stack_enabled(&listener), Ok(true));
6989 api.set_dual_stack_enabled(&listener, false).expect("can set dual-stack enabled");
6990
6991 assert_eq!(
6994 api.listen(
6995 &listener,
6996 SpecifiedAddr::new(bind_addr).map(|a| ZonedAddr::Unzoned(a)),
6997 Some(LOCAL_PORT),
6998 ),
6999 Err(Either::Right(LocalAddressError::CannotBindToAddress))
7000 );
7001 api.set_dual_stack_enabled(&listener, true).expect("can set dual-stack enabled");
7002 assert_eq!(
7004 api.listen(
7005 &listener,
7006 SpecifiedAddr::new(bind_addr).map(|a| ZonedAddr::Unzoned(a)),
7007 Some(LOCAL_PORT),
7008 ),
7009 Ok(())
7010 );
7011 }
7012
7013 #[test]
7014 fn dual_stack_bind_unassigned_v4_address() {
7015 const NOT_ASSIGNED_MAPPED: Ipv6Addr = net_ip_v6!("::ffff:8.8.8.8");
7016 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
7017 vec![SpecifiedAddr::new(V4_LOCAL_IP).unwrap()],
7018 vec![],
7019 ));
7020 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7021
7022 let listener = api.create();
7023 assert_eq!(
7024 api.listen(
7025 &listener,
7026 SpecifiedAddr::new(NOT_ASSIGNED_MAPPED).map(|a| ZonedAddr::Unzoned(a)),
7027 Some(LOCAL_PORT),
7028 ),
7029 Err(Either::Right(LocalAddressError::CannotBindToAddress))
7030 );
7031 }
7032
7033 #[test]
7038 fn dual_stack_connect_cleans_up_existing_listener() {
7039 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
7040 vec![Ipv6::TEST_ADDRS.local_ip],
7041 vec![Ipv6::TEST_ADDRS.remote_ip],
7042 ));
7043
7044 const DUAL_STACK_ANY_ADDR: Option<ZonedAddr<SpecifiedAddr<Ipv6Addr>, FakeDeviceId>> = None;
7045
7046 fn assert_listeners(core_ctx: &mut FakeUdpCoreCtx<FakeDeviceId>, expect_present: bool) {
7047 const V4_LISTENER_ADDR: ListenerAddr<
7048 ListenerIpAddr<Ipv4Addr, NonZeroU16>,
7049 FakeWeakDeviceId<FakeDeviceId>,
7050 > = ListenerAddr {
7051 ip: ListenerIpAddr { addr: None, identifier: LOCAL_PORT },
7052 device: None,
7053 };
7054 const V6_LISTENER_ADDR: ListenerAddr<
7055 ListenerIpAddr<Ipv6Addr, NonZeroU16>,
7056 FakeWeakDeviceId<FakeDeviceId>,
7057 > = ListenerAddr {
7058 ip: ListenerIpAddr { addr: None, identifier: LOCAL_PORT },
7059 device: None,
7060 };
7061
7062 DualStackBoundStateContext::with_both_bound_sockets_mut(
7063 get_dual_stack_context(&mut core_ctx.bound_sockets),
7064 |_core_ctx, v6_sockets, v4_sockets| {
7065 let v4 = v4_sockets.bound_sockets.listeners().get_by_addr(&V4_LISTENER_ADDR);
7066 let v6 = v6_sockets.bound_sockets.listeners().get_by_addr(&V6_LISTENER_ADDR);
7067 if expect_present {
7068 assert_matches!(v4, Some(_));
7069 assert_matches!(v6, Some(_));
7070 } else {
7071 assert_matches!(v4, None);
7072 assert_matches!(v6, None);
7073 }
7074 },
7075 );
7076 }
7077
7078 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7081 let socket = api.create();
7082 assert_eq!(api.listen(&socket, DUAL_STACK_ANY_ADDR, Some(LOCAL_PORT)), Ok(()));
7083 assert_listeners(api.core_ctx(), true);
7084
7085 assert_eq!(
7088 api.connect(
7089 &socket,
7090 Some(ZonedAddr::Unzoned(Ipv6::TEST_ADDRS.remote_ip)),
7091 REMOTE_PORT.into(),
7092 ),
7093 Ok(())
7094 );
7095 assert_matches!(api.get_info(&socket), SocketInfo::Connected(_));
7096 assert_listeners(api.core_ctx(), false);
7097 }
7098
7099 #[test_case(net_ip_v6!("::"), true; "dual stack any")]
7100 #[test_case(net_ip_v6!("::"), false; "v6 any")]
7101 #[test_case(net_ip_v6!("::ffff:0.0.0.0"), true; "v4 unspecified")]
7102 #[test_case(V4_LOCAL_IP_MAPPED, true; "v4 specified")]
7103 #[test_case(V6_LOCAL_IP, true; "v6 specified dual stack enabled")]
7104 #[test_case(V6_LOCAL_IP, false; "v6 specified dual stack disabled")]
7105 fn dual_stack_get_info(bind_addr: Ipv6Addr, enable_dual_stack: bool) {
7106 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs::<
7107 SpecifiedAddr<IpAddr>,
7108 >(
7109 vec![
7110 SpecifiedAddr::new(V4_LOCAL_IP).unwrap().into(),
7111 SpecifiedAddr::new(V6_LOCAL_IP).unwrap().into(),
7112 ],
7113 vec![],
7114 ));
7115 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7116
7117 let listener = api.create();
7118 api.set_dual_stack_enabled(&listener, enable_dual_stack)
7119 .expect("can set dual-stack enabled");
7120 let bind_addr = SpecifiedAddr::new(bind_addr);
7121 assert_eq!(
7122 api.listen(&listener, bind_addr.map(|a| ZonedAddr::Unzoned(a)), Some(LOCAL_PORT),),
7123 Ok(())
7124 );
7125
7126 assert_eq!(
7127 api.get_info(&listener),
7128 SocketInfo::Listener(datagram::ListenerInfo {
7129 local_ip: bind_addr.map(StrictlyZonedAddr::new_unzoned_or_panic),
7130 local_identifier: LOCAL_PORT,
7131 })
7132 );
7133 }
7134
7135 #[test_case(net_ip_v6!("::"), true; "dual stack any")]
7136 #[test_case(net_ip_v6!("::"), false; "v6 any")]
7137 #[test_case(net_ip_v6!("::ffff:0.0.0.0"), true; "v4 unspecified")]
7138 #[test_case(V4_LOCAL_IP_MAPPED, true; "v4 specified")]
7139 #[test_case(V6_LOCAL_IP, true; "v6 specified dual stack enabled")]
7140 #[test_case(V6_LOCAL_IP, false; "v6 specified dual stack disabled")]
7141 fn dual_stack_remove_listener(bind_addr: Ipv6Addr, enable_dual_stack: bool) {
7142 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs::<
7146 SpecifiedAddr<IpAddr>,
7147 >(
7148 vec![
7149 SpecifiedAddr::new(V4_LOCAL_IP).unwrap().into(),
7150 SpecifiedAddr::new(V6_LOCAL_IP).unwrap().into(),
7151 ],
7152 vec![],
7153 ));
7154 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7155
7156 let mut bind_listener = || {
7157 let listener = api.create();
7158 api.set_dual_stack_enabled(&listener, enable_dual_stack)
7159 .expect("can set dual-stack enabled");
7160 let bind_addr = SpecifiedAddr::new(bind_addr);
7161 assert_eq!(
7162 api.listen(&listener, bind_addr.map(|a| ZonedAddr::Unzoned(a)), Some(LOCAL_PORT)),
7163 Ok(())
7164 );
7165
7166 api.close(listener).into_removed();
7167 };
7168
7169 bind_listener();
7171 bind_listener();
7174 }
7175
7176 #[test_case(V6_REMOTE_IP, true; "This stack with dualstack enabled")]
7177 #[test_case(V6_REMOTE_IP, false; "This stack with dualstack disabled")]
7178 #[test_case(V4_REMOTE_IP_MAPPED, true; "other stack with dualstack enabled")]
7179 fn dualstack_remove_connected(remote_ip: SpecifiedAddr<Ipv6Addr>, enable_dual_stack: bool) {
7180 let mut ctx = datagram::testutil::setup_fake_ctx_with_dualstack_conn_addrs(
7184 Ipv6::UNSPECIFIED_ADDRESS.to_ip_addr(),
7185 remote_ip.into(),
7186 [FakeDeviceId {}],
7187 |device_configs| {
7188 FakeUdpCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
7189 device_configs,
7190 ))
7191 },
7192 );
7193 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7194
7195 let mut bind_connected = || {
7196 let socket = api.create();
7197 api.set_dual_stack_enabled(&socket, enable_dual_stack)
7198 .expect("can set dual-stack enabled");
7199 assert_eq!(
7200 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into(),),
7201 Ok(())
7202 );
7203
7204 api.close(socket).into_removed();
7205 };
7206
7207 bind_connected();
7209 bind_connected();
7212 }
7213
7214 #[test_case(false, V6_REMOTE_IP, Ok(());
7215 "connect to this stack with dualstack disabled")]
7216 #[test_case(true, V6_REMOTE_IP, Ok(());
7217 "connect to this stack with dualstack enabled")]
7218 #[test_case(false, V4_REMOTE_IP_MAPPED, Err(ConnectError::RemoteUnexpectedlyMapped);
7219 "connect to other stack with dualstack disabled")]
7220 #[test_case(true, V4_REMOTE_IP_MAPPED, Ok(());
7221 "connect to other stack with dualstack enabled")]
7222 fn dualstack_connect_unbound(
7223 enable_dual_stack: bool,
7224 remote_ip: SpecifiedAddr<Ipv6Addr>,
7225 expected_outcome: Result<(), ConnectError>,
7226 ) {
7227 let mut ctx = datagram::testutil::setup_fake_ctx_with_dualstack_conn_addrs(
7228 Ipv6::UNSPECIFIED_ADDRESS.to_ip_addr(),
7229 remote_ip.into(),
7230 [FakeDeviceId {}],
7231 |device_configs| {
7232 FakeUdpCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
7233 device_configs,
7234 ))
7235 },
7236 );
7237 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7238
7239 let socket = api.create();
7240
7241 api.set_dual_stack_enabled(&socket, enable_dual_stack).expect("can set dual-stack enabled");
7242
7243 assert_eq!(
7244 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into()),
7245 expected_outcome
7246 );
7247
7248 if expected_outcome.is_ok() {
7249 assert_matches!(
7250 api.get_info(&socket),
7251 SocketInfo::Connected(datagram::ConnInfo{
7252 local_ip: _,
7253 local_identifier: _,
7254 remote_ip: found_remote_ip,
7255 remote_identifier: found_remote_port,
7256 }) if found_remote_ip.addr() == remote_ip &&
7257 found_remote_port == u16::from(REMOTE_PORT)
7258 );
7259 assert_eq!(api.disconnect(&socket), Ok(()));
7261 }
7262
7263 assert_eq!(api.get_info(&socket), SocketInfo::Unbound);
7265 }
7266
7267 #[test_case(V6_LOCAL_IP, V6_REMOTE_IP, Ok(());
7268 "listener in this stack connected in this stack")]
7269 #[test_case(V6_LOCAL_IP, V4_REMOTE_IP_MAPPED, Err(ConnectError::RemoteUnexpectedlyMapped);
7270 "listener in this stack connected in other stack")]
7271 #[test_case(Ipv6::UNSPECIFIED_ADDRESS, V6_REMOTE_IP, Ok(());
7272 "listener in both stacks connected in this stack")]
7273 #[test_case(Ipv6::UNSPECIFIED_ADDRESS, V4_REMOTE_IP_MAPPED, Ok(());
7274 "listener in both stacks connected in other stack")]
7275 #[test_case(V4_LOCAL_IP_MAPPED, V6_REMOTE_IP,
7276 Err(ConnectError::RemoteUnexpectedlyNonMapped);
7277 "listener in other stack connected in this stack")]
7278 #[test_case(V4_LOCAL_IP_MAPPED, V4_REMOTE_IP_MAPPED, Ok(());
7279 "listener in other stack connected in other stack")]
7280 fn dualstack_connect_listener(
7281 local_ip: Ipv6Addr,
7282 remote_ip: SpecifiedAddr<Ipv6Addr>,
7283 expected_outcome: Result<(), ConnectError>,
7284 ) {
7285 let mut ctx = datagram::testutil::setup_fake_ctx_with_dualstack_conn_addrs(
7286 local_ip.to_ip_addr(),
7287 remote_ip.into(),
7288 [FakeDeviceId {}],
7289 |device_configs| {
7290 FakeUdpCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
7291 device_configs,
7292 ))
7293 },
7294 );
7295 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7296 let socket = api.create();
7297
7298 assert_eq!(
7299 api.listen(
7300 &socket,
7301 SpecifiedAddr::new(local_ip).map(|local_ip| ZonedAddr::Unzoned(local_ip)),
7302 Some(LOCAL_PORT),
7303 ),
7304 Ok(())
7305 );
7306
7307 assert_eq!(
7308 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into()),
7309 expected_outcome
7310 );
7311
7312 if expected_outcome.is_ok() {
7313 assert_matches!(
7314 api.get_info(&socket),
7315 SocketInfo::Connected(datagram::ConnInfo{
7316 local_ip: _,
7317 local_identifier: _,
7318 remote_ip: found_remote_ip,
7319 remote_identifier: found_remote_port,
7320 }) if found_remote_ip.addr() == remote_ip &&
7321 found_remote_port == u16::from(REMOTE_PORT)
7322 );
7323 assert_eq!(api.disconnect(&socket), Ok(()));
7325 }
7326
7327 assert_matches!(
7329 api.get_info(&socket),
7330 SocketInfo::Listener(datagram::ListenerInfo {
7331 local_ip: found_local_ip,
7332 local_identifier: found_local_port,
7333 }) if found_local_port == LOCAL_PORT &&
7334 local_ip == found_local_ip.map(
7335 |a| a.addr().get()
7336 ).unwrap_or(Ipv6::UNSPECIFIED_ADDRESS)
7337 );
7338 }
7339
7340 #[test_case(V6_REMOTE_IP, V6_REMOTE_IP, Ok(());
7341 "connected in this stack reconnected in this stack")]
7342 #[test_case(V6_REMOTE_IP, V4_REMOTE_IP_MAPPED, Err(ConnectError::RemoteUnexpectedlyMapped);
7343 "connected in this stack reconnected in other stack")]
7344 #[test_case(V4_REMOTE_IP_MAPPED, V6_REMOTE_IP,
7345 Err(ConnectError::RemoteUnexpectedlyNonMapped);
7346 "connected in other stack reconnected in this stack")]
7347 #[test_case(V4_REMOTE_IP_MAPPED, V4_REMOTE_IP_MAPPED, Ok(());
7348 "connected in other stack reconnected in other stack")]
7349 fn dualstack_connect_connected(
7350 original_remote_ip: SpecifiedAddr<Ipv6Addr>,
7351 new_remote_ip: SpecifiedAddr<Ipv6Addr>,
7352 expected_outcome: Result<(), ConnectError>,
7353 ) {
7354 let mut ctx = datagram::testutil::setup_fake_ctx_with_dualstack_conn_addrs(
7355 Ipv6::UNSPECIFIED_ADDRESS.to_ip_addr(),
7356 original_remote_ip.into(),
7357 [FakeDeviceId {}],
7358 |device_configs| {
7359 FakeUdpCoreCtx::with_ip_socket_ctx_state(FakeDualStackIpSocketCtx::new(
7360 device_configs,
7361 ))
7362 },
7363 );
7364
7365 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7366 let socket = api.create();
7367
7368 assert_eq!(
7369 api.connect(&socket, Some(ZonedAddr::Unzoned(original_remote_ip)), REMOTE_PORT.into(),),
7370 Ok(())
7371 );
7372
7373 assert_eq!(
7374 api.connect(
7375 &socket,
7376 Some(ZonedAddr::Unzoned(new_remote_ip)),
7377 OTHER_REMOTE_PORT.into(),
7378 ),
7379 expected_outcome
7380 );
7381
7382 let (expected_remote_ip, expected_remote_port) = if expected_outcome.is_ok() {
7383 (new_remote_ip, OTHER_REMOTE_PORT)
7384 } else {
7385 (original_remote_ip, REMOTE_PORT)
7387 };
7388 assert_matches!(
7389 api.get_info(&socket),
7390 SocketInfo::Connected(datagram::ConnInfo{
7391 local_ip: _,
7392 local_identifier: _,
7393 remote_ip: found_remote_ip,
7394 remote_identifier: found_remote_port,
7395 }) if found_remote_ip.addr() == expected_remote_ip &&
7396 found_remote_port == u16::from(expected_remote_port)
7397 );
7398
7399 assert_eq!(api.disconnect(&socket), Ok(()));
7401 assert_eq!(api.get_info(&socket), SocketInfo::Unbound);
7402 }
7403
7404 type FakeBoundSocketMap<I> =
7405 UdpBoundSocketMap<I, FakeWeakDeviceId<FakeDeviceId>, FakeUdpBindingsCtx<FakeDeviceId>>;
7406 type FakePortAlloc<'a, I> =
7407 UdpPortAlloc<'a, I, FakeWeakDeviceId<FakeDeviceId>, FakeUdpBindingsCtx<FakeDeviceId>>;
7408
7409 fn listen<I: IpExt>(
7410 ip: I::Addr,
7411 port: u16,
7412 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec> {
7413 let addr = SpecifiedAddr::new(ip).map(|a| SocketIpAddr::try_from(a).unwrap());
7414 let port = NonZeroU16::new(port).expect("port must be nonzero");
7415 AddrVec::Listen(ListenerAddr {
7416 ip: ListenerIpAddr { addr, identifier: port },
7417 device: None,
7418 })
7419 }
7420
7421 fn listen_device<I: IpExt>(
7422 ip: I::Addr,
7423 port: u16,
7424 device: FakeWeakDeviceId<FakeDeviceId>,
7425 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec> {
7426 let addr = SpecifiedAddr::new(ip).map(|a| SocketIpAddr::try_from(a).unwrap());
7427 let port = NonZeroU16::new(port).expect("port must be nonzero");
7428 AddrVec::Listen(ListenerAddr {
7429 ip: ListenerIpAddr { addr, identifier: port },
7430 device: Some(device),
7431 })
7432 }
7433
7434 fn conn<I: IpExt>(
7435 local_ip: I::Addr,
7436 local_port: u16,
7437 remote_ip: I::Addr,
7438 remote_port: u16,
7439 ) -> AddrVec<I, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec> {
7440 let local_ip = SocketIpAddr::new(local_ip).expect("addr must be specified & non-mapped");
7441 let local_port = NonZeroU16::new(local_port).expect("port must be nonzero");
7442 let remote_ip = SocketIpAddr::new(remote_ip).expect("addr must be specified & non-mapped");
7443 let remote_port = NonZeroU16::new(remote_port).expect("port must be nonzero").into();
7444 AddrVec::Conn(ConnAddr {
7445 ip: ConnIpAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) },
7446 device: None,
7447 })
7448 }
7449
7450 const SHARING_DOMAIN1: SharingDomain = SharingDomain::new(1);
7451 const SHARING_DOMAIN2: SharingDomain = SharingDomain::new(42);
7452 const EXCLUSIVE: Sharing = Sharing { reuse_addr: false, reuse_port: ReusePortOption::Disabled };
7453 const REUSE_ADDR: Sharing = Sharing { reuse_addr: true, reuse_port: ReusePortOption::Disabled };
7454 const REUSE_PORT: Sharing =
7455 Sharing { reuse_addr: false, reuse_port: ReusePortOption::Enabled(SHARING_DOMAIN1) };
7456 const REUSE_ADDR_PORT: Sharing =
7457 Sharing { reuse_addr: true, reuse_port: ReusePortOption::Enabled(SHARING_DOMAIN1) };
7458 const REUSE_PORT2: Sharing =
7459 Sharing { reuse_addr: false, reuse_port: ReusePortOption::Enabled(SHARING_DOMAIN2) };
7460 const REUSE_ADDR_PORT2: Sharing =
7461 Sharing { reuse_addr: true, reuse_port: ReusePortOption::Enabled(SHARING_DOMAIN2) };
7462
7463 #[test_case([
7464 (listen(ip_v4!("0.0.0.0"), 1), EXCLUSIVE),
7465 (listen(ip_v4!("0.0.0.0"), 2), EXCLUSIVE)],
7466 Ok(()); "listen_any_ip_different_port")]
7467 #[test_case([
7468 (listen(ip_v4!("0.0.0.0"), 1), EXCLUSIVE),
7469 (listen(ip_v4!("0.0.0.0"), 1), EXCLUSIVE)],
7470 Err(InsertError::Exists); "any_ip_same_port")]
7471 #[test_case([
7472 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7473 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE)],
7474 Err(InsertError::Exists); "listen_same_specific_ip")]
7475 #[test_case([
7476 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
7477 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR)],
7478 Ok(()); "listen_same_specific_ip_reuse_addr")]
7479 #[test_case([
7480 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7481 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT)],
7482 Ok(()); "listen_same_specific_ip_reuse_port")]
7483 #[test_case([
7484 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7485 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR)],
7486 Ok(()); "listen_same_specific_ip_reuse_addr_port_and_reuse_addr")]
7487 #[test_case([
7488 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
7489 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT)],
7490 Ok(()); "listen_same_specific_ip_reuse_addr_and_reuse_addr_port")]
7491 #[test_case([
7492 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7493 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT)],
7494 Ok(()); "listen_same_specific_ip_reuse_addr_port_and_reuse_port")]
7495 #[test_case([
7496 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7497 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT)],
7498 Ok(()); "listen_same_specific_ip_reuse_port_and_reuse_addr_port")]
7499 #[test_case([
7500 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7501 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT)],
7502 Ok(()); "listen_same_specific_ip_reuse_addr_port_and_reuse_addr_port")]
7503 #[test_case([
7504 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7505 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR)],
7506 Err(InsertError::Exists); "listen_same_specific_ip_exclusive_reuse_addr")]
7507 #[test_case([
7508 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
7509 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE)],
7510 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_exclusive")]
7511 #[test_case([
7512 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7513 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT)],
7514 Err(InsertError::Exists); "listen_same_specific_ip_exclusive_reuse_port")]
7515 #[test_case([
7516 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7517 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE)],
7518 Err(InsertError::Exists); "listen_same_specific_ip_reuse_port_exclusive")]
7519 #[test_case([
7520 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7521 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT)],
7522 Err(InsertError::Exists); "listen_same_specific_ip_exclusive_reuse_addr_port")]
7523 #[test_case([
7524 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7525 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE)],
7526 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_port_exclusive")]
7527 #[test_case([
7528 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7529 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR)],
7530 Err(InsertError::Exists); "listen_same_specific_ip_reuse_port_reuse_addr")]
7531 #[test_case([
7532 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
7533 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT)],
7534 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_reuse_port")]
7535 #[test_case([
7536 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7537 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7538 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),],
7539 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_port_and_reuse_port_and_reuse_addr")]
7540 #[test_case([
7541 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7542 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR),
7543 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),],
7544 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_port_and_reuse_addr_and_reuse_port")]
7545 #[test_case([
7546 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7547 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT2)],
7548 Err(InsertError::Exists); "listen_same_specific_ip_reuse_port_and_reuse_port2")]
7549 #[test_case([
7550 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7551 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT2)],
7552 Ok(()); "listen_same_specific_ip_reuse_addr_port_and_reuse_addr_port2")]
7553 #[test_case([
7554 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT),
7555 (listen(ip_v4!("1.1.1.1"), 1), REUSE_ADDR_PORT2),
7556 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT)],
7557 Err(InsertError::Exists); "listen_same_specific_ip_reuse_addr_port_and_reuse_addr_port2_and_reuse_port")]
7558 #[test_case([
7559 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7560 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), REUSE_PORT)],
7561 Ok(()); "conn_shadows_listener_reuse_port")]
7562 #[test_case([
7563 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7564 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE)],
7565 Err(InsertError::ShadowAddrExists); "conn_shadows_listener_exclusive")]
7566 #[test_case([
7567 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7568 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), REUSE_PORT)],
7569 Err(InsertError::ShadowAddrExists); "conn_shadows_listener_exclusive_reuse_port")]
7570 #[test_case([
7571 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7572 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE)],
7573 Err(InsertError::ShadowAddrExists); "conn_shadows_listener_reuse_port_exclusive")]
7574 #[test_case([
7575 (listen_device(ip_v4!("1.1.1.1"), 1, FakeWeakDeviceId(FakeDeviceId)), EXCLUSIVE),
7576 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE)],
7577 Err(InsertError::IndirectConflict); "conn_indirect_conflict_specific_listener")]
7578 #[test_case([
7579 (listen_device(ip_v4!("0.0.0.0"), 1, FakeWeakDeviceId(FakeDeviceId)), EXCLUSIVE),
7580 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE)],
7581 Err(InsertError::IndirectConflict); "conn_indirect_conflict_any_listener")]
7582 #[test_case([
7583 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE),
7584 (listen_device(ip_v4!("1.1.1.1"), 1, FakeWeakDeviceId(FakeDeviceId)), EXCLUSIVE)],
7585 Err(InsertError::IndirectConflict); "specific_listener_indirect_conflict_conn")]
7586 #[test_case([
7587 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 2), EXCLUSIVE),
7588 (listen_device(ip_v4!("0.0.0.0"), 1, FakeWeakDeviceId(FakeDeviceId)), EXCLUSIVE)],
7589 Err(InsertError::IndirectConflict); "any_listener_indirect_conflict_conn")]
7590 fn bind_sequence<
7591 C: IntoIterator<Item = (AddrVec<Ipv4, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>, Sharing)>,
7592 >(
7593 spec: C,
7594 expected: Result<(), InsertError>,
7595 ) {
7596 let mut primary_ids = Vec::new();
7597
7598 let mut create_socket = || {
7599 let primary =
7600 datagram::testutil::create_primary_id((), Default::default(), &Default::default());
7601 let id = UdpSocketId(PrimaryRc::clone_strong(&primary));
7602 primary_ids.push(primary);
7603 id
7604 };
7605
7606 let mut map = FakeBoundSocketMap::<Ipv4>::default();
7607 let mut spec = spec.into_iter().peekable();
7608 let mut try_insert = |(addr, options)| match addr {
7609 AddrVec::Conn(c) => map
7610 .conns_mut()
7611 .try_insert(c, options, EitherIpSocket::V4(create_socket()))
7612 .map(|_| ()),
7613 AddrVec::Listen(l) => map
7614 .listeners_mut()
7615 .try_insert(l, options, EitherIpSocket::V4(create_socket()))
7616 .map(|_| ()),
7617 };
7618 let last = loop {
7619 let one_spec = spec.next().expect("empty list of test cases");
7620 if spec.peek().is_none() {
7621 break one_spec;
7622 } else {
7623 try_insert(one_spec).expect("intermediate bind failed")
7624 }
7625 };
7626
7627 let result = try_insert(last);
7628 assert_eq!(result, expected);
7629 }
7630
7631 #[test_case([
7632 (listen(ip_v4!("1.1.1.1"), 1), EXCLUSIVE),
7633 (listen(ip_v4!("2.2.2.2"), 2), EXCLUSIVE),
7634 ]; "distinct")]
7635 #[test_case([
7636 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7637 (listen(ip_v4!("1.1.1.1"), 1), REUSE_PORT),
7638 ]; "listen_reuse_port")]
7639 #[test_case([
7640 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 3), REUSE_PORT),
7641 (conn(ip_v4!("1.1.1.1"), 1, ip_v4!("2.2.2.2"), 3), REUSE_PORT),
7642 ]; "conn_reuse_port")]
7643 fn remove_sequence<I>(spec: I)
7644 where
7645 I: IntoIterator<
7646 Item = (AddrVec<Ipv4, FakeWeakDeviceId<FakeDeviceId>, UdpAddrSpec>, Sharing),
7647 >,
7648 I::IntoIter: ExactSizeIterator,
7649 {
7650 enum Socket<I: IpExt, D: WeakDeviceIdentifier, BT: UdpBindingsTypes, LI, RI> {
7651 Listener(UdpSocketId<I, D, BT>, ListenerAddr<ListenerIpAddr<I::Addr, LI>, D>),
7652 Conn(UdpSocketId<I, D, BT>, ConnAddr<ConnIpAddr<I::Addr, LI, RI>, D>),
7653 }
7654 let spec = spec.into_iter();
7655 let spec_len = spec.len();
7656
7657 let mut primary_ids = Vec::new();
7658
7659 let mut create_socket = || {
7660 let primary =
7661 datagram::testutil::create_primary_id((), Default::default(), &Default::default());
7662 let id = UdpSocketId(PrimaryRc::clone_strong(&primary));
7663 primary_ids.push(primary);
7664 id
7665 };
7666
7667 for spec in spec.permutations(spec_len) {
7668 let mut map = FakeBoundSocketMap::<Ipv4>::default();
7669 let sockets = spec
7670 .into_iter()
7671 .map(|(addr, options)| match addr {
7672 AddrVec::Conn(c) => map
7673 .conns_mut()
7674 .try_insert(c, options, EitherIpSocket::V4(create_socket()))
7675 .map(|entry| {
7676 Socket::Conn(
7677 assert_matches!(entry.id(), EitherIpSocket::V4(id) => id.clone()),
7678 entry.get_addr().clone(),
7679 )
7680 })
7681 .expect("insert_failed"),
7682 AddrVec::Listen(l) => map
7683 .listeners_mut()
7684 .try_insert(l, options, EitherIpSocket::V4(create_socket()))
7685 .map(|entry| {
7686 Socket::Listener(
7687 assert_matches!(entry.id(), EitherIpSocket::V4(id) => id.clone()),
7688 entry.get_addr().clone(),
7689 )
7690 })
7691 .expect("insert_failed"),
7692 })
7693 .collect::<Vec<_>>();
7694
7695 for socket in sockets {
7696 match socket {
7697 Socket::Listener(l, addr) => {
7698 assert_matches!(
7699 map.listeners_mut().remove(&EitherIpSocket::V4(l), &addr),
7700 Ok(())
7701 );
7702 }
7703 Socket::Conn(c, addr) => {
7704 assert_matches!(
7705 map.conns_mut().remove(&EitherIpSocket::V4(c), &addr),
7706 Ok(())
7707 );
7708 }
7709 }
7710 }
7711 }
7712 }
7713
7714 enum OriginalSocketState {
7715 Unbound,
7716 Listener,
7717 Connected,
7718 }
7719
7720 impl OriginalSocketState {
7721 fn create_socket<I, C>(&self, api: &mut UdpApi<I, C>) -> UdpApiSocketId<I, C>
7722 where
7723 I: TestIpExt,
7724 C: ContextPair,
7725 C::CoreContext: StateContext<I, C::BindingsContext>
7726 + UdpCounterContext<
7727 I,
7728 <C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId,
7729 C::BindingsContext,
7730 >,
7731 C::BindingsContext:
7732 UdpBindingsContext<I, <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
7733 <C::BindingsContext as UdpBindingsTypes>::ExternalData<I>: Default,
7734 <C::BindingsContext as UdpBindingsTypes>::SocketWritableListener: Default,
7735 <C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId:
7736 netstack3_base::InterfaceProperties<
7737 <C::BindingsContext as MatcherBindingsTypes>::DeviceClass,
7738 >,
7739 {
7740 let socket = api.create();
7741 match self {
7742 OriginalSocketState::Unbound => {}
7743 OriginalSocketState::Listener => {
7744 api.listen(
7745 &socket,
7746 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)),
7747 Some(LOCAL_PORT),
7748 )
7749 .expect("listen should succeed");
7750 }
7751 OriginalSocketState::Connected => {
7752 api.connect(
7753 &socket,
7754 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
7755 UdpRemotePort::Set(REMOTE_PORT),
7756 )
7757 .expect("connect should succeed");
7758 }
7759 }
7760 socket
7761 }
7762 }
7763
7764 #[test_case(OriginalSocketState::Unbound; "unbound")]
7765 #[test_case(OriginalSocketState::Listener; "listener")]
7766 #[test_case(OriginalSocketState::Connected; "connected")]
7767 fn set_get_dual_stack_enabled_v4(original_state: OriginalSocketState) {
7768 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
7769 vec![Ipv4::TEST_ADDRS.local_ip],
7770 vec![Ipv4::TEST_ADDRS.remote_ip],
7771 ));
7772 let mut api = UdpApi::<Ipv4, _>::new(ctx.as_mut());
7773 let socket = original_state.create_socket(&mut api);
7774
7775 for enabled in [true, false] {
7776 assert_eq!(
7777 api.set_dual_stack_enabled(&socket, enabled),
7778 Err(NotDualStackCapableError.into())
7779 );
7780 assert_eq!(api.get_dual_stack_enabled(&socket), Err(NotDualStackCapableError));
7781 }
7782 }
7783
7784 #[test_case(OriginalSocketState::Unbound, Ok(()); "unbound")]
7785 #[test_case(OriginalSocketState::Listener, Err(SetDualStackEnabledError::SocketIsBound);
7786 "listener")]
7787 #[test_case(OriginalSocketState::Connected, Err(SetDualStackEnabledError::SocketIsBound);
7788 "connected")]
7789 fn set_get_dual_stack_enabled_v6(
7790 original_state: OriginalSocketState,
7791 expected_result: Result<(), SetDualStackEnabledError>,
7792 ) {
7793 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
7794 vec![Ipv6::TEST_ADDRS.local_ip],
7795 vec![Ipv6::TEST_ADDRS.remote_ip],
7796 ));
7797 let mut api = UdpApi::<Ipv6, _>::new(ctx.as_mut());
7798 let socket = original_state.create_socket(&mut api);
7799
7800 const ORIGINALLY_ENABLED: bool = true;
7802 assert_eq!(api.get_dual_stack_enabled(&socket), Ok(ORIGINALLY_ENABLED));
7803
7804 for enabled in [false, true] {
7805 assert_eq!(api.set_dual_stack_enabled(&socket, enabled), expected_result);
7806 let expect_enabled = match expected_result {
7807 Ok(_) => enabled,
7808 Err(_) => ORIGINALLY_ENABLED,
7810 };
7811 assert_eq!(api.get_dual_stack_enabled(&socket), Ok(expect_enabled));
7812 }
7813 }
7814
7815 #[ip_test(I)]
7816 #[test_case::test_matrix(
7817 [MarkDomain::Mark1, MarkDomain::Mark2],
7818 [None, Some(0), Some(1)]
7819 )]
7820 fn udp_socket_marks<I: TestIpExt>(domain: MarkDomain, mark: Option<u32>) {
7821 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::with_local_remote_ip_addrs(
7822 vec![I::TEST_ADDRS.local_ip],
7823 vec![I::TEST_ADDRS.remote_ip],
7824 ));
7825 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
7826 let socket = api.create();
7827
7828 assert_eq!(api.get_mark(&socket, domain), Mark(None));
7830
7831 let mark = Mark(mark);
7832 api.set_mark(&socket, domain, mark);
7834 assert_eq!(api.get_mark(&socket, domain), mark);
7835 }
7836
7837 #[ip_test(I)]
7838 fn udp_early_demux<I: TestIpExt>() {
7839 set_logger_for_test();
7840 let mut ctx = FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_fake_device::<I>());
7841 let mut api = UdpApi::<I, _>::new(ctx.as_mut());
7842
7843 let local_ip = local_ip::<I>();
7844 let remote_ip = remote_ip::<I>();
7845 let socket = api.create();
7846
7847 api.listen(&socket, Some(ZonedAddr::Unzoned(local_ip)), Some(LOCAL_PORT))
7848 .expect("Initial call to listen_udp was expected to succeed");
7849
7850 let builder =
7851 UdpPacketBuilder::new(remote_ip.get(), local_ip.get(), Some(REMOTE_PORT), LOCAL_PORT);
7852
7853 let buffer = builder
7854 .wrap_body(Buf::new(vec![1, 2, 3, 4], ..))
7855 .serialize_vec_outer()
7856 .unwrap()
7857 .into_inner();
7858
7859 let early_demux_socket =
7861 <UdpIpTransportContext as IpTransportContext<I, _, _>>::early_demux(
7862 api.core_ctx(),
7863 &FakeDeviceId,
7864 remote_ip.get(),
7865 local_ip.get(),
7866 buffer.as_ref(),
7867 );
7868 assert_eq!(early_demux_socket, None);
7869
7870 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
7871 .expect("connect should succeed");
7872
7873 let early_demux_socket =
7874 <UdpIpTransportContext as IpTransportContext<I, _, _>>::early_demux(
7875 api.core_ctx(),
7876 &FakeDeviceId,
7877 remote_ip.get(),
7878 local_ip.get(),
7879 buffer.as_ref(),
7880 );
7881 assert_matches!(early_demux_socket, Some(_));
7882 }
7883}