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