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