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