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, NetworkSerializer, NotFoundError, RemoveResourceResultWithContext,
34 ResourceCounterContext, RngContext, SendFrameError, StrongDeviceIdentifier, TimerContext,
35 TimerHandler, TxMetadataBindingsTypes, WeakDeviceIdentifier, WeakIpAddressId,
36};
37use netstack3_filter::ProofOfEgressCheck;
38use packet::BufferMut;
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: NetworkSerializer,
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>
1389 + GmpHandler<Ipv4, BC>
1390 + DadHandler<Ipv4, BC>
1391 + NudIpHandler<Ipv4, BC>,
1392>(
1393 core_ctx: &mut CC,
1394 bindings_ctx: &mut BC,
1395 device_id: &CC::DeviceId,
1396 config: &Ipv4DeviceConfiguration,
1397) {
1398 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1399 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1400 leave_ip_multicast_with_config(
1401 core_ctx,
1402 bindings_ctx,
1403 device_id,
1404 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1405 config,
1406 );
1407 core_ctx
1408 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1409 .into_iter()
1410 .for_each(|addr_id| {
1411 DadHandler::stop_duplicate_address_detection(
1412 core_ctx,
1413 bindings_ctx,
1414 device_id,
1415 &addr_id,
1416 );
1417 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1418 device: device_id.clone(),
1419 addr: addr_id.addr().into(),
1420 state: IpAddressState::Unavailable,
1421 });
1422 });
1423}
1424
1425pub fn get_ipv4_addr_subnet<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv4, BT>>(
1427 core_ctx: &mut CC,
1428 device_id: &CC::DeviceId,
1429) -> Option<AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> {
1430 core_ctx.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next().map(|a| a.addr_sub()))
1431}
1432
1433pub fn get_ipv6_hop_limit<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv6, BT>>(
1435 core_ctx: &mut CC,
1436 device: &CC::DeviceId,
1437) -> NonZeroU8 {
1438 core_ctx.with_default_hop_limit(device, Clone::clone)
1439}
1440
1441pub fn is_ip_unicast_forwarding_enabled<
1443 I: IpDeviceIpExt,
1444 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1445 CC: IpDeviceConfigurationContext<I, BC>,
1446>(
1447 core_ctx: &mut CC,
1448 device_id: &CC::DeviceId,
1449) -> bool {
1450 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1451 AsRef::<IpDeviceConfiguration>::as_ref(state).unicast_forwarding_enabled
1452 })
1453}
1454
1455pub fn is_ip_multicast_forwarding_enabled<
1457 I: IpDeviceIpExt,
1458 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1459 CC: IpDeviceConfigurationContext<I, BC>,
1460>(
1461 core_ctx: &mut CC,
1462 device_id: &CC::DeviceId,
1463) -> bool {
1464 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1465 AsRef::<IpDeviceConfiguration>::as_ref(state).multicast_forwarding_enabled
1466 })
1467}
1468
1469pub fn join_ip_multicast_with_config<
1476 I: IpDeviceIpExt,
1477 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1478 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1479>(
1480 core_ctx: &mut CC,
1481 bindings_ctx: &mut BC,
1482 device_id: &CC::DeviceId,
1483 multicast_addr: MulticastAddr<I::Addr>,
1484 _config: &I::Configuration,
1485) {
1486 match core_ctx.gmp_join_group(bindings_ctx, device_id, multicast_addr) {
1487 GroupJoinResult::Joined(()) => {
1488 debug!("joined IP Multicast Group {multicast_addr} on device {device_id:?}");
1489 core_ctx.join_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1490 }
1491 GroupJoinResult::AlreadyMember => {}
1492 }
1493}
1494
1495pub fn join_ip_multicast<
1506 I: IpDeviceIpExt,
1507 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1508 CC: IpDeviceConfigurationContext<I, BC>,
1509>(
1510 core_ctx: &mut CC,
1511 bindings_ctx: &mut BC,
1512 device_id: &CC::DeviceId,
1513 multicast_addr: MulticastAddr<I::Addr>,
1514) {
1515 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1516 join_ip_multicast_with_config(
1517 &mut core_ctx,
1518 bindings_ctx,
1519 device_id,
1520 multicast_addr,
1521 config,
1522 )
1523 })
1524}
1525
1526pub fn leave_ip_multicast_with_config<
1533 I: IpDeviceIpExt,
1534 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1535 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1536>(
1537 core_ctx: &mut CC,
1538 bindings_ctx: &mut BC,
1539 device_id: &CC::DeviceId,
1540 multicast_addr: MulticastAddr<I::Addr>,
1541 _config: &I::Configuration,
1542) {
1543 match core_ctx.gmp_leave_group(bindings_ctx, device_id, multicast_addr) {
1544 GroupLeaveResult::Left(()) => {
1545 core_ctx.leave_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1546 }
1547 GroupLeaveResult::StillMember => {}
1548 GroupLeaveResult::NotMember => panic!(
1549 "attempted to leave IP multicast group we were not a member of: {}",
1550 multicast_addr,
1551 ),
1552 }
1553}
1554
1555pub fn leave_ip_multicast<
1570 I: IpDeviceIpExt,
1571 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1572 CC: IpDeviceConfigurationContext<I, BC>,
1573>(
1574 core_ctx: &mut CC,
1575 bindings_ctx: &mut BC,
1576 device_id: &CC::DeviceId,
1577 multicast_addr: MulticastAddr<I::Addr>,
1578) {
1579 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1580 leave_ip_multicast_with_config(
1581 &mut core_ctx,
1582 bindings_ctx,
1583 device_id,
1584 multicast_addr,
1585 config,
1586 )
1587 })
1588}
1589
1590pub fn add_ip_addr_subnet_with_config<
1599 I: IpDeviceIpExt,
1600 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1601 CC: IpDeviceStateContext<I, BC>
1602 + IpDeviceAddAddressContext<I, BC>
1603 + GmpHandler<I, BC>
1604 + DadHandler<I, BC>,
1605>(
1606 core_ctx: &mut CC,
1607 bindings_ctx: &mut BC,
1608 device_id: &CC::DeviceId,
1609 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1610 addr_config: I::AddressConfig<BC::Instant>,
1611 _device_config: &I::Configuration,
1612) -> Result<CC::AddressId, ExistsError> {
1613 info!("adding addr {addr_sub:?} config {addr_config:?} to device {device_id:?}");
1615 let CommonAddressProperties { valid_until, preferred_lifetime } =
1617 I::get_common_props(&addr_config);
1618 let addr_id = core_ctx.add_ip_address(device_id, addr_sub, addr_config)?;
1619 assert_eq!(addr_id.addr().addr(), addr_sub.addr().get());
1620
1621 let ip_enabled =
1622 core_ctx.with_ip_device_flags(device_id, |IpDeviceFlags { ip_enabled }| *ip_enabled);
1623
1624 let needs_dad = if ip_enabled {
1625 DadHandler::initialize_duplicate_address_detection(
1626 core_ctx,
1627 bindings_ctx,
1628 device_id,
1629 &addr_id,
1630 |state| IpDeviceEvent::AddressAdded {
1631 device: device_id.clone(),
1632 addr: addr_sub.to_witness(),
1633 state,
1634 valid_until,
1635 preferred_lifetime,
1636 },
1637 )
1638 } else {
1639 bindings_ctx.on_event(IpDeviceEvent::AddressAdded {
1646 device: device_id.clone(),
1647 addr: addr_sub.to_witness(),
1648 state: IpAddressState::Unavailable,
1649 valid_until,
1650 preferred_lifetime,
1651 });
1652 NeedsDad::No
1653 };
1654
1655 match needs_dad {
1656 NeedsDad::Yes(token) => {
1657 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1658 }
1659 NeedsDad::No => {}
1660 }
1661
1662 Ok(addr_id)
1663}
1664
1665pub trait IpAddressRemovalHandler<I: IpDeviceIpExt, BC: InstantBindingsTypes>:
1667 DeviceIdContext<AnyDevice>
1668{
1669 fn on_address_removed(
1672 &mut self,
1673 bindings_ctx: &mut BC,
1674 device_id: &Self::DeviceId,
1675 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1676 config: I::AddressConfig<BC::Instant>,
1677 reason: AddressRemovedReason,
1678 );
1679}
1680
1681impl<CC: DeviceIdContext<AnyDevice>, BC: InstantBindingsTypes> IpAddressRemovalHandler<Ipv4, BC>
1683 for CC
1684{
1685 fn on_address_removed(
1686 &mut self,
1687 _bindings_ctx: &mut BC,
1688 _device_id: &Self::DeviceId,
1689 _addr_sub: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
1690 _config: Ipv4AddrConfig<BC::Instant>,
1691 _reason: AddressRemovedReason,
1692 ) {
1693 }
1695}
1696
1697impl<CC: SlaacHandler<BC>, BC: InstantContext> IpAddressRemovalHandler<Ipv6, BC> for CC {
1699 fn on_address_removed(
1700 &mut self,
1701 bindings_ctx: &mut BC,
1702 device_id: &Self::DeviceId,
1703 addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
1704 config: Ipv6AddrConfig<BC::Instant>,
1705 reason: AddressRemovedReason,
1706 ) {
1707 match config {
1708 Ipv6AddrConfig::Slaac(config) => SlaacHandler::on_address_removed(
1709 self,
1710 bindings_ctx,
1711 device_id,
1712 addr_sub,
1713 config,
1714 reason,
1715 ),
1716 Ipv6AddrConfig::Manual(_manual_config) => (),
1717 }
1718 }
1719}
1720
1721#[allow(missing_docs)]
1723pub enum DelIpAddr<Id, A> {
1724 SpecifiedAddr(SpecifiedAddr<A>),
1725 AddressId(Id),
1726}
1727
1728impl<Id: IpAddressId<A>, A: IpAddress<Version: AssignedAddrIpExt>> Display for DelIpAddr<Id, A> {
1729 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1730 match self {
1731 DelIpAddr::SpecifiedAddr(addr) => write!(f, "{}", *addr),
1732 DelIpAddr::AddressId(id) => write!(f, "{}", id.addr()),
1733 }
1734 }
1735}
1736
1737pub fn del_ip_addr_inner<
1740 I: IpDeviceIpExt,
1741 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1742 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1743>(
1744 core_ctx: &mut CC,
1745 bindings_ctx: &mut BC,
1746 device_id: &CC::DeviceId,
1747 addr: DelIpAddr<CC::AddressId, I::Addr>,
1748 reason: AddressRemovedReason,
1749 _config: &I::Configuration,
1756) -> Result<
1757 (
1758 AddrSubnet<I::Addr, I::AssignedWitness>,
1759 I::AddressConfig<BC::Instant>,
1760 RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>,
1761 ),
1762 NotFoundError,
1763> {
1764 let addr_id = match addr {
1765 DelIpAddr::SpecifiedAddr(addr) => core_ctx.get_address_id(device_id, addr)?,
1766 DelIpAddr::AddressId(id) => id,
1767 };
1768 DadHandler::stop_duplicate_address_detection(core_ctx, bindings_ctx, device_id, &addr_id);
1769 let addr_config = core_ctx
1773 .with_ip_address_data_mut(device_id, &addr_id, |addr_data| addr_data.config.take())
1774 .ok_or(NotFoundError)?;
1775
1776 let addr_sub = addr_id.addr_sub();
1777 let result = core_ctx.remove_ip_address(device_id, addr_id);
1778
1779 bindings_ctx.on_event(IpDeviceEvent::AddressRemoved {
1780 device: device_id.clone(),
1781 addr: addr_sub.addr().into(),
1782 reason,
1783 });
1784
1785 Ok((addr_sub, addr_config, result))
1786}
1787
1788fn del_ip_addr<
1790 I: IpDeviceIpExt,
1791 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1792 CC: IpDeviceConfigurationContext<I, BC>,
1793>(
1794 core_ctx: &mut CC,
1795 bindings_ctx: &mut BC,
1796 device_id: &CC::DeviceId,
1797 addr: DelIpAddr<CC::AddressId, I::Addr>,
1798 reason: AddressRemovedReason,
1799) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1800 info!("removing addr {addr} from device {device_id:?}");
1801 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1802 del_ip_addr_inner_and_notify_handler(
1803 &mut core_ctx,
1804 bindings_ctx,
1805 device_id,
1806 addr,
1807 reason,
1808 config,
1809 )
1810 })
1811}
1812
1813fn del_ip_addr_inner_and_notify_handler<
1816 I: IpDeviceIpExt,
1817 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1818 CC: IpDeviceStateContext<I, BC>
1819 + GmpHandler<I, BC>
1820 + DadHandler<I, BC>
1821 + IpAddressRemovalHandler<I, BC>,
1822>(
1823 core_ctx: &mut CC,
1824 bindings_ctx: &mut BC,
1825 device_id: &CC::DeviceId,
1826 addr: DelIpAddr<CC::AddressId, I::Addr>,
1827 reason: AddressRemovedReason,
1828 config: &I::Configuration,
1829) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1830 del_ip_addr_inner(core_ctx, bindings_ctx, device_id, addr, reason, config).map(
1831 |(addr_sub, config, result)| {
1832 core_ctx.on_address_removed(bindings_ctx, device_id, addr_sub, config, reason);
1833 result
1834 },
1835 )
1836}
1837
1838pub fn is_ip_device_enabled<
1840 I: IpDeviceIpExt,
1841 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1842 CC: IpDeviceStateContext<I, BC>,
1843>(
1844 core_ctx: &mut CC,
1845 device_id: &CC::DeviceId,
1846) -> bool {
1847 core_ctx.with_ip_device_flags(device_id, |flags| flags.ip_enabled)
1848}
1849
1850pub fn clear_ipv4_device_state<
1852 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1853 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1854>(
1855 core_ctx: &mut CC,
1856 bindings_ctx: &mut BC,
1857 device_id: &CC::DeviceId,
1858) {
1859 core_ctx.with_ip_device_configuration_mut(device_id, |mut core_ctx| {
1860 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1861 let IpDeviceFlags { ip_enabled } = flags;
1864 core::mem::replace(ip_enabled, false)
1865 });
1866
1867 let (config, mut core_ctx) = core_ctx.ip_device_configuration_and_ctx();
1868 let core_ctx = &mut core_ctx;
1869 if ip_enabled {
1870 disable_ipv4_device_with_config(core_ctx, bindings_ctx, device_id, config);
1871 }
1872 })
1873}
1874
1875pub fn clear_ipv6_device_state<
1877 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1878 CC: Ipv6DeviceConfigurationContext<BC>,
1879>(
1880 core_ctx: &mut CC,
1881 bindings_ctx: &mut BC,
1882 device_id: &CC::DeviceId,
1883) {
1884 core_ctx.with_ipv6_device_configuration_mut(device_id, |mut core_ctx| {
1885 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1886 let IpDeviceFlags { ip_enabled } = flags;
1889 core::mem::replace(ip_enabled, false)
1890 });
1891
1892 let (config, mut core_ctx) = core_ctx.ipv6_device_configuration_and_ctx();
1893 let core_ctx = &mut core_ctx;
1894 if ip_enabled {
1895 disable_ipv6_device_with_config(core_ctx, bindings_ctx, device_id, config);
1896 }
1897 })
1898}
1899
1900pub fn on_arp_packet<CC, BC>(
1904 core_ctx: &mut CC,
1905 bindings_ctx: &mut BC,
1906 device_id: &CC::DeviceId,
1907 frame_src: impl Debug,
1908 sender_hwaddr: impl Debug,
1909 sender_addr: Ipv4Addr,
1910 target_addr: Ipv4Addr,
1911 is_arp_probe: bool,
1912) -> bool
1913where
1914 CC: IpDeviceHandler<Ipv4, BC> + IpDeviceStateContext<Ipv4, BC>,
1915 BC: IpDeviceStateBindingsTypes,
1916{
1917 if let Some(sender_addr) = SpecifiedAddr::new(sender_addr) {
1923 let sender_addr_state = IpDeviceHandler::<Ipv4, _>::handle_received_dad_packet(
1924 core_ctx,
1925 bindings_ctx,
1926 &device_id,
1927 sender_addr,
1928 Ipv4DadAddressInfo::SourceAddr,
1929 );
1930 match sender_addr_state {
1931 None => {}
1932 Some(state) => {
1941 info!(
1942 "DAD received conflicting ARP packet (sender) for {sender_addr} \
1943 (state={state:?}). arp_sha={sender_hwaddr:?}, frame_src={frame_src:?}"
1944 );
1945 }
1946 }
1947 }
1948
1949 let Some(target_addr) = SpecifiedAddr::new(target_addr) else {
1950 return false;
1951 };
1952
1953 if is_arp_probe {
1959 let target_addr_state = IpDeviceHandler::<Ipv4, _>::handle_received_dad_packet(
1960 core_ctx,
1961 bindings_ctx,
1962 &device_id,
1963 target_addr,
1964 Ipv4DadAddressInfo::TargetAddr,
1965 );
1966 let assigned = match target_addr_state {
1967 None => false,
1968 Some(IpAddressState::Assigned) => true,
1971 Some(state @ (IpAddressState::Tentative | IpAddressState::Unavailable)) => {
1972 info!(
1973 "DAD received conflicting ARP packet (target) for {target_addr} \
1974 (state={state:?}). arp_sha={sender_hwaddr:?}, frame_src={frame_src:?}"
1975 );
1976 false
1977 }
1978 };
1979 assigned
1980 } else {
1981 let addr_id = match core_ctx.get_address_id(device_id, target_addr) {
1984 Ok(o) => o,
1985 Err(NotFoundError) => return false,
1986 };
1987
1988 core_ctx.with_ip_address_data(
1989 device_id,
1990 &addr_id,
1991 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
1992 )
1993 }
1994}
1995
1996#[cfg(any(test, feature = "testutils"))]
1997pub(crate) mod testutil {
1998 use alloc::boxed::Box;
1999
2000 use crate::device::IpAddressFlags;
2001
2002 use super::*;
2003
2004 pub fn with_assigned_ipv4_addr_subnets<
2007 BT: IpDeviceStateBindingsTypes,
2008 CC: IpDeviceStateContext<Ipv4, BT>,
2009 O,
2010 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> + '_>) -> O,
2011 >(
2012 core_ctx: &mut CC,
2013 device_id: &CC::DeviceId,
2014 cb: F,
2015 ) -> O {
2016 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
2017 cb(Box::new(addrs.map(|a| a.addr_sub())))
2018 })
2019 }
2020
2021 pub fn with_assigned_ipv6_addr_subnets<
2033 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
2034 CC: Ipv6DeviceContext<BC>,
2035 O,
2036 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>> + '_>) -> O,
2037 >(
2038 core_ctx: &mut CC,
2039 device_id: &CC::DeviceId,
2040 cb: F,
2041 ) -> O {
2042 core_ctx.with_address_ids(device_id, |addrs, core_ctx| {
2043 cb(Box::new(addrs.filter_map(|addr_id| {
2044 core_ctx
2045 .with_ip_address_data(
2046 device_id,
2047 &addr_id,
2048 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
2049 )
2050 .then(|| addr_id.addr_sub())
2051 })))
2052 })
2053 }
2054}