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::marker::PhantomData;
21use core::num::NonZeroU8;
22
23use derivative::Derivative;
24use log::info;
25use net_types::ip::{
26 AddrSubnet, GenericOverIp, Ip, IpAddress, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr,
27 Ipv6SourceAddr, Mtu, Subnet,
28};
29use net_types::{LinkLocalAddress as _, MulticastAddr, SpecifiedAddr, UnicastAddr, Witness};
30use netstack3_base::{
31 AnyDevice, AssignedAddrIpExt, CounterContext, DeferredResourceRemovalContext, DeviceIdContext,
32 EventContext, ExistsError, HandleableTimer, Instant, InstantBindingsTypes, InstantContext,
33 IpAddressId, IpDeviceAddr, IpDeviceAddressIdContext, IpExt, Ipv4DeviceAddr, Ipv6DeviceAddr,
34 NotFoundError, RemoveResourceResultWithContext, RngContext, SendFrameError,
35 StrongDeviceIdentifier, TimerContext, TimerHandler, TxMetadataBindingsTypes,
36 WeakDeviceIdentifier, WeakIpAddressId,
37};
38use netstack3_filter::ProofOfEgressCheck;
39use packet::{BufferMut, Serializer};
40use packet_formats::icmp::mld::MldPacket;
41use packet_formats::icmp::ndp::options::NdpNonce;
42use packet_formats::icmp::ndp::NonZeroNdpLifetime;
43use packet_formats::utils::NonZeroDuration;
44use zerocopy::SplitByteSlice;
45
46use crate::device::CommonAddressProperties;
47use crate::internal::base::{DeviceIpLayerMetadata, IpDeviceMtuContext, IpPacketDestination};
48use crate::internal::counters::IpCounters;
49use crate::internal::device::config::{
50 IpDeviceConfigurationUpdate, Ipv4DeviceConfigurationUpdate, Ipv6DeviceConfigurationUpdate,
51};
52use crate::internal::device::dad::{
53 DadHandler, DadIncomingProbeResult, DadIpExt, DadTimerId, Ipv6ProbeResultMetadata,
54};
55use crate::internal::device::nud::NudIpHandler;
56use crate::internal::device::route_discovery::{
57 Ipv6DiscoveredRoute, Ipv6DiscoveredRouteTimerId, RouteDiscoveryHandler,
58};
59use crate::internal::device::router_solicitation::{RsHandler, RsTimerId};
60use crate::internal::device::slaac::{SlaacHandler, SlaacTimerId};
61use crate::internal::device::state::{
62 IpAddressData, IpAddressFlags, IpDeviceConfiguration, IpDeviceFlags, IpDeviceState,
63 IpDeviceStateBindingsTypes, IpDeviceStateIpExt, Ipv4AddrConfig, Ipv4DeviceConfiguration,
64 Ipv4DeviceState, Ipv6AddrConfig, Ipv6AddrManualConfig, Ipv6DeviceConfiguration,
65 Ipv6DeviceState, Ipv6NetworkLearnedParameters, Lifetime, PreferredLifetime, WeakAddressId,
66};
67use crate::internal::gmp::igmp::{IgmpPacketHandler, IgmpTimerId};
68use crate::internal::gmp::mld::{MldPacketHandler, MldTimerId};
69use crate::internal::gmp::{self, GmpHandler, GroupJoinResult, GroupLeaveResult};
70use crate::internal::local_delivery::{IpHeaderInfo, LocalDeliveryPacketInfo};
71
72#[derive(Derivative, GenericOverIp)]
79#[derivative(
80 Clone(bound = ""),
81 Eq(bound = ""),
82 PartialEq(bound = ""),
83 Hash(bound = ""),
84 Debug(bound = "")
85)]
86#[generic_over_ip(I, Ip)]
87pub struct IpDeviceTimerId<
88 I: IpDeviceIpExt,
89 D: WeakDeviceIdentifier,
90 BT: IpDeviceStateBindingsTypes,
91>(I::Timer<D, BT>);
92
93#[derive(Derivative)]
97#[derivative(
98 Clone(bound = ""),
99 Debug(bound = ""),
100 Eq(bound = ""),
101 Hash(bound = ""),
102 PartialEq(bound = "")
103)]
104pub struct Ipv4DeviceTimerId<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
105 IgmpTimerId<D>,
106 PhantomData<BT>,
107);
108
109impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> Ipv4DeviceTimerId<D, BT> {
110 fn device_id(&self) -> Option<D::Strong> {
112 let Self(this, _phantom) = self;
113 this.device_id().upgrade()
114 }
115
116 pub fn into_common(self) -> IpDeviceTimerId<Ipv4, D, BT> {
118 self.into()
119 }
120}
121
122impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<IpDeviceTimerId<Ipv4, D, BT>>
123 for Ipv4DeviceTimerId<D, BT>
124{
125 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv4, D, BT>) -> Self {
126 inner
127 }
128}
129
130impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<Ipv4DeviceTimerId<D, BT>>
131 for IpDeviceTimerId<Ipv4, D, BT>
132{
133 fn from(value: Ipv4DeviceTimerId<D, BT>) -> Self {
134 Self(value)
135 }
136}
137
138impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<IgmpTimerId<D>>
139 for Ipv4DeviceTimerId<D, BT>
140{
141 fn from(id: IgmpTimerId<D>) -> Ipv4DeviceTimerId<D, BT> {
142 Ipv4DeviceTimerId(id, PhantomData)
143 }
144}
145
146impl<
147 D: WeakDeviceIdentifier,
148 BC: IpDeviceStateBindingsTypes,
149 CC: TimerHandler<BC, IgmpTimerId<D>>,
150 > HandleableTimer<CC, BC> for Ipv4DeviceTimerId<D, BC>
151{
152 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
153 let Self(id, _phantom) = self;
154 core_ctx.handle_timer(bindings_ctx, id, timer);
155 }
156}
157
158impl<I, CC, BC> HandleableTimer<CC, BC> for IpDeviceTimerId<I, CC::WeakDeviceId, BC>
159where
160 I: IpDeviceIpExt,
161 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
162 CC: IpDeviceConfigurationContext<I, BC>,
163 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>:
164 TimerHandler<BC, I::Timer<CC::WeakDeviceId, BC>>,
165{
166 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
167 let Self(id) = self;
168 let Some(device_id) = I::timer_device_id(&id) else {
169 return;
170 };
171 core_ctx.with_ip_device_configuration(&device_id, |_state, mut core_ctx| {
172 TimerHandler::handle_timer(&mut core_ctx, bindings_ctx, id, timer)
173 })
174 }
175}
176
177#[derive(Derivative)]
179#[derivative(
180 Clone(bound = ""),
181 Debug(bound = ""),
182 Eq(bound = ""),
183 Hash(bound = ""),
184 PartialEq(bound = "")
185)]
186#[allow(missing_docs)]
187pub enum Ipv6DeviceTimerId<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> {
188 Mld(MldTimerId<D>),
189 Dad(DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BT>>),
190 Rs(RsTimerId<D>),
191 RouteDiscovery(Ipv6DiscoveredRouteTimerId<D>),
192 Slaac(SlaacTimerId<D>),
193}
194
195impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<IpDeviceTimerId<Ipv6, D, BT>>
196 for Ipv6DeviceTimerId<D, BT>
197{
198 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv6, D, BT>) -> Self {
199 inner
200 }
201}
202
203impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<Ipv6DeviceTimerId<D, BT>>
204 for IpDeviceTimerId<Ipv6, D, BT>
205{
206 fn from(value: Ipv6DeviceTimerId<D, BT>) -> Self {
207 Self(value)
208 }
209}
210
211impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> Ipv6DeviceTimerId<D, BT> {
212 fn device_id(&self) -> Option<D::Strong> {
214 match self {
215 Self::Mld(id) => id.device_id(),
216 Self::Dad(id) => id.device_id(),
217 Self::Rs(id) => id.device_id(),
218 Self::RouteDiscovery(id) => id.device_id(),
219 Self::Slaac(id) => id.device_id(),
220 }
221 .upgrade()
222 }
223
224 pub fn into_common(self) -> IpDeviceTimerId<Ipv6, D, BT> {
226 self.into()
227 }
228}
229
230impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<MldTimerId<D>>
231 for Ipv6DeviceTimerId<D, BT>
232{
233 fn from(id: MldTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
234 Ipv6DeviceTimerId::Mld(id)
235 }
236}
237
238impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>
239 From<DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BT>>> for Ipv6DeviceTimerId<D, BT>
240{
241 fn from(id: DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BT>>) -> Ipv6DeviceTimerId<D, BT> {
242 Ipv6DeviceTimerId::Dad(id)
243 }
244}
245
246impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<RsTimerId<D>>
247 for Ipv6DeviceTimerId<D, BT>
248{
249 fn from(id: RsTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
250 Ipv6DeviceTimerId::Rs(id)
251 }
252}
253
254impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<Ipv6DiscoveredRouteTimerId<D>>
255 for Ipv6DeviceTimerId<D, BT>
256{
257 fn from(id: Ipv6DiscoveredRouteTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
258 Ipv6DeviceTimerId::RouteDiscovery(id)
259 }
260}
261
262impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<SlaacTimerId<D>>
263 for Ipv6DeviceTimerId<D, BT>
264{
265 fn from(id: SlaacTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
266 Ipv6DeviceTimerId::Slaac(id)
267 }
268}
269
270impl<
271 D: WeakDeviceIdentifier,
272 BC: IpDeviceStateBindingsTypes,
273 CC: TimerHandler<BC, RsTimerId<D>>
274 + TimerHandler<BC, Ipv6DiscoveredRouteTimerId<D>>
275 + TimerHandler<BC, MldTimerId<D>>
276 + TimerHandler<BC, SlaacTimerId<D>>
277 + TimerHandler<BC, DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BC>>>,
278 > HandleableTimer<CC, BC> for Ipv6DeviceTimerId<D, BC>
279{
280 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
281 match self {
282 Ipv6DeviceTimerId::Mld(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
283 Ipv6DeviceTimerId::Dad(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
284 Ipv6DeviceTimerId::Rs(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
285 Ipv6DeviceTimerId::RouteDiscovery(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
286 Ipv6DeviceTimerId::Slaac(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
287 }
288 }
289}
290
291pub trait IpDeviceIpExt: IpDeviceStateIpExt + AssignedAddrIpExt + gmp::IpExt + DadIpExt {
293 type State<BT: IpDeviceStateBindingsTypes>: AsRef<IpDeviceState<Self, BT>>
295 + AsMut<IpDeviceState<Self, BT>>;
296 type Configuration: AsRef<IpDeviceConfiguration>
298 + AsMut<IpDeviceConfiguration>
299 + Clone
300 + Debug
301 + Eq
302 + PartialEq;
303 type Timer<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>: Into<IpDeviceTimerId<Self, D, BT>>
305 + From<IpDeviceTimerId<Self, D, BT>>
306 + Clone
307 + Eq
308 + PartialEq
309 + Debug
310 + Hash;
311 type ManualAddressConfig<I: Instant>: Default + Debug + Into<Self::AddressConfig<I>>;
313 type ConfigurationUpdate: From<IpDeviceConfigurationUpdate>
315 + AsRef<IpDeviceConfigurationUpdate>
316 + Debug;
317
318 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I>;
320
321 fn timer_device_id<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
323 timer: &Self::Timer<D, BT>,
324 ) -> Option<D::Strong>;
325}
326
327impl IpDeviceIpExt for Ipv4 {
328 type State<BT: IpDeviceStateBindingsTypes> = Ipv4DeviceState<BT>;
329 type Configuration = Ipv4DeviceConfiguration;
330 type Timer<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> = Ipv4DeviceTimerId<D, BT>;
331 type ManualAddressConfig<I: Instant> = Ipv4AddrConfig<I>;
332 type ConfigurationUpdate = Ipv4DeviceConfigurationUpdate;
333
334 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
335 config.properties
336 }
337
338 fn timer_device_id<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
339 timer: &Self::Timer<D, BT>,
340 ) -> Option<D::Strong> {
341 timer.device_id()
342 }
343}
344
345impl IpDeviceIpExt for Ipv6 {
346 type State<BT: IpDeviceStateBindingsTypes> = Ipv6DeviceState<BT>;
347 type Configuration = Ipv6DeviceConfiguration;
348 type Timer<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> = Ipv6DeviceTimerId<D, BT>;
349 type ManualAddressConfig<I: Instant> = Ipv6AddrManualConfig<I>;
350 type ConfigurationUpdate = Ipv6DeviceConfigurationUpdate;
351
352 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
353 CommonAddressProperties {
354 valid_until: config.valid_until(),
355 preferred_lifetime: config.preferred_lifetime(),
356 }
357 }
358
359 fn timer_device_id<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
360 timer: &Self::Timer<D, BT>,
361 ) -> Option<D::Strong> {
362 timer.device_id()
363 }
364}
365#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
367pub enum IpAddressState {
368 Unavailable,
370 Assigned,
373 Tentative,
377}
378
379#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
381pub enum AddressRemovedReason {
382 Manual,
384 DadFailed,
386}
387
388#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
389#[generic_over_ip(I, Ip)]
390pub enum IpDeviceEvent<DeviceId, I: Ip, Instant> {
392 AddressAdded {
394 device: DeviceId,
396 addr: AddrSubnet<I::Addr>,
398 state: IpAddressState,
400 valid_until: Lifetime<Instant>,
402 preferred_lifetime: PreferredLifetime<Instant>,
404 },
405 AddressRemoved {
407 device: DeviceId,
409 addr: SpecifiedAddr<I::Addr>,
411 reason: AddressRemovedReason,
413 },
414 AddressStateChanged {
416 device: DeviceId,
418 addr: SpecifiedAddr<I::Addr>,
420 state: IpAddressState,
422 },
423 AddressPropertiesChanged {
425 device: DeviceId,
427 addr: SpecifiedAddr<I::Addr>,
429 valid_until: Lifetime<Instant>,
431 preferred_lifetime: PreferredLifetime<Instant>,
433 },
434 EnabledChanged {
436 device: DeviceId,
438 ip_enabled: bool,
440 },
441}
442
443impl<DeviceId, I: Ip, Instant> IpDeviceEvent<DeviceId, I, Instant> {
444 pub fn map_device<N, F: FnOnce(DeviceId) -> N>(self, map: F) -> IpDeviceEvent<N, I, Instant> {
446 match self {
447 IpDeviceEvent::AddressAdded {
448 device,
449 addr,
450 state,
451 valid_until,
452 preferred_lifetime,
453 } => IpDeviceEvent::AddressAdded {
454 device: map(device),
455 addr,
456 state,
457 valid_until,
458 preferred_lifetime,
459 },
460 IpDeviceEvent::AddressRemoved { device, addr, reason } => {
461 IpDeviceEvent::AddressRemoved { device: map(device), addr, reason }
462 }
463 IpDeviceEvent::AddressStateChanged { device, addr, state } => {
464 IpDeviceEvent::AddressStateChanged { device: map(device), addr, state }
465 }
466 IpDeviceEvent::EnabledChanged { device, ip_enabled } => {
467 IpDeviceEvent::EnabledChanged { device: map(device), ip_enabled }
468 }
469 IpDeviceEvent::AddressPropertiesChanged {
470 device,
471 addr,
472 valid_until,
473 preferred_lifetime,
474 } => IpDeviceEvent::AddressPropertiesChanged {
475 device: map(device),
476 addr,
477 valid_until,
478 preferred_lifetime,
479 },
480 }
481 }
482}
483
484pub trait IpDeviceBindingsContext<I: IpDeviceIpExt, D: StrongDeviceIdentifier>:
486 IpDeviceStateBindingsTypes
487 + DeferredResourceRemovalContext
488 + TimerContext
489 + RngContext
490 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>
491{
492}
493impl<
494 D: StrongDeviceIdentifier,
495 I: IpDeviceIpExt,
496 BC: IpDeviceStateBindingsTypes
497 + DeferredResourceRemovalContext
498 + TimerContext
499 + RngContext
500 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>,
501 > IpDeviceBindingsContext<I, D> for BC
502{
503}
504
505pub trait IpDeviceAddressContext<I: IpDeviceIpExt, BT: InstantBindingsTypes>:
507 IpDeviceAddressIdContext<I>
508{
509 fn with_ip_address_data<O, F: FnOnce(&IpAddressData<I, BT::Instant>) -> O>(
512 &mut self,
513 device_id: &Self::DeviceId,
514 addr_id: &Self::AddressId,
515 cb: F,
516 ) -> O;
517
518 fn with_ip_address_data_mut<O, F: FnOnce(&mut IpAddressData<I, BT::Instant>) -> O>(
521 &mut self,
522 device_id: &Self::DeviceId,
523 addr_id: &Self::AddressId,
524 cb: F,
525 ) -> O;
526}
527
528pub trait IpDeviceStateContext<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
530 IpDeviceAddressContext<I, BT>
531{
532 type IpDeviceAddressCtx<'a>: IpDeviceAddressContext<
534 I,
535 BT,
536 DeviceId = Self::DeviceId,
537 AddressId = Self::AddressId,
538 >;
539
540 fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
547 &mut self,
548 device_id: &Self::DeviceId,
549 cb: F,
550 ) -> O;
551
552 fn add_ip_address(
554 &mut self,
555 device_id: &Self::DeviceId,
556 addr: AddrSubnet<I::Addr, I::AssignedWitness>,
557 config: I::AddressConfig<BT::Instant>,
558 ) -> Result<Self::AddressId, ExistsError>;
559
560 fn remove_ip_address(
562 &mut self,
563 device_id: &Self::DeviceId,
564 addr: Self::AddressId,
565 ) -> RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BT>;
566
567 fn get_address_id(
569 &mut self,
570 device_id: &Self::DeviceId,
571 addr: SpecifiedAddr<I::Addr>,
572 ) -> Result<Self::AddressId, NotFoundError>;
573
574 type AddressIdsIter<'a>: Iterator<Item = Self::AddressId> + 'a;
576
577 fn with_address_ids<
580 O,
581 F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
582 >(
583 &mut self,
584 device_id: &Self::DeviceId,
585 cb: F,
586 ) -> O;
587
588 fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
591 &mut self,
592 device_id: &Self::DeviceId,
593 cb: F,
594 ) -> O;
595
596 fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
599 &mut self,
600 device_id: &Self::DeviceId,
601 cb: F,
602 ) -> O;
603
604 fn join_link_multicast_group(
607 &mut self,
608 bindings_ctx: &mut BT,
609 device_id: &Self::DeviceId,
610 multicast_addr: MulticastAddr<I::Addr>,
611 );
612
613 fn leave_link_multicast_group(
616 &mut self,
617 bindings_ctx: &mut BT,
618 device_id: &Self::DeviceId,
619 multicast_addr: MulticastAddr<I::Addr>,
620 );
621}
622
623pub trait WithIpDeviceConfigurationMutInner<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
626 DeviceIdContext<AnyDevice>
627{
628 type IpDeviceStateCtx<'s>: IpDeviceStateContext<I, BT, DeviceId = Self::DeviceId>
630 + GmpHandler<I, BT>
631 + NudIpHandler<I, BT>
632 + 's
633 where
634 Self: 's;
635
636 fn ip_device_configuration_and_ctx(
639 &mut self,
640 ) -> (&I::Configuration, Self::IpDeviceStateCtx<'_>);
641
642 fn with_configuration_and_flags_mut<
645 O,
646 F: FnOnce(&mut I::Configuration, &mut IpDeviceFlags) -> O,
647 >(
648 &mut self,
649 device_id: &Self::DeviceId,
650 cb: F,
651 ) -> O;
652}
653
654pub trait IpDeviceConfigurationContext<
656 I: IpDeviceIpExt,
657 BC: IpDeviceBindingsContext<I, Self::DeviceId>,
658>: IpDeviceStateContext<I, BC> + IpDeviceMtuContext<I> + DeviceIdContext<AnyDevice>
659{
660 type DevicesIter<'s>: Iterator<Item = Self::DeviceId> + 's;
662 type WithIpDeviceConfigurationInnerCtx<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
664 + GmpHandler<I, BC>
665 + NudIpHandler<I, BC>
666 + DadHandler<I, BC>
667 + IpAddressRemovalHandler<I, BC>
668 + IpDeviceMtuContext<I>
669 + 's;
670 type WithIpDeviceConfigurationMutInner<'s>: WithIpDeviceConfigurationMutInner<I, BC, DeviceId = Self::DeviceId>
672 + 's;
673 type DeviceAddressAndGroupsAccessor<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId>
675 + 's;
676
677 fn with_ip_device_configuration<
680 O,
681 F: FnOnce(&I::Configuration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
682 >(
683 &mut self,
684 device_id: &Self::DeviceId,
685 cb: F,
686 ) -> O;
687
688 fn with_ip_device_configuration_mut<
690 O,
691 F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
692 >(
693 &mut self,
694 device_id: &Self::DeviceId,
695 cb: F,
696 ) -> O;
697
698 fn with_devices_and_state<
701 O,
702 F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
703 >(
704 &mut self,
705 cb: F,
706 ) -> O;
707
708 fn loopback_id(&mut self) -> Option<Self::DeviceId>;
711}
712
713pub trait WithIpv6DeviceConfigurationMutInner<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
716 WithIpDeviceConfigurationMutInner<Ipv6, BC>
717{
718 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId>
720 + GmpHandler<Ipv6, BC>
721 + NudIpHandler<Ipv6, BC>
722 + DadHandler<Ipv6, BC>
723 + RsHandler<BC>
724 + SlaacHandler<BC>
725 + RouteDiscoveryHandler<BC>
726 + 's
727 where
728 Self: 's;
729
730 fn ipv6_device_configuration_and_ctx(
733 &mut self,
734 ) -> (&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>);
735}
736
737pub trait Ipv6DeviceConfigurationContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
739 IpDeviceConfigurationContext<Ipv6, BC>
740{
741 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
743 + GmpHandler<Ipv6, BC>
744 + MldPacketHandler<BC, Self::DeviceId>
745 + NudIpHandler<Ipv6, BC>
746 + DadHandler<Ipv6, BC>
747 + RsHandler<BC>
748 + SlaacHandler<BC>
749 + RouteDiscoveryHandler<BC>
750 + 's;
751 type WithIpv6DeviceConfigurationMutInner<'s>: WithIpv6DeviceConfigurationMutInner<BC, DeviceId = Self::DeviceId>
753 + 's;
754
755 fn with_ipv6_device_configuration<
758 O,
759 F: FnOnce(&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) -> O,
760 >(
761 &mut self,
762 device_id: &Self::DeviceId,
763 cb: F,
764 ) -> O;
765
766 fn with_ipv6_device_configuration_mut<
768 O,
769 F: FnOnce(Self::WithIpv6DeviceConfigurationMutInner<'_>) -> O,
770 >(
771 &mut self,
772 device_id: &Self::DeviceId,
773 cb: F,
774 ) -> O;
775}
776
777pub trait Ipv6LinkLayerAddr {
779 fn as_bytes(&self) -> &[u8];
781
782 fn eui64_iid(&self) -> [u8; 8];
784}
785
786pub trait Ipv6DeviceContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
788 IpDeviceStateContext<Ipv6, BC>
789{
790 type LinkLayerAddr: Ipv6LinkLayerAddr;
792
793 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
796
797 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
799
800 fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
802 &mut self,
803 device_id: &Self::DeviceId,
804 cb: F,
805 ) -> O;
806
807 fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
809 &mut self,
810 device_id: &Self::DeviceId,
811 cb: F,
812 ) -> O;
813}
814
815pub trait IpDeviceHandler<I: Ip, BC>: DeviceIdContext<AnyDevice> {
817 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool;
818
819 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8);
820}
821
822impl<
823 I: IpDeviceIpExt,
824 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
825 CC: IpDeviceConfigurationContext<I, BC>,
826 > IpDeviceHandler<I, BC> for CC
827{
828 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool {
829 is_ip_unicast_forwarding_enabled(self, device_id)
830 }
831
832 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8) {
833 self.with_default_hop_limit_mut(device_id, |default_hop_limit| {
834 *default_hop_limit = hop_limit
835 })
836 }
837}
838
839pub fn receive_igmp_packet<CC, BC, B, H>(
841 core_ctx: &mut CC,
842 bindings_ctx: &mut BC,
843 device: &CC::DeviceId,
844 src_ip: Ipv4SourceAddr,
845 dst_ip: SpecifiedAddr<Ipv4Addr>,
846 buffer: B,
847 info: &LocalDeliveryPacketInfo<Ipv4, H>,
848) where
849 CC: IpDeviceConfigurationContext<Ipv4, BC>,
850 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
851 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>: IpDeviceStateContext<Ipv4, BC, DeviceId = CC::DeviceId>
852 + IgmpPacketHandler<BC, CC::DeviceId>,
853 B: BufferMut,
854 H: IpHeaderInfo<Ipv4>,
855{
856 core_ctx.with_ip_device_configuration(device, |_config, mut core_ctx| {
857 IgmpPacketHandler::receive_igmp_packet(
858 &mut core_ctx,
859 bindings_ctx,
860 device,
861 src_ip,
862 dst_ip,
863 buffer,
864 info,
865 )
866 })
867}
868
869pub trait Ipv6DeviceHandler<BC>: IpDeviceHandler<Ipv6, BC> {
871 type LinkLayerAddr: Ipv6LinkLayerAddr;
873
874 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
877
878 fn set_discovered_retrans_timer(
880 &mut self,
881 bindings_ctx: &mut BC,
882 device_id: &Self::DeviceId,
883 retrans_timer: NonZeroDuration,
884 );
885
886 fn handle_received_dad_neighbor_solicitation(
894 &mut self,
895 bindings_ctx: &mut BC,
896 device_id: &Self::DeviceId,
897 addr: UnicastAddr<Ipv6Addr>,
898 nonce: Option<NdpNonce<&'_ [u8]>>,
899 ) -> IpAddressState;
900
901 fn handle_received_neighbor_advertisement(
910 &mut self,
911 bindings_ctx: &mut BC,
912 device_id: &Self::DeviceId,
913 addr: UnicastAddr<Ipv6Addr>,
914 ) -> IpAddressState;
915
916 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
918
919 fn update_discovered_ipv6_route(
921 &mut self,
922 bindings_ctx: &mut BC,
923 device_id: &Self::DeviceId,
924 route: Ipv6DiscoveredRoute,
925 lifetime: Option<NonZeroNdpLifetime>,
926 );
927
928 fn apply_slaac_update(
930 &mut self,
931 bindings_ctx: &mut BC,
932 device_id: &Self::DeviceId,
933 prefix: Subnet<Ipv6Addr>,
934 preferred_lifetime: Option<NonZeroNdpLifetime>,
935 valid_lifetime: Option<NonZeroNdpLifetime>,
936 );
937
938 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
940 &mut self,
941 bindings_ctx: &mut BC,
942 device: &Self::DeviceId,
943 src_ip: Ipv6SourceAddr,
944 dst_ip: SpecifiedAddr<Ipv6Addr>,
945 packet: MldPacket<B>,
946 header_info: &H,
947 );
948}
949
950impl<
951 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
952 CC: Ipv6DeviceContext<BC>
953 + Ipv6DeviceConfigurationContext<BC>
954 + CounterContext<IpCounters<Ipv6>>,
955 > Ipv6DeviceHandler<BC> for CC
956{
957 type LinkLayerAddr = CC::LinkLayerAddr;
958
959 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<CC::LinkLayerAddr> {
960 Ipv6DeviceContext::get_link_layer_addr(self, device_id)
961 }
962
963 fn set_discovered_retrans_timer(
964 &mut self,
965 _bindings_ctx: &mut BC,
966 device_id: &Self::DeviceId,
967 retrans_timer: NonZeroDuration,
968 ) {
969 self.with_network_learned_parameters_mut(device_id, |state| {
970 state.retrans_timer = Some(retrans_timer)
971 })
972 }
973
974 fn handle_received_dad_neighbor_solicitation(
975 &mut self,
976 bindings_ctx: &mut BC,
977 device_id: &Self::DeviceId,
978 addr: UnicastAddr<Ipv6Addr>,
979 nonce: Option<NdpNonce<&'_ [u8]>>,
980 ) -> IpAddressState {
981 let addr_id = match self.get_address_id(device_id, addr.into_specified()) {
982 Ok(o) => o,
983 Err(NotFoundError) => return IpAddressState::Unavailable,
984 };
985
986 match self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
987 core_ctx.handle_incoming_probe(bindings_ctx, device_id, &addr_id, nonce)
988 }) {
989 DadIncomingProbeResult::Assigned => IpAddressState::Assigned,
990 DadIncomingProbeResult::Tentative {
991 meta: Ipv6ProbeResultMetadata { matched_nonce: true },
992 } => {
993 self.counters().version_rx.drop_looped_back_dad_probe.increment();
994
995 IpAddressState::Tentative
1004 }
1005 DadIncomingProbeResult::Uninitialized
1006 | DadIncomingProbeResult::Tentative {
1007 meta: Ipv6ProbeResultMetadata { matched_nonce: false },
1008 } => {
1009 match del_ip_addr(
1017 self,
1018 bindings_ctx,
1019 device_id,
1020 DelIpAddr::AddressId(addr_id),
1021 AddressRemovedReason::DadFailed,
1022 ) {
1023 Ok(result) => {
1024 bindings_ctx.defer_removal_result(result);
1025 IpAddressState::Tentative
1026 }
1027 Err(NotFoundError) => {
1028 IpAddressState::Unavailable
1030 }
1031 }
1032 }
1033 }
1034 }
1035
1036 fn handle_received_neighbor_advertisement(
1037 &mut self,
1038 bindings_ctx: &mut BC,
1039 device_id: &Self::DeviceId,
1040 addr: UnicastAddr<Ipv6Addr>,
1041 ) -> IpAddressState {
1042 let addr_id = match self.get_address_id(device_id, addr.into_specified()) {
1043 Ok(o) => o,
1044 Err(NotFoundError) => return IpAddressState::Unavailable,
1045 };
1046
1047 let assigned = self.with_ip_address_data(
1048 device_id,
1049 &addr_id,
1050 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
1051 );
1052
1053 if assigned {
1054 IpAddressState::Assigned
1055 } else {
1056 match del_ip_addr(
1057 self,
1058 bindings_ctx,
1059 device_id,
1060 DelIpAddr::AddressId(addr_id),
1061 AddressRemovedReason::DadFailed,
1062 ) {
1063 Ok(result) => {
1064 bindings_ctx.defer_removal_result(result);
1065 IpAddressState::Tentative
1066 }
1067 Err(NotFoundError) => {
1068 IpAddressState::Unavailable
1070 }
1071 }
1072 }
1073 }
1074
1075 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
1076 Ipv6DeviceContext::set_link_mtu(self, device_id, mtu)
1077 }
1078
1079 fn update_discovered_ipv6_route(
1080 &mut self,
1081 bindings_ctx: &mut BC,
1082 device_id: &Self::DeviceId,
1083 route: Ipv6DiscoveredRoute,
1084 lifetime: Option<NonZeroNdpLifetime>,
1085 ) {
1086 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1087 RouteDiscoveryHandler::update_route(
1088 &mut core_ctx,
1089 bindings_ctx,
1090 device_id,
1091 route,
1092 lifetime,
1093 )
1094 })
1095 }
1096
1097 fn apply_slaac_update(
1098 &mut self,
1099 bindings_ctx: &mut BC,
1100 device_id: &Self::DeviceId,
1101 prefix: Subnet<Ipv6Addr>,
1102 preferred_lifetime: Option<NonZeroNdpLifetime>,
1103 valid_lifetime: Option<NonZeroNdpLifetime>,
1104 ) {
1105 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1106 SlaacHandler::apply_slaac_update(
1107 &mut core_ctx,
1108 bindings_ctx,
1109 device_id,
1110 prefix,
1111 preferred_lifetime,
1112 valid_lifetime,
1113 )
1114 })
1115 }
1116
1117 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
1118 &mut self,
1119 bindings_ctx: &mut BC,
1120 device: &Self::DeviceId,
1121 src_ip: Ipv6SourceAddr,
1122 dst_ip: SpecifiedAddr<Ipv6Addr>,
1123 packet: MldPacket<B>,
1124 header_info: &H,
1125 ) {
1126 self.with_ipv6_device_configuration(device, |_config, mut core_ctx| {
1127 MldPacketHandler::receive_mld_packet(
1128 &mut core_ctx,
1129 bindings_ctx,
1130 device,
1131 src_ip,
1132 dst_ip,
1133 packet,
1134 header_info,
1135 )
1136 })
1137 }
1138}
1139
1140pub trait IpDeviceSendContext<I: IpExt, BC: TxMetadataBindingsTypes>:
1142 DeviceIdContext<AnyDevice>
1143{
1144 fn send_ip_frame<S>(
1146 &mut self,
1147 bindings_ctx: &mut BC,
1148 device_id: &Self::DeviceId,
1149 destination: IpPacketDestination<I, &Self::DeviceId>,
1150 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
1151 body: S,
1152 egress_proof: ProofOfEgressCheck,
1153 ) -> Result<(), SendFrameError<S>>
1154 where
1155 S: Serializer,
1156 S::Buffer: BufferMut;
1157}
1158
1159fn enable_ipv6_device_with_config<
1160 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1161 CC: Ipv6DeviceContext<BC>
1162 + GmpHandler<Ipv6, BC>
1163 + RsHandler<BC>
1164 + DadHandler<Ipv6, BC>
1165 + SlaacHandler<BC>,
1166>(
1167 core_ctx: &mut CC,
1168 bindings_ctx: &mut BC,
1169 device_id: &CC::DeviceId,
1170 config: &Ipv6DeviceConfiguration,
1171) {
1172 join_ip_multicast_with_config(
1174 core_ctx,
1175 bindings_ctx,
1176 device_id,
1177 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1178 config,
1179 );
1180 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1181
1182 core_ctx
1189 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1190 .into_iter()
1191 .for_each(|addr_id| {
1192 let (state, start_dad) = DadHandler::initialize_duplicate_address_detection(
1193 core_ctx,
1194 bindings_ctx,
1195 device_id,
1196 &addr_id,
1197 )
1198 .into_address_state_and_start_dad();
1199 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1200 device: device_id.clone(),
1201 addr: addr_id.addr().into(),
1202 state,
1203 });
1204 if let Some(token) = start_dad {
1205 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1206 }
1207 });
1208
1209 if core_ctx.get_link_layer_addr(device_id).is_some() {
1212 SlaacHandler::generate_link_local_address(core_ctx, bindings_ctx, device_id);
1213 }
1214
1215 RsHandler::start_router_solicitation(core_ctx, bindings_ctx, device_id);
1216}
1217
1218fn disable_ipv6_device_with_config<
1219 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1220 CC: Ipv6DeviceContext<BC>
1221 + GmpHandler<Ipv6, BC>
1222 + RsHandler<BC>
1223 + DadHandler<Ipv6, BC>
1224 + RouteDiscoveryHandler<BC>
1225 + SlaacHandler<BC>
1226 + NudIpHandler<Ipv6, BC>,
1227>(
1228 core_ctx: &mut CC,
1229 bindings_ctx: &mut BC,
1230 device_id: &CC::DeviceId,
1231 device_config: &Ipv6DeviceConfiguration,
1232) {
1233 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1234
1235 SlaacHandler::remove_all_slaac_addresses(core_ctx, bindings_ctx, device_id);
1236
1237 RouteDiscoveryHandler::invalidate_routes(core_ctx, bindings_ctx, device_id);
1238
1239 RsHandler::stop_router_solicitation(core_ctx, bindings_ctx, device_id);
1240
1241 core_ctx.with_network_learned_parameters_mut(device_id, |params| params.reset());
1244
1245 core_ctx
1248 .with_address_ids(device_id, |addrs, core_ctx| {
1249 addrs
1250 .map(|addr_id| {
1251 core_ctx.with_ip_address_data(
1252 device_id,
1253 &addr_id,
1254 |IpAddressData { flags: _, config }| (addr_id.clone(), *config),
1255 )
1256 })
1257 .collect::<Vec<_>>()
1258 })
1259 .into_iter()
1260 .for_each(|(addr_id, config)| {
1261 if config
1262 .is_some_and(|config| config.is_slaac() && addr_id.addr().addr().is_link_local())
1263 {
1264 del_ip_addr_inner_and_notify_handler(
1265 core_ctx,
1266 bindings_ctx,
1267 device_id,
1268 DelIpAddr::AddressId(addr_id),
1269 AddressRemovedReason::Manual,
1270 device_config,
1271 )
1272 .map(|remove_result| {
1273 bindings_ctx.defer_removal_result(remove_result);
1274 })
1275 .unwrap_or_else(|NotFoundError| {
1276 })
1280 } else {
1281 DadHandler::stop_duplicate_address_detection(
1282 core_ctx,
1283 bindings_ctx,
1284 device_id,
1285 &addr_id,
1286 );
1287 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1288 device: device_id.clone(),
1289 addr: addr_id.addr().into(),
1290 state: IpAddressState::Unavailable,
1291 });
1292 }
1293 });
1294
1295 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1296 leave_ip_multicast_with_config(
1297 core_ctx,
1298 bindings_ctx,
1299 device_id,
1300 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1301 device_config,
1302 );
1303}
1304
1305fn enable_ipv4_device_with_config<
1306 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1307 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC>,
1308>(
1309 core_ctx: &mut CC,
1310 bindings_ctx: &mut BC,
1311 device_id: &CC::DeviceId,
1312 config: &Ipv4DeviceConfiguration,
1313) {
1314 join_ip_multicast_with_config(
1316 core_ctx,
1317 bindings_ctx,
1318 device_id,
1319 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1320 config,
1321 );
1322 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1323 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1324 addrs.for_each(|addr| {
1325 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1327 device: device_id.clone(),
1328 addr: addr.addr().into(),
1329 state: IpAddressState::Assigned,
1330 });
1331 })
1332 })
1333}
1334
1335fn disable_ipv4_device_with_config<
1336 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1337 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC> + NudIpHandler<Ipv4, BC>,
1338>(
1339 core_ctx: &mut CC,
1340 bindings_ctx: &mut BC,
1341 device_id: &CC::DeviceId,
1342 config: &Ipv4DeviceConfiguration,
1343) {
1344 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1345 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1346 leave_ip_multicast_with_config(
1347 core_ctx,
1348 bindings_ctx,
1349 device_id,
1350 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1351 config,
1352 );
1353 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1354 addrs.for_each(|addr| {
1355 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1356 device: device_id.clone(),
1357 addr: addr.addr().into(),
1358 state: IpAddressState::Unavailable,
1359 });
1360 })
1361 })
1362}
1363
1364pub fn get_ipv4_addr_subnet<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv4, BT>>(
1366 core_ctx: &mut CC,
1367 device_id: &CC::DeviceId,
1368) -> Option<AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> {
1369 core_ctx.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next().map(|a| a.addr_sub()))
1370}
1371
1372pub fn get_ipv6_hop_limit<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv6, BT>>(
1374 core_ctx: &mut CC,
1375 device: &CC::DeviceId,
1376) -> NonZeroU8 {
1377 core_ctx.with_default_hop_limit(device, Clone::clone)
1378}
1379
1380pub fn is_ip_unicast_forwarding_enabled<
1382 I: IpDeviceIpExt,
1383 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1384 CC: IpDeviceConfigurationContext<I, BC>,
1385>(
1386 core_ctx: &mut CC,
1387 device_id: &CC::DeviceId,
1388) -> bool {
1389 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1390 AsRef::<IpDeviceConfiguration>::as_ref(state).unicast_forwarding_enabled
1391 })
1392}
1393
1394pub fn is_ip_multicast_forwarding_enabled<
1396 I: IpDeviceIpExt,
1397 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1398 CC: IpDeviceConfigurationContext<I, BC>,
1399>(
1400 core_ctx: &mut CC,
1401 device_id: &CC::DeviceId,
1402) -> bool {
1403 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1404 AsRef::<IpDeviceConfiguration>::as_ref(state).multicast_forwarding_enabled
1405 })
1406}
1407
1408pub fn join_ip_multicast_with_config<
1415 I: IpDeviceIpExt,
1416 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1417 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1418>(
1419 core_ctx: &mut CC,
1420 bindings_ctx: &mut BC,
1421 device_id: &CC::DeviceId,
1422 multicast_addr: MulticastAddr<I::Addr>,
1423 _config: &I::Configuration,
1424) {
1425 match core_ctx.gmp_join_group(bindings_ctx, device_id, multicast_addr) {
1426 GroupJoinResult::Joined(()) => {
1427 core_ctx.join_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1428 }
1429 GroupJoinResult::AlreadyMember => {}
1430 }
1431}
1432
1433pub fn join_ip_multicast<
1444 I: IpDeviceIpExt,
1445 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1446 CC: IpDeviceConfigurationContext<I, BC>,
1447>(
1448 core_ctx: &mut CC,
1449 bindings_ctx: &mut BC,
1450 device_id: &CC::DeviceId,
1451 multicast_addr: MulticastAddr<I::Addr>,
1452) {
1453 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1454 join_ip_multicast_with_config(
1455 &mut core_ctx,
1456 bindings_ctx,
1457 device_id,
1458 multicast_addr,
1459 config,
1460 )
1461 })
1462}
1463
1464pub fn leave_ip_multicast_with_config<
1471 I: IpDeviceIpExt,
1472 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1473 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1474>(
1475 core_ctx: &mut CC,
1476 bindings_ctx: &mut BC,
1477 device_id: &CC::DeviceId,
1478 multicast_addr: MulticastAddr<I::Addr>,
1479 _config: &I::Configuration,
1480) {
1481 match core_ctx.gmp_leave_group(bindings_ctx, device_id, multicast_addr) {
1482 GroupLeaveResult::Left(()) => {
1483 core_ctx.leave_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1484 }
1485 GroupLeaveResult::StillMember => {}
1486 GroupLeaveResult::NotMember => panic!(
1487 "attempted to leave IP multicast group we were not a member of: {}",
1488 multicast_addr,
1489 ),
1490 }
1491}
1492
1493pub fn leave_ip_multicast<
1508 I: IpDeviceIpExt,
1509 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1510 CC: IpDeviceConfigurationContext<I, BC>,
1511>(
1512 core_ctx: &mut CC,
1513 bindings_ctx: &mut BC,
1514 device_id: &CC::DeviceId,
1515 multicast_addr: MulticastAddr<I::Addr>,
1516) {
1517 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1518 leave_ip_multicast_with_config(
1519 &mut core_ctx,
1520 bindings_ctx,
1521 device_id,
1522 multicast_addr,
1523 config,
1524 )
1525 })
1526}
1527
1528pub fn add_ip_addr_subnet_with_config<
1535 I: IpDeviceIpExt,
1536 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1537 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1538>(
1539 core_ctx: &mut CC,
1540 bindings_ctx: &mut BC,
1541 device_id: &CC::DeviceId,
1542 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1543 addr_config: I::AddressConfig<BC::Instant>,
1544 _device_config: &I::Configuration,
1545) -> Result<CC::AddressId, ExistsError> {
1546 info!("adding addr {addr_sub:?} config {addr_config:?} to device {device_id:?}");
1547 let CommonAddressProperties { valid_until, preferred_lifetime } =
1548 I::get_common_props(&addr_config);
1549 let addr_id = core_ctx.add_ip_address(device_id, addr_sub, addr_config)?;
1550 assert_eq!(addr_id.addr().addr(), addr_sub.addr().get());
1551
1552 let ip_enabled =
1553 core_ctx.with_ip_device_flags(device_id, |IpDeviceFlags { ip_enabled }| *ip_enabled);
1554
1555 let (state, start_dad) = if ip_enabled {
1556 DadHandler::initialize_duplicate_address_detection(
1557 core_ctx,
1558 bindings_ctx,
1559 device_id,
1560 &addr_id,
1561 )
1562 .into_address_state_and_start_dad()
1563 } else {
1564 (IpAddressState::Unavailable, None)
1567 };
1568
1569 bindings_ctx.on_event(IpDeviceEvent::AddressAdded {
1570 device: device_id.clone(),
1571 addr: addr_sub.to_witness(),
1572 state,
1573 valid_until,
1574 preferred_lifetime,
1575 });
1576
1577 if let Some(token) = start_dad {
1578 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1579 }
1580
1581 Ok(addr_id)
1582}
1583
1584pub trait IpAddressRemovalHandler<I: IpDeviceIpExt, BC: InstantBindingsTypes>:
1586 DeviceIdContext<AnyDevice>
1587{
1588 fn on_address_removed(
1591 &mut self,
1592 bindings_ctx: &mut BC,
1593 device_id: &Self::DeviceId,
1594 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1595 config: I::AddressConfig<BC::Instant>,
1596 reason: AddressRemovedReason,
1597 );
1598}
1599
1600impl<CC: DeviceIdContext<AnyDevice>, BC: InstantBindingsTypes> IpAddressRemovalHandler<Ipv4, BC>
1602 for CC
1603{
1604 fn on_address_removed(
1605 &mut self,
1606 _bindings_ctx: &mut BC,
1607 _device_id: &Self::DeviceId,
1608 _addr_sub: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
1609 _config: Ipv4AddrConfig<BC::Instant>,
1610 _reason: AddressRemovedReason,
1611 ) {
1612 }
1614}
1615
1616impl<CC: SlaacHandler<BC>, BC: InstantContext> IpAddressRemovalHandler<Ipv6, BC> for CC {
1618 fn on_address_removed(
1619 &mut self,
1620 bindings_ctx: &mut BC,
1621 device_id: &Self::DeviceId,
1622 addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
1623 config: Ipv6AddrConfig<BC::Instant>,
1624 reason: AddressRemovedReason,
1625 ) {
1626 match config {
1627 Ipv6AddrConfig::Slaac(config) => SlaacHandler::on_address_removed(
1628 self,
1629 bindings_ctx,
1630 device_id,
1631 addr_sub,
1632 config,
1633 reason,
1634 ),
1635 Ipv6AddrConfig::Manual(_manual_config) => (),
1636 }
1637 }
1638}
1639
1640#[allow(missing_docs)]
1642pub enum DelIpAddr<Id, A> {
1643 SpecifiedAddr(SpecifiedAddr<A>),
1644 AddressId(Id),
1645}
1646
1647impl<Id: IpAddressId<A>, A: IpAddress<Version: AssignedAddrIpExt>> Display for DelIpAddr<Id, A> {
1648 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1649 match self {
1650 DelIpAddr::SpecifiedAddr(addr) => write!(f, "{}", *addr),
1651 DelIpAddr::AddressId(id) => write!(f, "{}", id.addr()),
1652 }
1653 }
1654}
1655
1656pub fn del_ip_addr_inner<
1659 I: IpDeviceIpExt,
1660 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1661 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1662>(
1663 core_ctx: &mut CC,
1664 bindings_ctx: &mut BC,
1665 device_id: &CC::DeviceId,
1666 addr: DelIpAddr<CC::AddressId, I::Addr>,
1667 reason: AddressRemovedReason,
1668 _config: &I::Configuration,
1670) -> Result<
1671 (
1672 AddrSubnet<I::Addr, I::AssignedWitness>,
1673 I::AddressConfig<BC::Instant>,
1674 RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>,
1675 ),
1676 NotFoundError,
1677> {
1678 let addr_id = match addr {
1679 DelIpAddr::SpecifiedAddr(addr) => core_ctx.get_address_id(device_id, addr)?,
1680 DelIpAddr::AddressId(id) => id,
1681 };
1682 DadHandler::stop_duplicate_address_detection(core_ctx, bindings_ctx, device_id, &addr_id);
1683 let addr_config = core_ctx
1687 .with_ip_address_data_mut(device_id, &addr_id, |addr_data| addr_data.config.take())
1688 .ok_or(NotFoundError)?;
1689
1690 let addr_sub = addr_id.addr_sub();
1691 let result = core_ctx.remove_ip_address(device_id, addr_id);
1692
1693 bindings_ctx.on_event(IpDeviceEvent::AddressRemoved {
1694 device: device_id.clone(),
1695 addr: addr_sub.addr().into(),
1696 reason,
1697 });
1698
1699 Ok((addr_sub, addr_config, result))
1700}
1701
1702fn del_ip_addr<
1704 I: IpDeviceIpExt,
1705 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1706 CC: IpDeviceConfigurationContext<I, BC>,
1707>(
1708 core_ctx: &mut CC,
1709 bindings_ctx: &mut BC,
1710 device_id: &CC::DeviceId,
1711 addr: DelIpAddr<CC::AddressId, I::Addr>,
1712 reason: AddressRemovedReason,
1713) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1714 info!("removing addr {addr} from device {device_id:?}");
1715 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1716 del_ip_addr_inner_and_notify_handler(
1717 &mut core_ctx,
1718 bindings_ctx,
1719 device_id,
1720 addr,
1721 reason,
1722 config,
1723 )
1724 })
1725}
1726
1727fn del_ip_addr_inner_and_notify_handler<
1730 I: IpDeviceIpExt,
1731 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1732 CC: IpDeviceStateContext<I, BC>
1733 + GmpHandler<I, BC>
1734 + DadHandler<I, BC>
1735 + IpAddressRemovalHandler<I, BC>,
1736>(
1737 core_ctx: &mut CC,
1738 bindings_ctx: &mut BC,
1739 device_id: &CC::DeviceId,
1740 addr: DelIpAddr<CC::AddressId, I::Addr>,
1741 reason: AddressRemovedReason,
1742 config: &I::Configuration,
1743) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1744 del_ip_addr_inner(core_ctx, bindings_ctx, device_id, addr, reason, config).map(
1745 |(addr_sub, config, result)| {
1746 core_ctx.on_address_removed(bindings_ctx, device_id, addr_sub, config, reason);
1747 result
1748 },
1749 )
1750}
1751
1752pub fn is_ip_device_enabled<
1754 I: IpDeviceIpExt,
1755 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1756 CC: IpDeviceStateContext<I, BC>,
1757>(
1758 core_ctx: &mut CC,
1759 device_id: &CC::DeviceId,
1760) -> bool {
1761 core_ctx.with_ip_device_flags(device_id, |flags| flags.ip_enabled)
1762}
1763
1764pub fn clear_ipv4_device_state<
1766 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1767 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1768>(
1769 core_ctx: &mut CC,
1770 bindings_ctx: &mut BC,
1771 device_id: &CC::DeviceId,
1772) {
1773 core_ctx.with_ip_device_configuration_mut(device_id, |mut core_ctx| {
1774 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1775 let IpDeviceFlags { ip_enabled } = flags;
1778 core::mem::replace(ip_enabled, false)
1779 });
1780
1781 let (config, mut core_ctx) = core_ctx.ip_device_configuration_and_ctx();
1782 let core_ctx = &mut core_ctx;
1783 if ip_enabled {
1784 disable_ipv4_device_with_config(core_ctx, bindings_ctx, device_id, config);
1785 }
1786 })
1787}
1788
1789pub fn clear_ipv6_device_state<
1791 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1792 CC: Ipv6DeviceConfigurationContext<BC>,
1793>(
1794 core_ctx: &mut CC,
1795 bindings_ctx: &mut BC,
1796 device_id: &CC::DeviceId,
1797) {
1798 core_ctx.with_ipv6_device_configuration_mut(device_id, |mut core_ctx| {
1799 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1800 let IpDeviceFlags { ip_enabled } = flags;
1803 core::mem::replace(ip_enabled, false)
1804 });
1805
1806 let (config, mut core_ctx) = core_ctx.ipv6_device_configuration_and_ctx();
1807 let core_ctx = &mut core_ctx;
1808 if ip_enabled {
1809 disable_ipv6_device_with_config(core_ctx, bindings_ctx, device_id, config);
1810 }
1811 })
1812}
1813
1814#[cfg(any(test, feature = "testutils"))]
1815pub(crate) mod testutil {
1816 use alloc::boxed::Box;
1817
1818 use super::*;
1819
1820 pub fn with_assigned_ipv4_addr_subnets<
1823 BT: IpDeviceStateBindingsTypes,
1824 CC: IpDeviceStateContext<Ipv4, BT>,
1825 O,
1826 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> + '_>) -> O,
1827 >(
1828 core_ctx: &mut CC,
1829 device_id: &CC::DeviceId,
1830 cb: F,
1831 ) -> O {
1832 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1833 cb(Box::new(addrs.map(|a| a.addr_sub())))
1834 })
1835 }
1836
1837 pub fn with_assigned_ipv6_addr_subnets<
1849 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1850 CC: Ipv6DeviceContext<BC>,
1851 O,
1852 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>> + '_>) -> O,
1853 >(
1854 core_ctx: &mut CC,
1855 device_id: &CC::DeviceId,
1856 cb: F,
1857 ) -> O {
1858 core_ctx.with_address_ids(device_id, |addrs, core_ctx| {
1859 cb(Box::new(addrs.filter_map(|addr_id| {
1860 core_ctx
1861 .with_ip_address_data(
1862 device_id,
1863 &addr_id,
1864 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
1865 )
1866 .then(|| addr_id.addr_sub())
1867 })))
1868 })
1869 }
1870}