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