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