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