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