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::{DeviceIpLayerMetadata, IpDeviceMtuContext, IpPacketDestination};
47use crate::internal::counters::IpCounters;
48use crate::internal::device::config::{
49 IpDeviceConfigurationUpdate, Ipv4DeviceConfigurationUpdate, Ipv6DeviceConfigurationUpdate,
50};
51use crate::internal::device::dad::{DadAddressStateLookupResult, DadHandler, DadTimerId};
52use crate::internal::device::nud::NudIpHandler;
53use crate::internal::device::route_discovery::{
54 Ipv6DiscoveredRoute, Ipv6DiscoveredRouteTimerId, RouteDiscoveryHandler,
55};
56use crate::internal::device::router_solicitation::{RsHandler, RsTimerId};
57use crate::internal::device::slaac::{SlaacHandler, SlaacTimerId};
58use crate::internal::device::state::{
59 IpDeviceConfiguration, IpDeviceFlags, IpDeviceState, IpDeviceStateBindingsTypes,
60 IpDeviceStateIpExt, Ipv4AddrConfig, Ipv4AddressEntry, Ipv4AddressState,
61 Ipv4DeviceConfiguration, Ipv4DeviceState, Ipv6AddrConfig, Ipv6AddrManualConfig,
62 Ipv6AddressEntry, Ipv6AddressFlags, Ipv6AddressState, Ipv6DeviceConfiguration, Ipv6DeviceState,
63 Ipv6NetworkLearnedParameters, Lifetime, PreferredLifetime, WeakAddressId,
64};
65use crate::internal::gmp::igmp::{IgmpPacketHandler, IgmpTimerId};
66use crate::internal::gmp::mld::{MldPacketHandler, MldTimerId};
67use crate::internal::gmp::{self, GmpHandler, GroupJoinResult, GroupLeaveResult};
68use crate::internal::local_delivery::{IpHeaderInfo, LocalDeliveryPacketInfo};
69
70#[derive(Derivative, GenericOverIp)]
77#[derivative(
78 Clone(bound = ""),
79 Eq(bound = ""),
80 PartialEq(bound = ""),
81 Hash(bound = ""),
82 Debug(bound = "")
83)]
84#[generic_over_ip(I, Ip)]
85pub struct IpDeviceTimerId<I: IpDeviceIpExt, D: WeakDeviceIdentifier, A: IpAddressIdSpec>(
86 I::Timer<D, A>,
87);
88
89#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
91pub struct Ipv4DeviceTimerId<D: WeakDeviceIdentifier>(IgmpTimerId<D>);
92
93impl<D: WeakDeviceIdentifier> Ipv4DeviceTimerId<D> {
94 fn device_id(&self) -> Option<D::Strong> {
96 let Self(this) = self;
97 this.device_id().upgrade()
98 }
99
100 pub fn into_common<S: IpAddressIdSpec>(self) -> IpDeviceTimerId<Ipv4, D, S> {
102 self.into()
103 }
104}
105
106impl<D: WeakDeviceIdentifier, A: IpAddressIdSpec> From<IpDeviceTimerId<Ipv4, D, A>>
107 for Ipv4DeviceTimerId<D>
108{
109 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv4, D, A>) -> Self {
110 inner
111 }
112}
113
114impl<D: WeakDeviceIdentifier, A: IpAddressIdSpec> From<Ipv4DeviceTimerId<D>>
115 for IpDeviceTimerId<Ipv4, D, A>
116{
117 fn from(value: Ipv4DeviceTimerId<D>) -> Self {
118 Self(value)
119 }
120}
121
122impl<D: WeakDeviceIdentifier> From<IgmpTimerId<D>> for Ipv4DeviceTimerId<D> {
123 fn from(id: IgmpTimerId<D>) -> Ipv4DeviceTimerId<D> {
124 Ipv4DeviceTimerId(id)
125 }
126}
127
128impl<D: WeakDeviceIdentifier, BC: TimerBindingsTypes, CC: TimerHandler<BC, IgmpTimerId<D>>>
129 HandleableTimer<CC, BC> for Ipv4DeviceTimerId<D>
130{
131 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
132 let Self(id) = self;
133 core_ctx.handle_timer(bindings_ctx, id, timer);
134 }
135}
136
137impl<I, CC, BC, A> HandleableTimer<CC, BC> for IpDeviceTimerId<I, CC::WeakDeviceId, A>
138where
139 I: IpDeviceIpExt,
140 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
141 CC: IpDeviceConfigurationContext<I, BC>,
142 A: IpAddressIdSpec,
143 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>:
144 TimerHandler<BC, I::Timer<CC::WeakDeviceId, A>>,
145{
146 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
147 let Self(id) = self;
148 let Some(device_id) = I::timer_device_id(&id) else {
149 return;
150 };
151 core_ctx.with_ip_device_configuration(&device_id, |_state, mut core_ctx| {
152 TimerHandler::handle_timer(&mut core_ctx, bindings_ctx, id, timer)
153 })
154 }
155}
156
157#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
159#[allow(missing_docs)]
160pub enum Ipv6DeviceTimerId<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> {
161 Mld(MldTimerId<D>),
162 Dad(DadTimerId<D, A>),
163 Rs(RsTimerId<D>),
164 RouteDiscovery(Ipv6DiscoveredRouteTimerId<D>),
165 Slaac(SlaacTimerId<D>),
166}
167
168impl<D: WeakDeviceIdentifier, A: IpAddressIdSpec> From<IpDeviceTimerId<Ipv6, D, A>>
169 for Ipv6DeviceTimerId<D, A::WeakV6>
170{
171 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv6, D, A>) -> Self {
172 inner
173 }
174}
175
176impl<D: WeakDeviceIdentifier, A: IpAddressIdSpec> From<Ipv6DeviceTimerId<D, A::WeakV6>>
177 for IpDeviceTimerId<Ipv6, D, A>
178{
179 fn from(value: Ipv6DeviceTimerId<D, A::WeakV6>) -> Self {
180 Self(value)
181 }
182}
183
184impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> Ipv6DeviceTimerId<D, A> {
185 fn device_id(&self) -> Option<D::Strong> {
187 match self {
188 Self::Mld(id) => id.device_id(),
189 Self::Dad(id) => id.device_id(),
190 Self::Rs(id) => id.device_id(),
191 Self::RouteDiscovery(id) => id.device_id(),
192 Self::Slaac(id) => id.device_id(),
193 }
194 .upgrade()
195 }
196
197 pub fn into_common<S: IpAddressIdSpec<WeakV6 = A>>(self) -> IpDeviceTimerId<Ipv6, D, S> {
199 self.into()
200 }
201}
202
203impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<MldTimerId<D>>
204 for Ipv6DeviceTimerId<D, A>
205{
206 fn from(id: MldTimerId<D>) -> Ipv6DeviceTimerId<D, A> {
207 Ipv6DeviceTimerId::Mld(id)
208 }
209}
210
211impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<DadTimerId<D, A>>
212 for Ipv6DeviceTimerId<D, A>
213{
214 fn from(id: DadTimerId<D, A>) -> Ipv6DeviceTimerId<D, A> {
215 Ipv6DeviceTimerId::Dad(id)
216 }
217}
218
219impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<RsTimerId<D>>
220 for Ipv6DeviceTimerId<D, A>
221{
222 fn from(id: RsTimerId<D>) -> Ipv6DeviceTimerId<D, A> {
223 Ipv6DeviceTimerId::Rs(id)
224 }
225}
226
227impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<Ipv6DiscoveredRouteTimerId<D>>
228 for Ipv6DeviceTimerId<D, A>
229{
230 fn from(id: Ipv6DiscoveredRouteTimerId<D>) -> Ipv6DeviceTimerId<D, A> {
231 Ipv6DeviceTimerId::RouteDiscovery(id)
232 }
233}
234
235impl<D: WeakDeviceIdentifier, A: WeakIpAddressId<Ipv6Addr>> From<SlaacTimerId<D>>
236 for Ipv6DeviceTimerId<D, A>
237{
238 fn from(id: SlaacTimerId<D>) -> Ipv6DeviceTimerId<D, A> {
239 Ipv6DeviceTimerId::Slaac(id)
240 }
241}
242
243impl<
244 D: WeakDeviceIdentifier,
245 A: WeakIpAddressId<Ipv6Addr>,
246 BC: TimerBindingsTypes,
247 CC: TimerHandler<BC, RsTimerId<D>>
248 + TimerHandler<BC, Ipv6DiscoveredRouteTimerId<D>>
249 + TimerHandler<BC, MldTimerId<D>>
250 + TimerHandler<BC, SlaacTimerId<D>>
251 + TimerHandler<BC, DadTimerId<D, A>>,
252 > HandleableTimer<CC, BC> for Ipv6DeviceTimerId<D, A>
253{
254 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
255 match self {
256 Ipv6DeviceTimerId::Mld(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
257 Ipv6DeviceTimerId::Dad(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
258 Ipv6DeviceTimerId::Rs(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
259 Ipv6DeviceTimerId::RouteDiscovery(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
260 Ipv6DeviceTimerId::Slaac(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
261 }
262 }
263}
264
265pub trait IpDeviceIpExt: IpDeviceStateIpExt + AssignedAddrIpExt + gmp::IpExt {
267 type State<BT: IpDeviceStateBindingsTypes>: AsRef<IpDeviceState<Self, BT>>
269 + AsMut<IpDeviceState<Self, BT>>;
270 type Configuration: AsRef<IpDeviceConfiguration>
272 + AsMut<IpDeviceConfiguration>
273 + Clone
274 + Debug
275 + Eq
276 + PartialEq;
277 type Timer<D: WeakDeviceIdentifier, A: IpAddressIdSpec>: Into<IpDeviceTimerId<Self, D, A>>
279 + From<IpDeviceTimerId<Self, D, A>>
280 + Clone
281 + Eq
282 + PartialEq
283 + Debug
284 + Hash;
285 type AddressConfig<I: Instant>: Default + Debug;
287 type ManualAddressConfig<I: Instant>: Default + Debug + Into<Self::AddressConfig<I>>;
289 type AddressState<I: Instant>: 'static + Inspectable;
291 type ConfigurationUpdate: From<IpDeviceConfigurationUpdate>
293 + AsRef<IpDeviceConfigurationUpdate>
294 + Debug;
295
296 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I>;
298
299 fn is_addr_assigned<I: Instant>(addr_state: &Self::AddressState<I>) -> bool;
301
302 fn timer_device_id<D: WeakDeviceIdentifier, A: IpAddressIdSpec>(
304 timer: &Self::Timer<D, A>,
305 ) -> Option<D::Strong>;
306
307 fn take_addr_config_for_removal<I: Instant>(
310 addr_state: &mut Self::AddressState<I>,
311 ) -> Option<Self::AddressConfig<I>>;
312}
313
314impl IpDeviceIpExt for Ipv4 {
315 type State<BT: IpDeviceStateBindingsTypes> = Ipv4DeviceState<BT>;
316 type Configuration = Ipv4DeviceConfiguration;
317 type Timer<D: WeakDeviceIdentifier, A: IpAddressIdSpec> = Ipv4DeviceTimerId<D>;
318 type AddressConfig<I: Instant> = Ipv4AddrConfig<I>;
319 type ManualAddressConfig<I: Instant> = Ipv4AddrConfig<I>;
320 type AddressState<I: Instant> = Ipv4AddressState<I>;
321 type ConfigurationUpdate = Ipv4DeviceConfigurationUpdate;
322
323 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
324 config.properties
325 }
326
327 fn is_addr_assigned<I: Instant>(addr_state: &Ipv4AddressState<I>) -> bool {
328 let Ipv4AddressState { config: _ } = addr_state;
329 true
330 }
331
332 fn timer_device_id<D: WeakDeviceIdentifier, A: IpAddressIdSpec>(
333 timer: &Self::Timer<D, A>,
334 ) -> Option<D::Strong> {
335 timer.device_id()
336 }
337
338 fn take_addr_config_for_removal<I: Instant>(
339 addr_state: &mut Self::AddressState<I>,
340 ) -> Option<Self::AddressConfig<I>> {
341 addr_state.config.take()
342 }
343}
344
345impl IpDeviceIpExt for Ipv6 {
346 type State<BT: IpDeviceStateBindingsTypes> = Ipv6DeviceState<BT>;
347 type Configuration = Ipv6DeviceConfiguration;
348 type Timer<D: WeakDeviceIdentifier, A: IpAddressIdSpec> = Ipv6DeviceTimerId<D, A::WeakV6>;
349 type AddressConfig<I: Instant> = Ipv6AddrConfig<I>;
350 type ManualAddressConfig<I: Instant> = Ipv6AddrManualConfig<I>;
351 type AddressState<I: Instant> = Ipv6AddressState<I>;
352 type ConfigurationUpdate = Ipv6DeviceConfigurationUpdate;
353
354 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
355 CommonAddressProperties {
356 valid_until: config.valid_until(),
357 preferred_lifetime: config.preferred_lifetime(),
358 }
359 }
360
361 fn is_addr_assigned<I: Instant>(addr_state: &Ipv6AddressState<I>) -> bool {
362 addr_state.flags.assigned
363 }
364
365 fn timer_device_id<D: WeakDeviceIdentifier, A: IpAddressIdSpec>(
366 timer: &Self::Timer<D, A>,
367 ) -> Option<D::Strong> {
368 timer.device_id()
369 }
370
371 fn take_addr_config_for_removal<I: Instant>(
372 addr_state: &mut Self::AddressState<I>,
373 ) -> Option<Self::AddressConfig<I>> {
374 addr_state.config.take()
375 }
376}
377#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
379pub enum IpAddressState {
380 Unavailable,
382 Assigned,
385 Tentative,
389}
390
391#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
393pub enum AddressRemovedReason {
394 Manual,
396 DadFailed,
398}
399
400#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
401#[generic_over_ip(I, Ip)]
402pub enum IpDeviceEvent<DeviceId, I: Ip, Instant> {
404 AddressAdded {
406 device: DeviceId,
408 addr: AddrSubnet<I::Addr>,
410 state: IpAddressState,
412 valid_until: Lifetime<Instant>,
414 preferred_lifetime: PreferredLifetime<Instant>,
416 },
417 AddressRemoved {
419 device: DeviceId,
421 addr: SpecifiedAddr<I::Addr>,
423 reason: AddressRemovedReason,
425 },
426 AddressStateChanged {
428 device: DeviceId,
430 addr: SpecifiedAddr<I::Addr>,
432 state: IpAddressState,
434 },
435 AddressPropertiesChanged {
437 device: DeviceId,
439 addr: SpecifiedAddr<I::Addr>,
441 valid_until: Lifetime<Instant>,
443 preferred_lifetime: PreferredLifetime<Instant>,
445 },
446 EnabledChanged {
448 device: DeviceId,
450 ip_enabled: bool,
452 },
453}
454
455impl<DeviceId, I: Ip, Instant> IpDeviceEvent<DeviceId, I, Instant> {
456 pub fn map_device<N, F: FnOnce(DeviceId) -> N>(self, map: F) -> IpDeviceEvent<N, I, Instant> {
458 match self {
459 IpDeviceEvent::AddressAdded {
460 device,
461 addr,
462 state,
463 valid_until,
464 preferred_lifetime,
465 } => IpDeviceEvent::AddressAdded {
466 device: map(device),
467 addr,
468 state,
469 valid_until,
470 preferred_lifetime,
471 },
472 IpDeviceEvent::AddressRemoved { device, addr, reason } => {
473 IpDeviceEvent::AddressRemoved { device: map(device), addr, reason }
474 }
475 IpDeviceEvent::AddressStateChanged { device, addr, state } => {
476 IpDeviceEvent::AddressStateChanged { device: map(device), addr, state }
477 }
478 IpDeviceEvent::EnabledChanged { device, ip_enabled } => {
479 IpDeviceEvent::EnabledChanged { device: map(device), ip_enabled }
480 }
481 IpDeviceEvent::AddressPropertiesChanged {
482 device,
483 addr,
484 valid_until,
485 preferred_lifetime,
486 } => IpDeviceEvent::AddressPropertiesChanged {
487 device: map(device),
488 addr,
489 valid_until,
490 preferred_lifetime,
491 },
492 }
493 }
494}
495
496pub trait IpDeviceBindingsContext<I: IpDeviceIpExt, D: StrongDeviceIdentifier>:
498 IpDeviceStateBindingsTypes
499 + DeferredResourceRemovalContext
500 + TimerContext
501 + RngContext
502 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>
503{
504}
505impl<
506 D: StrongDeviceIdentifier,
507 I: IpDeviceIpExt,
508 BC: IpDeviceStateBindingsTypes
509 + DeferredResourceRemovalContext
510 + TimerContext
511 + RngContext
512 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>,
513 > IpDeviceBindingsContext<I, D> for BC
514{
515}
516
517pub trait IpAddressIdSpec {
522 type WeakV4: WeakIpAddressId<Ipv4Addr>;
524 type WeakV6: WeakIpAddressId<Ipv6Addr>;
526}
527
528pub trait IpAddressIdExt: Ip {
529 type Weak<BT: IpDeviceStateBindingsTypes>: WeakIpAddressId<Self::Addr>;
530}
531
532impl IpAddressIdExt for Ipv4 {
533 type Weak<BT: IpDeviceStateBindingsTypes> = WeakAddressId<Ipv4AddressEntry<BT>>;
534}
535
536impl IpAddressIdExt for Ipv6 {
537 type Weak<BT: IpDeviceStateBindingsTypes> = WeakAddressId<Ipv6AddressEntry<BT>>;
538}
539
540pub trait IpAddressIdSpecContext:
542 IpDeviceAddressIdContext<Ipv4> + IpDeviceAddressIdContext<Ipv6>
543{
544 type AddressIdSpec: IpAddressIdSpec<
546 WeakV4 = <Self as IpDeviceAddressIdContext<Ipv4>>::WeakAddressId,
547 WeakV6 = <Self as IpDeviceAddressIdContext<Ipv6>>::WeakAddressId,
548 >;
549}
550
551pub trait IpDeviceAddressContext<I: IpDeviceIpExt, BT: InstantBindingsTypes>:
553 IpDeviceAddressIdContext<I>
554{
555 fn with_ip_address_state<O, F: FnOnce(&I::AddressState<BT::Instant>) -> O>(
558 &mut self,
559 device_id: &Self::DeviceId,
560 addr_id: &Self::AddressId,
561 cb: F,
562 ) -> O;
563
564 fn with_ip_address_state_mut<O, F: FnOnce(&mut I::AddressState<BT::Instant>) -> O>(
567 &mut self,
568 device_id: &Self::DeviceId,
569 addr_id: &Self::AddressId,
570 cb: F,
571 ) -> O;
572}
573
574pub trait IpDeviceStateContext<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
576 IpDeviceAddressContext<I, BT>
577{
578 type IpDeviceAddressCtx<'a>: IpDeviceAddressContext<
580 I,
581 BT,
582 DeviceId = Self::DeviceId,
583 AddressId = Self::AddressId,
584 >;
585
586 fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
593 &mut self,
594 device_id: &Self::DeviceId,
595 cb: F,
596 ) -> O;
597
598 fn add_ip_address(
600 &mut self,
601 device_id: &Self::DeviceId,
602 addr: AddrSubnet<I::Addr, I::AssignedWitness>,
603 config: I::AddressConfig<BT::Instant>,
604 ) -> Result<Self::AddressId, ExistsError>;
605
606 fn remove_ip_address(
608 &mut self,
609 device_id: &Self::DeviceId,
610 addr: Self::AddressId,
611 ) -> RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BT>;
612
613 fn get_address_id(
615 &mut self,
616 device_id: &Self::DeviceId,
617 addr: SpecifiedAddr<I::Addr>,
618 ) -> Result<Self::AddressId, NotFoundError>;
619
620 type AddressIdsIter<'a>: Iterator<Item = Self::AddressId> + 'a;
622
623 fn with_address_ids<
626 O,
627 F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
628 >(
629 &mut self,
630 device_id: &Self::DeviceId,
631 cb: F,
632 ) -> O;
633
634 fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
637 &mut self,
638 device_id: &Self::DeviceId,
639 cb: F,
640 ) -> O;
641
642 fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
645 &mut self,
646 device_id: &Self::DeviceId,
647 cb: F,
648 ) -> O;
649
650 fn join_link_multicast_group(
653 &mut self,
654 bindings_ctx: &mut BT,
655 device_id: &Self::DeviceId,
656 multicast_addr: MulticastAddr<I::Addr>,
657 );
658
659 fn leave_link_multicast_group(
662 &mut self,
663 bindings_ctx: &mut BT,
664 device_id: &Self::DeviceId,
665 multicast_addr: MulticastAddr<I::Addr>,
666 );
667}
668
669pub trait WithIpDeviceConfigurationMutInner<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
672 DeviceIdContext<AnyDevice>
673{
674 type IpDeviceStateCtx<'s>: IpDeviceStateContext<I, BT, DeviceId = Self::DeviceId>
676 + GmpHandler<I, BT>
677 + NudIpHandler<I, BT>
678 + 's
679 where
680 Self: 's;
681
682 fn ip_device_configuration_and_ctx(
685 &mut self,
686 ) -> (&I::Configuration, Self::IpDeviceStateCtx<'_>);
687
688 fn with_configuration_and_flags_mut<
691 O,
692 F: FnOnce(&mut I::Configuration, &mut IpDeviceFlags) -> O,
693 >(
694 &mut self,
695 device_id: &Self::DeviceId,
696 cb: F,
697 ) -> O;
698}
699
700pub trait IpDeviceConfigurationContext<
702 I: IpDeviceIpExt,
703 BC: IpDeviceBindingsContext<I, Self::DeviceId>,
704>: IpDeviceStateContext<I, BC> + IpDeviceMtuContext<I> + DeviceIdContext<AnyDevice>
705{
706 type DevicesIter<'s>: Iterator<Item = Self::DeviceId> + 's;
708 type WithIpDeviceConfigurationInnerCtx<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
710 + GmpHandler<I, BC>
711 + NudIpHandler<I, BC>
712 + DadHandler<I, BC>
713 + IpAddressRemovalHandler<I, BC>
714 + IpDeviceMtuContext<I>
715 + 's;
716 type WithIpDeviceConfigurationMutInner<'s>: WithIpDeviceConfigurationMutInner<I, BC, DeviceId = Self::DeviceId>
718 + 's;
719 type DeviceAddressAndGroupsAccessor<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId>
721 + 's;
722
723 fn with_ip_device_configuration<
726 O,
727 F: FnOnce(&I::Configuration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
728 >(
729 &mut self,
730 device_id: &Self::DeviceId,
731 cb: F,
732 ) -> O;
733
734 fn with_ip_device_configuration_mut<
736 O,
737 F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
738 >(
739 &mut self,
740 device_id: &Self::DeviceId,
741 cb: F,
742 ) -> O;
743
744 fn with_devices_and_state<
747 O,
748 F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
749 >(
750 &mut self,
751 cb: F,
752 ) -> O;
753
754 fn loopback_id(&mut self) -> Option<Self::DeviceId>;
757}
758
759pub trait WithIpv6DeviceConfigurationMutInner<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
762 WithIpDeviceConfigurationMutInner<Ipv6, BC>
763{
764 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId>
766 + GmpHandler<Ipv6, BC>
767 + NudIpHandler<Ipv6, BC>
768 + DadHandler<Ipv6, BC>
769 + RsHandler<BC>
770 + SlaacHandler<BC>
771 + RouteDiscoveryHandler<BC>
772 + 's
773 where
774 Self: 's;
775
776 fn ipv6_device_configuration_and_ctx(
779 &mut self,
780 ) -> (&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>);
781}
782
783pub trait Ipv6DeviceConfigurationContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
785 IpDeviceConfigurationContext<Ipv6, BC>
786{
787 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
789 + GmpHandler<Ipv6, BC>
790 + MldPacketHandler<BC, Self::DeviceId>
791 + NudIpHandler<Ipv6, BC>
792 + DadHandler<Ipv6, BC>
793 + RsHandler<BC>
794 + SlaacHandler<BC>
795 + RouteDiscoveryHandler<BC>
796 + 's;
797 type WithIpv6DeviceConfigurationMutInner<'s>: WithIpv6DeviceConfigurationMutInner<BC, DeviceId = Self::DeviceId>
799 + 's;
800
801 fn with_ipv6_device_configuration<
804 O,
805 F: FnOnce(&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) -> O,
806 >(
807 &mut self,
808 device_id: &Self::DeviceId,
809 cb: F,
810 ) -> O;
811
812 fn with_ipv6_device_configuration_mut<
814 O,
815 F: FnOnce(Self::WithIpv6DeviceConfigurationMutInner<'_>) -> O,
816 >(
817 &mut self,
818 device_id: &Self::DeviceId,
819 cb: F,
820 ) -> O;
821}
822
823pub trait Ipv6LinkLayerAddr {
825 fn as_bytes(&self) -> &[u8];
827
828 fn eui64_iid(&self) -> [u8; 8];
830}
831
832pub trait Ipv6DeviceContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
834 IpDeviceStateContext<Ipv6, BC>
835{
836 type LinkLayerAddr: Ipv6LinkLayerAddr;
838
839 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
842
843 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
845
846 fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
848 &mut self,
849 device_id: &Self::DeviceId,
850 cb: F,
851 ) -> O;
852
853 fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
855 &mut self,
856 device_id: &Self::DeviceId,
857 cb: F,
858 ) -> O;
859}
860
861pub trait IpDeviceHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
863 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool;
864
865 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8);
866}
867
868impl<
869 I: IpDeviceIpExt,
870 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
871 CC: IpDeviceConfigurationContext<I, BC>,
872 > IpDeviceHandler<I, BC> for CC
873{
874 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool {
875 is_ip_unicast_forwarding_enabled(self, device_id)
876 }
877
878 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8) {
879 self.with_default_hop_limit_mut(device_id, |default_hop_limit| {
880 *default_hop_limit = hop_limit
881 })
882 }
883}
884
885pub fn receive_igmp_packet<CC, BC, B, H>(
887 core_ctx: &mut CC,
888 bindings_ctx: &mut BC,
889 device: &CC::DeviceId,
890 src_ip: Ipv4Addr,
891 dst_ip: SpecifiedAddr<Ipv4Addr>,
892 buffer: B,
893 info: &LocalDeliveryPacketInfo<Ipv4, H>,
894) where
895 CC: IpDeviceConfigurationContext<Ipv4, BC>,
896 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
897 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>: IpDeviceStateContext<Ipv4, BC, DeviceId = CC::DeviceId>
898 + IgmpPacketHandler<BC, CC::DeviceId>,
899 B: BufferMut,
900 H: IpHeaderInfo<Ipv4>,
901{
902 core_ctx.with_ip_device_configuration(device, |_config, mut core_ctx| {
903 IgmpPacketHandler::receive_igmp_packet(
904 &mut core_ctx,
905 bindings_ctx,
906 device,
907 src_ip,
908 dst_ip,
909 buffer,
910 info,
911 )
912 })
913}
914
915pub trait Ipv6DeviceHandler<BC>: IpDeviceHandler<Ipv6, BC> {
917 type LinkLayerAddr: Ipv6LinkLayerAddr;
919
920 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
923
924 fn set_discovered_retrans_timer(
926 &mut self,
927 bindings_ctx: &mut BC,
928 device_id: &Self::DeviceId,
929 retrans_timer: NonZeroDuration,
930 );
931
932 fn handle_received_dad_neighbor_solicitation(
940 &mut self,
941 bindings_ctx: &mut BC,
942 device_id: &Self::DeviceId,
943 addr: UnicastAddr<Ipv6Addr>,
944 nonce: Option<NdpNonce<&'_ [u8]>>,
945 ) -> IpAddressState;
946
947 fn handle_received_neighbor_advertisement(
956 &mut self,
957 bindings_ctx: &mut BC,
958 device_id: &Self::DeviceId,
959 addr: UnicastAddr<Ipv6Addr>,
960 ) -> IpAddressState;
961
962 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
964
965 fn update_discovered_ipv6_route(
967 &mut self,
968 bindings_ctx: &mut BC,
969 device_id: &Self::DeviceId,
970 route: Ipv6DiscoveredRoute,
971 lifetime: Option<NonZeroNdpLifetime>,
972 );
973
974 fn apply_slaac_update(
976 &mut self,
977 bindings_ctx: &mut BC,
978 device_id: &Self::DeviceId,
979 prefix: Subnet<Ipv6Addr>,
980 preferred_lifetime: Option<NonZeroNdpLifetime>,
981 valid_lifetime: Option<NonZeroNdpLifetime>,
982 );
983
984 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
986 &mut self,
987 bindings_ctx: &mut BC,
988 device: &Self::DeviceId,
989 src_ip: Ipv6SourceAddr,
990 dst_ip: SpecifiedAddr<Ipv6Addr>,
991 packet: MldPacket<B>,
992 header_info: &H,
993 );
994}
995
996impl<
997 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
998 CC: Ipv6DeviceContext<BC>
999 + Ipv6DeviceConfigurationContext<BC>
1000 + CounterContext<IpCounters<Ipv6>>,
1001 > Ipv6DeviceHandler<BC> for CC
1002{
1003 type LinkLayerAddr = CC::LinkLayerAddr;
1004
1005 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<CC::LinkLayerAddr> {
1006 Ipv6DeviceContext::get_link_layer_addr(self, device_id)
1007 }
1008
1009 fn set_discovered_retrans_timer(
1010 &mut self,
1011 _bindings_ctx: &mut BC,
1012 device_id: &Self::DeviceId,
1013 retrans_timer: NonZeroDuration,
1014 ) {
1015 self.with_network_learned_parameters_mut(device_id, |state| {
1016 state.retrans_timer = Some(retrans_timer)
1017 })
1018 }
1019
1020 fn handle_received_dad_neighbor_solicitation(
1021 &mut self,
1022 bindings_ctx: &mut BC,
1023 device_id: &Self::DeviceId,
1024 addr: UnicastAddr<Ipv6Addr>,
1025 nonce: Option<NdpNonce<&'_ [u8]>>,
1026 ) -> IpAddressState {
1027 let addr_id = match self.get_address_id(device_id, addr.into_specified()) {
1028 Ok(o) => o,
1029 Err(NotFoundError) => return IpAddressState::Unavailable,
1030 };
1031
1032 match self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1033 core_ctx.handle_incoming_dad_neighbor_solicitation(
1034 bindings_ctx,
1035 device_id,
1036 &addr_id,
1037 nonce,
1038 )
1039 }) {
1040 DadAddressStateLookupResult::Assigned => IpAddressState::Assigned,
1041 DadAddressStateLookupResult::Tentative { matched_nonce: true } => {
1042 self.counters().version_rx.drop_looped_back_dad_probe.increment();
1043
1044 IpAddressState::Tentative
1053 }
1054 DadAddressStateLookupResult::Uninitialized
1055 | DadAddressStateLookupResult::Tentative { matched_nonce: false } => {
1056 match del_ip_addr(
1064 self,
1065 bindings_ctx,
1066 device_id,
1067 DelIpAddr::AddressId(addr_id),
1068 AddressRemovedReason::DadFailed,
1069 ) {
1070 Ok(result) => {
1071 bindings_ctx.defer_removal_result(result);
1072 IpAddressState::Tentative
1073 }
1074 Err(NotFoundError) => {
1075 IpAddressState::Unavailable
1077 }
1078 }
1079 }
1080 }
1081 }
1082
1083 fn handle_received_neighbor_advertisement(
1084 &mut self,
1085 bindings_ctx: &mut BC,
1086 device_id: &Self::DeviceId,
1087 addr: UnicastAddr<Ipv6Addr>,
1088 ) -> IpAddressState {
1089 let addr_id = match self.get_address_id(device_id, addr.into_specified()) {
1090 Ok(o) => o,
1091 Err(NotFoundError) => return IpAddressState::Unavailable,
1092 };
1093
1094 let assigned = self.with_ip_address_state(
1095 device_id,
1096 &addr_id,
1097 |Ipv6AddressState { flags: Ipv6AddressFlags { assigned }, config: _ }| *assigned,
1098 );
1099
1100 if assigned {
1101 IpAddressState::Assigned
1102 } else {
1103 match del_ip_addr(
1104 self,
1105 bindings_ctx,
1106 device_id,
1107 DelIpAddr::AddressId(addr_id),
1108 AddressRemovedReason::DadFailed,
1109 ) {
1110 Ok(result) => {
1111 bindings_ctx.defer_removal_result(result);
1112 IpAddressState::Tentative
1113 }
1114 Err(NotFoundError) => {
1115 IpAddressState::Unavailable
1117 }
1118 }
1119 }
1120 }
1121
1122 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
1123 Ipv6DeviceContext::set_link_mtu(self, device_id, mtu)
1124 }
1125
1126 fn update_discovered_ipv6_route(
1127 &mut self,
1128 bindings_ctx: &mut BC,
1129 device_id: &Self::DeviceId,
1130 route: Ipv6DiscoveredRoute,
1131 lifetime: Option<NonZeroNdpLifetime>,
1132 ) {
1133 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1134 RouteDiscoveryHandler::update_route(
1135 &mut core_ctx,
1136 bindings_ctx,
1137 device_id,
1138 route,
1139 lifetime,
1140 )
1141 })
1142 }
1143
1144 fn apply_slaac_update(
1145 &mut self,
1146 bindings_ctx: &mut BC,
1147 device_id: &Self::DeviceId,
1148 prefix: Subnet<Ipv6Addr>,
1149 preferred_lifetime: Option<NonZeroNdpLifetime>,
1150 valid_lifetime: Option<NonZeroNdpLifetime>,
1151 ) {
1152 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1153 SlaacHandler::apply_slaac_update(
1154 &mut core_ctx,
1155 bindings_ctx,
1156 device_id,
1157 prefix,
1158 preferred_lifetime,
1159 valid_lifetime,
1160 )
1161 })
1162 }
1163
1164 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
1165 &mut self,
1166 bindings_ctx: &mut BC,
1167 device: &Self::DeviceId,
1168 src_ip: Ipv6SourceAddr,
1169 dst_ip: SpecifiedAddr<Ipv6Addr>,
1170 packet: MldPacket<B>,
1171 header_info: &H,
1172 ) {
1173 self.with_ipv6_device_configuration(device, |_config, mut core_ctx| {
1174 MldPacketHandler::receive_mld_packet(
1175 &mut core_ctx,
1176 bindings_ctx,
1177 device,
1178 src_ip,
1179 dst_ip,
1180 packet,
1181 header_info,
1182 )
1183 })
1184 }
1185}
1186
1187pub trait IpDeviceSendContext<I: IpExt, BC: TxMetadataBindingsTypes>:
1189 DeviceIdContext<AnyDevice>
1190{
1191 fn send_ip_frame<S>(
1193 &mut self,
1194 bindings_ctx: &mut BC,
1195 device_id: &Self::DeviceId,
1196 destination: IpPacketDestination<I, &Self::DeviceId>,
1197 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
1198 body: S,
1199 egress_proof: ProofOfEgressCheck,
1200 ) -> Result<(), SendFrameError<S>>
1201 where
1202 S: Serializer,
1203 S::Buffer: BufferMut;
1204}
1205
1206fn enable_ipv6_device_with_config<
1207 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1208 CC: Ipv6DeviceContext<BC>
1209 + GmpHandler<Ipv6, BC>
1210 + RsHandler<BC>
1211 + DadHandler<Ipv6, BC>
1212 + SlaacHandler<BC>,
1213>(
1214 core_ctx: &mut CC,
1215 bindings_ctx: &mut BC,
1216 device_id: &CC::DeviceId,
1217 config: &Ipv6DeviceConfiguration,
1218) {
1219 join_ip_multicast_with_config(
1221 core_ctx,
1222 bindings_ctx,
1223 device_id,
1224 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1225 config,
1226 );
1227 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1228
1229 core_ctx
1236 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1237 .into_iter()
1238 .for_each(|addr_id| {
1239 let (state, start_dad) = DadHandler::initialize_duplicate_address_detection(
1240 core_ctx,
1241 bindings_ctx,
1242 device_id,
1243 &addr_id,
1244 )
1245 .into_address_state_and_start_dad();
1246 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1247 device: device_id.clone(),
1248 addr: addr_id.addr().into(),
1249 state,
1250 });
1251 if let Some(token) = start_dad {
1252 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1253 }
1254 });
1255
1256 if core_ctx.get_link_layer_addr(device_id).is_some() {
1259 SlaacHandler::generate_link_local_address(core_ctx, bindings_ctx, device_id);
1260 }
1261
1262 RsHandler::start_router_solicitation(core_ctx, bindings_ctx, device_id);
1263}
1264
1265fn disable_ipv6_device_with_config<
1266 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1267 CC: Ipv6DeviceContext<BC>
1268 + GmpHandler<Ipv6, BC>
1269 + RsHandler<BC>
1270 + DadHandler<Ipv6, BC>
1271 + RouteDiscoveryHandler<BC>
1272 + SlaacHandler<BC>
1273 + NudIpHandler<Ipv6, BC>,
1274>(
1275 core_ctx: &mut CC,
1276 bindings_ctx: &mut BC,
1277 device_id: &CC::DeviceId,
1278 device_config: &Ipv6DeviceConfiguration,
1279) {
1280 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1281
1282 SlaacHandler::remove_all_slaac_addresses(core_ctx, bindings_ctx, device_id);
1283
1284 RouteDiscoveryHandler::invalidate_routes(core_ctx, bindings_ctx, device_id);
1285
1286 RsHandler::stop_router_solicitation(core_ctx, bindings_ctx, device_id);
1287
1288 core_ctx.with_network_learned_parameters_mut(device_id, |params| params.reset());
1291
1292 core_ctx
1295 .with_address_ids(device_id, |addrs, core_ctx| {
1296 addrs
1297 .map(|addr_id| {
1298 core_ctx.with_ip_address_state(
1299 device_id,
1300 &addr_id,
1301 |Ipv6AddressState { flags: _, config }| (addr_id.clone(), *config),
1302 )
1303 })
1304 .collect::<Vec<_>>()
1305 })
1306 .into_iter()
1307 .for_each(|(addr_id, config)| {
1308 if config
1309 .is_some_and(|config| config.is_slaac() && addr_id.addr().addr().is_link_local())
1310 {
1311 del_ip_addr_inner_and_notify_handler(
1312 core_ctx,
1313 bindings_ctx,
1314 device_id,
1315 DelIpAddr::AddressId(addr_id),
1316 AddressRemovedReason::Manual,
1317 device_config,
1318 )
1319 .map(|remove_result| {
1320 bindings_ctx.defer_removal_result(remove_result);
1321 })
1322 .unwrap_or_else(|NotFoundError| {
1323 })
1327 } else {
1328 DadHandler::stop_duplicate_address_detection(
1329 core_ctx,
1330 bindings_ctx,
1331 device_id,
1332 &addr_id,
1333 );
1334 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1335 device: device_id.clone(),
1336 addr: addr_id.addr().into(),
1337 state: IpAddressState::Unavailable,
1338 });
1339 }
1340 });
1341
1342 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1343 leave_ip_multicast_with_config(
1344 core_ctx,
1345 bindings_ctx,
1346 device_id,
1347 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1348 device_config,
1349 );
1350}
1351
1352fn enable_ipv4_device_with_config<
1353 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1354 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC>,
1355>(
1356 core_ctx: &mut CC,
1357 bindings_ctx: &mut BC,
1358 device_id: &CC::DeviceId,
1359 config: &Ipv4DeviceConfiguration,
1360) {
1361 join_ip_multicast_with_config(
1363 core_ctx,
1364 bindings_ctx,
1365 device_id,
1366 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1367 config,
1368 );
1369 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1370 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1371 addrs.for_each(|addr| {
1372 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1374 device: device_id.clone(),
1375 addr: addr.addr().into(),
1376 state: IpAddressState::Assigned,
1377 });
1378 })
1379 })
1380}
1381
1382fn disable_ipv4_device_with_config<
1383 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1384 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC> + NudIpHandler<Ipv4, BC>,
1385>(
1386 core_ctx: &mut CC,
1387 bindings_ctx: &mut BC,
1388 device_id: &CC::DeviceId,
1389 config: &Ipv4DeviceConfiguration,
1390) {
1391 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1392 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1393 leave_ip_multicast_with_config(
1394 core_ctx,
1395 bindings_ctx,
1396 device_id,
1397 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1398 config,
1399 );
1400 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1401 addrs.for_each(|addr| {
1402 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1403 device: device_id.clone(),
1404 addr: addr.addr().into(),
1405 state: IpAddressState::Unavailable,
1406 });
1407 })
1408 })
1409}
1410
1411pub fn get_ipv4_addr_subnet<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv4, BT>>(
1413 core_ctx: &mut CC,
1414 device_id: &CC::DeviceId,
1415) -> Option<AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> {
1416 core_ctx.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next().map(|a| a.addr_sub()))
1417}
1418
1419pub fn get_ipv6_hop_limit<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv6, BT>>(
1421 core_ctx: &mut CC,
1422 device: &CC::DeviceId,
1423) -> NonZeroU8 {
1424 core_ctx.with_default_hop_limit(device, Clone::clone)
1425}
1426
1427pub fn is_ip_unicast_forwarding_enabled<
1429 I: IpDeviceIpExt,
1430 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1431 CC: IpDeviceConfigurationContext<I, BC>,
1432>(
1433 core_ctx: &mut CC,
1434 device_id: &CC::DeviceId,
1435) -> bool {
1436 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1437 AsRef::<IpDeviceConfiguration>::as_ref(state).unicast_forwarding_enabled
1438 })
1439}
1440
1441pub fn is_ip_multicast_forwarding_enabled<
1443 I: IpDeviceIpExt,
1444 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1445 CC: IpDeviceConfigurationContext<I, BC>,
1446>(
1447 core_ctx: &mut CC,
1448 device_id: &CC::DeviceId,
1449) -> bool {
1450 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1451 AsRef::<IpDeviceConfiguration>::as_ref(state).multicast_forwarding_enabled
1452 })
1453}
1454
1455pub fn join_ip_multicast_with_config<
1462 I: IpDeviceIpExt,
1463 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1464 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1465>(
1466 core_ctx: &mut CC,
1467 bindings_ctx: &mut BC,
1468 device_id: &CC::DeviceId,
1469 multicast_addr: MulticastAddr<I::Addr>,
1470 _config: &I::Configuration,
1471) {
1472 match core_ctx.gmp_join_group(bindings_ctx, device_id, multicast_addr) {
1473 GroupJoinResult::Joined(()) => {
1474 core_ctx.join_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1475 }
1476 GroupJoinResult::AlreadyMember => {}
1477 }
1478}
1479
1480pub fn join_ip_multicast<
1491 I: IpDeviceIpExt,
1492 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1493 CC: IpDeviceConfigurationContext<I, BC>,
1494>(
1495 core_ctx: &mut CC,
1496 bindings_ctx: &mut BC,
1497 device_id: &CC::DeviceId,
1498 multicast_addr: MulticastAddr<I::Addr>,
1499) {
1500 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1501 join_ip_multicast_with_config(
1502 &mut core_ctx,
1503 bindings_ctx,
1504 device_id,
1505 multicast_addr,
1506 config,
1507 )
1508 })
1509}
1510
1511pub fn leave_ip_multicast_with_config<
1518 I: IpDeviceIpExt,
1519 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1520 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1521>(
1522 core_ctx: &mut CC,
1523 bindings_ctx: &mut BC,
1524 device_id: &CC::DeviceId,
1525 multicast_addr: MulticastAddr<I::Addr>,
1526 _config: &I::Configuration,
1527) {
1528 match core_ctx.gmp_leave_group(bindings_ctx, device_id, multicast_addr) {
1529 GroupLeaveResult::Left(()) => {
1530 core_ctx.leave_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1531 }
1532 GroupLeaveResult::StillMember => {}
1533 GroupLeaveResult::NotMember => panic!(
1534 "attempted to leave IP multicast group we were not a member of: {}",
1535 multicast_addr,
1536 ),
1537 }
1538}
1539
1540pub fn leave_ip_multicast<
1555 I: IpDeviceIpExt,
1556 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1557 CC: IpDeviceConfigurationContext<I, BC>,
1558>(
1559 core_ctx: &mut CC,
1560 bindings_ctx: &mut BC,
1561 device_id: &CC::DeviceId,
1562 multicast_addr: MulticastAddr<I::Addr>,
1563) {
1564 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1565 leave_ip_multicast_with_config(
1566 &mut core_ctx,
1567 bindings_ctx,
1568 device_id,
1569 multicast_addr,
1570 config,
1571 )
1572 })
1573}
1574
1575pub fn add_ip_addr_subnet_with_config<
1582 I: IpDeviceIpExt,
1583 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1584 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1585>(
1586 core_ctx: &mut CC,
1587 bindings_ctx: &mut BC,
1588 device_id: &CC::DeviceId,
1589 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1590 addr_config: I::AddressConfig<BC::Instant>,
1591 _device_config: &I::Configuration,
1592) -> Result<CC::AddressId, ExistsError> {
1593 info!("adding addr {addr_sub:?} config {addr_config:?} to device {device_id:?}");
1594 let CommonAddressProperties { valid_until, preferred_lifetime } =
1595 I::get_common_props(&addr_config);
1596 let addr_id = core_ctx.add_ip_address(device_id, addr_sub, addr_config)?;
1597 assert_eq!(addr_id.addr().addr(), addr_sub.addr().get());
1598
1599 let ip_enabled =
1600 core_ctx.with_ip_device_flags(device_id, |IpDeviceFlags { ip_enabled }| *ip_enabled);
1601
1602 let (state, start_dad) = if ip_enabled {
1603 DadHandler::initialize_duplicate_address_detection(
1604 core_ctx,
1605 bindings_ctx,
1606 device_id,
1607 &addr_id,
1608 )
1609 .into_address_state_and_start_dad()
1610 } else {
1611 (IpAddressState::Unavailable, None)
1614 };
1615
1616 bindings_ctx.on_event(IpDeviceEvent::AddressAdded {
1617 device: device_id.clone(),
1618 addr: addr_sub.to_witness(),
1619 state,
1620 valid_until,
1621 preferred_lifetime,
1622 });
1623
1624 if let Some(token) = start_dad {
1625 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1626 }
1627
1628 Ok(addr_id)
1629}
1630
1631pub trait IpAddressRemovalHandler<I: IpDeviceIpExt, BC: InstantBindingsTypes>:
1633 DeviceIdContext<AnyDevice>
1634{
1635 fn on_address_removed(
1638 &mut self,
1639 bindings_ctx: &mut BC,
1640 device_id: &Self::DeviceId,
1641 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1642 config: I::AddressConfig<BC::Instant>,
1643 reason: AddressRemovedReason,
1644 );
1645}
1646
1647impl<CC: DeviceIdContext<AnyDevice>, BC: InstantBindingsTypes> IpAddressRemovalHandler<Ipv4, BC>
1649 for CC
1650{
1651 fn on_address_removed(
1652 &mut self,
1653 _bindings_ctx: &mut BC,
1654 _device_id: &Self::DeviceId,
1655 _addr_sub: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
1656 _config: Ipv4AddrConfig<BC::Instant>,
1657 _reason: AddressRemovedReason,
1658 ) {
1659 }
1661}
1662
1663impl<CC: SlaacHandler<BC>, BC: InstantContext> IpAddressRemovalHandler<Ipv6, BC> for CC {
1665 fn on_address_removed(
1666 &mut self,
1667 bindings_ctx: &mut BC,
1668 device_id: &Self::DeviceId,
1669 addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
1670 config: Ipv6AddrConfig<BC::Instant>,
1671 reason: AddressRemovedReason,
1672 ) {
1673 match config {
1674 Ipv6AddrConfig::Slaac(config) => SlaacHandler::on_address_removed(
1675 self,
1676 bindings_ctx,
1677 device_id,
1678 addr_sub,
1679 config,
1680 reason,
1681 ),
1682 Ipv6AddrConfig::Manual(_manual_config) => (),
1683 }
1684 }
1685}
1686
1687#[allow(missing_docs)]
1689pub enum DelIpAddr<Id, A> {
1690 SpecifiedAddr(SpecifiedAddr<A>),
1691 AddressId(Id),
1692}
1693
1694impl<Id: IpAddressId<A>, A: IpAddress<Version: AssignedAddrIpExt>> Display for DelIpAddr<Id, A> {
1695 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1696 match self {
1697 DelIpAddr::SpecifiedAddr(addr) => write!(f, "{}", *addr),
1698 DelIpAddr::AddressId(id) => write!(f, "{}", id.addr()),
1699 }
1700 }
1701}
1702
1703pub fn del_ip_addr_inner<
1706 I: IpDeviceIpExt,
1707 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1708 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1709>(
1710 core_ctx: &mut CC,
1711 bindings_ctx: &mut BC,
1712 device_id: &CC::DeviceId,
1713 addr: DelIpAddr<CC::AddressId, I::Addr>,
1714 reason: AddressRemovedReason,
1715 _config: &I::Configuration,
1717) -> Result<
1718 (
1719 AddrSubnet<I::Addr, I::AssignedWitness>,
1720 I::AddressConfig<BC::Instant>,
1721 RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>,
1722 ),
1723 NotFoundError,
1724> {
1725 let addr_id = match addr {
1726 DelIpAddr::SpecifiedAddr(addr) => core_ctx.get_address_id(device_id, addr)?,
1727 DelIpAddr::AddressId(id) => id,
1728 };
1729 DadHandler::stop_duplicate_address_detection(core_ctx, bindings_ctx, device_id, &addr_id);
1730 let addr_config = core_ctx
1734 .with_ip_address_state_mut(device_id, &addr_id, |addr_state| {
1735 I::take_addr_config_for_removal(addr_state)
1736 })
1737 .ok_or(NotFoundError)?;
1738
1739 let addr_sub = addr_id.addr_sub();
1740 let result = core_ctx.remove_ip_address(device_id, addr_id);
1741
1742 bindings_ctx.on_event(IpDeviceEvent::AddressRemoved {
1743 device: device_id.clone(),
1744 addr: addr_sub.addr().into(),
1745 reason,
1746 });
1747
1748 Ok((addr_sub, addr_config, result))
1749}
1750
1751fn del_ip_addr<
1753 I: IpDeviceIpExt,
1754 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1755 CC: IpDeviceConfigurationContext<I, BC>,
1756>(
1757 core_ctx: &mut CC,
1758 bindings_ctx: &mut BC,
1759 device_id: &CC::DeviceId,
1760 addr: DelIpAddr<CC::AddressId, I::Addr>,
1761 reason: AddressRemovedReason,
1762) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1763 info!("removing addr {addr} from device {device_id:?}");
1764 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1765 del_ip_addr_inner_and_notify_handler(
1766 &mut core_ctx,
1767 bindings_ctx,
1768 device_id,
1769 addr,
1770 reason,
1771 config,
1772 )
1773 })
1774}
1775
1776fn del_ip_addr_inner_and_notify_handler<
1779 I: IpDeviceIpExt,
1780 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1781 CC: IpDeviceStateContext<I, BC>
1782 + GmpHandler<I, BC>
1783 + DadHandler<I, BC>
1784 + IpAddressRemovalHandler<I, BC>,
1785>(
1786 core_ctx: &mut CC,
1787 bindings_ctx: &mut BC,
1788 device_id: &CC::DeviceId,
1789 addr: DelIpAddr<CC::AddressId, I::Addr>,
1790 reason: AddressRemovedReason,
1791 config: &I::Configuration,
1792) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1793 del_ip_addr_inner(core_ctx, bindings_ctx, device_id, addr, reason, config).map(
1794 |(addr_sub, config, result)| {
1795 core_ctx.on_address_removed(bindings_ctx, device_id, addr_sub, config, reason);
1796 result
1797 },
1798 )
1799}
1800
1801pub fn is_ip_device_enabled<
1803 I: IpDeviceIpExt,
1804 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1805 CC: IpDeviceStateContext<I, BC>,
1806>(
1807 core_ctx: &mut CC,
1808 device_id: &CC::DeviceId,
1809) -> bool {
1810 core_ctx.with_ip_device_flags(device_id, |flags| flags.ip_enabled)
1811}
1812
1813pub fn clear_ipv4_device_state<
1815 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1816 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1817>(
1818 core_ctx: &mut CC,
1819 bindings_ctx: &mut BC,
1820 device_id: &CC::DeviceId,
1821) {
1822 core_ctx.with_ip_device_configuration_mut(device_id, |mut core_ctx| {
1823 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1824 let IpDeviceFlags { ip_enabled } = flags;
1827 core::mem::replace(ip_enabled, false)
1828 });
1829
1830 let (config, mut core_ctx) = core_ctx.ip_device_configuration_and_ctx();
1831 let core_ctx = &mut core_ctx;
1832 if ip_enabled {
1833 disable_ipv4_device_with_config(core_ctx, bindings_ctx, device_id, config);
1834 }
1835 })
1836}
1837
1838pub fn clear_ipv6_device_state<
1840 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1841 CC: Ipv6DeviceConfigurationContext<BC>,
1842>(
1843 core_ctx: &mut CC,
1844 bindings_ctx: &mut BC,
1845 device_id: &CC::DeviceId,
1846) {
1847 core_ctx.with_ipv6_device_configuration_mut(device_id, |mut core_ctx| {
1848 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1849 let IpDeviceFlags { ip_enabled } = flags;
1852 core::mem::replace(ip_enabled, false)
1853 });
1854
1855 let (config, mut core_ctx) = core_ctx.ipv6_device_configuration_and_ctx();
1856 let core_ctx = &mut core_ctx;
1857 if ip_enabled {
1858 disable_ipv6_device_with_config(core_ctx, bindings_ctx, device_id, config);
1859 }
1860 })
1861}
1862
1863#[cfg(any(test, feature = "testutils"))]
1864pub(crate) mod testutil {
1865 use alloc::boxed::Box;
1866
1867 use super::*;
1868
1869 pub fn with_assigned_ipv4_addr_subnets<
1872 BT: IpDeviceStateBindingsTypes,
1873 CC: IpDeviceStateContext<Ipv4, BT>,
1874 O,
1875 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> + '_>) -> O,
1876 >(
1877 core_ctx: &mut CC,
1878 device_id: &CC::DeviceId,
1879 cb: F,
1880 ) -> O {
1881 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1882 cb(Box::new(addrs.map(|a| a.addr_sub())))
1883 })
1884 }
1885
1886 pub fn with_assigned_ipv6_addr_subnets<
1898 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1899 CC: Ipv6DeviceContext<BC>,
1900 O,
1901 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>> + '_>) -> O,
1902 >(
1903 core_ctx: &mut CC,
1904 device_id: &CC::DeviceId,
1905 cb: F,
1906 ) -> O {
1907 core_ctx.with_address_ids(device_id, |addrs, core_ctx| {
1908 cb(Box::new(addrs.filter_map(|addr_id| {
1909 core_ctx
1910 .with_ip_address_state(
1911 device_id,
1912 &addr_id,
1913 |Ipv6AddressState { flags: Ipv6AddressFlags { assigned }, config: _ }| {
1914 *assigned
1915 },
1916 )
1917 .then(|| addr_id.addr_sub())
1918 })))
1919 })
1920 }
1921}