1use alloc::vec::Vec;
8use core::fmt::Debug;
9use core::hash::Hash;
10use core::num::{NonZeroU16, NonZeroU8};
11use core::ops::{Deref, DerefMut};
12use core::time::Duration;
13
14use derivative::Derivative;
15use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
16use net_types::ip::{
17 AddrSubnet, GenericOverIp, Ip, IpAddress, IpMarked, IpVersionMarker, Ipv4, Ipv4Addr, Ipv6,
18 Ipv6Addr,
19};
20use netstack3_base::sync::{Mutex, PrimaryRc, RwLock, StrongRc, WeakRc};
21use netstack3_base::{
22 AssignedAddrIpExt, BroadcastIpExt, CoreTimerContext, ExistsError, Inspectable,
23 InspectableValue, Inspector, Instant, InstantBindingsTypes, IpAddressId,
24 NestedIntoCoreTimerCtx, NotFoundError, ReferenceNotifiers, TimerBindingsTypes, TimerContext,
25 WeakDeviceIdentifier,
26};
27use packet_formats::icmp::ndp::NonZeroNdpLifetime;
28use packet_formats::utils::NonZeroDuration;
29
30use crate::internal::device::dad::DadBindingsTypes;
31use crate::internal::device::route_discovery::Ipv6RouteDiscoveryState;
32use crate::internal::device::router_solicitation::RsState;
33use crate::internal::device::slaac::{SlaacConfiguration, SlaacState};
34use crate::internal::device::{
35 IpAddressIdSpec, IpDeviceAddr, IpDeviceTimerId, Ipv4DeviceAddr, Ipv4DeviceTimerId,
36 Ipv6DeviceAddr, Ipv6DeviceTimerId, WeakIpAddressId,
37};
38use crate::internal::gmp::igmp::{IgmpConfig, IgmpCounters, IgmpTimerId, IgmpTypeLayout};
39use crate::internal::gmp::mld::{MldConfig, MldCounters, MldTimerId, MldTypeLayout};
40use crate::internal::gmp::{GmpGroupState, GmpState, GmpTimerId, GmpTypeLayout, MulticastGroupSet};
41use crate::internal::types::RawMetric;
42
43use super::dad::NonceCollection;
44
45pub const RETRANS_TIMER_DEFAULT: NonZeroDuration = NonZeroDuration::from_secs(1).unwrap();
49
50const DEFAULT_HOP_LIMIT: NonZeroU8 = NonZeroU8::new(64).unwrap();
53
54pub trait IpDeviceStateIpExt: BroadcastIpExt {
56 type AssignedAddressState<BT: IpDeviceStateBindingsTypes>: AssignedAddressState<Address = Self::Addr>
58 + Debug;
59 type GmpProtoConfig: Default;
61 type GmpTypeLayout<BT: IpDeviceStateBindingsTypes>: GmpTypeLayout<Self, BT>;
63 type GmpTimerId<D: WeakDeviceIdentifier>: From<GmpTimerId<Self, D>>;
65}
66
67impl IpDeviceStateIpExt for Ipv4 {
68 type AssignedAddressState<BT: IpDeviceStateBindingsTypes> = Ipv4AddressEntry<BT>;
69 type GmpTimerId<D: WeakDeviceIdentifier> = IgmpTimerId<D>;
70 type GmpProtoConfig = IgmpConfig;
71 type GmpTypeLayout<BT: IpDeviceStateBindingsTypes> = IgmpTypeLayout;
72}
73
74impl IpDeviceStateIpExt for Ipv6 {
75 type AssignedAddressState<BT: IpDeviceStateBindingsTypes> = Ipv6AddressEntry<BT>;
76 type GmpTimerId<D: WeakDeviceIdentifier> = MldTimerId<D>;
77 type GmpProtoConfig = MldConfig;
78 type GmpTypeLayout<BT: IpDeviceStateBindingsTypes> = MldTypeLayout;
79}
80
81pub trait AssignedAddressState: Debug + Send + Sync + 'static {
83 type Address: IpAddress<Version: AssignedAddrIpExt>;
85
86 fn addr(&self) -> IpDeviceAddr<Self::Address>;
88
89 fn addr_sub(
91 &self,
92 ) -> AddrSubnet<
93 Self::Address,
94 <<Self::Address as IpAddress>::Version as AssignedAddrIpExt>::AssignedWitness,
95 >;
96}
97
98impl<BT: IpDeviceStateBindingsTypes> AssignedAddressState for Ipv4AddressEntry<BT> {
99 type Address = Ipv4Addr;
100
101 fn addr(&self) -> IpDeviceAddr<Ipv4Addr> {
102 IpDeviceAddr::new_from_witness(self.addr_sub().addr())
103 }
104
105 fn addr_sub(&self) -> AddrSubnet<Ipv4Addr, Ipv4DeviceAddr> {
106 *self.addr_sub()
107 }
108}
109
110impl<BT: IpDeviceStateBindingsTypes> AssignedAddressState for Ipv6AddressEntry<BT> {
111 type Address = Ipv6Addr;
112
113 fn addr(&self) -> IpDeviceAddr<Ipv6Addr> {
114 IpDeviceAddr::new_from_ipv6_device_addr(self.addr_sub().addr())
115 }
116
117 fn addr_sub(&self) -> AddrSubnet<Ipv6Addr, Ipv6DeviceAddr> {
118 *self.addr_sub()
119 }
120}
121
122pub struct PrimaryAddressId<S>(PrimaryRc<S>);
125
126impl<S: AssignedAddressState> Debug for PrimaryAddressId<S> {
127 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
128 let Self(rc) = self;
129 write!(f, "PrimaryAddressId({:?} => {})", rc.debug_id(), self.addr_sub())
130 }
131}
132
133impl<S> Deref for PrimaryAddressId<S> {
134 type Target = S;
135
136 fn deref(&self) -> &Self::Target {
137 let Self(inner) = self;
138 inner.deref()
139 }
140}
141
142impl<S> PrimaryAddressId<S> {
143 fn new_with_strong_clone(addr: S) -> (Self, AddressId<S>) {
145 let primary = PrimaryRc::new(addr);
146 let strong = PrimaryRc::clone_strong(&primary);
147 (Self(primary), AddressId(strong))
148 }
149
150 pub fn clone_strong(&self) -> AddressId<S> {
152 let Self(inner) = self;
153 AddressId(PrimaryRc::clone_strong(inner))
154 }
155
156 pub fn ptr_eq(&self, other: &AddressId<S>) -> bool {
158 let Self(inner) = self;
159 let AddressId(other) = other;
160 PrimaryRc::ptr_eq(inner, other)
161 }
162
163 pub fn into_inner(self) -> PrimaryRc<S> {
165 self.0
166 }
167}
168
169impl<S: AssignedAddressState> AssignedAddressState for PrimaryAddressId<S> {
170 type Address = S::Address;
171
172 fn addr(&self) -> IpDeviceAddr<S::Address> {
173 let Self(inner) = self;
174 inner.addr()
175 }
176
177 fn addr_sub(
178 &self,
179 ) -> AddrSubnet<
180 S::Address,
181 <<S::Address as IpAddress>::Version as AssignedAddrIpExt>::AssignedWitness,
182 > {
183 let Self(inner) = self;
184 inner.addr_sub()
185 }
186}
187
188#[derive(Derivative)]
190#[derivative(Clone(bound = ""), Eq(bound = ""), Hash(bound = ""), PartialEq(bound = ""))]
191pub struct AddressId<S>(StrongRc<S>);
192
193impl<S: AssignedAddressState> Debug for AddressId<S> {
194 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
195 let Self(rc) = self;
196 write!(f, "AddressId({:?} => {})", rc.debug_id(), self.addr_sub())
197 }
198}
199
200impl<S> Deref for AddressId<S> {
201 type Target = S;
202
203 fn deref(&self) -> &Self::Target {
204 let Self(inner) = self;
205 inner.deref()
206 }
207}
208
209impl<A, S> IpAddressId<A> for AddressId<S>
210where
211 A: IpAddress<Version: AssignedAddrIpExt>,
212 S: AssignedAddressState<Address = A>,
213{
214 type Weak = WeakAddressId<S>;
215
216 fn downgrade(&self) -> Self::Weak {
217 let Self(inner) = self;
218 WeakAddressId(StrongRc::downgrade(inner))
219 }
220
221 fn addr(&self) -> IpDeviceAddr<A> {
222 let Self(inner) = self;
223 inner.addr()
224 }
225
226 fn addr_sub(&self) -> AddrSubnet<A, <A::Version as AssignedAddrIpExt>::AssignedWitness> {
227 let Self(inner) = self;
228 inner.addr_sub()
229 }
230}
231
232#[derive(Derivative)]
234#[derivative(Clone(bound = ""), Eq(bound = ""), Hash(bound = ""), PartialEq(bound = ""))]
235pub struct WeakAddressId<S>(WeakRc<S>);
236
237impl<S: AssignedAddressState> Debug for WeakAddressId<S> {
238 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239 let Self(rc) = self;
240 if let Some(id) = self.upgrade() {
241 write!(f, "WeakAddressId({:?} => {})", rc.debug_id(), id.addr_sub())
242 } else {
243 write!(
244 f,
245 "WeakAddressId({:?} => {})",
246 rc.debug_id(),
247 <S::Address as IpAddress>::Version::NAME
248 )
249 }
250 }
251}
252
253impl<S: AssignedAddressState> InspectableValue for WeakAddressId<S> {
254 fn record<I: Inspector>(&self, name: &str, inspector: &mut I) {
255 inspector.record_debug(name, self);
256 }
257}
258
259impl<A, S> WeakIpAddressId<A> for WeakAddressId<S>
260where
261 A: IpAddress<Version: AssignedAddrIpExt>,
262 S: AssignedAddressState<Address = A>,
263{
264 type Strong = AddressId<S>;
265
266 fn upgrade(&self) -> Option<Self::Strong> {
267 let Self(inner) = self;
268 inner.upgrade().map(AddressId)
269 }
270
271 fn is_assigned(&self) -> bool {
272 let Self(inner) = self;
273 inner.strong_count() != 0
274 }
275}
276
277#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
279pub struct IpDeviceFlags {
280 pub ip_enabled: bool,
282}
283
284pub struct IpDeviceMulticastGroups<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
286 pub groups: MulticastGroupSet<I::Addr, GmpGroupState<I, BT>>,
288 pub gmp: GmpState<I, I::GmpTypeLayout<BT>, BT>,
290 pub gmp_config: I::GmpProtoConfig,
292}
293
294#[derive(Copy, Clone, Debug)]
299pub struct DefaultHopLimit<I: Ip>(NonZeroU8, IpVersionMarker<I>);
300
301impl<I: Ip> Deref for DefaultHopLimit<I> {
302 type Target = NonZeroU8;
303 fn deref(&self) -> &NonZeroU8 {
304 let Self(value, IpVersionMarker { .. }) = self;
305 value
306 }
307}
308
309impl<I: Ip> DerefMut for DefaultHopLimit<I> {
310 fn deref_mut(&mut self) -> &mut NonZeroU8 {
311 let Self(value, IpVersionMarker { .. }) = self;
312 value
313 }
314}
315
316impl<I: Ip> Default for DefaultHopLimit<I> {
317 fn default() -> Self {
318 Self(DEFAULT_HOP_LIMIT, IpVersionMarker::new())
319 }
320}
321
322#[derive(GenericOverIp)]
324#[generic_over_ip(I, Ip)]
325pub struct IpDeviceState<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
326 addrs: RwLock<IpDeviceAddresses<I, BT>>,
333
334 multicast_groups: RwLock<IpDeviceMulticastGroups<I, BT>>,
336
337 default_hop_limit: RwLock<DefaultHopLimit<I>>,
340
341 flags: Mutex<IpMarked<I, IpDeviceFlags>>,
343}
344
345impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
346 OrderedLockAccess<IpDeviceAddresses<I, BT>> for DualStackIpDeviceState<BT>
347{
348 type Lock = RwLock<IpDeviceAddresses<I, BT>>;
349 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
350 OrderedLockRef::new(&self.ip_state::<I>().addrs)
351 }
352}
353
354impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
355 OrderedLockAccess<IpDeviceMulticastGroups<I, BT>> for DualStackIpDeviceState<BT>
356{
357 type Lock = RwLock<IpDeviceMulticastGroups<I, BT>>;
358 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
359 OrderedLockRef::new(&self.ip_state::<I>().multicast_groups)
360 }
361}
362
363impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> OrderedLockAccess<DefaultHopLimit<I>>
364 for DualStackIpDeviceState<BT>
365{
366 type Lock = RwLock<DefaultHopLimit<I>>;
367 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
368 OrderedLockRef::new(&self.ip_state::<I>().default_hop_limit)
369 }
370}
371
372impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>
373 OrderedLockAccess<IpMarked<I, IpDeviceFlags>> for DualStackIpDeviceState<BT>
374{
375 type Lock = Mutex<IpMarked<I, IpDeviceFlags>>;
376 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
377 OrderedLockRef::new(&self.ip_state::<I>().flags)
378 }
379}
380
381impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<SlaacState<BT>>
382 for DualStackIpDeviceState<BT>
383{
384 type Lock = Mutex<SlaacState<BT>>;
385 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
386 OrderedLockRef::new(&self.ipv6.slaac_state)
387 }
388}
389
390impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> IpDeviceState<I, BT> {
391 #[cfg(any(test, feature = "testutils"))]
393 pub fn addrs(&self) -> &RwLock<IpDeviceAddresses<I, BT>> {
394 &self.addrs
395 }
396}
397
398impl<I: IpDeviceStateIpExt, BC: IpDeviceStateBindingsTypes + TimerContext> IpDeviceState<I, BC> {
399 fn new<D: WeakDeviceIdentifier, CC: CoreTimerContext<I::GmpTimerId<D>, BC>>(
400 bindings_ctx: &mut BC,
401 device_id: D,
402 ) -> IpDeviceState<I, BC> {
403 IpDeviceState {
404 addrs: Default::default(),
405 multicast_groups: RwLock::new(IpDeviceMulticastGroups {
406 groups: Default::default(),
407 gmp: GmpState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx, device_id),
408 gmp_config: Default::default(),
409 }),
410 default_hop_limit: Default::default(),
411 flags: Default::default(),
412 }
413 }
414}
415
416#[derive(Derivative)]
418#[derivative(Default(bound = ""))]
419#[cfg_attr(test, derive(Debug))]
420pub struct IpDeviceAddresses<I: Ip + IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
421 addrs: Vec<PrimaryAddressId<I::AssignedAddressState<BT>>>,
422}
423
424impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> IpDeviceAddresses<I, BT> {
428 pub fn iter(
430 &self,
431 ) -> impl ExactSizeIterator<Item = &PrimaryAddressId<I::AssignedAddressState<BT>>>
432 + ExactSizeIterator
433 + Clone {
434 self.addrs.iter()
435 }
436
437 pub fn strong_iter(&self) -> AddressIdIter<'_, I, BT> {
439 AddressIdIter(self.addrs.iter())
440 }
441
442 pub fn add(
444 &mut self,
445 addr: I::AssignedAddressState<BT>,
446 ) -> Result<AddressId<I::AssignedAddressState<BT>>, ExistsError> {
447 if self.iter().any(|a| a.addr() == addr.addr()) {
448 return Err(ExistsError);
449 }
450 let (primary, strong) = PrimaryAddressId::new_with_strong_clone(addr);
451 self.addrs.push(primary);
452 Ok(strong)
453 }
454
455 pub fn remove(
457 &mut self,
458 addr: &I::Addr,
459 ) -> Result<PrimaryAddressId<I::AssignedAddressState<BT>>, NotFoundError> {
460 let (index, _entry): (_, &PrimaryAddressId<I::AssignedAddressState<BT>>) = self
461 .addrs
462 .iter()
463 .enumerate()
464 .find(|(_, entry)| &entry.addr().addr() == addr)
465 .ok_or(NotFoundError)?;
466 Ok(self.addrs.remove(index))
467 }
468}
469
470pub struct AddressIdIter<'a, I: Ip + IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes>(
472 core::slice::Iter<'a, PrimaryAddressId<I::AssignedAddressState<BT>>>,
473);
474
475impl<'a, I: Ip + IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Iterator
476 for AddressIdIter<'a, I, BT>
477{
478 type Item = AddressId<I::AssignedAddressState<BT>>;
479
480 fn next(&mut self) -> Option<Self::Item> {
481 let Self(inner) = self;
482 inner.next().map(|addr| addr.clone_strong())
483 }
484}
485
486pub struct Ipv4DeviceState<BT: IpDeviceStateBindingsTypes> {
488 ip_state: IpDeviceState<Ipv4, BT>,
489 config: RwLock<Ipv4DeviceConfiguration>,
490 igmp_counters: IgmpCounters,
491}
492
493impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv4DeviceConfiguration>
494 for DualStackIpDeviceState<BT>
495{
496 type Lock = RwLock<Ipv4DeviceConfiguration>;
497 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
498 OrderedLockRef::new(&self.ipv4.config)
499 }
500}
501
502impl<BC: IpDeviceStateBindingsTypes + TimerContext> Ipv4DeviceState<BC> {
503 fn new<D: WeakDeviceIdentifier, CC: CoreTimerContext<Ipv4DeviceTimerId<D>, BC>>(
504 bindings_ctx: &mut BC,
505 device_id: D,
506 ) -> Ipv4DeviceState<BC> {
507 Ipv4DeviceState {
508 ip_state: IpDeviceState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
509 bindings_ctx,
510 device_id,
511 ),
512 config: Default::default(),
513 igmp_counters: Default::default(),
514 }
515 }
516}
517
518impl<BT: IpDeviceStateBindingsTypes> Ipv4DeviceState<BT> {
519 fn igmp_counters(&self) -> &IgmpCounters {
520 &self.igmp_counters
521 }
522}
523
524impl<BT: IpDeviceStateBindingsTypes> AsRef<IpDeviceState<Ipv4, BT>> for Ipv4DeviceState<BT> {
525 fn as_ref(&self) -> &IpDeviceState<Ipv4, BT> {
526 &self.ip_state
527 }
528}
529
530impl<BT: IpDeviceStateBindingsTypes> AsMut<IpDeviceState<Ipv4, BT>> for Ipv4DeviceState<BT> {
531 fn as_mut(&mut self) -> &mut IpDeviceState<Ipv4, BT> {
532 &mut self.ip_state
533 }
534}
535
536#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
538pub struct IpDeviceConfiguration {
539 pub gmp_enabled: bool,
547
548 pub unicast_forwarding_enabled: bool,
560
561 pub multicast_forwarding_enabled: bool,
574}
575
576#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
578pub struct Ipv4DeviceConfiguration {
579 pub ip_config: IpDeviceConfiguration,
581}
582
583impl AsRef<IpDeviceConfiguration> for Ipv4DeviceConfiguration {
584 fn as_ref(&self) -> &IpDeviceConfiguration {
585 &self.ip_config
586 }
587}
588
589impl AsMut<IpDeviceConfiguration> for Ipv4DeviceConfiguration {
590 fn as_mut(&mut self) -> &mut IpDeviceConfiguration {
591 &mut self.ip_config
592 }
593}
594
595#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
597pub struct Ipv6DeviceConfiguration {
598 pub dad_transmits: Option<NonZeroU16>,
607
608 pub max_router_solicitations: Option<NonZeroU8>,
617
618 pub slaac_config: SlaacConfiguration,
620
621 pub ip_config: IpDeviceConfiguration,
623}
624
625impl Ipv6DeviceConfiguration {
626 pub const DEFAULT_MAX_RTR_SOLICITATIONS: NonZeroU8 = NonZeroU8::new(3).unwrap();
630
631 pub const DEFAULT_DUPLICATE_ADDRESS_DETECTION_TRANSMITS: NonZeroU16 =
635 NonZeroU16::new(1).unwrap();
636}
637
638impl AsRef<IpDeviceConfiguration> for Ipv6DeviceConfiguration {
639 fn as_ref(&self) -> &IpDeviceConfiguration {
640 &self.ip_config
641 }
642}
643
644impl AsMut<IpDeviceConfiguration> for Ipv6DeviceConfiguration {
645 fn as_mut(&mut self) -> &mut IpDeviceConfiguration {
646 &mut self.ip_config
647 }
648}
649
650impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv6NetworkLearnedParameters>
651 for DualStackIpDeviceState<BT>
652{
653 type Lock = RwLock<Ipv6NetworkLearnedParameters>;
654 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
655 OrderedLockRef::new(&self.ipv6.learned_params)
656 }
657}
658
659impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv6RouteDiscoveryState<BT>>
660 for DualStackIpDeviceState<BT>
661{
662 type Lock = Mutex<Ipv6RouteDiscoveryState<BT>>;
663 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
664 OrderedLockRef::new(&self.ipv6.route_discovery)
665 }
666}
667
668impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<RsState<BT>> for DualStackIpDeviceState<BT> {
669 type Lock = Mutex<RsState<BT>>;
670 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
671 OrderedLockRef::new(&self.ipv6.router_solicitations)
672 }
673}
674
675impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv6DeviceConfiguration>
676 for DualStackIpDeviceState<BT>
677{
678 type Lock = RwLock<Ipv6DeviceConfiguration>;
679 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
680 OrderedLockRef::new(&self.ipv6.config)
681 }
682}
683
684#[derive(Default)]
686pub struct Ipv6NetworkLearnedParameters {
687 pub retrans_timer: Option<NonZeroDuration>,
696}
697
698impl Ipv6NetworkLearnedParameters {
699 pub fn retrans_timer_or_default(&self) -> NonZeroDuration {
702 self.retrans_timer.clone().unwrap_or(RETRANS_TIMER_DEFAULT)
703 }
704}
705
706pub struct Ipv6DeviceState<BT: IpDeviceStateBindingsTypes> {
708 learned_params: RwLock<Ipv6NetworkLearnedParameters>,
709 route_discovery: Mutex<Ipv6RouteDiscoveryState<BT>>,
710 router_solicitations: Mutex<RsState<BT>>,
711 ip_state: IpDeviceState<Ipv6, BT>,
712 config: RwLock<Ipv6DeviceConfiguration>,
713 slaac_state: Mutex<SlaacState<BT>>,
714 mld_counters: MldCounters,
715}
716
717impl<BC: IpDeviceStateBindingsTypes + TimerContext> Ipv6DeviceState<BC> {
718 pub fn new<
719 D: WeakDeviceIdentifier,
720 A: WeakIpAddressId<Ipv6Addr>,
721 CC: CoreTimerContext<Ipv6DeviceTimerId<D, A>, BC>,
722 >(
723 bindings_ctx: &mut BC,
724 device_id: D,
725 ) -> Self {
726 Ipv6DeviceState {
727 learned_params: Default::default(),
728 route_discovery: Mutex::new(Ipv6RouteDiscoveryState::new::<
729 _,
730 NestedIntoCoreTimerCtx<CC, _>,
731 >(bindings_ctx, device_id.clone())),
732 router_solicitations: Default::default(),
733 ip_state: IpDeviceState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
734 bindings_ctx,
735 device_id.clone(),
736 ),
737 config: Default::default(),
738 slaac_state: Mutex::new(SlaacState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
739 bindings_ctx,
740 device_id,
741 )),
742 mld_counters: Default::default(),
743 }
744 }
745}
746
747impl<BT: IpDeviceStateBindingsTypes> Ipv6DeviceState<BT> {
748 fn mld_counters(&self) -> &MldCounters {
749 &self.mld_counters
750 }
751}
752
753impl<BT: IpDeviceStateBindingsTypes> AsRef<IpDeviceState<Ipv6, BT>> for Ipv6DeviceState<BT> {
754 fn as_ref(&self) -> &IpDeviceState<Ipv6, BT> {
755 &self.ip_state
756 }
757}
758
759impl<BT: IpDeviceStateBindingsTypes> AsMut<IpDeviceState<Ipv6, BT>> for Ipv6DeviceState<BT> {
760 fn as_mut(&mut self) -> &mut IpDeviceState<Ipv6, BT> {
761 &mut self.ip_state
762 }
763}
764
765pub trait IpDeviceStateBindingsTypes:
767 InstantBindingsTypes + TimerBindingsTypes + ReferenceNotifiers + 'static
768{
769}
770impl<BT> IpDeviceStateBindingsTypes for BT where
771 BT: InstantBindingsTypes + TimerBindingsTypes + ReferenceNotifiers + 'static
772{
773}
774
775pub struct DualStackIpDeviceState<BT: IpDeviceStateBindingsTypes> {
777 ipv4: Ipv4DeviceState<BT>,
779
780 ipv6: Ipv6DeviceState<BT>,
782
783 metric: RawMetric,
785}
786
787impl<BC: IpDeviceStateBindingsTypes + TimerContext> DualStackIpDeviceState<BC> {
788 pub fn new<
792 D: WeakDeviceIdentifier,
793 A: IpAddressIdSpec,
794 CC: CoreTimerContext<IpDeviceTimerId<Ipv6, D, A>, BC>
795 + CoreTimerContext<IpDeviceTimerId<Ipv4, D, A>, BC>,
796 >(
797 bindings_ctx: &mut BC,
798 device_id: D,
799 metric: RawMetric,
800 ) -> Self {
801 Self {
802 ipv4: Ipv4DeviceState::new::<D, NestedIntoCoreTimerCtx<CC, IpDeviceTimerId<Ipv4, D, A>>>(
803 bindings_ctx,
804 device_id.clone(),
805 ),
806 ipv6: Ipv6DeviceState::new::<
807 D,
808 A::WeakV6,
809 NestedIntoCoreTimerCtx<CC, IpDeviceTimerId<Ipv6, D, A>>,
810 >(bindings_ctx, device_id),
811 metric,
812 }
813 }
814}
815
816impl<BT: IpDeviceStateBindingsTypes> DualStackIpDeviceState<BT> {
817 pub fn metric(&self) -> &RawMetric {
819 &self.metric
820 }
821
822 pub fn ip_state<I: IpDeviceStateIpExt>(&self) -> &IpDeviceState<I, BT> {
824 I::map_ip_out(
825 self,
826 |dual_stack| &dual_stack.ipv4.ip_state,
827 |dual_stack| &dual_stack.ipv6.ip_state,
828 )
829 }
830
831 pub fn igmp_counters(&self) -> &IgmpCounters {
833 self.ipv4.igmp_counters()
834 }
835
836 pub fn mld_counters(&self) -> &MldCounters {
838 self.ipv6.mld_counters()
839 }
840}
841
842#[derive(Derivative)]
844#[derivative(Debug(bound = ""))]
845pub enum Ipv6DadState<BT: DadBindingsTypes> {
846 Assigned,
849
850 #[allow(missing_docs)]
857 Tentative {
858 dad_transmits_remaining: Option<NonZeroU16>,
859 timer: BT::Timer,
860 nonces: NonceCollection,
861 added_extra_transmits_after_detecting_looped_back_ns: bool,
865 },
866
867 Uninitialized,
869}
870
871#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
873pub struct TemporarySlaacConfig<Instant> {
874 pub valid_until: Instant,
876 pub desync_factor: Duration,
878 pub creation_time: Instant,
880 pub dad_counter: u8,
884}
885
886#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
888pub enum Lifetime<I> {
889 Finite(I),
891 Infinite,
893}
894
895impl<I: Instant> InspectableValue for Lifetime<I> {
896 fn record<N: Inspector>(&self, name: &str, inspector: &mut N) {
897 match self {
898 Self::Finite(instant) => inspector.record_inspectable_value(name, instant),
899 Self::Infinite => inspector.record_str(name, "infinite"),
900 }
901 }
902}
903
904impl<I: Instant> Lifetime<I> {
905 pub fn from_ndp(now: I, duration: NonZeroNdpLifetime) -> Self {
908 match duration {
909 NonZeroNdpLifetime::Finite(d) => Self::after(now, d.get()),
910 NonZeroNdpLifetime::Infinite => Self::Infinite,
911 }
912 }
913
914 pub fn after(now: I, duration: Duration) -> Self {
917 match now.checked_add(duration) {
918 Some(i) => Self::Finite(i),
919 None => Self::Infinite,
920 }
921 }
922}
923
924impl<Instant> Lifetime<Instant> {
925 pub fn map_instant<N, F: FnOnce(Instant) -> N>(self, f: F) -> Lifetime<N> {
927 match self {
928 Self::Infinite => Lifetime::Infinite,
929 Self::Finite(i) => Lifetime::Finite(f(i)),
930 }
931 }
932}
933
934#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
936pub enum PreferredLifetime<Instant> {
937 Preferred(Lifetime<Instant>),
942 Deprecated,
944}
945
946impl<Instant> PreferredLifetime<Instant> {
947 pub const fn preferred_until(instant: Instant) -> Self {
949 Self::Preferred(Lifetime::Finite(instant))
950 }
951
952 pub const fn preferred_forever() -> Self {
955 Self::Preferred(Lifetime::Infinite)
956 }
957
958 pub const fn is_deprecated(&self) -> bool {
960 match self {
961 Self::Preferred(_) => false,
962 Self::Deprecated => true,
963 }
964 }
965
966 pub fn map_instant<N, F: FnOnce(Instant) -> N>(self, f: F) -> PreferredLifetime<N> {
968 match self {
969 Self::Deprecated => PreferredLifetime::Deprecated,
970 Self::Preferred(l) => PreferredLifetime::Preferred(l.map_instant(f)),
971 }
972 }
973}
974
975impl<I: Instant> PreferredLifetime<I> {
976 pub fn preferred_for(now: I, duration: NonZeroNdpLifetime) -> Self {
979 Self::Preferred(Lifetime::from_ndp(now, duration))
980 }
981
982 pub fn maybe_preferred_for(now: I, duration: Option<NonZeroNdpLifetime>) -> Self {
985 match duration {
986 Some(d) => Self::preferred_for(now, d),
987 None => Self::Deprecated,
988 }
989 }
990}
991
992impl<Instant> Default for PreferredLifetime<Instant> {
993 fn default() -> Self {
994 Self::Preferred(Lifetime::Infinite)
995 }
996}
997
998impl<I: Instant> InspectableValue for PreferredLifetime<I> {
999 fn record<N: Inspector>(&self, name: &str, inspector: &mut N) {
1000 match self {
1001 Self::Deprecated => inspector.record_str(name, "deprecated"),
1002 Self::Preferred(lifetime) => inspector.record_inspectable_value(name, lifetime),
1003 }
1004 }
1005}
1006
1007#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1009pub struct CommonAddressProperties<Instant> {
1010 pub valid_until: Lifetime<Instant>,
1012 pub preferred_lifetime: PreferredLifetime<Instant>,
1020}
1021
1022impl<I> Default for CommonAddressProperties<I> {
1023 fn default() -> Self {
1024 Self {
1025 valid_until: Lifetime::Infinite,
1026 preferred_lifetime: PreferredLifetime::preferred_forever(),
1027 }
1028 }
1029}
1030
1031impl<Inst: Instant> Inspectable for CommonAddressProperties<Inst> {
1032 fn record<I: Inspector>(&self, inspector: &mut I) {
1033 let Self { valid_until, preferred_lifetime } = self;
1034 inspector.record_inspectable_value("ValidUntil", valid_until);
1035 inspector.record_inspectable_value("PreferredLifetime", preferred_lifetime);
1036 }
1037}
1038
1039#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1041pub struct Ipv4AddrConfig<Instant> {
1042 pub common: CommonAddressProperties<Instant>,
1044}
1045
1046impl<I> Default for Ipv4AddrConfig<I> {
1047 fn default() -> Self {
1048 Self { common: Default::default() }
1049 }
1050}
1051
1052#[derive(Derivative)]
1054#[derivative(Debug)]
1055pub struct Ipv4AddressEntry<BT: IpDeviceStateBindingsTypes> {
1056 addr_sub: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
1057 state: RwLock<Ipv4AddressState<BT::Instant>>,
1058}
1059
1060impl<BT: IpDeviceStateBindingsTypes> Ipv4AddressEntry<BT> {
1061 pub fn new(
1063 addr_sub: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
1064 config: Ipv4AddrConfig<BT::Instant>,
1065 ) -> Self {
1066 Self { addr_sub, state: RwLock::new(Ipv4AddressState { config: Some(config) }) }
1067 }
1068
1069 pub fn addr_sub(&self) -> &AddrSubnet<Ipv4Addr, Ipv4DeviceAddr> {
1071 &self.addr_sub
1072 }
1073}
1074
1075impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv4AddressState<BT::Instant>>
1076 for Ipv4AddressEntry<BT>
1077{
1078 type Lock = RwLock<Ipv4AddressState<BT::Instant>>;
1079 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1080 OrderedLockRef::new(&self.state)
1081 }
1082}
1083
1084#[derive(Debug)]
1086pub struct Ipv4AddressState<Instant> {
1087 pub(crate) config: Option<Ipv4AddrConfig<Instant>>,
1088}
1089
1090impl<Inst: Instant> Inspectable for Ipv4AddressState<Inst> {
1091 fn record<I: Inspector>(&self, inspector: &mut I) {
1092 let Self { config } = self;
1093 if let Some(Ipv4AddrConfig { common }) = config {
1094 inspector.delegate_inspectable(common);
1095 }
1096 }
1097}
1098
1099#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1102pub enum SlaacConfig<Instant> {
1103 Stable {
1105 valid_until: Lifetime<Instant>,
1107 creation_time: Instant,
1109 regen_counter: u8,
1112 dad_counter: u8,
1114 },
1115 Temporary(TemporarySlaacConfig<Instant>),
1119}
1120
1121impl<Instant: Copy> SlaacConfig<Instant> {
1122 pub fn valid_until(&self) -> Lifetime<Instant> {
1124 match self {
1125 SlaacConfig::Stable { valid_until, .. } => *valid_until,
1126 SlaacConfig::Temporary(TemporarySlaacConfig { valid_until, .. }) => {
1127 Lifetime::Finite(*valid_until)
1128 }
1129 }
1130 }
1131}
1132
1133#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1135pub enum Ipv6AddrConfig<Instant> {
1136 Slaac(Ipv6AddrSlaacConfig<Instant>),
1138
1139 Manual(Ipv6AddrManualConfig<Instant>),
1141}
1142
1143impl<Instant> Default for Ipv6AddrConfig<Instant> {
1144 fn default() -> Self {
1145 Self::Manual(Default::default())
1146 }
1147}
1148
1149#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1151pub struct Ipv6AddrSlaacConfig<Instant> {
1152 pub inner: SlaacConfig<Instant>,
1154 pub preferred_lifetime: PreferredLifetime<Instant>,
1156}
1157
1158#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1160pub struct Ipv6AddrManualConfig<Instant> {
1161 pub common: CommonAddressProperties<Instant>,
1163 pub temporary: bool,
1167}
1168
1169impl<Instant> Default for Ipv6AddrManualConfig<Instant> {
1170 fn default() -> Self {
1171 Self { common: Default::default(), temporary: false }
1172 }
1173}
1174
1175impl<Instant> From<Ipv6AddrManualConfig<Instant>> for Ipv6AddrConfig<Instant> {
1176 fn from(value: Ipv6AddrManualConfig<Instant>) -> Self {
1177 Self::Manual(value)
1178 }
1179}
1180
1181impl<Instant: Copy + PartialEq> Ipv6AddrConfig<Instant> {
1182 pub fn valid_until(&self) -> Lifetime<Instant> {
1184 match self {
1185 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig { inner, .. }) => inner.valid_until(),
1186 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig { common, .. }) => common.valid_until,
1187 }
1188 }
1189
1190 pub fn preferred_lifetime(&self) -> PreferredLifetime<Instant> {
1192 match self {
1193 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig { common, .. }) => {
1194 common.preferred_lifetime
1195 }
1196 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig { preferred_lifetime, .. }) => {
1197 *preferred_lifetime
1198 }
1199 }
1200 }
1201
1202 pub fn is_deprecated(&self) -> bool {
1204 self.preferred_lifetime().is_deprecated()
1205 }
1206
1207 pub fn is_temporary(&self) -> bool {
1209 match self {
1210 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig { inner, .. }) => match inner {
1211 SlaacConfig::Stable { .. } => false,
1212 SlaacConfig::Temporary(_) => true,
1213 },
1214 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig { temporary, .. }) => *temporary,
1215 }
1216 }
1217
1218 pub fn is_slaac(&self) -> bool {
1220 match self {
1221 Ipv6AddrConfig::Slaac(_) => true,
1222 Ipv6AddrConfig::Manual(_) => false,
1223 }
1224 }
1225}
1226
1227#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1229pub struct Ipv6AddressFlags {
1230 pub assigned: bool,
1232}
1233
1234#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1236pub struct Ipv6AddressState<Instant> {
1237 pub flags: Ipv6AddressFlags,
1239 pub config: Option<Ipv6AddrConfig<Instant>>,
1241}
1242
1243impl<Inst: Instant> Inspectable for Ipv6AddressState<Inst> {
1244 fn record<I: Inspector>(&self, inspector: &mut I) {
1245 let Self { flags: Ipv6AddressFlags { assigned }, config } = self;
1246 inspector.record_bool("Assigned", *assigned);
1247
1248 if let Some(config) = config {
1249 match config {
1250 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig { .. }) => {}
1251 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig { inner, preferred_lifetime: _ }) => {
1252 match inner {
1253 SlaacConfig::Stable {
1254 valid_until: _,
1255 creation_time,
1256 regen_counter,
1257 dad_counter,
1258 } => {
1259 inspector.record_inspectable_value("CreationTime", creation_time);
1260 inspector.record_uint("RegenCounter", *regen_counter);
1261 inspector.record_uint("DadCounter", *dad_counter);
1262 }
1263 SlaacConfig::Temporary(TemporarySlaacConfig {
1264 valid_until: _,
1265 desync_factor,
1266 creation_time,
1267 dad_counter,
1268 }) => {
1269 inspector
1270 .record_double("DesyncFactorSecs", desync_factor.as_secs_f64());
1271 inspector.record_uint("DadCounter", *dad_counter);
1272 inspector.record_inspectable_value("CreationTime", creation_time);
1273 }
1274 }
1275 }
1276 };
1277 inspector.record_bool("IsSlaac", config.is_slaac());
1278 inspector.record_inspectable_value("ValidUntil", &config.valid_until());
1279 inspector.record_inspectable_value("PreferredLifetime", &config.preferred_lifetime());
1280 inspector.record_bool("Temporary", config.is_temporary());
1281 }
1282 }
1283}
1284
1285#[derive(Derivative)]
1288#[derivative(Debug(bound = ""))]
1289pub struct Ipv6AddressEntry<BT: IpDeviceStateBindingsTypes> {
1290 addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
1291 dad_state: Mutex<Ipv6DadState<BT>>,
1292 state: RwLock<Ipv6AddressState<BT::Instant>>,
1293}
1294
1295impl<BT: IpDeviceStateBindingsTypes> Ipv6AddressEntry<BT> {
1296 pub fn new(
1298 addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
1299 dad_state: Ipv6DadState<BT>,
1300 config: Ipv6AddrConfig<BT::Instant>,
1301 ) -> Self {
1302 let assigned = match dad_state {
1303 Ipv6DadState::Assigned => true,
1304 Ipv6DadState::Tentative { .. } | Ipv6DadState::Uninitialized => false,
1305 };
1306
1307 Self {
1308 addr_sub,
1309 dad_state: Mutex::new(dad_state),
1310 state: RwLock::new(Ipv6AddressState {
1311 config: Some(config),
1312 flags: Ipv6AddressFlags { assigned },
1313 }),
1314 }
1315 }
1316
1317 pub fn addr_sub(&self) -> &AddrSubnet<Ipv6Addr, Ipv6DeviceAddr> {
1319 &self.addr_sub
1320 }
1321}
1322
1323impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv6DadState<BT>> for Ipv6AddressEntry<BT> {
1324 type Lock = Mutex<Ipv6DadState<BT>>;
1325 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1326 OrderedLockRef::new(&self.dad_state)
1327 }
1328}
1329
1330impl<BT: IpDeviceStateBindingsTypes> OrderedLockAccess<Ipv6AddressState<BT::Instant>>
1331 for Ipv6AddressEntry<BT>
1332{
1333 type Lock = RwLock<Ipv6AddressState<BT::Instant>>;
1334 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
1335 OrderedLockRef::new(&self.state)
1336 }
1337}
1338
1339#[cfg(test)]
1340mod tests {
1341 use super::*;
1342
1343 use netstack3_base::testutil::{FakeBindingsCtx, FakeInstant};
1344 use netstack3_base::InstantContext as _;
1345 use test_case::test_case;
1346
1347 type FakeBindingsCtxImpl = FakeBindingsCtx<(), (), (), ()>;
1348
1349 #[test_case(Lifetime::Infinite ; "with infinite valid_until")]
1350 #[test_case(Lifetime::Finite(FakeInstant::from(Duration::from_secs(1))); "with finite valid_until")]
1351 fn test_add_addr_ipv4(valid_until: Lifetime<FakeInstant>) {
1352 const ADDRESS: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
1353 const PREFIX_LEN: u8 = 8;
1354
1355 let mut ipv4 = IpDeviceAddresses::<Ipv4, FakeBindingsCtxImpl>::default();
1356 let config = Ipv4AddrConfig {
1357 common: CommonAddressProperties { valid_until, ..Default::default() },
1358 };
1359
1360 let _: AddressId<_> = ipv4
1361 .add(Ipv4AddressEntry::new(AddrSubnet::new(ADDRESS, PREFIX_LEN).unwrap(), config))
1362 .unwrap();
1363 assert_eq!(
1365 ipv4.add(Ipv4AddressEntry::new(
1366 AddrSubnet::new(ADDRESS, PREFIX_LEN + 1).unwrap(),
1367 config,
1368 ))
1369 .unwrap_err(),
1370 ExistsError
1371 );
1372 }
1373
1374 #[test_case(Lifetime::Infinite ; "with infinite valid_until")]
1375 #[test_case(Lifetime::Finite(FakeInstant::from(Duration::from_secs(1))); "with finite valid_until")]
1376 fn test_add_addr_ipv6(valid_until: Lifetime<FakeInstant>) {
1377 const ADDRESS: Ipv6Addr =
1378 Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6]);
1379 const PREFIX_LEN: u8 = 8;
1380
1381 let mut ipv6 = IpDeviceAddresses::<Ipv6, FakeBindingsCtxImpl>::default();
1382
1383 let mut bindings_ctx = FakeBindingsCtxImpl::default();
1384
1385 let _: AddressId<_> = ipv6
1386 .add(Ipv6AddressEntry::new(
1387 AddrSubnet::new(ADDRESS, PREFIX_LEN).unwrap(),
1388 Ipv6DadState::Tentative {
1389 dad_transmits_remaining: None,
1390 timer: bindings_ctx.new_timer(()),
1391 nonces: Default::default(),
1392 added_extra_transmits_after_detecting_looped_back_ns: false,
1393 },
1394 Ipv6AddrConfig::Slaac(Ipv6AddrSlaacConfig {
1395 inner: SlaacConfig::Stable {
1396 valid_until,
1397 creation_time: bindings_ctx.now(),
1398 regen_counter: 0,
1399 dad_counter: 0,
1400 },
1401 preferred_lifetime: PreferredLifetime::Preferred(Lifetime::Infinite),
1402 }),
1403 ))
1404 .unwrap();
1405 assert_eq!(
1408 ipv6.add(Ipv6AddressEntry::new(
1409 AddrSubnet::new(ADDRESS, PREFIX_LEN + 1).unwrap(),
1410 Ipv6DadState::Assigned,
1411 Ipv6AddrConfig::Manual(Ipv6AddrManualConfig {
1412 common: CommonAddressProperties { valid_until, ..Default::default() },
1413 ..Default::default()
1414 }),
1415 ))
1416 .unwrap_err(),
1417 ExistsError,
1418 );
1419 }
1420}