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