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