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, 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, MulticastMembershipHandler, ResolveRouteError,
49 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>>,
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>>;
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>> {
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 {}
820impl<BT> DatagramBindingsTypes for BT where BT: TxMetadataBindingsTypes {}
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: 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 type SerializeError: Error;
1472
1473 fn make_packet<I: IpExt, B: BufferMut>(
1475 body: B,
1476 addr: &ConnIpAddr<
1477 I::Addr,
1478 <Self::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1479 <Self::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
1480 >,
1481 ) -> Result<Self::Serializer<I, B>, Self::SerializeError>;
1482
1483 fn try_alloc_listen_identifier<I: IpExt, D: WeakDeviceIdentifier>(
1487 rng: &mut impl RngContext,
1488 is_available: impl Fn(
1489 <Self::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1490 ) -> Result<(), InUseError>,
1491 ) -> Option<<Self::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>;
1492
1493 fn conn_info_from_state<I: IpExt, D: WeakDeviceIdentifier>(
1495 state: &Self::ConnState<I, D>,
1496 ) -> ConnInfo<I::Addr, D>;
1497
1498 fn try_alloc_local_id<I: IpExt, D: WeakDeviceIdentifier, BC: RngContext>(
1500 bound: &BoundDatagramSocketMap<I, D, Self>,
1501 bindings_ctx: &mut BC,
1502 flow: DatagramFlowId<I::Addr, <Self::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier>,
1503 ) -> Option<<Self::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>;
1504
1505 fn downgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
1508 id: &Self::SocketId<I, D>,
1509 ) -> Self::WeakSocketId<I, D>;
1510
1511 fn upgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
1514 id: &Self::WeakSocketId<I, D>,
1515 ) -> Option<Self::SocketId<I, D>>;
1516}
1517
1518pub struct InUseError;
1520
1521pub fn create_primary_id<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1523 external_data: S::ExternalData<I>,
1524) -> PrimaryRc<I, D, S> {
1525 PrimaryRc::new(ReferenceState {
1526 state: RwLock::new(SocketState {
1527 inner: SocketStateInner::Unbound(UnboundSocketState::default()),
1528 ip_options: Default::default(),
1529 sharing: Default::default(),
1530 }),
1531 external_data,
1532 counters: Default::default(),
1533 })
1534}
1535
1536#[derive(GenericOverIp, Debug, Eq, PartialEq)]
1538#[generic_over_ip(A, IpAddress)]
1539pub struct ListenerInfo<A: IpAddress, D> {
1540 pub local_ip: Option<StrictlyZonedAddr<A, SpecifiedAddr<A>, D>>,
1543 pub local_identifier: NonZeroU16,
1545}
1546
1547impl<A: IpAddress, LA: Into<(Option<SpecifiedAddr<A>>, NonZeroU16)>, D> From<ListenerAddr<LA, D>>
1548 for ListenerInfo<A, D>
1549{
1550 fn from(ListenerAddr { ip, device }: ListenerAddr<LA, D>) -> Self {
1551 let (addr, local_identifier) = ip.into();
1552 Self {
1553 local_ip: addr.map(|addr| {
1554 StrictlyZonedAddr::new_with_zone(addr, || {
1555 device.expect("device must be bound for addresses that require zones")
1558 })
1559 }),
1560 local_identifier,
1561 }
1562 }
1563}
1564
1565impl<A: IpAddress, D> From<NonZeroU16> for ListenerInfo<A, D> {
1566 fn from(local_identifier: NonZeroU16) -> Self {
1567 Self { local_ip: None, local_identifier }
1568 }
1569}
1570
1571#[derive(Debug, GenericOverIp, PartialEq)]
1573#[generic_over_ip(A, IpAddress)]
1574pub struct ConnInfo<A: IpAddress, D> {
1575 pub local_ip: StrictlyZonedAddr<A, SpecifiedAddr<A>, D>,
1577 pub local_identifier: NonZeroU16,
1579 pub remote_ip: StrictlyZonedAddr<A, SpecifiedAddr<A>, D>,
1581 pub remote_identifier: u16,
1583}
1584
1585impl<A: IpAddress, D> ConnInfo<A, D> {
1586 pub fn new(
1588 local_ip: SpecifiedAddr<A>,
1589 local_identifier: NonZeroU16,
1590 remote_ip: SpecifiedAddr<A>,
1591 remote_identifier: u16,
1592 mut get_zone: impl FnMut() -> D,
1593 ) -> Self {
1594 Self {
1595 local_ip: StrictlyZonedAddr::new_with_zone(local_ip, &mut get_zone),
1596 local_identifier,
1597 remote_ip: StrictlyZonedAddr::new_with_zone(remote_ip, &mut get_zone),
1598 remote_identifier,
1599 }
1600 }
1601}
1602
1603#[derive(GenericOverIp, Debug, PartialEq)]
1605#[generic_over_ip(A, IpAddress)]
1606pub enum SocketInfo<A: IpAddress, D> {
1607 Unbound,
1609 Listener(ListenerInfo<A, D>),
1611 Connected(ConnInfo<A, D>),
1613}
1614
1615trait EntryOperationType {
1617 type ReverseOp: EntryOperationType<ReverseOp = Self>;
1618 type Error: Debug;
1619
1620 fn apply<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1622 op: SocketEntryOp<I, D, S, Self>,
1623 sockets: &mut BoundDatagramSocketMap<I, D, S>,
1624 ) -> Result<SocketEntryOp<I, D, S, Self::ReverseOp>, Self::Error>;
1625}
1626
1627enum EntryInsertOp {}
1628impl EntryOperationType for EntryInsertOp {
1629 type ReverseOp = EntryRemoveOp;
1630 type Error = InsertError;
1631
1632 fn apply<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1633 op: SocketEntryOp<I, D, S, Self>,
1634 sockets: &mut BoundDatagramSocketMap<I, D, S>,
1635 ) -> Result<SocketEntryOp<I, D, S, Self::ReverseOp>, Self::Error> {
1636 let SocketEntryOp { socket_id, sharing, addr, _marker } = op;
1637 match &addr {
1638 AddrVec::Listen(addr) => {
1639 let SocketStateEntry { .. } = sockets.listeners_mut().try_insert(
1640 addr.clone(),
1641 sharing.clone(),
1642 socket_id.clone(),
1643 )?;
1644 }
1645 AddrVec::Conn(addr) => {
1646 let SocketStateEntry { .. } = sockets.conns_mut().try_insert(
1647 addr.clone(),
1648 sharing.clone(),
1649 socket_id.clone(),
1650 )?;
1651 }
1652 };
1653 Ok(SocketEntryOp { socket_id, sharing, addr, _marker: PhantomData })
1654 }
1655}
1656
1657enum EntryRemoveOp {}
1658impl EntryOperationType for EntryRemoveOp {
1659 type ReverseOp = EntryInsertOp;
1660 type Error = NotFoundError;
1661
1662 fn apply<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>(
1663 op: SocketEntryOp<I, D, S, Self>,
1664 sockets: &mut BoundDatagramSocketMap<I, D, S>,
1665 ) -> Result<SocketEntryOp<I, D, S, Self::ReverseOp>, Self::Error> {
1666 let SocketEntryOp { socket_id, sharing, addr, _marker } = op;
1667 match &addr {
1668 AddrVec::Listen(addr) => {
1669 sockets.listeners_mut().remove(&socket_id, &addr)?;
1670 }
1671 AddrVec::Conn(addr) => {
1672 sockets.conns_mut().remove(&socket_id, &addr)?;
1673 }
1674 };
1675 Ok(SocketEntryOp { socket_id, sharing, addr, _marker: PhantomData })
1676 }
1677}
1678
1679struct SocketEntryOp<
1681 I: IpExt,
1682 D: WeakDeviceIdentifier,
1683 S: DatagramSocketSpec,
1684 O: EntryOperationType + ?Sized,
1685> {
1686 socket_id: <S::SocketMapSpec<I, D> as DatagramSocketMapSpec<I, D, S::AddrSpec>>::BoundSocketId,
1687 sharing: S::SharingState,
1688 addr: AddrVec<I, D, S::AddrSpec>,
1689 _marker: PhantomData<O>,
1690}
1691
1692type SingleStackRemoveOperation<I, D, S> = SocketEntryOp<I, D, S, EntryRemoveOp>;
1693type SingleStackInsertOperation<I, D, S> = SocketEntryOp<I, D, S, EntryInsertOp>;
1694
1695impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> SingleStackRemoveOperation<I, D, S> {
1696 fn new_from_state<BC, CC: NonDualStackDatagramBoundStateContext<I, BC, S, WeakDeviceId = D>>(
1698 core_ctx: &mut CC,
1699 socket_id: &S::SocketId<I, D>,
1700 state: &BoundSocketState<I, D, S>,
1701 sharing: S::SharingState,
1702 ) -> Self {
1703 let BoundSocketState { socket_type: state, original_bound_addr: _ } = state;
1704 match state {
1705 BoundSocketStateType::Listener(ListenerState { addr: ListenerAddr { ip, device } }) => {
1706 Self {
1707 addr: AddrVec::Listen(ListenerAddr {
1708 ip: core_ctx.nds_converter().convert(ip.clone()),
1709 device: device.clone(),
1710 }),
1711 sharing,
1712 socket_id: S::make_bound_socket_map_id(socket_id),
1713 _marker: PhantomData,
1714 }
1715 }
1716 BoundSocketStateType::Connected(state) => {
1717 let ConnState {
1718 addr,
1719 socket: _,
1720 clear_device_on_disconnect: _,
1721 shutdown: _,
1722 extra: _,
1723 } = core_ctx.nds_converter().convert(state);
1724 Self {
1725 addr: AddrVec::Conn(addr.clone()),
1726 sharing,
1727 socket_id: S::make_bound_socket_map_id(socket_id),
1728 _marker: PhantomData,
1729 }
1730 }
1731 }
1732 }
1733}
1734
1735impl<I, D, S, O> SocketEntryOp<I, D, S, O>
1736where
1737 I: IpExt,
1738 D: WeakDeviceIdentifier,
1739 S: DatagramSocketSpec,
1740 O: EntryOperationType,
1741{
1742 fn apply(
1744 self,
1745 sockets: &mut BoundDatagramSocketMap<I, D, S>,
1746 ) -> Result<SocketEntryOp<I, D, S, O::ReverseOp>, O::Error> {
1747 O::apply(self, sockets)
1748 }
1749}
1750
1751struct DualStackListenerOp<I, D, S, O>
1752where
1753 I: IpExt,
1754 D: WeakDeviceIdentifier,
1755 S: DatagramSocketSpec,
1756 O: EntryOperationType,
1757{
1758 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1759 device: Option<D>,
1760 sharing: S::SharingState,
1761 socket_ids: PairedBoundSocketIds<I, D, S>,
1762 _marker: PhantomData<O>,
1763}
1764
1765type DualStackListenerRemoveOperation<I, D, S> = DualStackListenerOp<I, D, S, EntryRemoveOp>;
1766type DualStackListenerInsertOperation<I, D, S> = DualStackListenerOp<I, D, S, EntryInsertOp>;
1767
1768impl<I, D, S, O> DualStackListenerOp<I, D, S, O>
1769where
1770 I: IpExt,
1771 D: WeakDeviceIdentifier,
1772 S: DatagramSocketSpec,
1773 O: EntryOperationType,
1774{
1775 fn this_stack_op(&self) -> SocketEntryOp<I, D, S, O> {
1776 SocketEntryOp {
1777 addr: AddrVec::Listen(ListenerAddr {
1778 ip: ListenerIpAddr { addr: None, identifier: self.identifier },
1779 device: self.device.clone(),
1780 }),
1781 sharing: self.sharing.clone(),
1782 socket_id: self.socket_ids.this.clone(),
1783 _marker: PhantomData,
1784 }
1785 }
1786
1787 fn other_stack_op(&self) -> SocketEntryOp<I::OtherVersion, D, S, O> {
1788 SocketEntryOp {
1789 addr: AddrVec::Listen(ListenerAddr {
1790 ip: ListenerIpAddr { addr: None, identifier: self.identifier },
1791 device: self.device.clone(),
1792 }),
1793 sharing: self.sharing.clone(),
1794 socket_id: self.socket_ids.other.clone(),
1795 _marker: PhantomData,
1796 }
1797 }
1798
1799 fn apply(
1802 self,
1803 sockets: &mut BoundDatagramSocketMap<I, D, S>,
1804 other_sockets: &mut BoundDatagramSocketMap<I::OtherVersion, D, S>,
1805 ) -> Result<DualStackListenerOp<I, D, S, O::ReverseOp>, O::Error> {
1806 let this_stack_reverse_op = self.this_stack_op().apply(sockets)?;
1807 match self.other_stack_op().apply(other_sockets) {
1808 Ok(SocketEntryOp::<_, _, _, O::ReverseOp> { .. }) => (),
1809 Err(e) => {
1810 let _: SocketEntryOp<_, _, _, O> = this_stack_reverse_op
1811 .apply(sockets)
1812 .expect("Failed to revert socket map operation");
1813 return Err(e);
1814 }
1815 };
1816
1817 let Self { identifier, device, sharing, socket_ids, _marker: _ } = self;
1818 Ok(DualStackListenerOp { identifier, device, sharing, socket_ids, _marker: PhantomData })
1819 }
1820}
1821
1822enum DualStackSocketEntryOp<I, D, S, O>
1824where
1825 I: IpExt,
1826 D: WeakDeviceIdentifier,
1827 S: DatagramSocketSpec,
1828 O: EntryOperationType,
1829{
1830 CurrentStack(SocketEntryOp<I, D, S, O>),
1831 OtherStack(SocketEntryOp<I::OtherVersion, D, S, O>),
1832 ListenerBothStacks(DualStackListenerOp<I, D, S, O>),
1833}
1834
1835type DualStackRemoveOperation<I, D, S> = DualStackSocketEntryOp<I, D, S, EntryRemoveOp>;
1836type DualStackInsertOperation<I, D, S> = DualStackSocketEntryOp<I, D, S, EntryInsertOp>;
1837
1838impl<I, D, S> DualStackRemoveOperation<I, D, S>
1839where
1840 I: IpExt,
1841 D: WeakDeviceIdentifier,
1842 S: DatagramSocketSpec,
1843{
1844 fn new_from_state<BC, CC>(
1846 core_ctx: &mut CC,
1847 socket_id: &S::SocketId<I, D>,
1848 ip_options: &IpOptions<I, D, S>,
1849 state: &BoundSocketState<I, D, S>,
1850 sharing: S::SharingState,
1851 ) -> Self
1852 where
1853 BC: DatagramBindingsTypes,
1854 CC: DualStackDatagramBoundStateContext<I, BC, S, WeakDeviceId = D>,
1855 {
1856 let BoundSocketState { socket_type: state, original_bound_addr: _ } = state;
1857 match state {
1858 BoundSocketStateType::Listener(ListenerState { addr }) => {
1859 let ListenerAddr { ip, device } = addr.clone();
1860 match (core_ctx.ds_converter().convert(ip), core_ctx.dual_stack_enabled(ip_options))
1861 {
1862 (DualStackListenerIpAddr::BothStacks(identifier), true) => {
1864 DualStackSocketEntryOp::ListenerBothStacks(DualStackListenerOp {
1865 identifier: identifier.clone(),
1866 device,
1867 sharing,
1868 socket_ids: PairedBoundSocketIds {
1869 this: S::make_bound_socket_map_id(socket_id),
1870 other: core_ctx.to_other_bound_socket_id(socket_id),
1871 },
1872 _marker: PhantomData,
1873 })
1874 }
1875 (DualStackListenerIpAddr::ThisStack(addr), true | false) => {
1877 DualStackSocketEntryOp::CurrentStack(SocketEntryOp {
1878 addr: AddrVec::Listen(ListenerAddr { ip: addr, device }),
1879 sharing,
1880 socket_id: S::make_bound_socket_map_id(socket_id),
1881 _marker: PhantomData,
1882 })
1883 }
1884 (DualStackListenerIpAddr::OtherStack(addr), true) => {
1886 DualStackSocketEntryOp::OtherStack(SocketEntryOp {
1887 addr: AddrVec::Listen(ListenerAddr { ip: addr, device }),
1888 sharing,
1889 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
1890 _marker: PhantomData,
1891 })
1892 }
1893 (DualStackListenerIpAddr::OtherStack(_), false)
1894 | (DualStackListenerIpAddr::BothStacks(_), false) => {
1895 unreachable!("dual-stack disabled socket cannot use the other stack")
1896 }
1897 }
1898 }
1899 BoundSocketStateType::Connected(state) => {
1900 match core_ctx.ds_converter().convert(state) {
1901 DualStackConnState::ThisStack(ConnState { addr, .. }) => {
1902 DualStackSocketEntryOp::CurrentStack(SocketEntryOp {
1903 addr: AddrVec::Conn(addr.clone()),
1904 sharing,
1905 socket_id: S::make_bound_socket_map_id(socket_id),
1906 _marker: PhantomData,
1907 })
1908 }
1909 DualStackConnState::OtherStack(ConnState { addr, .. }) => {
1910 core_ctx.assert_dual_stack_enabled(&ip_options);
1911 DualStackSocketEntryOp::OtherStack(SocketEntryOp {
1912 addr: AddrVec::Conn(addr.clone()),
1913 sharing,
1914 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
1915 _marker: PhantomData,
1916 })
1917 }
1918 }
1919 }
1920 }
1921 }
1922}
1923
1924impl<I, D, S, O> DualStackSocketEntryOp<I, D, S, O>
1925where
1926 I: IpExt,
1927 D: WeakDeviceIdentifier,
1928 S: DatagramSocketSpec,
1929 O: EntryOperationType,
1930{
1931 fn apply(
1934 self,
1935 sockets: &mut BoundDatagramSocketMap<I, D, S>,
1936 other_sockets: &mut BoundDatagramSocketMap<I::OtherVersion, D, S>,
1937 ) -> Result<DualStackSocketEntryOp<I, D, S, O::ReverseOp>, O::Error> {
1938 let result = match self {
1939 DualStackSocketEntryOp::CurrentStack(remove) => {
1940 DualStackSocketEntryOp::CurrentStack(remove.apply(sockets)?)
1941 }
1942 DualStackSocketEntryOp::OtherStack(remove) => {
1943 DualStackSocketEntryOp::OtherStack(remove.apply(other_sockets)?)
1944 }
1945 DualStackSocketEntryOp::ListenerBothStacks(listener_op) => {
1946 DualStackSocketEntryOp::ListenerBothStacks(
1947 listener_op.apply(sockets, other_sockets)?,
1948 )
1949 }
1950 };
1951 Ok(result)
1952 }
1953}
1954
1955trait BoundStateHandler<I: IpExt, S: DatagramSocketSpec, D: WeakDeviceIdentifier> {
1957 type ListenerAddr: Clone;
1959 type BoundSocketId;
1961
1962 fn is_listener_entry_available(
1968 &self,
1969 addr: Self::ListenerAddr,
1970 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1971 sharing_state: &S::SharingState,
1972 ) -> bool;
1973
1974 fn try_insert_listener(
1981 &mut self,
1982 addr: Self::ListenerAddr,
1983 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
1984 device: Option<D>,
1985 sharing: S::SharingState,
1986 id: Self::BoundSocketId,
1987 ) -> Result<(), LocalAddressError>;
1988}
1989
1990pub type BoundDatagramSocketMap<I, D, S> = BoundSocketMap<
1992 I,
1993 D,
1994 <S as DatagramSocketSpec>::AddrSpec,
1995 <S as DatagramSocketSpec>::SocketMapSpec<I, D>,
1996>;
1997
1998type BoundDatagramSocketId<I, D, S> =
1999 <<S as DatagramSocketSpec>::SocketMapSpec<I, D> as DatagramSocketMapSpec<
2000 I,
2001 D,
2002 <S as DatagramSocketSpec>::AddrSpec,
2003 >>::BoundSocketId;
2004
2005#[derive(Copy, Clone, Debug)]
2010struct DualStackUnspecifiedAddr;
2011
2012impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> BoundStateHandler<I, S, D>
2014 for BoundDatagramSocketMap<I, D, S>
2015{
2016 type ListenerAddr = Option<SocketIpAddr<I::Addr>>;
2017 type BoundSocketId = BoundDatagramSocketId<I, D, S>;
2018
2019 fn is_listener_entry_available(
2020 &self,
2021 addr: Self::ListenerAddr,
2022 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2023 sharing: &S::SharingState,
2024 ) -> bool {
2025 let check_addr = ListenerAddr { device: None, ip: ListenerIpAddr { identifier, addr } };
2026 match self.listeners().could_insert(&check_addr, sharing) {
2027 Ok(()) => true,
2028 Err(
2029 InsertError::Exists
2030 | InsertError::IndirectConflict
2031 | InsertError::ShadowAddrExists
2032 | InsertError::WouldShadowExisting,
2033 ) => false,
2034 }
2035 }
2036
2037 fn try_insert_listener(
2038 &mut self,
2039 addr: Self::ListenerAddr,
2040 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2041 device: Option<D>,
2042 sharing: S::SharingState,
2043 id: Self::BoundSocketId,
2044 ) -> Result<(), LocalAddressError> {
2045 let _: SocketStateEntry<'_, _, _, _, _, _> = self
2046 .listeners_mut()
2047 .try_insert(
2048 ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device },
2049 sharing,
2050 id,
2051 )
2052 .map_err(Into::<LocalAddressError>::into)?;
2053
2054 Ok(())
2055 }
2056}
2057
2058struct PairedSocketMapMut<'a, I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
2059 bound: &'a mut BoundDatagramSocketMap<I, D, S>,
2060 other_bound: &'a mut BoundDatagramSocketMap<I::OtherVersion, D, S>,
2061}
2062
2063#[derive(Derivative)]
2064#[derivative(Clone(bound = ""))]
2065struct PairedBoundSocketIds<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
2066 this: BoundDatagramSocketId<I, D, S>,
2067 other: BoundDatagramSocketId<I::OtherVersion, D, S>,
2068}
2069
2070impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> BoundStateHandler<I, S, D>
2072 for PairedSocketMapMut<'_, I, D, S>
2073{
2074 type ListenerAddr = DualStackUnspecifiedAddr;
2075 type BoundSocketId = PairedBoundSocketIds<I, D, S>;
2076
2077 fn is_listener_entry_available(
2078 &self,
2079 DualStackUnspecifiedAddr: Self::ListenerAddr,
2080 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2081 sharing: &S::SharingState,
2082 ) -> bool {
2083 let PairedSocketMapMut { bound, other_bound } = self;
2084 BoundStateHandler::<I, S, D>::is_listener_entry_available(*bound, None, identifier, sharing)
2085 && BoundStateHandler::<I::OtherVersion, S, D>::is_listener_entry_available(
2086 *other_bound,
2087 None,
2088 identifier,
2089 sharing,
2090 )
2091 }
2092
2093 fn try_insert_listener(
2094 &mut self,
2095 DualStackUnspecifiedAddr: Self::ListenerAddr,
2096 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
2097 device: Option<D>,
2098 sharing: S::SharingState,
2099 id: Self::BoundSocketId,
2100 ) -> Result<(), LocalAddressError> {
2101 let PairedSocketMapMut { bound: this, other_bound: other } = self;
2102
2103 let op = DualStackListenerInsertOperation {
2104 identifier,
2105 device,
2106 sharing,
2107 socket_ids: id,
2108 _marker: PhantomData,
2109 };
2110
2111 let _: DualStackListenerRemoveOperation<I, D, S> =
2112 op.apply(this, other).map_err(Into::<LocalAddressError>::into)?;
2113
2114 Ok(())
2115 }
2116}
2117
2118fn try_pick_identifier<
2119 I: IpExt,
2120 S: DatagramSocketSpec,
2121 D: WeakDeviceIdentifier,
2122 BS: BoundStateHandler<I, S, D>,
2123 BC: RngContext,
2124>(
2125 addr: BS::ListenerAddr,
2126 bound: &BS,
2127 bindings_ctx: &mut BC,
2128 sharing: &S::SharingState,
2129) -> Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier> {
2130 S::try_alloc_listen_identifier::<I, D>(bindings_ctx, move |identifier| {
2131 bound
2132 .is_listener_entry_available(addr.clone(), identifier, sharing)
2133 .then_some(())
2134 .ok_or(InUseError)
2135 })
2136}
2137
2138fn try_pick_bound_address<
2139 I: IpExt,
2140 CC: TransportIpContext<I, BC>,
2141 BC: DatagramBindingsTypes,
2142 LI,
2143>(
2144 addr: Option<ZonedAddr<SocketIpAddr<I::Addr>, CC::DeviceId>>,
2145 device: &Option<CC::WeakDeviceId>,
2146 core_ctx: &mut CC,
2147 identifier: LI,
2148 transparent: bool,
2149) -> Result<
2150 (Option<SocketIpAddr<I::Addr>>, Option<EitherDeviceId<CC::DeviceId, CC::WeakDeviceId>>, LI),
2151 LocalAddressError,
2152> {
2153 let (addr, device, identifier) = match addr {
2154 Some(addr) => {
2155 let (addr, device) = addr.resolve_addr_with_device(device.clone())?;
2159
2160 if !addr.addr().is_multicast() && !transparent {
2164 BaseTransportIpContext::<I, _>::with_devices_with_assigned_addr(
2165 core_ctx,
2166 addr.into(),
2167 |mut assigned_to| {
2168 if let Some(device) = &device {
2169 if !assigned_to.any(|d| device == &EitherDeviceId::Strong(d)) {
2170 return Err(LocalAddressError::AddressMismatch);
2171 }
2172 } else {
2173 if !assigned_to.any(|_: CC::DeviceId| true) {
2174 return Err(LocalAddressError::CannotBindToAddress);
2175 }
2176 }
2177 Ok(())
2178 },
2179 )?;
2180 }
2181 (Some(addr), device, identifier)
2182 }
2183 None => (None, device.clone().map(EitherDeviceId::Weak), identifier),
2184 };
2185 Ok((addr, device, identifier))
2186}
2187
2188fn listen_inner<
2189 I: IpExt,
2190 BC: DatagramBindingsContext,
2191 CC: DatagramBoundStateContext<I, BC, S>,
2192 S: DatagramSocketSpec,
2193>(
2194 core_ctx: &mut CC,
2195 bindings_ctx: &mut BC,
2196 state: &mut SocketState<I, CC::WeakDeviceId, S>,
2197 id: &S::SocketId<I, CC::WeakDeviceId>,
2198 addr: Option<ZonedAddr<SpecifiedAddr<I::Addr>, CC::DeviceId>>,
2199 local_id: Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
2200) -> Result<(), Either<ExpectedUnboundError, LocalAddressError>> {
2201 #[derive(Debug, GenericOverIp)]
2205 #[generic_over_ip(I, Ip)]
2206 enum BoundOperation<'a, I: IpExt, DS: DeviceIdContext<AnyDevice>, NDS> {
2207 DualStackAnyAddr(&'a mut DS),
2209 OnlyCurrentStack(
2211 MaybeDualStack<&'a mut DS, &'a mut NDS>,
2212 Option<ZonedAddr<SocketIpAddr<I::Addr>, DS::DeviceId>>,
2213 ),
2214 OnlyOtherStack(
2216 &'a mut DS,
2217 Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, DS::DeviceId>>,
2218 ),
2219 }
2220
2221 let SocketState { inner, ip_options, sharing } = state;
2222 let UnboundSocketState { device } = match inner {
2223 SocketStateInner::Unbound(state) => state,
2224 SocketStateInner::Bound(_) => return Err(Either::Left(ExpectedUnboundError)),
2225 };
2226
2227 let dual_stack = core_ctx.dual_stack_context_mut();
2228 let bound_operation: BoundOperation<'_, I, _, _> = match (dual_stack, addr) {
2229 (MaybeDualStack::DualStack(dual_stack), None) => {
2231 match dual_stack.dual_stack_enabled(ip_options) {
2232 true => BoundOperation::DualStackAnyAddr(dual_stack),
2234 false => {
2237 BoundOperation::OnlyCurrentStack(MaybeDualStack::DualStack(dual_stack), None)
2238 }
2239 }
2240 }
2241 (MaybeDualStack::DualStack(dual_stack), Some(addr)) => {
2244 match DualStackLocalIp::<I, _>::new(addr) {
2245 DualStackLocalIp::ThisStack(addr) => BoundOperation::OnlyCurrentStack(
2247 MaybeDualStack::DualStack(dual_stack),
2248 Some(addr),
2249 ),
2250 DualStackLocalIp::OtherStack(addr) => {
2252 match dual_stack.dual_stack_enabled(ip_options) {
2253 true => BoundOperation::OnlyOtherStack(dual_stack, addr),
2254 false => return Err(Either::Right(LocalAddressError::CannotBindToAddress)),
2255 }
2256 }
2257 }
2258 }
2259 (MaybeDualStack::NotDualStack(single_stack), None) => {
2261 BoundOperation::OnlyCurrentStack(MaybeDualStack::NotDualStack(single_stack), None)
2262 }
2263 (MaybeDualStack::NotDualStack(single_stack), Some(addr)) => {
2266 match DualStackLocalIp::<I, _>::new(addr) {
2267 DualStackLocalIp::ThisStack(addr) => BoundOperation::OnlyCurrentStack(
2269 MaybeDualStack::NotDualStack(single_stack),
2270 Some(addr),
2271 ),
2272 DualStackLocalIp::OtherStack(_addr) => {
2275 let _: Option<ZonedAddr<SocketIpAddr<<I::OtherVersion as Ip>::Addr>, _>> =
2276 _addr;
2277 return Err(Either::Right(LocalAddressError::CannotBindToAddress));
2278 }
2279 }
2280 }
2281 };
2282
2283 fn try_bind_single_stack<
2284 I: IpExt,
2285 S: DatagramSocketSpec,
2286 CC: TransportIpContext<I, BC>,
2287 BC: DatagramBindingsContext,
2288 >(
2289 core_ctx: &mut CC,
2290 bindings_ctx: &mut BC,
2291 bound: &mut BoundSocketMap<
2292 I,
2293 CC::WeakDeviceId,
2294 S::AddrSpec,
2295 S::SocketMapSpec<I, CC::WeakDeviceId>,
2296 >,
2297 addr: Option<ZonedAddr<SocketIpAddr<I::Addr>, CC::DeviceId>>,
2298 device: &Option<CC::WeakDeviceId>,
2299 local_id: Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
2300 id: <S::SocketMapSpec<I, CC::WeakDeviceId> as SocketMapStateSpec>::ListenerId,
2301 sharing: S::SharingState,
2302 transparent: bool,
2303 ) -> Result<
2304 ListenerAddr<
2305 ListenerIpAddr<I::Addr, <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
2306 CC::WeakDeviceId,
2307 >,
2308 LocalAddressError,
2309 > {
2310 let identifier = match local_id {
2311 Some(id) => Some(id),
2312 None => try_pick_identifier::<I, S, _, _, _>(
2313 addr.as_ref().map(ZonedAddr::addr),
2314 bound,
2315 bindings_ctx,
2316 &sharing,
2317 ),
2318 }
2319 .ok_or(LocalAddressError::FailedToAllocateLocalPort)?;
2320 let (addr, device, identifier) =
2321 try_pick_bound_address::<I, _, _, _>(addr, device, core_ctx, identifier, transparent)?;
2322 let weak_device = device.map(|d| d.as_weak().into_owned());
2323
2324 BoundStateHandler::<_, S, _>::try_insert_listener(
2325 bound,
2326 addr,
2327 identifier,
2328 weak_device.clone(),
2329 sharing,
2330 id,
2331 )
2332 .map(|()| ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device: weak_device })
2333 }
2334
2335 let bound_addr: ListenerAddr<S::ListenerIpAddr<I>, CC::WeakDeviceId> = match bound_operation {
2336 BoundOperation::OnlyCurrentStack(either_dual_stack, addr) => {
2337 let converter = match either_dual_stack {
2338 MaybeDualStack::DualStack(ds) => MaybeDualStack::DualStack(ds.ds_converter()),
2339 MaybeDualStack::NotDualStack(nds) => {
2340 MaybeDualStack::NotDualStack(nds.nds_converter())
2341 }
2342 };
2343 core_ctx
2344 .with_bound_sockets_mut(|core_ctx, bound| {
2345 let id = S::make_bound_socket_map_id(id);
2346
2347 try_bind_single_stack::<I, S, _, _>(
2348 core_ctx,
2349 bindings_ctx,
2350 bound,
2351 addr,
2352 &device,
2353 local_id,
2354 id,
2355 sharing.clone(),
2356 ip_options.common.transparent,
2357 )
2358 })
2359 .map(|ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device }| {
2360 let ip = match converter {
2361 MaybeDualStack::DualStack(converter) => converter.convert_back(
2362 DualStackListenerIpAddr::ThisStack(ListenerIpAddr { addr, identifier }),
2363 ),
2364 MaybeDualStack::NotDualStack(converter) => {
2365 converter.convert_back(ListenerIpAddr { addr, identifier })
2366 }
2367 };
2368 ListenerAddr { ip, device }
2369 })
2370 }
2371 BoundOperation::OnlyOtherStack(core_ctx, addr) => {
2372 let id = core_ctx.to_other_bound_socket_id(id);
2373 core_ctx
2374 .with_other_bound_sockets_mut(|core_ctx, other_bound| {
2375 try_bind_single_stack::<_, S, _, _>(
2376 core_ctx,
2377 bindings_ctx,
2378 other_bound,
2379 addr,
2380 &device,
2381 local_id,
2382 id,
2383 sharing.clone(),
2384 ip_options.common.transparent,
2385 )
2386 })
2387 .map(|ListenerAddr { ip: ListenerIpAddr { addr, identifier }, device }| {
2388 ListenerAddr {
2389 ip: core_ctx.ds_converter().convert_back(
2390 DualStackListenerIpAddr::OtherStack(ListenerIpAddr {
2391 addr,
2392 identifier,
2393 }),
2394 ),
2395 device,
2396 }
2397 })
2398 }
2399 BoundOperation::DualStackAnyAddr(core_ctx) => {
2400 let ids = PairedBoundSocketIds {
2401 this: S::make_bound_socket_map_id(id),
2402 other: core_ctx.to_other_bound_socket_id(id),
2403 };
2404 core_ctx
2405 .with_both_bound_sockets_mut(|core_ctx, bound, other_bound| {
2406 let mut bound_pair = PairedSocketMapMut { bound, other_bound };
2407 let sharing = sharing.clone();
2408
2409 let identifier = match local_id {
2410 Some(id) => Some(id),
2411 None => try_pick_identifier::<I, S, _, _, _>(
2412 DualStackUnspecifiedAddr,
2413 &bound_pair,
2414 bindings_ctx,
2415 &sharing,
2416 ),
2417 }
2418 .ok_or(LocalAddressError::FailedToAllocateLocalPort)?;
2419 let (_addr, device, identifier) = try_pick_bound_address::<I, _, _, _>(
2420 None,
2421 &device,
2422 core_ctx,
2423 identifier,
2424 ip_options.common.transparent,
2425 )?;
2426 let weak_device = device.map(|d| d.as_weak().into_owned());
2427
2428 BoundStateHandler::<_, S, _>::try_insert_listener(
2429 &mut bound_pair,
2430 DualStackUnspecifiedAddr,
2431 identifier,
2432 weak_device.clone(),
2433 sharing,
2434 ids,
2435 )
2436 .map(|()| (identifier, weak_device))
2437 })
2438 .map(|(identifier, device)| ListenerAddr {
2439 ip: core_ctx
2440 .ds_converter()
2441 .convert_back(DualStackListenerIpAddr::BothStacks(identifier)),
2442 device,
2443 })
2444 }
2445 }
2446 .map_err(Either::Right)?;
2447 let original_bound_addr = local_id.map(|_id| {
2450 let ListenerAddr { ip, device: _ } = &bound_addr;
2451 ip.clone()
2452 });
2453
2454 state.inner = SocketStateInner::Bound(BoundSocketState {
2457 socket_type: BoundSocketStateType::Listener(ListenerState { addr: bound_addr }),
2458 original_bound_addr,
2459 });
2460 Ok(())
2461}
2462
2463#[derive(Error, Copy, Clone, Debug, Eq, PartialEq)]
2465pub enum ConnectError {
2466 #[error(transparent)]
2468 Ip(#[from] IpSockCreationError),
2469 #[error("a local port could not be allocated")]
2471 CouldNotAllocateLocalPort,
2472 #[error("the socket's IP address and port conflict with an existing socket")]
2475 SockAddrConflict,
2476 #[error(transparent)]
2478 Zone(#[from] ZonedAddressError),
2479 #[error("IPv4-mapped-IPv6 addresses are not supported by this socket")]
2482 RemoteUnexpectedlyMapped,
2483 #[error("non IPv4-mapped-Ipv6 addresses are not supported by this socket")]
2486 RemoteUnexpectedlyNonMapped,
2487}
2488
2489struct ConnectParameters<WireI: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
2491 local_ip: Option<SocketIpAddr<WireI::Addr>>,
2492 local_port: Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
2493 remote_ip: ZonedAddr<SocketIpAddr<WireI::Addr>, D::Strong>,
2494 remote_port: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
2495 device: Option<D>,
2496 sharing: S::SharingState,
2497 common_ip_options: DatagramIpAgnosticOptions,
2498 socket_options: DatagramIpSpecificSocketOptions<WireI, D>,
2499 socket_id:
2500 <S::SocketMapSpec<WireI, D> as DatagramSocketMapSpec<WireI, D, S::AddrSpec>>::BoundSocketId,
2501 original_shutdown: Option<Shutdown>,
2502 extra: S::ConnStateExtra,
2503}
2504
2505fn connect_inner<
2512 WireI: IpExt,
2513 D: WeakDeviceIdentifier,
2514 S: DatagramSocketSpec,
2515 R,
2516 BC: DatagramBindingsContext,
2517 CC: IpSocketHandler<WireI, BC, WeakDeviceId = D, DeviceId = D::Strong>,
2518>(
2519 connect_params: ConnectParameters<WireI, D, S>,
2520 core_ctx: &mut CC,
2521 bindings_ctx: &mut BC,
2522 sockets: &mut BoundSocketMap<WireI, D, S::AddrSpec, S::SocketMapSpec<WireI, D>>,
2523 remove_original: impl FnOnce(
2524 &mut BoundSocketMap<WireI, D, S::AddrSpec, S::SocketMapSpec<WireI, D>>,
2525 ) -> R,
2526 reinsert_original: impl FnOnce(
2527 &mut BoundSocketMap<WireI, D, S::AddrSpec, S::SocketMapSpec<WireI, D>>,
2528 R,
2529 ),
2530) -> Result<ConnState<WireI, D, S>, ConnectError> {
2531 let ConnectParameters {
2532 local_ip,
2533 local_port,
2534 remote_ip,
2535 remote_port,
2536 device,
2537 sharing,
2538 common_ip_options,
2539 socket_options,
2540 socket_id,
2541 original_shutdown,
2542 extra,
2543 } = connect_params;
2544
2545 let device = device.or_else(|| {
2547 remote_ip
2548 .addr()
2549 .addr()
2550 .is_multicast()
2551 .then(|| socket_options.multicast_interface.clone())
2552 .flatten()
2553 });
2554
2555 let (remote_ip, socket_device) = remote_ip.resolve_addr_with_device(device.clone())?;
2556
2557 let clear_device_on_disconnect = device.is_none() && socket_device.is_some();
2558
2559 let ip_sock = IpSocketHandler::<WireI, _>::new_ip_socket(
2560 core_ctx,
2561 bindings_ctx,
2562 IpSocketArgs {
2563 device: socket_device.as_ref().map(|d| d.as_ref()),
2564 local_ip: local_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr),
2565 remote_ip,
2566 proto: S::ip_proto::<WireI>(),
2567 options: &common_ip_options,
2568 },
2569 )?;
2570
2571 let local_port = match local_port {
2572 Some(id) => id.clone(),
2573 None => S::try_alloc_local_id(
2574 sockets,
2575 bindings_ctx,
2576 DatagramFlowId {
2577 local_ip: SocketIpAddr::from(*ip_sock.local_ip()),
2578 remote_ip: *ip_sock.remote_ip(),
2579 remote_id: remote_port.clone(),
2580 },
2581 )
2582 .ok_or(ConnectError::CouldNotAllocateLocalPort)?,
2583 };
2584 let conn_addr = ConnAddr {
2585 ip: ConnIpAddr {
2586 local: (SocketIpAddr::from(*ip_sock.local_ip()), local_port),
2587 remote: (*ip_sock.remote_ip(), remote_port),
2588 },
2589 device: ip_sock.device().cloned(),
2590 };
2591 let reinsert_op = remove_original(sockets);
2594 let bound_addr = match sockets.conns_mut().try_insert(conn_addr, sharing, socket_id) {
2597 Ok(bound_entry) => bound_entry.get_addr().clone(),
2598 Err(
2599 InsertError::Exists
2600 | InsertError::IndirectConflict
2601 | InsertError::ShadowAddrExists
2602 | InsertError::WouldShadowExisting,
2603 ) => {
2604 reinsert_original(sockets, reinsert_op);
2605 return Err(ConnectError::SockAddrConflict);
2606 }
2607 };
2608 Ok(ConnState {
2609 socket: ip_sock,
2610 clear_device_on_disconnect,
2611 shutdown: original_shutdown.unwrap_or_else(Shutdown::default),
2612 addr: bound_addr,
2613 extra,
2614 })
2615}
2616
2617struct SingleStackConnectOperation<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
2619 params: ConnectParameters<I, D, S>,
2620 remove_op: Option<SingleStackRemoveOperation<I, D, S>>,
2621}
2622
2623impl<I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>
2624 SingleStackConnectOperation<I, D, S>
2625{
2626 fn new_from_state<
2628 BC,
2629 CC: NonDualStackDatagramBoundStateContext<I, BC, S, WeakDeviceId = D, DeviceId = D::Strong>,
2630 >(
2631 core_ctx: &mut CC,
2632 socket_id: &S::SocketId<I, D>,
2633 state: &SocketState<I, D, S>,
2634 remote_ip: ZonedAddr<SocketIpAddr<I::Addr>, D::Strong>,
2635 remote_port: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
2636 extra: S::ConnStateExtra,
2637 ) -> Self {
2638 let SocketState { ip_options, inner, sharing } = state;
2639 match inner {
2640 SocketStateInner::Unbound(UnboundSocketState { device }) => {
2641 SingleStackConnectOperation {
2642 params: ConnectParameters {
2643 local_ip: None,
2644 local_port: None,
2645 remote_ip,
2646 remote_port,
2647 device: device.clone(),
2648 sharing: sharing.clone(),
2649 common_ip_options: ip_options.common.clone(),
2650 socket_options: ip_options.socket_options.clone(),
2651 socket_id: S::make_bound_socket_map_id(socket_id),
2652 original_shutdown: None,
2653 extra,
2654 },
2655 remove_op: None,
2656 }
2657 }
2658 SocketStateInner::Bound(state) => {
2659 let remove_op = SingleStackRemoveOperation::new_from_state(
2660 core_ctx,
2661 socket_id,
2662 state,
2663 sharing.clone(),
2664 );
2665 let BoundSocketState { socket_type, original_bound_addr: _ } = state;
2666 match socket_type {
2667 BoundSocketStateType::Listener(ListenerState {
2668 addr: ListenerAddr { ip, device },
2669 }) => {
2670 let ListenerIpAddr { addr, identifier } =
2671 core_ctx.nds_converter().convert(ip);
2672 SingleStackConnectOperation {
2673 params: ConnectParameters {
2674 local_ip: addr.clone(),
2675 local_port: Some(*identifier),
2676 remote_ip,
2677 remote_port,
2678 device: device.clone(),
2679 sharing: sharing.clone(),
2680 common_ip_options: ip_options.common.clone(),
2681 socket_options: ip_options.socket_options.clone(),
2682 socket_id: S::make_bound_socket_map_id(socket_id),
2683 original_shutdown: None,
2684 extra,
2685 },
2686 remove_op: Some(remove_op),
2687 }
2688 }
2689 BoundSocketStateType::Connected(state) => {
2690 let ConnState {
2691 socket: _,
2692 shutdown,
2693 addr:
2694 ConnAddr {
2695 ip: ConnIpAddr { local: (local_ip, local_id), remote: _ },
2696 device,
2697 },
2698 clear_device_on_disconnect: _,
2699 extra: _,
2700 } = core_ctx.nds_converter().convert(state);
2701 SingleStackConnectOperation {
2702 params: ConnectParameters {
2703 local_ip: Some(local_ip.clone()),
2704 local_port: Some(*local_id),
2705 remote_ip,
2706 remote_port,
2707 device: device.clone(),
2708 sharing: sharing.clone(),
2709 common_ip_options: ip_options.common.clone(),
2710 socket_options: ip_options.socket_options.clone(),
2711 socket_id: S::make_bound_socket_map_id(socket_id),
2712 original_shutdown: Some(shutdown.clone()),
2713 extra,
2714 },
2715 remove_op: Some(remove_op),
2716 }
2717 }
2718 }
2719 }
2720 }
2721 }
2722
2723 fn apply<
2730 BC: DatagramBindingsContext,
2731 CC: IpSocketHandler<I, BC, WeakDeviceId = D, DeviceId = D::Strong>,
2732 >(
2733 self,
2734 core_ctx: &mut CC,
2735 bindings_ctx: &mut BC,
2736 socket_map: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>,
2737 ) -> Result<ConnState<I, D, S>, ConnectError> {
2738 let SingleStackConnectOperation { params, remove_op } = self;
2739 let remove_fn =
2740 |sockets: &mut BoundSocketMap<I, D, S::AddrSpec, S::SocketMapSpec<I, D>>| {
2741 remove_op.map(|remove_op| {
2742 remove_op.apply(sockets).expect("Failed to remove listener socket")
2743 })
2744 };
2745 let reinsert_fn =
2746 |sockets: &mut BoundDatagramSocketMap<I, D, S>,
2747 insert_op: Option<SingleStackInsertOperation<I, D, S>>| {
2748 if let Some(insert_op) = insert_op {
2749 let _: SingleStackRemoveOperation<I, D, S> =
2750 insert_op.apply(sockets).expect("Failed to revert listener socket removal");
2751 }
2752 };
2753 connect_inner(params, core_ctx, bindings_ctx, socket_map, remove_fn, reinsert_fn)
2754 }
2755}
2756
2757struct DualStackConnectOperation<I: DualStackIpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>
2759{
2760 params: EitherStack<ConnectParameters<I, D, S>, ConnectParameters<I::OtherVersion, D, S>>,
2761 remove_op: Option<DualStackRemoveOperation<I, D, S>>,
2762}
2763
2764impl<I: DualStackIpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec>
2765 DualStackConnectOperation<I, D, S>
2766{
2767 fn new_from_state<
2769 BC: DatagramBindingsContext,
2770 CC: DualStackDatagramBoundStateContext<I, BC, S, WeakDeviceId = D, DeviceId = D::Strong>,
2771 >(
2772 core_ctx: &mut CC,
2773 socket_id: &S::SocketId<I, D>,
2774 state: &SocketState<I, D, S>,
2775 remote_ip: DualStackRemoteIp<I, D::Strong>,
2776 remote_port: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
2777 extra: S::ConnStateExtra,
2778 ) -> Result<Self, ConnectError> {
2779 let SocketState { ip_options, inner, sharing } = state;
2780 match inner {
2781 SocketStateInner::Unbound(UnboundSocketState { device }) => {
2782 let params = match remote_ip {
2785 DualStackRemoteIp::ThisStack(remote_ip) => {
2786 EitherStack::ThisStack(ConnectParameters {
2787 local_ip: None,
2788 local_port: None,
2789 remote_ip,
2790 remote_port,
2791 device: device.clone(),
2792 sharing: sharing.clone(),
2793 common_ip_options: ip_options.common.clone(),
2794 socket_options: ip_options.socket_options.clone(),
2795 socket_id: S::make_bound_socket_map_id(socket_id),
2796 original_shutdown: None,
2797 extra,
2798 })
2799 }
2800 DualStackRemoteIp::OtherStack(remote_ip) => {
2801 if !core_ctx.dual_stack_enabled(ip_options) {
2802 return Err(ConnectError::RemoteUnexpectedlyMapped);
2803 }
2804 EitherStack::OtherStack(ConnectParameters {
2805 local_ip: None,
2806 local_port: None,
2807 remote_ip,
2808 remote_port,
2809 device: device.clone(),
2810 sharing: sharing.clone(),
2811 common_ip_options: ip_options.common.clone(),
2812 socket_options: core_ctx.to_other_socket_options(ip_options).clone(),
2813 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
2814 original_shutdown: None,
2815 extra,
2816 })
2817 }
2818 };
2819 Ok(DualStackConnectOperation { params, remove_op: None })
2820 }
2821 SocketStateInner::Bound(state) => {
2822 let remove_op = DualStackRemoveOperation::new_from_state(
2823 core_ctx,
2824 socket_id,
2825 ip_options,
2826 state,
2827 sharing.clone(),
2828 );
2829
2830 let BoundSocketState { socket_type, original_bound_addr: _ } = state;
2831 match socket_type {
2832 BoundSocketStateType::Listener(ListenerState {
2833 addr: ListenerAddr { ip, device },
2834 }) => {
2835 match (remote_ip, core_ctx.ds_converter().convert(ip)) {
2836 (
2839 DualStackRemoteIp::OtherStack(_),
2840 DualStackListenerIpAddr::ThisStack(_),
2841 ) => Err(ConnectError::RemoteUnexpectedlyMapped),
2842 (
2845 DualStackRemoteIp::ThisStack(_),
2846 DualStackListenerIpAddr::OtherStack(_),
2847 ) => Err(ConnectError::RemoteUnexpectedlyNonMapped),
2848 (
2850 DualStackRemoteIp::ThisStack(remote_ip),
2851 DualStackListenerIpAddr::ThisStack(ListenerIpAddr {
2852 addr,
2853 identifier,
2854 }),
2855 ) => Ok(DualStackConnectOperation {
2856 params: EitherStack::ThisStack(ConnectParameters {
2857 local_ip: addr.clone(),
2858 local_port: Some(*identifier),
2859 remote_ip,
2860 remote_port,
2861 device: device.clone(),
2862 sharing: sharing.clone(),
2863 common_ip_options: ip_options.common.clone(),
2864 socket_options: ip_options.socket_options.clone(),
2865 socket_id: S::make_bound_socket_map_id(socket_id),
2866 original_shutdown: None,
2867 extra,
2868 }),
2869 remove_op: Some(remove_op),
2870 }),
2871 (
2875 DualStackRemoteIp::ThisStack(remote_ip),
2876 DualStackListenerIpAddr::BothStacks(identifier),
2877 ) => Ok(DualStackConnectOperation {
2878 params: EitherStack::ThisStack(ConnectParameters {
2879 local_ip: None,
2880 local_port: Some(*identifier),
2881 remote_ip,
2882 remote_port,
2883 device: device.clone(),
2884 sharing: sharing.clone(),
2885 common_ip_options: ip_options.common.clone(),
2886 socket_options: ip_options.socket_options.clone(),
2887 socket_id: S::make_bound_socket_map_id(socket_id),
2888 original_shutdown: None,
2889 extra,
2890 }),
2891 remove_op: Some(remove_op),
2892 }),
2893 (
2895 DualStackRemoteIp::OtherStack(remote_ip),
2896 DualStackListenerIpAddr::OtherStack(ListenerIpAddr {
2897 addr,
2898 identifier,
2899 }),
2900 ) => Ok(DualStackConnectOperation {
2901 params: EitherStack::OtherStack(ConnectParameters {
2902 local_ip: addr.clone(),
2903 local_port: Some(*identifier),
2904 remote_ip,
2905 remote_port,
2906 device: device.clone(),
2907 sharing: sharing.clone(),
2908 common_ip_options: ip_options.common.clone(),
2909 socket_options: core_ctx
2910 .to_other_socket_options(ip_options)
2911 .clone(),
2912 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
2913 original_shutdown: None,
2914 extra,
2915 }),
2916 remove_op: Some(remove_op),
2917 }),
2918 (
2922 DualStackRemoteIp::OtherStack(remote_ip),
2923 DualStackListenerIpAddr::BothStacks(identifier),
2924 ) => Ok(DualStackConnectOperation {
2925 params: EitherStack::OtherStack(ConnectParameters {
2926 local_ip: None,
2927 local_port: Some(*identifier),
2928 remote_ip,
2929 remote_port,
2930 device: device.clone(),
2931 sharing: sharing.clone(),
2932 common_ip_options: ip_options.common.clone(),
2933 socket_options: core_ctx
2934 .to_other_socket_options(ip_options)
2935 .clone(),
2936 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
2937 original_shutdown: None,
2938 extra,
2939 }),
2940 remove_op: Some(remove_op),
2941 }),
2942 }
2943 }
2944 BoundSocketStateType::Connected(state) => {
2945 match (remote_ip, core_ctx.ds_converter().convert(state)) {
2946 (
2949 DualStackRemoteIp::OtherStack(_),
2950 DualStackConnState::ThisStack(_),
2951 ) => Err(ConnectError::RemoteUnexpectedlyMapped),
2952 (
2955 DualStackRemoteIp::ThisStack(_),
2956 DualStackConnState::OtherStack(_),
2957 ) => Err(ConnectError::RemoteUnexpectedlyNonMapped),
2958 (
2960 DualStackRemoteIp::ThisStack(remote_ip),
2961 DualStackConnState::ThisStack(ConnState {
2962 socket: _,
2963 shutdown,
2964 addr:
2965 ConnAddr {
2966 ip:
2967 ConnIpAddr { local: (local_ip, local_id), remote: _ },
2968 device,
2969 },
2970 clear_device_on_disconnect: _,
2971 extra: _,
2972 }),
2973 ) => Ok(DualStackConnectOperation {
2974 params: EitherStack::ThisStack(ConnectParameters {
2975 local_ip: Some(local_ip.clone()),
2976 local_port: Some(*local_id),
2977 remote_ip,
2978 remote_port,
2979 device: device.clone(),
2980 sharing: sharing.clone(),
2981 common_ip_options: ip_options.common.clone(),
2982 socket_options: ip_options.socket_options.clone(),
2983 socket_id: S::make_bound_socket_map_id(socket_id),
2984 original_shutdown: Some(shutdown.clone()),
2985 extra,
2986 }),
2987 remove_op: Some(remove_op),
2988 }),
2989 (
2991 DualStackRemoteIp::OtherStack(remote_ip),
2992 DualStackConnState::OtherStack(ConnState {
2993 socket: _,
2994 shutdown,
2995 addr:
2996 ConnAddr {
2997 ip:
2998 ConnIpAddr { local: (local_ip, local_id), remote: _ },
2999 device,
3000 },
3001 clear_device_on_disconnect: _,
3002 extra: _,
3003 }),
3004 ) => Ok(DualStackConnectOperation {
3005 params: EitherStack::OtherStack(ConnectParameters {
3006 local_ip: Some(local_ip.clone()),
3007 local_port: Some(*local_id),
3008 remote_ip,
3009 remote_port,
3010 device: device.clone(),
3011 sharing: sharing.clone(),
3012 common_ip_options: ip_options.common.clone(),
3013 socket_options: core_ctx
3014 .to_other_socket_options(ip_options)
3015 .clone(),
3016 socket_id: core_ctx.to_other_bound_socket_id(socket_id),
3017 original_shutdown: Some(shutdown.clone()),
3018 extra,
3019 }),
3020 remove_op: Some(remove_op),
3021 }),
3022 }
3023 }
3024 }
3025 }
3026 }
3027 }
3028
3029 fn apply<
3037 BC: DatagramBindingsContext,
3038 CC: IpSocketHandler<I, BC, WeakDeviceId = D, DeviceId = D::Strong>
3039 + IpSocketHandler<I::OtherVersion, BC, WeakDeviceId = D, DeviceId = D::Strong>,
3040 >(
3041 self,
3042 core_ctx: &mut CC,
3043 bindings_ctx: &mut BC,
3044 socket_map: &mut BoundDatagramSocketMap<I, D, S>,
3045 other_socket_map: &mut BoundDatagramSocketMap<I::OtherVersion, D, S>,
3046 ) -> Result<DualStackConnState<I, D, S>, ConnectError> {
3047 let DualStackConnectOperation { params, remove_op } = self;
3048 match params {
3049 EitherStack::ThisStack(params) => {
3050 let remove_fn = |sockets: &mut BoundDatagramSocketMap<I, D, S>| {
3055 remove_op.map(|remove_op| {
3056 let reinsert_op = remove_op
3057 .apply(sockets, other_socket_map)
3058 .expect("Failed to remove listener socket");
3059 (reinsert_op, other_socket_map)
3060 })
3061 };
3062 let reinsert_fn = |sockets: &mut BoundDatagramSocketMap<I, D, S>,
3063 insert_op: Option<(
3064 DualStackInsertOperation<I, D, S>,
3065 &mut BoundDatagramSocketMap<I::OtherVersion, D, S>,
3066 )>| {
3067 if let Some((insert_op, other_sockets)) = insert_op {
3068 let _: DualStackRemoveOperation<I, D, S> = insert_op
3069 .apply(sockets, other_sockets)
3070 .expect("Failed to revert listener socket removal");
3071 }
3072 };
3073 connect_inner(params, core_ctx, bindings_ctx, socket_map, remove_fn, reinsert_fn)
3074 .map(DualStackConnState::ThisStack)
3075 }
3076 EitherStack::OtherStack(params) => {
3077 let remove_fn =
3082 |other_sockets: &mut BoundDatagramSocketMap<I::OtherVersion, D, S>| {
3083 remove_op.map(|remove_op| {
3084 let reinsert_op = remove_op
3085 .apply(socket_map, other_sockets)
3086 .expect("Failed to remove listener socket");
3087 (reinsert_op, socket_map)
3088 })
3089 };
3090 let reinsert_fn =
3091 |other_sockets: &mut BoundDatagramSocketMap<I::OtherVersion, D, S>,
3092 insert_op: Option<(
3093 DualStackInsertOperation<I, D, S>,
3094 &mut BoundDatagramSocketMap<I, D, S>,
3095 )>| {
3096 if let Some((insert_op, sockets)) = insert_op {
3097 let _: DualStackRemoveOperation<I, D, S> = insert_op
3098 .apply(sockets, other_sockets)
3099 .expect("Failed to revert listener socket removal");
3100 }
3101 };
3102 connect_inner(
3103 params,
3104 core_ctx,
3105 bindings_ctx,
3106 other_socket_map,
3107 remove_fn,
3108 reinsert_fn,
3109 )
3110 .map(DualStackConnState::OtherStack)
3111 }
3112 }
3113 }
3114}
3115
3116#[derive(Copy, Clone, Debug, Default, Eq, GenericOverIp, PartialEq, Error)]
3118#[generic_over_ip()]
3119#[error("expected connected socket")]
3120pub struct ExpectedConnError;
3121
3122#[derive(Copy, Clone, Debug, Default, Eq, GenericOverIp, PartialEq, Error)]
3124#[generic_over_ip()]
3125#[error("expected unbound socket")]
3126pub struct ExpectedUnboundError;
3127
3128fn disconnect_to_unbound<
3133 I: IpExt,
3134 BC: DatagramBindingsContext,
3135 CC: DatagramBoundStateContext<I, BC, S>,
3136 S: DatagramSocketSpec,
3137>(
3138 core_ctx: &mut CC,
3139 id: &S::SocketId<I, CC::WeakDeviceId>,
3140 clear_device_on_disconnect: bool,
3141 ip_options: &IpOptions<I, CC::WeakDeviceId, S>,
3142 socket_state: &BoundSocketState<I, CC::WeakDeviceId, S>,
3143 sharing: S::SharingState,
3144) -> UnboundSocketState<CC::WeakDeviceId> {
3145 match core_ctx.dual_stack_context_mut() {
3146 MaybeDualStack::NotDualStack(nds) => {
3147 let remove_op =
3148 SingleStackRemoveOperation::new_from_state(nds, id, socket_state, sharing);
3149 let _: SingleStackInsertOperation<_, _, _> =
3150 core_ctx.with_bound_sockets_mut(|_core_ctx, bound| {
3151 remove_op.apply(bound).expect("Failed to remove connected socket entry")
3152 });
3153 }
3154 MaybeDualStack::DualStack(ds) => {
3155 let remove_op =
3156 DualStackRemoveOperation::new_from_state(ds, id, ip_options, socket_state, sharing);
3157 let _: DualStackInsertOperation<_, _, _> =
3158 ds.with_both_bound_sockets_mut(|_core_ctx, bound, other_bound| {
3159 remove_op
3160 .apply(bound, other_bound)
3161 .expect("Failed to remove connected socket entry")
3162 });
3163 }
3164 };
3165 let device =
3166 if clear_device_on_disconnect { None } else { socket_state.get_device(core_ctx).clone() };
3167 UnboundSocketState { device }
3168}
3169
3170fn disconnect_to_listener<
3175 I: IpExt,
3176 BC: DatagramBindingsContext,
3177 CC: DatagramBoundStateContext<I, BC, S>,
3178 S: DatagramSocketSpec,
3179>(
3180 core_ctx: &mut CC,
3181 id: &S::SocketId<I, CC::WeakDeviceId>,
3182 listener_ip: S::ListenerIpAddr<I>,
3183 clear_device_on_disconnect: bool,
3184 ip_options: &IpOptions<I, CC::WeakDeviceId, S>,
3185 socket_state: &BoundSocketState<I, CC::WeakDeviceId, S>,
3186 sharing: S::SharingState,
3187) -> BoundSocketState<I, CC::WeakDeviceId, S> {
3188 let new_device =
3189 if clear_device_on_disconnect { None } else { socket_state.get_device(core_ctx).clone() };
3190
3191 match core_ctx.dual_stack_context_mut() {
3192 MaybeDualStack::NotDualStack(nds) => {
3193 let ListenerIpAddr { addr, identifier } =
3194 nds.nds_converter().convert(listener_ip.clone());
3195 let remove_op =
3196 SingleStackRemoveOperation::new_from_state(nds, id, socket_state, sharing.clone());
3197 core_ctx.with_bound_sockets_mut(|_core_ctx, bound| {
3198 let _: SingleStackInsertOperation<_, _, _> =
3199 remove_op.apply(bound).expect("Failed to remove connected socket entry");
3200 BoundStateHandler::<_, S, _>::try_insert_listener(
3201 bound,
3202 addr,
3203 identifier,
3204 new_device.clone(),
3205 sharing.clone(),
3206 S::make_bound_socket_map_id(id),
3207 )
3208 .expect("inserting listener for disconnected socket should succeed");
3209 })
3210 }
3211 MaybeDualStack::DualStack(ds) => {
3212 let remove_op = DualStackRemoveOperation::new_from_state(
3213 ds,
3214 id,
3215 ip_options,
3216 socket_state,
3217 sharing.clone(),
3218 );
3219 let other_id = ds.to_other_bound_socket_id(id);
3220 let id = S::make_bound_socket_map_id(id);
3221 let converter = ds.ds_converter();
3222 ds.with_both_bound_sockets_mut(|_core_ctx, bound, other_bound| {
3223 let _: DualStackInsertOperation<_, _, _> = remove_op
3224 .apply(bound, other_bound)
3225 .expect("Failed to remove connected socket entry");
3226
3227 match converter.convert(listener_ip.clone()) {
3228 DualStackListenerIpAddr::ThisStack(ListenerIpAddr { addr, identifier }) => {
3229 BoundStateHandler::<_, S, _>::try_insert_listener(
3230 bound,
3231 addr,
3232 identifier,
3233 new_device.clone(),
3234 sharing.clone(),
3235 id,
3236 )
3237 }
3238 DualStackListenerIpAddr::OtherStack(ListenerIpAddr { addr, identifier }) => {
3239 BoundStateHandler::<_, S, _>::try_insert_listener(
3240 other_bound,
3241 addr,
3242 identifier,
3243 new_device.clone(),
3244 sharing.clone(),
3245 other_id,
3246 )
3247 }
3248 DualStackListenerIpAddr::BothStacks(identifier) => {
3249 let ids = PairedBoundSocketIds { this: id, other: other_id };
3250 let mut bound_pair = PairedSocketMapMut { bound, other_bound };
3251 BoundStateHandler::<_, S, _>::try_insert_listener(
3252 &mut bound_pair,
3253 DualStackUnspecifiedAddr,
3254 identifier,
3255 new_device.clone(),
3256 sharing.clone(),
3257 ids,
3258 )
3259 }
3260 }
3261 .expect("inserting listener for disconnected socket should succeed");
3262 })
3263 }
3264 };
3265 BoundSocketState {
3266 original_bound_addr: Some(listener_ip.clone()),
3267 socket_type: BoundSocketStateType::Listener(ListenerState {
3268 addr: ListenerAddr { ip: listener_ip, device: new_device },
3269 }),
3270 }
3271}
3272
3273#[derive(Debug, GenericOverIp, Error)]
3275#[generic_over_ip()]
3276pub enum SendError<SE: Error> {
3277 #[error("socket not connected")]
3279 NotConnected,
3280 #[error("socket not writeable")]
3282 NotWriteable,
3283 #[error("error sending IP packet: {0}")]
3285 IpSock(#[from] IpSockSendError),
3286 #[error("error serializing packet: {0:?}")]
3288 SerializeError(#[source] SE),
3289}
3290
3291#[derive(Debug, Error)]
3293pub enum SendToError<SE: Error> {
3294 #[error("socket not writeable")]
3296 NotWriteable,
3297 #[error("local address error: {0}")]
3300 LocalAddress(#[from] LocalAddressError),
3301 #[error("problem with zone of remote address: {0}")]
3303 Zone(#[from] ZonedAddressError),
3304 #[error("error creating temporary IP socket for send: {0}")]
3307 CreateAndSend(#[from] IpSockCreateAndSendError),
3308 #[error("remote address is mapped, but socket is not dual-stack enabled")]
3311 RemoteUnexpectedlyMapped,
3312 #[error(
3315 "remote address is non-mapped, but socket is \
3316 dual-stack enabled and bound to mapped address"
3317 )]
3318 RemoteUnexpectedlyNonMapped,
3319 #[error("serialize buffer invalid")]
3321 SerializeError(#[source] SE),
3322}
3323
3324struct SendOneshotParameters<
3325 'a,
3326 SockI: IpExt,
3327 WireI: IpExt,
3328 S: DatagramSocketSpec,
3329 D: WeakDeviceIdentifier,
3330> {
3331 local_ip: Option<SocketIpAddr<WireI::Addr>>,
3332 local_id: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
3333 remote_ip: ZonedAddr<SocketIpAddr<WireI::Addr>, D::Strong>,
3334 remote_id: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
3335 device: &'a Option<D>,
3336 options: IpOptionsRef<'a, WireI, D>,
3337 id: &'a S::SocketId<SockI, D>,
3338 send_token: S::SendToken,
3339}
3340
3341fn send_oneshot<
3342 SockI: IpExt,
3343 WireI: IpExt,
3344 S: DatagramSocketSpec,
3345 CC: IpSocketHandler<WireI, BC> + CoreTxMetadataContext<TxMetadata<SockI, CC::WeakDeviceId, S>, BC>,
3346 BC: DatagramBindingsContext,
3347 B: BufferMut,
3348>(
3349 core_ctx: &mut CC,
3350 bindings_ctx: &mut BC,
3351 params: SendOneshotParameters<'_, SockI, WireI, S, CC::WeakDeviceId>,
3352 body: B,
3353) -> Result<(), SendToError<S::SerializeError>> {
3354 let SendOneshotParameters {
3355 local_ip,
3356 local_id,
3357 remote_ip,
3358 remote_id,
3359 device,
3360 options,
3361 id,
3362 send_token,
3363 } = params;
3364 let device = device.clone().or_else(|| {
3365 remote_ip
3366 .addr()
3367 .addr()
3368 .is_multicast()
3369 .then(|| options.ip_specific.multicast_interface.clone())
3370 .flatten()
3371 });
3372 let (remote_ip, device) = match remote_ip.resolve_addr_with_device(device) {
3373 Ok(addr) => addr,
3374 Err(e) => return Err(SendToError::Zone(e)),
3375 };
3376
3377 let tx_metadata = core_ctx.convert_tx_meta(TxMetadata::new(id, send_token));
3378
3379 core_ctx
3380 .send_oneshot_ip_packet_with_fallible_serializer(
3381 bindings_ctx,
3382 IpSocketArgs {
3383 device: device.as_ref().map(|d| d.as_ref()),
3384 local_ip: local_ip.and_then(IpDeviceAddr::new_from_socket_ip_addr),
3385 remote_ip,
3386 proto: S::ip_proto::<WireI>(),
3387 options: &options,
3388 },
3389 tx_metadata,
3390 |local_ip| {
3391 S::make_packet::<WireI, _>(
3392 body,
3393 &ConnIpAddr {
3394 local: (local_ip.into(), local_id),
3395 remote: (remote_ip, remote_id),
3396 },
3397 )
3398 },
3399 )
3400 .map_err(|err| match err {
3401 SendOneShotIpPacketError::CreateAndSendError { err } => SendToError::CreateAndSend(err),
3402 SendOneShotIpPacketError::SerializeError(err) => SendToError::SerializeError(err),
3403 })
3404}
3405
3406enum SetBoundDeviceParameters<'a, I: IpExt, D: WeakDeviceIdentifier, S: DatagramSocketSpec> {
3409 Listener {
3410 ip: &'a ListenerIpAddr<I::Addr, <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
3411 device: &'a mut Option<D>,
3412 },
3413 Connected(&'a mut ConnState<I, D, S>),
3414}
3415
3416fn set_bound_device_single_stack<
3426 'a,
3427 I: IpExt,
3428 D: WeakDeviceIdentifier,
3429 S: DatagramSocketSpec,
3430 BC: DatagramBindingsContext,
3431 CC: IpSocketHandler<I, BC, WeakDeviceId = D, DeviceId = D::Strong>,
3432>(
3433 bindings_ctx: &mut BC,
3434 core_ctx: &mut CC,
3435 params: SetBoundDeviceParameters<'a, I, D, S>,
3436 sockets: &mut BoundDatagramSocketMap<I, D, S>,
3437 socket_id: &BoundDatagramSocketId<I, D, S>,
3438 common_ip_options: &DatagramIpAgnosticOptions,
3439 new_device: Option<&D::Strong>,
3440 sharing: S::SharingState,
3441) -> Result<(), SocketError> {
3442 let (local_ip, remote_ip, old_device) = match ¶ms {
3443 SetBoundDeviceParameters::Listener {
3444 ip: ListenerIpAddr { addr, identifier: _ },
3445 device,
3446 } => (addr.as_ref(), None, device.as_ref()),
3447 SetBoundDeviceParameters::Connected(ConnState {
3448 socket: _,
3449 addr:
3450 ConnAddr {
3451 ip: ConnIpAddr { local: (local_ip, _local_id), remote: (remote_ip, _remote_id) },
3452 device,
3453 },
3454 shutdown: _,
3455 clear_device_on_disconnect: _,
3456 extra: _,
3457 }) => (Some(local_ip), Some(remote_ip), device.as_ref()),
3458 };
3459 let device_update = SocketDeviceUpdate {
3462 local_ip: local_ip.map(AsRef::<SpecifiedAddr<I::Addr>>::as_ref),
3463 remote_ip: remote_ip.map(AsRef::<SpecifiedAddr<I::Addr>>::as_ref),
3464 old_device,
3465 };
3466 match device_update.check_update(new_device) {
3467 Ok(()) => (),
3468 Err(SocketDeviceUpdateNotAllowedError) => {
3469 return Err(SocketError::Local(LocalAddressError::Zone(
3470 ZonedAddressError::DeviceZoneMismatch,
3471 )));
3472 }
3473 };
3474
3475 let new_device_strong = new_device.map(EitherDeviceId::Strong);
3476 let new_device_weak = new_device.map(|d| d.downgrade());
3477
3478 let (old_addr, new_addr, update_state) = match params {
3479 SetBoundDeviceParameters::Listener { ip, device } => (
3480 AddrVec::Listen(ListenerAddr { ip: ip.clone(), device: device.clone() }),
3481 AddrVec::Listen(ListenerAddr { ip: ip.clone(), device: new_device_weak.clone() }),
3482 Either::Left(move || {
3483 *device = new_device_weak;
3484 }),
3485 ),
3486 SetBoundDeviceParameters::Connected(ConnState {
3487 socket,
3488 addr,
3489 shutdown: _,
3490 clear_device_on_disconnect,
3491 extra: _,
3492 }) => {
3493 let ConnIpAddr { local: (local_ip, _local_id), remote: (remote_ip, _remote_id) } =
3494 addr.ip;
3495 let new_socket = core_ctx
3496 .new_ip_socket(
3497 bindings_ctx,
3498 IpSocketArgs {
3499 device: new_device_strong,
3500 local_ip: IpDeviceAddr::new_from_socket_ip_addr(local_ip.clone()),
3501 remote_ip: remote_ip.clone(),
3502 proto: socket.proto(),
3503 options: common_ip_options,
3504 },
3505 )
3506 .map_err(|_: IpSockCreationError| {
3507 SocketError::Remote(RemoteAddressError::NoRoute)
3508 })?;
3509 let new_addr = ConnAddr { ip: addr.ip.clone(), device: new_device_weak.clone() };
3510 (
3511 AddrVec::Conn(addr.clone()),
3512 AddrVec::Conn(new_addr.clone()),
3513 Either::Right(move || {
3514 *socket = new_socket;
3515 if new_device.is_some() {
3518 *clear_device_on_disconnect = false;
3519 }
3520 *addr = new_addr
3521 }),
3522 )
3523 }
3524 };
3525
3526 let remove_op = SingleStackRemoveOperation::<I, D, S> {
3528 socket_id: socket_id.clone(),
3529 sharing: sharing.clone(),
3530 addr: old_addr,
3531 _marker: PhantomData,
3532 };
3533 let reinsert_op = remove_op.apply(sockets).expect("failed to remove socket in set_device");
3534
3535 let insert_op = SingleStackInsertOperation::<I, D, S> {
3538 socket_id: socket_id.clone(),
3539 sharing: sharing,
3540 addr: new_addr,
3541 _marker: PhantomData,
3542 };
3543 match insert_op.apply(sockets) {
3544 Err(e) => {
3545 let _: SingleStackRemoveOperation<_, _, _> = reinsert_op
3546 .apply(sockets)
3547 .expect("failed to reinsert socket after failed set_device");
3548 return Err(SocketError::Local(e.into()));
3549 }
3550 Ok(_) => {}
3551 }
3552
3553 match update_state {
3555 Either::Left(f) => f(),
3556 Either::Right(f) => f(),
3557 }
3558
3559 Ok(())
3560}
3561
3562fn set_bound_device_listener_both_stacks<
3571 'a,
3572 I: IpExt,
3573 D: WeakDeviceIdentifier,
3574 S: DatagramSocketSpec,
3575>(
3576 old_device: &mut Option<D>,
3577 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
3578 sockets: PairedSocketMapMut<'a, I, D, S>,
3579 socket_ids: PairedBoundSocketIds<I, D, S>,
3580 new_device: Option<D>,
3581 sharing: S::SharingState,
3582) -> Result<(), SocketError> {
3583 let PairedSocketMapMut { bound: sockets, other_bound: other_sockets } = sockets;
3584
3585 let remove_op = DualStackListenerRemoveOperation {
3586 identifier,
3587 device: old_device.clone(),
3588 sharing: sharing.clone(),
3589 socket_ids: socket_ids.clone(),
3590 _marker: PhantomData,
3591 };
3592 let reinsert_op =
3593 remove_op.apply(sockets, other_sockets).expect("failed to remove socket in set_device");
3594
3595 let insert_op = DualStackListenerInsertOperation {
3596 identifier,
3597 device: new_device.clone(),
3598 sharing,
3599 socket_ids,
3600 _marker: PhantomData,
3601 };
3602 match insert_op.apply(sockets, other_sockets) {
3603 Err(e) => {
3604 let _: DualStackListenerRemoveOperation<_, _, _> = reinsert_op
3605 .apply(sockets, other_sockets)
3606 .expect("failed to reinsert socket after failed set_device");
3607 return Err(SocketError::Local(e.into()));
3608 }
3609 Ok(_) => {}
3610 };
3611
3612 *old_device = new_device;
3613 return Ok(());
3614}
3615
3616#[derive(Copy, Clone, Debug, Eq, PartialEq, Error)]
3619pub enum SetMulticastMembershipError {
3620 #[error("provided address does not match the provided device")]
3622 AddressNotAvailable,
3623 #[error("device does not exist")]
3625 DeviceDoesNotExist,
3626 #[error("provided address does not match any address on the host")]
3628 NoDeviceWithAddress,
3629 #[error(
3632 "no device or address was specified and \
3633 there is no device with a route to the multicast address"
3634 )]
3635 NoDeviceAvailable,
3636 #[error("tried to join a group again")]
3638 GroupAlreadyJoined,
3639 #[error("tried to leave an unjoined group")]
3641 GroupNotJoined,
3642 #[error("socket is bound to a device that doesn't match the one specified")]
3644 WrongDevice,
3645}
3646
3647fn pick_interface_for_addr<
3650 A: IpAddress,
3651 S: DatagramSocketSpec,
3652 BC: DatagramBindingsContext,
3653 CC: DatagramBoundStateContext<A::Version, BC, S>,
3654>(
3655 core_ctx: &mut CC,
3656 remote_addr: MulticastAddr<A>,
3657 source_addr: Option<SpecifiedAddr<A>>,
3658 marks: &Marks,
3659) -> Result<CC::DeviceId, SetMulticastMembershipError>
3660where
3661 A::Version: IpExt,
3662{
3663 core_ctx.with_transport_context(|core_ctx| match source_addr {
3664 Some(source_addr) => {
3665 BaseTransportIpContext::<A::Version, _>::with_devices_with_assigned_addr(
3666 core_ctx,
3667 source_addr,
3668 |mut devices| {
3669 if let Some(d) = devices.next() {
3670 if devices.next() == None {
3671 return Ok(d);
3672 }
3673 }
3674 Err(SetMulticastMembershipError::NoDeviceAvailable)
3675 },
3676 )
3677 }
3678 None => {
3679 let device = MulticastMembershipHandler::select_device_for_multicast_group(
3680 core_ctx,
3681 remote_addr,
3682 marks,
3683 )
3684 .map_err(|e| match e {
3685 ResolveRouteError::NoSrcAddr | ResolveRouteError::Unreachable => {
3686 SetMulticastMembershipError::NoDeviceAvailable
3687 }
3688 })?;
3689 Ok(device)
3690 }
3691 })
3692}
3693
3694#[derive(Copy, Clone, Debug, Eq, GenericOverIp, PartialEq)]
3696#[generic_over_ip(A, IpAddress)]
3697pub enum MulticastInterfaceSelector<A: IpAddress, D> {
3698 LocalAddress(SpecifiedAddr<A>),
3700 Interface(D),
3702}
3703
3704#[derive(Copy, Clone, Debug, Eq, PartialEq, GenericOverIp)]
3709#[generic_over_ip(A, IpAddress)]
3710pub enum MulticastMembershipInterfaceSelector<A: IpAddress, D> {
3711 Specified(MulticastInterfaceSelector<A, D>),
3713 AnyInterfaceWithRoute,
3715}
3716
3717impl<A: IpAddress, D> From<MulticastInterfaceSelector<A, D>>
3718 for MulticastMembershipInterfaceSelector<A, D>
3719{
3720 fn from(selector: MulticastInterfaceSelector<A, D>) -> Self {
3721 Self::Specified(selector)
3722 }
3723}
3724
3725#[derive(RefCast)]
3727#[repr(transparent)]
3728pub struct DatagramApi<I, C, S>(C, PhantomData<(S, I)>);
3729
3730impl<I, C, S> DatagramApi<I, C, S> {
3731 pub fn new(ctx: C) -> Self {
3733 Self(ctx, PhantomData)
3734 }
3735
3736 pub fn wrap(ctx: &mut C) -> &mut Self {
3739 Self::ref_cast_mut(ctx)
3740 }
3741}
3742
3743type DatagramApiSocketId<I, C, S> = <S as DatagramSocketSpec>::SocketId<
3749 I,
3750 <<C as ContextPair>::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId,
3751>;
3752type DatagramApiDeviceId<C> =
3758 <<C as ContextPair>::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId;
3759type DatagramApiWeakDeviceId<C> =
3765 <<C as ContextPair>::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId;
3766
3767impl<I, C, S> DatagramApi<I, C, S>
3768where
3769 I: IpExt,
3770 C: ContextPair,
3771 C::BindingsContext: DatagramBindingsContext,
3772 C::CoreContext: DatagramStateContext<I, C::BindingsContext, S>,
3773 S: DatagramSocketSpec,
3774{
3775 fn core_ctx(&mut self) -> &mut C::CoreContext {
3776 let Self(pair, PhantomData) = self;
3777 pair.core_ctx()
3778 }
3779
3780 fn contexts(&mut self) -> (&mut C::CoreContext, &mut C::BindingsContext) {
3781 let Self(pair, PhantomData) = self;
3782 pair.contexts()
3783 }
3784
3785 pub fn create(
3791 &mut self,
3792 external_data: S::ExternalData<I>,
3793 ) -> S::SocketId<I, DatagramApiWeakDeviceId<C>> {
3794 let primary = create_primary_id(external_data);
3795 let strong = PrimaryRc::clone_strong(&primary);
3796 self.core_ctx().with_all_sockets_mut(move |socket_set| {
3797 let strong = PrimaryRc::clone_strong(&primary);
3798 assert_matches::assert_matches!(socket_set.insert(strong, primary), None);
3799 });
3800 strong.into()
3801 }
3802
3803 #[cfg(any(test, feature = "testutils"))]
3805 pub fn create_default(&mut self) -> S::SocketId<I, DatagramApiWeakDeviceId<C>>
3806 where
3807 S::ExternalData<I>: Default,
3808 {
3809 self.create(Default::default())
3810 }
3811
3812 pub fn collect_all_sockets(&mut self) -> Vec<S::SocketId<I, DatagramApiWeakDeviceId<C>>> {
3814 self.core_ctx()
3815 .with_all_sockets(|socket_set| socket_set.keys().map(|s| s.clone().into()).collect())
3816 }
3817
3818 pub fn close<O, F>(
3820 &mut self,
3821 id: DatagramApiSocketId<I, C, S>,
3822 map: F,
3823 ) -> RemoveResourceResultWithContext<O, C::BindingsContext>
3824 where
3825 O: Send,
3826 F: Send + Clone + 'static + FnOnce(ReferenceState<I, DatagramApiWeakDeviceId<C>, S>) -> O,
3827 {
3828 let (core_ctx, bindings_ctx) = self.contexts();
3829 let primary = core_ctx.with_all_sockets_mut(|all_sockets| {
3831 all_sockets.remove(id.borrow()).expect("socket already closed")
3832 });
3833 core_ctx.with_socket_state(&id, |core_ctx, state| {
3834 let SocketState { ip_options, inner, sharing } = state;
3835 match inner {
3836 SocketStateInner::Unbound(UnboundSocketState { device: _ }) => {}
3837 SocketStateInner::Bound(state) => match core_ctx.dual_stack_context_mut() {
3838 MaybeDualStack::DualStack(dual_stack) => {
3839 let op = DualStackRemoveOperation::new_from_state(
3840 dual_stack,
3841 &id,
3842 ip_options,
3843 state,
3844 sharing.clone(),
3845 );
3846 let _: DualStackInsertOperation<_, _, _> = dual_stack
3847 .with_both_bound_sockets_mut(|_core_ctx, sockets, other_sockets| {
3848 op.apply(sockets, other_sockets).expect("Failed to remove socket")
3849 });
3850 }
3851 MaybeDualStack::NotDualStack(not_dual_stack) => {
3852 let op = SingleStackRemoveOperation::new_from_state(
3853 not_dual_stack,
3854 &id,
3855 state,
3856 sharing.clone(),
3857 );
3858 let _: SingleStackInsertOperation<_, _, _> = core_ctx
3859 .with_bound_sockets_mut(|_core_ctx, sockets| {
3860 op.apply(sockets).expect("Failed to remove socket")
3861 });
3862 }
3863 },
3864 };
3865 DatagramBoundStateContext::<I, _, _>::with_transport_context(core_ctx, |core_ctx| {
3866 leave_all_joined_groups(core_ctx, bindings_ctx, &ip_options.multicast_memberships)
3867 });
3868 });
3869
3870 core::mem::drop(id);
3873 <C::BindingsContext as ReferenceNotifiersExt>::unwrap_or_notify_with_new_reference_notifier(
3874 primary, map,
3875 )
3876 }
3877
3878 pub fn get_info(
3880 &mut self,
3881 id: &DatagramApiSocketId<I, C, S>,
3882 ) -> SocketInfo<I::Addr, DatagramApiWeakDeviceId<C>> {
3883 self.core_ctx().with_socket_state(id, |_core_ctx, state| state.to_socket_info())
3884 }
3885
3886 pub fn listen(
3888 &mut self,
3889 id: &DatagramApiSocketId<I, C, S>,
3890 addr: Option<ZonedAddr<SpecifiedAddr<I::Addr>, DatagramApiDeviceId<C>>>,
3891 local_id: Option<<S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
3892 ) -> Result<(), Either<ExpectedUnboundError, LocalAddressError>> {
3893 let (core_ctx, bindings_ctx) = self.contexts();
3894 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
3895 listen_inner::<_, _, _, S>(core_ctx, bindings_ctx, state, id, addr, local_id)
3896 })
3897 }
3898
3899 pub fn connect(
3901 &mut self,
3902 id: &DatagramApiSocketId<I, C, S>,
3903 remote_ip: Option<ZonedAddr<SpecifiedAddr<I::Addr>, DatagramApiDeviceId<C>>>,
3904 remote_id: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
3905 extra: S::ConnStateExtra,
3906 ) -> Result<(), ConnectError> {
3907 let (core_ctx, bindings_ctx) = self.contexts();
3908 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
3909 let conn_state = match (
3910 core_ctx.dual_stack_context_mut(),
3911 DualStackRemoteIp::<I, _>::new(remote_ip.clone()),
3912 ) {
3913 (MaybeDualStack::DualStack(ds), remote_ip) => {
3914 let connect_op = DualStackConnectOperation::new_from_state(
3915 ds, id, state, remote_ip, remote_id, extra,
3916 )?;
3917 let converter = ds.ds_converter();
3918 let conn_state =
3919 ds.with_both_bound_sockets_mut(|core_ctx, bound, other_bound| {
3920 connect_op.apply(core_ctx, bindings_ctx, bound, other_bound)
3921 })?;
3922 Ok(converter.convert_back(conn_state))
3923 }
3924 (MaybeDualStack::NotDualStack(nds), DualStackRemoteIp::ThisStack(remote_ip)) => {
3925 let connect_op = SingleStackConnectOperation::new_from_state(
3926 nds, id, state, remote_ip, remote_id, extra,
3927 );
3928 let converter = nds.nds_converter();
3929 let conn_state = core_ctx.with_bound_sockets_mut(|core_ctx, bound| {
3930 connect_op.apply(core_ctx, bindings_ctx, bound)
3931 })?;
3932 Ok(converter.convert_back(conn_state))
3933 }
3934 (MaybeDualStack::NotDualStack(_), DualStackRemoteIp::OtherStack(_)) => {
3935 Err(ConnectError::RemoteUnexpectedlyMapped)
3936 }
3937 }?;
3938 let original_bound_addr = match &state.inner {
3939 SocketStateInner::Unbound(_) => None,
3940 SocketStateInner::Bound(BoundSocketState {
3941 socket_type: _,
3942 original_bound_addr,
3943 }) => original_bound_addr.clone(),
3944 };
3945 state.inner = SocketStateInner::Bound(BoundSocketState {
3946 socket_type: BoundSocketStateType::Connected(conn_state),
3947 original_bound_addr,
3948 });
3949 Ok(())
3950 })
3951 }
3952
3953 pub fn disconnect_connected(
3955 &mut self,
3956 id: &DatagramApiSocketId<I, C, S>,
3957 ) -> Result<(), ExpectedConnError> {
3958 self.core_ctx().with_socket_state_mut(id, |core_ctx, state| {
3959 let SocketState { ip_options, inner, sharing } = state;
3960 let inner_state = match inner {
3961 SocketStateInner::Unbound(_) => return Err(ExpectedConnError),
3962 SocketStateInner::Bound(state) => state,
3963 };
3964 let BoundSocketState { socket_type, original_bound_addr } = inner_state;
3965 let conn_state = match socket_type {
3966 BoundSocketStateType::Listener(_) => {
3967 return Err(ExpectedConnError);
3968 }
3969 BoundSocketStateType::Connected(state) => state,
3970 };
3971
3972 let clear_device_on_disconnect = match core_ctx.dual_stack_context_mut() {
3973 MaybeDualStack::DualStack(dual_stack) => {
3974 match dual_stack.ds_converter().convert(conn_state) {
3975 DualStackConnState::ThisStack(conn_state) => {
3976 conn_state.clear_device_on_disconnect
3977 }
3978 DualStackConnState::OtherStack(conn_state) => {
3979 conn_state.clear_device_on_disconnect
3980 }
3981 }
3982 }
3983 MaybeDualStack::NotDualStack(not_dual_stack) => {
3984 not_dual_stack.nds_converter().convert(conn_state).clear_device_on_disconnect
3985 }
3986 };
3987
3988 state.inner = match original_bound_addr {
3989 None => SocketStateInner::Unbound(disconnect_to_unbound(
3990 core_ctx,
3991 id,
3992 clear_device_on_disconnect,
3993 &state.ip_options,
3994 inner_state,
3995 sharing.clone(),
3996 )),
3997 Some(original_bound_addr) => SocketStateInner::Bound(disconnect_to_listener(
3998 core_ctx,
3999 id,
4000 original_bound_addr.clone(),
4001 clear_device_on_disconnect,
4002 &ip_options,
4003 inner_state,
4004 sharing.clone(),
4005 )),
4006 };
4007 Ok(())
4008 })
4009 }
4010
4011 pub fn disconnect_any_to_unbound(&mut self, id: &DatagramApiSocketId<I, C, S>) {
4014 self.core_ctx().with_socket_state_mut(id, |core_ctx, state| {
4015 let SocketState { ip_options, inner, sharing, .. } = state;
4016 match inner {
4017 SocketStateInner::Unbound(UnboundSocketState { device }) => {
4018 *device = None;
4019 }
4020 SocketStateInner::Bound(bound_state) => {
4021 let unbound_state = disconnect_to_unbound(
4022 core_ctx,
4023 id,
4024 true,
4025 ip_options,
4026 bound_state,
4027 sharing.clone(),
4028 );
4029 state.inner = SocketStateInner::Unbound(unbound_state);
4030 }
4031 }
4032 });
4033 }
4034
4035 pub fn get_shutdown_connected(
4037 &mut self,
4038 id: &DatagramApiSocketId<I, C, S>,
4039 ) -> Option<ShutdownType> {
4040 self.core_ctx().with_socket_state(id, |core_ctx, state| {
4041 let state = match &state.inner {
4042 SocketStateInner::Unbound(_) => return None,
4043 SocketStateInner::Bound(BoundSocketState {
4044 socket_type,
4045 original_bound_addr: _,
4046 }) => match socket_type {
4047 BoundSocketStateType::Listener(_) => return None,
4048 BoundSocketStateType::Connected(state) => state,
4049 },
4050 };
4051 let Shutdown { send, receive } = match core_ctx.dual_stack_context_mut() {
4052 MaybeDualStack::DualStack(ds) => ds.ds_converter().convert(state).as_ref(),
4053 MaybeDualStack::NotDualStack(nds) => nds.nds_converter().convert(state).as_ref(),
4054 };
4055 ShutdownType::from_send_receive(*send, *receive)
4056 })
4057 }
4058
4059 pub fn shutdown_connected(
4063 &mut self,
4064 id: &DatagramApiSocketId<I, C, S>,
4065 which: ShutdownType,
4066 ) -> Result<(), ExpectedConnError> {
4067 self.core_ctx().with_socket_state_mut(id, |core_ctx, state| {
4068 let state = match &mut state.inner {
4069 SocketStateInner::Unbound(_) => return Err(ExpectedConnError),
4070 SocketStateInner::Bound(BoundSocketState {
4071 socket_type,
4072 original_bound_addr: _,
4073 }) => match socket_type {
4074 BoundSocketStateType::Listener(_) => {
4075 return Err(ExpectedConnError);
4076 }
4077 BoundSocketStateType::Connected(state) => state,
4078 },
4079 };
4080 let (shutdown_send, shutdown_receive) = which.to_send_receive();
4081 let Shutdown { send, receive } = match core_ctx.dual_stack_context_mut() {
4082 MaybeDualStack::DualStack(ds) => ds.ds_converter().convert(state).as_mut(),
4083 MaybeDualStack::NotDualStack(nds) => nds.nds_converter().convert(state).as_mut(),
4084 };
4085 *send |= shutdown_send;
4086 *receive |= shutdown_receive;
4087 Ok(())
4088 })
4089 }
4090
4091 pub fn send_conn<B: BufferMut>(
4093 &mut self,
4094 id: &DatagramApiSocketId<I, C, S>,
4095 body: B,
4096 send_token: S::SendToken,
4097 ) -> Result<(), SendError<S::SerializeError>> {
4098 let (core_ctx, bindings_ctx) = self.contexts();
4099 core_ctx.with_socket_state(id, |core_ctx, state| {
4100 let SocketState { inner, ip_options, sharing: _ } = state;
4101 let state = match inner {
4102 SocketStateInner::Unbound(_) => return Err(SendError::NotConnected),
4103 SocketStateInner::Bound(BoundSocketState {
4104 socket_type,
4105 original_bound_addr: _,
4106 }) => match socket_type {
4107 BoundSocketStateType::Listener(_) => {
4108 return Err(SendError::NotConnected);
4109 }
4110 BoundSocketStateType::Connected(state) => state,
4111 },
4112 };
4113
4114 struct SendParams<
4115 'a,
4116 I: IpExt,
4117 S: DatagramSocketSpec,
4118 D: WeakDeviceIdentifier,
4119 O: SendOptions<I> + RouteResolutionOptions<I>,
4120 > {
4121 socket: &'a IpSock<I, D>,
4122 ip: &'a ConnIpAddr<
4123 I::Addr,
4124 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
4125 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
4126 >,
4127 options: O,
4128 }
4129
4130 enum Operation<
4131 'a,
4132 I: DualStackIpExt,
4133 S: DatagramSocketSpec,
4134 D: WeakDeviceIdentifier,
4135 BC: DatagramBindingsContext,
4136 DualStackSC: DualStackDatagramBoundStateContext<I, BC, S>,
4137 CC: DatagramBoundStateContext<I, BC, S>,
4138 O: SendOptions<I> + RouteResolutionOptions<I>,
4139 OtherO: SendOptions<I::OtherVersion> + RouteResolutionOptions<I::OtherVersion>,
4140 > {
4141 SendToThisStack((SendParams<'a, I, S, D, O>, &'a mut CC)),
4142 SendToOtherStack(
4143 (SendParams<'a, I::OtherVersion, S, D, OtherO>, &'a mut DualStackSC),
4144 ),
4145 _Phantom((!, PhantomData<BC>)),
4148 }
4149
4150 let (shutdown, operation) = match core_ctx.dual_stack_context_mut() {
4151 MaybeDualStack::DualStack(dual_stack) => {
4152 match dual_stack.ds_converter().convert(state) {
4153 DualStackConnState::ThisStack(ConnState {
4154 socket,
4155 clear_device_on_disconnect: _,
4156 shutdown,
4157 addr: ConnAddr { ip, device: _ },
4158 extra: _,
4159 }) => (
4160 shutdown,
4161 Operation::SendToThisStack((
4162 SendParams {
4163 socket,
4164 ip,
4165 options: ip_options.this_stack_options_ref(),
4166 },
4167 core_ctx,
4168 )),
4169 ),
4170 DualStackConnState::OtherStack(ConnState {
4171 socket,
4172 clear_device_on_disconnect: _,
4173 shutdown,
4174 addr: ConnAddr { ip, device: _ },
4175 extra: _,
4176 }) => (
4177 shutdown,
4178 Operation::SendToOtherStack((
4179 SendParams {
4180 socket,
4181 ip,
4182 options: ip_options.other_stack_options_ref(dual_stack),
4183 },
4184 dual_stack,
4185 )),
4186 ),
4187 }
4188 }
4189 MaybeDualStack::NotDualStack(not_dual_stack) => {
4190 let ConnState {
4191 socket,
4192 clear_device_on_disconnect: _,
4193 shutdown,
4194 addr: ConnAddr { ip, device: _ },
4195 extra: _,
4196 } = not_dual_stack.nds_converter().convert(state);
4197 (
4198 shutdown,
4199 Operation::SendToThisStack((
4200 SendParams { socket, ip, options: ip_options.this_stack_options_ref() },
4201 core_ctx,
4202 )),
4203 )
4204 }
4205 };
4206
4207 let Shutdown { send: shutdown_send, receive: _ } = shutdown;
4208 if *shutdown_send {
4209 return Err(SendError::NotWriteable);
4210 }
4211
4212 let tx_metadata = TxMetadata::<I, _, _>::new(id, send_token);
4213 match operation {
4214 Operation::SendToThisStack((SendParams { socket, ip, options }, core_ctx)) => {
4215 let packet =
4216 S::make_packet::<I, _>(body, &ip).map_err(SendError::SerializeError)?;
4217 DatagramBoundStateContext::with_transport_context(core_ctx, |core_ctx| {
4218 let tx_metadata = core_ctx.convert_tx_meta(tx_metadata);
4219 core_ctx
4220 .send_ip_packet(bindings_ctx, &socket, packet, &options, tx_metadata)
4221 .map_err(|send_error| SendError::IpSock(send_error))
4222 })
4223 }
4224 Operation::SendToOtherStack((SendParams { socket, ip, options }, dual_stack)) => {
4225 let packet = S::make_packet::<I::OtherVersion, _>(body, &ip)
4226 .map_err(SendError::SerializeError)?;
4227 DualStackDatagramBoundStateContext::with_transport_context::<_, _>(
4228 dual_stack,
4229 |core_ctx| {
4230 let tx_metadata = core_ctx.convert_tx_meta(tx_metadata);
4231 core_ctx
4232 .send_ip_packet(
4233 bindings_ctx,
4234 &socket,
4235 packet,
4236 &options,
4237 tx_metadata,
4238 )
4239 .map_err(|send_error| SendError::IpSock(send_error))
4240 },
4241 )
4242 }
4243 }
4244 })
4245 }
4246
4247 pub fn send_to<B: BufferMut>(
4249 &mut self,
4250 id: &DatagramApiSocketId<I, C, S>,
4251 remote_ip: Option<ZonedAddr<SpecifiedAddr<I::Addr>, DatagramApiDeviceId<C>>>,
4252 remote_identifier: <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
4253 body: B,
4254 send_token: S::SendToken,
4255 ) -> Result<(), SendToError<S::SerializeError>> {
4256 let (core_ctx, bindings_ctx) = self.contexts();
4257 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
4258 match listen_inner(core_ctx, bindings_ctx, state, id, None, None) {
4259 Ok(()) | Err(Either::Left(ExpectedUnboundError)) => (),
4260 Err(Either::Right(e)) => return Err(SendToError::LocalAddress(e)),
4261 };
4262 let SocketState { inner, ip_options, sharing: _ } = state;
4263 let state = match inner {
4264 SocketStateInner::Unbound(_) => panic!("expected bound socket"),
4265 SocketStateInner::Bound(BoundSocketState {
4266 socket_type: state,
4267 original_bound_addr: _,
4268 }) => state,
4269 };
4270
4271 enum Operation<
4272 'a,
4273 I: DualStackIpExt,
4274 S: DatagramSocketSpec,
4275 D: WeakDeviceIdentifier,
4276 BC: DatagramBindingsContext,
4277 DualStackSC: DualStackDatagramBoundStateContext<I, BC, S>,
4278 CC: DatagramBoundStateContext<I, BC, S>,
4279 > {
4280 SendToThisStack((SendOneshotParameters<'a, I, I, S, D>, &'a mut CC)),
4281
4282 SendToOtherStack(
4283 (SendOneshotParameters<'a, I, I::OtherVersion, S, D>, &'a mut DualStackSC),
4284 ),
4285 _Phantom((!, PhantomData<BC>)),
4288 }
4289
4290 let (operation, shutdown) = match (
4291 core_ctx.dual_stack_context_mut(),
4292 DualStackRemoteIp::<I, _>::new(remote_ip.clone()),
4293 ) {
4294 (MaybeDualStack::NotDualStack(_), DualStackRemoteIp::OtherStack(_)) => {
4295 return Err(SendToError::RemoteUnexpectedlyMapped);
4296 }
4297 (MaybeDualStack::NotDualStack(nds), DualStackRemoteIp::ThisStack(remote_ip)) => {
4298 match state {
4299 BoundSocketStateType::Listener(ListenerState {
4300 addr: ListenerAddr { ip, device },
4301 }) => {
4302 let ListenerIpAddr { addr, identifier } =
4303 nds.nds_converter().convert(ip.clone());
4304 (
4305 Operation::SendToThisStack((
4306 SendOneshotParameters {
4307 local_ip: addr,
4308 local_id: identifier,
4309 remote_ip,
4310 remote_id: remote_identifier,
4311 device,
4312 options: ip_options.this_stack_options_ref(),
4313 id,
4314 send_token,
4315 },
4316 core_ctx,
4317 )),
4318 None,
4319 )
4320 }
4321 BoundSocketStateType::Connected(state) => {
4322 let ConnState {
4323 socket: _,
4324 clear_device_on_disconnect: _,
4325 shutdown,
4326 addr:
4327 ConnAddr {
4328 ip: ConnIpAddr { local: (local_ip, local_id), remote: _ },
4329 device,
4330 },
4331 extra: _,
4332 } = nds.nds_converter().convert(state);
4333 (
4334 Operation::SendToThisStack((
4335 SendOneshotParameters {
4336 local_ip: Some(*local_ip),
4337 local_id: *local_id,
4338 remote_ip,
4339 remote_id: remote_identifier,
4340 device,
4341 options: ip_options.this_stack_options_ref(),
4342 id,
4343 send_token,
4344 },
4345 core_ctx,
4346 )),
4347 Some(shutdown),
4348 )
4349 }
4350 }
4351 }
4352 (MaybeDualStack::DualStack(ds), remote_ip) => match state {
4353 BoundSocketStateType::Listener(ListenerState {
4354 addr: ListenerAddr { ip, device },
4355 }) => match (ds.ds_converter().convert(ip), remote_ip) {
4356 (
4357 DualStackListenerIpAddr::ThisStack(_),
4358 DualStackRemoteIp::OtherStack(_),
4359 ) => return Err(SendToError::RemoteUnexpectedlyMapped),
4360 (
4361 DualStackListenerIpAddr::OtherStack(_),
4362 DualStackRemoteIp::ThisStack(_),
4363 ) => return Err(SendToError::RemoteUnexpectedlyNonMapped),
4364 (
4365 DualStackListenerIpAddr::ThisStack(ListenerIpAddr { addr, identifier }),
4366 DualStackRemoteIp::ThisStack(remote_ip),
4367 ) => (
4368 Operation::SendToThisStack((
4369 SendOneshotParameters {
4370 local_ip: *addr,
4371 local_id: *identifier,
4372 remote_ip,
4373 remote_id: remote_identifier,
4374 device,
4375 options: ip_options.this_stack_options_ref(),
4376 id,
4377 send_token,
4378 },
4379 core_ctx,
4380 )),
4381 None,
4382 ),
4383 (
4384 DualStackListenerIpAddr::BothStacks(identifier),
4385 DualStackRemoteIp::ThisStack(remote_ip),
4386 ) => (
4387 Operation::SendToThisStack((
4388 SendOneshotParameters {
4389 local_ip: None,
4390 local_id: *identifier,
4391 remote_ip,
4392 remote_id: remote_identifier,
4393 device,
4394 options: ip_options.this_stack_options_ref(),
4395 id,
4396 send_token,
4397 },
4398 core_ctx,
4399 )),
4400 None,
4401 ),
4402 (
4403 DualStackListenerIpAddr::OtherStack(ListenerIpAddr {
4404 addr,
4405 identifier,
4406 }),
4407 DualStackRemoteIp::OtherStack(remote_ip),
4408 ) => (
4409 Operation::SendToOtherStack((
4410 SendOneshotParameters {
4411 local_ip: *addr,
4412 local_id: *identifier,
4413 remote_ip,
4414 remote_id: remote_identifier,
4415 device,
4416 options: ip_options.other_stack_options_ref(ds),
4417 id,
4418 send_token,
4419 },
4420 ds,
4421 )),
4422 None,
4423 ),
4424 (
4425 DualStackListenerIpAddr::BothStacks(identifier),
4426 DualStackRemoteIp::OtherStack(remote_ip),
4427 ) => (
4428 Operation::SendToOtherStack((
4429 SendOneshotParameters {
4430 local_ip: None,
4431 local_id: *identifier,
4432 remote_ip,
4433 remote_id: remote_identifier,
4434 device,
4435 options: ip_options.other_stack_options_ref(ds),
4436 id,
4437 send_token,
4438 },
4439 ds,
4440 )),
4441 None,
4442 ),
4443 },
4444 BoundSocketStateType::Connected(state) => {
4445 match (ds.ds_converter().convert(state), remote_ip) {
4446 (
4447 DualStackConnState::ThisStack(_),
4448 DualStackRemoteIp::OtherStack(_),
4449 ) => return Err(SendToError::RemoteUnexpectedlyMapped),
4450 (
4451 DualStackConnState::OtherStack(_),
4452 DualStackRemoteIp::ThisStack(_),
4453 ) => {
4454 return Err(SendToError::RemoteUnexpectedlyNonMapped);
4455 }
4456 (
4457 DualStackConnState::ThisStack(state),
4458 DualStackRemoteIp::ThisStack(remote_ip),
4459 ) => {
4460 let ConnState {
4461 socket: _,
4462 clear_device_on_disconnect: _,
4463 shutdown,
4464 addr,
4465 extra: _,
4466 } = state;
4467 let ConnAddr {
4468 ip: ConnIpAddr { local: (local_ip, local_id), remote: _ },
4469 device,
4470 } = addr;
4471 (
4472 Operation::SendToThisStack((
4473 SendOneshotParameters {
4474 local_ip: Some(*local_ip),
4475 local_id: *local_id,
4476 remote_ip,
4477 remote_id: remote_identifier,
4478 device,
4479 options: ip_options.this_stack_options_ref(),
4480 id,
4481 send_token,
4482 },
4483 core_ctx,
4484 )),
4485 Some(shutdown),
4486 )
4487 }
4488 (
4489 DualStackConnState::OtherStack(state),
4490 DualStackRemoteIp::OtherStack(remote_ip),
4491 ) => {
4492 let ConnState {
4493 socket: _,
4494 clear_device_on_disconnect: _,
4495 shutdown,
4496 addr,
4497 extra: _,
4498 } = state;
4499 let ConnAddr {
4500 ip: ConnIpAddr { local: (local_ip, local_id), .. },
4501 device,
4502 } = addr;
4503 (
4504 Operation::SendToOtherStack((
4505 SendOneshotParameters {
4506 local_ip: Some(*local_ip),
4507 local_id: *local_id,
4508 remote_ip,
4509 remote_id: remote_identifier,
4510 device,
4511 options: ip_options.other_stack_options_ref(ds),
4512 id,
4513 send_token,
4514 },
4515 ds,
4516 )),
4517 Some(shutdown),
4518 )
4519 }
4520 }
4521 }
4522 },
4523 };
4524
4525 if let Some(Shutdown { send: shutdown_write, receive: _ }) = shutdown {
4526 if *shutdown_write {
4527 return Err(SendToError::NotWriteable);
4528 }
4529 }
4530
4531 match operation {
4532 Operation::SendToThisStack((params, core_ctx)) => {
4533 DatagramBoundStateContext::with_transport_context(core_ctx, |core_ctx| {
4534 send_oneshot(core_ctx, bindings_ctx, params, body)
4535 })
4536 }
4537 Operation::SendToOtherStack((params, core_ctx)) => {
4538 DualStackDatagramBoundStateContext::with_transport_context::<_, _>(
4539 core_ctx,
4540 |core_ctx| send_oneshot(core_ctx, bindings_ctx, params, body),
4541 )
4542 }
4543 }
4544 })
4545 }
4546
4547 pub fn get_bound_device(
4549 &mut self,
4550 id: &DatagramApiSocketId<I, C, S>,
4551 ) -> Option<DatagramApiWeakDeviceId<C>> {
4552 self.core_ctx().with_socket_state(id, |core_ctx, state| state.get_device(core_ctx).clone())
4553 }
4554
4555 pub fn set_device(
4557 &mut self,
4558 id: &DatagramApiSocketId<I, C, S>,
4559 new_device: Option<&DatagramApiDeviceId<C>>,
4560 ) -> Result<(), SocketError> {
4561 let (core_ctx, bindings_ctx) = self.contexts();
4562 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
4563 let SocketState { inner, ip_options, sharing } = state;
4564 match inner {
4565 SocketStateInner::Unbound(state) => {
4566 let UnboundSocketState { device } = state;
4567 *device = new_device.map(|d| d.downgrade());
4568 Ok(())
4569 }
4570 SocketStateInner::Bound(BoundSocketState {
4571 socket_type,
4572 original_bound_addr: _,
4573 }) => {
4574 enum Operation<
4577 'a,
4578 I: IpExt,
4579 D: WeakDeviceIdentifier,
4580 S: DatagramSocketSpec,
4581 CC,
4582 DualStackSC,
4583 > {
4584 ThisStack {
4585 params: SetBoundDeviceParameters<'a, I, D, S>,
4586 core_ctx: CC,
4587 },
4588 OtherStack {
4589 params: SetBoundDeviceParameters<'a, I::OtherVersion, D, S>,
4590 core_ctx: DualStackSC,
4591 },
4592 ListenerBothStacks {
4593 identifier: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
4594 device: &'a mut Option<D>,
4595 core_ctx: DualStackSC,
4596 },
4597 }
4598
4599 let op = match core_ctx.dual_stack_context_mut() {
4601 MaybeDualStack::DualStack(ds) => match socket_type {
4602 BoundSocketStateType::Listener(ListenerState {
4603 addr: ListenerAddr { ip, device },
4604 }) => match ds.ds_converter().convert(ip) {
4605 DualStackListenerIpAddr::ThisStack(ip) => Operation::ThisStack {
4606 params: SetBoundDeviceParameters::Listener { ip, device },
4607 core_ctx,
4608 },
4609 DualStackListenerIpAddr::OtherStack(ip) => Operation::OtherStack {
4610 params: SetBoundDeviceParameters::Listener { ip, device },
4611 core_ctx: ds,
4612 },
4613 DualStackListenerIpAddr::BothStacks(identifier) => {
4614 Operation::ListenerBothStacks {
4615 identifier: *identifier,
4616 device,
4617 core_ctx: ds,
4618 }
4619 }
4620 },
4621 BoundSocketStateType::Connected(state) => {
4622 match ds.ds_converter().convert(state) {
4623 DualStackConnState::ThisStack(state) => Operation::ThisStack {
4624 params: SetBoundDeviceParameters::Connected(state),
4625 core_ctx,
4626 },
4627 DualStackConnState::OtherStack(state) => {
4628 Operation::OtherStack {
4629 params: SetBoundDeviceParameters::Connected(state),
4630 core_ctx: ds,
4631 }
4632 }
4633 }
4634 }
4635 },
4636 MaybeDualStack::NotDualStack(nds) => match socket_type {
4637 BoundSocketStateType::Listener(ListenerState {
4638 addr: ListenerAddr { ip, device },
4639 }) => Operation::ThisStack {
4640 params: SetBoundDeviceParameters::Listener {
4641 ip: nds.nds_converter().convert(ip),
4642 device,
4643 },
4644 core_ctx,
4645 },
4646 BoundSocketStateType::Connected(state) => Operation::ThisStack {
4647 params: SetBoundDeviceParameters::Connected(
4648 nds.nds_converter().convert(state),
4649 ),
4650 core_ctx,
4651 },
4652 },
4653 };
4654
4655 match op {
4657 Operation::ThisStack { params, core_ctx } => {
4658 let socket_id = S::make_bound_socket_map_id(id);
4659 DatagramBoundStateContext::<I, _, _>::with_bound_sockets_mut(
4660 core_ctx,
4661 |core_ctx, bound| {
4662 set_bound_device_single_stack(
4663 bindings_ctx,
4664 core_ctx,
4665 params,
4666 bound,
4667 &socket_id,
4668 &ip_options.common,
4669 new_device,
4670 sharing.clone(),
4671 )
4672 },
4673 )
4674 }
4675 Operation::OtherStack { params, core_ctx } => {
4676 let socket_id = core_ctx.to_other_bound_socket_id(id);
4677 core_ctx.with_other_bound_sockets_mut(|core_ctx, bound| {
4678 set_bound_device_single_stack(
4679 bindings_ctx,
4680 core_ctx,
4681 params,
4682 bound,
4683 &socket_id,
4684 &ip_options.common,
4685 new_device,
4686 sharing.clone(),
4687 )
4688 })
4689 }
4690 Operation::ListenerBothStacks { identifier, device, core_ctx } => {
4691 let socket_id = PairedBoundSocketIds::<_, _, S> {
4692 this: S::make_bound_socket_map_id(id),
4693 other: core_ctx.to_other_bound_socket_id(id),
4694 };
4695 core_ctx.with_both_bound_sockets_mut(|_core_ctx, bound, other_bound| {
4696 set_bound_device_listener_both_stacks(
4697 device,
4698 identifier,
4699 PairedSocketMapMut { bound, other_bound },
4700 socket_id,
4701 new_device.map(|d| d.downgrade()),
4702 sharing.clone(),
4703 )
4704 })
4705 }
4706 }
4707 }
4708 }
4709 })
4710 }
4711
4712 pub fn set_multicast_membership(
4719 &mut self,
4720 id: &DatagramApiSocketId<I, C, S>,
4721 multicast_group: MulticastAddr<I::Addr>,
4722 interface: MulticastMembershipInterfaceSelector<I::Addr, DatagramApiDeviceId<C>>,
4723 want_membership: bool,
4724 ) -> Result<(), SetMulticastMembershipError> {
4725 let (core_ctx, bindings_ctx) = self.contexts();
4726 core_ctx.with_socket_state_mut(id, |core_ctx, state| {
4727 let ip_options = state.options();
4728 let bound_device = state.get_device(core_ctx);
4729
4730 let interface = match interface {
4731 MulticastMembershipInterfaceSelector::Specified(selector) => match selector {
4732 MulticastInterfaceSelector::Interface(device) => {
4733 if bound_device.as_ref().is_some_and(|d| d != &device) {
4734 return Err(SetMulticastMembershipError::WrongDevice);
4735 } else {
4736 EitherDeviceId::Strong(device)
4737 }
4738 }
4739 MulticastInterfaceSelector::LocalAddress(addr) => {
4740 EitherDeviceId::Strong(pick_interface_for_addr(
4741 core_ctx,
4742 multicast_group,
4743 Some(addr),
4744 &ip_options.common.marks,
4745 )?)
4746 }
4747 },
4748 MulticastMembershipInterfaceSelector::AnyInterfaceWithRoute => {
4749 if let Some(bound_device) = bound_device.as_ref() {
4750 EitherDeviceId::Weak(bound_device.clone())
4751 } else {
4752 EitherDeviceId::Strong(pick_interface_for_addr(
4753 core_ctx,
4754 multicast_group,
4755 None,
4756 &ip_options.common.marks,
4757 )?)
4758 }
4759 }
4760 };
4761
4762 let ip_options = state.options_mut();
4763
4764 let Some(strong_interface) = interface.as_strong() else {
4765 return Err(SetMulticastMembershipError::DeviceDoesNotExist);
4766 };
4767
4768 let change = ip_options
4769 .multicast_memberships
4770 .apply_membership_change(multicast_group, &interface.as_weak(), want_membership)
4771 .ok_or(if want_membership {
4772 SetMulticastMembershipError::GroupAlreadyJoined
4773 } else {
4774 SetMulticastMembershipError::GroupNotJoined
4775 })?;
4776
4777 DatagramBoundStateContext::<I, _, _>::with_transport_context(core_ctx, |core_ctx| {
4778 match change {
4779 MulticastMembershipChange::Join => {
4780 MulticastMembershipHandler::<I, _>::join_multicast_group(
4781 core_ctx,
4782 bindings_ctx,
4783 &strong_interface,
4784 multicast_group,
4785 )
4786 }
4787 MulticastMembershipChange::Leave => {
4788 MulticastMembershipHandler::<I, _>::leave_multicast_group(
4789 core_ctx,
4790 bindings_ctx,
4791 &strong_interface,
4792 multicast_group,
4793 )
4794 }
4795 }
4796 });
4797
4798 Ok(())
4799 })
4800 }
4801
4802 pub fn update_ip_hop_limit(
4804 &mut self,
4805 id: &DatagramApiSocketId<I, C, S>,
4806 update: impl FnOnce(&mut SocketHopLimits<I>),
4807 ) {
4808 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4809 let options = state.options_mut();
4810
4811 update(&mut options.socket_options.hop_limits)
4812 })
4813 }
4814
4815 pub fn get_ip_hop_limits(&mut self, id: &DatagramApiSocketId<I, C, S>) -> HopLimits {
4817 self.core_ctx().with_socket_state(id, |core_ctx, state| {
4818 let options = state.options();
4819 let device = state.get_device(core_ctx);
4820 let device = device.as_ref().and_then(|d| d.upgrade());
4821 DatagramBoundStateContext::<I, _, _>::with_transport_context(core_ctx, |core_ctx| {
4822 options.socket_options.hop_limits.get_limits_with_defaults(
4823 &BaseTransportIpContext::<I, _>::get_default_hop_limits(
4824 core_ctx,
4825 device.as_ref(),
4826 ),
4827 )
4828 })
4829 })
4830 }
4831
4832 pub fn with_other_stack_ip_options_mut_if_unbound<R>(
4838 &mut self,
4839 id: &DatagramApiSocketId<I, C, S>,
4840 cb: impl FnOnce(&mut S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>) -> R,
4841 ) -> Result<R, ExpectedUnboundError> {
4842 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4843 let is_unbound = match &state.inner {
4844 SocketStateInner::Unbound(_) => true,
4845 SocketStateInner::Bound(_) => false,
4846 };
4847 if is_unbound {
4848 let options = state.options_mut();
4849 Ok(cb(&mut options.other_stack))
4850 } else {
4851 Err(ExpectedUnboundError)
4852 }
4853 })
4854 }
4855
4856 pub fn with_other_stack_ip_options_mut<R>(
4859 &mut self,
4860 id: &DatagramApiSocketId<I, C, S>,
4861 cb: impl FnOnce(&mut S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>) -> R,
4862 ) -> R {
4863 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4864 let options = state.options_mut();
4865 cb(&mut options.other_stack)
4866 })
4867 }
4868
4869 pub fn with_other_stack_ip_options<R>(
4871 &mut self,
4872 id: &DatagramApiSocketId<I, C, S>,
4873 cb: impl FnOnce(&S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>) -> R,
4874 ) -> R {
4875 self.core_ctx().with_socket_state(id, |_core_ctx, state| cb(&state.options().other_stack))
4876 }
4877
4878 pub fn with_other_stack_ip_options_and_default_hop_limits<R>(
4884 &mut self,
4885 id: &DatagramApiSocketId<I, C, S>,
4886 cb: impl FnOnce(&S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>, HopLimits) -> R,
4887 ) -> Result<R, NotDualStackCapableError> {
4888 self.core_ctx().with_socket_state(id, |core_ctx, state| {
4889 let options = state.options();
4890 let device = state.get_device(core_ctx).as_ref().and_then(|d| d.upgrade());
4891 match DatagramBoundStateContext::<I, _, _>::dual_stack_context_mut(core_ctx) {
4892 MaybeDualStack::NotDualStack(_) => Err(NotDualStackCapableError),
4893 MaybeDualStack::DualStack(ds) => {
4894 let default_hop_limits =
4895 DualStackDatagramBoundStateContext::<I, _, _>::with_transport_context(
4896 ds,
4897 |sync_ctx| {
4898 BaseTransportIpContext::<I, _>::get_default_hop_limits(
4899 sync_ctx,
4900 device.as_ref(),
4901 )
4902 },
4903 );
4904 Ok(cb(&options.other_stack, default_hop_limits))
4905 }
4906 }
4907 })
4908 }
4909
4910 pub fn with_both_stacks_ip_options_mut<R>(
4914 &mut self,
4915 id: &DatagramApiSocketId<I, C, S>,
4916 cb: impl FnOnce(
4917 &mut DatagramIpSpecificSocketOptions<I, DatagramApiWeakDeviceId<C>>,
4918 &mut S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>,
4919 ) -> R,
4920 ) -> R {
4921 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4922 let options = state.options_mut();
4923 cb(&mut options.socket_options, &mut options.other_stack)
4924 })
4925 }
4926
4927 pub fn with_both_stacks_ip_options<R>(
4930 &mut self,
4931 id: &DatagramApiSocketId<I, C, S>,
4932 cb: impl FnOnce(
4933 &DatagramIpSpecificSocketOptions<I, DatagramApiWeakDeviceId<C>>,
4934 &S::OtherStackIpOptions<I, DatagramApiWeakDeviceId<C>>,
4935 ) -> R,
4936 ) -> R {
4937 self.core_ctx().with_socket_state(id, |_core_ctx, state| {
4938 let options = state.options();
4939 cb(&options.socket_options, &options.other_stack)
4940 })
4941 }
4942
4943 pub fn update_sharing(
4948 &mut self,
4949 id: &DatagramApiSocketId<I, C, S>,
4950 f: impl FnOnce(&mut S::SharingState),
4951 ) -> Result<(), ExpectedUnboundError> {
4952 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4953 match &mut state.inner {
4954 SocketStateInner::Unbound(_) => (),
4955 SocketStateInner::Bound(_) => return Err(ExpectedUnboundError),
4956 };
4957
4958 f(&mut state.sharing);
4959 Ok(())
4960 })
4961 }
4962
4963 pub fn get_sharing(&mut self, id: &DatagramApiSocketId<I, C, S>) -> S::SharingState {
4965 self.core_ctx().with_socket_state(id, |_core_ctx, state| state.sharing.clone())
4966 }
4967
4968 pub fn set_ip_transparent(&mut self, id: &DatagramApiSocketId<I, C, S>, value: bool) {
4970 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4971 state.options_mut().common.transparent = value;
4972 })
4973 }
4974
4975 pub fn get_ip_transparent(&mut self, id: &DatagramApiSocketId<I, C, S>) -> bool {
4977 self.core_ctx().with_socket_state(id, |_core_ctx, state| state.options().common.transparent)
4978 }
4979
4980 pub fn set_mark(&mut self, id: &DatagramApiSocketId<I, C, S>, domain: MarkDomain, mark: Mark) {
4982 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
4983 *state.options_mut().common.marks.get_mut(domain) = mark;
4984 })
4985 }
4986
4987 pub fn get_mark(&mut self, id: &DatagramApiSocketId<I, C, S>, domain: MarkDomain) -> Mark {
4989 self.core_ctx()
4990 .with_socket_state(id, |_core_ctx, state| *state.options().common.marks.get(domain))
4991 }
4992
4993 pub fn set_broadcast(
4995 &mut self,
4996 id: &DatagramApiSocketId<I, C, S>,
4997 value: Option<I::BroadcastMarker>,
4998 ) {
4999 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5000 state.options_mut().socket_options.allow_broadcast = value;
5001 })
5002 }
5003
5004 pub fn get_broadcast(
5006 &mut self,
5007 id: &DatagramApiSocketId<I, C, S>,
5008 ) -> Option<I::BroadcastMarker> {
5009 self.core_ctx().with_socket_state(id, |_core_ctx, state| {
5010 state.options().socket_options.allow_broadcast
5011 })
5012 }
5013
5014 pub fn set_multicast_interface(
5016 &mut self,
5017 id: &DatagramApiSocketId<I, C, S>,
5018 value: Option<&DatagramApiDeviceId<C>>,
5019 ) {
5020 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5021 state.options_mut().socket_options.multicast_interface = value.map(|v| v.downgrade());
5022 })
5023 }
5024
5025 pub fn get_multicast_interface(
5027 &mut self,
5028 id: &DatagramApiSocketId<I, C, S>,
5029 ) -> Option<DatagramApiWeakDeviceId<C>> {
5030 self.core_ctx().with_socket_state(id, |_core_ctx, state| {
5031 state.options().socket_options.multicast_interface.clone()
5032 })
5033 }
5034
5035 pub fn set_multicast_loop(&mut self, id: &DatagramApiSocketId<I, C, S>, value: bool) {
5037 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5038 state.options_mut().socket_options.multicast_loop = value;
5039 })
5040 }
5041
5042 pub fn get_multicast_loop(&mut self, id: &DatagramApiSocketId<I, C, S>) -> bool {
5044 self.core_ctx()
5045 .with_socket_state(id, |_core_ctx, state| state.options().socket_options.multicast_loop)
5046 }
5047
5048 pub fn set_dscp_and_ecn(&mut self, id: &DatagramApiSocketId<I, C, S>, value: DscpAndEcn) {
5050 self.core_ctx().with_socket_state_mut(id, |_core_ctx, state| {
5051 state.options_mut().socket_options.dscp_and_ecn = value;
5052 })
5053 }
5054
5055 pub fn get_dscp_and_ecn(&mut self, id: &DatagramApiSocketId<I, C, S>) -> DscpAndEcn {
5057 self.core_ctx()
5058 .with_socket_state(id, |_core_ctx, state| state.options().socket_options.dscp_and_ecn)
5059 }
5060}
5061
5062#[cfg(any(test, feature = "testutils"))]
5063pub(crate) mod testutil {
5064 use super::*;
5065
5066 use alloc::vec;
5067 use net_types::Witness;
5068 use net_types::ip::IpAddr;
5069 use netstack3_base::CtxPair;
5070 use netstack3_base::testutil::{FakeStrongDeviceId, TestIpExt};
5071 use netstack3_ip::socket::testutil::FakeDeviceConfig;
5072
5073 pub fn setup_fake_ctx_with_dualstack_conn_addrs<CC, BC: Default, D: FakeStrongDeviceId>(
5077 local_ip: IpAddr,
5078 remote_ip: SpecifiedAddr<IpAddr>,
5079 devices: impl IntoIterator<Item = D>,
5080 core_ctx_builder: impl FnOnce(Vec<FakeDeviceConfig<D, SpecifiedAddr<IpAddr>>>) -> CC,
5081 ) -> CtxPair<CC, BC> {
5082 fn unmap_ip(addr: IpAddr) -> IpAddr {
5084 match addr {
5085 IpAddr::V4(v4) => IpAddr::V4(v4),
5086 IpAddr::V6(v6) => match v6.to_ipv4_mapped() {
5087 Some(v4) => IpAddr::V4(v4),
5088 None => IpAddr::V6(v6),
5089 },
5090 }
5091 }
5092
5093 let local_ip = unmap_ip(local_ip);
5095 let remote_ip = unmap_ip(remote_ip.get());
5096 let local_ip = SpecifiedAddr::new(local_ip).unwrap_or_else(|| match remote_ip {
5101 IpAddr::V4(_) => Ipv4::TEST_ADDRS.local_ip.into(),
5102 IpAddr::V6(_) => Ipv6::TEST_ADDRS.local_ip.into(),
5103 });
5104 let remote_ip = SpecifiedAddr::new(remote_ip).expect("remote-ip should be specified");
5107 CtxPair::with_core_ctx(core_ctx_builder(
5108 devices
5109 .into_iter()
5110 .map(|device| FakeDeviceConfig {
5111 device,
5112 local_ips: vec![local_ip],
5113 remote_ips: vec![remote_ip],
5114 })
5115 .collect(),
5116 ))
5117 }
5118}
5119
5120#[cfg(test)]
5121mod test {
5122
5123 use alloc::vec;
5124 use assert_matches::assert_matches;
5125 use derivative::Derivative;
5126 use ip_test_macro::ip_test;
5127 use net_declare::{net_ip_v4, net_ip_v6};
5128 use net_types::Witness;
5129 use net_types::ip::{IpVersionMarker, Ipv4Addr, Ipv6Addr};
5130 use netstack3_base::socket::{
5131 AddrVec, Bound, IncompatibleError, ListenerAddrInfo, RemoveResult, SocketMapAddrStateSpec,
5132 };
5133 use netstack3_base::socketmap::SocketMap;
5134 use netstack3_base::testutil::{
5135 FakeDeviceId, FakeReferencyDeviceId, FakeSendToken, FakeStrongDeviceId, FakeWeakDeviceId,
5136 MultipleDevicesId, TestIpExt,
5137 };
5138 use netstack3_base::{ContextProvider, CtxPair, UninstantiableWrapper};
5139 use netstack3_ip::DEFAULT_HOP_LIMITS;
5140 use netstack3_ip::device::IpDeviceStateIpExt;
5141 use netstack3_ip::socket::testutil::{
5142 FakeDeviceConfig, FakeDualStackIpSocketCtx, FakeIpSocketCtx,
5143 };
5144 use netstack3_ip::testutil::DualStackSendIpPacketMeta;
5145 use packet::{Buf, NestableSerializer as _};
5146 use packet_formats::ip::{Ipv4Proto, Ipv6Proto};
5147 use test_case::test_case;
5148
5149 use super::*;
5150 use crate::internal::spec_context;
5151
5152 trait DatagramIpExt<D: FakeStrongDeviceId>:
5153 IpExt + IpDeviceStateIpExt + TestIpExt + DualStackIpExt + DualStackContextsIpExt<D>
5154 {
5155 }
5156 impl<
5157 D: FakeStrongDeviceId,
5158 I: Ip + IpExt + IpDeviceStateIpExt + TestIpExt + DualStackIpExt + DualStackContextsIpExt<D>,
5159 > DatagramIpExt<D> for I
5160 {
5161 }
5162
5163 #[derive(Debug)]
5164 enum FakeAddrSpec {}
5165
5166 impl SocketMapAddrSpec for FakeAddrSpec {
5167 type LocalIdentifier = NonZeroU16;
5168 type RemoteIdentifier = u16;
5169 }
5170
5171 #[derive(Debug)]
5172 enum FakeStateSpec {}
5173
5174 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
5175 struct Tag;
5176
5177 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
5178
5179 enum Sharing {
5180 #[default]
5181 NoConflicts,
5182 ConnectionConflicts {
5185 remote_port: u16,
5186 },
5187 }
5188
5189 #[derive(Clone, Debug, Derivative)]
5190 #[derivative(Eq(bound = ""), PartialEq(bound = ""))]
5191 struct Id<I: IpExt, D: WeakDeviceIdentifier>(StrongRc<I, D, FakeStateSpec>);
5192
5193 impl<I: IpExt, D: WeakDeviceIdentifier> Id<I, D> {
5195 fn get(&self) -> impl Deref<Target = SocketState<I, D, FakeStateSpec>> + '_ {
5196 let Self(rc) = self;
5197 rc.state.read()
5198 }
5199
5200 fn get_mut(&self) -> impl DerefMut<Target = SocketState<I, D, FakeStateSpec>> + '_ {
5201 let Self(rc) = self;
5202 rc.state.write()
5203 }
5204 }
5205
5206 impl<I: IpExt, D: WeakDeviceIdentifier> From<StrongRc<I, D, FakeStateSpec>> for Id<I, D> {
5207 fn from(value: StrongRc<I, D, FakeStateSpec>) -> Self {
5208 Self(value)
5209 }
5210 }
5211
5212 impl<I: IpExt, D: WeakDeviceIdentifier> Borrow<StrongRc<I, D, FakeStateSpec>> for Id<I, D> {
5213 fn borrow(&self) -> &StrongRc<I, D, FakeStateSpec> {
5214 let Self(rc) = self;
5215 rc
5216 }
5217 }
5218
5219 #[derive(Debug)]
5220 struct AddrState<T>(T);
5221
5222 struct FakeSocketMapStateSpec<I, D>(PhantomData<(I, D)>, !);
5223
5224 impl<I: IpExt, D: WeakDeviceIdentifier> SocketMapStateSpec for FakeSocketMapStateSpec<I, D> {
5225 type AddrVecTag = Tag;
5226 type ConnAddrState = AddrState<Self::ConnId>;
5227 type ConnId = I::DualStackBoundSocketId<D, FakeStateSpec>;
5228 type ConnSharingState = Sharing;
5229 type ListenerAddrState = AddrState<Self::ListenerId>;
5230 type ListenerId = I::DualStackBoundSocketId<D, FakeStateSpec>;
5231 type ListenerSharingState = Sharing;
5232 fn listener_tag(_: ListenerAddrInfo, _state: &Self::ListenerAddrState) -> Self::AddrVecTag {
5233 Tag
5234 }
5235 fn connected_tag(_has_device: bool, _state: &Self::ConnAddrState) -> Self::AddrVecTag {
5236 Tag
5237 }
5238 }
5239
5240 const FAKE_DATAGRAM_IPV4_PROTOCOL: Ipv4Proto = Ipv4Proto::Other(253);
5241 const FAKE_DATAGRAM_IPV6_PROTOCOL: Ipv6Proto = Ipv6Proto::Other(254);
5242
5243 impl DatagramSocketSpec for FakeStateSpec {
5244 const NAME: &'static str = "FAKE";
5245 type AddrSpec = FakeAddrSpec;
5246 type SocketId<I: IpExt, D: WeakDeviceIdentifier> = Id<I, D>;
5247 type WeakSocketId<I: IpExt, D: WeakDeviceIdentifier> = Id<I, D>;
5250 type OtherStackIpOptions<I: IpExt, D: WeakDeviceIdentifier> =
5251 DatagramIpSpecificSocketOptions<I::OtherVersion, D>;
5252 type SocketMapSpec<I: IpExt, D: WeakDeviceIdentifier> = FakeSocketMapStateSpec<I, D>;
5253 type SharingState = Sharing;
5254 type ListenerIpAddr<I: IpExt> =
5255 I::DualStackListenerIpAddr<<FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier>;
5256 type ConnIpAddr<I: IpExt> = I::DualStackConnIpAddr<Self>;
5257 type ConnStateExtra = ();
5258 type ConnState<I: IpExt, D: WeakDeviceIdentifier> = I::DualStackConnState<D, Self>;
5259 type Counters<I: Ip> = ();
5260 type ExternalData<I: Ip> = ();
5261 type SendToken = FakeSendToken;
5262
5263 fn ip_proto<I: IpProtoExt>() -> I::Proto {
5264 I::map_ip((), |()| FAKE_DATAGRAM_IPV4_PROTOCOL, |()| FAKE_DATAGRAM_IPV6_PROTOCOL)
5265 }
5266
5267 fn make_bound_socket_map_id<I: IpExt, D: WeakDeviceIdentifier>(
5268 s: &Self::SocketId<I, D>,
5269 ) -> <Self::SocketMapSpec<I, D> as DatagramSocketMapSpec<I, D, Self::AddrSpec>>::BoundSocketId
5270 {
5271 I::into_dual_stack_bound_socket_id(s.clone())
5272 }
5273
5274 type Serializer<I: IpExt, B: BufferMut> = packet::Nested<B, ()>;
5275 type SerializeError = !;
5276 fn make_packet<I: IpExt, B: BufferMut>(
5277 body: B,
5278 _addr: &ConnIpAddr<
5279 I::Addr,
5280 <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier,
5281 <FakeAddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
5282 >,
5283 ) -> Result<Self::Serializer<I, B>, !> {
5284 Ok(body.wrap_in(()))
5285 }
5286 fn try_alloc_listen_identifier<I: Ip, D: WeakDeviceIdentifier>(
5287 _bindings_ctx: &mut impl RngContext,
5288 is_available: impl Fn(
5289 <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier,
5290 ) -> Result<(), InUseError>,
5291 ) -> Option<<FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier> {
5292 (1..=u16::MAX).map(|i| NonZeroU16::new(i).unwrap()).find(|i| is_available(*i).is_ok())
5293 }
5294
5295 fn conn_info_from_state<I: IpExt, D: WeakDeviceIdentifier>(
5296 state: &Self::ConnState<I, D>,
5297 ) -> ConnInfo<I::Addr, D> {
5298 let ConnAddr { ip, device } = I::conn_addr_from_state(state);
5299 let ConnInfoAddr { local: (local_ip, local_port), remote: (remote_ip, remote_port) } =
5300 ip.into();
5301 ConnInfo::new(local_ip, local_port, remote_ip, remote_port, || {
5302 device.clone().expect("device must be bound for addresses that require zones")
5303 })
5304 }
5305
5306 fn try_alloc_local_id<I: IpExt, D: WeakDeviceIdentifier, BC: RngContext>(
5307 bound: &BoundSocketMap<I, D, FakeAddrSpec, FakeSocketMapStateSpec<I, D>>,
5308 _bindings_ctx: &mut BC,
5309 _flow: DatagramFlowId<I::Addr, <FakeAddrSpec as SocketMapAddrSpec>::RemoteIdentifier>,
5310 ) -> Option<<FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier> {
5311 (1..u16::MAX).find_map(|identifier| {
5312 let identifier = NonZeroU16::new(identifier).unwrap();
5313 bound
5314 .listeners()
5315 .could_insert(
5316 &ListenerAddr {
5317 device: None,
5318 ip: ListenerIpAddr { addr: None, identifier },
5319 },
5320 &Default::default(),
5321 )
5322 .is_ok()
5323 .then_some(identifier)
5324 })
5325 }
5326
5327 fn upgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
5328 id: &Self::WeakSocketId<I, D>,
5329 ) -> Option<Self::SocketId<I, D>> {
5330 Some(id.clone())
5331 }
5332
5333 fn downgrade_socket_id<I: IpExt, D: WeakDeviceIdentifier>(
5334 id: &Self::SocketId<I, D>,
5335 ) -> Self::WeakSocketId<I, D> {
5336 id.clone()
5337 }
5338 }
5339
5340 impl<I: IpExt, D: WeakDeviceIdentifier> DatagramSocketMapSpec<I, D, FakeAddrSpec>
5341 for FakeSocketMapStateSpec<I, D>
5342 {
5343 type BoundSocketId = I::DualStackBoundSocketId<D, FakeStateSpec>;
5344 }
5345
5346 impl<I: IpExt, D: WeakDeviceIdentifier>
5347 SocketMapConflictPolicy<
5348 ConnAddr<
5349 ConnIpAddr<
5350 I::Addr,
5351 <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier,
5352 <FakeAddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
5353 >,
5354 D,
5355 >,
5356 Sharing,
5357 I,
5358 D,
5359 FakeAddrSpec,
5360 > for FakeSocketMapStateSpec<I, D>
5361 {
5362 fn check_insert_conflicts(
5363 sharing: &Sharing,
5364 addr: &ConnAddr<
5365 ConnIpAddr<
5366 I::Addr,
5367 <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier,
5368 <FakeAddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
5369 >,
5370 D,
5371 >,
5372 _socketmap: &SocketMap<AddrVec<I, D, FakeAddrSpec>, Bound<Self>>,
5373 ) -> Result<(), InsertError> {
5374 let ConnAddr { ip: ConnIpAddr { local: _, remote: (_remote_ip, port) }, device: _ } =
5375 addr;
5376 match sharing {
5377 Sharing::NoConflicts => Ok(()),
5378 Sharing::ConnectionConflicts { remote_port } => {
5379 if remote_port == port {
5380 Err(InsertError::Exists)
5381 } else {
5382 Ok(())
5383 }
5384 }
5385 }
5386 }
5387 }
5388
5389 impl<I: IpExt, D: WeakDeviceIdentifier>
5390 SocketMapConflictPolicy<
5391 ListenerAddr<
5392 ListenerIpAddr<I::Addr, <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
5393 D,
5394 >,
5395 Sharing,
5396 I,
5397 D,
5398 FakeAddrSpec,
5399 > for FakeSocketMapStateSpec<I, D>
5400 {
5401 fn check_insert_conflicts(
5402 sharing: &Sharing,
5403 _addr: &ListenerAddr<
5404 ListenerIpAddr<I::Addr, <FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier>,
5405 D,
5406 >,
5407 _socketmap: &SocketMap<AddrVec<I, D, FakeAddrSpec>, Bound<Self>>,
5408 ) -> Result<(), InsertError> {
5409 match sharing {
5410 Sharing::NoConflicts => Ok(()),
5411 Sharing::ConnectionConflicts { remote_port: _ } => Ok(()),
5414 }
5415 }
5416 }
5417
5418 impl<T: Eq> SocketMapAddrStateSpec for AddrState<T> {
5419 type Id = T;
5420 type SharingState = Sharing;
5421 type Inserter<'a>
5422 = !
5423 where
5424 Self: 'a;
5425
5426 fn new(_sharing: &Self::SharingState, id: Self::Id) -> Self {
5427 AddrState(id)
5428 }
5429 fn contains_id(&self, id: &Self::Id) -> bool {
5430 let Self(inner) = self;
5431 inner == id
5432 }
5433 fn try_get_inserter<'a, 'b>(
5434 &'b mut self,
5435 _new_sharing_state: &'a Self::SharingState,
5436 ) -> Result<Self::Inserter<'b>, IncompatibleError> {
5437 Err(IncompatibleError)
5438 }
5439 fn could_insert(
5440 &self,
5441 _new_sharing_state: &Self::SharingState,
5442 ) -> Result<(), IncompatibleError> {
5443 Err(IncompatibleError)
5444 }
5445 fn remove_by_id(&mut self, _id: Self::Id) -> RemoveResult {
5446 RemoveResult::IsLast
5447 }
5448 fn sharing_state(&self) -> Self::SharingState {
5449 Sharing::NoConflicts
5450 }
5451 }
5452
5453 #[derive(Derivative, GenericOverIp)]
5454 #[derivative(Default(bound = ""))]
5455 #[generic_over_ip()]
5456 struct FakeBoundSockets<D: FakeStrongDeviceId> {
5457 v4: BoundDatagramSocketMap<Ipv4, FakeWeakDeviceId<D>, FakeStateSpec>,
5458 v6: BoundDatagramSocketMap<Ipv6, FakeWeakDeviceId<D>, FakeStateSpec>,
5459 }
5460
5461 impl<D: FakeStrongDeviceId, I: IpExt>
5462 AsRef<
5463 BoundSocketMap<
5464 I,
5465 FakeWeakDeviceId<D>,
5466 FakeAddrSpec,
5467 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5468 >,
5469 > for FakeBoundSockets<D>
5470 {
5471 fn as_ref(
5472 &self,
5473 ) -> &BoundSocketMap<
5474 I,
5475 FakeWeakDeviceId<D>,
5476 FakeAddrSpec,
5477 FakeSocketMapStateSpec<I, FakeWeakDeviceId<D>>,
5478 > {
5479 #[derive(GenericOverIp)]
5480 #[generic_over_ip(I, Ip)]
5481 struct Wrap<'a, I: IpExt, D: FakeStrongDeviceId>(
5482 &'a BoundDatagramSocketMap<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5483 );
5484 let Wrap(state) = I::map_ip(self, |state| Wrap(&state.v4), |state| Wrap(&state.v6));
5485 state
5486 }
5487 }
5488
5489 impl<D: FakeStrongDeviceId, I: IpExt>
5490 AsMut<BoundDatagramSocketMap<I, FakeWeakDeviceId<D>, FakeStateSpec>>
5491 for FakeBoundSockets<D>
5492 {
5493 fn as_mut(&mut self) -> &mut BoundDatagramSocketMap<I, FakeWeakDeviceId<D>, FakeStateSpec> {
5494 #[derive(GenericOverIp)]
5495 #[generic_over_ip(I, Ip)]
5496 struct Wrap<'a, I: IpExt, D: FakeStrongDeviceId>(
5497 &'a mut BoundDatagramSocketMap<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5498 );
5499 let Wrap(state) =
5500 I::map_ip(self, |state| Wrap(&mut state.v4), |state| Wrap(&mut state.v6));
5501 state
5502 }
5503 }
5504
5505 type FakeBindingsCtx = netstack3_base::testutil::FakeBindingsCtx<(), (), (), ()>;
5506 type FakeCtx<I, D> = CtxPair<FakeCoreCtx<I, D>, FakeBindingsCtx>;
5507
5508 type FakeSocketSet<I, D> = DatagramSocketSet<I, FakeWeakDeviceId<D>, FakeStateSpec>;
5509
5510 type InnerIpSocketCtx<D> = netstack3_base::testutil::FakeCoreCtx<
5511 FakeDualStackIpSocketCtx<D>,
5512 DualStackSendIpPacketMeta<D>,
5513 D,
5514 >;
5515
5516 trait DatagramApiExt: ContextPair + Sized {
5518 fn datagram_api<I: Ip>(&mut self) -> DatagramApi<I, &mut Self, FakeStateSpec> {
5519 DatagramApi::new(self)
5520 }
5521 }
5522
5523 impl<O> DatagramApiExt for O where O: ContextPair + Sized {}
5524
5525 struct FakeDualStackCoreCtx<D: FakeStrongDeviceId> {
5526 bound_sockets: FakeBoundSockets<D>,
5527 ip_socket_ctx: InnerIpSocketCtx<D>,
5528 }
5529
5530 struct FakeCoreCtx<I: IpExt, D: FakeStrongDeviceId> {
5531 dual_stack: FakeDualStackCoreCtx<D>,
5532 socket_set: FakeSocketSet<I, D>,
5535 }
5536
5537 impl<I: IpExt, D: FakeStrongDeviceId> ContextProvider for FakeCoreCtx<I, D> {
5538 type Context = Self;
5539 fn context(&mut self) -> &mut Self::Context {
5540 self
5541 }
5542 }
5543
5544 impl<I: IpExt, D: FakeStrongDeviceId> FakeCoreCtx<I, D> {
5545 fn new() -> Self {
5546 Self::new_with_sockets(Default::default(), Default::default())
5547 }
5548
5549 fn new_with_sockets(
5550 socket_set: FakeSocketSet<I, D>,
5551 bound_sockets: FakeBoundSockets<D>,
5552 ) -> Self {
5553 Self {
5554 socket_set,
5555 dual_stack: FakeDualStackCoreCtx {
5556 bound_sockets,
5557 ip_socket_ctx: Default::default(),
5558 },
5559 }
5560 }
5561
5562 fn new_with_ip_socket_ctx(ip_socket_ctx: FakeDualStackIpSocketCtx<D>) -> Self {
5563 Self {
5564 socket_set: Default::default(),
5565 dual_stack: FakeDualStackCoreCtx {
5566 bound_sockets: Default::default(),
5567 ip_socket_ctx: InnerIpSocketCtx::with_state(ip_socket_ctx),
5568 },
5569 }
5570 }
5571 }
5572
5573 impl<I: IpExt, D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeCoreCtx<I, D> {
5574 type DeviceId = D;
5575 type WeakDeviceId = FakeWeakDeviceId<D>;
5576 }
5577
5578 impl<D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeDualStackCoreCtx<D> {
5579 type DeviceId = D;
5580 type WeakDeviceId = FakeWeakDeviceId<D>;
5581 }
5582
5583 impl<D: FakeStrongDeviceId, I: DatagramIpExt<D>>
5584 spec_context::DatagramSpecStateContext<I, FakeCoreCtx<I, D>, FakeBindingsCtx>
5585 for FakeStateSpec
5586 {
5587 type SocketsStateCtx<'a> = FakeDualStackCoreCtx<D>;
5588
5589 fn with_all_sockets_mut<
5590 O,
5591 F: FnOnce(&mut DatagramSocketSet<I, FakeWeakDeviceId<D>, FakeStateSpec>) -> O,
5592 >(
5593 core_ctx: &mut FakeCoreCtx<I, D>,
5594 cb: F,
5595 ) -> O {
5596 cb(&mut core_ctx.socket_set)
5597 }
5598
5599 fn with_all_sockets<
5600 O,
5601 F: FnOnce(&DatagramSocketSet<I, FakeWeakDeviceId<D>, FakeStateSpec>) -> O,
5602 >(
5603 core_ctx: &mut FakeCoreCtx<I, D>,
5604 cb: F,
5605 ) -> O {
5606 cb(&core_ctx.socket_set)
5607 }
5608
5609 fn with_socket_state<
5610 O,
5611 F: FnOnce(
5612 &mut Self::SocketsStateCtx<'_>,
5613 &SocketState<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5614 ) -> O,
5615 >(
5616 core_ctx: &mut FakeCoreCtx<I, D>,
5617 id: &Id<I, FakeWeakDeviceId<D>>,
5618 cb: F,
5619 ) -> O {
5620 cb(&mut core_ctx.dual_stack, &id.get())
5621 }
5622
5623 fn with_socket_state_mut<
5624 O,
5625 F: FnOnce(
5626 &mut Self::SocketsStateCtx<'_>,
5627 &mut SocketState<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5628 ) -> O,
5629 >(
5630 core_ctx: &mut FakeCoreCtx<I, D>,
5631 id: &Id<I, FakeWeakDeviceId<D>>,
5632 cb: F,
5633 ) -> O {
5634 cb(&mut core_ctx.dual_stack, &mut id.get_mut())
5635 }
5636
5637 fn for_each_socket<
5638 F: FnMut(
5639 &mut Self::SocketsStateCtx<'_>,
5640 &Id<I, FakeWeakDeviceId<D>>,
5641 &SocketState<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5642 ),
5643 >(
5644 core_ctx: &mut FakeCoreCtx<I, D>,
5645 mut cb: F,
5646 ) {
5647 core_ctx.socket_set.keys().for_each(|id| {
5648 let id = Id::from(id.clone());
5649 cb(&mut core_ctx.dual_stack, &id, &id.get());
5650 })
5651 }
5652 }
5653
5654 trait DualStackContextsIpExt<D: FakeStrongDeviceId>: IpExt {
5662 type DualStackContext: DualStackDatagramBoundStateContext<
5663 Self,
5664 FakeBindingsCtx,
5665 FakeStateSpec,
5666 DeviceId = D,
5667 WeakDeviceId = FakeWeakDeviceId<D>,
5668 >;
5669 type NonDualStackContext: NonDualStackDatagramBoundStateContext<
5670 Self,
5671 FakeBindingsCtx,
5672 FakeStateSpec,
5673 DeviceId = D,
5674 WeakDeviceId = FakeWeakDeviceId<D>,
5675 >;
5676
5677 fn dual_stack_context(
5678 core_ctx: &FakeDualStackCoreCtx<D>,
5679 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext>;
5680
5681 fn dual_stack_context_mut(
5682 core_ctx: &mut FakeDualStackCoreCtx<D>,
5683 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext>;
5684 }
5685
5686 impl<D: FakeStrongDeviceId> DualStackContextsIpExt<D> for Ipv4 {
5687 type DualStackContext = UninstantiableWrapper<FakeDualStackCoreCtx<D>>;
5688 type NonDualStackContext = FakeDualStackCoreCtx<D>;
5689
5690 fn dual_stack_context(
5691 core_ctx: &FakeDualStackCoreCtx<D>,
5692 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext> {
5693 MaybeDualStack::NotDualStack(core_ctx)
5694 }
5695
5696 fn dual_stack_context_mut(
5697 core_ctx: &mut FakeDualStackCoreCtx<D>,
5698 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
5699 MaybeDualStack::NotDualStack(core_ctx)
5700 }
5701 }
5702
5703 impl<D: FakeStrongDeviceId> DualStackContextsIpExt<D> for Ipv6 {
5704 type DualStackContext = FakeDualStackCoreCtx<D>;
5705 type NonDualStackContext = UninstantiableWrapper<FakeDualStackCoreCtx<D>>;
5706
5707 fn dual_stack_context(
5708 core_ctx: &FakeDualStackCoreCtx<D>,
5709 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext> {
5710 MaybeDualStack::DualStack(core_ctx)
5711 }
5712
5713 fn dual_stack_context_mut(
5714 core_ctx: &mut FakeDualStackCoreCtx<D>,
5715 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
5716 MaybeDualStack::DualStack(core_ctx)
5717 }
5718 }
5719
5720 impl<D: FakeStrongDeviceId, I: DualStackContextsIpExt<D>>
5721 spec_context::DatagramSpecBoundStateContext<I, FakeDualStackCoreCtx<D>, FakeBindingsCtx>
5722 for FakeStateSpec
5723 {
5724 type IpSocketsCtx<'a> = InnerIpSocketCtx<D>;
5725 type DualStackContext = I::DualStackContext;
5726 type NonDualStackContext = I::NonDualStackContext;
5727
5728 fn with_bound_sockets<O, F>(core_ctx: &mut FakeDualStackCoreCtx<D>, cb: F) -> O
5729 where
5730 F: FnOnce(
5731 &mut Self::IpSocketsCtx<'_>,
5732 &BoundDatagramSocketMap<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5733 ) -> O,
5734 {
5735 let FakeDualStackCoreCtx { bound_sockets, ip_socket_ctx } = core_ctx;
5736 cb(ip_socket_ctx, bound_sockets.as_ref())
5737 }
5738 fn with_bound_sockets_mut<O, F>(core_ctx: &mut FakeDualStackCoreCtx<D>, cb: F) -> O
5739 where
5740 F: FnOnce(
5741 &mut Self::IpSocketsCtx<'_>,
5742 &mut BoundDatagramSocketMap<I, FakeWeakDeviceId<D>, FakeStateSpec>,
5743 ) -> O,
5744 {
5745 let FakeDualStackCoreCtx { bound_sockets, ip_socket_ctx } = core_ctx;
5746 cb(ip_socket_ctx, bound_sockets.as_mut())
5747 }
5748
5749 fn with_transport_context<O, F>(core_ctx: &mut FakeDualStackCoreCtx<D>, cb: F) -> O
5750 where
5751 F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O,
5752 {
5753 cb(&mut core_ctx.ip_socket_ctx)
5754 }
5755
5756 fn dual_stack_context(
5757 core_ctx: &FakeDualStackCoreCtx<D>,
5758 ) -> MaybeDualStack<&Self::DualStackContext, &Self::NonDualStackContext> {
5759 I::dual_stack_context(core_ctx)
5760 }
5761
5762 fn dual_stack_context_mut(
5763 core_ctx: &mut FakeDualStackCoreCtx<D>,
5764 ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
5765 I::dual_stack_context_mut(core_ctx)
5766 }
5767 }
5768
5769 impl<D: FakeStrongDeviceId>
5770 spec_context::NonDualStackDatagramSpecBoundStateContext<
5771 Ipv4,
5772 FakeDualStackCoreCtx<D>,
5773 FakeBindingsCtx,
5774 > for FakeStateSpec
5775 {
5776 fn nds_converter(
5777 _core_ctx: &FakeDualStackCoreCtx<D>,
5778 ) -> impl NonDualStackConverter<Ipv4, FakeWeakDeviceId<D>, Self> {
5779 ()
5780 }
5781 }
5782
5783 impl<D: FakeStrongDeviceId>
5784 spec_context::DualStackDatagramSpecBoundStateContext<
5785 Ipv6,
5786 FakeDualStackCoreCtx<D>,
5787 FakeBindingsCtx,
5788 > for FakeStateSpec
5789 {
5790 type IpSocketsCtx<'a> = InnerIpSocketCtx<D>;
5791 fn dual_stack_enabled(
5792 _core_ctx: &FakeDualStackCoreCtx<D>,
5793 _ip_options: &IpOptions<Ipv6, FakeWeakDeviceId<D>, FakeStateSpec>,
5794 ) -> bool {
5795 true
5799 }
5800
5801 fn to_other_socket_options<'a>(
5802 _core_ctx: &FakeDualStackCoreCtx<D>,
5803 state: &'a IpOptions<Ipv6, FakeWeakDeviceId<D>, FakeStateSpec>,
5804 ) -> &'a DatagramIpSpecificSocketOptions<Ipv4, FakeWeakDeviceId<D>> {
5805 let IpOptions { other_stack, .. } = state;
5806 other_stack
5807 }
5808
5809 fn ds_converter(
5810 _core_ctx: &FakeDualStackCoreCtx<D>,
5811 ) -> impl DualStackConverter<Ipv6, FakeWeakDeviceId<D>, Self> {
5812 ()
5813 }
5814
5815 fn to_other_bound_socket_id(
5816 _core_ctx: &FakeDualStackCoreCtx<D>,
5817 id: &Id<Ipv6, D::Weak>,
5818 ) -> EitherIpSocket<D::Weak, FakeStateSpec> {
5819 EitherIpSocket::V6(id.clone())
5820 }
5821
5822 fn with_both_bound_sockets_mut<
5823 O,
5824 F: FnOnce(
5825 &mut Self::IpSocketsCtx<'_>,
5826 &mut BoundSocketsFromSpec<Ipv6, FakeDualStackCoreCtx<D>, FakeStateSpec>,
5827 &mut BoundSocketsFromSpec<Ipv4, FakeDualStackCoreCtx<D>, FakeStateSpec>,
5828 ) -> O,
5829 >(
5830 core_ctx: &mut FakeDualStackCoreCtx<D>,
5831 cb: F,
5832 ) -> O {
5833 let FakeDualStackCoreCtx { bound_sockets: FakeBoundSockets { v4, v6 }, ip_socket_ctx } =
5834 core_ctx;
5835 cb(ip_socket_ctx, v6, v4)
5836 }
5837
5838 fn with_other_bound_sockets_mut<
5839 O,
5840 F: FnOnce(
5841 &mut Self::IpSocketsCtx<'_>,
5842 &mut BoundSocketsFromSpec<Ipv4, FakeDualStackCoreCtx<D>, FakeStateSpec>,
5843 ) -> O,
5844 >(
5845 core_ctx: &mut FakeDualStackCoreCtx<D>,
5846 cb: F,
5847 ) -> O {
5848 let FakeDualStackCoreCtx { bound_sockets, ip_socket_ctx } = core_ctx;
5849 cb(ip_socket_ctx, bound_sockets.as_mut())
5850 }
5851
5852 fn with_transport_context<O, F: FnOnce(&mut Self::IpSocketsCtx<'_>) -> O>(
5853 core_ctx: &mut FakeDualStackCoreCtx<D>,
5854 cb: F,
5855 ) -> O {
5856 cb(&mut core_ctx.ip_socket_ctx)
5857 }
5858 }
5859
5860 #[ip_test(I)]
5861 fn set_get_hop_limits<I: DatagramIpExt<FakeDeviceId>>() {
5862 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, FakeDeviceId>::new());
5863 let mut api = ctx.datagram_api::<I>();
5864
5865 let unbound = api.create_default();
5866 const EXPECTED_HOP_LIMITS: HopLimits = HopLimits {
5867 unicast: NonZeroU8::new(45).unwrap(),
5868 multicast: NonZeroU8::new(23).unwrap(),
5869 };
5870
5871 api.update_ip_hop_limit(&unbound, |limits| {
5872 *limits = SocketHopLimits {
5873 unicast: Some(EXPECTED_HOP_LIMITS.unicast),
5874 multicast: Some(EXPECTED_HOP_LIMITS.multicast),
5875 version: IpVersionMarker::default(),
5876 }
5877 });
5878
5879 assert_eq!(api.get_ip_hop_limits(&unbound), EXPECTED_HOP_LIMITS);
5880 }
5881
5882 #[ip_test(I)]
5883 fn set_get_device_hop_limits<I: DatagramIpExt<FakeReferencyDeviceId>>() {
5884 let device = FakeReferencyDeviceId::default();
5885 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(
5886 FakeDualStackIpSocketCtx::new([FakeDeviceConfig::<_, SpecifiedAddr<I::Addr>> {
5887 device: device.clone(),
5888 local_ips: Default::default(),
5889 remote_ips: Default::default(),
5890 }]),
5891 ));
5892 let mut api = ctx.datagram_api::<I>();
5893
5894 let unbound = api.create_default();
5895 api.set_device(&unbound, Some(&device)).unwrap();
5896
5897 let HopLimits { mut unicast, multicast } = DEFAULT_HOP_LIMITS;
5898 unicast = unicast.checked_add(1).unwrap();
5899 {
5900 let device_state =
5901 api.core_ctx().dual_stack.ip_socket_ctx.state.get_device_state_mut::<I>(&device);
5902 assert_ne!(device_state.default_hop_limit, unicast);
5903 device_state.default_hop_limit = unicast;
5904 }
5905 assert_eq!(api.get_ip_hop_limits(&unbound), HopLimits { unicast, multicast });
5906
5907 device.mark_removed();
5909 assert_eq!(api.get_ip_hop_limits(&unbound), DEFAULT_HOP_LIMITS);
5910 }
5911
5912 #[ip_test(I)]
5913 fn default_hop_limits<I: DatagramIpExt<FakeDeviceId>>() {
5914 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, FakeDeviceId>::new());
5915 let mut api = ctx.datagram_api::<I>();
5916 let unbound = api.create_default();
5917 assert_eq!(api.get_ip_hop_limits(&unbound), DEFAULT_HOP_LIMITS);
5918
5919 api.update_ip_hop_limit(&unbound, |limits| {
5920 *limits = SocketHopLimits {
5921 unicast: Some(NonZeroU8::new(1).unwrap()),
5922 multicast: Some(NonZeroU8::new(1).unwrap()),
5923 version: IpVersionMarker::default(),
5924 }
5925 });
5926
5927 assert_ne!(api.get_ip_hop_limits(&unbound), DEFAULT_HOP_LIMITS);
5929
5930 api.update_ip_hop_limit(&unbound, |limits| *limits = Default::default());
5932
5933 assert_eq!(api.get_ip_hop_limits(&unbound), DEFAULT_HOP_LIMITS);
5935 }
5936
5937 #[ip_test(I)]
5938 fn bind_device_unbound<I: DatagramIpExt<FakeDeviceId>>() {
5939 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, FakeDeviceId>::new());
5940 let mut api = ctx.datagram_api::<I>();
5941 let unbound = api.create_default();
5942
5943 api.set_device(&unbound, Some(&FakeDeviceId)).unwrap();
5944 assert_eq!(api.get_bound_device(&unbound), Some(FakeWeakDeviceId(FakeDeviceId)));
5945
5946 api.set_device(&unbound, None).unwrap();
5947 assert_eq!(api.get_bound_device(&unbound), None);
5948 }
5949
5950 #[ip_test(I)]
5951 fn send_to_binds_unbound<I: DatagramIpExt<FakeDeviceId>>() {
5952 let mut ctx =
5953 FakeCtx::with_core_ctx(FakeCoreCtx::<I, FakeDeviceId>::new_with_ip_socket_ctx(
5954 FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
5955 device: FakeDeviceId,
5956 local_ips: vec![I::TEST_ADDRS.local_ip],
5957 remote_ips: vec![I::TEST_ADDRS.remote_ip],
5958 }]),
5959 ));
5960 let mut api = ctx.datagram_api::<I>();
5961 let socket = api.create_default();
5962 let body = Buf::new(Vec::new(), ..);
5963
5964 api.send_to(
5965 &socket,
5966 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
5967 1234,
5968 body,
5969 FakeSendToken::default(),
5970 )
5971 .expect("succeeds");
5972 assert_matches!(api.get_info(&socket), SocketInfo::Listener(_));
5973 }
5974
5975 #[ip_test(I)]
5976 fn send_to_no_route_still_binds<I: DatagramIpExt<FakeDeviceId>>() {
5977 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(
5978 FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
5979 device: FakeDeviceId,
5980 local_ips: vec![I::TEST_ADDRS.local_ip],
5981 remote_ips: vec![],
5982 }]),
5983 ));
5984 let mut api = ctx.datagram_api::<I>();
5985 let socket = api.create_default();
5986 let body = Buf::new(Vec::new(), ..);
5987
5988 assert_matches!(
5989 api.send_to(
5990 &socket,
5991 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
5992 1234,
5993 body,
5994 FakeSendToken::default(),
5995 ),
5996 Err(SendToError::CreateAndSend(_))
5997 );
5998 assert_matches!(api.get_info(&socket), SocketInfo::Listener(_));
5999 }
6000
6001 #[ip_test(I)]
6002 #[test_case(true; "remove device b")]
6003 #[test_case(false; "dont remove device b")]
6004 fn multicast_membership_changes<I: DatagramIpExt<FakeReferencyDeviceId> + TestIpExt>(
6005 remove_device_b: bool,
6006 ) {
6007 let device_a = FakeReferencyDeviceId::default();
6008 let device_b = FakeReferencyDeviceId::default();
6009 let mut core_ctx = FakeIpSocketCtx::<I, FakeReferencyDeviceId>::new(
6010 [device_a.clone(), device_b.clone()].into_iter().map(|device| FakeDeviceConfig {
6011 device,
6012 local_ips: Default::default(),
6013 remote_ips: Default::default(),
6014 }),
6015 );
6016 let mut bindings_ctx = FakeBindingsCtx::default();
6017
6018 let multicast_addr1 = I::get_multicast_addr(1);
6019 let mut memberships = MulticastMemberships::default();
6020 assert_eq!(
6021 memberships.apply_membership_change(
6022 multicast_addr1,
6023 &FakeWeakDeviceId(device_a.clone()),
6024 true ),
6026 Some(MulticastMembershipChange::Join),
6027 );
6028 core_ctx.join_multicast_group(&mut bindings_ctx, &device_a, multicast_addr1);
6029
6030 let multicast_addr2 = I::get_multicast_addr(2);
6031 assert_eq!(
6032 memberships.apply_membership_change(
6033 multicast_addr2,
6034 &FakeWeakDeviceId(device_b.clone()),
6035 true ),
6037 Some(MulticastMembershipChange::Join),
6038 );
6039 core_ctx.join_multicast_group(&mut bindings_ctx, &device_b, multicast_addr2);
6040
6041 for (device, addr, expected) in [
6042 (&device_a, multicast_addr1, true),
6043 (&device_a, multicast_addr2, false),
6044 (&device_b, multicast_addr1, false),
6045 (&device_b, multicast_addr2, true),
6046 ] {
6047 assert_eq!(
6048 core_ctx.get_device_state(device).is_in_multicast_group(&addr),
6049 expected,
6050 "device={:?}, addr={}",
6051 device,
6052 addr,
6053 );
6054 }
6055
6056 if remove_device_b {
6057 device_b.mark_removed();
6058 }
6059
6060 leave_all_joined_groups(&mut core_ctx, &mut bindings_ctx, &memberships);
6061 for (device, addr, expected) in [
6062 (&device_a, multicast_addr1, false),
6063 (&device_a, multicast_addr2, false),
6064 (&device_b, multicast_addr1, false),
6065 (&device_b, multicast_addr2, remove_device_b),
6070 ] {
6071 assert_eq!(
6072 core_ctx.get_device_state(device).is_in_multicast_group(&addr),
6073 expected,
6074 "device={:?}, addr={}",
6075 device,
6076 addr,
6077 );
6078 }
6079 }
6080
6081 #[ip_test(I)]
6082 fn set_get_transparent<I: DatagramIpExt<FakeDeviceId>>() {
6083 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(
6084 FakeDualStackIpSocketCtx::new([FakeDeviceConfig::<_, SpecifiedAddr<I::Addr>> {
6085 device: FakeDeviceId,
6086 local_ips: Default::default(),
6087 remote_ips: Default::default(),
6088 }]),
6089 ));
6090 let mut api = ctx.datagram_api::<I>();
6091 let unbound = api.create_default();
6092
6093 assert!(!api.get_ip_transparent(&unbound));
6094
6095 api.set_ip_transparent(&unbound, true);
6096
6097 assert!(api.get_ip_transparent(&unbound));
6098
6099 api.set_ip_transparent(&unbound, false);
6100
6101 assert!(!api.get_ip_transparent(&unbound));
6102 }
6103
6104 #[ip_test(I)]
6105 fn transparent_bind_connect_non_local_src_addr<I: DatagramIpExt<FakeDeviceId>>() {
6106 let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(
6107 FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
6108 device: FakeDeviceId,
6109 local_ips: vec![],
6110 remote_ips: vec![I::TEST_ADDRS.remote_ip],
6111 }]),
6112 ));
6113 let mut api = ctx.datagram_api::<I>();
6114 let socket = api.create_default();
6115 api.set_ip_transparent(&socket, true);
6116
6117 const LOCAL_PORT: NonZeroU16 = NonZeroU16::new(10).unwrap();
6118 const REMOTE_PORT: u16 = 1234;
6119
6120 api.listen(&socket, Some(ZonedAddr::Unzoned(I::TEST_ADDRS.local_ip)), Some(LOCAL_PORT))
6123 .expect("listen should succeed");
6124
6125 api.connect(
6128 &socket,
6129 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
6130 REMOTE_PORT,
6131 Default::default(),
6132 )
6133 .expect("connect should succeed");
6134
6135 api.send_to(
6136 &socket,
6137 Some(ZonedAddr::Unzoned(I::TEST_ADDRS.remote_ip)),
6138 REMOTE_PORT,
6139 Buf::new(Vec::new(), ..),
6140 FakeSendToken::default(),
6141 )
6142 .expect("send_to should succeed");
6143 }
6144
6145 #[derive(Eq, PartialEq)]
6146 enum OriginalSocketState {
6147 Unbound,
6148 Listener,
6149 Connected,
6150 }
6151
6152 #[ip_test(I)]
6153 #[test_case(OriginalSocketState::Unbound; "reinsert_unbound")]
6154 #[test_case(OriginalSocketState::Listener; "reinsert_listener")]
6155 #[test_case(OriginalSocketState::Connected; "reinsert_connected")]
6156 fn connect_reinserts_on_failure_single_stack<I: DatagramIpExt<FakeDeviceId>>(
6157 original: OriginalSocketState,
6158 ) {
6159 connect_reinserts_on_failure_inner::<I>(
6160 original,
6161 I::TEST_ADDRS.local_ip.get(),
6162 I::TEST_ADDRS.remote_ip,
6163 );
6164 }
6165
6166 #[test_case(OriginalSocketState::Listener, net_ip_v6!("::FFFF:192.0.2.1"),
6167 net_ip_v4!("192.0.2.2"); "reinsert_listener_other_stack")]
6168 #[test_case(OriginalSocketState::Listener, net_ip_v6!("::"),
6169 net_ip_v4!("192.0.2.2"); "reinsert_listener_both_stacks")]
6170 #[test_case(OriginalSocketState::Connected, net_ip_v6!("::FFFF:192.0.2.1"),
6171 net_ip_v4!("192.0.2.2"); "reinsert_connected_other_stack")]
6172 fn connect_reinserts_on_failure_dual_stack(
6173 original: OriginalSocketState,
6174 local_ip: Ipv6Addr,
6175 remote_ip: Ipv4Addr,
6176 ) {
6177 let remote_ip = remote_ip.to_ipv6_mapped();
6178 connect_reinserts_on_failure_inner::<Ipv6>(original, local_ip, remote_ip);
6179 }
6180
6181 fn connect_reinserts_on_failure_inner<I: DatagramIpExt<FakeDeviceId>>(
6182 original: OriginalSocketState,
6183 local_ip: I::Addr,
6184 remote_ip: SpecifiedAddr<I::Addr>,
6185 ) {
6186 let mut ctx = testutil::setup_fake_ctx_with_dualstack_conn_addrs::<_, FakeBindingsCtx, _>(
6187 local_ip.to_ip_addr(),
6188 remote_ip.into(),
6189 [FakeDeviceId {}],
6190 |device_configs| {
6191 FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(FakeDualStackIpSocketCtx::new(
6192 device_configs,
6193 ))
6194 },
6195 );
6196 let mut api = ctx.datagram_api::<I>();
6197 let socket = api.create_default();
6198 const LOCAL_PORT: NonZeroU16 = NonZeroU16::new(10).unwrap();
6199 const ORIGINAL_REMOTE_PORT: u16 = 1234;
6200 const NEW_REMOTE_PORT: u16 = 5678;
6201
6202 match original {
6204 OriginalSocketState::Unbound => {}
6205 OriginalSocketState::Listener => api
6206 .listen(
6207 &socket,
6208 SpecifiedAddr::new(local_ip).map(ZonedAddr::Unzoned),
6209 Some(LOCAL_PORT),
6210 )
6211 .expect("listen should succeed"),
6212 OriginalSocketState::Connected => api
6213 .connect(
6214 &socket,
6215 Some(ZonedAddr::Unzoned(remote_ip)),
6216 ORIGINAL_REMOTE_PORT,
6217 Default::default(),
6218 )
6219 .expect("connect should succeed"),
6220 }
6221
6222 api.core_ctx().with_socket_state_mut(
6224 &socket,
6225 |_core_ctx, state: &mut SocketState<I, _, FakeStateSpec>| {
6226 state.sharing = Sharing::ConnectionConflicts { remote_port: NEW_REMOTE_PORT };
6227 },
6228 );
6229
6230 assert_matches!(
6232 api.connect(
6233 &socket,
6234 Some(ZonedAddr::Unzoned(remote_ip)),
6235 NEW_REMOTE_PORT,
6236 Default::default(),
6237 ),
6238 Err(ConnectError::SockAddrConflict)
6239 );
6240
6241 let info = api.get_info(&socket);
6243 match original {
6244 OriginalSocketState::Unbound => assert_matches!(info, SocketInfo::Unbound),
6245 OriginalSocketState::Listener => {
6246 let local_port = assert_matches!(
6247 info,
6248 SocketInfo::Listener(ListenerInfo {
6249 local_ip: _,
6250 local_identifier,
6251 }) => local_identifier
6252 );
6253 assert_eq!(LOCAL_PORT, local_port);
6254 }
6255 OriginalSocketState::Connected => {
6256 let remote_port = assert_matches!(
6257 info,
6258 SocketInfo::Connected(ConnInfo {
6259 local_ip: _,
6260 local_identifier: _,
6261 remote_ip: _,
6262 remote_identifier,
6263 }) => remote_identifier
6264 );
6265 assert_eq!(ORIGINAL_REMOTE_PORT, remote_port);
6266 }
6267 }
6268 }
6269
6270 #[test_case(net_ip_v6!("::a:b:c:d"), ShutdownType::Send; "this_stack_send")]
6271 #[test_case(net_ip_v6!("::a:b:c:d"), ShutdownType::Receive; "this_stack_receive")]
6272 #[test_case(net_ip_v6!("::a:b:c:d"), ShutdownType::SendAndReceive; "this_stack_send_and_receive")]
6273 #[test_case(net_ip_v6!("::FFFF:192.0.2.1"), ShutdownType::Send; "other_stack_send")]
6274 #[test_case(net_ip_v6!("::FFFF:192.0.2.1"), ShutdownType::Receive; "other_stack_receive")]
6275 #[test_case(net_ip_v6!("::FFFF:192.0.2.1"), ShutdownType::SendAndReceive; "other_stack_send_and_receive")]
6276 fn set_get_shutdown_dualstack(remote_ip: Ipv6Addr, shutdown: ShutdownType) {
6277 let remote_ip = SpecifiedAddr::new(remote_ip).expect("remote_ip should be specified");
6278 let mut ctx = testutil::setup_fake_ctx_with_dualstack_conn_addrs::<_, FakeBindingsCtx, _>(
6279 Ipv6::UNSPECIFIED_ADDRESS.into(),
6280 remote_ip.into(),
6281 [FakeDeviceId {}],
6282 |device_configs| {
6283 FakeCoreCtx::<Ipv6, _>::new_with_ip_socket_ctx(FakeDualStackIpSocketCtx::new(
6284 device_configs,
6285 ))
6286 },
6287 );
6288 let mut api = ctx.datagram_api::<Ipv6>();
6289
6290 const REMOTE_PORT: u16 = 1234;
6291 let socket = api.create_default();
6292 api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT, Default::default())
6293 .expect("connect should succeed");
6294 assert_eq!(api.get_shutdown_connected(&socket), None);
6295
6296 api.shutdown_connected(&socket, shutdown).expect("shutdown should succeed");
6297 assert_eq!(api.get_shutdown_connected(&socket), Some(shutdown));
6298 }
6299
6300 #[ip_test(I)]
6301 #[test_case(OriginalSocketState::Unbound; "unbound")]
6302 #[test_case(OriginalSocketState::Listener; "listener")]
6303 #[test_case(OriginalSocketState::Connected; "connected")]
6304 fn set_get_device_single_stack<I: DatagramIpExt<MultipleDevicesId>>(
6305 original: OriginalSocketState,
6306 ) {
6307 set_get_device_inner::<I>(original, I::TEST_ADDRS.local_ip.get(), I::TEST_ADDRS.remote_ip);
6308 }
6309
6310 #[test_case(OriginalSocketState::Listener, net_ip_v6!("::FFFF:192.0.2.1"),
6311 net_ip_v4!("192.0.2.2"); "listener_other_stack")]
6312 #[test_case(OriginalSocketState::Listener, net_ip_v6!("::"),
6313 net_ip_v4!("192.0.2.2"); "listener_both_stacks")]
6314 #[test_case(OriginalSocketState::Connected, net_ip_v6!("::FFFF:192.0.2.1"),
6315 net_ip_v4!("192.0.2.2"); "connected_other_stack")]
6316 fn set_get_device_dual_stack(
6317 original: OriginalSocketState,
6318 local_ip: Ipv6Addr,
6319 remote_ip: Ipv4Addr,
6320 ) {
6321 let remote_ip = remote_ip.to_ipv6_mapped();
6322 set_get_device_inner::<Ipv6>(original, local_ip, remote_ip);
6323 }
6324
6325 fn set_get_device_inner<I: DatagramIpExt<MultipleDevicesId>>(
6326 original: OriginalSocketState,
6327 local_ip: I::Addr,
6328 remote_ip: SpecifiedAddr<I::Addr>,
6329 ) {
6330 const DEVICE_ID1: MultipleDevicesId = MultipleDevicesId::A;
6331 const DEVICE_ID2: MultipleDevicesId = MultipleDevicesId::B;
6332
6333 let mut ctx = testutil::setup_fake_ctx_with_dualstack_conn_addrs::<_, FakeBindingsCtx, _>(
6334 local_ip.to_ip_addr(),
6335 remote_ip.into(),
6336 [DEVICE_ID1, DEVICE_ID2],
6337 |device_configs| {
6338 FakeCoreCtx::<I, _>::new_with_ip_socket_ctx(FakeDualStackIpSocketCtx::new(
6339 device_configs,
6340 ))
6341 },
6342 );
6343
6344 const LOCAL_PORT: NonZeroU16 = NonZeroU16::new(10).unwrap();
6345 const REMOTE_PORT: u16 = 1234;
6346
6347 let mut api = ctx.datagram_api::<I>();
6348 let socket1 = api.create_default();
6349 let socket2 = api.create_default();
6350
6351 for (socket, device_id) in [(&socket1, DEVICE_ID1), (&socket2, DEVICE_ID2)] {
6354 match original {
6355 OriginalSocketState::Unbound => {}
6356 OriginalSocketState::Listener => api
6357 .listen(
6358 &socket,
6359 SpecifiedAddr::new(local_ip).map(ZonedAddr::Unzoned),
6360 Some(LOCAL_PORT),
6361 )
6362 .expect("listen should succeed"),
6363 OriginalSocketState::Connected => api
6364 .connect(
6365 &socket,
6366 Some(ZonedAddr::Unzoned(remote_ip)),
6367 REMOTE_PORT,
6368 Default::default(),
6369 )
6370 .expect("connect should succeed"),
6371 }
6372
6373 assert_eq!(api.get_bound_device(socket), None);
6374 api.set_device(socket, Some(&device_id)).expect("set device should succeed");
6375 assert_eq!(api.get_bound_device(socket), Some(FakeWeakDeviceId(device_id)));
6376 }
6377
6378 if original != OriginalSocketState::Unbound {
6382 assert_eq!(
6383 api.set_device(&socket2, Some(&DEVICE_ID1)),
6384 Err(SocketError::Local(LocalAddressError::AddressInUse))
6385 );
6386 assert_eq!(api.get_bound_device(&socket1), Some(FakeWeakDeviceId(DEVICE_ID1)));
6388 assert_eq!(api.get_bound_device(&socket2), Some(FakeWeakDeviceId(DEVICE_ID2)));
6389 }
6390
6391 api.close(socket2, |_: ReferenceState<_, _, _>| ()).into_removed();
6394 api.set_device(&socket1, None).expect("set device should succeed");
6395 assert_eq!(api.get_bound_device(&socket1), None,);
6396 }
6397}