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::{debug, info};
24use net_types::ip::{
25 AddrSubnet, GenericOverIp, Ip, IpAddress, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr,
26 Ipv6SourceAddr, Mtu, Subnet,
27};
28use net_types::{LinkLocalAddress as _, MulticastAddr, SpecifiedAddr, Witness};
29use netstack3_base::{
30 AnyDevice, AssignedAddrIpExt, Counter, CounterCollectionSpec, DeferredResourceRemovalContext,
31 DeviceIdContext, EventContext, ExistsError, HandleableTimer, Instant, InstantBindingsTypes,
32 InstantContext, IpAddressId, IpDeviceAddr, IpDeviceAddressIdContext, IpExt, Ipv4DeviceAddr,
33 Ipv6DeviceAddr, NotFoundError, RemoveResourceResultWithContext, ResourceCounterContext,
34 RngContext, SendFrameError, StrongDeviceIdentifier, 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::NonZeroNdpLifetime;
41use packet_formats::utils::NonZeroDuration;
42use zerocopy::SplitByteSlice;
43
44use crate::device::CommonAddressProperties;
45use crate::internal::base::{DeviceIpLayerMetadata, IpDeviceMtuContext, IpPacketDestination};
46use crate::internal::counters::IpCounters;
47use crate::internal::device::config::{
48 IpDeviceConfigurationUpdate, Ipv4DeviceConfigurationUpdate, Ipv6DeviceConfigurationUpdate,
49};
50use crate::internal::device::dad::{
51 DadHandler, DadIncomingPacketResult, DadIpExt, DadTimerId, Ipv4DadAddressInfo,
52 Ipv6PacketResultMetadata, NeedsDad,
53};
54use crate::internal::device::nud::NudIpHandler;
55use crate::internal::device::route_discovery::{
56 Ipv6DiscoveredRoute, Ipv6DiscoveredRouteProperties, Ipv6DiscoveredRouteTimerId,
57 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)]
95#[derivative(
96 Clone(bound = ""),
97 Debug(bound = ""),
98 Eq(bound = ""),
99 Hash(bound = ""),
100 PartialEq(bound = "")
101)]
102pub enum Ipv4DeviceTimerId<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> {
103 Igmp(IgmpTimerId<D>),
105 Dad(DadTimerId<Ipv4, D, WeakAddressId<Ipv4, BT>>),
107}
108
109impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> Ipv4DeviceTimerId<D, BT> {
110 fn device_id(&self) -> Option<D::Strong> {
112 match self {
113 Ipv4DeviceTimerId::Igmp(igmp) => igmp.device_id().upgrade(),
114 Ipv4DeviceTimerId::Dad(dad) => dad.device_id().upgrade(),
115 }
116 }
117
118 pub fn into_common(self) -> IpDeviceTimerId<Ipv4, D, BT> {
120 self.into()
121 }
122}
123
124impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<IpDeviceTimerId<Ipv4, D, BT>>
125 for Ipv4DeviceTimerId<D, BT>
126{
127 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv4, D, BT>) -> Self {
128 inner
129 }
130}
131
132impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<Ipv4DeviceTimerId<D, BT>>
133 for IpDeviceTimerId<Ipv4, D, BT>
134{
135 fn from(value: Ipv4DeviceTimerId<D, BT>) -> Self {
136 Self(value)
137 }
138}
139
140impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<IgmpTimerId<D>>
141 for Ipv4DeviceTimerId<D, BT>
142{
143 fn from(id: IgmpTimerId<D>) -> Ipv4DeviceTimerId<D, BT> {
144 Ipv4DeviceTimerId::Igmp(id)
145 }
146}
147
148impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>
149 From<DadTimerId<Ipv4, D, WeakAddressId<Ipv4, BT>>> for Ipv4DeviceTimerId<D, BT>
150{
151 fn from(id: DadTimerId<Ipv4, D, WeakAddressId<Ipv4, BT>>) -> Ipv4DeviceTimerId<D, BT> {
152 Ipv4DeviceTimerId::Dad(id)
153 }
154}
155
156impl<
157 D: WeakDeviceIdentifier,
158 BC: IpDeviceStateBindingsTypes,
159 CC: TimerHandler<BC, IgmpTimerId<D>>
160 + TimerHandler<BC, DadTimerId<Ipv4, D, WeakAddressId<Ipv4, BC>>>,
161> HandleableTimer<CC, BC> for Ipv4DeviceTimerId<D, BC>
162{
163 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
164 match self {
165 Ipv4DeviceTimerId::Igmp(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
166 Ipv4DeviceTimerId::Dad(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
167 }
168 }
169}
170
171impl<I, CC, BC> HandleableTimer<CC, BC> for IpDeviceTimerId<I, CC::WeakDeviceId, BC>
172where
173 I: IpDeviceIpExt,
174 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
175 CC: IpDeviceConfigurationContext<I, BC>,
176 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>:
177 TimerHandler<BC, I::Timer<CC::WeakDeviceId, BC>>,
178{
179 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
180 let Self(id) = self;
181 let Some(device_id) = I::timer_device_id(&id) else {
182 return;
183 };
184 core_ctx.with_ip_device_configuration(&device_id, |_state, mut core_ctx| {
185 TimerHandler::handle_timer(&mut core_ctx, bindings_ctx, id, timer)
186 })
187 }
188}
189
190#[derive(Derivative)]
192#[derivative(
193 Clone(bound = ""),
194 Debug(bound = ""),
195 Eq(bound = ""),
196 Hash(bound = ""),
197 PartialEq(bound = "")
198)]
199#[allow(missing_docs)]
200pub enum Ipv6DeviceTimerId<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> {
201 Mld(MldTimerId<D>),
202 Dad(DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BT>>),
203 Rs(RsTimerId<D>),
204 RouteDiscovery(Ipv6DiscoveredRouteTimerId<D>),
205 Slaac(SlaacTimerId<D>),
206}
207
208impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<IpDeviceTimerId<Ipv6, D, BT>>
209 for Ipv6DeviceTimerId<D, BT>
210{
211 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv6, D, BT>) -> Self {
212 inner
213 }
214}
215
216impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<Ipv6DeviceTimerId<D, BT>>
217 for IpDeviceTimerId<Ipv6, D, BT>
218{
219 fn from(value: Ipv6DeviceTimerId<D, BT>) -> Self {
220 Self(value)
221 }
222}
223
224impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> Ipv6DeviceTimerId<D, BT> {
225 fn device_id(&self) -> Option<D::Strong> {
227 match self {
228 Self::Mld(id) => id.device_id(),
229 Self::Dad(id) => id.device_id(),
230 Self::Rs(id) => id.device_id(),
231 Self::RouteDiscovery(id) => id.device_id(),
232 Self::Slaac(id) => id.device_id(),
233 }
234 .upgrade()
235 }
236
237 pub fn into_common(self) -> IpDeviceTimerId<Ipv6, D, BT> {
239 self.into()
240 }
241}
242
243impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<MldTimerId<D>>
244 for Ipv6DeviceTimerId<D, BT>
245{
246 fn from(id: MldTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
247 Ipv6DeviceTimerId::Mld(id)
248 }
249}
250
251impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>
252 From<DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BT>>> for Ipv6DeviceTimerId<D, BT>
253{
254 fn from(id: DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BT>>) -> Ipv6DeviceTimerId<D, BT> {
255 Ipv6DeviceTimerId::Dad(id)
256 }
257}
258
259impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<RsTimerId<D>>
260 for Ipv6DeviceTimerId<D, BT>
261{
262 fn from(id: RsTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
263 Ipv6DeviceTimerId::Rs(id)
264 }
265}
266
267impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<Ipv6DiscoveredRouteTimerId<D>>
268 for Ipv6DeviceTimerId<D, BT>
269{
270 fn from(id: Ipv6DiscoveredRouteTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
271 Ipv6DeviceTimerId::RouteDiscovery(id)
272 }
273}
274
275impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<SlaacTimerId<D>>
276 for Ipv6DeviceTimerId<D, BT>
277{
278 fn from(id: SlaacTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
279 Ipv6DeviceTimerId::Slaac(id)
280 }
281}
282
283impl<
284 D: WeakDeviceIdentifier,
285 BC: IpDeviceStateBindingsTypes,
286 CC: TimerHandler<BC, RsTimerId<D>>
287 + TimerHandler<BC, Ipv6DiscoveredRouteTimerId<D>>
288 + TimerHandler<BC, MldTimerId<D>>
289 + TimerHandler<BC, SlaacTimerId<D>>
290 + TimerHandler<BC, DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BC>>>,
291> HandleableTimer<CC, BC> for Ipv6DeviceTimerId<D, BC>
292{
293 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
294 match self {
295 Ipv6DeviceTimerId::Mld(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
296 Ipv6DeviceTimerId::Dad(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
297 Ipv6DeviceTimerId::Rs(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
298 Ipv6DeviceTimerId::RouteDiscovery(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
299 Ipv6DeviceTimerId::Slaac(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
300 }
301 }
302}
303
304pub trait IpDeviceIpExt: IpDeviceStateIpExt + AssignedAddrIpExt + gmp::IpExt + DadIpExt {
306 type State<BT: IpDeviceStateBindingsTypes>: AsRef<IpDeviceState<Self, BT>>
308 + AsMut<IpDeviceState<Self, BT>>;
309 type Configuration: AsRef<IpDeviceConfiguration>
311 + AsMut<IpDeviceConfiguration>
312 + Clone
313 + Debug
314 + Eq
315 + PartialEq;
316 type Timer<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>: Into<IpDeviceTimerId<Self, D, BT>>
318 + From<IpDeviceTimerId<Self, D, BT>>
319 + Clone
320 + Eq
321 + PartialEq
322 + Debug
323 + Hash;
324 type ManualAddressConfig<I: Instant>: Default + Debug + Into<Self::AddressConfig<I>>;
326 type ConfigurationUpdate: From<IpDeviceConfigurationUpdate>
328 + AsRef<IpDeviceConfigurationUpdate>
329 + Debug;
330
331 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I>;
333
334 fn timer_device_id<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
336 timer: &Self::Timer<D, BT>,
337 ) -> Option<D::Strong>;
338}
339
340impl IpDeviceIpExt for Ipv4 {
341 type State<BT: IpDeviceStateBindingsTypes> = Ipv4DeviceState<BT>;
342 type Configuration = Ipv4DeviceConfiguration;
343 type Timer<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> = Ipv4DeviceTimerId<D, BT>;
344 type ManualAddressConfig<I: Instant> = Ipv4AddrConfig<I>;
345 type ConfigurationUpdate = Ipv4DeviceConfigurationUpdate;
346
347 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
348 config.properties
349 }
350
351 fn timer_device_id<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
352 timer: &Self::Timer<D, BT>,
353 ) -> Option<D::Strong> {
354 timer.device_id()
355 }
356}
357
358impl IpDeviceIpExt for Ipv6 {
359 type State<BT: IpDeviceStateBindingsTypes> = Ipv6DeviceState<BT>;
360 type Configuration = Ipv6DeviceConfiguration;
361 type Timer<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> = Ipv6DeviceTimerId<D, BT>;
362 type ManualAddressConfig<I: Instant> = Ipv6AddrManualConfig<I>;
363 type ConfigurationUpdate = Ipv6DeviceConfigurationUpdate;
364
365 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
366 CommonAddressProperties {
367 valid_until: config.valid_until(),
368 preferred_lifetime: config.preferred_lifetime(),
369 }
370 }
371
372 fn timer_device_id<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
373 timer: &Self::Timer<D, BT>,
374 ) -> Option<D::Strong> {
375 timer.device_id()
376 }
377}
378#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
380pub enum IpAddressState {
381 Unavailable,
383 Assigned,
386 Tentative,
390}
391
392#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
394pub enum AddressRemovedReason {
395 Manual,
397 DadFailed,
399 Forfeited,
402}
403
404#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
405#[generic_over_ip(I, Ip)]
406pub enum IpDeviceEvent<DeviceId, I: Ip, Instant> {
408 AddressAdded {
410 device: DeviceId,
412 addr: AddrSubnet<I::Addr>,
414 state: IpAddressState,
416 valid_until: Lifetime<Instant>,
418 preferred_lifetime: PreferredLifetime<Instant>,
420 },
421 AddressRemoved {
423 device: DeviceId,
425 addr: SpecifiedAddr<I::Addr>,
427 reason: AddressRemovedReason,
429 },
430 AddressStateChanged {
432 device: DeviceId,
434 addr: SpecifiedAddr<I::Addr>,
436 state: IpAddressState,
438 },
439 AddressPropertiesChanged {
441 device: DeviceId,
443 addr: SpecifiedAddr<I::Addr>,
445 valid_until: Lifetime<Instant>,
447 preferred_lifetime: PreferredLifetime<Instant>,
449 },
450 EnabledChanged {
452 device: DeviceId,
454 ip_enabled: bool,
456 },
457}
458
459impl<DeviceId, I: Ip, Instant> IpDeviceEvent<DeviceId, I, Instant> {
460 pub fn map_device<N, F: FnOnce(DeviceId) -> N>(self, map: F) -> IpDeviceEvent<N, I, Instant> {
462 match self {
463 IpDeviceEvent::AddressAdded {
464 device,
465 addr,
466 state,
467 valid_until,
468 preferred_lifetime,
469 } => IpDeviceEvent::AddressAdded {
470 device: map(device),
471 addr,
472 state,
473 valid_until,
474 preferred_lifetime,
475 },
476 IpDeviceEvent::AddressRemoved { device, addr, reason } => {
477 IpDeviceEvent::AddressRemoved { device: map(device), addr, reason }
478 }
479 IpDeviceEvent::AddressStateChanged { device, addr, state } => {
480 IpDeviceEvent::AddressStateChanged { device: map(device), addr, state }
481 }
482 IpDeviceEvent::EnabledChanged { device, ip_enabled } => {
483 IpDeviceEvent::EnabledChanged { device: map(device), ip_enabled }
484 }
485 IpDeviceEvent::AddressPropertiesChanged {
486 device,
487 addr,
488 valid_until,
489 preferred_lifetime,
490 } => IpDeviceEvent::AddressPropertiesChanged {
491 device: map(device),
492 addr,
493 valid_until,
494 preferred_lifetime,
495 },
496 }
497 }
498}
499
500pub trait IpDeviceBindingsContext<I: IpDeviceIpExt, D: StrongDeviceIdentifier>:
502 IpDeviceStateBindingsTypes
503 + DeferredResourceRemovalContext
504 + TimerContext
505 + RngContext
506 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>
507{
508}
509impl<
510 D: StrongDeviceIdentifier,
511 I: IpDeviceIpExt,
512 BC: IpDeviceStateBindingsTypes
513 + DeferredResourceRemovalContext
514 + TimerContext
515 + RngContext
516 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>,
517> IpDeviceBindingsContext<I, D> for BC
518{
519}
520
521pub trait IpDeviceAddressContext<I: IpDeviceIpExt, BT: InstantBindingsTypes>:
523 IpDeviceAddressIdContext<I>
524{
525 fn with_ip_address_data<O, F: FnOnce(&IpAddressData<I, BT::Instant>) -> O>(
528 &mut self,
529 device_id: &Self::DeviceId,
530 addr_id: &Self::AddressId,
531 cb: F,
532 ) -> O;
533
534 fn with_ip_address_data_mut<O, F: FnOnce(&mut IpAddressData<I, BT::Instant>) -> O>(
537 &mut self,
538 device_id: &Self::DeviceId,
539 addr_id: &Self::AddressId,
540 cb: F,
541 ) -> O;
542}
543
544pub trait IpDeviceStateContext<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
546 IpDeviceAddressContext<I, BT>
547{
548 type IpDeviceAddressCtx<'a>: IpDeviceAddressContext<I, BT, DeviceId = Self::DeviceId, AddressId = Self::AddressId>;
550
551 fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
558 &mut self,
559 device_id: &Self::DeviceId,
560 cb: F,
561 ) -> O;
562
563 fn remove_ip_address(
565 &mut self,
566 device_id: &Self::DeviceId,
567 addr: Self::AddressId,
568 ) -> RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BT>;
569
570 fn get_address_id(
572 &mut self,
573 device_id: &Self::DeviceId,
574 addr: SpecifiedAddr<I::Addr>,
575 ) -> Result<Self::AddressId, NotFoundError>;
576
577 type AddressIdsIter<'a>: Iterator<Item = Self::AddressId> + 'a;
579
580 fn with_address_ids<
583 O,
584 F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
585 >(
586 &mut self,
587 device_id: &Self::DeviceId,
588 cb: F,
589 ) -> O;
590
591 fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
594 &mut self,
595 device_id: &Self::DeviceId,
596 cb: F,
597 ) -> O;
598
599 fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
602 &mut self,
603 device_id: &Self::DeviceId,
604 cb: F,
605 ) -> O;
606
607 fn join_link_multicast_group(
610 &mut self,
611 bindings_ctx: &mut BT,
612 device_id: &Self::DeviceId,
613 multicast_addr: MulticastAddr<I::Addr>,
614 );
615
616 fn leave_link_multicast_group(
619 &mut self,
620 bindings_ctx: &mut BT,
621 device_id: &Self::DeviceId,
622 multicast_addr: MulticastAddr<I::Addr>,
623 );
624}
625
626pub trait IpDeviceAddAddressContext<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
632 IpDeviceAddressContext<I, BT>
633{
634 fn add_ip_address(
636 &mut self,
637 device_id: &Self::DeviceId,
638 addr: AddrSubnet<I::Addr, I::AssignedWitness>,
639 config: I::AddressConfig<BT::Instant>,
640 ) -> Result<Self::AddressId, ExistsError>;
641}
642
643pub trait WithIpDeviceConfigurationMutInner<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
646 DeviceIdContext<AnyDevice>
647{
648 type IpDeviceStateCtx<'s>: IpDeviceStateContext<I, BT, DeviceId = Self::DeviceId>
650 + IpDeviceAddAddressContext<I, BT>
651 + GmpHandler<I, BT>
652 + NudIpHandler<I, BT>
653 + DadHandler<I, BT>
654 + 's
655 where
656 Self: 's;
657
658 fn ip_device_configuration_and_ctx(
661 &mut self,
662 ) -> (&I::Configuration, Self::IpDeviceStateCtx<'_>);
663
664 fn with_configuration_and_flags_mut<
667 O,
668 F: FnOnce(&mut I::Configuration, &mut IpDeviceFlags) -> O,
669 >(
670 &mut self,
671 device_id: &Self::DeviceId,
672 cb: F,
673 ) -> O;
674}
675
676pub trait IpDeviceConfigurationContext<
678 I: IpDeviceIpExt,
679 BC: IpDeviceBindingsContext<I, Self::DeviceId>,
680>: IpDeviceStateContext<I, BC> + IpDeviceMtuContext<I> + DeviceIdContext<AnyDevice>
681{
682 type DevicesIter<'s>: Iterator<Item = Self::DeviceId> + 's;
684 type WithIpDeviceConfigurationInnerCtx<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
686 + GmpHandler<I, BC>
687 + NudIpHandler<I, BC>
688 + DadHandler<I, BC>
689 + IpAddressRemovalHandler<I, BC>
690 + IpDeviceMtuContext<I>
691 + 's;
692 type WithIpDeviceConfigurationMutInner<'s>: WithIpDeviceConfigurationMutInner<I, BC, DeviceId = Self::DeviceId>
694 + 's;
695 type DeviceAddressAndGroupsAccessor<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId>
697 + 's;
698
699 fn with_ip_device_configuration<
702 O,
703 F: FnOnce(&I::Configuration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
704 >(
705 &mut self,
706 device_id: &Self::DeviceId,
707 cb: F,
708 ) -> O;
709
710 fn with_ip_device_configuration_mut<
712 O,
713 F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
714 >(
715 &mut self,
716 device_id: &Self::DeviceId,
717 cb: F,
718 ) -> O;
719
720 fn with_devices_and_state<
723 O,
724 F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
725 >(
726 &mut self,
727 cb: F,
728 ) -> O;
729
730 fn loopback_id(&mut self) -> Option<Self::DeviceId>;
733}
734
735pub trait WithIpv6DeviceConfigurationMutInner<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
738 WithIpDeviceConfigurationMutInner<Ipv6, BC>
739{
740 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId>
742 + GmpHandler<Ipv6, BC>
743 + NudIpHandler<Ipv6, BC>
744 + DadHandler<Ipv6, BC>
745 + RsHandler<BC>
746 + SlaacHandler<BC>
747 + RouteDiscoveryHandler<BC>
748 + 's
749 where
750 Self: 's;
751
752 fn ipv6_device_configuration_and_ctx(
755 &mut self,
756 ) -> (&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>);
757}
758
759pub trait Ipv6DeviceConfigurationContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
761 IpDeviceConfigurationContext<Ipv6, BC>
762{
763 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
765 + GmpHandler<Ipv6, BC>
766 + MldPacketHandler<BC, Self::DeviceId>
767 + NudIpHandler<Ipv6, BC>
768 + DadHandler<Ipv6, BC>
769 + RsHandler<BC>
770 + SlaacHandler<BC>
771 + RouteDiscoveryHandler<BC>
772 + 's;
773 type WithIpv6DeviceConfigurationMutInner<'s>: WithIpv6DeviceConfigurationMutInner<BC, DeviceId = Self::DeviceId>
775 + 's;
776
777 fn with_ipv6_device_configuration<
780 O,
781 F: FnOnce(&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) -> O,
782 >(
783 &mut self,
784 device_id: &Self::DeviceId,
785 cb: F,
786 ) -> O;
787
788 fn with_ipv6_device_configuration_mut<
790 O,
791 F: FnOnce(Self::WithIpv6DeviceConfigurationMutInner<'_>) -> O,
792 >(
793 &mut self,
794 device_id: &Self::DeviceId,
795 cb: F,
796 ) -> O;
797}
798
799pub trait Ipv6LinkLayerAddr {
801 fn as_bytes(&self) -> &[u8];
803
804 fn eui64_iid(&self) -> [u8; 8];
806}
807
808pub trait Ipv6DeviceContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
810 IpDeviceStateContext<Ipv6, BC>
811{
812 type LinkLayerAddr: Ipv6LinkLayerAddr;
814
815 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
818
819 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
821
822 fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
824 &mut self,
825 device_id: &Self::DeviceId,
826 cb: F,
827 ) -> O;
828
829 fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
831 &mut self,
832 device_id: &Self::DeviceId,
833 cb: F,
834 ) -> O;
835}
836
837pub trait IpDeviceHandler<I: IpDeviceIpExt, BC>: DeviceIdContext<AnyDevice> {
839 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool;
841
842 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8);
844
845 fn handle_received_dad_packet(
860 &mut self,
861 bindings_ctx: &mut BC,
862 device_id: &Self::DeviceId,
863 addr: SpecifiedAddr<I::Addr>,
864 packet_data: I::ReceivedPacketData<'_>,
865 ) -> Option<IpAddressState>;
866}
867
868impl<
869 I: IpDeviceIpExt,
870 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
871 CC: IpDeviceConfigurationContext<I, BC> + ResourceCounterContext<CC::DeviceId, IpCounters<I>>,
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 fn handle_received_dad_packet(
885 &mut self,
886 bindings_ctx: &mut BC,
887 device_id: &Self::DeviceId,
888 addr: SpecifiedAddr<I::Addr>,
889 packet_data: I::ReceivedPacketData<'_>,
890 ) -> Option<IpAddressState> {
891 let addr_id = match self.get_address_id(device_id, addr) {
892 Ok(o) => o,
893 Err(NotFoundError) => return None,
894 };
895
896 let orig_state =
897 match self.with_ip_device_configuration(device_id, |_config, mut core_ctx| {
898 core_ctx.handle_incoming_packet(bindings_ctx, device_id, &addr_id, packet_data)
899 }) {
900 DadIncomingPacketResult::Assigned { should_remove } => {
901 if !should_remove {
902 return Some(IpAddressState::Assigned);
904 } else {
905 IpAddressState::Assigned
916 }
917 }
918 DadIncomingPacketResult::Tentative { meta } => {
919 #[derive(GenericOverIp)]
920 #[generic_over_ip(I, Ip)]
921 struct Wrapped<I: IpDeviceIpExt>(I::IncomingPacketResultMeta);
922 let is_looped_back = I::map_ip_in(
923 Wrapped(meta),
924 |Wrapped(())| false,
927 |Wrapped(Ipv6PacketResultMetadata { matched_nonce })| matched_nonce,
940 );
941
942 if is_looped_back {
943 self.increment_both(device_id, |c| {
945 #[derive(GenericOverIp)]
946 #[generic_over_ip(I, Ip)]
947 struct InCounters<'a, I: IpDeviceIpExt>(
948 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<
949 Counter,
950 >,
951 );
952 I::map_ip_in::<_, _>(
953 InCounters(&c.version_rx),
954 |_counters| {
955 unreachable!("Looped back ARP probes are dropped in ARP")
956 },
957 |InCounters(counters)| &counters.drop_looped_back_dad_probe,
958 )
959 });
960
961 return Some(IpAddressState::Tentative);
964 } else {
965 IpAddressState::Tentative
967 }
968 }
969 DadIncomingPacketResult::Uninitialized => IpAddressState::Unavailable,
970 };
971
972 let removal_reason = match orig_state {
975 IpAddressState::Assigned => AddressRemovedReason::Forfeited,
978 IpAddressState::Tentative | IpAddressState::Unavailable => {
981 AddressRemovedReason::DadFailed
982 }
983 };
984 match del_ip_addr(
985 self,
986 bindings_ctx,
987 device_id,
988 DelIpAddr::AddressId(addr_id),
989 removal_reason,
990 ) {
991 Ok(result) => {
992 bindings_ctx.defer_removal_result(result);
993 Some(orig_state)
994 }
995 Err(NotFoundError) => {
996 None
998 }
999 }
1000 }
1001}
1002
1003pub fn receive_igmp_packet<CC, BC, B, H>(
1005 core_ctx: &mut CC,
1006 bindings_ctx: &mut BC,
1007 device: &CC::DeviceId,
1008 src_ip: Ipv4SourceAddr,
1009 dst_ip: SpecifiedAddr<Ipv4Addr>,
1010 buffer: B,
1011 info: &LocalDeliveryPacketInfo<Ipv4, H>,
1012) where
1013 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1014 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1015 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>: IpDeviceStateContext<Ipv4, BC, DeviceId = CC::DeviceId>
1016 + IgmpPacketHandler<BC, CC::DeviceId>,
1017 B: BufferMut,
1018 H: IpHeaderInfo<Ipv4>,
1019{
1020 core_ctx.with_ip_device_configuration(device, |_config, mut core_ctx| {
1021 IgmpPacketHandler::receive_igmp_packet(
1022 &mut core_ctx,
1023 bindings_ctx,
1024 device,
1025 src_ip,
1026 dst_ip,
1027 buffer,
1028 info,
1029 )
1030 })
1031}
1032
1033pub trait Ipv6DeviceHandler<BC>: IpDeviceHandler<Ipv6, BC> {
1035 type LinkLayerAddr: Ipv6LinkLayerAddr;
1037
1038 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
1041
1042 fn set_discovered_retrans_timer(
1044 &mut self,
1045 bindings_ctx: &mut BC,
1046 device_id: &Self::DeviceId,
1047 retrans_timer: NonZeroDuration,
1048 );
1049
1050 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
1052
1053 fn update_discovered_ipv6_route(
1055 &mut self,
1056 bindings_ctx: &mut BC,
1057 device_id: &Self::DeviceId,
1058 route: Ipv6DiscoveredRoute,
1059 properties: Ipv6DiscoveredRouteProperties,
1060 lifetime: Option<NonZeroNdpLifetime>,
1061 );
1062
1063 fn apply_slaac_update(
1065 &mut self,
1066 bindings_ctx: &mut BC,
1067 device_id: &Self::DeviceId,
1068 prefix: Subnet<Ipv6Addr>,
1069 preferred_lifetime: Option<NonZeroNdpLifetime>,
1070 valid_lifetime: Option<NonZeroNdpLifetime>,
1071 );
1072
1073 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
1075 &mut self,
1076 bindings_ctx: &mut BC,
1077 device: &Self::DeviceId,
1078 src_ip: Ipv6SourceAddr,
1079 dst_ip: SpecifiedAddr<Ipv6Addr>,
1080 packet: MldPacket<B>,
1081 header_info: &H,
1082 );
1083}
1084
1085impl<
1086 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1087 CC: Ipv6DeviceContext<BC>
1088 + Ipv6DeviceConfigurationContext<BC>
1089 + ResourceCounterContext<CC::DeviceId, IpCounters<Ipv6>>,
1090> Ipv6DeviceHandler<BC> for CC
1091{
1092 type LinkLayerAddr = CC::LinkLayerAddr;
1093
1094 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<CC::LinkLayerAddr> {
1095 Ipv6DeviceContext::get_link_layer_addr(self, device_id)
1096 }
1097
1098 fn set_discovered_retrans_timer(
1099 &mut self,
1100 _bindings_ctx: &mut BC,
1101 device_id: &Self::DeviceId,
1102 retrans_timer: NonZeroDuration,
1103 ) {
1104 self.with_network_learned_parameters_mut(device_id, |state| {
1105 state.retrans_timer = Some(retrans_timer)
1106 })
1107 }
1108
1109 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
1110 Ipv6DeviceContext::set_link_mtu(self, device_id, mtu)
1111 }
1112
1113 fn update_discovered_ipv6_route(
1114 &mut self,
1115 bindings_ctx: &mut BC,
1116 device_id: &Self::DeviceId,
1117 route: Ipv6DiscoveredRoute,
1118 properties: Ipv6DiscoveredRouteProperties,
1119 lifetime: Option<NonZeroNdpLifetime>,
1120 ) {
1121 self.with_ipv6_device_configuration(device_id, |config, mut core_ctx| {
1122 RouteDiscoveryHandler::update_route(
1123 &mut core_ctx,
1124 bindings_ctx,
1125 device_id,
1126 route,
1127 properties,
1128 lifetime,
1129 &config.route_discovery_config,
1130 )
1131 })
1132 }
1133
1134 fn apply_slaac_update(
1135 &mut self,
1136 bindings_ctx: &mut BC,
1137 device_id: &Self::DeviceId,
1138 prefix: Subnet<Ipv6Addr>,
1139 preferred_lifetime: Option<NonZeroNdpLifetime>,
1140 valid_lifetime: Option<NonZeroNdpLifetime>,
1141 ) {
1142 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1143 SlaacHandler::apply_slaac_update(
1144 &mut core_ctx,
1145 bindings_ctx,
1146 device_id,
1147 prefix,
1148 preferred_lifetime,
1149 valid_lifetime,
1150 )
1151 })
1152 }
1153
1154 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
1155 &mut self,
1156 bindings_ctx: &mut BC,
1157 device: &Self::DeviceId,
1158 src_ip: Ipv6SourceAddr,
1159 dst_ip: SpecifiedAddr<Ipv6Addr>,
1160 packet: MldPacket<B>,
1161 header_info: &H,
1162 ) {
1163 self.with_ipv6_device_configuration(device, |_config, mut core_ctx| {
1164 MldPacketHandler::receive_mld_packet(
1165 &mut core_ctx,
1166 bindings_ctx,
1167 device,
1168 src_ip,
1169 dst_ip,
1170 packet,
1171 header_info,
1172 )
1173 })
1174 }
1175}
1176
1177pub trait IpDeviceSendContext<I: IpExt, BC: TxMetadataBindingsTypes>:
1179 DeviceIdContext<AnyDevice>
1180{
1181 fn send_ip_frame<S>(
1183 &mut self,
1184 bindings_ctx: &mut BC,
1185 device_id: &Self::DeviceId,
1186 destination: IpPacketDestination<I, &Self::DeviceId>,
1187 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
1188 body: S,
1189 egress_proof: ProofOfEgressCheck,
1190 ) -> Result<(), SendFrameError<S>>
1191 where
1192 S: Serializer,
1193 S::Buffer: BufferMut;
1194}
1195
1196fn enable_ipv6_device_with_config<
1197 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1198 CC: Ipv6DeviceContext<BC>
1199 + GmpHandler<Ipv6, BC>
1200 + RsHandler<BC>
1201 + DadHandler<Ipv6, BC>
1202 + SlaacHandler<BC>,
1203>(
1204 core_ctx: &mut CC,
1205 bindings_ctx: &mut BC,
1206 device_id: &CC::DeviceId,
1207 config: &Ipv6DeviceConfiguration,
1208) {
1209 join_ip_multicast_with_config(
1211 core_ctx,
1212 bindings_ctx,
1213 device_id,
1214 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1215 config,
1216 );
1217 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1218
1219 core_ctx
1226 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1227 .into_iter()
1228 .for_each(|addr_id| {
1229 let needs_dad = DadHandler::initialize_duplicate_address_detection(
1230 core_ctx,
1231 bindings_ctx,
1232 device_id,
1233 &addr_id,
1234 |state| IpDeviceEvent::AddressStateChanged {
1235 device: device_id.clone(),
1236 addr: addr_id.addr().into(),
1237 state,
1238 },
1239 );
1240 match needs_dad {
1241 NeedsDad::Yes(token) => {
1242 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1243 }
1244 NeedsDad::No => {}
1245 }
1246 });
1247
1248 if core_ctx.get_link_layer_addr(device_id).is_some() {
1251 SlaacHandler::generate_link_local_address(core_ctx, bindings_ctx, device_id);
1252 }
1253
1254 RsHandler::start_router_solicitation(core_ctx, bindings_ctx, device_id);
1255}
1256
1257fn disable_ipv6_device_with_config<
1258 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1259 CC: Ipv6DeviceContext<BC>
1260 + GmpHandler<Ipv6, BC>
1261 + RsHandler<BC>
1262 + DadHandler<Ipv6, BC>
1263 + RouteDiscoveryHandler<BC>
1264 + SlaacHandler<BC>
1265 + NudIpHandler<Ipv6, BC>,
1266>(
1267 core_ctx: &mut CC,
1268 bindings_ctx: &mut BC,
1269 device_id: &CC::DeviceId,
1270 device_config: &Ipv6DeviceConfiguration,
1271) {
1272 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1273
1274 SlaacHandler::remove_all_slaac_addresses(core_ctx, bindings_ctx, device_id);
1275
1276 RouteDiscoveryHandler::invalidate_routes(core_ctx, bindings_ctx, device_id);
1277
1278 RsHandler::stop_router_solicitation(core_ctx, bindings_ctx, device_id);
1279
1280 core_ctx.with_network_learned_parameters_mut(device_id, |params| params.reset());
1283
1284 core_ctx
1287 .with_address_ids(device_id, |addrs, core_ctx| {
1288 addrs
1289 .map(|addr_id| {
1290 core_ctx.with_ip_address_data(
1291 device_id,
1292 &addr_id,
1293 |IpAddressData { flags: _, config }| (addr_id.clone(), *config),
1294 )
1295 })
1296 .collect::<Vec<_>>()
1297 })
1298 .into_iter()
1299 .for_each(|(addr_id, config)| {
1300 if config
1301 .is_some_and(|config| config.is_slaac() && addr_id.addr().addr().is_link_local())
1302 {
1303 del_ip_addr_inner_and_notify_handler(
1304 core_ctx,
1305 bindings_ctx,
1306 device_id,
1307 DelIpAddr::AddressId(addr_id),
1308 AddressRemovedReason::Manual,
1309 device_config,
1310 )
1311 .map(|remove_result| {
1312 bindings_ctx.defer_removal_result(remove_result);
1313 })
1314 .unwrap_or_else(|NotFoundError| {
1315 })
1319 } else {
1320 DadHandler::stop_duplicate_address_detection(
1321 core_ctx,
1322 bindings_ctx,
1323 device_id,
1324 &addr_id,
1325 );
1326 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1327 device: device_id.clone(),
1328 addr: addr_id.addr().into(),
1329 state: IpAddressState::Unavailable,
1330 });
1331 }
1332 });
1333
1334 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1335 leave_ip_multicast_with_config(
1336 core_ctx,
1337 bindings_ctx,
1338 device_id,
1339 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1340 device_config,
1341 );
1342}
1343
1344fn enable_ipv4_device_with_config<
1345 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1346 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC> + DadHandler<Ipv4, BC>,
1347>(
1348 core_ctx: &mut CC,
1349 bindings_ctx: &mut BC,
1350 device_id: &CC::DeviceId,
1351 config: &Ipv4DeviceConfiguration,
1352) {
1353 join_ip_multicast_with_config(
1355 core_ctx,
1356 bindings_ctx,
1357 device_id,
1358 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1359 config,
1360 );
1361 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1362 core_ctx
1363 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1364 .into_iter()
1365 .for_each(|addr_id| {
1366 let needs_dad = DadHandler::initialize_duplicate_address_detection(
1367 core_ctx,
1368 bindings_ctx,
1369 device_id,
1370 &addr_id,
1371 |state| IpDeviceEvent::AddressStateChanged {
1372 device: device_id.clone(),
1373 addr: addr_id.addr().into(),
1374 state,
1375 },
1376 );
1377 match needs_dad {
1378 NeedsDad::Yes(token) => {
1379 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1380 }
1381 NeedsDad::No => {}
1382 }
1383 })
1384}
1385
1386fn disable_ipv4_device_with_config<
1387 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1388 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC> + NudIpHandler<Ipv4, BC>,
1389>(
1390 core_ctx: &mut CC,
1391 bindings_ctx: &mut BC,
1392 device_id: &CC::DeviceId,
1393 config: &Ipv4DeviceConfiguration,
1394) {
1395 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1396 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1397 leave_ip_multicast_with_config(
1398 core_ctx,
1399 bindings_ctx,
1400 device_id,
1401 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1402 config,
1403 );
1404 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1405 addrs.for_each(|addr| {
1406 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1407 device: device_id.clone(),
1408 addr: addr.addr().into(),
1409 state: IpAddressState::Unavailable,
1410 });
1411 })
1412 })
1413}
1414
1415pub fn get_ipv4_addr_subnet<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv4, BT>>(
1417 core_ctx: &mut CC,
1418 device_id: &CC::DeviceId,
1419) -> Option<AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> {
1420 core_ctx.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next().map(|a| a.addr_sub()))
1421}
1422
1423pub fn get_ipv6_hop_limit<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv6, BT>>(
1425 core_ctx: &mut CC,
1426 device: &CC::DeviceId,
1427) -> NonZeroU8 {
1428 core_ctx.with_default_hop_limit(device, Clone::clone)
1429}
1430
1431pub fn is_ip_unicast_forwarding_enabled<
1433 I: IpDeviceIpExt,
1434 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1435 CC: IpDeviceConfigurationContext<I, BC>,
1436>(
1437 core_ctx: &mut CC,
1438 device_id: &CC::DeviceId,
1439) -> bool {
1440 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1441 AsRef::<IpDeviceConfiguration>::as_ref(state).unicast_forwarding_enabled
1442 })
1443}
1444
1445pub fn is_ip_multicast_forwarding_enabled<
1447 I: IpDeviceIpExt,
1448 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1449 CC: IpDeviceConfigurationContext<I, BC>,
1450>(
1451 core_ctx: &mut CC,
1452 device_id: &CC::DeviceId,
1453) -> bool {
1454 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1455 AsRef::<IpDeviceConfiguration>::as_ref(state).multicast_forwarding_enabled
1456 })
1457}
1458
1459pub fn join_ip_multicast_with_config<
1466 I: IpDeviceIpExt,
1467 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1468 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1469>(
1470 core_ctx: &mut CC,
1471 bindings_ctx: &mut BC,
1472 device_id: &CC::DeviceId,
1473 multicast_addr: MulticastAddr<I::Addr>,
1474 _config: &I::Configuration,
1475) {
1476 match core_ctx.gmp_join_group(bindings_ctx, device_id, multicast_addr) {
1477 GroupJoinResult::Joined(()) => {
1478 debug!("joined IP Multicast Group {multicast_addr} on device {device_id:?}");
1479 core_ctx.join_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1480 }
1481 GroupJoinResult::AlreadyMember => {}
1482 }
1483}
1484
1485pub fn join_ip_multicast<
1496 I: IpDeviceIpExt,
1497 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1498 CC: IpDeviceConfigurationContext<I, BC>,
1499>(
1500 core_ctx: &mut CC,
1501 bindings_ctx: &mut BC,
1502 device_id: &CC::DeviceId,
1503 multicast_addr: MulticastAddr<I::Addr>,
1504) {
1505 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1506 join_ip_multicast_with_config(
1507 &mut core_ctx,
1508 bindings_ctx,
1509 device_id,
1510 multicast_addr,
1511 config,
1512 )
1513 })
1514}
1515
1516pub fn leave_ip_multicast_with_config<
1523 I: IpDeviceIpExt,
1524 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1525 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1526>(
1527 core_ctx: &mut CC,
1528 bindings_ctx: &mut BC,
1529 device_id: &CC::DeviceId,
1530 multicast_addr: MulticastAddr<I::Addr>,
1531 _config: &I::Configuration,
1532) {
1533 match core_ctx.gmp_leave_group(bindings_ctx, device_id, multicast_addr) {
1534 GroupLeaveResult::Left(()) => {
1535 core_ctx.leave_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1536 }
1537 GroupLeaveResult::StillMember => {}
1538 GroupLeaveResult::NotMember => panic!(
1539 "attempted to leave IP multicast group we were not a member of: {}",
1540 multicast_addr,
1541 ),
1542 }
1543}
1544
1545pub fn leave_ip_multicast<
1560 I: IpDeviceIpExt,
1561 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1562 CC: IpDeviceConfigurationContext<I, BC>,
1563>(
1564 core_ctx: &mut CC,
1565 bindings_ctx: &mut BC,
1566 device_id: &CC::DeviceId,
1567 multicast_addr: MulticastAddr<I::Addr>,
1568) {
1569 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1570 leave_ip_multicast_with_config(
1571 &mut core_ctx,
1572 bindings_ctx,
1573 device_id,
1574 multicast_addr,
1575 config,
1576 )
1577 })
1578}
1579
1580pub fn add_ip_addr_subnet_with_config<
1589 I: IpDeviceIpExt,
1590 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1591 CC: IpDeviceStateContext<I, BC>
1592 + IpDeviceAddAddressContext<I, BC>
1593 + GmpHandler<I, BC>
1594 + DadHandler<I, BC>,
1595>(
1596 core_ctx: &mut CC,
1597 bindings_ctx: &mut BC,
1598 device_id: &CC::DeviceId,
1599 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1600 addr_config: I::AddressConfig<BC::Instant>,
1601 _device_config: &I::Configuration,
1602) -> Result<CC::AddressId, ExistsError> {
1603 info!("adding addr {addr_sub:?} config {addr_config:?} to device {device_id:?}");
1604 let CommonAddressProperties { valid_until, preferred_lifetime } =
1605 I::get_common_props(&addr_config);
1606 let addr_id = core_ctx.add_ip_address(device_id, addr_sub, addr_config)?;
1607 assert_eq!(addr_id.addr().addr(), addr_sub.addr().get());
1608
1609 let ip_enabled =
1610 core_ctx.with_ip_device_flags(device_id, |IpDeviceFlags { ip_enabled }| *ip_enabled);
1611
1612 let needs_dad = if ip_enabled {
1613 DadHandler::initialize_duplicate_address_detection(
1614 core_ctx,
1615 bindings_ctx,
1616 device_id,
1617 &addr_id,
1618 |state| IpDeviceEvent::AddressAdded {
1619 device: device_id.clone(),
1620 addr: addr_sub.to_witness(),
1621 state,
1622 valid_until,
1623 preferred_lifetime,
1624 },
1625 )
1626 } else {
1627 bindings_ctx.on_event(IpDeviceEvent::AddressAdded {
1634 device: device_id.clone(),
1635 addr: addr_sub.to_witness(),
1636 state: IpAddressState::Unavailable,
1637 valid_until,
1638 preferred_lifetime,
1639 });
1640 NeedsDad::No
1641 };
1642
1643 match needs_dad {
1644 NeedsDad::Yes(token) => {
1645 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1646 }
1647 NeedsDad::No => {}
1648 }
1649
1650 Ok(addr_id)
1651}
1652
1653pub trait IpAddressRemovalHandler<I: IpDeviceIpExt, BC: InstantBindingsTypes>:
1655 DeviceIdContext<AnyDevice>
1656{
1657 fn on_address_removed(
1660 &mut self,
1661 bindings_ctx: &mut BC,
1662 device_id: &Self::DeviceId,
1663 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1664 config: I::AddressConfig<BC::Instant>,
1665 reason: AddressRemovedReason,
1666 );
1667}
1668
1669impl<CC: DeviceIdContext<AnyDevice>, BC: InstantBindingsTypes> IpAddressRemovalHandler<Ipv4, BC>
1671 for CC
1672{
1673 fn on_address_removed(
1674 &mut self,
1675 _bindings_ctx: &mut BC,
1676 _device_id: &Self::DeviceId,
1677 _addr_sub: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
1678 _config: Ipv4AddrConfig<BC::Instant>,
1679 _reason: AddressRemovedReason,
1680 ) {
1681 }
1683}
1684
1685impl<CC: SlaacHandler<BC>, BC: InstantContext> IpAddressRemovalHandler<Ipv6, BC> for CC {
1687 fn on_address_removed(
1688 &mut self,
1689 bindings_ctx: &mut BC,
1690 device_id: &Self::DeviceId,
1691 addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
1692 config: Ipv6AddrConfig<BC::Instant>,
1693 reason: AddressRemovedReason,
1694 ) {
1695 match config {
1696 Ipv6AddrConfig::Slaac(config) => SlaacHandler::on_address_removed(
1697 self,
1698 bindings_ctx,
1699 device_id,
1700 addr_sub,
1701 config,
1702 reason,
1703 ),
1704 Ipv6AddrConfig::Manual(_manual_config) => (),
1705 }
1706 }
1707}
1708
1709#[allow(missing_docs)]
1711pub enum DelIpAddr<Id, A> {
1712 SpecifiedAddr(SpecifiedAddr<A>),
1713 AddressId(Id),
1714}
1715
1716impl<Id: IpAddressId<A>, A: IpAddress<Version: AssignedAddrIpExt>> Display for DelIpAddr<Id, A> {
1717 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1718 match self {
1719 DelIpAddr::SpecifiedAddr(addr) => write!(f, "{}", *addr),
1720 DelIpAddr::AddressId(id) => write!(f, "{}", id.addr()),
1721 }
1722 }
1723}
1724
1725pub fn del_ip_addr_inner<
1728 I: IpDeviceIpExt,
1729 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1730 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1731>(
1732 core_ctx: &mut CC,
1733 bindings_ctx: &mut BC,
1734 device_id: &CC::DeviceId,
1735 addr: DelIpAddr<CC::AddressId, I::Addr>,
1736 reason: AddressRemovedReason,
1737 _config: &I::Configuration,
1744) -> Result<
1745 (
1746 AddrSubnet<I::Addr, I::AssignedWitness>,
1747 I::AddressConfig<BC::Instant>,
1748 RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>,
1749 ),
1750 NotFoundError,
1751> {
1752 let addr_id = match addr {
1753 DelIpAddr::SpecifiedAddr(addr) => core_ctx.get_address_id(device_id, addr)?,
1754 DelIpAddr::AddressId(id) => id,
1755 };
1756 DadHandler::stop_duplicate_address_detection(core_ctx, bindings_ctx, device_id, &addr_id);
1757 let addr_config = core_ctx
1761 .with_ip_address_data_mut(device_id, &addr_id, |addr_data| addr_data.config.take())
1762 .ok_or(NotFoundError)?;
1763
1764 let addr_sub = addr_id.addr_sub();
1765 let result = core_ctx.remove_ip_address(device_id, addr_id);
1766
1767 bindings_ctx.on_event(IpDeviceEvent::AddressRemoved {
1768 device: device_id.clone(),
1769 addr: addr_sub.addr().into(),
1770 reason,
1771 });
1772
1773 Ok((addr_sub, addr_config, result))
1774}
1775
1776fn del_ip_addr<
1778 I: IpDeviceIpExt,
1779 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1780 CC: IpDeviceConfigurationContext<I, BC>,
1781>(
1782 core_ctx: &mut CC,
1783 bindings_ctx: &mut BC,
1784 device_id: &CC::DeviceId,
1785 addr: DelIpAddr<CC::AddressId, I::Addr>,
1786 reason: AddressRemovedReason,
1787) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1788 info!("removing addr {addr} from device {device_id:?}");
1789 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1790 del_ip_addr_inner_and_notify_handler(
1791 &mut core_ctx,
1792 bindings_ctx,
1793 device_id,
1794 addr,
1795 reason,
1796 config,
1797 )
1798 })
1799}
1800
1801fn del_ip_addr_inner_and_notify_handler<
1804 I: IpDeviceIpExt,
1805 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1806 CC: IpDeviceStateContext<I, BC>
1807 + GmpHandler<I, BC>
1808 + DadHandler<I, BC>
1809 + IpAddressRemovalHandler<I, BC>,
1810>(
1811 core_ctx: &mut CC,
1812 bindings_ctx: &mut BC,
1813 device_id: &CC::DeviceId,
1814 addr: DelIpAddr<CC::AddressId, I::Addr>,
1815 reason: AddressRemovedReason,
1816 config: &I::Configuration,
1817) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1818 del_ip_addr_inner(core_ctx, bindings_ctx, device_id, addr, reason, config).map(
1819 |(addr_sub, config, result)| {
1820 core_ctx.on_address_removed(bindings_ctx, device_id, addr_sub, config, reason);
1821 result
1822 },
1823 )
1824}
1825
1826pub fn is_ip_device_enabled<
1828 I: IpDeviceIpExt,
1829 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1830 CC: IpDeviceStateContext<I, BC>,
1831>(
1832 core_ctx: &mut CC,
1833 device_id: &CC::DeviceId,
1834) -> bool {
1835 core_ctx.with_ip_device_flags(device_id, |flags| flags.ip_enabled)
1836}
1837
1838pub fn clear_ipv4_device_state<
1840 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1841 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1842>(
1843 core_ctx: &mut CC,
1844 bindings_ctx: &mut BC,
1845 device_id: &CC::DeviceId,
1846) {
1847 core_ctx.with_ip_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.ip_device_configuration_and_ctx();
1856 let core_ctx = &mut core_ctx;
1857 if ip_enabled {
1858 disable_ipv4_device_with_config(core_ctx, bindings_ctx, device_id, config);
1859 }
1860 })
1861}
1862
1863pub fn clear_ipv6_device_state<
1865 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1866 CC: Ipv6DeviceConfigurationContext<BC>,
1867>(
1868 core_ctx: &mut CC,
1869 bindings_ctx: &mut BC,
1870 device_id: &CC::DeviceId,
1871) {
1872 core_ctx.with_ipv6_device_configuration_mut(device_id, |mut core_ctx| {
1873 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1874 let IpDeviceFlags { ip_enabled } = flags;
1877 core::mem::replace(ip_enabled, false)
1878 });
1879
1880 let (config, mut core_ctx) = core_ctx.ipv6_device_configuration_and_ctx();
1881 let core_ctx = &mut core_ctx;
1882 if ip_enabled {
1883 disable_ipv6_device_with_config(core_ctx, bindings_ctx, device_id, config);
1884 }
1885 })
1886}
1887
1888pub fn on_arp_packet<CC, BC>(
1892 core_ctx: &mut CC,
1893 bindings_ctx: &mut BC,
1894 device_id: &CC::DeviceId,
1895 frame_src: impl Debug,
1896 sender_hwaddr: impl Debug,
1897 sender_addr: Ipv4Addr,
1898 target_addr: Ipv4Addr,
1899 is_arp_probe: bool,
1900) -> bool
1901where
1902 CC: IpDeviceHandler<Ipv4, BC> + IpDeviceStateContext<Ipv4, BC>,
1903 BC: IpDeviceStateBindingsTypes,
1904{
1905 if let Some(sender_addr) = SpecifiedAddr::new(sender_addr) {
1911 let sender_addr_state = IpDeviceHandler::<Ipv4, _>::handle_received_dad_packet(
1912 core_ctx,
1913 bindings_ctx,
1914 &device_id,
1915 sender_addr,
1916 Ipv4DadAddressInfo::SourceAddr,
1917 );
1918 match sender_addr_state {
1919 None => {}
1920 Some(state) => {
1929 info!(
1930 "DAD received conflicting ARP packet (sender) for {sender_addr} \
1931 (state={state:?}). arp_sha={sender_hwaddr:?}, frame_src={frame_src:?}"
1932 );
1933 }
1934 }
1935 }
1936
1937 let Some(target_addr) = SpecifiedAddr::new(target_addr) else {
1938 return false;
1939 };
1940
1941 if is_arp_probe {
1947 let target_addr_state = IpDeviceHandler::<Ipv4, _>::handle_received_dad_packet(
1948 core_ctx,
1949 bindings_ctx,
1950 &device_id,
1951 target_addr,
1952 Ipv4DadAddressInfo::TargetAddr,
1953 );
1954 let assigned = match target_addr_state {
1955 None => false,
1956 Some(IpAddressState::Assigned) => true,
1959 Some(state @ (IpAddressState::Tentative | IpAddressState::Unavailable)) => {
1960 info!(
1961 "DAD received conflicting ARP packet (target) for {target_addr} \
1962 (state={state:?}). arp_sha={sender_hwaddr:?}, frame_src={frame_src:?}"
1963 );
1964 false
1965 }
1966 };
1967 assigned
1968 } else {
1969 let addr_id = match core_ctx.get_address_id(device_id, target_addr) {
1972 Ok(o) => o,
1973 Err(NotFoundError) => return false,
1974 };
1975
1976 core_ctx.with_ip_address_data(
1977 device_id,
1978 &addr_id,
1979 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
1980 )
1981 }
1982}
1983
1984#[cfg(any(test, feature = "testutils"))]
1985pub(crate) mod testutil {
1986 use alloc::boxed::Box;
1987
1988 use crate::device::IpAddressFlags;
1989
1990 use super::*;
1991
1992 pub fn with_assigned_ipv4_addr_subnets<
1995 BT: IpDeviceStateBindingsTypes,
1996 CC: IpDeviceStateContext<Ipv4, BT>,
1997 O,
1998 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> + '_>) -> O,
1999 >(
2000 core_ctx: &mut CC,
2001 device_id: &CC::DeviceId,
2002 cb: F,
2003 ) -> O {
2004 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
2005 cb(Box::new(addrs.map(|a| a.addr_sub())))
2006 })
2007 }
2008
2009 pub fn with_assigned_ipv6_addr_subnets<
2021 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
2022 CC: Ipv6DeviceContext<BC>,
2023 O,
2024 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>> + '_>) -> O,
2025 >(
2026 core_ctx: &mut CC,
2027 device_id: &CC::DeviceId,
2028 cb: F,
2029 ) -> O {
2030 core_ctx.with_address_ids(device_id, |addrs, core_ctx| {
2031 cb(Box::new(addrs.filter_map(|addr_id| {
2032 core_ctx
2033 .with_ip_address_data(
2034 device_id,
2035 &addr_id,
2036 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
2037 )
2038 .then(|| addr_id.addr_sub())
2039 })))
2040 })
2041 }
2042}