1use alloc::vec::Vec;
8use core::borrow::Borrow;
9use core::convert::Infallible as Never;
10use core::error::Error;
11use core::fmt::Debug;
12use core::hash::Hash;
13use core::marker::PhantomData;
14use core::num::{NonZeroU8, NonZeroU16};
15use core::ops::{Deref, DerefMut};
16use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
17use netstack3_ip::marker::OptionDelegationMarker;
18
19use derivative::Derivative;
20use either::Either;
21use net_types::ip::{GenericOverIp, Ip, IpAddress, Ipv4, Ipv6, Mtu};
22use net_types::{MulticastAddr, MulticastAddress as _, SpecifiedAddr, Witness, ZonedAddr};
23use netstack3_base::socket::{
24 self, BoundSocketMap, ConnAddr, ConnInfoAddr, ConnIpAddr, DualStackConnIpAddr,
25 DualStackListenerIpAddr, DualStackLocalIp, DualStackRemoteIp, EitherStack, InsertError,
26 ListenerAddr, ListenerIpAddr, MaybeDualStack, NotDualStackCapableError, Shutdown, ShutdownType,
27 SocketCookie, SocketDeviceUpdate, SocketDeviceUpdateNotAllowedError, SocketIpAddr, SocketIpExt,
28 SocketMapAddrSpec, SocketMapConflictPolicy, SocketMapStateSpec, SocketWritableListener,
29 SocketZonedAddrExt as _, StrictlyZonedAddr,
30};
31use netstack3_base::sync::{self, RwLock};
32use netstack3_base::{
33 AnyDevice, BidirectionalConverter, ContextPair, CoreTxMetadataContext, DeviceIdContext,
34 DeviceIdentifier, EitherDeviceId, ExistsError, Inspector, InspectorDeviceExt,
35 InspectorExt as _, IpDeviceAddr, LocalAddressError, Mark, MarkDomain, Marks, NotFoundError,
36 OwnedOrRefsBidirectionalConverter, ReferenceNotifiers, ReferenceNotifiersExt,
37 RemoteAddressError, RemoveResourceResultWithContext, RngContext, SettingsContext, SocketError,
38 StrongDeviceIdentifier as _, TxMetadataBindingsTypes, WeakDeviceIdentifier, ZonedAddressError,
39};
40use netstack3_filter::{FilterIpExt, TransportPacketSerializer};
41use netstack3_hashmap::{HashMap, HashSet};
42use netstack3_ip::socket::{
43 DelegatedRouteResolutionOptions, DelegatedSendOptions, IpSock, IpSockCreateAndSendError,
44 IpSockCreationError, IpSockSendError, IpSocketArgs, IpSocketHandler, RouteResolutionOptions,
45 SendOneShotIpPacketError, SendOptions, SocketHopLimits,
46};
47use netstack3_ip::{
48 BaseTransportIpContext, HopLimits, IpLayerIpExt, MulticastMembershipHandler, ResolveRouteError,
49 SocketMetadata, TransportIpContext,
50};
51use packet::BufferMut;
52use packet_formats::ip::{DscpAndEcn, IpProtoExt};
53use ref_cast::RefCast;
54use thiserror::Error;
55
56use crate::internal::settings::DatagramSettings;
57use crate::internal::sndbuf::{SendBufferError, SendBufferTracking, TxMetadata};
58
59pub type BoundSockets<I, D, A, S> = BoundSocketMap<I, D, A, S>;
61
62#[derive(Derivative)]
64#[derivative(Debug(bound = ""))]
65pub struct ReferenceState<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
66 pub(crate) state: RwLock<SocketState<I, D, S>>,
67 pub(crate) external_data: S::ExternalData<I>,
68 pub(crate) send_buffer: SendBufferTracking<S>,
69 pub(crate) counters: S::Counters<I>,
70}
71
72type PrimaryRc<I, D, S> = sync::PrimaryRc<ReferenceState<I, D, S>>;
74pub type StrongRc<I, D, S> = sync::StrongRc<ReferenceState<I, D, S>>;
76pub type WeakRc<I, D, S> = sync::WeakRc<ReferenceState<I, D, S>>;
78
79impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>
80 OrderedLockAccess<SocketState<I, D, S>> for ReferenceState<I, D, S>
81{
82 type Lock = RwLock<SocketState<I, D, S>>;
83 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
84 OrderedLockRef::new(&self.state)
85 }
86}
87
88impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> ReferenceState<I, D, S> {
89 pub fn external_data(&self) -> &S::ExternalData<I> {
91 &self.external_data
92 }
93
94 #[cfg(any(test, feature = "testutils"))]
96 pub fn state(&self) -> &RwLock<SocketState<I, D, S>> {
97 &self.state
98 }
99
100 pub fn counters(&self) -> &S::Counters<I> {
102 &self.counters
103 }
104}
105
106#[derive(Derivative, GenericOverIp)]
108#[derivative(Default(bound = ""))]
109#[generic_over_ip(I, Ip)]
110pub struct DatagramSocketSet<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
111 HashMap<StrongRc<I, D, S>, PrimaryRc<I, D, S>>,
112);
113
114impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> Debug
115 for DatagramSocketSet<I, D, S>
116{
117 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118 let Self(rc) = self;
119 f.debug_list().entries(rc.keys().map(StrongRc::debug_id)).finish()
120 }
121}
122
123impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> Deref
124 for DatagramSocketSet<I, D, S>
125{
126 type Target = HashMap<StrongRc<I, D, S>, PrimaryRc<I, D, S>>;
127 fn deref(&self) -> &Self::Target {
128 &self.0
129 }
130}
131
132impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> DerefMut
133 for DatagramSocketSet<I, D, S>
134{
135 fn deref_mut(&mut self) -> &mut Self::Target {
136 &mut self.0
137 }
138}
139
140pub trait IpExt:
142 netstack3_base::IpExt + DualStackIpExt + netstack3_base::IcmpIpExt + FilterIpExt + IpLayerIpExt
143{
144}
145impl<
146 I: netstack3_base::IpExt + DualStackIpExt + netstack3_base::IcmpIpExt + FilterIpExt + IpLayerIpExt,
147> IpExt for I
148{
149}
150
151#[derive(Derivative, GenericOverIp)]
153#[generic_over_ip(I, Ip)]
154#[derivative(Debug(bound = ""))]
155pub struct SocketState<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
156 pub inner: SocketStateInner<I, D, S>,
158
159 pub(crate) ip_options: IpOptions<I, D, S>,
161}
162
163#[derive(Derivative, GenericOverIp)]
164#[generic_over_ip(I, Ip)]
165#[derivative(Debug(bound = ""))]
166#[allow(missing_docs)]
167pub enum SocketStateInner<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
168 Unbound(UnboundSocketState<D, S>),
169 Bound(BoundSocketState<I, D, S>),
170}
171
172impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> SocketState<I, D, S> {
173 pub fn to_socket_info(&self) -> SocketInfo<I::Addr, D> {
175 match &self.inner {
176 SocketStateInner::Unbound(_) => SocketInfo::Unbound,
177 SocketStateInner::Bound(BoundSocketState { socket_type, original_bound_addr: _ }) => {
178 match socket_type {
179 BoundSocketStateType::Listener { state, sharing: _ } => {
180 let ListenerState { addr } = state;
181 SocketInfo::Listener(addr.clone().into())
182 }
183 BoundSocketStateType::Connected { state, sharing: _ } => {
184 SocketInfo::Connected(S::conn_info_from_state(&state))
185 }
186 }
187 }
188 }
189 }
190
191 pub fn local_ip(&self) -> Option<StrictlyZonedAddr<I::Addr, SpecifiedAddr<I::Addr>, D>> {
193 match self.to_socket_info() {
194 SocketInfo::Unbound => None,
195 SocketInfo::Listener(ListenerInfo { local_ip, .. }) => local_ip,
196 SocketInfo::Connected(ConnInfo { local_ip, .. }) => Some(local_ip),
197 }
198 }
199
200 pub fn local_identifier(&self) -> Option<NonZeroU16> {
202 match self.to_socket_info() {
203 SocketInfo::Unbound => None,
204 SocketInfo::Listener(ListenerInfo { local_identifier, .. }) => Some(local_identifier),
205 SocketInfo::Connected(ConnInfo { local_identifier, .. }) => Some(local_identifier),
206 }
207 }
208
209 pub fn remote_ip(&self) -> Option<StrictlyZonedAddr<I::Addr, SpecifiedAddr<I::Addr>, D>> {
211 match self.to_socket_info() {
212 SocketInfo::Unbound => None,
213 SocketInfo::Listener(_) => None,
214 SocketInfo::Connected(ConnInfo { remote_ip, .. }) => Some(remote_ip),
215 }
216 }
217
218 pub fn remote_identifier(&self) -> Option<u16> {
220 match self.to_socket_info() {
221 SocketInfo::Unbound => None,
222 SocketInfo::Listener(_) => None,
223 SocketInfo::Connected(ConnInfo { remote_identifier, .. }) => Some(remote_identifier),
224 }
225 }
226
227 pub fn record_common_info<N>(&self, inspector: &mut N)
229 where
230 N: Inspector + InspectorDeviceExt<D>,
231 {
232 inspector.record_str("TransportProtocol", S::NAME);
233 inspector.record_str("NetworkProtocol", I::NAME);
234
235 let socket_info = self.to_socket_info();
236 let (local, remote) = match socket_info {
237 SocketInfo::Unbound => (None, None),
238 SocketInfo::Listener(ListenerInfo { local_ip, local_identifier }) => (
239 Some((
240 local_ip.map_or_else(
241 || ZonedAddr::Unzoned(I::UNSPECIFIED_ADDRESS),
242 |addr| addr.into_inner_without_witness(),
243 ),
244 local_identifier,
245 )),
246 None,
247 ),
248 SocketInfo::Connected(ConnInfo {
249 local_ip,
250 local_identifier,
251 remote_ip,
252 remote_identifier,
253 }) => (
254 Some((local_ip.into_inner_without_witness(), local_identifier)),
255 Some((remote_ip.into_inner_without_witness(), remote_identifier)),
256 ),
257 };
258 inspector.record_local_socket_addr::<N, _, _, _>(local);
259 inspector.record_remote_socket_addr::<N, _, _, _>(remote);
260
261 let IpOptions {
262 multicast_memberships: MulticastMemberships(multicast_memberships),
263 socket_options: _,
264 other_stack: _,
265 common,
266 } = self.options();
267 inspector.record_child("MulticastGroupMemberships", |node| {
268 for (index, (multicast_addr, device)) in multicast_memberships.iter().enumerate() {
269 node.record_debug_child(index, |node| {
270 node.record_ip_addr("MulticastGroup", multicast_addr.get());
271 N::record_device(node, "Device", device);
272 })
273 }
274 });
275 inspector.delegate_inspectable(&common.marks);
276 }
277
278 pub fn get_options_device<
280 'a,
281 BC: DatagramBindingsTypes,
282 CC: DatagramBoundStateContext<I, BC, S, WeakDeviceId = D>,
283 >(
284 &'a self,
285 core_ctx: &CC,
286 ) -> (&'a IpOptions<I, CC::WeakDeviceId, S>, &'a Option<CC::WeakDeviceId>) {
287 let device = match &self.inner {
288 SocketStateInner::Unbound(state) => {
289 let UnboundSocketState { device, sharing: _ } = state;
290 device
291 }
292 SocketStateInner::Bound(BoundSocketState { socket_type, original_bound_addr: _ }) => {
293 match socket_type {
294 BoundSocketStateType::Listener { state, sharing: _ } => {
295 let ListenerState { addr: ListenerAddr { device, ip: _ } } = state;
296 device
297 }
298 BoundSocketStateType::Connected { state, sharing: _ } => {
299 match core_ctx.dual_stack_context() {
300 MaybeDualStack::DualStack(dual_stack) => {
301 match dual_stack.ds_converter().convert(state) {
302 DualStackConnState::ThisStack(state) => state.get_device(),
303 DualStackConnState::OtherStack(state) => {
304 dual_stack.assert_dual_stack_enabled(&self.ip_options);
305 state.get_device()
306 }
307 }
308 }
309 MaybeDualStack::NotDualStack(not_dual_stack) => {
310 not_dual_stack.nds_converter().convert(state).get_device()
311 }
312 }
313 }
314 }
315 }
316 };
317 (&self.ip_options, device)
318 }
319
320 pub fn options(&self) -> &IpOptions<I, D, S> {
322 &self.ip_options
323 }
324
325 pub fn options_mut(&mut self) -> &mut IpOptions<I, D, S> {
327 &mut self.ip_options
328 }
329}
330
331#[derive(Derivative)]
333#[derivative(Debug(bound = "D: Debug"))]
334pub struct BoundSocketState<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
335 pub socket_type: BoundSocketStateType<I, D, S>,
338 pub original_bound_addr: Option<S::ListenerIpAddr<I>>,
343}
344
345#[derive(Derivative)]
347#[derivative(Debug(bound = "D: Debug"))]
348#[allow(missing_docs)]
349pub enum BoundSocketStateType<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
350 Listener { state: ListenerState<I, D, S>, sharing: S::SharingState },
351 Connected { state: S::ConnState<I, D>, sharing: S::SharingState },
352}
353
354#[derive(Derivative)]
355#[derivative(Debug(bound = ""), Default(bound = ""))]
356pub struct UnboundSocketState<D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
357 device: Option<D>,
358 sharing: S::SharingState,
359}
360
361#[derive(Derivative)]
363#[derivative(Debug(bound = ""))]
364pub struct ListenerState<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec + ?Sized> {
365 pub(crate) addr: ListenerAddr<S::ListenerIpAddr<I>, D>,
366}
367
368#[derive(Derivative)]
370#[derivative(Debug(bound = "D: Debug"))]
371pub struct ConnState<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec + ?Sized> {
372 pub(crate) socket: IpSock<WireI, D>,
373 pub(crate) shutdown: Shutdown,
374 pub(crate) addr: ConnAddr<
375 ConnIpAddr<
376 WireI::Addr,
377 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
378 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
379 >,
380 D,
381 >,
382 pub(crate) clear_device_on_disconnect: bool,
394
395 pub(crate) extra: S::ConnStateExtra,
400}
401
402impl<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> AsRef<Shutdown>
403 for ConnState<WireI, D, S>
404{
405 fn as_ref(&self) -> &Shutdown {
406 &self.shutdown
407 }
408}
409
410impl<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> AsMut<Shutdown>
411 for ConnState<WireI, D, S>
412{
413 fn as_mut(&mut self) -> &mut Shutdown {
414 &mut self.shutdown
415 }
416}
417
418impl<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> ConnState<WireI, D, S> {
419 pub fn should_receive(&self) -> bool {
421 let Self { shutdown, socket: _, clear_device_on_disconnect: _, addr: _, extra: _ } = self;
422 let Shutdown { receive, send: _ } = shutdown;
423 !*receive
424 }
425
426 pub fn addr(
428 &self,
429 ) -> &ConnAddr<
430 ConnIpAddr<
431 WireI::Addr,
432 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
433 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
434 >,
435 D,
436 > {
437 &self.addr
438 }
439
440 pub fn extra(&self) -> &S::ConnStateExtra {
442 &self.extra
443 }
444
445 fn get_device(&self) -> &Option<D> {
446 let Self { addr: ConnAddr { device, .. }, .. } = self;
447 device
448 }
449}
450
451#[derive(Derivative)]
453#[derivative(Debug(bound = ""))]
454pub enum DualStackConnState<
455 I: IpExt + DualStackIpExt,
456 D: WeakDeviceIdentifier,
457 S: DatagramSocketSpec + ?Sized,
458> {
459 ThisStack(ConnState<I, D, S>),
461 OtherStack(ConnState<I::OtherVersion, D, S>),
463}
464
465impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> AsRef<Shutdown>
466 for DualStackConnState<I, D, S>
467{
468 fn as_ref(&self) -> &Shutdown {
469 match self {
470 DualStackConnState::ThisStack(state) => state.as_ref(),
471 DualStackConnState::OtherStack(state) => state.as_ref(),
472 }
473 }
474}
475
476impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> AsMut<Shutdown>
477 for DualStackConnState<I, D, S>
478{
479 fn as_mut(&mut self) -> &mut Shutdown {
480 match self {
481 DualStackConnState::ThisStack(state) => state.as_mut(),
482 DualStackConnState::OtherStack(state) => state.as_mut(),
483 }
484 }
485}
486
487#[derive(Derivative, GenericOverIp)]
492#[generic_over_ip(I, Ip)]
493#[derivative(Clone(bound = ""), Debug, Default(bound = ""))]
494pub struct DatagramIpSpecificSocketOptions<I: IpExt, D: WeakDeviceIdentifier> {
495 pub hop_limits: SocketHopLimits<I>,
497 pub multicast_interface: Option<D>,
499
500 #[derivative(Default(value = "true"))]
503 pub multicast_loop: bool,
504
505 pub allow_broadcast: Option<I::BroadcastMarker>,
507
508 pub dscp_and_ecn: DscpAndEcn,
510}
511
512impl<I: IpExt, D: WeakDeviceIdentifier> SendOptions<I> for DatagramIpSpecificSocketOptions<I, D> {
513 fn hop_limit(&self, destination: &SpecifiedAddr<I::Addr>) -> Option<NonZeroU8> {
514 self.hop_limits.hop_limit_for_dst(destination)
515 }
516
517 fn multicast_loop(&self) -> bool {
518 self.multicast_loop
519 }
520
521 fn allow_broadcast(&self) -> Option<I::BroadcastMarker> {
522 self.allow_broadcast
523 }
524
525 fn dscp_and_ecn(&self) -> DscpAndEcn {
526 self.dscp_and_ecn
527 }
528
529 fn mtu(&self) -> Mtu {
530 Mtu::no_limit()
531 }
532}
533
534#[derive(Clone, Debug, Default)]
535struct DatagramIpAgnosticOptions {
536 transparent: bool,
537 marks: Marks,
538}
539
540impl<I: Ip> RouteResolutionOptions<I> for DatagramIpAgnosticOptions {
541 fn transparent(&self) -> bool {
542 self.transparent
543 }
544
545 fn marks(&self) -> &Marks {
546 &self.marks
547 }
548}
549
550struct IpOptionsRef<'a, I: IpExt, D: WeakDeviceIdentifier> {
553 ip_specific: &'a DatagramIpSpecificSocketOptions<I, D>,
554 agnostic: &'a DatagramIpAgnosticOptions,
555}
556
557impl<'a, I: IpExt, D: WeakDeviceIdentifier> OptionDelegationMarker for IpOptionsRef<'a, I, D> {}
558
559impl<'a, I: IpExt, D: WeakDeviceIdentifier> DelegatedSendOptions<I> for IpOptionsRef<'a, I, D> {
560 fn delegate(&self) -> &impl SendOptions<I> {
561 self.ip_specific
562 }
563}
564
565impl<'a, I: IpExt, D: WeakDeviceIdentifier> DelegatedRouteResolutionOptions<I>
566 for IpOptionsRef<'a, I, D>
567{
568 fn delegate(&self) -> &impl RouteResolutionOptions<I> {
569 self.agnostic
570 }
571}
572
573#[derive(Derivative, GenericOverIp)]
575#[generic_over_ip(I, Ip)]
576#[derivative(Clone(bound = ""), Debug, Default(bound = ""))]
577pub struct IpOptions<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec + ?Sized> {
578 multicast_memberships: MulticastMemberships<I::Addr, D>,
579 socket_options: DatagramIpSpecificSocketOptions<I, D>,
580 other_stack: S::OtherStackIpOptions<I, D>,
581 common: DatagramIpAgnosticOptions,
582}
583
584impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> IpOptions<I, D, S> {
585 pub fn other_stack(&self) -> &S::OtherStackIpOptions<I, D> {
587 &self.other_stack
588 }
589
590 pub fn transparent(&self) -> bool {
592 self.common.transparent
593 }
594
595 pub fn marks(&self) -> &Marks {
597 &self.common.marks
598 }
599
600 fn this_stack_options_ref(&self) -> IpOptionsRef<'_, I, D> {
601 IpOptionsRef { ip_specific: &self.socket_options, agnostic: &self.common }
602 }
603
604 fn other_stack_options_ref<
605 'a,
606 BC: DatagramBindingsTypes,
607 CC: DualStackDatagramBoundStateContext<I, BC, S, WeakDeviceId = D>,
608 >(
609 &'a self,
610 ctx: &CC,
611 ) -> IpOptionsRef<'_, I::OtherVersion, D> {
612 IpOptionsRef { ip_specific: ctx.to_other_socket_options(self), agnostic: &self.common }
613 }
614}
615
616#[derive(Clone, Debug, Derivative)]
617#[derivative(Default(bound = ""))]
618pub(crate) struct MulticastMemberships<A, D>(HashSet<(MulticastAddr<A>, D)>);
619
620#[cfg_attr(test, derive(Debug, PartialEq))]
621pub(crate) enum MulticastMembershipChange {
622 Join,
623 Leave,
624}
625
626impl<A: Eq + Hash, D: WeakDeviceIdentifier> MulticastMemberships<A, D> {
627 pub(crate) fn apply_membership_change(
628 &mut self,
629 address: MulticastAddr<A>,
630 device: &D,
631 want_membership: bool,
632 ) -> Option<MulticastMembershipChange> {
633 let device = device.clone();
634
635 let Self(map) = self;
636 if want_membership {
637 map.insert((address, device)).then_some(MulticastMembershipChange::Join)
638 } else {
639 map.remove(&(address, device)).then_some(MulticastMembershipChange::Leave)
640 }
641 }
642}
643
644impl<A: Eq + Hash, D: Eq + Hash> IntoIterator for MulticastMemberships<A, D> {
645 type Item = (MulticastAddr<A>, D);
646 type IntoIter = <HashSet<(MulticastAddr<A>, D)> as IntoIterator>::IntoIter;
647
648 fn into_iter(self) -> Self::IntoIter {
649 let Self(memberships) = self;
650 memberships.into_iter()
651 }
652}
653
654fn leave_all_joined_groups<A: IpAddress, BC, CC: MulticastMembershipHandler<A::Version, BC>>(
655 core_ctx: &mut CC,
656 bindings_ctx: &mut BC,
657 memberships: &MulticastMemberships<A, CC::WeakDeviceId>,
658) {
659 let MulticastMemberships(map) = memberships;
660 for (addr, device) in map.iter() {
661 let Some(device) = device.upgrade() else {
662 continue;
663 };
664 core_ctx.leave_multicast_group(bindings_ctx, &device, addr.clone())
665 }
666}
667
668#[derive(Hash)]
670pub struct DatagramFlowId<A: IpAddress, RI> {
671 pub local_ip: SocketIpAddr<A>,
673 pub remote_ip: SocketIpAddr<A>,
675 pub remote_id: RI,
677}
678
679pub trait DatagramStateContext<I: IpExt, BC: DatagramBindingsTypes, S: DatagramSocketSpec>:
681 DeviceIdContext<AnyDevice>
682{
683 type SocketsStateCtx<'a>: DatagramBoundStateContext<I, BC, S>
685 + DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
686
687 fn with_all_sockets_mut<O, F: FnOnce(&mut DatagramSocketSet<I, Self::WeakDeviceId, S>) -> O>(
690 &mut self,
691 cb: F,
692 ) -> O;
693
694 fn with_all_sockets<O, F: FnOnce(&DatagramSocketSet<I, Self::WeakDeviceId, S>) -> O>(
697 &mut self,
698 cb: F,
699 ) -> O;
700
701 fn with_socket_state<
704 O,
705 F: FnOnce(&mut Self::SocketsStateCtx<'_>, &SocketState<I, Self::WeakDeviceId, S>) -> O,
706 >(
707 &mut self,
708 id: &S::SocketId<I, Self::WeakDeviceId>,
709 cb: F,
710 ) -> O;
711
712 fn with_socket_state_mut<
714 O,
715 F: FnOnce(&mut Self::SocketsStateCtx<'_>, &mut SocketState<I, Self::WeakDeviceId, S>) -> O,
716 >(
717 &mut self,
718 id: &S::SocketId<I, Self::WeakDeviceId>,
719 cb: F,
720 ) -> O;
721
722 fn for_each_socket<
724 F: FnMut(
725 &mut Self::SocketsStateCtx<'_>,
726 &S::SocketId<I, Self::WeakDeviceId>,
727 &SocketState<I, Self::WeakDeviceId, S>,
728 ),
729 >(
730 &mut self,
731 cb: F,
732 );
733}
734
735pub(crate) type BoundSocketsFromSpec<I, CC, S> = BoundSockets<
737 I,
738 <CC as DeviceIdContext<AnyDevice>>::WeakDeviceId,
739 <S as DatagramSocketSpec>::AddrSpec,
740 <S as DatagramSocketSpec>::SocketMapSpec<I, <CC as DeviceIdContext<AnyDevice>>::WeakDeviceId>,
741>;
742
743pub trait DatagramBindingsTypes: TxMetadataBindingsTypes {}
745impl<BT> DatagramBindingsTypes for BT where BT: TxMetadataBindingsTypes {}
746
747pub trait DatagramBoundStateContext<
749 I: IpExt + DualStackIpExt,
750 BC: DatagramBindingsTypes,
751 S: DatagramSocketSpec,
752>: DeviceIdContext<AnyDevice>
753{
754 type IpSocketsCtx<'a>: TransportIpContext<I, BC>
756 + CoreTxMetadataContext<TxMetadata<I, Self::WeakDeviceId, S>, BC>
757 + MulticastMembershipHandler<I, BC>
758 + DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>;
759
760 type DualStackContext: DualStackDatagramBoundStateContext<
770 I,
771 BC,
772 S,
773 DeviceId = Self::DeviceId,
774 WeakDeviceId = Self::WeakDeviceId,
775 >;
776
777 type NonDualStackContext: NonDualStackDatagramBoundStateContext<
783 I,
784 BC,
785 S,
786 DeviceId = Self::DeviceId,
787 WeakDeviceId = Self::WeakDeviceId,
788 >;
789
790 fn with_bound_sockets<
792 O,
793 F: FnOnce(&mut Self::IpSocketsCtx<'_>, &BoundSocketsFromSpec<I, Self, S>) -> O,
794 >(
795 &mut self,
796 cb: F,
797 ) -> O;
798
799 fn with_bound_sockets_mut<
801 O,
802 F: FnOnce(&mut Self::IpSocketsCtx<'_>, &mut BoundSocketsFromSpec<I, Self, S>) -> O,
803 >(
804 &mut self,
805 cb: F,
806 ) -> O;
807
808 fn dual_stack_context(
817 &self,
818 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext>;
819
820 fn dual_stack_context_mut(
822 &mut self,
823 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext>;
824
825 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
827 &mut self,
828 cb: F,
829 ) -> O;
830}
831
832pub trait DualStackConverter<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>:
835 'static
836 + OwnedOrRefsBidirectionalConverter<
837 S::ListenerIpAddr<I>,
838 DualStackListenerIpAddr<I::Addr, <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
839 >
840 + OwnedOrRefsBidirectionalConverter<
841 S::ConnIpAddr<I>,
842 DualStackConnIpAddr<
843 I::Addr,
844 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
845 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
846 >,
847 >
848 + OwnedOrRefsBidirectionalConverter<S::ConnState<I, D>, DualStackConnState<I, D, S>>
849{
850}
851
852impl<I, D, S, O> DualStackConverter<I, D, S> for O
853where
854 I: IpExt,
855 D: WeakDeviceIdentifier,
856 S: DatagramSocketSpec,
857 O: 'static
858 + OwnedOrRefsBidirectionalConverter<
859 S::ListenerIpAddr<I>,
860 DualStackListenerIpAddr<I::Addr, <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
861 >
862 + OwnedOrRefsBidirectionalConverter<
863 S::ConnIpAddr<I>,
864 DualStackConnIpAddr<
865 I::Addr,
866 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
867 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
868 >,
869 >
870 + OwnedOrRefsBidirectionalConverter<S::ConnState<I, D>, DualStackConnState<I, D, S>>,
871{
872}
873
874pub trait DualStackDatagramBoundStateContext<
876 I: IpExt,
877 BC: DatagramBindingsTypes,
878 S: DatagramSocketSpec,
879>: DeviceIdContext<AnyDevice>
880{
881 type IpSocketsCtx<'a>: TransportIpContext<I, BC>
883 + CoreTxMetadataContext<TxMetadata<I, Self::WeakDeviceId, S>, BC>
884 + DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
885 + TransportIpContext<I::OtherVersion, BC>
887 + CoreTxMetadataContext<TxMetadata<I::OtherVersion, Self::WeakDeviceId, S>, BC>;
888
889 fn dual_stack_enabled(&self, ip_options: &IpOptions<I, Self::WeakDeviceId, S>) -> bool;
891
892 fn to_other_socket_options<'a>(
894 &self,
895 state: &'a IpOptions<I, Self::WeakDeviceId, S>,
896 ) -> &'a DatagramIpSpecificSocketOptions<I::OtherVersion, Self::WeakDeviceId>;
897
898 fn assert_dual_stack_enabled(&self, ip_options: &IpOptions<I, Self::WeakDeviceId, S>) {
902 debug_assert!(self.dual_stack_enabled(ip_options), "socket must be dual-stack enabled")
903 }
904
905 fn ds_converter(&self) -> impl DualStackConverter<I, Self::WeakDeviceId, S>;
908
909 fn to_other_bound_socket_id(
914 &self,
915 id: &S::SocketId<I, Self::WeakDeviceId>,
916 ) -> <S::SocketMapSpec<I::OtherVersion, Self::WeakDeviceId> as DatagramSocketMapSpec<
917 I::OtherVersion,
918 Self::WeakDeviceId,
919 S::AddrSpec,
920 >>::BoundSocketId;
921
922 fn with_both_bound_sockets_mut<
925 O,
926 F: FnOnce(
927 &mut Self::IpSocketsCtx<'_>,
928 &mut BoundSocketsFromSpec<I, Self, S>,
929 &mut BoundSocketsFromSpec<I::OtherVersion, Self, S>,
930 ) -> O,
931 >(
932 &mut self,
933 cb: F,
934 ) -> O;
935
936 fn with_other_bound_sockets_mut<
939 O,
940 F: FnOnce(
941 &mut Self::IpSocketsCtx<'_>,
942 &mut BoundSocketsFromSpec<I::OtherVersion, Self, S>,
943 ) -> O,
944 >(
945 &mut self,
946 cb: F,
947 ) -> O;
948
949 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
951 &mut self,
952 cb: F,
953 ) -> O;
954}
955
956pub trait NonDualStackConverter<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>:
959 'static
960 + OwnedOrRefsBidirectionalConverter<
961 S::ListenerIpAddr<I>,
962 ListenerIpAddr<I::Addr, <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
963 >
964 + OwnedOrRefsBidirectionalConverter<
965 S::ConnIpAddr<I>,
966 ConnIpAddr<
967 I::Addr,
968 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
969 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
970 >,
971 >
972 + OwnedOrRefsBidirectionalConverter<S::ConnState<I, D>, ConnState<I, D, S>>
973{
974}
975
976impl<I, D, S, O> NonDualStackConverter<I, D, S> for O
977where
978 I: IpExt,
979 D: WeakDeviceIdentifier,
980 S: DatagramSocketSpec,
981 O: 'static
982 + OwnedOrRefsBidirectionalConverter<
983 S::ListenerIpAddr<I>,
984 ListenerIpAddr<I::Addr, <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
985 >
986 + OwnedOrRefsBidirectionalConverter<
987 S::ConnIpAddr<I>,
988 ConnIpAddr<
989 I::Addr,
990 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
991 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
992 >,
993 >
994 + OwnedOrRefsBidirectionalConverter<S::ConnState<I, D>, ConnState<I, D, S>>,
995{
996}
997
998pub trait NonDualStackDatagramBoundStateContext<I: IpExt, BC, S: DatagramSocketSpec>:
1000 DeviceIdContext<AnyDevice>
1001{
1002 fn nds_converter(&self) -> impl NonDualStackConverter<I, Self::WeakDeviceId, S>;
1005}
1006
1007pub trait DatagramBindingsContext: RngContext + ReferenceNotifiers + DatagramBindingsTypes {}
1009impl<BC> DatagramBindingsContext for BC where
1010 BC: RngContext + ReferenceNotifiers + DatagramBindingsTypes
1011{
1012}
1013
1014pub trait DatagramSocketMapSpec<I: Ip, D: DeviceIdentifier, A: SocketMapAddrSpec>:
1019 SocketMapStateSpec<ListenerId = Self::BoundSocketId, ConnId = Self::BoundSocketId>
1020 + SocketMapConflictPolicy<
1021 ListenerAddr<ListenerIpAddr<I::Addr, A::LocalIdentifier>, D>,
1022 <Self as SocketMapStateSpec>::ListenerSharingState,
1023 I,
1024 D,
1025 A,
1026 > + SocketMapConflictPolicy<
1027 ConnAddr<ConnIpAddr<I::Addr, A::LocalIdentifier, A::RemoteIdentifier>, D>,
1028 <Self as SocketMapStateSpec>::ConnSharingState,
1029 I,
1030 D,
1031 A,
1032 >
1033{
1034 type BoundSocketId: Clone + Debug;
1045}
1046
1047pub trait DualStackIpExt:
1052 DualStackBaseIpExt
1053 + socket::DualStackIpExt<OtherVersion: DualStackBaseIpExt + FilterIpExt + IpLayerIpExt>
1054{
1055}
1056
1057impl<I> DualStackIpExt for I where
1058 I: DualStackBaseIpExt
1059 + socket::DualStackIpExt<OtherVersion: DualStackBaseIpExt + FilterIpExt + IpLayerIpExt>
1060{
1061}
1062
1063pub trait DualStackBaseIpExt:
1070 socket::DualStackIpExt + SocketIpExt + netstack3_base::IpExt + FilterIpExt + IpLayerIpExt
1071{
1072 type DualStackBoundSocketId<D: WeakDeviceIdentifier, S: DatagramSocketSpec>: Clone + Debug + Eq;
1079
1080 type OtherStackIpOptions<State: Clone + Debug + Default + Send + Sync>: Clone
1087 + Debug
1088 + Default
1089 + Send
1090 + Sync;
1091
1092 type DualStackListenerIpAddr<LocalIdentifier: Clone + Debug + Send + Sync + Into<NonZeroU16>>: Clone
1094 + Debug
1095 + Send
1096 + Sync
1097 + Into<(Option<SpecifiedAddr<Self::Addr>>, NonZeroU16)>;
1098
1099 type DualStackConnIpAddr<S: DatagramSocketSpec>: Clone
1101 + Debug
1102 + Into<ConnInfoAddr<Self::Addr, <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier>>;
1103
1104 type DualStackConnState<D: WeakDeviceIdentifier, S: DatagramSocketSpec>: Debug + Send + Sync
1106 where
1107 Self::OtherVersion: DualStackBaseIpExt;
1108
1109 fn into_dual_stack_bound_socket_id<D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1115 id: S::SocketId<Self, D>,
1116 ) -> Self::DualStackBoundSocketId<D, S>
1117 where
1118 Self: IpExt;
1119
1120 fn conn_addr_from_state<D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1122 state: &Self::DualStackConnState<D, S>,
1123 ) -> ConnAddr<Self::DualStackConnIpAddr<S>, D>
1124 where
1125 Self::OtherVersion: DualStackBaseIpExt;
1126}
1127
1128#[derive(Derivative)]
1130#[derivative(
1131 Clone(bound = ""),
1132 Debug(bound = ""),
1133 Eq(bound = "S::SocketId<Ipv4, D>: Eq, S::SocketId<Ipv6, D>: Eq"),
1134 PartialEq(bound = "S::SocketId<Ipv4, D>: PartialEq, S::SocketId<Ipv6, D>: PartialEq")
1135)]
1136#[allow(missing_docs)]
1137pub enum EitherIpSocket<D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
1138 V4(S::SocketId<Ipv4, D>),
1139 V6(S::SocketId<Ipv6, D>),
1140}
1141
1142impl<CC, D, S> SocketMetadata<CC> for EitherIpSocket<D, S>
1143where
1144 D: WeakDeviceIdentifier,
1145 S: DatagramSocketSpec,
1146 S::SocketId<Ipv4, D>: SocketMetadata<CC>,
1147 S::SocketId<Ipv6, D>: SocketMetadata<CC>,
1148{
1149 fn socket_cookie(&self, core_ctx: &mut CC) -> SocketCookie {
1150 match self {
1151 EitherIpSocket::V4(id) => id.socket_cookie(core_ctx),
1152 EitherIpSocket::V6(id) => id.socket_cookie(core_ctx),
1153 }
1154 }
1155 fn marks(&self, core_ctx: &mut CC) -> Marks {
1156 match self {
1157 EitherIpSocket::V4(id) => id.marks(core_ctx),
1158 EitherIpSocket::V6(id) => id.marks(core_ctx),
1159 }
1160 }
1161}
1162
1163impl DualStackBaseIpExt for Ipv4 {
1164 type DualStackBoundSocketId<D: WeakDeviceIdentifier, S: DatagramSocketSpec> =
1166 EitherIpSocket<D, S>;
1167 type OtherStackIpOptions<State: Clone + Debug + Default + Send + Sync> = ();
1168 type DualStackListenerIpAddr<LocalIdentifier: Clone + Debug + Send + Sync + Into<NonZeroU16>> =
1170 ListenerIpAddr<Self::Addr, LocalIdentifier>;
1171 type DualStackConnIpAddr<S: DatagramSocketSpec> = ConnIpAddr<
1173 Self::Addr,
1174 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1175 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
1176 >;
1177 type DualStackConnState<D: WeakDeviceIdentifier, S: DatagramSocketSpec> = ConnState<Self, D, S>;
1179
1180 fn into_dual_stack_bound_socket_id<D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1181 id: S::SocketId<Self, D>,
1182 ) -> Self::DualStackBoundSocketId<D, S> {
1183 EitherIpSocket::V4(id)
1184 }
1185
1186 fn conn_addr_from_state<D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1187 state: &Self::DualStackConnState<D, S>,
1188 ) -> ConnAddr<Self::DualStackConnIpAddr<S>, D> {
1189 let ConnState { socket: _, shutdown: _, addr, clear_device_on_disconnect: _, extra: _ } =
1190 state;
1191 addr.clone()
1192 }
1193}
1194
1195impl DualStackBaseIpExt for Ipv6 {
1196 type DualStackBoundSocketId<D: WeakDeviceIdentifier, S: DatagramSocketSpec> =
1198 S::SocketId<Self, D>;
1199 type OtherStackIpOptions<State: Clone + Debug + Default + Send + Sync> = State;
1200 type DualStackListenerIpAddr<LocalIdentifier: Clone + Debug + Send + Sync + Into<NonZeroU16>> =
1203 DualStackListenerIpAddr<Self::Addr, LocalIdentifier>;
1204 type DualStackConnIpAddr<S: DatagramSocketSpec> = DualStackConnIpAddr<
1207 Self::Addr,
1208 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1209 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
1210 >;
1211 type DualStackConnState<D: WeakDeviceIdentifier, S: DatagramSocketSpec> =
1214 DualStackConnState<Self, D, S>;
1215
1216 fn into_dual_stack_bound_socket_id<D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1217 id: S::SocketId<Self, D>,
1218 ) -> Self::DualStackBoundSocketId<D, S> {
1219 id
1220 }
1221
1222 fn conn_addr_from_state<D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1223 state: &Self::DualStackConnState<D, S>,
1224 ) -> ConnAddr<Self::DualStackConnIpAddr<S>, D> {
1225 match state {
1226 DualStackConnState::ThisStack(state) => {
1227 let ConnState { addr, .. } = state;
1228 let ConnAddr { ip, device } = addr.clone();
1229 ConnAddr { ip: DualStackConnIpAddr::ThisStack(ip), device }
1230 }
1231 DualStackConnState::OtherStack(state) => {
1232 let ConnState {
1233 socket: _,
1234 shutdown: _,
1235 addr,
1236 clear_device_on_disconnect: _,
1237 extra: _,
1238 } = state;
1239 let ConnAddr { ip, device } = addr.clone();
1240 ConnAddr { ip: DualStackConnIpAddr::OtherStack(ip), device }
1241 }
1242 }
1243 }
1244}
1245
1246#[derive(GenericOverIp)]
1247#[generic_over_ip(I, Ip)]
1248pub struct WrapOtherStackIpOptions<
1250 'a,
1251 I: DualStackIpExt,
1252 S: 'a + Clone + Debug + Default + Send + Sync,
1253>(pub &'a I::OtherStackIpOptions<S>);
1254
1255#[derive(GenericOverIp)]
1256#[generic_over_ip(I, Ip)]
1257pub struct WrapOtherStackIpOptionsMut<
1259 'a,
1260 I: DualStackIpExt,
1261 S: 'a + Clone + Debug + Default + Send + Sync,
1262>(pub &'a mut I::OtherStackIpOptions<S>);
1263
1264pub trait DatagramSocketSpec: Sized + 'static {
1268 const NAME: &'static str;
1270
1271 type AddrSpec: SocketMapAddrSpec;
1276
1277 type SocketId<I: IpExt, D: WeakDeviceIdentifier>: Clone
1283 + Debug
1284 + Eq
1285 + Send
1286 + Borrow<StrongRc<I, D, Self>>
1287 + From<StrongRc<I, D, Self>>;
1288
1289 type WeakSocketId<I: IpExt, D: WeakDeviceIdentifier>: Clone + Debug + Eq + Send;
1291
1292 type OtherStackIpOptions<I: IpExt, D: WeakDeviceIdentifier>: Clone
1294 + Debug
1295 + Default
1296 + Send
1297 + Sync;
1298
1299 type ListenerIpAddr<I: IpExt>: Clone
1307 + Debug
1308 + Into<(Option<SpecifiedAddr<I::Addr>>, NonZeroU16)>
1309 + Send
1310 + Sync
1311 + 'static;
1312
1313 type SharingState: Clone + Debug + Default + Send + Sync + 'static;
1320
1321 type ConnIpAddr<I: IpExt>: Clone
1329 + Debug
1330 + Into<ConnInfoAddr<I::Addr, <Self::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier>>;
1331
1332 type ConnState<I: IpExt, D: WeakDeviceIdentifier>: Debug + Send + Sync;
1339
1340 type ConnStateExtra: Debug + Send + Sync;
1349
1350 type SocketMapSpec<I: IpExt + DualStackIpExt, D: WeakDeviceIdentifier>: DatagramSocketMapSpec<
1355 I,
1356 D,
1357 Self::AddrSpec,
1358 ListenerSharingState = Self::SharingState,
1359 ConnSharingState = Self::SharingState,
1360 >;
1361
1362 type ExternalData<I: Ip>: Debug + Send + Sync + 'static;
1367
1368 type Settings: AsRef<DatagramSettings> + Default;
1370
1371 type Counters<I: Ip>: Debug + Default + Send + Sync + 'static;
1373
1374 type SocketWritableListener: SocketWritableListener + Debug + Send + Sync + 'static;
1376
1377 const FIXED_HEADER_SIZE: usize;
1385
1386 fn ip_proto<I: IpProtoExt>() -> I::Proto;
1388
1389 fn make_bound_socket_map_id<I: IpExt, D: WeakDeviceIdentifier>(
1395 s: &Self::SocketId<I, D>,
1396 ) -> <Self::SocketMapSpec<I, D> as DatagramSocketMapSpec<I, D, Self::AddrSpec>>::BoundSocketId;
1397
1398 type Serializer<I: IpExt, B: BufferMut>: TransportPacketSerializer<I, Buffer = B>;
1401 type SerializeError: Error;
1405
1406 fn make_packet<I: IpExt, B: BufferMut>(
1408 body: B,
1409 addr: &ConnIpAddr<
1410 I::Addr,
1411 <Self::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1412 <Self::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
1413 >,
1414 ) -> Result<Self::Serializer<I, B>, Self::SerializeError>;
1415
1416 fn try_alloc_listen_identifier<I: IpExt, D: WeakDeviceIdentifier>(
1420 rng: &mut impl RngContext,
1421 is_available: impl Fn(
1422 <Self::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1423 ) -> Result<(), InUseError>,
1424 ) -> Option<<Self::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>;
1425
1426 fn conn_info_from_state<I: IpExt, D: WeakDeviceIdentifier>(
1428 state: &Self::ConnState<I, D>,
1429 ) -> ConnInfo<I::Addr, D>;
1430
1431 fn try_alloc_local_id<I: IpExt, D: WeakDeviceIdentifier, BC: RngContext>(
1433 bound: &BoundSocketMap<I, D, Self::AddrSpec, Self::SocketMapSpec<I, D>>,
1434 bindings_ctx: &mut BC,
1435 flow: DatagramFlowId<I::Addr, <Self::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier>,
1436 ) -> Option<<Self::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>;
1437
1438 fn downgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
1441 id: &Self::SocketId<I, D>,
1442 ) -> Self::WeakSocketId<I, D>;
1443
1444 fn upgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
1447 id: &Self::WeakSocketId<I, D>,
1448 ) -> Option<Self::SocketId<I, D>>;
1449}
1450
1451pub struct InUseError;
1453
1454pub fn create_primary_id<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1456 external_data: S::ExternalData<I>,
1457 writable_listener: S::SocketWritableListener,
1458 settings: &DatagramSettings,
1459) -> PrimaryRc<I, D, S> {
1460 PrimaryRc::new(ReferenceState {
1461 state: RwLock::new(SocketState {
1462 inner: SocketStateInner::Unbound(UnboundSocketState::default()),
1463 ip_options: Default::default(),
1464 }),
1465 external_data,
1466 send_buffer: SendBufferTracking::new(writable_listener, settings),
1467 counters: Default::default(),
1468 })
1469}
1470
1471#[derive(GenericOverIp, Debug, Eq, PartialEq)]
1473#[generic_over_ip(A, IpAddress)]
1474pub struct ListenerInfo<A: IpAddress, D> {
1475 pub local_ip: Option<StrictlyZonedAddr<A, SpecifiedAddr<A>, D>>,
1478 pub local_identifier: NonZeroU16,
1480}
1481
1482impl<A: IpAddress, LA: Into<(Option<SpecifiedAddr<A>>, NonZeroU16)>, D> From<ListenerAddr<LA, D>>
1483 for ListenerInfo<A, D>
1484{
1485 fn from(ListenerAddr { ip, device }: ListenerAddr<LA, D>) -> Self {
1486 let (addr, local_identifier) = ip.into();
1487 Self {
1488 local_ip: addr.map(|addr| {
1489 StrictlyZonedAddr::new_with_zone(addr, || {
1490 device.expect("device must be bound for addresses that require zones")
1493 })
1494 }),
1495 local_identifier,
1496 }
1497 }
1498}
1499
1500impl<A: IpAddress, D> From<NonZeroU16> for ListenerInfo<A, D> {
1501 fn from(local_identifier: NonZeroU16) -> Self {
1502 Self { local_ip: None, local_identifier }
1503 }
1504}
1505
1506#[derive(Debug, GenericOverIp, PartialEq)]
1508#[generic_over_ip(A, IpAddress)]
1509pub struct ConnInfo<A: IpAddress, D> {
1510 pub local_ip: StrictlyZonedAddr<A, SpecifiedAddr<A>, D>,
1512 pub local_identifier: NonZeroU16,
1514 pub remote_ip: StrictlyZonedAddr<A, SpecifiedAddr<A>, D>,
1516 pub remote_identifier: u16,
1518}
1519
1520impl<A: IpAddress, D> ConnInfo<A, D> {
1521 pub fn new(
1523 local_ip: SpecifiedAddr<A>,
1524 local_identifier: NonZeroU16,
1525 remote_ip: SpecifiedAddr<A>,
1526 remote_identifier: u16,
1527 mut get_zone: impl FnMut() -> D,
1528 ) -> Self {
1529 Self {
1530 local_ip: StrictlyZonedAddr::new_with_zone(local_ip, &mut get_zone),
1531 local_identifier,
1532 remote_ip: StrictlyZonedAddr::new_with_zone(remote_ip, &mut get_zone),
1533 remote_identifier,
1534 }
1535 }
1536}
1537
1538#[derive(GenericOverIp, Debug, PartialEq)]
1540#[generic_over_ip(A, IpAddress)]
1541pub enum SocketInfo<A: IpAddress, D> {
1542 Unbound,
1544 Listener(ListenerInfo<A, D>),
1546 Connected(ConnInfo<A, D>),
1548}
1549
1550enum Remove<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
1557 Listener {
1558 concrete_addr: ListenerAddr<
1560 ListenerIpAddr<WireI::Addr, <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
1561 D,
1562 >,
1563 sharing: S::SharingState,
1564 socket_id:
1565 <S::SocketMapSpec<WireI, D> as DatagramSocketMapSpec<WireI, D, S::AddrSpec>>::BoundSocketId,
1566 },
1567 Connected {
1568 concrete_addr: ConnAddr<
1570 ConnIpAddr<
1571 WireI::Addr,
1572 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1573 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
1574 >,
1575 D,
1576 >,
1577 sharing: S::SharingState,
1578 socket_id:
1579 <S::SocketMapSpec<WireI, D> as DatagramSocketMapSpec<WireI, D, S::AddrSpec>>::BoundSocketId,
1580 },
1581}
1582
1583struct RemoveOperation<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1588 Remove<WireI, D, S>,
1589);
1590
1591impl<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> RemoveOperation<WireI, D, S> {
1592 fn apply(
1599 self,
1600 sockets: &mut BoundSocketMap<WireI, D, S::AddrSpec, S::SocketMapSpec<WireI, D>>,
1601 ) -> RemoveInfo<WireI, D, S> {
1602 let RemoveOperation(remove) = self;
1603 match &remove {
1604 Remove::Listener { concrete_addr, sharing: _, socket_id } => {
1605 let ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device } =
1606 concrete_addr;
1607 BoundStateHandler::<_, S, _>::remove_listener(
1608 sockets,
1609 addr,
1610 *identifier,
1611 device,
1612 socket_id,
1613 );
1614 }
1615 Remove::Connected { concrete_addr, sharing: _, socket_id } => {
1616 sockets
1617 .conns_mut()
1618 .remove(socket_id, concrete_addr)
1619 .expect("UDP connection not found");
1620 }
1621 }
1622 RemoveInfo(remove)
1623 }
1624}
1625
1626impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> RemoveOperation<I, D, S> {
1629 fn new_from_state<BC, CC: NonDualStackDatagramBoundStateContext<I, BC, S, WeakDeviceId = D>>(
1631 core_ctx: &mut CC,
1632 socket_id: &S::SocketId<I, D>,
1633 state: &BoundSocketState<I, D, S>,
1634 ) -> Self {
1635 let BoundSocketState { socket_type: state, original_bound_addr: _ } = state;
1636 RemoveOperation(match state {
1637 BoundSocketStateType::Listener {
1638 state: ListenerState { addr: ListenerAddr { ip, device } },
1639 sharing,
1640 } => Remove::Listener {
1641 concrete_addr: ListenerAddr {
1642 ip: core_ctx.nds_converter().convert(ip.clone()),
1643 device: device.clone(),
1644 },
1645 sharing: sharing.clone(),
1646 socket_id: S::make_bound_socket_map_id(socket_id),
1647 },
1648 BoundSocketStateType::Connected { state, sharing } => {
1649 let ConnState {
1650 addr,
1651 socket: _,
1652 clear_device_on_disconnect: _,
1653 shutdown: _,
1654 extra: _,
1655 } = core_ctx.nds_converter().convert(state);
1656 Remove::Connected {
1657 concrete_addr: addr.clone(),
1658 sharing: sharing.clone(),
1659 socket_id: S::make_bound_socket_map_id(socket_id),
1660 }
1661 }
1662 })
1663 }
1664}
1665
1666struct RemoveInfo<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1671 Remove<WireI, D, S>,
1672);
1673
1674impl<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> RemoveInfo<WireI, D, S> {
1675 fn into_sharing_and_device(self) -> (S::SharingState, Option<D>) {
1676 let RemoveInfo(remove) = self;
1677 match remove {
1678 Remove::Listener {
1679 concrete_addr: ListenerAddr { ip: _, device },
1680 sharing,
1681 socket_id: _,
1682 } => (sharing, device),
1683 Remove::Connected {
1684 concrete_addr: ConnAddr { ip: _, device },
1685 sharing,
1686 socket_id: _,
1687 } => (sharing, device),
1688 }
1689 }
1690
1691 fn reinsert(
1699 self,
1700 sockets: &mut BoundSocketMap<WireI, D, S::AddrSpec, S::SocketMapSpec<WireI, D>>,
1701 ) {
1702 let RemoveInfo(remove) = self;
1703 match remove {
1704 Remove::Listener {
1705 concrete_addr: ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device },
1706 sharing,
1707 socket_id,
1708 } => {
1709 BoundStateHandler::<_, S, _>::try_insert_listener(
1710 sockets, addr, identifier, device, sharing, socket_id,
1711 )
1712 .expect("reinserting just-removed listener failed");
1713 }
1714 Remove::Connected { concrete_addr, sharing, socket_id } => {
1715 let _entry = sockets
1716 .conns_mut()
1717 .try_insert(concrete_addr, sharing, socket_id)
1718 .expect("reinserting just-removed connected failed");
1719 }
1720 }
1721 }
1722}
1723
1724type SingleStackRemoveOperation<I, D, S> = RemoveOperation<I, D, S>;
1726
1727type SingleStackRemoveInfo<I, D, S> = RemoveInfo<I, D, S>;
1729
1730enum DualStackRemove<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
1732 CurrentStack(Remove<I, D, S>),
1733 OtherStack(Remove<I::OtherVersion, D, S>),
1734 ListenerBothStacks {
1735 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1736 device: Option<D>,
1737 sharing: S::SharingState,
1738 socket_ids: PairedBoundSocketIds<I, D, S>,
1739 },
1740}
1741
1742struct DualStackRemoveOperation<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1744 DualStackRemove<I, D, S>,
1745);
1746
1747impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> DualStackRemoveOperation<I, D, S> {
1748 fn new_from_state<
1750 BC: DatagramBindingsTypes,
1751 CC: DualStackDatagramBoundStateContext<I, BC, S, WeakDeviceId = D>,
1752 >(
1753 core_ctx: &mut CC,
1754 socket_id: &S::SocketId<I, D>,
1755 ip_options: &IpOptions<I, D, S>,
1756 state: &BoundSocketState<I, D, S>,
1757 ) -> Self {
1758 let BoundSocketState { socket_type: state, original_bound_addr: _ } = state;
1759 DualStackRemoveOperation(match state {
1760 BoundSocketStateType::Listener { state: ListenerState { addr }, sharing } => {
1761 let ListenerAddr { ip, device } = addr.clone();
1762 match (core_ctx.ds_converter().convert(ip), core_ctx.dual_stack_enabled(ip_options))
1763 {
1764 (DualStackListenerIpAddr::BothStacks(identifier), true) => {
1766 DualStackRemove::ListenerBothStacks {
1767 identifier: identifier.clone(),
1768 device,
1769 sharing: sharing.clone(),
1770 socket_ids: PairedBoundSocketIds {
1771 this: S::make_bound_socket_map_id(socket_id),
1772 other: core_ctx.to_other_bound_socket_id(socket_id),
1773 },
1774 }
1775 }
1776 (DualStackListenerIpAddr::ThisStack(addr), true | false) => {
1778 DualStackRemove::CurrentStack(Remove::Listener {
1779 concrete_addr: ListenerAddr { ip: addr, device },
1780 sharing: sharing.clone(),
1781 socket_id: S::make_bound_socket_map_id(socket_id),
1782 })
1783 }
1784 (DualStackListenerIpAddr::OtherStack(addr), true) => {
1786 DualStackRemove::OtherStack(Remove::Listener {
1787 concrete_addr: ListenerAddr { ip: addr, device },
1788 sharing: sharing.clone(),
1789 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
1790 })
1791 }
1792 (DualStackListenerIpAddr::OtherStack(_), false)
1793 | (DualStackListenerIpAddr::BothStacks(_), false) => {
1794 unreachable!("dual-stack disabled socket cannot use the other stack")
1795 }
1796 }
1797 }
1798 BoundSocketStateType::Connected { state, sharing } => {
1799 match core_ctx.ds_converter().convert(state) {
1800 DualStackConnState::ThisStack(state) => {
1801 let ConnState {
1802 addr,
1803 socket: _,
1804 clear_device_on_disconnect: _,
1805 shutdown: _,
1806 extra: _,
1807 } = state;
1808 DualStackRemove::CurrentStack(Remove::Connected {
1809 concrete_addr: addr.clone(),
1810 sharing: sharing.clone(),
1811 socket_id: S::make_bound_socket_map_id(socket_id),
1812 })
1813 }
1814 DualStackConnState::OtherStack(state) => {
1815 core_ctx.assert_dual_stack_enabled(&ip_options);
1816 let ConnState {
1817 addr,
1818 socket: _,
1819 clear_device_on_disconnect: _,
1820 shutdown: _,
1821 extra: _,
1822 } = state;
1823 DualStackRemove::OtherStack(Remove::Connected {
1824 concrete_addr: addr.clone(),
1825 sharing: sharing.clone(),
1826 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
1827 })
1828 }
1829 }
1830 }
1831 })
1832 }
1833
1834 fn apply(
1841 self,
1842 sockets: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
1843 other_sockets: &mut BoundSocketMap<
1844 I::OtherVersion,
1845 D,
1846 S::AddrSpec,
1847 S::SocketMapSpec<I::OtherVersion, D>,
1848 >,
1849 ) -> DualStackRemoveInfo<I, D, S> {
1850 let DualStackRemoveOperation(dual_stack_remove) = self;
1851 match dual_stack_remove {
1852 DualStackRemove::CurrentStack(remove) => {
1853 let RemoveInfo(remove) = RemoveOperation(remove).apply(sockets);
1854 DualStackRemoveInfo(DualStackRemove::CurrentStack(remove))
1855 }
1856 DualStackRemove::OtherStack(remove) => {
1857 let RemoveInfo(remove) = RemoveOperation(remove).apply(other_sockets);
1858 DualStackRemoveInfo(DualStackRemove::OtherStack(remove))
1859 }
1860 DualStackRemove::ListenerBothStacks { identifier, device, sharing, socket_ids } => {
1861 PairedSocketMapMut::<_, _, S> { bound: sockets, other_bound: other_sockets }
1862 .remove_listener(&DualStackUnspecifiedAddr, identifier, &device, &socket_ids);
1863 DualStackRemoveInfo(DualStackRemove::ListenerBothStacks {
1864 identifier,
1865 device,
1866 sharing,
1867 socket_ids,
1868 })
1869 }
1870 }
1871 }
1872}
1873
1874struct DualStackRemoveInfo<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1876 DualStackRemove<I, D, S>,
1877);
1878
1879impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> DualStackRemoveInfo<I, D, S> {
1880 fn into_sharing_and_device(self) -> (S::SharingState, Option<D>) {
1881 let DualStackRemoveInfo(dual_stack_remove) = self;
1882 match dual_stack_remove {
1883 DualStackRemove::CurrentStack(remove) => RemoveInfo(remove).into_sharing_and_device(),
1884 DualStackRemove::OtherStack(remove) => RemoveInfo(remove).into_sharing_and_device(),
1885 DualStackRemove::ListenerBothStacks {
1886 identifier: _,
1887 device,
1888 sharing,
1889 socket_ids: _,
1890 } => (sharing, device),
1891 }
1892 }
1893
1894 fn reinsert(
1902 self,
1903 sockets: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
1904 other_sockets: &mut BoundSocketMap<
1905 I::OtherVersion,
1906 D,
1907 S::AddrSpec,
1908 S::SocketMapSpec<I::OtherVersion, D>,
1909 >,
1910 ) {
1911 let DualStackRemoveInfo(dual_stack_remove) = self;
1912 match dual_stack_remove {
1913 DualStackRemove::CurrentStack(remove) => {
1914 RemoveInfo(remove).reinsert(sockets);
1915 }
1916 DualStackRemove::OtherStack(remove) => {
1917 RemoveInfo(remove).reinsert(other_sockets);
1918 }
1919 DualStackRemove::ListenerBothStacks { identifier, device, sharing, socket_ids } => {
1920 let mut socket_maps_pair =
1921 PairedSocketMapMut { bound: sockets, other_bound: other_sockets };
1922 BoundStateHandler::<_, S, _>::try_insert_listener(
1923 &mut socket_maps_pair,
1924 DualStackUnspecifiedAddr,
1925 identifier,
1926 device,
1927 sharing,
1928 socket_ids,
1929 )
1930 .expect("reinserting just-removed listener failed")
1931 }
1932 }
1933 }
1934}
1935
1936trait BoundStateHandler<I: IpExt, S: DatagramSocketSpec, D: WeakDeviceIdentifier> {
1938 type ListenerAddr: Clone;
1940 type BoundSocketId;
1942
1943 fn is_listener_entry_available(
1949 &self,
1950 addr: Self::ListenerAddr,
1951 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1952 sharing_state: &S::SharingState,
1953 ) -> bool;
1954
1955 fn try_insert_listener(
1962 &mut self,
1963 addr: Self::ListenerAddr,
1964 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1965 device: Option<D>,
1966 sharing: S::SharingState,
1967 id: Self::BoundSocketId,
1968 ) -> Result<(), LocalAddressError>;
1969
1970 fn remove_listener(
1974 &mut self,
1975 addr: &Self::ListenerAddr,
1976 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1977 device: &Option<D>,
1978 id: &Self::BoundSocketId,
1979 );
1980}
1981
1982#[derive(Copy, Clone, Debug)]
1987struct DualStackUnspecifiedAddr;
1988
1989impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> BoundStateHandler<I, S, D>
1991 for BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>
1992{
1993 type ListenerAddr = Option<SocketIpAddr<I::Addr>>;
1994 type BoundSocketId =
1995 <S::SocketMapSpec<I, D> as DatagramSocketMapSpec<I, D, S::AddrSpec>>::BoundSocketId;
1996 fn is_listener_entry_available(
1997 &self,
1998 addr: Self::ListenerAddr,
1999 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2000 sharing: &S::SharingState,
2001 ) -> bool {
2002 let check_addr = ListenerAddr { device: None, ip: ListenerIpAddr { identifier, addr } };
2003 match self.listeners().could_insert(&check_addr, sharing) {
2004 Ok(()) => true,
2005 Err(
2006 InsertError::Exists
2007 | InsertError::IndirectConflict
2008 | InsertError::ShadowAddrExists
2009 | InsertError::ShadowerExists,
2010 ) => false,
2011 }
2012 }
2013
2014 fn try_insert_listener(
2015 &mut self,
2016 addr: Self::ListenerAddr,
2017 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2018 device: Option<D>,
2019 sharing: S::SharingState,
2020 id: Self::BoundSocketId,
2021 ) -> Result<(), LocalAddressError> {
2022 try_insert_single_listener(self, addr, identifier, device, sharing, id).map(|_entry| ())
2023 }
2024
2025 fn remove_listener(
2026 &mut self,
2027 addr: &Self::ListenerAddr,
2028 identifier: <<S as DatagramSocketSpec>::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2029 device: &Option<D>,
2030 id: &Self::BoundSocketId,
2031 ) {
2032 remove_single_listener(self, addr, identifier, device, id)
2033 }
2034}
2035
2036struct PairedSocketMapMut<'a, I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
2037 bound: &'a mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
2038 other_bound: &'a mut BoundSocketMap<
2039 I::OtherVersion,
2040 D,
2041 S::AddrSpec,
2042 S::SocketMapSpec<I::OtherVersion, D>,
2043 >,
2044}
2045
2046struct PairedBoundSocketIds<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
2047 this: <S::SocketMapSpec<I, D> as DatagramSocketMapSpec<I, D, S::AddrSpec>>::BoundSocketId,
2048 other: <S::SocketMapSpec<I::OtherVersion, D> as DatagramSocketMapSpec<
2049 I::OtherVersion,
2050 D,
2051 S::AddrSpec,
2052 >>::BoundSocketId,
2053}
2054
2055impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> BoundStateHandler<I, S, D>
2057 for PairedSocketMapMut<'_, I, D, S>
2058{
2059 type ListenerAddr = DualStackUnspecifiedAddr;
2060 type BoundSocketId = PairedBoundSocketIds<I, D, S>;
2061
2062 fn is_listener_entry_available(
2063 &self,
2064 DualStackUnspecifiedAddr: Self::ListenerAddr,
2065 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2066 sharing: &S::SharingState,
2067 ) -> bool {
2068 let PairedSocketMapMut { bound, other_bound } = self;
2069 BoundStateHandler::<I, S, D>::is_listener_entry_available(*bound, None, identifier, sharing)
2070 && BoundStateHandler::<I::OtherVersion, S, D>::is_listener_entry_available(
2071 *other_bound,
2072 None,
2073 identifier,
2074 sharing,
2075 )
2076 }
2077
2078 fn try_insert_listener(
2079 &mut self,
2080 DualStackUnspecifiedAddr: Self::ListenerAddr,
2081 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2082 device: Option<D>,
2083 sharing: S::SharingState,
2084 id: Self::BoundSocketId,
2085 ) -> Result<(), LocalAddressError> {
2086 let PairedSocketMapMut { bound: this, other_bound: other } = self;
2087 let PairedBoundSocketIds { this: this_id, other: other_id } = id;
2088 try_insert_single_listener(this, None, identifier, device.clone(), sharing.clone(), this_id)
2089 .and_then(|first_entry| {
2090 match try_insert_single_listener(other, None, identifier, device, sharing, other_id)
2091 {
2092 Ok(_second_entry) => Ok(()),
2093 Err(e) => {
2094 first_entry.remove();
2095 Err(e)
2096 }
2097 }
2098 })
2099 }
2100
2101 fn remove_listener(
2102 &mut self,
2103 DualStackUnspecifiedAddr: &Self::ListenerAddr,
2104 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2105 device: &Option<D>,
2106 id: &PairedBoundSocketIds<I, D, S>,
2107 ) {
2108 let PairedSocketMapMut { bound: this, other_bound: other } = self;
2109 let PairedBoundSocketIds { this: this_id, other: other_id } = id;
2110 remove_single_listener(this, &None, identifier, device, this_id);
2111 remove_single_listener(other, &None, identifier, device, other_id);
2112 }
2113}
2114
2115fn try_insert_single_listener<
2116 I: IpExt,
2117 D: WeakDeviceIdentifier,
2118 A: SocketMapAddrSpec,
2119 S: DatagramSocketMapSpec<I, D, A>,
2120>(
2121 bound: &mut BoundSocketMap<I, D, A, S>,
2122 addr: Option<SocketIpAddr<I::Addr>>,
2123 identifier: A::LocalIdentifier,
2124 device: Option<D>,
2125 sharing: S::ListenerSharingState,
2126 id: S::ListenerId,
2127) -> Result<socket::SocketStateEntry<'_, I, D, A, S, socket::Listener>, LocalAddressError> {
2128 bound
2129 .listeners_mut()
2130 .try_insert(ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device }, sharing, id)
2131 .map_err(|e| match e {
2132 (
2133 InsertError::ShadowAddrExists
2134 | InsertError::Exists
2135 | InsertError::IndirectConflict
2136 | InsertError::ShadowerExists,
2137 sharing,
2138 ) => {
2139 let _: S::ListenerSharingState = sharing;
2140 LocalAddressError::AddressInUse
2141 }
2142 })
2143}
2144
2145fn remove_single_listener<
2146 I: IpExt,
2147 D: WeakDeviceIdentifier,
2148 A: SocketMapAddrSpec,
2149 S: DatagramSocketMapSpec<I, D, A>,
2150>(
2151 bound: &mut BoundSocketMap<I, D, A, S>,
2152 addr: &Option<SocketIpAddr<I::Addr>>,
2153 identifier: A::LocalIdentifier,
2154 device: &Option<D>,
2155 id: &S::ListenerId,
2156) {
2157 let addr =
2158 ListenerAddr { ip: ListenerIpAddr { addr: *addr, identifier }, device: device.clone() };
2159 bound
2160 .listeners_mut()
2161 .remove(id, &addr)
2162 .unwrap_or_else(|NotFoundError| panic!("socket ID {:?} not found for {:?}", id, addr))
2163}
2164
2165fn try_pick_identifier<
2166 I: IpExt,
2167 S: DatagramSocketSpec,
2168 D: WeakDeviceIdentifier,
2169 BS: BoundStateHandler<I, S, D>,
2170 BC: RngContext,
2171>(
2172 addr: BS::ListenerAddr,
2173 bound: &BS,
2174 bindings_ctx: &mut BC,
2175 sharing: &S::SharingState,
2176) -> Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier> {
2177 S::try_alloc_listen_identifier::<I, D>(bindings_ctx, move |identifier| {
2178 bound
2179 .is_listener_entry_available(addr.clone(), identifier, sharing)
2180 .then_some(())
2181 .ok_or(InUseError)
2182 })
2183}
2184
2185fn try_pick_bound_address<
2186 I: IpExt,
2187 CC: TransportIpContext<I, BC>,
2188 BC: DatagramBindingsTypes,
2189 LI,
2190>(
2191 addr: Option<ZonedAddr<SocketIpAddr<I::Addr>, CC::DeviceId>>,
2192 device: &Option<CC::WeakDeviceId>,
2193 core_ctx: &mut CC,
2194 identifier: LI,
2195 transparent: bool,
2196) -> Result<
2197 (Option<SocketIpAddr<I::Addr>>, Option<EitherDeviceId<CC::DeviceId, CC::WeakDeviceId>>, LI),
2198 LocalAddressError,
2199> {
2200 let (addr, device, identifier) = match addr {
2201 Some(addr) => {
2202 let (addr, device) = addr.resolve_addr_with_device(device.clone())?;
2206
2207 if !addr.addr().is_multicast() && !transparent {
2211 BaseTransportIpContext::<I, _>::with_devices_with_assigned_addr(
2212 core_ctx,
2213 addr.into(),
2214 |mut assigned_to| {
2215 if let Some(device) = &device {
2216 if !assigned_to.any(|d| device == &EitherDeviceId::Strong(d)) {
2217 return Err(LocalAddressError::AddressMismatch);
2218 }
2219 } else {
2220 if !assigned_to.any(|_: CC::DeviceId| true) {
2221 return Err(LocalAddressError::CannotBindToAddress);
2222 }
2223 }
2224 Ok(())
2225 },
2226 )?;
2227 }
2228 (Some(addr), device, identifier)
2229 }
2230 None => (None, device.clone().map(EitherDeviceId::Weak), identifier),
2231 };
2232 Ok((addr, device, identifier))
2233}
2234
2235fn listen_inner<
2236 I: IpExt,
2237 BC: DatagramBindingsContext,
2238 CC: DatagramBoundStateContext<I, BC, S>,
2239 S: DatagramSocketSpec,
2240>(
2241 core_ctx: &mut CC,
2242 bindings_ctx: &mut BC,
2243 state: &mut SocketState<I, CC::WeakDeviceId, S>,
2244 id: &S::SocketId<I, CC::WeakDeviceId>,
2245 addr: Option<ZonedAddr<SpecifiedAddr<I::Addr>, CC::DeviceId>>,
2246 local_id: Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
2247) -> Result<(), Either<ExpectedUnboundError, LocalAddressError>> {
2248 #[derive(Debug, GenericOverIp)]
2252 #[generic_over_ip(I, Ip)]
2253 enum BoundOperation<'a, I: IpExt, DS: DeviceIdContext<AnyDevice>, NDS> {
2254 DualStackAnyAddr(&'a mut DS),
2256 OnlyCurrentStack(
2258 MaybeDualStack<&'a mut DS, &'a mut NDS>,
2259 Option<ZonedAddr<SocketIpAddr<I::Addr>, DS::DeviceId>>,
2260 ),
2261 OnlyOtherStack(
2263 &'a mut DS,
2264 Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, DS::DeviceId>>,
2265 ),
2266 }
2267
2268 let SocketState { inner, ip_options } = state;
2269 let UnboundSocketState { device, sharing } = match inner {
2270 SocketStateInner::Unbound(state) => state,
2271 SocketStateInner::Bound(_) => return Err(Either::Left(ExpectedUnboundError)),
2272 };
2273
2274 let dual_stack = core_ctx.dual_stack_context_mut();
2275 let bound_operation: BoundOperation<'_, I, _, _> = match (dual_stack, addr) {
2276 (MaybeDualStack::DualStack(dual_stack), None) => {
2278 match dual_stack.dual_stack_enabled(ip_options) {
2279 true => BoundOperation::DualStackAnyAddr(dual_stack),
2281 false => {
2284 BoundOperation::OnlyCurrentStack(MaybeDualStack::DualStack(dual_stack), None)
2285 }
2286 }
2287 }
2288 (MaybeDualStack::DualStack(dual_stack), Some(addr)) => {
2291 match DualStackLocalIp::<I, _>::new(addr) {
2292 DualStackLocalIp::ThisStack(addr) => BoundOperation::OnlyCurrentStack(
2294 MaybeDualStack::DualStack(dual_stack),
2295 Some(addr),
2296 ),
2297 DualStackLocalIp::OtherStack(addr) => {
2299 match dual_stack.dual_stack_enabled(ip_options) {
2300 true => BoundOperation::OnlyOtherStack(dual_stack, addr),
2301 false => return Err(Either::Right(LocalAddressError::CannotBindToAddress)),
2302 }
2303 }
2304 }
2305 }
2306 (MaybeDualStack::NotDualStack(single_stack), None) => {
2308 BoundOperation::OnlyCurrentStack(MaybeDualStack::NotDualStack(single_stack), None)
2309 }
2310 (MaybeDualStack::NotDualStack(single_stack), Some(addr)) => {
2313 match DualStackLocalIp::<I, _>::new(addr) {
2314 DualStackLocalIp::ThisStack(addr) => BoundOperation::OnlyCurrentStack(
2316 MaybeDualStack::NotDualStack(single_stack),
2317 Some(addr),
2318 ),
2319 DualStackLocalIp::OtherStack(_addr) => {
2322 let _: Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, _>> =
2323 _addr;
2324 return Err(Either::Right(LocalAddressError::CannotBindToAddress));
2325 }
2326 }
2327 }
2328 };
2329
2330 fn try_bind_single_stack<
2331 I: IpExt,
2332 S: DatagramSocketSpec,
2333 CC: TransportIpContext<I, BC>,
2334 BC: DatagramBindingsContext,
2335 >(
2336 core_ctx: &mut CC,
2337 bindings_ctx: &mut BC,
2338 bound: &mut BoundSocketMap<
2339 I,
2340 CC::WeakDeviceId,
2341 S::AddrSpec,
2342 S::SocketMapSpec<I, CC::WeakDeviceId>,
2343 >,
2344 addr: Option<ZonedAddr<SocketIpAddr<I::Addr>, CC::DeviceId>>,
2345 device: &Option<CC::WeakDeviceId>,
2346 local_id: Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
2347 id: <S::SocketMapSpec<I, CC::WeakDeviceId> as SocketMapStateSpec>::ListenerId,
2348 sharing: S::SharingState,
2349 transparent: bool,
2350 ) -> Result<
2351 ListenerAddr<
2352 ListenerIpAddr<I::Addr, <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
2353 CC::WeakDeviceId,
2354 >,
2355 LocalAddressError,
2356 > {
2357 let identifier = match local_id {
2358 Some(id) => Some(id),
2359 None => try_pick_identifier::<I, S, _, _, _>(
2360 addr.as_ref().map(ZonedAddr::addr),
2361 bound,
2362 bindings_ctx,
2363 &sharing,
2364 ),
2365 }
2366 .ok_or(LocalAddressError::FailedToAllocateLocalPort)?;
2367 let (addr, device, identifier) =
2368 try_pick_bound_address::<I, _, _, _>(addr, device, core_ctx, identifier, transparent)?;
2369 let weak_device = device.map(|d| d.as_weak().into_owned());
2370
2371 BoundStateHandler::<_, S, _>::try_insert_listener(
2372 bound,
2373 addr,
2374 identifier,
2375 weak_device.clone(),
2376 sharing,
2377 id,
2378 )
2379 .map(|()| ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device: weak_device })
2380 }
2381
2382 let bound_addr: ListenerAddr<S::ListenerIpAddr<I>, CC::WeakDeviceId> = match bound_operation {
2383 BoundOperation::OnlyCurrentStack(either_dual_stack, addr) => {
2384 let converter = match either_dual_stack {
2385 MaybeDualStack::DualStack(ds) => MaybeDualStack::DualStack(ds.ds_converter()),
2386 MaybeDualStack::NotDualStack(nds) => {
2387 MaybeDualStack::NotDualStack(nds.nds_converter())
2388 }
2389 };
2390 core_ctx
2391 .with_bound_sockets_mut(|core_ctx, bound| {
2392 let id = S::make_bound_socket_map_id(id);
2393
2394 try_bind_single_stack::<I, S, _, _>(
2395 core_ctx,
2396 bindings_ctx,
2397 bound,
2398 addr,
2399 device,
2400 local_id,
2401 id,
2402 sharing.clone(),
2403 ip_options.common.transparent,
2404 )
2405 })
2406 .map(|ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device }| {
2407 let ip = match converter {
2408 MaybeDualStack::DualStack(converter) => converter.convert_back(
2409 DualStackListenerIpAddr::ThisStack(ListenerIpAddr { addr, identifier }),
2410 ),
2411 MaybeDualStack::NotDualStack(converter) => {
2412 converter.convert_back(ListenerIpAddr { addr, identifier })
2413 }
2414 };
2415 ListenerAddr { ip, device }
2416 })
2417 }
2418 BoundOperation::OnlyOtherStack(core_ctx, addr) => {
2419 let id = core_ctx.to_other_bound_socket_id(id);
2420 core_ctx
2421 .with_other_bound_sockets_mut(|core_ctx, other_bound| {
2422 try_bind_single_stack::<_, S, _, _>(
2423 core_ctx,
2424 bindings_ctx,
2425 other_bound,
2426 addr,
2427 device,
2428 local_id,
2429 id,
2430 sharing.clone(),
2431 ip_options.common.transparent,
2432 )
2433 })
2434 .map(|ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device }| {
2435 ListenerAddr {
2436 ip: core_ctx.ds_converter().convert_back(
2437 DualStackListenerIpAddr::OtherStack(ListenerIpAddr {
2438 addr,
2439 identifier,
2440 }),
2441 ),
2442 device,
2443 }
2444 })
2445 }
2446 BoundOperation::DualStackAnyAddr(core_ctx) => {
2447 let ids = PairedBoundSocketIds {
2448 this: S::make_bound_socket_map_id(id),
2449 other: core_ctx.to_other_bound_socket_id(id),
2450 };
2451 core_ctx
2452 .with_both_bound_sockets_mut(|core_ctx, bound, other_bound| {
2453 let mut bound_pair = PairedSocketMapMut { bound, other_bound };
2454 let sharing = sharing.clone();
2455
2456 let identifier = match local_id {
2457 Some(id) => Some(id),
2458 None => try_pick_identifier::<I, S, _, _, _>(
2459 DualStackUnspecifiedAddr,
2460 &bound_pair,
2461 bindings_ctx,
2462 &sharing,
2463 ),
2464 }
2465 .ok_or(LocalAddressError::FailedToAllocateLocalPort)?;
2466 let (_addr, device, identifier) = try_pick_bound_address::<I, _, _, _>(
2467 None,
2468 device,
2469 core_ctx,
2470 identifier,
2471 ip_options.common.transparent,
2472 )?;
2473 let weak_device = device.map(|d| d.as_weak().into_owned());
2474
2475 BoundStateHandler::<_, S, _>::try_insert_listener(
2476 &mut bound_pair,
2477 DualStackUnspecifiedAddr,
2478 identifier,
2479 weak_device.clone(),
2480 sharing,
2481 ids,
2482 )
2483 .map(|()| (identifier, weak_device))
2484 })
2485 .map(|(identifier, device)| ListenerAddr {
2486 ip: core_ctx
2487 .ds_converter()
2488 .convert_back(DualStackListenerIpAddr::BothStacks(identifier)),
2489 device,
2490 })
2491 }
2492 }
2493 .map_err(Either::Right)?;
2494 let original_bound_addr = local_id.map(|_id| {
2497 let ListenerAddr { ip, device: _ } = &bound_addr;
2498 ip.clone()
2499 });
2500
2501 state.inner = SocketStateInner::Bound(BoundSocketState {
2504 socket_type: BoundSocketStateType::Listener {
2505 state: ListenerState { addr: bound_addr },
2506 sharing: sharing.clone(),
2507 },
2508 original_bound_addr,
2509 });
2510 Ok(())
2511}
2512
2513#[derive(Error, Copy, Clone, Debug, Eq, PartialEq)]
2515pub enum ConnectError {
2516 #[error(transparent)]
2518 Ip(#[from] IpSockCreationError),
2519 #[error("a local port could not be allocated")]
2521 CouldNotAllocateLocalPort,
2522 #[error("the socket's IP address and port conflict with an existing socket")]
2525 SockAddrConflict,
2526 #[error(transparent)]
2528 Zone(#[from] ZonedAddressError),
2529 #[error("IPv4-mapped-IPv6 addresses are not supported by this socket")]
2532 RemoteUnexpectedlyMapped,
2533 #[error("non IPv4-mapped-Ipv6 addresses are not supported by this socket")]
2536 RemoteUnexpectedlyNonMapped,
2537}
2538
2539struct ConnectParameters<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
2541 local_ip: Option<SocketIpAddr<WireI::Addr>>,
2542 local_port: Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
2543 remote_ip: ZonedAddr<SocketIpAddr<WireI::Addr>, D::Strong>,
2544 remote_port: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
2545 device: Option<D>,
2546 sharing: S::SharingState,
2547 common_ip_options: DatagramIpAgnosticOptions,
2548 socket_options: DatagramIpSpecificSocketOptions<WireI, D>,
2549 socket_id:
2550 <S::SocketMapSpec<WireI, D> as DatagramSocketMapSpec<WireI, D, S::AddrSpec>>::BoundSocketId,
2551 original_shutdown: Option<Shutdown>,
2552 extra: S::ConnStateExtra,
2553}
2554
2555fn connect_inner<
2562 WireI: IpExt,
2563 D: WeakDeviceIdentifier,
2564 S: DatagramSocketSpec,
2565 R,
2566 BC: DatagramBindingsContext,
2567 CC: IpSocketHandler<WireI, BC, WeakDeviceId = D, DeviceId = D::Strong>,
2568>(
2569 connect_params: ConnectParameters<WireI, D, S>,
2570 core_ctx: &mut CC,
2571 bindings_ctx: &mut BC,
2572 sockets: &mut BoundSocketMap<WireI, D, S::AddrSpec, S::SocketMapSpec<WireI, D>>,
2573 remove_original: impl FnOnce(
2574 &mut BoundSocketMap<WireI, D, S::AddrSpec, S::SocketMapSpec<WireI, D>>,
2575 ) -> R,
2576 reinsert_original: impl FnOnce(
2577 &mut BoundSocketMap<WireI, D, S::AddrSpec, S::SocketMapSpec<WireI, D>>,
2578 R,
2579 ),
2580) -> Result<ConnState<WireI, D, S>, ConnectError> {
2581 let ConnectParameters {
2582 local_ip,
2583 local_port,
2584 remote_ip,
2585 remote_port,
2586 device,
2587 sharing,
2588 common_ip_options,
2589 socket_options,
2590 socket_id,
2591 original_shutdown,
2592 extra,
2593 } = connect_params;
2594
2595 let device = device.or_else(|| {
2597 remote_ip
2598 .addr()
2599 .addr()
2600 .is_multicast()
2601 .then(|| socket_options.multicast_interface.clone())
2602 .flatten()
2603 });
2604
2605 let (remote_ip, socket_device) = remote_ip.resolve_addr_with_device(device.clone())?;
2606
2607 let clear_device_on_disconnect = device.is_none() && socket_device.is_some();
2608
2609 let ip_sock = IpSocketHandler::<WireI, _>::new_ip_socket(
2610 core_ctx,
2611 bindings_ctx,
2612 IpSocketArgs {
2613 device: socket_device.as_ref().map(|d| d.as_ref()),
2614 local_ip: local_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr),
2615 remote_ip,
2616 proto: S::ip_proto::<WireI>(),
2617 options: &common_ip_options,
2618 },
2619 )?;
2620
2621 let local_port = match local_port {
2622 Some(id) => id.clone(),
2623 None => S::try_alloc_local_id(
2624 sockets,
2625 bindings_ctx,
2626 DatagramFlowId {
2627 local_ip: SocketIpAddr::from(*ip_sock.local_ip()),
2628 remote_ip: *ip_sock.remote_ip(),
2629 remote_id: remote_port.clone(),
2630 },
2631 )
2632 .ok_or(ConnectError::CouldNotAllocateLocalPort)?,
2633 };
2634 let conn_addr = ConnAddr {
2635 ip: ConnIpAddr {
2636 local: (SocketIpAddr::from(*ip_sock.local_ip()), local_port),
2637 remote: (*ip_sock.remote_ip(), remote_port),
2638 },
2639 device: ip_sock.device().cloned(),
2640 };
2641 let reinsert_op = remove_original(sockets);
2644 let bound_addr = match sockets.conns_mut().try_insert(conn_addr, sharing, socket_id) {
2647 Ok(bound_entry) => bound_entry.get_addr().clone(),
2648 Err((
2649 InsertError::Exists
2650 | InsertError::IndirectConflict
2651 | InsertError::ShadowerExists
2652 | InsertError::ShadowAddrExists,
2653 _sharing,
2654 )) => {
2655 reinsert_original(sockets, reinsert_op);
2656 return Err(ConnectError::SockAddrConflict);
2657 }
2658 };
2659 Ok(ConnState {
2660 socket: ip_sock,
2661 clear_device_on_disconnect,
2662 shutdown: original_shutdown.unwrap_or_else(Shutdown::default),
2663 addr: bound_addr,
2664 extra,
2665 })
2666}
2667
2668struct SingleStackConnectOperation<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
2670 params: ConnectParameters<I, D, S>,
2671 remove_op: Option<SingleStackRemoveOperation<I, D, S>>,
2672 sharing: S::SharingState,
2673}
2674
2675impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>
2676 SingleStackConnectOperation<I, D, S>
2677{
2678 fn new_from_state<
2680 BC,
2681 CC: NonDualStackDatagramBoundStateContext<I, BC, S, WeakDeviceId = D, DeviceId = D::Strong>,
2682 >(
2683 core_ctx: &mut CC,
2684 socket_id: &S::SocketId<I, D>,
2685 state: &SocketState<I, D, S>,
2686 remote_ip: ZonedAddr<SocketIpAddr<I::Addr>, D::Strong>,
2687 remote_port: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
2688 extra: S::ConnStateExtra,
2689 ) -> Self {
2690 let SocketState { ip_options, inner } = state;
2691 match inner {
2692 SocketStateInner::Unbound(UnboundSocketState { device, sharing }) => {
2693 SingleStackConnectOperation {
2694 params: ConnectParameters {
2695 local_ip: None,
2696 local_port: None,
2697 remote_ip,
2698 remote_port,
2699 device: device.clone(),
2700 sharing: sharing.clone(),
2701 common_ip_options: ip_options.common.clone(),
2702 socket_options: ip_options.socket_options.clone(),
2703 socket_id: S::make_bound_socket_map_id(socket_id),
2704 original_shutdown: None,
2705 extra,
2706 },
2707 sharing: sharing.clone(),
2708 remove_op: None,
2709 }
2710 }
2711 SocketStateInner::Bound(state) => {
2712 let remove_op =
2713 SingleStackRemoveOperation::new_from_state(core_ctx, socket_id, state);
2714 let BoundSocketState { socket_type, original_bound_addr: _ } = state;
2715 match socket_type {
2716 BoundSocketStateType::Listener {
2717 state: ListenerState { addr: ListenerAddr { ip, device } },
2718 sharing,
2719 } => {
2720 let ListenerIpAddr { addr, identifier } =
2721 core_ctx.nds_converter().convert(ip);
2722 SingleStackConnectOperation {
2723 params: ConnectParameters {
2724 local_ip: addr.clone(),
2725 local_port: Some(*identifier),
2726 remote_ip,
2727 remote_port,
2728 device: device.clone(),
2729 sharing: sharing.clone(),
2730 common_ip_options: ip_options.common.clone(),
2731 socket_options: ip_options.socket_options.clone(),
2732 socket_id: S::make_bound_socket_map_id(socket_id),
2733 original_shutdown: None,
2734 extra,
2735 },
2736 sharing: sharing.clone(),
2737 remove_op: Some(remove_op),
2738 }
2739 }
2740 BoundSocketStateType::Connected { state, sharing } => {
2741 let ConnState {
2742 socket: _,
2743 shutdown,
2744 addr:
2745 ConnAddr {
2746 ip: ConnIpAddr { local: (local_ip, local_id), remote: _ },
2747 device,
2748 },
2749 clear_device_on_disconnect: _,
2750 extra: _,
2751 } = core_ctx.nds_converter().convert(state);
2752 SingleStackConnectOperation {
2753 params: ConnectParameters {
2754 local_ip: Some(local_ip.clone()),
2755 local_port: Some(*local_id),
2756 remote_ip,
2757 remote_port,
2758 device: device.clone(),
2759 sharing: sharing.clone(),
2760 common_ip_options: ip_options.common.clone(),
2761 socket_options: ip_options.socket_options.clone(),
2762 socket_id: S::make_bound_socket_map_id(socket_id),
2763 original_shutdown: Some(shutdown.clone()),
2764 extra,
2765 },
2766 sharing: sharing.clone(),
2767 remove_op: Some(remove_op),
2768 }
2769 }
2770 }
2771 }
2772 }
2773 }
2774
2775 fn apply<
2783 BC: DatagramBindingsContext,
2784 CC: IpSocketHandler<I, BC, WeakDeviceId = D, DeviceId = D::Strong>,
2785 >(
2786 self,
2787 core_ctx: &mut CC,
2788 bindings_ctx: &mut BC,
2789 socket_map: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
2790 ) -> Result<(ConnState<I, D, S>, S::SharingState), ConnectError> {
2791 let SingleStackConnectOperation { params, remove_op, sharing } = self;
2792 let remove_fn =
2793 |sockets: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>| {
2794 remove_op.map(|remove_op| remove_op.apply(sockets))
2795 };
2796 let reinsert_fn =
2797 |sockets: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
2798 remove_info: Option<SingleStackRemoveInfo<I, D, S>>| {
2799 if let Some(remove_info) = remove_info {
2800 remove_info.reinsert(sockets)
2801 }
2802 };
2803 let conn_state =
2804 connect_inner(params, core_ctx, bindings_ctx, socket_map, remove_fn, reinsert_fn)?;
2805 Ok((conn_state, sharing))
2806 }
2807}
2808
2809struct DualStackConnectOperation<I: DualStackIpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>
2811{
2812 params: EitherStack<ConnectParameters<I, D, S>, ConnectParameters<I::OtherVersion, D, S>>,
2813 remove_op: Option<DualStackRemoveOperation<I, D, S>>,
2814 sharing: S::SharingState,
2815}
2816
2817impl<I: DualStackIpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>
2818 DualStackConnectOperation<I, D, S>
2819{
2820 fn new_from_state<
2822 BC: DatagramBindingsContext,
2823 CC: DualStackDatagramBoundStateContext<I, BC, S, WeakDeviceId = D, DeviceId = D::Strong>,
2824 >(
2825 core_ctx: &mut CC,
2826 socket_id: &S::SocketId<I, D>,
2827 state: &SocketState<I, D, S>,
2828 remote_ip: DualStackRemoteIp<I, D::Strong>,
2829 remote_port: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
2830 extra: S::ConnStateExtra,
2831 ) -> Result<Self, ConnectError> {
2832 let SocketState { ip_options, inner } = state;
2833 match inner {
2834 SocketStateInner::Unbound(UnboundSocketState { device, sharing }) => {
2835 let params = match remote_ip {
2838 DualStackRemoteIp::ThisStack(remote_ip) => {
2839 EitherStack::ThisStack(ConnectParameters {
2840 local_ip: None,
2841 local_port: None,
2842 remote_ip,
2843 remote_port,
2844 device: device.clone(),
2845 sharing: sharing.clone(),
2846 common_ip_options: ip_options.common.clone(),
2847 socket_options: ip_options.socket_options.clone(),
2848 socket_id: S::make_bound_socket_map_id(socket_id),
2849 original_shutdown: None,
2850 extra,
2851 })
2852 }
2853 DualStackRemoteIp::OtherStack(remote_ip) => {
2854 if !core_ctx.dual_stack_enabled(ip_options) {
2855 return Err(ConnectError::RemoteUnexpectedlyMapped);
2856 }
2857 EitherStack::OtherStack(ConnectParameters {
2858 local_ip: None,
2859 local_port: None,
2860 remote_ip,
2861 remote_port,
2862 device: device.clone(),
2863 sharing: sharing.clone(),
2864 common_ip_options: ip_options.common.clone(),
2865 socket_options: core_ctx.to_other_socket_options(ip_options).clone(),
2866 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
2867 original_shutdown: None,
2868 extra,
2869 })
2870 }
2871 };
2872 Ok(DualStackConnectOperation { params, remove_op: None, sharing: sharing.clone() })
2873 }
2874 SocketStateInner::Bound(state) => {
2875 let remove_op = DualStackRemoveOperation::new_from_state(
2876 core_ctx, socket_id, ip_options, state,
2877 );
2878
2879 let BoundSocketState { socket_type, original_bound_addr: _ } = state;
2880 match socket_type {
2881 BoundSocketStateType::Listener {
2882 state: ListenerState { addr: ListenerAddr { ip, device } },
2883 sharing,
2884 } => {
2885 match (remote_ip, core_ctx.ds_converter().convert(ip)) {
2886 (
2889 DualStackRemoteIp::OtherStack(_),
2890 DualStackListenerIpAddr::ThisStack(_),
2891 ) => Err(ConnectError::RemoteUnexpectedlyMapped),
2892 (
2895 DualStackRemoteIp::ThisStack(_),
2896 DualStackListenerIpAddr::OtherStack(_),
2897 ) => Err(ConnectError::RemoteUnexpectedlyNonMapped),
2898 (
2900 DualStackRemoteIp::ThisStack(remote_ip),
2901 DualStackListenerIpAddr::ThisStack(ListenerIpAddr {
2902 addr,
2903 identifier,
2904 }),
2905 ) => Ok(DualStackConnectOperation {
2906 params: EitherStack::ThisStack(ConnectParameters {
2907 local_ip: addr.clone(),
2908 local_port: Some(*identifier),
2909 remote_ip,
2910 remote_port,
2911 device: device.clone(),
2912 sharing: sharing.clone(),
2913 common_ip_options: ip_options.common.clone(),
2914 socket_options: ip_options.socket_options.clone(),
2915 socket_id: S::make_bound_socket_map_id(socket_id),
2916 original_shutdown: None,
2917 extra,
2918 }),
2919 sharing: sharing.clone(),
2920 remove_op: Some(remove_op),
2921 }),
2922 (
2926 DualStackRemoteIp::ThisStack(remote_ip),
2927 DualStackListenerIpAddr::BothStacks(identifier),
2928 ) => Ok(DualStackConnectOperation {
2929 params: EitherStack::ThisStack(ConnectParameters {
2930 local_ip: None,
2931 local_port: Some(*identifier),
2932 remote_ip,
2933 remote_port,
2934 device: device.clone(),
2935 sharing: sharing.clone(),
2936 common_ip_options: ip_options.common.clone(),
2937 socket_options: ip_options.socket_options.clone(),
2938 socket_id: S::make_bound_socket_map_id(socket_id),
2939 original_shutdown: None,
2940 extra,
2941 }),
2942 sharing: sharing.clone(),
2943 remove_op: Some(remove_op),
2944 }),
2945 (
2947 DualStackRemoteIp::OtherStack(remote_ip),
2948 DualStackListenerIpAddr::OtherStack(ListenerIpAddr {
2949 addr,
2950 identifier,
2951 }),
2952 ) => Ok(DualStackConnectOperation {
2953 params: EitherStack::OtherStack(ConnectParameters {
2954 local_ip: addr.clone(),
2955 local_port: Some(*identifier),
2956 remote_ip,
2957 remote_port,
2958 device: device.clone(),
2959 sharing: sharing.clone(),
2960 common_ip_options: ip_options.common.clone(),
2961 socket_options: core_ctx
2962 .to_other_socket_options(ip_options)
2963 .clone(),
2964 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
2965 original_shutdown: None,
2966 extra,
2967 }),
2968 sharing: sharing.clone(),
2969 remove_op: Some(remove_op),
2970 }),
2971 (
2975 DualStackRemoteIp::OtherStack(remote_ip),
2976 DualStackListenerIpAddr::BothStacks(identifier),
2977 ) => Ok(DualStackConnectOperation {
2978 params: EitherStack::OtherStack(ConnectParameters {
2979 local_ip: None,
2980 local_port: Some(*identifier),
2981 remote_ip,
2982 remote_port,
2983 device: device.clone(),
2984 sharing: sharing.clone(),
2985 common_ip_options: ip_options.common.clone(),
2986 socket_options: core_ctx
2987 .to_other_socket_options(ip_options)
2988 .clone(),
2989 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
2990 original_shutdown: None,
2991 extra,
2992 }),
2993 sharing: sharing.clone(),
2994 remove_op: Some(remove_op),
2995 }),
2996 }
2997 }
2998 BoundSocketStateType::Connected { state, sharing } => {
2999 match (remote_ip, core_ctx.ds_converter().convert(state)) {
3000 (
3003 DualStackRemoteIp::OtherStack(_),
3004 DualStackConnState::ThisStack(_),
3005 ) => Err(ConnectError::RemoteUnexpectedlyMapped),
3006 (
3009 DualStackRemoteIp::ThisStack(_),
3010 DualStackConnState::OtherStack(_),
3011 ) => Err(ConnectError::RemoteUnexpectedlyNonMapped),
3012 (
3014 DualStackRemoteIp::ThisStack(remote_ip),
3015 DualStackConnState::ThisStack(ConnState {
3016 socket: _,
3017 shutdown,
3018 addr:
3019 ConnAddr {
3020 ip:
3021 ConnIpAddr { local: (local_ip, local_id), remote: _ },
3022 device,
3023 },
3024 clear_device_on_disconnect: _,
3025 extra: _,
3026 }),
3027 ) => Ok(DualStackConnectOperation {
3028 params: EitherStack::ThisStack(ConnectParameters {
3029 local_ip: Some(local_ip.clone()),
3030 local_port: Some(*local_id),
3031 remote_ip,
3032 remote_port,
3033 device: device.clone(),
3034 sharing: sharing.clone(),
3035 common_ip_options: ip_options.common.clone(),
3036 socket_options: ip_options.socket_options.clone(),
3037 socket_id: S::make_bound_socket_map_id(socket_id),
3038 original_shutdown: Some(shutdown.clone()),
3039 extra,
3040 }),
3041 sharing: sharing.clone(),
3042 remove_op: Some(remove_op),
3043 }),
3044 (
3046 DualStackRemoteIp::OtherStack(remote_ip),
3047 DualStackConnState::OtherStack(ConnState {
3048 socket: _,
3049 shutdown,
3050 addr:
3051 ConnAddr {
3052 ip:
3053 ConnIpAddr { local: (local_ip, local_id), remote: _ },
3054 device,
3055 },
3056 clear_device_on_disconnect: _,
3057 extra: _,
3058 }),
3059 ) => Ok(DualStackConnectOperation {
3060 params: EitherStack::OtherStack(ConnectParameters {
3061 local_ip: Some(local_ip.clone()),
3062 local_port: Some(*local_id),
3063 remote_ip,
3064 remote_port,
3065 device: device.clone(),
3066 sharing: sharing.clone(),
3067 common_ip_options: ip_options.common.clone(),
3068 socket_options: core_ctx
3069 .to_other_socket_options(ip_options)
3070 .clone(),
3071 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
3072 original_shutdown: Some(shutdown.clone()),
3073 extra,
3074 }),
3075 sharing: sharing.clone(),
3076 remove_op: Some(remove_op),
3077 }),
3078 }
3079 }
3080 }
3081 }
3082 }
3083 }
3084
3085 fn apply<
3093 BC: DatagramBindingsContext,
3094 CC: IpSocketHandler<I, BC, WeakDeviceId = D, DeviceId = D::Strong>
3095 + IpSocketHandler<I::OtherVersion, BC, WeakDeviceId = D, DeviceId = D::Strong>,
3096 >(
3097 self,
3098 core_ctx: &mut CC,
3099 bindings_ctx: &mut BC,
3100 socket_map: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
3101 other_socket_map: &mut BoundSocketMap<
3102 I::OtherVersion,
3103 D,
3104 S::AddrSpec,
3105 S::SocketMapSpec<I::OtherVersion, D>,
3106 >,
3107 ) -> Result<(DualStackConnState<I, D, S>, S::SharingState), ConnectError> {
3108 let DualStackConnectOperation { params, remove_op, sharing } = self;
3109 let conn_state = match params {
3110 EitherStack::ThisStack(params) => {
3111 let remove_fn =
3116 |sockets: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>| {
3117 remove_op.map(|remove_op| {
3118 let remove_info = remove_op.apply(sockets, other_socket_map);
3119 (remove_info, other_socket_map)
3120 })
3121 };
3122 let reinsert_fn =
3123 |sockets: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
3124 remove_info: Option<(
3125 DualStackRemoveInfo<I, D, S>,
3126 &mut BoundSocketMap<
3127 I::OtherVersion,
3128 D,
3129 S::AddrSpec,
3130 S::SocketMapSpec<I::OtherVersion, D>,
3131 >,
3132 )>| {
3133 if let Some((remove_info, other_sockets)) = remove_info {
3134 remove_info.reinsert(sockets, other_sockets)
3135 }
3136 };
3137 connect_inner(params, core_ctx, bindings_ctx, socket_map, remove_fn, reinsert_fn)
3138 .map(DualStackConnState::ThisStack)
3139 }
3140 EitherStack::OtherStack(params) => {
3141 let remove_fn = |other_sockets: &mut BoundSocketMap<
3146 I::OtherVersion,
3147 D,
3148 S::AddrSpec,
3149 S::SocketMapSpec<I::OtherVersion, D>,
3150 >| {
3151 remove_op.map(|remove_op| {
3152 let remove_info = remove_op.apply(socket_map, other_sockets);
3153 (remove_info, socket_map)
3154 })
3155 };
3156 let reinsert_fn = |other_sockets: &mut BoundSocketMap<
3157 I::OtherVersion,
3158 D,
3159 S::AddrSpec,
3160 S::SocketMapSpec<I::OtherVersion, D>,
3161 >,
3162 remove_info: Option<(
3163 DualStackRemoveInfo<I, D, S>,
3164 &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
3165 )>| {
3166 if let Some((remove_info, sockets)) = remove_info {
3167 remove_info.reinsert(sockets, other_sockets)
3168 }
3169 };
3170 connect_inner(
3171 params,
3172 core_ctx,
3173 bindings_ctx,
3174 other_socket_map,
3175 remove_fn,
3176 reinsert_fn,
3177 )
3178 .map(DualStackConnState::OtherStack)
3179 }
3180 }?;
3181 Ok((conn_state, sharing))
3182 }
3183}
3184
3185#[derive(Copy, Clone, Debug, Default, Eq, GenericOverIp, PartialEq, Error)]
3187#[generic_over_ip()]
3188#[error("expected connected socket")]
3189pub struct ExpectedConnError;
3190
3191#[derive(Copy, Clone, Debug, Default, Eq, GenericOverIp, PartialEq, Error)]
3193#[generic_over_ip()]
3194#[error("expected unbound socket")]
3195pub struct ExpectedUnboundError;
3196
3197fn disconnect_to_unbound<
3202 I: IpExt,
3203 BC: DatagramBindingsContext,
3204 CC: DatagramBoundStateContext<I, BC, S>,
3205 S: DatagramSocketSpec,
3206>(
3207 core_ctx: &mut CC,
3208 id: &S::SocketId<I, CC::WeakDeviceId>,
3209 clear_device_on_disconnect: bool,
3210 ip_options: &IpOptions<I, CC::WeakDeviceId, S>,
3211 socket_state: &BoundSocketState<I, CC::WeakDeviceId, S>,
3212) -> UnboundSocketState<CC::WeakDeviceId, S> {
3213 let (sharing, mut device) = match core_ctx.dual_stack_context_mut() {
3214 MaybeDualStack::NotDualStack(nds) => {
3215 let remove_op = SingleStackRemoveOperation::new_from_state(nds, id, socket_state);
3216 let info = core_ctx.with_bound_sockets_mut(|_core_ctx, bound| remove_op.apply(bound));
3217 info.into_sharing_and_device()
3218 }
3219 MaybeDualStack::DualStack(ds) => {
3220 let remove_op =
3221 DualStackRemoveOperation::new_from_state(ds, id, ip_options, socket_state);
3222 let info = ds.with_both_bound_sockets_mut(|_core_ctx, bound, other_bound| {
3223 remove_op.apply(bound, other_bound)
3224 });
3225 info.into_sharing_and_device()
3226 }
3227 };
3228 if clear_device_on_disconnect {
3229 device = None
3230 }
3231 UnboundSocketState { device, sharing }
3232}
3233
3234fn disconnect_to_listener<
3239 I: IpExt,
3240 BC: DatagramBindingsContext,
3241 CC: DatagramBoundStateContext<I, BC, S>,
3242 S: DatagramSocketSpec,
3243>(
3244 core_ctx: &mut CC,
3245 id: &S::SocketId<I, CC::WeakDeviceId>,
3246 listener_ip: S::ListenerIpAddr<I>,
3247 clear_device_on_disconnect: bool,
3248 ip_options: &IpOptions<I, CC::WeakDeviceId, S>,
3249 socket_state: &BoundSocketState<I, CC::WeakDeviceId, S>,
3250) -> BoundSocketState<I, CC::WeakDeviceId, S> {
3251 let (sharing, device) = match core_ctx.dual_stack_context_mut() {
3252 MaybeDualStack::NotDualStack(nds) => {
3253 let ListenerIpAddr { addr, identifier } =
3254 nds.nds_converter().convert(listener_ip.clone());
3255 let remove_op = SingleStackRemoveOperation::new_from_state(nds, id, socket_state);
3256 core_ctx.with_bound_sockets_mut(|_core_ctx, bound| {
3257 let (sharing, mut device) = remove_op.apply(bound).into_sharing_and_device();
3258 if clear_device_on_disconnect {
3259 device = None;
3260 }
3261 BoundStateHandler::<_, S, _>::try_insert_listener(
3262 bound,
3263 addr,
3264 identifier,
3265 device.clone(),
3266 sharing.clone(),
3267 S::make_bound_socket_map_id(id),
3268 )
3269 .expect("inserting listener for disconnected socket should succeed");
3270 (sharing, device)
3271 })
3272 }
3273 MaybeDualStack::DualStack(ds) => {
3274 let remove_op =
3275 DualStackRemoveOperation::new_from_state(ds, id, ip_options, socket_state);
3276 let other_id = ds.to_other_bound_socket_id(id);
3277 let id = S::make_bound_socket_map_id(id);
3278 let converter = ds.ds_converter();
3279 ds.with_both_bound_sockets_mut(|_core_ctx, bound, other_bound| {
3280 let (sharing, mut device) =
3281 remove_op.apply(bound, other_bound).into_sharing_and_device();
3282 if clear_device_on_disconnect {
3283 device = None;
3284 }
3285
3286 match converter.convert(listener_ip.clone()) {
3287 DualStackListenerIpAddr::ThisStack(ListenerIpAddr { addr, identifier }) => {
3288 BoundStateHandler::<_, S, _>::try_insert_listener(
3289 bound,
3290 addr,
3291 identifier,
3292 device.clone(),
3293 sharing.clone(),
3294 id,
3295 )
3296 }
3297 DualStackListenerIpAddr::OtherStack(ListenerIpAddr { addr, identifier }) => {
3298 BoundStateHandler::<_, S, _>::try_insert_listener(
3299 other_bound,
3300 addr,
3301 identifier,
3302 device.clone(),
3303 sharing.clone(),
3304 other_id,
3305 )
3306 }
3307 DualStackListenerIpAddr::BothStacks(identifier) => {
3308 let ids = PairedBoundSocketIds { this: id, other: other_id };
3309 let mut bound_pair = PairedSocketMapMut { bound, other_bound };
3310 BoundStateHandler::<_, S, _>::try_insert_listener(
3311 &mut bound_pair,
3312 DualStackUnspecifiedAddr,
3313 identifier,
3314 device.clone(),
3315 sharing.clone(),
3316 ids,
3317 )
3318 }
3319 }
3320 .expect("inserting listener for disconnected socket should succeed");
3321 (sharing, device)
3322 })
3323 }
3324 };
3325 BoundSocketState {
3326 original_bound_addr: Some(listener_ip.clone()),
3327 socket_type: BoundSocketStateType::Listener {
3328 state: ListenerState { addr: ListenerAddr { ip: listener_ip, device } },
3329 sharing,
3330 },
3331 }
3332}
3333
3334#[derive(Debug, GenericOverIp, Error)]
3336#[generic_over_ip()]
3337pub enum SendError<SE: Error> {
3338 #[error("socket not connected")]
3340 NotConnected,
3341 #[error("socket not writeable")]
3343 NotWriteable,
3344 #[error("error sending IP packet: {0}")]
3346 IpSock(#[from] IpSockSendError),
3347 #[error("error serializing packet: {0:?}")]
3349 SerializeError(#[source] SE),
3350 #[error("send buffer full")]
3352 SendBufferFull,
3353 #[error("invalid message length")]
3355 InvalidLength,
3356}
3357
3358impl<SE: Error> From<SendBufferError> for SendError<SE> {
3359 fn from(err: SendBufferError) -> Self {
3360 match err {
3361 SendBufferError::SendBufferFull => Self::SendBufferFull,
3362 SendBufferError::InvalidLength => Self::InvalidLength,
3363 }
3364 }
3365}
3366
3367#[derive(Debug, Error)]
3369pub enum SendToError<SE: Error> {
3370 #[error("socket not writeable")]
3372 NotWriteable,
3373 #[error("problem with zone of remote address: {0}")]
3375 Zone(#[from] ZonedAddressError),
3376 #[error("error creating temporary IP socket for send: {0}")]
3379 CreateAndSend(#[from] IpSockCreateAndSendError),
3380 #[error("remote address is mapped, but socket is not dual-stack enabled")]
3383 RemoteUnexpectedlyMapped,
3384 #[error(
3387 "remote address is non-mapped, but socket is \
3388 dual-stack enabled and bound to mapped address"
3389 )]
3390 RemoteUnexpectedlyNonMapped,
3391 #[error("serialize buffer invalid")]
3393 SerializeError(#[source] SE),
3394 #[error("send buffer full")]
3396 SendBufferFull,
3397 #[error("invalid message length")]
3399 InvalidLength,
3400}
3401
3402impl<SE: Error> From<SendBufferError> for SendToError<SE> {
3403 fn from(err: SendBufferError) -> Self {
3404 match err {
3405 SendBufferError::SendBufferFull => Self::SendBufferFull,
3406 SendBufferError::InvalidLength => Self::InvalidLength,
3407 }
3408 }
3409}
3410
3411struct SendOneshotParameters<
3412 'a,
3413 SockI: IpExt,
3414 WireI: IpExt,
3415 S: DatagramSocketSpec,
3416 D: WeakDeviceIdentifier,
3417> {
3418 local_ip: Option<SocketIpAddr<WireI::Addr>>,
3419 local_id: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
3420 remote_ip: ZonedAddr<SocketIpAddr<WireI::Addr>, D::Strong>,
3421 remote_id: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
3422 device: &'a Option<D>,
3423 options: IpOptionsRef<'a, WireI, D>,
3424 id: &'a S::SocketId<SockI, D>,
3425}
3426
3427fn send_oneshot<
3428 SockI: IpExt,
3429 WireI: IpExt,
3430 S: DatagramSocketSpec,
3431 CC: IpSocketHandler<WireI, BC> + CoreTxMetadataContext<TxMetadata<SockI, CC::WeakDeviceId, S>, BC>,
3432 BC: DatagramBindingsContext,
3433 B: BufferMut,
3434>(
3435 core_ctx: &mut CC,
3436 bindings_ctx: &mut BC,
3437 params: SendOneshotParameters<'_, SockI, WireI, S, CC::WeakDeviceId>,
3438 body: B,
3439) -> Result<(), SendToError<S::SerializeError>> {
3440 let SendOneshotParameters { local_ip, local_id, remote_ip, remote_id, device, options, id } =
3441 params;
3442 let device = device.clone().or_else(|| {
3443 remote_ip
3444 .addr()
3445 .addr()
3446 .is_multicast()
3447 .then(|| options.ip_specific.multicast_interface.clone())
3448 .flatten()
3449 });
3450 let (remote_ip, device) = match remote_ip.resolve_addr_with_device(device) {
3451 Ok(addr) => addr,
3452 Err(e) => return Err(SendToError::Zone(e)),
3453 };
3454
3455 let tx_metadata = id.borrow().send_buffer.prepare_for_send::<WireI, _, _, _>(id, &body)?;
3456 let tx_metadata = core_ctx.convert_tx_meta(tx_metadata);
3457
3458 core_ctx
3459 .send_oneshot_ip_packet_with_fallible_serializer(
3460 bindings_ctx,
3461 IpSocketArgs {
3462 device: device.as_ref().map(|d| d.as_ref()),
3463 local_ip: local_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr),
3464 remote_ip,
3465 proto: S::ip_proto::<WireI>(),
3466 options: &options,
3467 },
3468 tx_metadata,
3469 |local_ip| {
3470 S::make_packet::<WireI, _>(
3471 body,
3472 &ConnIpAddr {
3473 local: (local_ip.into(), local_id),
3474 remote: (remote_ip, remote_id),
3475 },
3476 )
3477 },
3478 )
3479 .map_err(|err| match err {
3480 SendOneShotIpPacketError::CreateAndSendError { err } => SendToError::CreateAndSend(err),
3481 SendOneShotIpPacketError::SerializeError(err) => SendToError::SerializeError(err),
3482 })
3483}
3484
3485enum SetBoundDeviceParameters<'a, WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
3488 Listener {
3489 ip: &'a ListenerIpAddr<WireI::Addr, <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
3490 device: &'a mut Option<D>,
3491 },
3492 Connected(&'a mut ConnState<WireI, D, S>),
3493}
3494
3495fn set_bound_device_single_stack<
3505 'a,
3506 WireI: IpExt,
3507 D: WeakDeviceIdentifier,
3508 S: DatagramSocketSpec,
3509 BC: DatagramBindingsContext,
3510 CC: IpSocketHandler<WireI, BC, WeakDeviceId = D, DeviceId = D::Strong>,
3511>(
3512 bindings_ctx: &mut BC,
3513 core_ctx: &mut CC,
3514 params: SetBoundDeviceParameters<'a, WireI, D, S>,
3515 sockets: &mut BoundSocketMap<WireI, D, S::AddrSpec, S::SocketMapSpec<WireI, D>>,
3516 socket_id: &<
3517 S::SocketMapSpec<WireI, D> as DatagramSocketMapSpec<WireI, D, S::AddrSpec>
3518 >::BoundSocketId,
3519 common_ip_options: &DatagramIpAgnosticOptions,
3520 new_device: Option<&D::Strong>,
3521) -> Result<(), SocketError> {
3522 let (local_ip, remote_ip, old_device) = match ¶ms {
3523 SetBoundDeviceParameters::Listener {
3524 ip: ListenerIpAddr { addr, identifier: _ },
3525 device,
3526 } => (addr.as_ref(), None, device.as_ref()),
3527 SetBoundDeviceParameters::Connected(ConnState {
3528 socket: _,
3529 addr:
3530 ConnAddr {
3531 ip: ConnIpAddr { local: (local_ip, _local_id), remote: (remote_ip, _remote_id) },
3532 device,
3533 },
3534 shutdown: _,
3535 clear_device_on_disconnect: _,
3536 extra: _,
3537 }) => (Some(local_ip), Some(remote_ip), device.as_ref()),
3538 };
3539 let device_update = SocketDeviceUpdate {
3542 local_ip: local_ip.map(AsRef::<SpecifiedAddr<WireI::Addr>>::as_ref),
3543 remote_ip: remote_ip.map(AsRef::<SpecifiedAddr<WireI::Addr>>::as_ref),
3544 old_device,
3545 };
3546 match device_update.check_update(new_device) {
3547 Ok(()) => (),
3548 Err(SocketDeviceUpdateNotAllowedError) => {
3549 return Err(SocketError::Local(LocalAddressError::Zone(
3550 ZonedAddressError::DeviceZoneMismatch,
3551 )));
3552 }
3553 };
3554
3555 match params {
3556 SetBoundDeviceParameters::Listener { ip, device } => {
3557 let new_device = new_device.map(|d| d.downgrade());
3558 let old_addr = ListenerAddr { ip: ip.clone(), device: device.clone() };
3559 let new_addr = ListenerAddr { ip: ip.clone(), device: new_device.clone() };
3560 let entry = sockets
3561 .listeners_mut()
3562 .entry(socket_id, &old_addr)
3563 .unwrap_or_else(|| panic!("invalid listener ID {:?}", socket_id));
3564 let _entry = entry
3565 .try_update_addr(new_addr)
3566 .map_err(|(ExistsError {}, _entry)| LocalAddressError::AddressInUse)?;
3567 *device = new_device
3568 }
3569 SetBoundDeviceParameters::Connected(ConnState {
3570 socket,
3571 addr,
3572 shutdown: _,
3573 clear_device_on_disconnect,
3574 extra: _,
3575 }) => {
3576 let ConnAddr { ip, device } = addr;
3577 let ConnIpAddr { local: (local_ip, _local_id), remote: (remote_ip, _remote_id) } = ip;
3578 let new_socket = core_ctx
3579 .new_ip_socket(
3580 bindings_ctx,
3581 IpSocketArgs {
3582 device: new_device.map(EitherDeviceId::Strong),
3583 local_ip: IpDeviceAddr::new_from_socket_ip_addr(local_ip.clone()),
3584 remote_ip: remote_ip.clone(),
3585 proto: socket.proto(),
3586 options: common_ip_options,
3587 },
3588 )
3589 .map_err(|_: IpSockCreationError| {
3590 SocketError::Remote(RemoteAddressError::NoRoute)
3591 })?;
3592 let new_device = new_socket.device().cloned();
3593 let old_addr = ConnAddr { ip: ip.clone(), device: device.clone() };
3594 let entry = sockets
3595 .conns_mut()
3596 .entry(socket_id, &old_addr)
3597 .unwrap_or_else(|| panic!("invalid conn id {:?}", socket_id));
3598 let new_addr = ConnAddr { ip: ip.clone(), device: new_device.clone() };
3599 let entry = entry
3600 .try_update_addr(new_addr)
3601 .map_err(|(ExistsError {}, _entry)| LocalAddressError::AddressInUse)?;
3602 *socket = new_socket;
3603 if new_device.is_some() {
3606 *clear_device_on_disconnect = false;
3607 }
3608 *addr = entry.get_addr().clone()
3609 }
3610 }
3611 Ok(())
3612}
3613
3614fn set_bound_device_listener_both_stacks<
3623 'a,
3624 I: IpExt,
3625 D: WeakDeviceIdentifier,
3626 S: DatagramSocketSpec,
3627>(
3628 old_device: &mut Option<D>,
3629 local_id: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
3630 PairedSocketMapMut { bound: sockets, other_bound: other_sockets }: PairedSocketMapMut<
3631 'a,
3632 I,
3633 D,
3634 S,
3635 >,
3636 PairedBoundSocketIds { this: socket_id, other: other_socket_id }: PairedBoundSocketIds<I, D, S>,
3637 new_device: Option<D>,
3638) -> Result<(), SocketError> {
3639 fn try_update_entry<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
3640 old_device: Option<D>,
3641 new_device: Option<D>,
3642 sockets: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
3643 socket_id: &<
3644 S::SocketMapSpec<I, D> as DatagramSocketMapSpec<I, D, S::AddrSpec>
3645 >::BoundSocketId,
3646 local_id: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
3647 ) -> Result<(), SocketError> {
3648 let old_addr = ListenerAddr {
3649 ip: ListenerIpAddr { addr: None, identifier: local_id },
3650 device: old_device,
3651 };
3652 let entry = sockets
3653 .listeners_mut()
3654 .entry(socket_id, &old_addr)
3655 .unwrap_or_else(|| panic!("invalid listener ID {:?}", socket_id));
3656 let new_addr = ListenerAddr {
3657 ip: ListenerIpAddr { addr: None, identifier: local_id },
3658 device: new_device,
3659 };
3660 let _entry = entry
3661 .try_update_addr(new_addr)
3662 .map_err(|(ExistsError {}, _entry)| LocalAddressError::AddressInUse)?;
3663 return Ok(());
3664 }
3665
3666 try_update_entry::<_, _, S>(
3668 old_device.clone(),
3669 new_device.clone(),
3670 sockets,
3671 &socket_id,
3672 local_id,
3673 )?;
3674
3675 let result = try_update_entry::<_, _, S>(
3677 old_device.clone(),
3678 new_device.clone(),
3679 other_sockets,
3680 &other_socket_id,
3681 local_id,
3682 );
3683
3684 if let Err(e) = result {
3685 try_update_entry::<_, _, S>(new_device, old_device.clone(), sockets, &socket_id, local_id)
3689 .expect("failed to rollback listener in this stack to it's original device");
3690 return Err(e);
3691 }
3692 *old_device = new_device;
3693 return Ok(());
3694}
3695
3696#[derive(Copy, Clone, Debug, Eq, PartialEq, Error)]
3699pub enum SetMulticastMembershipError {
3700 #[error("provided address does not match the provided device")]
3702 AddressNotAvailable,
3703 #[error("device does not exist")]
3705 DeviceDoesNotExist,
3706 #[error("provided address does not match any address on the host")]
3708 NoDeviceWithAddress,
3709 #[error(
3712 "no device or address was specified and \
3713 there is no device with a route to the multicast address"
3714 )]
3715 NoDeviceAvailable,
3716 #[error("tried to join a group again")]
3718 GroupAlreadyJoined,
3719 #[error("tried to leave an unjoined group")]
3721 GroupNotJoined,
3722 #[error("socket is bound to a device that doesn't match the one specified")]
3724 WrongDevice,
3725}
3726
3727fn pick_interface_for_addr<
3730 A: IpAddress,
3731 S: DatagramSocketSpec,
3732 BC: DatagramBindingsContext,
3733 CC: DatagramBoundStateContext<A::Version, BC, S>,
3734>(
3735 core_ctx: &mut CC,
3736 remote_addr: MulticastAddr<A>,
3737 source_addr: Option<SpecifiedAddr<A>>,
3738 marks: &Marks,
3739) -> Result<CC::DeviceId, SetMulticastMembershipError>
3740where
3741 A::Version: IpExt,
3742{
3743 core_ctx.with_transport_context(|core_ctx| match source_addr {
3744 Some(source_addr) => {
3745 BaseTransportIpContext::<A::Version, _>::with_devices_with_assigned_addr(
3746 core_ctx,
3747 source_addr,
3748 |mut devices| {
3749 if let Some(d) = devices.next() {
3750 if devices.next() == None {
3751 return Ok(d);
3752 }
3753 }
3754 Err(SetMulticastMembershipError::NoDeviceAvailable)
3755 },
3756 )
3757 }
3758 None => {
3759 let device = MulticastMembershipHandler::select_device_for_multicast_group(
3760 core_ctx,
3761 remote_addr,
3762 marks,
3763 )
3764 .map_err(|e| match e {
3765 ResolveRouteError::NoSrcAddr | ResolveRouteError::Unreachable => {
3766 SetMulticastMembershipError::NoDeviceAvailable
3767 }
3768 })?;
3769 Ok(device)
3770 }
3771 })
3772}
3773
3774#[derive(Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
3776#[generic_over_ip(A, IpAddress)]
3777pub enum MulticastInterfaceSelector<A: IpAddress, D> {
3778 LocalAddress(SpecifiedAddr<A>),
3780 Interface(D),
3782}
3783
3784#[derive(Copy, Clone, Debug, Eq, PartialEq, GenericOverIp)]
3789#[generic_over_ip(A, IpAddress)]
3790pub enum MulticastMembershipInterfaceSelector<A: IpAddress, D> {
3791 Specified(MulticastInterfaceSelector<A, D>),
3793 AnyInterfaceWithRoute,
3795}
3796
3797impl<A: IpAddress, D> From<MulticastInterfaceSelector<A, D>>
3798 for MulticastMembershipInterfaceSelector<A, D>
3799{
3800 fn from(selector: MulticastInterfaceSelector<A, D>) -> Self {
3801 Self::Specified(selector)
3802 }
3803}
3804
3805#[derive(RefCast)]
3807#[repr(transparent)]
3808pub struct DatagramApi<I, C, S>(C, PhantomData<(S, I)>);
3809
3810impl<I, C, S> DatagramApi<I, C, S> {
3811 pub fn new(ctx: C) -> Self {
3813 Self(ctx, PhantomData)
3814 }
3815
3816 pub fn wrap(ctx: &mut C) -> &mut Self {
3819 Self::ref_cast_mut(ctx)
3820 }
3821}
3822
3823type DatagramApiSocketId<I, C, S> = <S as DatagramSocketSpec>::SocketId<
3829 I,
3830 <<C as ContextPair>::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId,
3831>;
3832type DatagramApiDeviceId<C> =
3838 <<C as ContextPair>::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId;
3839type DatagramApiWeakDeviceId<C> =
3845 <<C as ContextPair>::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId;
3846
3847impl<I, C, S> DatagramApi<I, C, S>
3848where
3849 I: IpExt,
3850 C: ContextPair,
3851 C::BindingsContext: DatagramBindingsContext + SettingsContext<S::Settings>,
3852 C::CoreContext: DatagramStateContext<I, C::BindingsContext, S>,
3853 S: DatagramSocketSpec,
3854{
3855 fn core_ctx(&mut self) -> &mut C::CoreContext {
3856 let Self(pair, PhantomData) = self;
3857 pair.core_ctx()
3858 }
3859
3860 fn bindings_ctx(&mut self) -> &mut C::BindingsContext {
3861 let Self(pair, PhantomData) = self;
3862 pair.bindings_ctx()
3863 }
3864
3865 fn contexts(&mut self) -> (&mut C::CoreContext, &mut C::BindingsContext) {
3866 let Self(pair, PhantomData) = self;
3867 pair.contexts()
3868 }
3869
3870 pub fn create(
3876 &mut self,
3877 external_data: S::ExternalData<I>,
3878 writable_listener: S::SocketWritableListener,
3879 ) -> S::SocketId<I, DatagramApiWeakDeviceId<C>> {
3880 let primary = {
3881 let settings = self.bindings_ctx().settings();
3882 create_primary_id(external_data, writable_listener, settings.as_ref())
3883 };
3884 let strong = PrimaryRc::clone_strong(&primary);
3885 self.core_ctx().with_all_sockets_mut(move |socket_set| {
3886 let strong = PrimaryRc::clone_strong(&primary);
3887 assert_matches::assert_matches!(socket_set.insert(strong, primary), None);
3888 });
3889 strong.into()
3890 }
3891
3892 #[cfg(any(test, feature = "testutils"))]
3894 pub fn create_default(&mut self) -> S::SocketId<I, DatagramApiWeakDeviceId<C>>
3895 where
3896 S::ExternalData<I>: Default,
3897 S::SocketWritableListener: Default,
3898 {
3899 self.create(Default::default(), Default::default())
3900 }
3901
3902 pub fn collect_all_sockets(&mut self) -> Vec<S::SocketId<I, DatagramApiWeakDeviceId<C>>> {
3904 self.core_ctx()
3905 .with_all_sockets(|socket_set| socket_set.keys().map(|s| s.clone().into()).collect())
3906 }
3907
3908 pub fn close(
3910 &mut self,
3911 id: DatagramApiSocketId<I, C, S>,
3912 ) -> RemoveResourceResultWithContext<S::ExternalData<I>, C::BindingsContext> {
3913 let (core_ctx, bindings_ctx) = self.contexts();
3914 let primary = core_ctx.with_all_sockets_mut(|all_sockets| {
3916 all_sockets.remove(id.borrow()).expect("socket already closed")
3917 });
3918 core_ctx.with_socket_state(&id, |core_ctx, state| {
3919 let SocketState { ip_options, inner } = state;
3920 match inner {
3921 SocketStateInner::Unbound(UnboundSocketState { device: _, sharing: _ }) => {}
3922 SocketStateInner::Bound(state) => match core_ctx.dual_stack_context_mut() {
3923 MaybeDualStack::DualStack(dual_stack) => {
3924 let op = DualStackRemoveOperation::new_from_state(
3925 dual_stack, &id, ip_options, state,
3926 );
3927 let _: DualStackRemoveInfo<_, _, _> = dual_stack
3928 .with_both_bound_sockets_mut(|_core_ctx, sockets, other_sockets| {
3929 op.apply(sockets, other_sockets)
3930 });
3931 }
3932 MaybeDualStack::NotDualStack(not_dual_stack) => {
3933 let op =
3934 SingleStackRemoveOperation::new_from_state(not_dual_stack, &id, state);
3935 let _: SingleStackRemoveInfo<_, _, _> =
3936 core_ctx.with_bound_sockets_mut(|_core_ctx, sockets| op.apply(sockets));
3937 }
3938 },
3939 };
3940 DatagramBoundStateContext::<I, _, _>::with_transport_context(core_ctx, |core_ctx| {
3941 leave_all_joined_groups(core_ctx, bindings_ctx, &ip_options.multicast_memberships)
3942 });
3943 });
3944 core::mem::drop(id);
3947 <C::BindingsContext as ReferenceNotifiersExt>::unwrap_or_notify_with_new_reference_notifier(
3948 primary,
3949 |ReferenceState { external_data, .. }| external_data,
3950 )
3951 }
3952
3953 pub fn get_info(
3955 &mut self,
3956 id: &DatagramApiSocketId<I, C, S>,
3957 ) -> SocketInfo<I::Addr, DatagramApiWeakDeviceId<C>> {
3958 self.core_ctx().with_socket_state(id, |_core_ctx, state| state.to_socket_info())
3959 }
3960
3961 pub fn listen(
3963 &mut self,
3964 id: &DatagramApiSocketId<I, C, S>,
3965 addr: Option<ZonedAddr<SpecifiedAddr<I::Addr>, DatagramApiDeviceId<C>>>,
3966 local_id: Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
3967 ) -> Result<(), Either<ExpectedUnboundError, LocalAddressError>> {
3968 let (core_ctx, bindings_ctx) = self.contexts();
3969 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
3970 listen_inner::<_, _, _, S>(core_ctx, bindings_ctx, state, id, addr, local_id)
3971 })
3972 }
3973
3974 pub fn connect(
3976 &mut self,
3977 id: &DatagramApiSocketId<I, C, S>,
3978 remote_ip: Option<ZonedAddr<SpecifiedAddr<I::Addr>, DatagramApiDeviceId<C>>>,
3979 remote_id: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
3980 extra: S::ConnStateExtra,
3981 ) -> Result<(), ConnectError> {
3982 let (core_ctx, bindings_ctx) = self.contexts();
3983 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
3984 let (conn_state, sharing) = match (
3985 core_ctx.dual_stack_context_mut(),
3986 DualStackRemoteIp::<I, _>::new(remote_ip.clone()),
3987 ) {
3988 (MaybeDualStack::DualStack(ds), remote_ip) => {
3989 let connect_op = DualStackConnectOperation::new_from_state(
3990 ds, id, state, remote_ip, remote_id, extra,
3991 )?;
3992 let converter = ds.ds_converter();
3993 let (conn_state, sharing) =
3994 ds.with_both_bound_sockets_mut(|core_ctx, bound, other_bound| {
3995 connect_op.apply(core_ctx, bindings_ctx, bound, other_bound)
3996 })?;
3997 Ok((converter.convert_back(conn_state), sharing))
3998 }
3999 (MaybeDualStack::NotDualStack(nds), DualStackRemoteIp::ThisStack(remote_ip)) => {
4000 let connect_op = SingleStackConnectOperation::new_from_state(
4001 nds, id, state, remote_ip, remote_id, extra,
4002 );
4003 let converter = nds.nds_converter();
4004 let (conn_state, sharing) =
4005 core_ctx.with_bound_sockets_mut(|core_ctx, bound| {
4006 connect_op.apply(core_ctx, bindings_ctx, bound)
4007 })?;
4008 Ok((converter.convert_back(conn_state), sharing))
4009 }
4010 (MaybeDualStack::NotDualStack(_), DualStackRemoteIp::OtherStack(_)) => {
4011 Err(ConnectError::RemoteUnexpectedlyMapped)
4012 }
4013 }?;
4014 let original_bound_addr = match &state.inner {
4015 SocketStateInner::Unbound(_) => None,
4016 SocketStateInner::Bound(BoundSocketState {
4017 socket_type: _,
4018 original_bound_addr,
4019 }) => original_bound_addr.clone(),
4020 };
4021 state.inner = SocketStateInner::Bound(BoundSocketState {
4022 socket_type: BoundSocketStateType::Connected { state: conn_state, sharing },
4023 original_bound_addr,
4024 });
4025 Ok(())
4026 })
4027 }
4028
4029 pub fn disconnect_connected(
4031 &mut self,
4032 id: &DatagramApiSocketId<I, C, S>,
4033 ) -> Result<(), ExpectedConnError> {
4034 self.core_ctx().with_socket_state_mut(id, |core_ctx, state| {
4035 let SocketState { ip_options, inner } = state;
4036 let inner_state = match inner {
4037 SocketStateInner::Unbound(_) => return Err(ExpectedConnError),
4038 SocketStateInner::Bound(state) => state,
4039 };
4040 let BoundSocketState { socket_type, original_bound_addr } = inner_state;
4041 let conn_state = match socket_type {
4042 BoundSocketStateType::Listener { state: _, sharing: _ } => {
4043 return Err(ExpectedConnError);
4044 }
4045 BoundSocketStateType::Connected { state, sharing: _ } => state,
4046 };
4047
4048 let clear_device_on_disconnect = match core_ctx.dual_stack_context_mut() {
4049 MaybeDualStack::DualStack(dual_stack) => {
4050 match dual_stack.ds_converter().convert(conn_state) {
4051 DualStackConnState::ThisStack(conn_state) => {
4052 conn_state.clear_device_on_disconnect
4053 }
4054 DualStackConnState::OtherStack(conn_state) => {
4055 conn_state.clear_device_on_disconnect
4056 }
4057 }
4058 }
4059 MaybeDualStack::NotDualStack(not_dual_stack) => {
4060 not_dual_stack.nds_converter().convert(conn_state).clear_device_on_disconnect
4061 }
4062 };
4063
4064 state.inner = match original_bound_addr {
4065 None => SocketStateInner::Unbound(disconnect_to_unbound(
4066 core_ctx,
4067 id,
4068 clear_device_on_disconnect,
4069 &state.ip_options,
4070 inner_state,
4071 )),
4072 Some(original_bound_addr) => SocketStateInner::Bound(disconnect_to_listener(
4073 core_ctx,
4074 id,
4075 original_bound_addr.clone(),
4076 clear_device_on_disconnect,
4077 &ip_options,
4078 inner_state,
4079 )),
4080 };
4081 Ok(())
4082 })
4083 }
4084
4085 pub fn get_shutdown_connected(
4087 &mut self,
4088 id: &DatagramApiSocketId<I, C, S>,
4089 ) -> Option<ShutdownType> {
4090 self.core_ctx().with_socket_state(id, |core_ctx, state| {
4091 let state = match &state.inner {
4092 SocketStateInner::Unbound(_) => return None,
4093 SocketStateInner::Bound(BoundSocketState {
4094 socket_type,
4095 original_bound_addr: _,
4096 }) => match socket_type {
4097 BoundSocketStateType::Listener { state: _, sharing: _ } => return None,
4098 BoundSocketStateType::Connected { state, sharing: _ } => state,
4099 },
4100 };
4101 let Shutdown { send, receive } = match core_ctx.dual_stack_context_mut() {
4102 MaybeDualStack::DualStack(ds) => ds.ds_converter().convert(state).as_ref(),
4103 MaybeDualStack::NotDualStack(nds) => nds.nds_converter().convert(state).as_ref(),
4104 };
4105 ShutdownType::from_send_receive(*send, *receive)
4106 })
4107 }
4108
4109 pub fn shutdown_connected(
4113 &mut self,
4114 id: &DatagramApiSocketId<I, C, S>,
4115 which: ShutdownType,
4116 ) -> Result<(), ExpectedConnError> {
4117 self.core_ctx().with_socket_state_mut(id, |core_ctx, state| {
4118 let state = match &mut state.inner {
4119 SocketStateInner::Unbound(_) => return Err(ExpectedConnError),
4120 SocketStateInner::Bound(BoundSocketState {
4121 socket_type,
4122 original_bound_addr: _,
4123 }) => match socket_type {
4124 BoundSocketStateType::Listener { state: _, sharing: _ } => {
4125 return Err(ExpectedConnError);
4126 }
4127 BoundSocketStateType::Connected { state, sharing: _ } => state,
4128 },
4129 };
4130 let (shutdown_send, shutdown_receive) = which.to_send_receive();
4131 let Shutdown { send, receive } = match core_ctx.dual_stack_context_mut() {
4132 MaybeDualStack::DualStack(ds) => ds.ds_converter().convert(state).as_mut(),
4133 MaybeDualStack::NotDualStack(nds) => nds.nds_converter().convert(state).as_mut(),
4134 };
4135 *send |= shutdown_send;
4136 *receive |= shutdown_receive;
4137 Ok(())
4138 })
4139 }
4140
4141 pub fn send_conn<B: BufferMut>(
4143 &mut self,
4144 id: &DatagramApiSocketId<I, C, S>,
4145 body: B,
4146 ) -> Result<(), SendError<S::SerializeError>> {
4147 let (core_ctx, bindings_ctx) = self.contexts();
4148 core_ctx.with_socket_state(id, |core_ctx, state| {
4149 let SocketState { inner, ip_options } = state;
4150 let state = match inner {
4151 SocketStateInner::Unbound(_) => return Err(SendError::NotConnected),
4152 SocketStateInner::Bound(BoundSocketState {
4153 socket_type,
4154 original_bound_addr: _,
4155 }) => match socket_type {
4156 BoundSocketStateType::Listener { state: _, sharing: _ } => {
4157 return Err(SendError::NotConnected);
4158 }
4159 BoundSocketStateType::Connected { state, sharing: _ } => state,
4160 },
4161 };
4162
4163 struct SendParams<
4164 'a,
4165 I: IpExt,
4166 S: DatagramSocketSpec,
4167 D: WeakDeviceIdentifier,
4168 O: SendOptions<I> + RouteResolutionOptions<I>,
4169 > {
4170 socket: &'a IpSock<I, D>,
4171 ip: &'a ConnIpAddr<
4172 I::Addr,
4173 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
4174 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
4175 >,
4176 options: O,
4177 }
4178
4179 enum Operation<
4180 'a,
4181 I: DualStackIpExt,
4182 S: DatagramSocketSpec,
4183 D: WeakDeviceIdentifier,
4184 BC: DatagramBindingsContext,
4185 DualStackSC: DualStackDatagramBoundStateContext<I, BC, S>,
4186 CC: DatagramBoundStateContext<I, BC, S>,
4187 O: SendOptions<I> + RouteResolutionOptions<I>,
4188 OtherO: SendOptions<I::OtherVersion> + RouteResolutionOptions<I::OtherVersion>,
4189 > {
4190 SendToThisStack((SendParams<'a, I, S, D, O>, &'a mut CC)),
4191 SendToOtherStack(
4192 (SendParams<'a, I::OtherVersion, S, D, OtherO>, &'a mut DualStackSC),
4193 ),
4194 _Phantom((Never, PhantomData<BC>)),
4197 }
4198
4199 let (shutdown, operation) = match core_ctx.dual_stack_context_mut() {
4200 MaybeDualStack::DualStack(dual_stack) => {
4201 match dual_stack.ds_converter().convert(state) {
4202 DualStackConnState::ThisStack(ConnState {
4203 socket,
4204 clear_device_on_disconnect: _,
4205 shutdown,
4206 addr: ConnAddr { ip, device: _ },
4207 extra: _,
4208 }) => (
4209 shutdown,
4210 Operation::SendToThisStack((
4211 SendParams {
4212 socket,
4213 ip,
4214 options: ip_options.this_stack_options_ref(),
4215 },
4216 core_ctx,
4217 )),
4218 ),
4219 DualStackConnState::OtherStack(ConnState {
4220 socket,
4221 clear_device_on_disconnect: _,
4222 shutdown,
4223 addr: ConnAddr { ip, device: _ },
4224 extra: _,
4225 }) => (
4226 shutdown,
4227 Operation::SendToOtherStack((
4228 SendParams {
4229 socket,
4230 ip,
4231 options: ip_options.other_stack_options_ref(dual_stack),
4232 },
4233 dual_stack,
4234 )),
4235 ),
4236 }
4237 }
4238 MaybeDualStack::NotDualStack(not_dual_stack) => {
4239 let ConnState {
4240 socket,
4241 clear_device_on_disconnect: _,
4242 shutdown,
4243 addr: ConnAddr { ip, device: _ },
4244 extra: _,
4245 } = not_dual_stack.nds_converter().convert(state);
4246 (
4247 shutdown,
4248 Operation::SendToThisStack((
4249 SendParams { socket, ip, options: ip_options.this_stack_options_ref() },
4250 core_ctx,
4251 )),
4252 )
4253 }
4254 };
4255
4256 let Shutdown { send: shutdown_send, receive: _ } = shutdown;
4257 if *shutdown_send {
4258 return Err(SendError::NotWriteable);
4259 }
4260
4261 match operation {
4262 Operation::SendToThisStack((SendParams { socket, ip, options }, core_ctx)) => {
4263 let tx_metadata =
4264 id.borrow().send_buffer.prepare_for_send::<I, _, _, _>(id, &body)?;
4265 let packet =
4266 S::make_packet::<I, _>(body, &ip).map_err(SendError::SerializeError)?;
4267 DatagramBoundStateContext::with_transport_context(core_ctx, |core_ctx| {
4268 let tx_metadata = core_ctx.convert_tx_meta(tx_metadata);
4269 core_ctx
4270 .send_ip_packet(bindings_ctx, &socket, packet, &options, tx_metadata)
4271 .map_err(|send_error| SendError::IpSock(send_error))
4272 })
4273 }
4274 Operation::SendToOtherStack((SendParams { socket, ip, options }, dual_stack)) => {
4275 let tx_metadata = id
4276 .borrow()
4277 .send_buffer
4278 .prepare_for_send::<I::OtherVersion, _, _, _>(id, &body)?;
4279 let packet = S::make_packet::<I::OtherVersion, _>(body, &ip)
4280 .map_err(SendError::SerializeError)?;
4281 DualStackDatagramBoundStateContext::with_transport_context::<_, _>(
4282 dual_stack,
4283 |core_ctx| {
4284 let tx_metadata = core_ctx.convert_tx_meta(tx_metadata);
4285 core_ctx
4286 .send_ip_packet(
4287 bindings_ctx,
4288 &socket,
4289 packet,
4290 &options,
4291 tx_metadata,
4292 )
4293 .map_err(|send_error| SendError::IpSock(send_error))
4294 },
4295 )
4296 }
4297 }
4298 })
4299 }
4300
4301 pub fn send_to<B: BufferMut>(
4303 &mut self,
4304 id: &DatagramApiSocketId<I, C, S>,
4305 remote_ip: Option<ZonedAddr<SpecifiedAddr<I::Addr>, DatagramApiDeviceId<C>>>,
4306 remote_identifier: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
4307 body: B,
4308 ) -> Result<(), Either<LocalAddressError, SendToError<S::SerializeError>>> {
4309 let (core_ctx, bindings_ctx) = self.contexts();
4310 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
4311 match listen_inner(core_ctx, bindings_ctx, state, id, None, None) {
4312 Ok(()) | Err(Either::Left(ExpectedUnboundError)) => (),
4313 Err(Either::Right(e)) => return Err(Either::Left(e)),
4314 };
4315 let SocketState { inner, ip_options } = state;
4316 let state = match inner {
4317 SocketStateInner::Unbound(_) => panic!("expected bound socket"),
4318 SocketStateInner::Bound(BoundSocketState {
4319 socket_type: state,
4320 original_bound_addr: _,
4321 }) => state,
4322 };
4323
4324 enum Operation<
4325 'a,
4326 I: DualStackIpExt,
4327 S: DatagramSocketSpec,
4328 D: WeakDeviceIdentifier,
4329 BC: DatagramBindingsContext,
4330 DualStackSC: DualStackDatagramBoundStateContext<I, BC, S>,
4331 CC: DatagramBoundStateContext<I, BC, S>,
4332 > {
4333 SendToThisStack((SendOneshotParameters<'a, I, I, S, D>, &'a mut CC)),
4334
4335 SendToOtherStack(
4336 (SendOneshotParameters<'a, I, I::OtherVersion, S, D>, &'a mut DualStackSC),
4337 ),
4338 _Phantom((Never, PhantomData<BC>)),
4341 }
4342
4343 let (operation, shutdown) = match (
4344 core_ctx.dual_stack_context_mut(),
4345 DualStackRemoteIp::<I, _>::new(remote_ip.clone()),
4346 ) {
4347 (MaybeDualStack::NotDualStack(_), DualStackRemoteIp::OtherStack(_)) => {
4348 return Err(Either::Right(SendToError::RemoteUnexpectedlyMapped));
4349 }
4350 (MaybeDualStack::NotDualStack(nds), DualStackRemoteIp::ThisStack(remote_ip)) => {
4351 match state {
4352 BoundSocketStateType::Listener {
4353 state: ListenerState { addr: ListenerAddr { ip, device } },
4354 sharing: _,
4355 } => {
4356 let ListenerIpAddr { addr, identifier } =
4357 nds.nds_converter().convert(ip.clone());
4358 (
4359 Operation::SendToThisStack((
4360 SendOneshotParameters {
4361 local_ip: addr,
4362 local_id: identifier,
4363 remote_ip,
4364 remote_id: remote_identifier,
4365 device,
4366 options: ip_options.this_stack_options_ref(),
4367 id,
4368 },
4369 core_ctx,
4370 )),
4371 None,
4372 )
4373 }
4374 BoundSocketStateType::Connected { state, sharing: _ } => {
4375 let ConnState {
4376 socket: _,
4377 clear_device_on_disconnect: _,
4378 shutdown,
4379 addr:
4380 ConnAddr {
4381 ip: ConnIpAddr { local: (local_ip, local_id), remote: _ },
4382 device,
4383 },
4384 extra: _,
4385 } = nds.nds_converter().convert(state);
4386 (
4387 Operation::SendToThisStack((
4388 SendOneshotParameters {
4389 local_ip: Some(*local_ip),
4390 local_id: *local_id,
4391 remote_ip,
4392 remote_id: remote_identifier,
4393 device,
4394 options: ip_options.this_stack_options_ref(),
4395 id,
4396 },
4397 core_ctx,
4398 )),
4399 Some(shutdown),
4400 )
4401 }
4402 }
4403 }
4404 (MaybeDualStack::DualStack(ds), remote_ip) => match state {
4405 BoundSocketStateType::Listener {
4406 state: ListenerState { addr: ListenerAddr { ip, device } },
4407 sharing: _,
4408 } => match (ds.ds_converter().convert(ip), remote_ip) {
4409 (
4410 DualStackListenerIpAddr::ThisStack(_),
4411 DualStackRemoteIp::OtherStack(_),
4412 ) => return Err(Either::Right(SendToError::RemoteUnexpectedlyMapped)),
4413 (
4414 DualStackListenerIpAddr::OtherStack(_),
4415 DualStackRemoteIp::ThisStack(_),
4416 ) => return Err(Either::Right(SendToError::RemoteUnexpectedlyNonMapped)),
4417 (
4418 DualStackListenerIpAddr::ThisStack(ListenerIpAddr { addr, identifier }),
4419 DualStackRemoteIp::ThisStack(remote_ip),
4420 ) => (
4421 Operation::SendToThisStack((
4422 SendOneshotParameters {
4423 local_ip: *addr,
4424 local_id: *identifier,
4425 remote_ip,
4426 remote_id: remote_identifier,
4427 device,
4428 options: ip_options.this_stack_options_ref(),
4429 id,
4430 },
4431 core_ctx,
4432 )),
4433 None,
4434 ),
4435 (
4436 DualStackListenerIpAddr::BothStacks(identifier),
4437 DualStackRemoteIp::ThisStack(remote_ip),
4438 ) => (
4439 Operation::SendToThisStack((
4440 SendOneshotParameters {
4441 local_ip: None,
4442 local_id: *identifier,
4443 remote_ip,
4444 remote_id: remote_identifier,
4445 device,
4446 options: ip_options.this_stack_options_ref(),
4447 id,
4448 },
4449 core_ctx,
4450 )),
4451 None,
4452 ),
4453 (
4454 DualStackListenerIpAddr::OtherStack(ListenerIpAddr {
4455 addr,
4456 identifier,
4457 }),
4458 DualStackRemoteIp::OtherStack(remote_ip),
4459 ) => (
4460 Operation::SendToOtherStack((
4461 SendOneshotParameters {
4462 local_ip: *addr,
4463 local_id: *identifier,
4464 remote_ip,
4465 remote_id: remote_identifier,
4466 device,
4467 options: ip_options.other_stack_options_ref(ds),
4468 id,
4469 },
4470 ds,
4471 )),
4472 None,
4473 ),
4474 (
4475 DualStackListenerIpAddr::BothStacks(identifier),
4476 DualStackRemoteIp::OtherStack(remote_ip),
4477 ) => (
4478 Operation::SendToOtherStack((
4479 SendOneshotParameters {
4480 local_ip: None,
4481 local_id: *identifier,
4482 remote_ip,
4483 remote_id: remote_identifier,
4484 device,
4485 options: ip_options.other_stack_options_ref(ds),
4486 id,
4487 },
4488 ds,
4489 )),
4490 None,
4491 ),
4492 },
4493 BoundSocketStateType::Connected { state, sharing: _ } => {
4494 match (ds.ds_converter().convert(state), remote_ip) {
4495 (
4496 DualStackConnState::ThisStack(_),
4497 DualStackRemoteIp::OtherStack(_),
4498 ) => return Err(Either::Right(SendToError::RemoteUnexpectedlyMapped)),
4499 (
4500 DualStackConnState::OtherStack(_),
4501 DualStackRemoteIp::ThisStack(_),
4502 ) => {
4503 return Err(Either::Right(
4504 SendToError::RemoteUnexpectedlyNonMapped,
4505 ));
4506 }
4507 (
4508 DualStackConnState::ThisStack(state),
4509 DualStackRemoteIp::ThisStack(remote_ip),
4510 ) => {
4511 let ConnState {
4512 socket: _,
4513 clear_device_on_disconnect: _,
4514 shutdown,
4515 addr,
4516 extra: _,
4517 } = state;
4518 let ConnAddr {
4519 ip: ConnIpAddr { local: (local_ip, local_id), remote: _ },
4520 device,
4521 } = addr;
4522 (
4523 Operation::SendToThisStack((
4524 SendOneshotParameters {
4525 local_ip: Some(*local_ip),
4526 local_id: *local_id,
4527 remote_ip,
4528 remote_id: remote_identifier,
4529 device,
4530 options: ip_options.this_stack_options_ref(),
4531 id,
4532 },
4533 core_ctx,
4534 )),
4535 Some(shutdown),
4536 )
4537 }
4538 (
4539 DualStackConnState::OtherStack(state),
4540 DualStackRemoteIp::OtherStack(remote_ip),
4541 ) => {
4542 let ConnState {
4543 socket: _,
4544 clear_device_on_disconnect: _,
4545 shutdown,
4546 addr,
4547 extra: _,
4548 } = state;
4549 let ConnAddr {
4550 ip: ConnIpAddr { local: (local_ip, local_id), .. },
4551 device,
4552 } = addr;
4553 (
4554 Operation::SendToOtherStack((
4555 SendOneshotParameters {
4556 local_ip: Some(*local_ip),
4557 local_id: *local_id,
4558 remote_ip,
4559 remote_id: remote_identifier,
4560 device,
4561 options: ip_options.other_stack_options_ref(ds),
4562 id,
4563 },
4564 ds,
4565 )),
4566 Some(shutdown),
4567 )
4568 }
4569 }
4570 }
4571 },
4572 };
4573
4574 if let Some(Shutdown { send: shutdown_write, receive: _ }) = shutdown {
4575 if *shutdown_write {
4576 return Err(Either::Right(SendToError::NotWriteable));
4577 }
4578 }
4579
4580 match operation {
4581 Operation::SendToThisStack((params, core_ctx)) => {
4582 DatagramBoundStateContext::with_transport_context(core_ctx, |core_ctx| {
4583 send_oneshot(core_ctx, bindings_ctx, params, body)
4584 })
4585 }
4586 Operation::SendToOtherStack((params, core_ctx)) => {
4587 DualStackDatagramBoundStateContext::with_transport_context::<_, _>(
4588 core_ctx,
4589 |core_ctx| send_oneshot(core_ctx, bindings_ctx, params, body),
4590 )
4591 }
4592 }
4593 .map_err(Either::Right)
4594 })
4595 }
4596
4597 pub fn get_bound_device(
4599 &mut self,
4600 id: &DatagramApiSocketId<I, C, S>,
4601 ) -> Option<DatagramApiWeakDeviceId<C>> {
4602 self.core_ctx().with_socket_state(id, |core_ctx, state| {
4603 let (_, device): (&IpOptions<_, _, _>, _) = state.get_options_device(core_ctx);
4604 device.clone()
4605 })
4606 }
4607
4608 pub fn set_device(
4610 &mut self,
4611 id: &DatagramApiSocketId<I, C, S>,
4612 new_device: Option<&DatagramApiDeviceId<C>>,
4613 ) -> Result<(), SocketError> {
4614 let (core_ctx, bindings_ctx) = self.contexts();
4615 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
4616 let SocketState { inner, ip_options } = state;
4617 match inner {
4618 SocketStateInner::Unbound(state) => {
4619 let UnboundSocketState { device, sharing: _ } = state;
4620 *device = new_device.map(|d| d.downgrade());
4621 Ok(())
4622 }
4623 SocketStateInner::Bound(BoundSocketState {
4624 socket_type,
4625 original_bound_addr: _,
4626 }) => {
4627 enum Operation<
4630 'a,
4631 I: IpExt,
4632 D: WeakDeviceIdentifier,
4633 S: DatagramSocketSpec,
4634 CC,
4635 DualStackSC,
4636 > {
4637 ThisStack {
4638 params: SetBoundDeviceParameters<'a, I, D, S>,
4639 core_ctx: CC,
4640 },
4641 OtherStack {
4642 params: SetBoundDeviceParameters<'a, I::OtherVersion, D, S>,
4643 core_ctx: DualStackSC,
4644 },
4645 ListenerBothStacks {
4646 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
4647 device: &'a mut Option<D>,
4648 core_ctx: DualStackSC,
4649 },
4650 }
4651
4652 let op = match core_ctx.dual_stack_context_mut() {
4654 MaybeDualStack::DualStack(ds) => match socket_type {
4655 BoundSocketStateType::Listener { state, sharing: _ } => {
4656 let ListenerState { addr: ListenerAddr { ip, device } } = state;
4657 match ds.ds_converter().convert(ip) {
4658 DualStackListenerIpAddr::ThisStack(ip) => {
4659 Operation::ThisStack {
4660 params: SetBoundDeviceParameters::Listener {
4661 ip,
4662 device,
4663 },
4664 core_ctx,
4665 }
4666 }
4667 DualStackListenerIpAddr::OtherStack(ip) => {
4668 Operation::OtherStack {
4669 params: SetBoundDeviceParameters::Listener {
4670 ip,
4671 device,
4672 },
4673 core_ctx: ds,
4674 }
4675 }
4676 DualStackListenerIpAddr::BothStacks(identifier) => {
4677 Operation::ListenerBothStacks {
4678 identifier: *identifier,
4679 device,
4680 core_ctx: ds,
4681 }
4682 }
4683 }
4684 }
4685 BoundSocketStateType::Connected { state, sharing: _ } => {
4686 match ds.ds_converter().convert(state) {
4687 DualStackConnState::ThisStack(state) => Operation::ThisStack {
4688 params: SetBoundDeviceParameters::Connected(state),
4689 core_ctx,
4690 },
4691 DualStackConnState::OtherStack(state) => {
4692 Operation::OtherStack {
4693 params: SetBoundDeviceParameters::Connected(state),
4694 core_ctx: ds,
4695 }
4696 }
4697 }
4698 }
4699 },
4700 MaybeDualStack::NotDualStack(nds) => match socket_type {
4701 BoundSocketStateType::Listener { state, sharing: _ } => {
4702 let ListenerState { addr: ListenerAddr { ip, device } } = state;
4703 Operation::ThisStack {
4704 params: SetBoundDeviceParameters::Listener {
4705 ip: nds.nds_converter().convert(ip),
4706 device,
4707 },
4708 core_ctx,
4709 }
4710 }
4711 BoundSocketStateType::Connected { state, sharing: _ } => {
4712 Operation::ThisStack {
4713 params: SetBoundDeviceParameters::Connected(
4714 nds.nds_converter().convert(state),
4715 ),
4716 core_ctx,
4717 }
4718 }
4719 },
4720 };
4721
4722 match op {
4724 Operation::ThisStack { params, core_ctx } => {
4725 let socket_id = S::make_bound_socket_map_id(id);
4726 DatagramBoundStateContext::<I, _, _>::with_bound_sockets_mut(
4727 core_ctx,
4728 |core_ctx, bound| {
4729 set_bound_device_single_stack(
4730 bindings_ctx,
4731 core_ctx,
4732 params,
4733 bound,
4734 &socket_id,
4735 &ip_options.common,
4736 new_device,
4737 )
4738 },
4739 )
4740 }
4741 Operation::OtherStack { params, core_ctx } => {
4742 let socket_id = core_ctx.to_other_bound_socket_id(id);
4743 core_ctx.with_other_bound_sockets_mut(|core_ctx, bound| {
4744 set_bound_device_single_stack(
4745 bindings_ctx,
4746 core_ctx,
4747 params,
4748 bound,
4749 &socket_id,
4750 &ip_options.common,
4751 new_device,
4752 )
4753 })
4754 }
4755 Operation::ListenerBothStacks { identifier, device, core_ctx } => {
4756 let socket_id = PairedBoundSocketIds::<_, _, S> {
4757 this: S::make_bound_socket_map_id(id),
4758 other: core_ctx.to_other_bound_socket_id(id),
4759 };
4760 core_ctx.with_both_bound_sockets_mut(|_core_ctx, bound, other_bound| {
4761 set_bound_device_listener_both_stacks(
4762 device,
4763 identifier,
4764 PairedSocketMapMut { bound, other_bound },
4765 socket_id,
4766 new_device.map(|d| d.downgrade()),
4767 )
4768 })
4769 }
4770 }
4771 }
4772 }
4773 })
4774 }
4775
4776 pub fn set_multicast_membership(
4783 &mut self,
4784 id: &DatagramApiSocketId<I, C, S>,
4785 multicast_group: MulticastAddr<I::Addr>,
4786 interface: MulticastMembershipInterfaceSelector<I::Addr, DatagramApiDeviceId<C>>,
4787 want_membership: bool,
4788 ) -> Result<(), SetMulticastMembershipError> {
4789 let (core_ctx, bindings_ctx) = self.contexts();
4790 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
4791 let (ip_options, bound_device) = state.get_options_device(core_ctx);
4792
4793 let interface = match interface {
4794 MulticastMembershipInterfaceSelector::Specified(selector) => match selector {
4795 MulticastInterfaceSelector::Interface(device) => {
4796 if bound_device.as_ref().is_some_and(|d| d != &device) {
4797 return Err(SetMulticastMembershipError::WrongDevice);
4798 } else {
4799 EitherDeviceId::Strong(device)
4800 }
4801 }
4802 MulticastInterfaceSelector::LocalAddress(addr) => {
4803 EitherDeviceId::Strong(pick_interface_for_addr(
4804 core_ctx,
4805 multicast_group,
4806 Some(addr),
4807 &ip_options.common.marks,
4808 )?)
4809 }
4810 },
4811 MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute => {
4812 if let Some(bound_device) = bound_device.as_ref() {
4813 EitherDeviceId::Weak(bound_device.clone())
4814 } else {
4815 EitherDeviceId::Strong(pick_interface_for_addr(
4816 core_ctx,
4817 multicast_group,
4818 None,
4819 &ip_options.common.marks,
4820 )?)
4821 }
4822 }
4823 };
4824
4825 let ip_options = state.options_mut();
4826
4827 let Some(strong_interface) = interface.as_strong() else {
4828 return Err(SetMulticastMembershipError::DeviceDoesNotExist);
4829 };
4830
4831 let change = ip_options
4832 .multicast_memberships
4833 .apply_membership_change(multicast_group, &interface.as_weak(), want_membership)
4834 .ok_or(if want_membership {
4835 SetMulticastMembershipError::GroupAlreadyJoined
4836 } else {
4837 SetMulticastMembershipError::GroupNotJoined
4838 })?;
4839
4840 DatagramBoundStateContext::<I, _, _>::with_transport_context(core_ctx, |core_ctx| {
4841 match change {
4842 MulticastMembershipChange::Join => {
4843 MulticastMembershipHandler::<I, _>::join_multicast_group(
4844 core_ctx,
4845 bindings_ctx,
4846 &strong_interface,
4847 multicast_group,
4848 )
4849 }
4850 MulticastMembershipChange::Leave => {
4851 MulticastMembershipHandler::<I, _>::leave_multicast_group(
4852 core_ctx,
4853 bindings_ctx,
4854 &strong_interface,
4855 multicast_group,
4856 )
4857 }
4858 }
4859 });
4860
4861 Ok(())
4862 })
4863 }
4864
4865 pub fn update_ip_hop_limit(
4867 &mut self,
4868 id: &DatagramApiSocketId<I, C, S>,
4869 update: impl FnOnce(&mut SocketHopLimits<I>),
4870 ) {
4871 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4872 let options = state.options_mut();
4873
4874 update(&mut options.socket_options.hop_limits)
4875 })
4876 }
4877
4878 pub fn get_ip_hop_limits(&mut self, id: &DatagramApiSocketId<I, C, S>) -> HopLimits {
4880 self.core_ctx().with_socket_state(id, |core_ctx, state| {
4881 let (options, device) = state.get_options_device(core_ctx);
4882 let device = device.as_ref().and_then(|d| d.upgrade());
4883 DatagramBoundStateContext::<I, _, _>::with_transport_context(core_ctx, |core_ctx| {
4884 options.socket_options.hop_limits.get_limits_with_defaults(
4885 &BaseTransportIpContext::<I, _>::get_default_hop_limits(
4886 core_ctx,
4887 device.as_ref(),
4888 ),
4889 )
4890 })
4891 })
4892 }
4893
4894 pub fn with_other_stack_ip_options_mut_if_unbound<R>(
4900 &mut self,
4901 id: &DatagramApiSocketId<I, C, S>,
4902 cb: impl FnOnce(&mut S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>) -> R,
4903 ) -> Result<R, ExpectedUnboundError> {
4904 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4905 let is_unbound = match &state.inner {
4906 SocketStateInner::Unbound(_) => true,
4907 SocketStateInner::Bound(_) => false,
4908 };
4909 if is_unbound {
4910 let options = state.options_mut();
4911 Ok(cb(&mut options.other_stack))
4912 } else {
4913 Err(ExpectedUnboundError)
4914 }
4915 })
4916 }
4917
4918 pub fn with_other_stack_ip_options_mut<R>(
4921 &mut self,
4922 id: &DatagramApiSocketId<I, C, S>,
4923 cb: impl FnOnce(&mut S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>) -> R,
4924 ) -> R {
4925 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4926 let options = state.options_mut();
4927 cb(&mut options.other_stack)
4928 })
4929 }
4930
4931 pub fn with_other_stack_ip_options<R>(
4933 &mut self,
4934 id: &DatagramApiSocketId<I, C, S>,
4935 cb: impl FnOnce(&S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>) -> R,
4936 ) -> R {
4937 self.core_ctx().with_socket_state(id, |core_ctx, state| {
4938 let (options, _device) = state.get_options_device(core_ctx);
4939 cb(&options.other_stack)
4940 })
4941 }
4942
4943 pub fn with_other_stack_ip_options_and_default_hop_limits<R>(
4949 &mut self,
4950 id: &DatagramApiSocketId<I, C, S>,
4951 cb: impl FnOnce(&S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>, HopLimits) -> R,
4952 ) -> Result<R, NotDualStackCapableError> {
4953 self.core_ctx().with_socket_state(id, |core_ctx, state| {
4954 let (options, device) = state.get_options_device(core_ctx);
4955 let device = device.as_ref().and_then(|d| d.upgrade());
4956 match DatagramBoundStateContext::<I, _, _>::dual_stack_context_mut(core_ctx) {
4957 MaybeDualStack::NotDualStack(_) => Err(NotDualStackCapableError),
4958 MaybeDualStack::DualStack(ds) => {
4959 let default_hop_limits =
4960 DualStackDatagramBoundStateContext::<I, _, _>::with_transport_context(
4961 ds,
4962 |sync_ctx| {
4963 BaseTransportIpContext::<I, _>::get_default_hop_limits(
4964 sync_ctx,
4965 device.as_ref(),
4966 )
4967 },
4968 );
4969 Ok(cb(&options.other_stack, default_hop_limits))
4970 }
4971 }
4972 })
4973 }
4974
4975 pub fn with_both_stacks_ip_options_mut<R>(
4979 &mut self,
4980 id: &DatagramApiSocketId<I, C, S>,
4981 cb: impl FnOnce(
4982 &mut DatagramIpSpecificSocketOptions<I, DatagramApiWeakDeviceId<C>>,
4983 &mut S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>,
4984 ) -> R,
4985 ) -> R {
4986 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4987 let options = state.options_mut();
4988 cb(&mut options.socket_options, &mut options.other_stack)
4989 })
4990 }
4991
4992 pub fn with_both_stacks_ip_options<R>(
4995 &mut self,
4996 id: &DatagramApiSocketId<I, C, S>,
4997 cb: impl FnOnce(
4998 &DatagramIpSpecificSocketOptions<I, DatagramApiWeakDeviceId<C>>,
4999 &S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>,
5000 ) -> R,
5001 ) -> R {
5002 self.core_ctx().with_socket_state(id, |core_ctx, state| {
5003 let (options, _device) = state.get_options_device(core_ctx);
5004 cb(&options.socket_options, &options.other_stack)
5005 })
5006 }
5007
5008 pub fn update_sharing(
5013 &mut self,
5014 id: &DatagramApiSocketId<I, C, S>,
5015 f: impl FnOnce(&mut S::SharingState),
5016 ) -> Result<(), ExpectedUnboundError> {
5017 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5018 let state = match &mut state.inner {
5019 SocketStateInner::Bound(_) => return Err(ExpectedUnboundError),
5020 SocketStateInner::Unbound(state) => state,
5021 };
5022
5023 f(&mut state.sharing);
5024 Ok(())
5025 })
5026 }
5027
5028 pub fn get_sharing(&mut self, id: &DatagramApiSocketId<I, C, S>) -> S::SharingState {
5030 self.core_ctx().with_socket_state(id, |_core_ctx, state| {
5031 match &state.inner {
5032 SocketStateInner::Unbound(state) => {
5033 let UnboundSocketState { device: _, sharing } = state;
5034 sharing
5035 }
5036 SocketStateInner::Bound(BoundSocketState {
5037 socket_type,
5038 original_bound_addr: _,
5039 }) => match socket_type {
5040 BoundSocketStateType::Listener { state: _, sharing } => sharing,
5041 BoundSocketStateType::Connected { state: _, sharing } => sharing,
5042 },
5043 }
5044 .clone()
5045 })
5046 }
5047
5048 pub fn set_ip_transparent(&mut self, id: &DatagramApiSocketId<I, C, S>, value: bool) {
5050 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5051 state.options_mut().common.transparent = value;
5052 })
5053 }
5054
5055 pub fn get_ip_transparent(&mut self, id: &DatagramApiSocketId<I, C, S>) -> bool {
5057 self.core_ctx().with_socket_state(id, |core_ctx, state| {
5058 let (options, _device) = state.get_options_device(core_ctx);
5059 options.common.transparent
5060 })
5061 }
5062
5063 pub fn set_mark(&mut self, id: &DatagramApiSocketId<I, C, S>, domain: MarkDomain, mark: Mark) {
5065 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5066 *state.options_mut().common.marks.get_mut(domain) = mark;
5067 })
5068 }
5069
5070 pub fn get_mark(&mut self, id: &DatagramApiSocketId<I, C, S>, domain: MarkDomain) -> Mark {
5072 self.core_ctx().with_socket_state(id, |core_ctx, state| {
5073 let (options, _device) = state.get_options_device(core_ctx);
5074 *options.common.marks.get(domain)
5075 })
5076 }
5077
5078 pub fn set_broadcast(
5080 &mut self,
5081 id: &DatagramApiSocketId<I, C, S>,
5082 value: Option<I::BroadcastMarker>,
5083 ) {
5084 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5085 state.options_mut().socket_options.allow_broadcast = value;
5086 })
5087 }
5088
5089 pub fn get_broadcast(
5091 &mut self,
5092 id: &DatagramApiSocketId<I, C, S>,
5093 ) -> Option<I::BroadcastMarker> {
5094 self.core_ctx().with_socket_state_mut(id, |core_ctx, state| {
5095 let (options, _device) = state.get_options_device(core_ctx);
5096 options.socket_options.allow_broadcast
5097 })
5098 }
5099
5100 pub fn set_multicast_interface(
5102 &mut self,
5103 id: &DatagramApiSocketId<I, C, S>,
5104 value: Option<&DatagramApiDeviceId<C>>,
5105 ) {
5106 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5107 state.options_mut().socket_options.multicast_interface = value.map(|v| v.downgrade());
5108 })
5109 }
5110
5111 pub fn get_multicast_interface(
5113 &mut self,
5114 id: &DatagramApiSocketId<I, C, S>,
5115 ) -> Option<DatagramApiWeakDeviceId<C>> {
5116 self.core_ctx().with_socket_state(id, |core_ctx, state| {
5117 let (options, _device) = state.get_options_device(core_ctx);
5118 options.socket_options.multicast_interface.clone()
5119 })
5120 }
5121
5122 pub fn set_multicast_loop(&mut self, id: &DatagramApiSocketId<I, C, S>, value: bool) {
5124 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5125 state.options_mut().socket_options.multicast_loop = value;
5126 })
5127 }
5128
5129 pub fn get_multicast_loop(&mut self, id: &DatagramApiSocketId<I, C, S>) -> bool {
5131 self.core_ctx().with_socket_state(id, |core_ctx, state| {
5132 let (options, _device) = state.get_options_device(core_ctx);
5133 options.socket_options.multicast_loop
5134 })
5135 }
5136
5137 pub fn set_dscp_and_ecn(&mut self, id: &DatagramApiSocketId<I, C, S>, value: DscpAndEcn) {
5139 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5140 state.options_mut().socket_options.dscp_and_ecn = value;
5141 })
5142 }
5143
5144 pub fn get_dscp_and_ecn(&mut self, id: &DatagramApiSocketId<I, C, S>) -> DscpAndEcn {
5146 self.core_ctx().with_socket_state(id, |core_ctx, state| {
5147 let (options, _device) = state.get_options_device(core_ctx);
5148 options.socket_options.dscp_and_ecn
5149 })
5150 }
5151
5152 pub fn set_send_buffer(&mut self, id: &DatagramApiSocketId<I, C, S>, size: usize) {
5154 let settings = self.bindings_ctx().settings();
5155 id.borrow().send_buffer.set_capacity(size, settings.as_ref())
5156 }
5157
5158 pub fn send_buffer(&mut self, id: &DatagramApiSocketId<I, C, S>) -> usize {
5160 id.borrow().send_buffer.capacity()
5161 }
5162
5163 #[cfg(any(test, feature = "testutils"))]
5165 pub fn send_buffer_available(&mut self, id: &DatagramApiSocketId<I, C, S>) -> usize {
5166 id.borrow().send_buffer.available()
5167 }
5168}
5169
5170#[cfg(any(test, feature = "testutils"))]
5171pub(crate) mod testutil {
5172 use super::*;
5173
5174 use alloc::vec;
5175 use net_types::Witness;
5176 use net_types::ip::IpAddr;
5177 use netstack3_base::CtxPair;
5178 use netstack3_base::testutil::{FakeStrongDeviceId, TestIpExt};
5179 use netstack3_ip::socket::testutil::FakeDeviceConfig;
5180
5181 pub fn setup_fake_ctx_with_dualstack_conn_addrs<CC, BC: Default, D: FakeStrongDeviceId>(
5185 local_ip: IpAddr,
5186 remote_ip: SpecifiedAddr<IpAddr>,
5187 devices: impl IntoIterator<Item = D>,
5188 core_ctx_builder: impl FnOnce(Vec<FakeDeviceConfig<D, SpecifiedAddr<IpAddr>>>) -> CC,
5189 ) -> CtxPair<CC, BC> {
5190 fn unmap_ip(addr: IpAddr) -> IpAddr {
5192 match addr {
5193 IpAddr::V4(v4) => IpAddr::V4(v4),
5194 IpAddr::V6(v6) => match v6.to_ipv4_mapped() {
5195 Some(v4) => IpAddr::V4(v4),
5196 None => IpAddr::V6(v6),
5197 },
5198 }
5199 }
5200
5201 let local_ip = unmap_ip(local_ip);
5203 let remote_ip = unmap_ip(remote_ip.get());
5204 let local_ip = SpecifiedAddr::new(local_ip).unwrap_or_else(|| match remote_ip {
5209 IpAddr::V4(_) => Ipv4::TEST_ADDRS.local_ip.into(),
5210 IpAddr::V6(_) => Ipv6::TEST_ADDRS.local_ip.into(),
5211 });
5212 let remote_ip = SpecifiedAddr::new(remote_ip).expect("remote-ip should be specified");
5215 CtxPair::with_core_ctx(core_ctx_builder(
5216 devices
5217 .into_iter()
5218 .map(|device| FakeDeviceConfig {
5219 device,
5220 local_ips: vec![local_ip],
5221 remote_ips: vec![remote_ip],
5222 })
5223 .collect(),
5224 ))
5225 }
5226}
5227
5228#[cfg(test)]
5229mod test {
5230 use core::convert::Infallible as Never;
5231
5232 use alloc::vec;
5233 use assert_matches::assert_matches;
5234 use derivative::Derivative;
5235 use ip_test_macro::ip_test;
5236 use net_declare::{net_ip_v4, net_ip_v6};
5237 use net_types::Witness;
5238 use net_types::ip::{IpVersionMarker, Ipv4Addr, Ipv6Addr};
5239 use netstack3_base::socket::{
5240 AddrVec, Bound, IncompatibleError, ListenerAddrInfo, RemoveResult, SocketMapAddrStateSpec,
5241 };
5242 use netstack3_base::socketmap::SocketMap;
5243 use netstack3_base::testutil::{
5244 FakeDeviceId, FakeReferencyDeviceId, FakeSocketWritableListener, FakeStrongDeviceId,
5245 FakeWeakDeviceId, MultipleDevicesId, TestIpExt,
5246 };
5247 use netstack3_base::{ContextProvider, CtxPair, UninstantiableWrapper};
5248 use netstack3_ip::DEFAULT_HOP_LIMITS;
5249 use netstack3_ip::device::IpDeviceStateIpExt;
5250 use netstack3_ip::socket::testutil::{
5251 FakeDeviceConfig, FakeDualStackIpSocketCtx, FakeIpSocketCtx,
5252 };
5253 use netstack3_ip::testutil::DualStackSendIpPacketMeta;
5254 use packet::{Buf, Serializer as _};
5255 use packet_formats::ip::{Ipv4Proto, Ipv6Proto};
5256 use test_case::test_case;
5257
5258 use super::*;
5259 use crate::internal::spec_context;
5260
5261 trait DatagramIpExt<D: FakeStrongDeviceId>:
5262 IpExt + IpDeviceStateIpExt + TestIpExt + DualStackIpExt + DualStackContextsIpExt<D>
5263 {
5264 }
5265 impl<
5266 D: FakeStrongDeviceId,
5267 I: Ip + IpExt + IpDeviceStateIpExt + TestIpExt + DualStackIpExt + DualStackContextsIpExt<D>,
5268 > DatagramIpExt<D> for I
5269 {
5270 }
5271
5272 #[derive(Debug)]
5273 enum FakeAddrSpec {}
5274
5275 impl SocketMapAddrSpec for FakeAddrSpec {
5276 type LocalIdentifier = NonZeroU16;
5277 type RemoteIdentifier = u16;
5278 }
5279
5280 #[derive(Debug)]
5281 enum FakeStateSpec {}
5282
5283 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
5284 struct Tag;
5285
5286 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
5287
5288 enum Sharing {
5289 #[default]
5290 NoConflicts,
5291 ConnectionConflicts {
5294 remote_port: u16,
5295 },
5296 }
5297
5298 #[derive(Clone, Debug, Derivative)]
5299 #[derivative(Eq(bound = ""), PartialEq(bound = ""))]
5300 struct Id<I: IpExt, D: WeakDeviceIdentifier>(StrongRc<I, D, FakeStateSpec>);
5301
5302 impl<I: IpExt, D: WeakDeviceIdentifier> Id<I, D> {
5304 fn get(&self) -> impl Deref<Target = SocketState<I, D, FakeStateSpec>> + '_ {
5305 let Self(rc) = self;
5306 rc.state.read()
5307 }
5308
5309 fn get_mut(&self) -> impl DerefMut<Target = SocketState<I, D, FakeStateSpec>> + '_ {
5310 let Self(rc) = self;
5311 rc.state.write()
5312 }
5313 }
5314
5315 impl<I: IpExt, D: WeakDeviceIdentifier> From<StrongRc<I, D, FakeStateSpec>> for Id<I, D> {
5316 fn from(value: StrongRc<I, D, FakeStateSpec>) -> Self {
5317 Self(value)
5318 }
5319 }
5320
5321 impl<I: IpExt, D: WeakDeviceIdentifier> Borrow<StrongRc<I, D, FakeStateSpec>> for Id<I, D> {
5322 fn borrow(&self) -> &StrongRc<I, D, FakeStateSpec> {
5323 let Self(rc) = self;
5324 rc
5325 }
5326 }
5327
5328 #[derive(Debug)]
5329 struct AddrState<T>(T);
5330
5331 struct FakeSocketMapStateSpec<I, D>(PhantomData<(I, D)>, Never);
5332
5333 impl<I: IpExt, D: WeakDeviceIdentifier> SocketMapStateSpec for FakeSocketMapStateSpec<I, D> {
5334 type AddrVecTag = Tag;
5335 type ConnAddrState = AddrState<Self::ConnId>;
5336 type ConnId = I::DualStackBoundSocketId<D, FakeStateSpec>;
5337 type ConnSharingState = Sharing;
5338 type ListenerAddrState = AddrState<Self::ListenerId>;
5339 type ListenerId = I::DualStackBoundSocketId<D, FakeStateSpec>;
5340 type ListenerSharingState = Sharing;
5341 fn listener_tag(_: ListenerAddrInfo, _state: &Self::ListenerAddrState) -> Self::AddrVecTag {
5342 Tag
5343 }
5344 fn connected_tag(_has_device: bool, _state: &Self::ConnAddrState) -> Self::AddrVecTag {
5345 Tag
5346 }
5347 }
5348
5349 const FAKE_DATAGRAM_IPV4_PROTOCOL: Ipv4Proto = Ipv4Proto::Other(253);
5350 const FAKE_DATAGRAM_IPV6_PROTOCOL: Ipv6Proto = Ipv6Proto::Other(254);
5351
5352 impl DatagramSocketSpec for FakeStateSpec {
5353 const NAME: &'static str = "FAKE";
5354 type AddrSpec = FakeAddrSpec;
5355 type SocketId<I: IpExt, D: WeakDeviceIdentifier> = Id<I, D>;
5356 type WeakSocketId<I: IpExt, D: WeakDeviceIdentifier> = Id<I, D>;
5359 type OtherStackIpOptions<I: IpExt, D: WeakDeviceIdentifier> =
5360 DatagramIpSpecificSocketOptions<I::OtherVersion, D>;
5361 type SocketMapSpec<I: IpExt, D: WeakDeviceIdentifier> = FakeSocketMapStateSpec<I, D>;
5362 type SharingState = Sharing;
5363 type ListenerIpAddr<I: IpExt> =
5364 I::DualStackListenerIpAddr<<FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier>;
5365 type ConnIpAddr<I: IpExt> = I::DualStackConnIpAddr<Self>;
5366 type ConnStateExtra = ();
5367 type ConnState<I: IpExt, D: WeakDeviceIdentifier> = I::DualStackConnState<D, Self>;
5368 type Counters<I: Ip> = ();
5369 type ExternalData<I: Ip> = ();
5370 type SocketWritableListener = FakeSocketWritableListener;
5371 type Settings = DatagramSettings;
5372
5373 fn ip_proto<I: IpProtoExt>() -> I::Proto {
5374 I::map_ip((), |()| FAKE_DATAGRAM_IPV4_PROTOCOL, |()| FAKE_DATAGRAM_IPV6_PROTOCOL)
5375 }
5376
5377 fn make_bound_socket_map_id<I: IpExt, D: WeakDeviceIdentifier>(
5378 s: &Self::SocketId<I, D>,
5379 ) -> <Self::SocketMapSpec<I, D> as DatagramSocketMapSpec<I, D, Self::AddrSpec>>::BoundSocketId
5380 {
5381 I::into_dual_stack_bound_socket_id(s.clone())
5382 }
5383
5384 type Serializer<I: IpExt, B: BufferMut> = packet::Nested<B, ()>;
5385 type SerializeError = Never;
5386 const FIXED_HEADER_SIZE: usize = 0;
5387 fn make_packet<I: IpExt, B: BufferMut>(
5388 body: B,
5389 _addr: &ConnIpAddr<
5390 I::Addr,
5391 <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier,
5392 <FakeAddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
5393 >,
5394 ) -> Result<Self::Serializer<I, B>, Never> {
5395 Ok(body.wrap_in(()))
5396 }
5397 fn try_alloc_listen_identifier<I: Ip, D: WeakDeviceIdentifier>(
5398 _bindings_ctx: &mut impl RngContext,
5399 is_available: impl Fn(
5400 <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier,
5401 ) -> Result<(), InUseError>,
5402 ) -> Option<<FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier> {
5403 (1..=u16::MAX).map(|i| NonZeroU16::new(i).unwrap()).find(|i| is_available(*i).is_ok())
5404 }
5405
5406 fn conn_info_from_state<I: IpExt, D: WeakDeviceIdentifier>(
5407 state: &Self::ConnState<I, D>,
5408 ) -> ConnInfo<I::Addr, D> {
5409 let ConnAddr { ip, device } = I::conn_addr_from_state(state);
5410 let ConnInfoAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) } =
5411 ip.into();
5412 ConnInfo::new(local_ip, local_port, remote_ip, remote_port, || {
5413 device.clone().expect("device must be bound for addresses that require zones")
5414 })
5415 }
5416
5417 fn try_alloc_local_id<I: IpExt, D: WeakDeviceIdentifier, BC: RngContext>(
5418 bound: &BoundSocketMap<I, D, FakeAddrSpec, FakeSocketMapStateSpec<I, D>>,
5419 _bindings_ctx: &mut BC,
5420 _flow: DatagramFlowId<I::Addr, <FakeAddrSpec as SocketMapAddrSpec>::RemoteIdentifier>,
5421 ) -> Option<<FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier> {
5422 (1..u16::MAX).find_map(|identifier| {
5423 let identifier = NonZeroU16::new(identifier).unwrap();
5424 bound
5425 .listeners()
5426 .could_insert(
5427 &ListenerAddr {
5428 device: None,
5429 ip: ListenerIpAddr { addr: None, identifier },
5430 },
5431 &Default::default(),
5432 )
5433 .is_ok()
5434 .then_some(identifier)
5435 })
5436 }
5437
5438 fn upgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
5439 id: &Self::WeakSocketId<I, D>,
5440 ) -> Option<Self::SocketId<I, D>> {
5441 Some(id.clone())
5442 }
5443
5444 fn downgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
5445 id: &Self::SocketId<I, D>,
5446 ) -> Self::WeakSocketId<I, D> {
5447 id.clone()
5448 }
5449 }
5450
5451 impl<I: IpExt, D: WeakDeviceIdentifier> DatagramSocketMapSpec<I, D, FakeAddrSpec>
5452 for FakeSocketMapStateSpec<I, D>
5453 {
5454 type BoundSocketId = I::DualStackBoundSocketId<D, FakeStateSpec>;
5455 }
5456
5457 impl<I: IpExt, D: WeakDeviceIdentifier>
5458 SocketMapConflictPolicy<
5459 ConnAddr<
5460 ConnIpAddr<
5461 I::Addr,
5462 <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier,
5463 <FakeAddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
5464 >,
5465 D,
5466 >,
5467 Sharing,
5468 I,
5469 D,
5470 FakeAddrSpec,
5471 > for FakeSocketMapStateSpec<I, D>
5472 {
5473 fn check_insert_conflicts(
5474 sharing: &Sharing,
5475 addr: &ConnAddr<
5476 ConnIpAddr<
5477 I::Addr,
5478 <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier,
5479 <FakeAddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
5480 >,
5481 D,
5482 >,
5483 _socketmap: &SocketMap<AddrVec<I, D, FakeAddrSpec>, Bound<Self>>,
5484 ) -> Result<(), InsertError> {
5485 let ConnAddr { ip: ConnIpAddr { local: _, remote: (_remote_ip, port) }, device: _ } =
5486 addr;
5487 match sharing {
5488 Sharing::NoConflicts => Ok(()),
5489 Sharing::ConnectionConflicts { remote_port } => {
5490 if remote_port == port {
5491 Err(InsertError::Exists)
5492 } else {
5493 Ok(())
5494 }
5495 }
5496 }
5497 }
5498 }
5499
5500 impl<I: IpExt, D: WeakDeviceIdentifier>
5501 SocketMapConflictPolicy<
5502 ListenerAddr<
5503 ListenerIpAddr<I::Addr, <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
5504 D,
5505 >,
5506 Sharing,
5507 I,
5508 D,
5509 FakeAddrSpec,
5510 > for FakeSocketMapStateSpec<I, D>
5511 {
5512 fn check_insert_conflicts(
5513 sharing: &Sharing,
5514 _addr: &ListenerAddr<
5515 ListenerIpAddr<I::Addr, <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
5516 D,
5517 >,
5518 _socketmap: &SocketMap<AddrVec<I, D, FakeAddrSpec>, Bound<Self>>,
5519 ) -> Result<(), InsertError> {
5520 match sharing {
5521 Sharing::NoConflicts => Ok(()),
5522 Sharing::ConnectionConflicts { remote_port: _ } => Ok(()),
5525 }
5526 }
5527 }
5528
5529 impl<T: Eq> SocketMapAddrStateSpec for AddrState<T> {
5530 type Id = T;
5531 type SharingState = Sharing;
5532 type Inserter<'a>
5533 = Never
5534 where
5535 Self: 'a;
5536
5537 fn new(_sharing: &Self::SharingState, id: Self::Id) -> Self {
5538 AddrState(id)
5539 }
5540 fn contains_id(&self, id: &Self::Id) -> bool {
5541 let Self(inner) = self;
5542 inner == id
5543 }
5544 fn try_get_inserter<'a, 'b>(
5545 &'b mut self,
5546 _new_sharing_state: &'a Self::SharingState,
5547 ) -> Result<Self::Inserter<'b>, IncompatibleError> {
5548 Err(IncompatibleError)
5549 }
5550 fn could_insert(
5551 &self,
5552 _new_sharing_state: &Self::SharingState,
5553 ) -> Result<(), IncompatibleError> {
5554 Err(IncompatibleError)
5555 }
5556 fn remove_by_id(&mut self, _id: Self::Id) -> RemoveResult {
5557 RemoveResult::IsLast
5558 }
5559 }
5560
5561 #[derive(Derivative, GenericOverIp)]
5562 #[derivative(Default(bound = ""))]
5563 #[generic_over_ip()]
5564 struct FakeBoundSockets<D: FakeStrongDeviceId> {
5565 v4: BoundSockets<
5566 Ipv4,
5567 FakeWeakDeviceId<D>,
5568 FakeAddrSpec,
5569 FakeSocketMapStateSpec<Ipv4, FakeWeakDeviceId<D>>,
5570 >,
5571 v6: BoundSockets<
5572 Ipv6,
5573 FakeWeakDeviceId<D>,
5574 FakeAddrSpec,
5575 FakeSocketMapStateSpec<Ipv6, FakeWeakDeviceId<D>>,
5576 >,
5577 }
5578
5579 impl<D: FakeStrongDeviceId, I: IpExt>
5580 AsRef<
5581 BoundSockets<
5582 I,
5583 FakeWeakDeviceId<D>,
5584 FakeAddrSpec,
5585 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5586 >,
5587 > for FakeBoundSockets<D>
5588 {
5589 fn as_ref(
5590 &self,
5591 ) -> &BoundSockets<
5592 I,
5593 FakeWeakDeviceId<D>,
5594 FakeAddrSpec,
5595 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5596 > {
5597 #[derive(GenericOverIp)]
5598 #[generic_over_ip(I, Ip)]
5599 struct Wrap<'a, I: IpExt, D: FakeStrongDeviceId>(
5600 &'a BoundSockets<
5601 I,
5602 FakeWeakDeviceId<D>,
5603 FakeAddrSpec,
5604 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5605 >,
5606 );
5607 let Wrap(state) = I::map_ip(self, |state| Wrap(&state.v4), |state| Wrap(&state.v6));
5608 state
5609 }
5610 }
5611
5612 impl<D: FakeStrongDeviceId, I: IpExt>
5613 AsMut<
5614 BoundSockets<
5615 I,
5616 FakeWeakDeviceId<D>,
5617 FakeAddrSpec,
5618 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5619 >,
5620 > for FakeBoundSockets<D>
5621 {
5622 fn as_mut(
5623 &mut self,
5624 ) -> &mut BoundSockets<
5625 I,
5626 FakeWeakDeviceId<D>,
5627 FakeAddrSpec,
5628 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5629 > {
5630 #[derive(GenericOverIp)]
5631 #[generic_over_ip(I, Ip)]
5632 struct Wrap<'a, I: IpExt, D: FakeStrongDeviceId>(
5633 &'a mut BoundSockets<
5634 I,
5635 FakeWeakDeviceId<D>,
5636 FakeAddrSpec,
5637 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5638 >,
5639 );
5640 let Wrap(state) =
5641 I::map_ip(self, |state| Wrap(&mut state.v4), |state| Wrap(&mut state.v6));
5642 state
5643 }
5644 }
5645
5646 type FakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<(), (), (), ()>;
5647 type FakeCtx<I, D> = CtxPair<FakeCoreCtx<I, D>, FakeBindingsCtx>;
5648
5649 type FakeSocketSet<I, D> = DatagramSocketSet<I, FakeWeakDeviceId<D>, FakeStateSpec>;
5650
5651 type InnerIpSocketCtx<D> = netstack3_base::testutil::FakeCoreCtx<
5652 FakeDualStackIpSocketCtx<D>,
5653 DualStackSendIpPacketMeta<D>,
5654 D,
5655 >;
5656
5657 trait DatagramApiExt: ContextPair + Sized {
5659 fn datagram_api<I: Ip>(&mut self) -> DatagramApi<I, &mut Self, FakeStateSpec> {
5660 DatagramApi::new(self)
5661 }
5662 }
5663
5664 impl<O> DatagramApiExt for O where O: ContextPair + Sized {}
5665
5666 struct FakeDualStackCoreCtx<D: FakeStrongDeviceId> {
5667 bound_sockets: FakeBoundSockets<D>,
5668 ip_socket_ctx: InnerIpSocketCtx<D>,
5669 }
5670
5671 struct FakeCoreCtx<I: IpExt, D: FakeStrongDeviceId> {
5672 dual_stack: FakeDualStackCoreCtx<D>,
5673 socket_set: FakeSocketSet<I, D>,
5676 }
5677
5678 impl<I: IpExt, D: FakeStrongDeviceId> ContextProvider for FakeCoreCtx<I, D> {
5679 type Context = Self;
5680 fn context(&mut self) -> &mut Self::Context {
5681 self
5682 }
5683 }
5684
5685 impl<I: IpExt, D: FakeStrongDeviceId> FakeCoreCtx<I, D> {
5686 fn new() -> Self {
5687 Self::new_with_sockets(Default::default(), Default::default())
5688 }
5689
5690 fn new_with_sockets(
5691 socket_set: FakeSocketSet<I, D>,
5692 bound_sockets: FakeBoundSockets<D>,
5693 ) -> Self {
5694 Self {
5695 socket_set,
5696 dual_stack: FakeDualStackCoreCtx {
5697 bound_sockets,
5698 ip_socket_ctx: Default::default(),
5699 },
5700 }
5701 }
5702
5703 fn new_with_ip_socket_ctx(ip_socket_ctx: FakeDualStackIpSocketCtx<D>) -> Self {
5704 Self {
5705 socket_set: Default::default(),
5706 dual_stack: FakeDualStackCoreCtx {
5707 bound_sockets: Default::default(),
5708 ip_socket_ctx: InnerIpSocketCtx::with_state(ip_socket_ctx),
5709 },
5710 }
5711 }
5712 }
5713
5714 impl<I: IpExt, D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeCoreCtx<I, D> {
5715 type DeviceId = D;
5716 type WeakDeviceId = FakeWeakDeviceId<D>;
5717 }
5718
5719 impl<D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeDualStackCoreCtx<D> {
5720 type DeviceId = D;
5721 type WeakDeviceId = FakeWeakDeviceId<D>;
5722 }
5723
5724 impl<D: FakeStrongDeviceId, I: DatagramIpExt<D>>
5725 spec_context::DatagramSpecStateContext<I, FakeCoreCtx<I, D>, FakeBindingsCtx>
5726 for FakeStateSpec
5727 {
5728 type SocketsStateCtx<'a> = FakeDualStackCoreCtx<D>;
5729
5730 fn with_all_sockets_mut<
5731 O,
5732 F: FnOnce(&mut DatagramSocketSet<I, FakeWeakDeviceId<D>, FakeStateSpec>) -> O,
5733 >(
5734 core_ctx: &mut FakeCoreCtx<I, D>,
5735 cb: F,
5736 ) -> O {
5737 cb(&mut core_ctx.socket_set)
5738 }
5739
5740 fn with_all_sockets<
5741 O,
5742 F: FnOnce(&DatagramSocketSet<I, FakeWeakDeviceId<D>, FakeStateSpec>) -> O,
5743 >(
5744 core_ctx: &mut FakeCoreCtx<I, D>,
5745 cb: F,
5746 ) -> O {
5747 cb(&core_ctx.socket_set)
5748 }
5749
5750 fn with_socket_state<
5751 O,
5752 F: FnOnce(
5753 &mut Self::SocketsStateCtx<'_>,
5754 &SocketState<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5755 ) -> O,
5756 >(
5757 core_ctx: &mut FakeCoreCtx<I, D>,
5758 id: &Id<I, FakeWeakDeviceId<D>>,
5759 cb: F,
5760 ) -> O {
5761 cb(&mut core_ctx.dual_stack, &id.get())
5762 }
5763
5764 fn with_socket_state_mut<
5765 O,
5766 F: FnOnce(
5767 &mut Self::SocketsStateCtx<'_>,
5768 &mut SocketState<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5769 ) -> O,
5770 >(
5771 core_ctx: &mut FakeCoreCtx<I, D>,
5772 id: &Id<I, FakeWeakDeviceId<D>>,
5773 cb: F,
5774 ) -> O {
5775 cb(&mut core_ctx.dual_stack, &mut id.get_mut())
5776 }
5777
5778 fn for_each_socket<
5779 F: FnMut(
5780 &mut Self::SocketsStateCtx<'_>,
5781 &Id<I, FakeWeakDeviceId<D>>,
5782 &SocketState<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5783 ),
5784 >(
5785 core_ctx: &mut FakeCoreCtx<I, D>,
5786 mut cb: F,
5787 ) {
5788 core_ctx.socket_set.keys().for_each(|id| {
5789 let id = Id::from(id.clone());
5790 cb(&mut core_ctx.dual_stack, &id, &id.get());
5791 })
5792 }
5793 }
5794
5795 trait DualStackContextsIpExt<D: FakeStrongDeviceId>: IpExt {
5803 type DualStackContext: DualStackDatagramBoundStateContext<
5804 Self,
5805 FakeBindingsCtx,
5806 FakeStateSpec,
5807 DeviceId = D,
5808 WeakDeviceId = FakeWeakDeviceId<D>,
5809 >;
5810 type NonDualStackContext: NonDualStackDatagramBoundStateContext<
5811 Self,
5812 FakeBindingsCtx,
5813 FakeStateSpec,
5814 DeviceId = D,
5815 WeakDeviceId = FakeWeakDeviceId<D>,
5816 >;
5817
5818 fn dual_stack_context(
5819 core_ctx: &FakeDualStackCoreCtx<D>,
5820 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext>;
5821
5822 fn dual_stack_context_mut(
5823 core_ctx: &mut FakeDualStackCoreCtx<D>,
5824 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext>;
5825 }
5826
5827 impl<D: FakeStrongDeviceId> DualStackContextsIpExt<D> for Ipv4 {
5828 type DualStackContext = UninstantiableWrapper<FakeDualStackCoreCtx<D>>;
5829 type NonDualStackContext = FakeDualStackCoreCtx<D>;
5830
5831 fn dual_stack_context(
5832 core_ctx: &FakeDualStackCoreCtx<D>,
5833 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext> {
5834 MaybeDualStack::NotDualStack(core_ctx)
5835 }
5836
5837 fn dual_stack_context_mut(
5838 core_ctx: &mut FakeDualStackCoreCtx<D>,
5839 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
5840 MaybeDualStack::NotDualStack(core_ctx)
5841 }
5842 }
5843
5844 impl<D: FakeStrongDeviceId> DualStackContextsIpExt<D> for Ipv6 {
5845 type DualStackContext = FakeDualStackCoreCtx<D>;
5846 type NonDualStackContext = UninstantiableWrapper<FakeDualStackCoreCtx<D>>;
5847
5848 fn dual_stack_context(
5849 core_ctx: &FakeDualStackCoreCtx<D>,
5850 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext> {
5851 MaybeDualStack::DualStack(core_ctx)
5852 }
5853
5854 fn dual_stack_context_mut(
5855 core_ctx: &mut FakeDualStackCoreCtx<D>,
5856 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
5857 MaybeDualStack::DualStack(core_ctx)
5858 }
5859 }
5860
5861 impl<D: FakeStrongDeviceId, I: DualStackContextsIpExt<D>>
5862 spec_context::DatagramSpecBoundStateContext<I, FakeDualStackCoreCtx<D>, FakeBindingsCtx>
5863 for FakeStateSpec
5864 {
5865 type IpSocketsCtx<'a> = InnerIpSocketCtx<D>;
5866 type DualStackContext = I::DualStackContext;
5867 type NonDualStackContext = I::NonDualStackContext;
5868
5869 fn with_bound_sockets<
5870 O,
5871 F: FnOnce(
5872 &mut Self::IpSocketsCtx<'_>,
5873 &BoundSockets<
5874 I,
5875 FakeWeakDeviceId<D>,
5876 FakeAddrSpec,
5877 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5878 >,
5879 ) -> O,
5880 >(
5881 core_ctx: &mut FakeDualStackCoreCtx<D>,
5882 cb: F,
5883 ) -> O {
5884 let FakeDualStackCoreCtx { bound_sockets, ip_socket_ctx } = core_ctx;
5885 cb(ip_socket_ctx, bound_sockets.as_ref())
5886 }
5887 fn with_bound_sockets_mut<
5888 O,
5889 F: FnOnce(
5890 &mut Self::IpSocketsCtx<'_>,
5891 &mut BoundSockets<
5892 I,
5893 FakeWeakDeviceId<D>,
5894 FakeAddrSpec,
5895 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5896 >,
5897 ) -> O,
5898 >(
5899 core_ctx: &mut FakeDualStackCoreCtx<D>,
5900 cb: F,
5901 ) -> O {
5902 let FakeDualStackCoreCtx { bound_sockets, ip_socket_ctx } = core_ctx;
5903 cb(ip_socket_ctx, bound_sockets.as_mut())
5904 }
5905
5906 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
5907 core_ctx: &mut FakeDualStackCoreCtx<D>,
5908 cb: F,
5909 ) -> O {
5910 cb(&mut core_ctx.ip_socket_ctx)
5911 }
5912
5913 fn dual_stack_context(
5914 core_ctx: &FakeDualStackCoreCtx<D>,
5915 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext> {
5916 I::dual_stack_context(core_ctx)
5917 }
5918
5919 fn dual_stack_context_mut(
5920 core_ctx: &mut FakeDualStackCoreCtx<D>,
5921 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
5922 I::dual_stack_context_mut(core_ctx)
5923 }
5924 }
5925
5926 impl<D: FakeStrongDeviceId>
5927 spec_context::NonDualStackDatagramSpecBoundStateContext<
5928 Ipv4,
5929 FakeDualStackCoreCtx<D>,
5930 FakeBindingsCtx,
5931 > for FakeStateSpec
5932 {
5933 fn nds_converter(
5934 _core_ctx: &FakeDualStackCoreCtx<D>,
5935 ) -> impl NonDualStackConverter<Ipv4, FakeWeakDeviceId<D>, Self> {
5936 ()
5937 }
5938 }
5939
5940 impl<D: FakeStrongDeviceId>
5941 spec_context::DualStackDatagramSpecBoundStateContext<
5942 Ipv6,
5943 FakeDualStackCoreCtx<D>,
5944 FakeBindingsCtx,
5945 > for FakeStateSpec
5946 {
5947 type IpSocketsCtx<'a> = InnerIpSocketCtx<D>;
5948 fn dual_stack_enabled(
5949 _core_ctx: &FakeDualStackCoreCtx<D>,
5950 _ip_options: &IpOptions<Ipv6, FakeWeakDeviceId<D>, FakeStateSpec>,
5951 ) -> bool {
5952 true
5956 }
5957
5958 fn to_other_socket_options<'a>(
5959 _core_ctx: &FakeDualStackCoreCtx<D>,
5960 state: &'a IpOptions<Ipv6, FakeWeakDeviceId<D>, FakeStateSpec>,
5961 ) -> &'a DatagramIpSpecificSocketOptions<Ipv4, FakeWeakDeviceId<D>> {
5962 let IpOptions { other_stack, .. } = state;
5963 other_stack
5964 }
5965
5966 fn ds_converter(
5967 _core_ctx: &FakeDualStackCoreCtx<D>,
5968 ) -> impl DualStackConverter<Ipv6, FakeWeakDeviceId<D>, Self> {
5969 ()
5970 }
5971
5972 fn to_other_bound_socket_id(
5973 _core_ctx: &FakeDualStackCoreCtx<D>,
5974 id: &Id<Ipv6, D::Weak>,
5975 ) -> EitherIpSocket<D::Weak, FakeStateSpec> {
5976 EitherIpSocket::V6(id.clone())
5977 }
5978
5979 fn with_both_bound_sockets_mut<
5980 O,
5981 F: FnOnce(
5982 &mut Self::IpSocketsCtx<'_>,
5983 &mut BoundSocketsFromSpec<Ipv6, FakeDualStackCoreCtx<D>, FakeStateSpec>,
5984 &mut BoundSocketsFromSpec<Ipv4, FakeDualStackCoreCtx<D>, FakeStateSpec>,
5985 ) -> O,
5986 >(
5987 core_ctx: &mut FakeDualStackCoreCtx<D>,
5988 cb: F,
5989 ) -> O {
5990 let FakeDualStackCoreCtx { bound_sockets: FakeBoundSockets { v4, v6 }, ip_socket_ctx } =
5991 core_ctx;
5992 cb(ip_socket_ctx, v6, v4)
5993 }
5994
5995 fn with_other_bound_sockets_mut<
5996 O,
5997 F: FnOnce(
5998 &mut Self::IpSocketsCtx<'_>,
5999 &mut BoundSocketsFromSpec<Ipv4, FakeDualStackCoreCtx<D>, FakeStateSpec>,
6000 ) -> O,
6001 >(
6002 core_ctx: &mut FakeDualStackCoreCtx<D>,
6003 cb: F,
6004 ) -> O {
6005 let FakeDualStackCoreCtx { bound_sockets, ip_socket_ctx } = core_ctx;
6006 cb(ip_socket_ctx, bound_sockets.as_mut())
6007 }
6008
6009 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
6010 core_ctx: &mut FakeDualStackCoreCtx<D>,
6011 cb: F,
6012 ) -> O {
6013 cb(&mut core_ctx.ip_socket_ctx)
6014 }
6015 }
6016
6017 #[ip_test(I)]
6018 fn set_get_hop_limits<I: DatagramIpExt<FakeDeviceId>>() {
6019 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, FakeDeviceId>::new());
6020 let mut api = ctx.datagram_api::<I>();
6021
6022 let unbound = api.create_default();
6023 const EXPECTED_HOP_LIMITS: HopLimits = HopLimits {
6024 unicast: NonZeroU8::new(45).unwrap(),
6025 multicast: NonZeroU8::new(23).unwrap(),
6026 };
6027
6028 api.update_ip_hop_limit(&unbound, |limits| {
6029 *limits = SocketHopLimits {
6030 unicast: Some(EXPECTED_HOP_LIMITS.unicast),
6031 multicast: Some(EXPECTED_HOP_LIMITS.multicast),
6032 version: IpVersionMarker::default(),
6033 }
6034 });
6035
6036 assert_eq!(api.get_ip_hop_limits(&unbound), EXPECTED_HOP_LIMITS);
6037 }
6038
6039 #[ip_test(I)]
6040 fn set_get_device_hop_limits<I: DatagramIpExt<FakeReferencyDeviceId>>() {
6041 let device = FakeReferencyDeviceId::default();
6042 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(
6043 FakeDualStackIpSocketCtx::new([FakeDeviceConfig::<_, SpecifiedAddr<I::Addr>> {
6044 device: device.clone(),
6045 local_ips: Default::default(),
6046 remote_ips: Default::default(),
6047 }]),
6048 ));
6049 let mut api = ctx.datagram_api::<I>();
6050
6051 let unbound = api.create_default();
6052 api.set_device(&unbound, Some(&device)).unwrap();
6053
6054 let HopLimits { mut unicast, multicast } = DEFAULT_HOP_LIMITS;
6055 unicast = unicast.checked_add(1).unwrap();
6056 {
6057 let device_state =
6058 api.core_ctx().dual_stack.ip_socket_ctx.state.get_device_state_mut::<I>(&device);
6059 assert_ne!(device_state.default_hop_limit, unicast);
6060 device_state.default_hop_limit = unicast;
6061 }
6062 assert_eq!(api.get_ip_hop_limits(&unbound), HopLimits { unicast, multicast });
6063
6064 device.mark_removed();
6066 assert_eq!(api.get_ip_hop_limits(&unbound), DEFAULT_HOP_LIMITS);
6067 }
6068
6069 #[ip_test(I)]
6070 fn default_hop_limits<I: DatagramIpExt<FakeDeviceId>>() {
6071 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, FakeDeviceId>::new());
6072 let mut api = ctx.datagram_api::<I>();
6073 let unbound = api.create_default();
6074 assert_eq!(api.get_ip_hop_limits(&unbound), DEFAULT_HOP_LIMITS);
6075
6076 api.update_ip_hop_limit(&unbound, |limits| {
6077 *limits = SocketHopLimits {
6078 unicast: Some(NonZeroU8::new(1).unwrap()),
6079 multicast: Some(NonZeroU8::new(1).unwrap()),
6080 version: IpVersionMarker::default(),
6081 }
6082 });
6083
6084 assert_ne!(api.get_ip_hop_limits(&unbound), DEFAULT_HOP_LIMITS);
6086
6087 api.update_ip_hop_limit(&unbound, |limits| *limits = Default::default());
6089
6090 assert_eq!(api.get_ip_hop_limits(&unbound), DEFAULT_HOP_LIMITS);
6092 }
6093
6094 #[ip_test(I)]
6095 fn bind_device_unbound<I: DatagramIpExt<FakeDeviceId>>() {
6096 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, FakeDeviceId>::new());
6097 let mut api = ctx.datagram_api::<I>();
6098 let unbound = api.create_default();
6099
6100 api.set_device(&unbound, Some(&FakeDeviceId)).unwrap();
6101 assert_eq!(api.get_bound_device(&unbound), Some(FakeWeakDeviceId(FakeDeviceId)));
6102
6103 api.set_device(&unbound, None).unwrap();
6104 assert_eq!(api.get_bound_device(&unbound), None);
6105 }
6106
6107 #[ip_test(I)]
6108 fn send_to_binds_unbound<I: DatagramIpExt<FakeDeviceId>>() {
6109 let mut ctx =
6110 FakeCtx::with_core_ctx(FakeCoreCtx::<I, FakeDeviceId>::new_with_ip_socket_ctx(
6111 FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
6112 device: FakeDeviceId,
6113 local_ips: vec![I::TEST_ADDRS.local_ip],
6114 remote_ips: vec![I::TEST_ADDRS.remote_ip],
6115 }]),
6116 ));
6117 let mut api = ctx.datagram_api::<I>();
6118 let socket = api.create_default();
6119 let body = Buf::new(Vec::new(), ..);
6120
6121 api.send_to(&socket, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), 1234, body)
6122 .expect("succeeds");
6123 assert_matches!(api.get_info(&socket), SocketInfo::Listener(_));
6124 }
6125
6126 #[ip_test(I)]
6127 fn send_to_no_route_still_binds<I: DatagramIpExt<FakeDeviceId>>() {
6128 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(
6129 FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
6130 device: FakeDeviceId,
6131 local_ips: vec![I::TEST_ADDRS.local_ip],
6132 remote_ips: vec![],
6133 }]),
6134 ));
6135 let mut api = ctx.datagram_api::<I>();
6136 let socket = api.create_default();
6137 let body = Buf::new(Vec::new(), ..);
6138
6139 assert_matches!(
6140 api.send_to(&socket, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)), 1234, body,),
6141 Err(Either::Right(SendToError::CreateAndSend(_)))
6142 );
6143 assert_matches!(api.get_info(&socket), SocketInfo::Listener(_));
6144 }
6145
6146 #[ip_test(I)]
6147 #[test_case(true; "remove device b")]
6148 #[test_case(false; "dont remove device b")]
6149 fn multicast_membership_changes<I: DatagramIpExt<FakeReferencyDeviceId> + TestIpExt>(
6150 remove_device_b: bool,
6151 ) {
6152 let device_a = FakeReferencyDeviceId::default();
6153 let device_b = FakeReferencyDeviceId::default();
6154 let mut core_ctx = FakeIpSocketCtx::<I, FakeReferencyDeviceId>::new(
6155 [device_a.clone(), device_b.clone()].into_iter().map(|device| FakeDeviceConfig {
6156 device,
6157 local_ips: Default::default(),
6158 remote_ips: Default::default(),
6159 }),
6160 );
6161 let mut bindings_ctx = FakeBindingsCtx::default();
6162
6163 let multicast_addr1 = I::get_multicast_addr(1);
6164 let mut memberships = MulticastMemberships::default();
6165 assert_eq!(
6166 memberships.apply_membership_change(
6167 multicast_addr1,
6168 &FakeWeakDeviceId(device_a.clone()),
6169 true ),
6171 Some(MulticastMembershipChange::Join),
6172 );
6173 core_ctx.join_multicast_group(&mut bindings_ctx, &device_a, multicast_addr1);
6174
6175 let multicast_addr2 = I::get_multicast_addr(2);
6176 assert_eq!(
6177 memberships.apply_membership_change(
6178 multicast_addr2,
6179 &FakeWeakDeviceId(device_b.clone()),
6180 true ),
6182 Some(MulticastMembershipChange::Join),
6183 );
6184 core_ctx.join_multicast_group(&mut bindings_ctx, &device_b, multicast_addr2);
6185
6186 for (device, addr, expected) in [
6187 (&device_a, multicast_addr1, true),
6188 (&device_a, multicast_addr2, false),
6189 (&device_b, multicast_addr1, false),
6190 (&device_b, multicast_addr2, true),
6191 ] {
6192 assert_eq!(
6193 core_ctx.get_device_state(device).is_in_multicast_group(&addr),
6194 expected,
6195 "device={:?}, addr={}",
6196 device,
6197 addr,
6198 );
6199 }
6200
6201 if remove_device_b {
6202 device_b.mark_removed();
6203 }
6204
6205 leave_all_joined_groups(&mut core_ctx, &mut bindings_ctx, &memberships);
6206 for (device, addr, expected) in [
6207 (&device_a, multicast_addr1, false),
6208 (&device_a, multicast_addr2, false),
6209 (&device_b, multicast_addr1, false),
6210 (&device_b, multicast_addr2, remove_device_b),
6215 ] {
6216 assert_eq!(
6217 core_ctx.get_device_state(device).is_in_multicast_group(&addr),
6218 expected,
6219 "device={:?}, addr={}",
6220 device,
6221 addr,
6222 );
6223 }
6224 }
6225
6226 #[ip_test(I)]
6227 fn set_get_transparent<I: DatagramIpExt<FakeDeviceId>>() {
6228 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(
6229 FakeDualStackIpSocketCtx::new([FakeDeviceConfig::<_, SpecifiedAddr<I::Addr>> {
6230 device: FakeDeviceId,
6231 local_ips: Default::default(),
6232 remote_ips: Default::default(),
6233 }]),
6234 ));
6235 let mut api = ctx.datagram_api::<I>();
6236 let unbound = api.create_default();
6237
6238 assert!(!api.get_ip_transparent(&unbound));
6239
6240 api.set_ip_transparent(&unbound, true);
6241
6242 assert!(api.get_ip_transparent(&unbound));
6243
6244 api.set_ip_transparent(&unbound, false);
6245
6246 assert!(!api.get_ip_transparent(&unbound));
6247 }
6248
6249 #[ip_test(I)]
6250 fn transparent_bind_connect_non_local_src_addr<I: DatagramIpExt<FakeDeviceId>>() {
6251 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(
6252 FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
6253 device: FakeDeviceId,
6254 local_ips: vec![],
6255 remote_ips: vec![I::TEST_ADDRS.remote_ip],
6256 }]),
6257 ));
6258 let mut api = ctx.datagram_api::<I>();
6259 let socket = api.create_default();
6260 api.set_ip_transparent(&socket, true);
6261
6262 const LOCAL_PORT: NonZeroU16 = NonZeroU16::new(10).unwrap();
6263 const REMOTE_PORT: u16 = 1234;
6264
6265 api.listen(&socket, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT))
6268 .expect("listen should succeed");
6269
6270 api.connect(
6273 &socket,
6274 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
6275 REMOTE_PORT,
6276 Default::default(),
6277 )
6278 .expect("connect should succeed");
6279
6280 api.send_to(
6281 &socket,
6282 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
6283 REMOTE_PORT,
6284 Buf::new(Vec::new(), ..),
6285 )
6286 .expect("send_to should succeed");
6287 }
6288
6289 #[derive(Eq, PartialEq)]
6290 enum OriginalSocketState {
6291 Unbound,
6292 Listener,
6293 Connected,
6294 }
6295
6296 #[ip_test(I)]
6297 #[test_case(OriginalSocketState::Unbound; "reinsert_unbound")]
6298 #[test_case(OriginalSocketState::Listener; "reinsert_listener")]
6299 #[test_case(OriginalSocketState::Connected; "reinsert_connected")]
6300 fn connect_reinserts_on_failure_single_stack<I: DatagramIpExt<FakeDeviceId>>(
6301 original: OriginalSocketState,
6302 ) {
6303 connect_reinserts_on_failure_inner::<I>(
6304 original,
6305 I::TEST_ADDRS.local_ip.get(),
6306 I::TEST_ADDRS.remote_ip,
6307 );
6308 }
6309
6310 #[test_case(OriginalSocketState::Listener, net_ip_v6!("::FFFF:192.0.2.1"),
6311 net_ip_v4!("192.0.2.2"); "reinsert_listener_other_stack")]
6312 #[test_case(OriginalSocketState::Listener, net_ip_v6!("::"),
6313 net_ip_v4!("192.0.2.2"); "reinsert_listener_both_stacks")]
6314 #[test_case(OriginalSocketState::Connected, net_ip_v6!("::FFFF:192.0.2.1"),
6315 net_ip_v4!("192.0.2.2"); "reinsert_connected_other_stack")]
6316 fn connect_reinserts_on_failure_dual_stack(
6317 original: OriginalSocketState,
6318 local_ip: Ipv6Addr,
6319 remote_ip: Ipv4Addr,
6320 ) {
6321 let remote_ip = remote_ip.to_ipv6_mapped();
6322 connect_reinserts_on_failure_inner::<Ipv6>(original, local_ip, remote_ip);
6323 }
6324
6325 fn connect_reinserts_on_failure_inner<I: DatagramIpExt<FakeDeviceId>>(
6326 original: OriginalSocketState,
6327 local_ip: I::Addr,
6328 remote_ip: SpecifiedAddr<I::Addr>,
6329 ) {
6330 let mut ctx = testutil::setup_fake_ctx_with_dualstack_conn_addrs::<_, FakeBindingsCtx, _>(
6331 local_ip.to_ip_addr(),
6332 remote_ip.into(),
6333 [FakeDeviceId {}],
6334 |device_configs| {
6335 FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(FakeDualStackIpSocketCtx::new(
6336 device_configs,
6337 ))
6338 },
6339 );
6340 let mut api = ctx.datagram_api::<I>();
6341 let socket = api.create_default();
6342 const LOCAL_PORT: NonZeroU16 = NonZeroU16::new(10).unwrap();
6343 const ORIGINAL_REMOTE_PORT: u16 = 1234;
6344 const NEW_REMOTE_PORT: u16 = 5678;
6345
6346 match original {
6348 OriginalSocketState::Unbound => {}
6349 OriginalSocketState::Listener => api
6350 .listen(
6351 &socket,
6352 SpecifiedAddr::new(local_ip).map(ZonedAddr::Unzoned),
6353 Some(LOCAL_PORT),
6354 )
6355 .expect("listen should succeed"),
6356 OriginalSocketState::Connected => api
6357 .connect(
6358 &socket,
6359 Some(ZonedAddr::Unzoned(remote_ip)),
6360 ORIGINAL_REMOTE_PORT,
6361 Default::default(),
6362 )
6363 .expect("connect should succeed"),
6364 }
6365
6366 api.core_ctx().with_socket_state_mut(
6368 &socket,
6369 |_core_ctx, state: &mut SocketState<I, _, FakeStateSpec>| {
6370 let sharing = match &mut state.inner {
6371 SocketStateInner::Unbound(UnboundSocketState { device: _, sharing }) => sharing,
6372 SocketStateInner::Bound(BoundSocketState {
6373 socket_type,
6374 original_bound_addr: _,
6375 }) => match socket_type {
6376 BoundSocketStateType::Connected { state: _, sharing } => sharing,
6377 BoundSocketStateType::Listener { state: _, sharing } => sharing,
6378 },
6379 };
6380 *sharing = Sharing::ConnectionConflicts { remote_port: NEW_REMOTE_PORT };
6381 },
6382 );
6383
6384 assert_matches!(
6386 api.connect(
6387 &socket,
6388 Some(ZonedAddr::Unzoned(remote_ip)),
6389 NEW_REMOTE_PORT,
6390 Default::default(),
6391 ),
6392 Err(ConnectError::SockAddrConflict)
6393 );
6394
6395 let info = api.get_info(&socket);
6397 match original {
6398 OriginalSocketState::Unbound => assert_matches!(info, SocketInfo::Unbound),
6399 OriginalSocketState::Listener => {
6400 let local_port = assert_matches!(
6401 info,
6402 SocketInfo::Listener(ListenerInfo {
6403 local_ip: _,
6404 local_identifier,
6405 }) => local_identifier
6406 );
6407 assert_eq!(LOCAL_PORT, local_port);
6408 }
6409 OriginalSocketState::Connected => {
6410 let remote_port = assert_matches!(
6411 info,
6412 SocketInfo::Connected(ConnInfo {
6413 local_ip: _,
6414 local_identifier: _,
6415 remote_ip: _,
6416 remote_identifier,
6417 }) => remote_identifier
6418 );
6419 assert_eq!(ORIGINAL_REMOTE_PORT, remote_port);
6420 }
6421 }
6422 }
6423
6424 #[test_case(net_ip_v6!("::a:b:c:d"), ShutdownType::Send; "this_stack_send")]
6425 #[test_case(net_ip_v6!("::a:b:c:d"), ShutdownType::Receive; "this_stack_receive")]
6426 #[test_case(net_ip_v6!("::a:b:c:d"), ShutdownType::SendAndReceive; "this_stack_send_and_receive")]
6427 #[test_case(net_ip_v6!("::FFFF:192.0.2.1"), ShutdownType::Send; "other_stack_send")]
6428 #[test_case(net_ip_v6!("::FFFF:192.0.2.1"), ShutdownType::Receive; "other_stack_receive")]
6429 #[test_case(net_ip_v6!("::FFFF:192.0.2.1"), ShutdownType::SendAndReceive; "other_stack_send_and_receive")]
6430 fn set_get_shutdown_dualstack(remote_ip: Ipv6Addr, shutdown: ShutdownType) {
6431 let remote_ip = SpecifiedAddr::new(remote_ip).expect("remote_ip should be specified");
6432 let mut ctx = testutil::setup_fake_ctx_with_dualstack_conn_addrs::<_, FakeBindingsCtx, _>(
6433 Ipv6::UNSPECIFIED_ADDRESS.into(),
6434 remote_ip.into(),
6435 [FakeDeviceId {}],
6436 |device_configs| {
6437 FakeCoreCtx::<Ipv6, _>::new_with_ip_socket_ctx(FakeDualStackIpSocketCtx::new(
6438 device_configs,
6439 ))
6440 },
6441 );
6442 let mut api = ctx.datagram_api::<Ipv6>();
6443
6444 const REMOTE_PORT: u16 = 1234;
6445 let socket = api.create_default();
6446 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT, Default::default())
6447 .expect("connect should succeed");
6448 assert_eq!(api.get_shutdown_connected(&socket), None);
6449
6450 api.shutdown_connected(&socket, shutdown).expect("shutdown should succeed");
6451 assert_eq!(api.get_shutdown_connected(&socket), Some(shutdown));
6452 }
6453
6454 #[ip_test(I)]
6455 #[test_case(OriginalSocketState::Unbound; "unbound")]
6456 #[test_case(OriginalSocketState::Listener; "listener")]
6457 #[test_case(OriginalSocketState::Connected; "connected")]
6458 fn set_get_device_single_stack<I: DatagramIpExt<MultipleDevicesId>>(
6459 original: OriginalSocketState,
6460 ) {
6461 set_get_device_inner::<I>(original, I::TEST_ADDRS.local_ip.get(), I::TEST_ADDRS.remote_ip);
6462 }
6463
6464 #[test_case(OriginalSocketState::Listener, net_ip_v6!("::FFFF:192.0.2.1"),
6465 net_ip_v4!("192.0.2.2"); "listener_other_stack")]
6466 #[test_case(OriginalSocketState::Listener, net_ip_v6!("::"),
6467 net_ip_v4!("192.0.2.2"); "listener_both_stacks")]
6468 #[test_case(OriginalSocketState::Connected, net_ip_v6!("::FFFF:192.0.2.1"),
6469 net_ip_v4!("192.0.2.2"); "connected_other_stack")]
6470 fn set_get_device_dual_stack(
6471 original: OriginalSocketState,
6472 local_ip: Ipv6Addr,
6473 remote_ip: Ipv4Addr,
6474 ) {
6475 let remote_ip = remote_ip.to_ipv6_mapped();
6476 set_get_device_inner::<Ipv6>(original, local_ip, remote_ip);
6477 }
6478
6479 fn set_get_device_inner<I: DatagramIpExt<MultipleDevicesId>>(
6480 original: OriginalSocketState,
6481 local_ip: I::Addr,
6482 remote_ip: SpecifiedAddr<I::Addr>,
6483 ) {
6484 const DEVICE_ID1: MultipleDevicesId = MultipleDevicesId::A;
6485 const DEVICE_ID2: MultipleDevicesId = MultipleDevicesId::B;
6486
6487 let mut ctx = testutil::setup_fake_ctx_with_dualstack_conn_addrs::<_, FakeBindingsCtx, _>(
6488 local_ip.to_ip_addr(),
6489 remote_ip.into(),
6490 [DEVICE_ID1, DEVICE_ID2],
6491 |device_configs| {
6492 FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(FakeDualStackIpSocketCtx::new(
6493 device_configs,
6494 ))
6495 },
6496 );
6497
6498 const LOCAL_PORT: NonZeroU16 = NonZeroU16::new(10).unwrap();
6499 const REMOTE_PORT: u16 = 1234;
6500
6501 let mut api = ctx.datagram_api::<I>();
6502 let socket1 = api.create_default();
6503 let socket2 = api.create_default();
6504
6505 for (socket, device_id) in [(&socket1, DEVICE_ID1), (&socket2, DEVICE_ID2)] {
6508 match original {
6509 OriginalSocketState::Unbound => {}
6510 OriginalSocketState::Listener => api
6511 .listen(
6512 &socket,
6513 SpecifiedAddr::new(local_ip).map(ZonedAddr::Unzoned),
6514 Some(LOCAL_PORT),
6515 )
6516 .expect("listen should succeed"),
6517 OriginalSocketState::Connected => api
6518 .connect(
6519 &socket,
6520 Some(ZonedAddr::Unzoned(remote_ip)),
6521 REMOTE_PORT,
6522 Default::default(),
6523 )
6524 .expect("connect should succeed"),
6525 }
6526
6527 assert_eq!(api.get_bound_device(socket), None);
6528 api.set_device(socket, Some(&device_id)).expect("set device should succeed");
6529 assert_eq!(api.get_bound_device(socket), Some(FakeWeakDeviceId(device_id)));
6530 }
6531
6532 if original != OriginalSocketState::Unbound {
6536 assert_eq!(
6537 api.set_device(&socket2, Some(&DEVICE_ID1)),
6538 Err(SocketError::Local(LocalAddressError::AddressInUse))
6539 );
6540 assert_eq!(api.get_bound_device(&socket1), Some(FakeWeakDeviceId(DEVICE_ID1)));
6542 assert_eq!(api.get_bound_device(&socket2), Some(FakeWeakDeviceId(DEVICE_ID2)));
6543 }
6544
6545 api.close(socket2).into_removed();
6548 api.set_device(&socket1, None).expect("set device should succeed");
6549 assert_eq!(api.get_bound_device(&socket1), None,);
6550 }
6551}