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