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