1pub(crate) mod api;
8pub(crate) mod config;
9pub(crate) mod dad;
10pub(crate) mod nud;
11pub(crate) mod opaque_iid;
12pub(crate) mod route_discovery;
13pub(crate) mod router_solicitation;
14pub(crate) mod slaac;
15pub(crate) mod state;
16
17use alloc::vec::Vec;
18use core::fmt::{Debug, Display};
19use core::hash::Hash;
20use core::num::NonZeroU8;
21
22use derivative::Derivative;
23use log::info;
24use net_types::ip::{
25 AddrSubnet, GenericOverIp, Ip, IpAddress, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu,
26 Subnet,
27};
28use net_types::{LinkLocalAddress as _, MulticastAddr, SpecifiedAddr, UnicastAddr, Witness};
29use netstack3_base::{
30 AnyDevice, AssignedAddrIpExt, CounterContext, DeferredResourceRemovalContext, DeviceIdContext,
31 EventContext, ExistsError, HandleableTimer, Inspectable, Instant, InstantBindingsTypes,
32 InstantContext, IpAddressId, IpDeviceAddr, IpDeviceAddressIdContext, IpExt, Ipv4DeviceAddr,
33 Ipv6DeviceAddr, NotFoundError, RemoveResourceResultWithContext, RngContext, SendFrameError,
34 StrongDeviceIdentifier, TimerBindingsTypes, TimerContext, TimerHandler,
35 TxMetadataBindingsTypes, WeakDeviceIdentifier, WeakIpAddressId,
36};
37use netstack3_filter::ProofOfEgressCheck;
38use packet::{BufferMut, Serializer};
39use packet_formats::icmp::mld::MldPacket;
40use packet_formats::icmp::ndp::options::NdpNonce;
41use packet_formats::icmp::ndp::NonZeroNdpLifetime;
42use packet_formats::utils::NonZeroDuration;
43use zerocopy::SplitByteSlice;
44
45use crate::device::CommonAddressProperties;
46use crate::internal::base::{
47 DeviceIpLayerMetadata, IpCounters, IpDeviceMtuContext, IpPacketDestination,
48};
49use crate::internal::device::config::{
50 IpDeviceConfigurationUpdate, Ipv4DeviceConfigurationUpdate, Ipv6DeviceConfigurationUpdate,
51};
52use crate::internal::device::dad::{DadAddressStateLookupResult, DadHandler, DadTimerId};
53use crate::internal::device::nud::NudIpHandler;
54use crate::internal::device::route_discovery::{
55 Ipv6DiscoveredRoute, Ipv6DiscoveredRouteTimerId, RouteDiscoveryHandler,
56};
57use crate::internal::device::router_solicitation::{RsHandler, RsTimerId};
58use crate::internal::device::slaac::{SlaacHandler, SlaacTimerId};
59use crate::internal::device::state::{
60 IpDeviceConfiguration, IpDeviceFlags, IpDeviceState, IpDeviceStateBindingsTypes,
61 IpDeviceStateIpExt, Ipv4AddrConfig, Ipv4AddressEntry, Ipv4AddressState,
62 Ipv4DeviceConfiguration, Ipv4DeviceState, Ipv6AddrConfig, Ipv6AddrManualConfig,
63 Ipv6AddressEntry, Ipv6AddressFlags, Ipv6AddressState, Ipv6DeviceConfiguration, Ipv6DeviceState,
64 Ipv6NetworkLearnedParameters, Lifetime, PreferredLifetime, WeakAddressId,
65};
66use crate::internal::gmp::igmp::{IgmpPacketHandler, IgmpTimerId};
67use crate::internal::gmp::mld::{MldPacketHandler, MldTimerId};
68use crate::internal::gmp::{self, GmpHandler, GroupJoinResult, GroupLeaveResult};
69use crate::internal::local_delivery::{IpHeaderInfo, LocalDeliveryPacketInfo};
70
71#[derive(Derivative, GenericOverIp)]
78#[derivative(
79 Clone(bound = ""),
80 Eq(bound = ""),
81 PartialEq(bound = ""),
82 Hash(bound = ""),
83 Debug(bound = "")
84)]
85#[generic_over_ip(I, Ip)]
86pub struct IpDeviceTimerId<I: IpDeviceIpExt, D: WeakDeviceIdentifier, A: IpAddressIdSpec>(
87 I::Timer<D, A>,
88);
89
90#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
92pub struct Ipv4DeviceTimerId<D: WeakDeviceIdentifier>(IgmpTimerId<D>);
93
94impl<D: WeakDeviceIdentifier> Ipv4DeviceTimerId<D> {
95 fn device_id(&self) -> Option<D::Strong> {
97 let Self(this) = self;
98 this.device_id().upgrade()
99 }
100
101 pub fn into_common<S: IpAddressIdSpec>(self) -> IpDeviceTimerId<Ipv4, D, S> {
103 self.into()
104 }
105}
106
107impl<D: WeakDeviceIdentifier, A: IpAddressIdSpec> From<IpDeviceTimerId<Ipv4, D, A>>
108 for Ipv4DeviceTimerId<D>
109{
110 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv4, D, A>) -> Self {
111 inner
112 }
113}
114
115impl<D: WeakDeviceIdentifier, A: IpAddressIdSpec> From<Ipv4DeviceTimerId<D>>
116 for IpDeviceTimerId<Ipv4, D, A>
117{
118 fn from(value: Ipv4DeviceTimerId<D>) -> Self {
119 Self(value)
120 }
121}
122
123impl<D: WeakDeviceIdentifier> From<IgmpTimerId<D>> for Ipv4DeviceTimerId<D> {
124 fn from(id: IgmpTimerId<D>) -> Ipv4DeviceTimerId<D> {
125 Ipv4DeviceTimerId(id)
126 }
127}
128
129impl<D: WeakDeviceIdentifier, BC: TimerBindingsTypes, CC: TimerHandler<BC, IgmpTimerId<D>>>
130 HandleableTimer<CC, BC> for Ipv4DeviceTimerId<D>
131{
132 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
133 let Self(id) = self;
134 core_ctx.handle_timer(bindings_ctx, id, timer);
135 }
136}
137
138impl<I, CC, BC, A> HandleableTimer<CC, BC> for IpDeviceTimerId<I, CC::WeakDeviceId, A>
139where
140 I: IpDeviceIpExt,
141 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
142 CC: IpDeviceConfigurationContext<I, BC>,
143 A: IpAddressIdSpec,
144 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>:
145 TimerHandler<BC, I::Timer<CC::WeakDeviceId, A>>,
146{
147 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
148 let Self(id) = self;
149 let Some(device_id) = I::timer_device_id(&id) else {
150 return;
151 };
152 core_ctx.with_ip_device_configuration(&device_id, |_state, mut core_ctx| {
153 TimerHandler::handle_timer(&mut core_ctx, bindings_ctx, id, timer)
154 })
155 }
156}
157
158#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
160#[allow(missing_docs)]
161pub enum Ipv6DeviceTimerId<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> {
162 Mld(MldTimerId<D>),
163 Dad(DadTimerId<D, A>),
164 Rs(RsTimerId<D>),
165 RouteDiscovery(Ipv6DiscoveredRouteTimerId<D>),
166 Slaac(SlaacTimerId<D>),
167}
168
169impl<D: WeakDeviceIdentifier, A: IpAddressIdSpec> From<IpDeviceTimerId<Ipv6, D, A>>
170 for Ipv6DeviceTimerId<D, A::WeakV6>
171{
172 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv6, D, A>) -> Self {
173 inner
174 }
175}
176
177impl<D: WeakDeviceIdentifier, A: IpAddressIdSpec> From<Ipv6DeviceTimerId<D, A::WeakV6>>
178 for IpDeviceTimerId<Ipv6, D, A>
179{
180 fn from(value: Ipv6DeviceTimerId<D, A::WeakV6>) -> Self {
181 Self(value)
182 }
183}
184
185impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> Ipv6DeviceTimerId<D, A> {
186 fn device_id(&self) -> Option<D::Strong> {
188 match self {
189 Self::Mld(id) => id.device_id(),
190 Self::Dad(id) => id.device_id(),
191 Self::Rs(id) => id.device_id(),
192 Self::RouteDiscovery(id) => id.device_id(),
193 Self::Slaac(id) => id.device_id(),
194 }
195 .upgrade()
196 }
197
198 pub fn into_common<S: IpAddressIdSpec<WeakV6 = A>>(self) -> IpDeviceTimerId<Ipv6, D, S> {
200 self.into()
201 }
202}
203
204impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<MldTimerId<D>>
205 for Ipv6DeviceTimerId<D, A>
206{
207 fn from(id: MldTimerId<D>) -> Ipv6DeviceTimerId<D, A> {
208 Ipv6DeviceTimerId::Mld(id)
209 }
210}
211
212impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<DadTimerId<D, A>>
213 for Ipv6DeviceTimerId<D, A>
214{
215 fn from(id: DadTimerId<D, A>) -> Ipv6DeviceTimerId<D, A> {
216 Ipv6DeviceTimerId::Dad(id)
217 }
218}
219
220impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<RsTimerId<D>>
221 for Ipv6DeviceTimerId<D, A>
222{
223 fn from(id: RsTimerId<D>) -> Ipv6DeviceTimerId<D, A> {
224 Ipv6DeviceTimerId::Rs(id)
225 }
226}
227
228impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<Ipv6DiscoveredRouteTimerId<D>>
229 for Ipv6DeviceTimerId<D, A>
230{
231 fn from(id: Ipv6DiscoveredRouteTimerId<D>) -> Ipv6DeviceTimerId<D, A> {
232 Ipv6DeviceTimerId::RouteDiscovery(id)
233 }
234}
235
236impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<SlaacTimerId<D>>
237 for Ipv6DeviceTimerId<D, A>
238{
239 fn from(id: SlaacTimerId<D>) -> Ipv6DeviceTimerId<D, A> {
240 Ipv6DeviceTimerId::Slaac(id)
241 }
242}
243
244impl<
245 D: WeakDeviceIdentifier,
246 A: WeakIpAddressId<Ipv6Addr>,
247 BC: TimerBindingsTypes,
248 CC: TimerHandler<BC, RsTimerId<D>>
249 + TimerHandler<BC, Ipv6DiscoveredRouteTimerId<D>>
250 + TimerHandler<BC, MldTimerId<D>>
251 + TimerHandler<BC, SlaacTimerId<D>>
252 + TimerHandler<BC, DadTimerId<D, A>>,
253 > HandleableTimer<CC, BC> for Ipv6DeviceTimerId<D, A>
254{
255 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
256 match self {
257 Ipv6DeviceTimerId::Mld(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
258 Ipv6DeviceTimerId::Dad(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
259 Ipv6DeviceTimerId::Rs(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
260 Ipv6DeviceTimerId::RouteDiscovery(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
261 Ipv6DeviceTimerId::Slaac(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
262 }
263 }
264}
265
266pub trait IpDeviceIpExt: IpDeviceStateIpExt + AssignedAddrIpExt + gmp::IpExt {
268 type State<BT: IpDeviceStateBindingsTypes>: AsRef<IpDeviceState<Self, BT>>
270 + AsMut<IpDeviceState<Self, BT>>;
271 type Configuration: AsRef<IpDeviceConfiguration>
273 + AsMut<IpDeviceConfiguration>
274 + Clone
275 + Debug
276 + Eq
277 + PartialEq;
278 type Timer<D: WeakDeviceIdentifier, A: IpAddressIdSpec>: Into<IpDeviceTimerId<Self, D, A>>
280 + From<IpDeviceTimerId<Self, D, A>>
281 + Clone
282 + Eq
283 + PartialEq
284 + Debug
285 + Hash;
286 type AddressConfig<I: Instant>: Default + Debug;
288 type ManualAddressConfig<I: Instant>: Default + Debug + Into<Self::AddressConfig<I>>;
290 type AddressState<I: Instant>: 'static + Inspectable;
292 type ConfigurationUpdate: From<IpDeviceConfigurationUpdate>
294 + AsRef<IpDeviceConfigurationUpdate>
295 + Debug;
296
297 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I>;
299
300 fn is_addr_assigned<I: Instant>(addr_state: &Self::AddressState<I>) -> bool;
302
303 fn timer_device_id<D: WeakDeviceIdentifier, A: IpAddressIdSpec>(
305 timer: &Self::Timer<D, A>,
306 ) -> Option<D::Strong>;
307
308 fn take_addr_config_for_removal<I: Instant>(
311 addr_state: &mut Self::AddressState<I>,
312 ) -> Option<Self::AddressConfig<I>>;
313}
314
315impl IpDeviceIpExt for Ipv4 {
316 type State<BT: IpDeviceStateBindingsTypes> = Ipv4DeviceState<BT>;
317 type Configuration = Ipv4DeviceConfiguration;
318 type Timer<D: WeakDeviceIdentifier, A: IpAddressIdSpec> = Ipv4DeviceTimerId<D>;
319 type AddressConfig<I: Instant> = Ipv4AddrConfig<I>;
320 type ManualAddressConfig<I: Instant> = Ipv4AddrConfig<I>;
321 type AddressState<I: Instant> = Ipv4AddressState<I>;
322 type ConfigurationUpdate = Ipv4DeviceConfigurationUpdate;
323
324 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
325 config.common
326 }
327
328 fn is_addr_assigned<I: Instant>(addr_state: &Ipv4AddressState<I>) -> bool {
329 let Ipv4AddressState { config: _ } = addr_state;
330 true
331 }
332
333 fn timer_device_id<D: WeakDeviceIdentifier, A: IpAddressIdSpec>(
334 timer: &Self::Timer<D, A>,
335 ) -> Option<D::Strong> {
336 timer.device_id()
337 }
338
339 fn take_addr_config_for_removal<I: Instant>(
340 addr_state: &mut Self::AddressState<I>,
341 ) -> Option<Self::AddressConfig<I>> {
342 addr_state.config.take()
343 }
344}
345
346impl IpDeviceIpExt for Ipv6 {
347 type State<BT: IpDeviceStateBindingsTypes> = Ipv6DeviceState<BT>;
348 type Configuration = Ipv6DeviceConfiguration;
349 type Timer<D: WeakDeviceIdentifier, A: IpAddressIdSpec> = Ipv6DeviceTimerId<D, A::WeakV6>;
350 type AddressConfig<I: Instant> = Ipv6AddrConfig<I>;
351 type ManualAddressConfig<I: Instant> = Ipv6AddrManualConfig<I>;
352 type AddressState<I: Instant> = Ipv6AddressState<I>;
353 type ConfigurationUpdate = Ipv6DeviceConfigurationUpdate;
354
355 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
356 CommonAddressProperties {
357 valid_until: config.valid_until(),
358 preferred_lifetime: config.preferred_lifetime(),
359 }
360 }
361
362 fn is_addr_assigned<I: Instant>(addr_state: &Ipv6AddressState<I>) -> bool {
363 addr_state.flags.assigned
364 }
365
366 fn timer_device_id<D: WeakDeviceIdentifier, A: IpAddressIdSpec>(
367 timer: &Self::Timer<D, A>,
368 ) -> Option<D::Strong> {
369 timer.device_id()
370 }
371
372 fn take_addr_config_for_removal<I: Instant>(
373 addr_state: &mut Self::AddressState<I>,
374 ) -> Option<Self::AddressConfig<I>> {
375 addr_state.config.take()
376 }
377}
378#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
380pub enum IpAddressState {
381 Unavailable,
383 Assigned,
386 Tentative,
390}
391
392#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
394pub enum AddressRemovedReason {
395 Manual,
397 DadFailed,
399}
400
401#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
402#[generic_over_ip(I, Ip)]
403pub enum IpDeviceEvent<DeviceId, I: Ip, Instant> {
405 AddressAdded {
407 device: DeviceId,
409 addr: AddrSubnet<I::Addr>,
411 state: IpAddressState,
413 valid_until: Lifetime<Instant>,
415 preferred_lifetime: PreferredLifetime<Instant>,
417 },
418 AddressRemoved {
420 device: DeviceId,
422 addr: SpecifiedAddr<I::Addr>,
424 reason: AddressRemovedReason,
426 },
427 AddressStateChanged {
429 device: DeviceId,
431 addr: SpecifiedAddr<I::Addr>,
433 state: IpAddressState,
435 },
436 AddressPropertiesChanged {
438 device: DeviceId,
440 addr: SpecifiedAddr<I::Addr>,
442 valid_until: Lifetime<Instant>,
444 preferred_lifetime: PreferredLifetime<Instant>,
446 },
447 EnabledChanged {
449 device: DeviceId,
451 ip_enabled: bool,
453 },
454}
455
456impl<DeviceId, I: Ip, Instant> IpDeviceEvent<DeviceId, I, Instant> {
457 pub fn map_device<N, F: FnOnce(DeviceId) -> N>(self, map: F) -> IpDeviceEvent<N, I, Instant> {
459 match self {
460 IpDeviceEvent::AddressAdded {
461 device,
462 addr,
463 state,
464 valid_until,
465 preferred_lifetime,
466 } => IpDeviceEvent::AddressAdded {
467 device: map(device),
468 addr,
469 state,
470 valid_until,
471 preferred_lifetime,
472 },
473 IpDeviceEvent::AddressRemoved { device, addr, reason } => {
474 IpDeviceEvent::AddressRemoved { device: map(device), addr, reason }
475 }
476 IpDeviceEvent::AddressStateChanged { device, addr, state } => {
477 IpDeviceEvent::AddressStateChanged { device: map(device), addr, state }
478 }
479 IpDeviceEvent::EnabledChanged { device, ip_enabled } => {
480 IpDeviceEvent::EnabledChanged { device: map(device), ip_enabled }
481 }
482 IpDeviceEvent::AddressPropertiesChanged {
483 device,
484 addr,
485 valid_until,
486 preferred_lifetime,
487 } => IpDeviceEvent::AddressPropertiesChanged {
488 device: map(device),
489 addr,
490 valid_until,
491 preferred_lifetime,
492 },
493 }
494 }
495}
496
497pub trait IpDeviceBindingsContext<I: IpDeviceIpExt, D: StrongDeviceIdentifier>:
499 IpDeviceStateBindingsTypes
500 + DeferredResourceRemovalContext
501 + TimerContext
502 + RngContext
503 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>
504{
505}
506impl<
507 D: StrongDeviceIdentifier,
508 I: IpDeviceIpExt,
509 BC: IpDeviceStateBindingsTypes
510 + DeferredResourceRemovalContext
511 + TimerContext
512 + RngContext
513 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>,
514 > IpDeviceBindingsContext<I, D> for BC
515{
516}
517
518pub trait IpAddressIdSpec {
523 type WeakV4: WeakIpAddressId<Ipv4Addr>;
525 type WeakV6: WeakIpAddressId<Ipv6Addr>;
527}
528
529pub trait IpAddressIdExt: Ip {
530 type Weak<BT: IpDeviceStateBindingsTypes>: WeakIpAddressId<Self::Addr>;
531}
532
533impl IpAddressIdExt for Ipv4 {
534 type Weak<BT: IpDeviceStateBindingsTypes> = WeakAddressId<Ipv4AddressEntry<BT>>;
535}
536
537impl IpAddressIdExt for Ipv6 {
538 type Weak<BT: IpDeviceStateBindingsTypes> = WeakAddressId<Ipv6AddressEntry<BT>>;
539}
540
541pub trait IpAddressIdSpecContext:
543 IpDeviceAddressIdContext<Ipv4> + IpDeviceAddressIdContext<Ipv6>
544{
545 type AddressIdSpec: IpAddressIdSpec<
547 WeakV4 = <Self as IpDeviceAddressIdContext<Ipv4>>::WeakAddressId,
548 WeakV6 = <Self as IpDeviceAddressIdContext<Ipv6>>::WeakAddressId,
549 >;
550}
551
552pub trait IpDeviceAddressContext<I: IpDeviceIpExt, BT: InstantBindingsTypes>:
554 IpDeviceAddressIdContext<I>
555{
556 fn with_ip_address_state<O, F: FnOnce(&I::AddressState<BT::Instant>) -> O>(
559 &mut self,
560 device_id: &Self::DeviceId,
561 addr_id: &Self::AddressId,
562 cb: F,
563 ) -> O;
564
565 fn with_ip_address_state_mut<O, F: FnOnce(&mut I::AddressState<BT::Instant>) -> O>(
568 &mut self,
569 device_id: &Self::DeviceId,
570 addr_id: &Self::AddressId,
571 cb: F,
572 ) -> O;
573}
574
575pub trait IpDeviceStateContext<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
577 IpDeviceAddressContext<I, BT>
578{
579 type IpDeviceAddressCtx<'a>: IpDeviceAddressContext<
581 I,
582 BT,
583 DeviceId = Self::DeviceId,
584 AddressId = Self::AddressId,
585 >;
586
587 fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
594 &mut self,
595 device_id: &Self::DeviceId,
596 cb: F,
597 ) -> O;
598
599 fn add_ip_address(
601 &mut self,
602 device_id: &Self::DeviceId,
603 addr: AddrSubnet<I::Addr, I::AssignedWitness>,
604 config: I::AddressConfig<BT::Instant>,
605 ) -> Result<Self::AddressId, ExistsError>;
606
607 fn remove_ip_address(
609 &mut self,
610 device_id: &Self::DeviceId,
611 addr: Self::AddressId,
612 ) -> RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BT>;
613
614 fn get_address_id(
616 &mut self,
617 device_id: &Self::DeviceId,
618 addr: SpecifiedAddr<I::Addr>,
619 ) -> Result<Self::AddressId, NotFoundError>;
620
621 type AddressIdsIter<'a>: Iterator<Item = Self::AddressId> + 'a;
623
624 fn with_address_ids<
627 O,
628 F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
629 >(
630 &mut self,
631 device_id: &Self::DeviceId,
632 cb: F,
633 ) -> O;
634
635 fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
638 &mut self,
639 device_id: &Self::DeviceId,
640 cb: F,
641 ) -> O;
642
643 fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
646 &mut self,
647 device_id: &Self::DeviceId,
648 cb: F,
649 ) -> O;
650
651 fn join_link_multicast_group(
654 &mut self,
655 bindings_ctx: &mut BT,
656 device_id: &Self::DeviceId,
657 multicast_addr: MulticastAddr<I::Addr>,
658 );
659
660 fn leave_link_multicast_group(
663 &mut self,
664 bindings_ctx: &mut BT,
665 device_id: &Self::DeviceId,
666 multicast_addr: MulticastAddr<I::Addr>,
667 );
668}
669
670pub trait WithIpDeviceConfigurationMutInner<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
673 DeviceIdContext<AnyDevice>
674{
675 type IpDeviceStateCtx<'s>: IpDeviceStateContext<I, BT, DeviceId = Self::DeviceId>
677 + GmpHandler<I, BT>
678 + NudIpHandler<I, BT>
679 + 's
680 where
681 Self: 's;
682
683 fn ip_device_configuration_and_ctx(
686 &mut self,
687 ) -> (&I::Configuration, Self::IpDeviceStateCtx<'_>);
688
689 fn with_configuration_and_flags_mut<
692 O,
693 F: FnOnce(&mut I::Configuration, &mut IpDeviceFlags) -> O,
694 >(
695 &mut self,
696 device_id: &Self::DeviceId,
697 cb: F,
698 ) -> O;
699}
700
701pub trait IpDeviceConfigurationContext<
703 I: IpDeviceIpExt,
704 BC: IpDeviceBindingsContext<I, Self::DeviceId>,
705>: IpDeviceStateContext<I, BC> + IpDeviceMtuContext<I> + DeviceIdContext<AnyDevice>
706{
707 type DevicesIter<'s>: Iterator<Item = Self::DeviceId> + 's;
709 type WithIpDeviceConfigurationInnerCtx<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
711 + GmpHandler<I, BC>
712 + NudIpHandler<I, BC>
713 + DadHandler<I, BC>
714 + IpAddressRemovalHandler<I, BC>
715 + IpDeviceMtuContext<I>
716 + 's;
717 type WithIpDeviceConfigurationMutInner<'s>: WithIpDeviceConfigurationMutInner<I, BC, DeviceId = Self::DeviceId>
719 + 's;
720 type DeviceAddressAndGroupsAccessor<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId>
722 + 's;
723
724 fn with_ip_device_configuration<
727 O,
728 F: FnOnce(&I::Configuration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
729 >(
730 &mut self,
731 device_id: &Self::DeviceId,
732 cb: F,
733 ) -> O;
734
735 fn with_ip_device_configuration_mut<
737 O,
738 F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
739 >(
740 &mut self,
741 device_id: &Self::DeviceId,
742 cb: F,
743 ) -> O;
744
745 fn with_devices_and_state<
748 O,
749 F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
750 >(
751 &mut self,
752 cb: F,
753 ) -> O;
754
755 fn loopback_id(&mut self) -> Option<Self::DeviceId>;
758}
759
760pub trait WithIpv6DeviceConfigurationMutInner<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
763 WithIpDeviceConfigurationMutInner<Ipv6, BC>
764{
765 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId>
767 + GmpHandler<Ipv6, BC>
768 + NudIpHandler<Ipv6, BC>
769 + DadHandler<Ipv6, BC>
770 + RsHandler<BC>
771 + SlaacHandler<BC>
772 + RouteDiscoveryHandler<BC>
773 + 's
774 where
775 Self: 's;
776
777 fn ipv6_device_configuration_and_ctx(
780 &mut self,
781 ) -> (&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>);
782}
783
784pub trait Ipv6DeviceConfigurationContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
786 IpDeviceConfigurationContext<Ipv6, BC>
787{
788 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
790 + GmpHandler<Ipv6, BC>
791 + MldPacketHandler<BC, Self::DeviceId>
792 + NudIpHandler<Ipv6, BC>
793 + DadHandler<Ipv6, BC>
794 + RsHandler<BC>
795 + SlaacHandler<BC>
796 + RouteDiscoveryHandler<BC>
797 + 's;
798 type WithIpv6DeviceConfigurationMutInner<'s>: WithIpv6DeviceConfigurationMutInner<BC, DeviceId = Self::DeviceId>
800 + 's;
801
802 fn with_ipv6_device_configuration<
805 O,
806 F: FnOnce(&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) -> O,
807 >(
808 &mut self,
809 device_id: &Self::DeviceId,
810 cb: F,
811 ) -> O;
812
813 fn with_ipv6_device_configuration_mut<
815 O,
816 F: FnOnce(Self::WithIpv6DeviceConfigurationMutInner<'_>) -> O,
817 >(
818 &mut self,
819 device_id: &Self::DeviceId,
820 cb: F,
821 ) -> O;
822}
823
824pub trait Ipv6LinkLayerAddr {
826 fn as_bytes(&self) -> &[u8];
828
829 fn eui64_iid(&self) -> [u8; 8];
831}
832
833pub trait Ipv6DeviceContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
835 IpDeviceStateContext<Ipv6, BC>
836{
837 type LinkLayerAddr: Ipv6LinkLayerAddr;
839
840 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
843
844 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
846
847 fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
849 &mut self,
850 device_id: &Self::DeviceId,
851 cb: F,
852 ) -> O;
853
854 fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
856 &mut self,
857 device_id: &Self::DeviceId,
858 cb: F,
859 ) -> O;
860}
861
862pub trait IpDeviceHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
864 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool;
865
866 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8);
867}
868
869impl<
870 I: IpDeviceIpExt,
871 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
872 CC: IpDeviceConfigurationContext<I, BC>,
873 > IpDeviceHandler<I, BC> for CC
874{
875 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool {
876 is_ip_unicast_forwarding_enabled(self, device_id)
877 }
878
879 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8) {
880 self.with_default_hop_limit_mut(device_id, |default_hop_limit| {
881 *default_hop_limit = hop_limit
882 })
883 }
884}
885
886pub fn receive_igmp_packet<CC, BC, B, H>(
888 core_ctx: &mut CC,
889 bindings_ctx: &mut BC,
890 device: &CC::DeviceId,
891 src_ip: Ipv4Addr,
892 dst_ip: SpecifiedAddr<Ipv4Addr>,
893 buffer: B,
894 info: &LocalDeliveryPacketInfo<Ipv4, H>,
895) where
896 CC: IpDeviceConfigurationContext<Ipv4, BC>,
897 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
898 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>: IpDeviceStateContext<Ipv4, BC, DeviceId = CC::DeviceId>
899 + IgmpPacketHandler<BC, CC::DeviceId>,
900 B: BufferMut,
901 H: IpHeaderInfo<Ipv4>,
902{
903 core_ctx.with_ip_device_configuration(device, |_config, mut core_ctx| {
904 IgmpPacketHandler::receive_igmp_packet(
905 &mut core_ctx,
906 bindings_ctx,
907 device,
908 src_ip,
909 dst_ip,
910 buffer,
911 info,
912 )
913 })
914}
915
916pub trait Ipv6DeviceHandler<BC>: IpDeviceHandler<Ipv6, BC> {
918 type LinkLayerAddr: Ipv6LinkLayerAddr;
920
921 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
924
925 fn set_discovered_retrans_timer(
927 &mut self,
928 bindings_ctx: &mut BC,
929 device_id: &Self::DeviceId,
930 retrans_timer: NonZeroDuration,
931 );
932
933 fn handle_received_dad_neighbor_solicitation(
941 &mut self,
942 bindings_ctx: &mut BC,
943 device_id: &Self::DeviceId,
944 addr: UnicastAddr<Ipv6Addr>,
945 nonce: Option<NdpNonce<&'_ [u8]>>,
946 ) -> IpAddressState;
947
948 fn handle_received_neighbor_advertisement(
957 &mut self,
958 bindings_ctx: &mut BC,
959 device_id: &Self::DeviceId,
960 addr: UnicastAddr<Ipv6Addr>,
961 ) -> IpAddressState;
962
963 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
965
966 fn update_discovered_ipv6_route(
968 &mut self,
969 bindings_ctx: &mut BC,
970 device_id: &Self::DeviceId,
971 route: Ipv6DiscoveredRoute,
972 lifetime: Option<NonZeroNdpLifetime>,
973 );
974
975 fn apply_slaac_update(
977 &mut self,
978 bindings_ctx: &mut BC,
979 device_id: &Self::DeviceId,
980 prefix: Subnet<Ipv6Addr>,
981 preferred_lifetime: Option<NonZeroNdpLifetime>,
982 valid_lifetime: Option<NonZeroNdpLifetime>,
983 );
984
985 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
987 &mut self,
988 bindings_ctx: &mut BC,
989 device: &Self::DeviceId,
990 src_ip: Ipv6SourceAddr,
991 dst_ip: SpecifiedAddr<Ipv6Addr>,
992 packet: MldPacket<B>,
993 header_info: &H,
994 );
995}
996
997impl<
998 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
999 CC: Ipv6DeviceContext<BC>
1000 + Ipv6DeviceConfigurationContext<BC>
1001 + CounterContext<IpCounters<Ipv6>>,
1002 > Ipv6DeviceHandler<BC> for CC
1003{
1004 type LinkLayerAddr = CC::LinkLayerAddr;
1005
1006 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<CC::LinkLayerAddr> {
1007 Ipv6DeviceContext::get_link_layer_addr(self, device_id)
1008 }
1009
1010 fn set_discovered_retrans_timer(
1011 &mut self,
1012 _bindings_ctx: &mut BC,
1013 device_id: &Self::DeviceId,
1014 retrans_timer: NonZeroDuration,
1015 ) {
1016 self.with_network_learned_parameters_mut(device_id, |state| {
1017 state.retrans_timer = Some(retrans_timer)
1018 })
1019 }
1020
1021 fn handle_received_dad_neighbor_solicitation(
1022 &mut self,
1023 bindings_ctx: &mut BC,
1024 device_id: &Self::DeviceId,
1025 addr: UnicastAddr<Ipv6Addr>,
1026 nonce: Option<NdpNonce<&'_ [u8]>>,
1027 ) -> IpAddressState {
1028 let addr_id = match self.get_address_id(device_id, addr.into_specified()) {
1029 Ok(o) => o,
1030 Err(NotFoundError) => return IpAddressState::Unavailable,
1031 };
1032
1033 match self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1034 core_ctx.handle_incoming_dad_neighbor_solicitation(
1035 bindings_ctx,
1036 device_id,
1037 &addr_id,
1038 nonce,
1039 )
1040 }) {
1041 DadAddressStateLookupResult::Assigned => IpAddressState::Assigned,
1042 DadAddressStateLookupResult::Tentative { matched_nonce: true } => {
1043 self.counters().version_rx.drop_looped_back_dad_probe.increment();
1044
1045 IpAddressState::Tentative
1054 }
1055 DadAddressStateLookupResult::Uninitialized
1056 | DadAddressStateLookupResult::Tentative { matched_nonce: false } => {
1057 match del_ip_addr(
1065 self,
1066 bindings_ctx,
1067 device_id,
1068 DelIpAddr::AddressId(addr_id),
1069 AddressRemovedReason::DadFailed,
1070 ) {
1071 Ok(result) => {
1072 bindings_ctx.defer_removal_result(result);
1073 IpAddressState::Tentative
1074 }
1075 Err(NotFoundError) => {
1076 IpAddressState::Unavailable
1078 }
1079 }
1080 }
1081 }
1082 }
1083
1084 fn handle_received_neighbor_advertisement(
1085 &mut self,
1086 bindings_ctx: &mut BC,
1087 device_id: &Self::DeviceId,
1088 addr: UnicastAddr<Ipv6Addr>,
1089 ) -> IpAddressState {
1090 let addr_id = match self.get_address_id(device_id, addr.into_specified()) {
1091 Ok(o) => o,
1092 Err(NotFoundError) => return IpAddressState::Unavailable,
1093 };
1094
1095 let assigned = self.with_ip_address_state(
1096 device_id,
1097 &addr_id,
1098 |Ipv6AddressState { flags: Ipv6AddressFlags { assigned }, config: _ }| *assigned,
1099 );
1100
1101 if assigned {
1102 IpAddressState::Assigned
1103 } else {
1104 match del_ip_addr(
1105 self,
1106 bindings_ctx,
1107 device_id,
1108 DelIpAddr::AddressId(addr_id),
1109 AddressRemovedReason::DadFailed,
1110 ) {
1111 Ok(result) => {
1112 bindings_ctx.defer_removal_result(result);
1113 IpAddressState::Tentative
1114 }
1115 Err(NotFoundError) => {
1116 IpAddressState::Unavailable
1118 }
1119 }
1120 }
1121 }
1122
1123 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
1124 Ipv6DeviceContext::set_link_mtu(self, device_id, mtu)
1125 }
1126
1127 fn update_discovered_ipv6_route(
1128 &mut self,
1129 bindings_ctx: &mut BC,
1130 device_id: &Self::DeviceId,
1131 route: Ipv6DiscoveredRoute,
1132 lifetime: Option<NonZeroNdpLifetime>,
1133 ) {
1134 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1135 RouteDiscoveryHandler::update_route(
1136 &mut core_ctx,
1137 bindings_ctx,
1138 device_id,
1139 route,
1140 lifetime,
1141 )
1142 })
1143 }
1144
1145 fn apply_slaac_update(
1146 &mut self,
1147 bindings_ctx: &mut BC,
1148 device_id: &Self::DeviceId,
1149 prefix: Subnet<Ipv6Addr>,
1150 preferred_lifetime: Option<NonZeroNdpLifetime>,
1151 valid_lifetime: Option<NonZeroNdpLifetime>,
1152 ) {
1153 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1154 SlaacHandler::apply_slaac_update(
1155 &mut core_ctx,
1156 bindings_ctx,
1157 device_id,
1158 prefix,
1159 preferred_lifetime,
1160 valid_lifetime,
1161 )
1162 })
1163 }
1164
1165 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
1166 &mut self,
1167 bindings_ctx: &mut BC,
1168 device: &Self::DeviceId,
1169 src_ip: Ipv6SourceAddr,
1170 dst_ip: SpecifiedAddr<Ipv6Addr>,
1171 packet: MldPacket<B>,
1172 header_info: &H,
1173 ) {
1174 self.with_ipv6_device_configuration(device, |_config, mut core_ctx| {
1175 MldPacketHandler::receive_mld_packet(
1176 &mut core_ctx,
1177 bindings_ctx,
1178 device,
1179 src_ip,
1180 dst_ip,
1181 packet,
1182 header_info,
1183 )
1184 })
1185 }
1186}
1187
1188pub trait IpDeviceSendContext<I: IpExt, BC: TxMetadataBindingsTypes>:
1190 DeviceIdContext<AnyDevice>
1191{
1192 fn send_ip_frame<S>(
1194 &mut self,
1195 bindings_ctx: &mut BC,
1196 device_id: &Self::DeviceId,
1197 destination: IpPacketDestination<I, &Self::DeviceId>,
1198 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
1199 body: S,
1200 egress_proof: ProofOfEgressCheck,
1201 ) -> Result<(), SendFrameError<S>>
1202 where
1203 S: Serializer,
1204 S::Buffer: BufferMut;
1205}
1206
1207fn enable_ipv6_device_with_config<
1208 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1209 CC: Ipv6DeviceContext<BC>
1210 + GmpHandler<Ipv6, BC>
1211 + RsHandler<BC>
1212 + DadHandler<Ipv6, BC>
1213 + SlaacHandler<BC>,
1214>(
1215 core_ctx: &mut CC,
1216 bindings_ctx: &mut BC,
1217 device_id: &CC::DeviceId,
1218 config: &Ipv6DeviceConfiguration,
1219) {
1220 join_ip_multicast_with_config(
1222 core_ctx,
1223 bindings_ctx,
1224 device_id,
1225 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1226 config,
1227 );
1228 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1229
1230 core_ctx
1237 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1238 .into_iter()
1239 .for_each(|addr_id| {
1240 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1241 device: device_id.clone(),
1242 addr: addr_id.addr().into(),
1243 state: IpAddressState::Tentative,
1244 });
1245 DadHandler::start_duplicate_address_detection(
1246 core_ctx,
1247 bindings_ctx,
1248 device_id,
1249 &addr_id,
1250 );
1251 });
1252
1253 if core_ctx.get_link_layer_addr(device_id).is_some() {
1256 SlaacHandler::generate_link_local_address(core_ctx, bindings_ctx, device_id);
1257 }
1258
1259 RsHandler::start_router_solicitation(core_ctx, bindings_ctx, device_id);
1260}
1261
1262fn disable_ipv6_device_with_config<
1263 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1264 CC: Ipv6DeviceContext<BC>
1265 + GmpHandler<Ipv6, BC>
1266 + RsHandler<BC>
1267 + DadHandler<Ipv6, BC>
1268 + RouteDiscoveryHandler<BC>
1269 + SlaacHandler<BC>
1270 + NudIpHandler<Ipv6, BC>,
1271>(
1272 core_ctx: &mut CC,
1273 bindings_ctx: &mut BC,
1274 device_id: &CC::DeviceId,
1275 device_config: &Ipv6DeviceConfiguration,
1276) {
1277 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1278
1279 SlaacHandler::remove_all_slaac_addresses(core_ctx, bindings_ctx, device_id);
1280
1281 RouteDiscoveryHandler::invalidate_routes(core_ctx, bindings_ctx, device_id);
1282
1283 RsHandler::stop_router_solicitation(core_ctx, bindings_ctx, device_id);
1284
1285 core_ctx
1288 .with_address_ids(device_id, |addrs, core_ctx| {
1289 addrs
1290 .map(|addr_id| {
1291 core_ctx.with_ip_address_state(
1292 device_id,
1293 &addr_id,
1294 |Ipv6AddressState { flags: _, config }| (addr_id.clone(), *config),
1295 )
1296 })
1297 .collect::<Vec<_>>()
1298 })
1299 .into_iter()
1300 .for_each(|(addr_id, config)| {
1301 if config
1302 .is_some_and(|config| config.is_slaac() && addr_id.addr().addr().is_link_local())
1303 {
1304 del_ip_addr_inner_and_notify_handler(
1305 core_ctx,
1306 bindings_ctx,
1307 device_id,
1308 DelIpAddr::AddressId(addr_id),
1309 AddressRemovedReason::Manual,
1310 device_config,
1311 )
1312 .map(|remove_result| {
1313 bindings_ctx.defer_removal_result(remove_result);
1314 })
1315 .unwrap_or_else(|NotFoundError| {
1316 })
1320 } else {
1321 DadHandler::stop_duplicate_address_detection(
1322 core_ctx,
1323 bindings_ctx,
1324 device_id,
1325 &addr_id,
1326 );
1327 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1328 device: device_id.clone(),
1329 addr: addr_id.addr().into(),
1330 state: IpAddressState::Unavailable,
1331 });
1332 }
1333 });
1334
1335 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1336 leave_ip_multicast_with_config(
1337 core_ctx,
1338 bindings_ctx,
1339 device_id,
1340 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1341 device_config,
1342 );
1343}
1344
1345fn enable_ipv4_device_with_config<
1346 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1347 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC>,
1348>(
1349 core_ctx: &mut CC,
1350 bindings_ctx: &mut BC,
1351 device_id: &CC::DeviceId,
1352 config: &Ipv4DeviceConfiguration,
1353) {
1354 join_ip_multicast_with_config(
1356 core_ctx,
1357 bindings_ctx,
1358 device_id,
1359 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1360 config,
1361 );
1362 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1363 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1364 addrs.for_each(|addr| {
1365 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1366 device: device_id.clone(),
1367 addr: addr.addr().into(),
1368 state: IpAddressState::Assigned,
1369 });
1370 })
1371 })
1372}
1373
1374fn disable_ipv4_device_with_config<
1375 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1376 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC> + NudIpHandler<Ipv4, BC>,
1377>(
1378 core_ctx: &mut CC,
1379 bindings_ctx: &mut BC,
1380 device_id: &CC::DeviceId,
1381 config: &Ipv4DeviceConfiguration,
1382) {
1383 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1384 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1385 leave_ip_multicast_with_config(
1386 core_ctx,
1387 bindings_ctx,
1388 device_id,
1389 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1390 config,
1391 );
1392 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1393 addrs.for_each(|addr| {
1394 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1395 device: device_id.clone(),
1396 addr: addr.addr().into(),
1397 state: IpAddressState::Unavailable,
1398 });
1399 })
1400 })
1401}
1402
1403pub fn get_ipv4_addr_subnet<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv4, BT>>(
1405 core_ctx: &mut CC,
1406 device_id: &CC::DeviceId,
1407) -> Option<AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> {
1408 core_ctx.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next().map(|a| a.addr_sub()))
1409}
1410
1411pub fn get_ipv6_hop_limit<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv6, BT>>(
1413 core_ctx: &mut CC,
1414 device: &CC::DeviceId,
1415) -> NonZeroU8 {
1416 core_ctx.with_default_hop_limit(device, Clone::clone)
1417}
1418
1419pub fn is_ip_unicast_forwarding_enabled<
1421 I: IpDeviceIpExt,
1422 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1423 CC: IpDeviceConfigurationContext<I, BC>,
1424>(
1425 core_ctx: &mut CC,
1426 device_id: &CC::DeviceId,
1427) -> bool {
1428 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1429 AsRef::<IpDeviceConfiguration>::as_ref(state).unicast_forwarding_enabled
1430 })
1431}
1432
1433pub fn is_ip_multicast_forwarding_enabled<
1435 I: IpDeviceIpExt,
1436 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1437 CC: IpDeviceConfigurationContext<I, BC>,
1438>(
1439 core_ctx: &mut CC,
1440 device_id: &CC::DeviceId,
1441) -> bool {
1442 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1443 AsRef::<IpDeviceConfiguration>::as_ref(state).multicast_forwarding_enabled
1444 })
1445}
1446
1447pub fn join_ip_multicast_with_config<
1454 I: IpDeviceIpExt,
1455 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1456 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1457>(
1458 core_ctx: &mut CC,
1459 bindings_ctx: &mut BC,
1460 device_id: &CC::DeviceId,
1461 multicast_addr: MulticastAddr<I::Addr>,
1462 _config: &I::Configuration,
1463) {
1464 match core_ctx.gmp_join_group(bindings_ctx, device_id, multicast_addr) {
1465 GroupJoinResult::Joined(()) => {
1466 core_ctx.join_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1467 }
1468 GroupJoinResult::AlreadyMember => {}
1469 }
1470}
1471
1472pub fn join_ip_multicast<
1483 I: IpDeviceIpExt,
1484 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1485 CC: IpDeviceConfigurationContext<I, BC>,
1486>(
1487 core_ctx: &mut CC,
1488 bindings_ctx: &mut BC,
1489 device_id: &CC::DeviceId,
1490 multicast_addr: MulticastAddr<I::Addr>,
1491) {
1492 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1493 join_ip_multicast_with_config(
1494 &mut core_ctx,
1495 bindings_ctx,
1496 device_id,
1497 multicast_addr,
1498 config,
1499 )
1500 })
1501}
1502
1503pub fn leave_ip_multicast_with_config<
1510 I: IpDeviceIpExt,
1511 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1512 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1513>(
1514 core_ctx: &mut CC,
1515 bindings_ctx: &mut BC,
1516 device_id: &CC::DeviceId,
1517 multicast_addr: MulticastAddr<I::Addr>,
1518 _config: &I::Configuration,
1519) {
1520 match core_ctx.gmp_leave_group(bindings_ctx, device_id, multicast_addr) {
1521 GroupLeaveResult::Left(()) => {
1522 core_ctx.leave_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1523 }
1524 GroupLeaveResult::StillMember => {}
1525 GroupLeaveResult::NotMember => panic!(
1526 "attempted to leave IP multicast group we were not a member of: {}",
1527 multicast_addr,
1528 ),
1529 }
1530}
1531
1532pub fn leave_ip_multicast<
1547 I: IpDeviceIpExt,
1548 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1549 CC: IpDeviceConfigurationContext<I, BC>,
1550>(
1551 core_ctx: &mut CC,
1552 bindings_ctx: &mut BC,
1553 device_id: &CC::DeviceId,
1554 multicast_addr: MulticastAddr<I::Addr>,
1555) {
1556 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1557 leave_ip_multicast_with_config(
1558 &mut core_ctx,
1559 bindings_ctx,
1560 device_id,
1561 multicast_addr,
1562 config,
1563 )
1564 })
1565}
1566
1567pub fn add_ip_addr_subnet_with_config<
1574 I: IpDeviceIpExt,
1575 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1576 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1577>(
1578 core_ctx: &mut CC,
1579 bindings_ctx: &mut BC,
1580 device_id: &CC::DeviceId,
1581 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1582 addr_config: I::AddressConfig<BC::Instant>,
1583 _device_config: &I::Configuration,
1584) -> Result<CC::AddressId, ExistsError> {
1585 info!("adding addr {addr_sub:?} config {addr_config:?} to device {device_id:?}");
1586 let CommonAddressProperties { valid_until, preferred_lifetime } =
1587 I::get_common_props(&addr_config);
1588 let addr_id = core_ctx.add_ip_address(device_id, addr_sub, addr_config)?;
1589 assert_eq!(addr_id.addr().addr(), addr_sub.addr().get());
1590
1591 let ip_enabled =
1592 core_ctx.with_ip_device_flags(device_id, |IpDeviceFlags { ip_enabled }| *ip_enabled);
1593
1594 let state = match ip_enabled {
1595 true => CC::INITIAL_ADDRESS_STATE,
1596 false => IpAddressState::Unavailable,
1597 };
1598
1599 bindings_ctx.on_event(IpDeviceEvent::AddressAdded {
1600 device: device_id.clone(),
1601 addr: addr_sub.to_witness(),
1602 state,
1603 valid_until,
1604 preferred_lifetime,
1605 });
1606
1607 if ip_enabled {
1608 DadHandler::start_duplicate_address_detection(core_ctx, bindings_ctx, device_id, &addr_id)
1611 }
1612
1613 Ok(addr_id)
1614}
1615
1616pub trait IpAddressRemovalHandler<I: IpDeviceIpExt, BC: InstantBindingsTypes>:
1618 DeviceIdContext<AnyDevice>
1619{
1620 fn on_address_removed(
1623 &mut self,
1624 bindings_ctx: &mut BC,
1625 device_id: &Self::DeviceId,
1626 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1627 config: I::AddressConfig<BC::Instant>,
1628 reason: AddressRemovedReason,
1629 );
1630}
1631
1632impl<CC: DeviceIdContext<AnyDevice>, BC: InstantBindingsTypes> IpAddressRemovalHandler<Ipv4, BC>
1634 for CC
1635{
1636 fn on_address_removed(
1637 &mut self,
1638 _bindings_ctx: &mut BC,
1639 _device_id: &Self::DeviceId,
1640 _addr_sub: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
1641 _config: Ipv4AddrConfig<BC::Instant>,
1642 _reason: AddressRemovedReason,
1643 ) {
1644 }
1646}
1647
1648impl<CC: SlaacHandler<BC>, BC: InstantContext> IpAddressRemovalHandler<Ipv6, BC> for CC {
1650 fn on_address_removed(
1651 &mut self,
1652 bindings_ctx: &mut BC,
1653 device_id: &Self::DeviceId,
1654 addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
1655 config: Ipv6AddrConfig<BC::Instant>,
1656 reason: AddressRemovedReason,
1657 ) {
1658 match config {
1659 Ipv6AddrConfig::Slaac(config) => SlaacHandler::on_address_removed(
1660 self,
1661 bindings_ctx,
1662 device_id,
1663 addr_sub,
1664 config,
1665 reason,
1666 ),
1667 Ipv6AddrConfig::Manual(_manual_config) => (),
1668 }
1669 }
1670}
1671
1672#[allow(missing_docs)]
1674pub enum DelIpAddr<Id, A> {
1675 SpecifiedAddr(SpecifiedAddr<A>),
1676 AddressId(Id),
1677}
1678
1679impl<Id: IpAddressId<A>, A: IpAddress<Version: AssignedAddrIpExt>> Display for DelIpAddr<Id, A> {
1680 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1681 match self {
1682 DelIpAddr::SpecifiedAddr(addr) => write!(f, "{}", *addr),
1683 DelIpAddr::AddressId(id) => write!(f, "{}", id.addr()),
1684 }
1685 }
1686}
1687
1688pub fn del_ip_addr_inner<
1691 I: IpDeviceIpExt,
1692 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1693 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1694>(
1695 core_ctx: &mut CC,
1696 bindings_ctx: &mut BC,
1697 device_id: &CC::DeviceId,
1698 addr: DelIpAddr<CC::AddressId, I::Addr>,
1699 reason: AddressRemovedReason,
1700 _config: &I::Configuration,
1702) -> Result<
1703 (
1704 AddrSubnet<I::Addr, I::AssignedWitness>,
1705 I::AddressConfig<BC::Instant>,
1706 RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>,
1707 ),
1708 NotFoundError,
1709> {
1710 let addr_id = match addr {
1711 DelIpAddr::SpecifiedAddr(addr) => core_ctx.get_address_id(device_id, addr)?,
1712 DelIpAddr::AddressId(id) => id,
1713 };
1714 DadHandler::stop_duplicate_address_detection(core_ctx, bindings_ctx, device_id, &addr_id);
1715 let addr_config = core_ctx
1719 .with_ip_address_state_mut(device_id, &addr_id, |addr_state| {
1720 I::take_addr_config_for_removal(addr_state)
1721 })
1722 .ok_or(NotFoundError)?;
1723
1724 let addr_sub = addr_id.addr_sub();
1725 let result = core_ctx.remove_ip_address(device_id, addr_id);
1726
1727 bindings_ctx.on_event(IpDeviceEvent::AddressRemoved {
1728 device: device_id.clone(),
1729 addr: addr_sub.addr().into(),
1730 reason,
1731 });
1732
1733 Ok((addr_sub, addr_config, result))
1734}
1735
1736fn del_ip_addr<
1738 I: IpDeviceIpExt,
1739 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1740 CC: IpDeviceConfigurationContext<I, BC>,
1741>(
1742 core_ctx: &mut CC,
1743 bindings_ctx: &mut BC,
1744 device_id: &CC::DeviceId,
1745 addr: DelIpAddr<CC::AddressId, I::Addr>,
1746 reason: AddressRemovedReason,
1747) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1748 info!("removing addr {addr} from device {device_id:?}");
1749 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1750 del_ip_addr_inner_and_notify_handler(
1751 &mut core_ctx,
1752 bindings_ctx,
1753 device_id,
1754 addr,
1755 reason,
1756 config,
1757 )
1758 })
1759}
1760
1761fn del_ip_addr_inner_and_notify_handler<
1764 I: IpDeviceIpExt,
1765 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1766 CC: IpDeviceStateContext<I, BC>
1767 + GmpHandler<I, BC>
1768 + DadHandler<I, BC>
1769 + IpAddressRemovalHandler<I, BC>,
1770>(
1771 core_ctx: &mut CC,
1772 bindings_ctx: &mut BC,
1773 device_id: &CC::DeviceId,
1774 addr: DelIpAddr<CC::AddressId, I::Addr>,
1775 reason: AddressRemovedReason,
1776 config: &I::Configuration,
1777) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1778 del_ip_addr_inner(core_ctx, bindings_ctx, device_id, addr, reason, config).map(
1779 |(addr_sub, config, result)| {
1780 core_ctx.on_address_removed(bindings_ctx, device_id, addr_sub, config, reason);
1781 result
1782 },
1783 )
1784}
1785
1786pub fn is_ip_device_enabled<
1788 I: IpDeviceIpExt,
1789 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1790 CC: IpDeviceStateContext<I, BC>,
1791>(
1792 core_ctx: &mut CC,
1793 device_id: &CC::DeviceId,
1794) -> bool {
1795 core_ctx.with_ip_device_flags(device_id, |flags| flags.ip_enabled)
1796}
1797
1798pub fn clear_ipv4_device_state<
1800 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1801 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1802>(
1803 core_ctx: &mut CC,
1804 bindings_ctx: &mut BC,
1805 device_id: &CC::DeviceId,
1806) {
1807 core_ctx.with_ip_device_configuration_mut(device_id, |mut core_ctx| {
1808 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1809 let IpDeviceFlags { ip_enabled } = flags;
1812 core::mem::replace(ip_enabled, false)
1813 });
1814
1815 let (config, mut core_ctx) = core_ctx.ip_device_configuration_and_ctx();
1816 let core_ctx = &mut core_ctx;
1817 if ip_enabled {
1818 disable_ipv4_device_with_config(core_ctx, bindings_ctx, device_id, config);
1819 }
1820 })
1821}
1822
1823pub fn clear_ipv6_device_state<
1825 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1826 CC: Ipv6DeviceConfigurationContext<BC>,
1827>(
1828 core_ctx: &mut CC,
1829 bindings_ctx: &mut BC,
1830 device_id: &CC::DeviceId,
1831) {
1832 core_ctx.with_ipv6_device_configuration_mut(device_id, |mut core_ctx| {
1833 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1834 let IpDeviceFlags { ip_enabled } = flags;
1837 core::mem::replace(ip_enabled, false)
1838 });
1839
1840 let (config, mut core_ctx) = core_ctx.ipv6_device_configuration_and_ctx();
1841 let core_ctx = &mut core_ctx;
1842 if ip_enabled {
1843 disable_ipv6_device_with_config(core_ctx, bindings_ctx, device_id, config);
1844 }
1845 })
1846}
1847
1848#[cfg(any(test, feature = "testutils"))]
1849pub(crate) mod testutil {
1850 use alloc::boxed::Box;
1851
1852 use super::*;
1853
1854 pub fn with_assigned_ipv4_addr_subnets<
1857 BT: IpDeviceStateBindingsTypes,
1858 CC: IpDeviceStateContext<Ipv4, BT>,
1859 O,
1860 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> + '_>) -> O,
1861 >(
1862 core_ctx: &mut CC,
1863 device_id: &CC::DeviceId,
1864 cb: F,
1865 ) -> O {
1866 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1867 cb(Box::new(addrs.map(|a| a.addr_sub())))
1868 })
1869 }
1870
1871 pub fn with_assigned_ipv6_addr_subnets<
1883 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1884 CC: Ipv6DeviceContext<BC>,
1885 O,
1886 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>> + '_>) -> O,
1887 >(
1888 core_ctx: &mut CC,
1889 device_id: &CC::DeviceId,
1890 cb: F,
1891 ) -> O {
1892 core_ctx.with_address_ids(device_id, |addrs, core_ctx| {
1893 cb(Box::new(addrs.filter_map(|addr_id| {
1894 core_ctx
1895 .with_ip_address_state(
1896 device_id,
1897 &addr_id,
1898 |Ipv6AddressState { flags: Ipv6AddressFlags { assigned }, config: _ }| {
1899 *assigned
1900 },
1901 )
1902 .then(|| addr_id.addr_sub())
1903 })))
1904 })
1905 }
1906}