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, Ipv6DiscoveredRouteTimerId, RouteDiscoveryHandler,
57};
58use crate::internal::device::router_solicitation::{RsHandler, RsTimerId};
59use crate::internal::device::slaac::{SlaacHandler, SlaacTimerId};
60use crate::internal::device::state::{
61 IpAddressData, IpAddressFlags, IpDeviceConfiguration, IpDeviceFlags, IpDeviceState,
62 IpDeviceStateBindingsTypes, IpDeviceStateIpExt, Ipv4AddrConfig, Ipv4DeviceConfiguration,
63 Ipv4DeviceState, Ipv6AddrConfig, Ipv6AddrManualConfig, Ipv6DeviceConfiguration,
64 Ipv6DeviceState, Ipv6NetworkLearnedParameters, Lifetime, PreferredLifetime, WeakAddressId,
65};
66use crate::internal::gmp::igmp::{IgmpPacketHandler, IgmpTimerId};
67use crate::internal::gmp::mld::{MldPacketHandler, MldTimerId};
68use crate::internal::gmp::{self, GmpHandler, GroupJoinResult, GroupLeaveResult};
69use crate::internal::local_delivery::{IpHeaderInfo, LocalDeliveryPacketInfo};
70
71#[derive(Derivative, GenericOverIp)]
78#[derivative(
79 Clone(bound = ""),
80 Eq(bound = ""),
81 PartialEq(bound = ""),
82 Hash(bound = ""),
83 Debug(bound = "")
84)]
85#[generic_over_ip(I, Ip)]
86pub struct IpDeviceTimerId<
87 I: IpDeviceIpExt,
88 D: WeakDeviceIdentifier,
89 BT: IpDeviceStateBindingsTypes,
90>(I::Timer<D, BT>);
91
92#[derive(Derivative)]
94#[derivative(
95 Clone(bound = ""),
96 Debug(bound = ""),
97 Eq(bound = ""),
98 Hash(bound = ""),
99 PartialEq(bound = "")
100)]
101pub enum Ipv4DeviceTimerId<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> {
102 Igmp(IgmpTimerId<D>),
104 Dad(DadTimerId<Ipv4, D, WeakAddressId<Ipv4, BT>>),
106}
107
108impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> Ipv4DeviceTimerId<D, BT> {
109 fn device_id(&self) -> Option<D::Strong> {
111 match self {
112 Ipv4DeviceTimerId::Igmp(igmp) => igmp.device_id().upgrade(),
113 Ipv4DeviceTimerId::Dad(dad) => dad.device_id().upgrade(),
114 }
115 }
116
117 pub fn into_common(self) -> IpDeviceTimerId<Ipv4, D, BT> {
119 self.into()
120 }
121}
122
123impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<IpDeviceTimerId<Ipv4, D, BT>>
124 for Ipv4DeviceTimerId<D, BT>
125{
126 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv4, D, BT>) -> Self {
127 inner
128 }
129}
130
131impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<Ipv4DeviceTimerId<D, BT>>
132 for IpDeviceTimerId<Ipv4, D, BT>
133{
134 fn from(value: Ipv4DeviceTimerId<D, BT>) -> Self {
135 Self(value)
136 }
137}
138
139impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<IgmpTimerId<D>>
140 for Ipv4DeviceTimerId<D, BT>
141{
142 fn from(id: IgmpTimerId<D>) -> Ipv4DeviceTimerId<D, BT> {
143 Ipv4DeviceTimerId::Igmp(id)
144 }
145}
146
147impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>
148 From<DadTimerId<Ipv4, D, WeakAddressId<Ipv4, BT>>> for Ipv4DeviceTimerId<D, BT>
149{
150 fn from(id: DadTimerId<Ipv4, D, WeakAddressId<Ipv4, BT>>) -> Ipv4DeviceTimerId<D, BT> {
151 Ipv4DeviceTimerId::Dad(id)
152 }
153}
154
155impl<
156 D: WeakDeviceIdentifier,
157 BC: IpDeviceStateBindingsTypes,
158 CC: TimerHandler<BC, IgmpTimerId<D>>
159 + TimerHandler<BC, DadTimerId<Ipv4, D, WeakAddressId<Ipv4, BC>>>,
160> HandleableTimer<CC, BC> for Ipv4DeviceTimerId<D, BC>
161{
162 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
163 match self {
164 Ipv4DeviceTimerId::Igmp(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
165 Ipv4DeviceTimerId::Dad(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
166 }
167 }
168}
169
170impl<I, CC, BC> HandleableTimer<CC, BC> for IpDeviceTimerId<I, CC::WeakDeviceId, BC>
171where
172 I: IpDeviceIpExt,
173 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
174 CC: IpDeviceConfigurationContext<I, BC>,
175 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>:
176 TimerHandler<BC, I::Timer<CC::WeakDeviceId, BC>>,
177{
178 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
179 let Self(id) = self;
180 let Some(device_id) = I::timer_device_id(&id) else {
181 return;
182 };
183 core_ctx.with_ip_device_configuration(&device_id, |_state, mut core_ctx| {
184 TimerHandler::handle_timer(&mut core_ctx, bindings_ctx, id, timer)
185 })
186 }
187}
188
189#[derive(Derivative)]
191#[derivative(
192 Clone(bound = ""),
193 Debug(bound = ""),
194 Eq(bound = ""),
195 Hash(bound = ""),
196 PartialEq(bound = "")
197)]
198#[allow(missing_docs)]
199pub enum Ipv6DeviceTimerId<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> {
200 Mld(MldTimerId<D>),
201 Dad(DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BT>>),
202 Rs(RsTimerId<D>),
203 RouteDiscovery(Ipv6DiscoveredRouteTimerId<D>),
204 Slaac(SlaacTimerId<D>),
205}
206
207impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<IpDeviceTimerId<Ipv6, D, BT>>
208 for Ipv6DeviceTimerId<D, BT>
209{
210 fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv6, D, BT>) -> Self {
211 inner
212 }
213}
214
215impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<Ipv6DeviceTimerId<D, BT>>
216 for IpDeviceTimerId<Ipv6, D, BT>
217{
218 fn from(value: Ipv6DeviceTimerId<D, BT>) -> Self {
219 Self(value)
220 }
221}
222
223impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> Ipv6DeviceTimerId<D, BT> {
224 fn device_id(&self) -> Option<D::Strong> {
226 match self {
227 Self::Mld(id) => id.device_id(),
228 Self::Dad(id) => id.device_id(),
229 Self::Rs(id) => id.device_id(),
230 Self::RouteDiscovery(id) => id.device_id(),
231 Self::Slaac(id) => id.device_id(),
232 }
233 .upgrade()
234 }
235
236 pub fn into_common(self) -> IpDeviceTimerId<Ipv6, D, BT> {
238 self.into()
239 }
240}
241
242impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<MldTimerId<D>>
243 for Ipv6DeviceTimerId<D, BT>
244{
245 fn from(id: MldTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
246 Ipv6DeviceTimerId::Mld(id)
247 }
248}
249
250impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>
251 From<DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BT>>> for Ipv6DeviceTimerId<D, BT>
252{
253 fn from(id: DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BT>>) -> Ipv6DeviceTimerId<D, BT> {
254 Ipv6DeviceTimerId::Dad(id)
255 }
256}
257
258impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<RsTimerId<D>>
259 for Ipv6DeviceTimerId<D, BT>
260{
261 fn from(id: RsTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
262 Ipv6DeviceTimerId::Rs(id)
263 }
264}
265
266impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<Ipv6DiscoveredRouteTimerId<D>>
267 for Ipv6DeviceTimerId<D, BT>
268{
269 fn from(id: Ipv6DiscoveredRouteTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
270 Ipv6DeviceTimerId::RouteDiscovery(id)
271 }
272}
273
274impl<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> From<SlaacTimerId<D>>
275 for Ipv6DeviceTimerId<D, BT>
276{
277 fn from(id: SlaacTimerId<D>) -> Ipv6DeviceTimerId<D, BT> {
278 Ipv6DeviceTimerId::Slaac(id)
279 }
280}
281
282impl<
283 D: WeakDeviceIdentifier,
284 BC: IpDeviceStateBindingsTypes,
285 CC: TimerHandler<BC, RsTimerId<D>>
286 + TimerHandler<BC, Ipv6DiscoveredRouteTimerId<D>>
287 + TimerHandler<BC, MldTimerId<D>>
288 + TimerHandler<BC, SlaacTimerId<D>>
289 + TimerHandler<BC, DadTimerId<Ipv6, D, WeakAddressId<Ipv6, BC>>>,
290> HandleableTimer<CC, BC> for Ipv6DeviceTimerId<D, BC>
291{
292 fn handle(self, core_ctx: &mut CC, bindings_ctx: &mut BC, timer: BC::UniqueTimerId) {
293 match self {
294 Ipv6DeviceTimerId::Mld(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
295 Ipv6DeviceTimerId::Dad(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
296 Ipv6DeviceTimerId::Rs(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
297 Ipv6DeviceTimerId::RouteDiscovery(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
298 Ipv6DeviceTimerId::Slaac(id) => core_ctx.handle_timer(bindings_ctx, id, timer),
299 }
300 }
301}
302
303pub trait IpDeviceIpExt: IpDeviceStateIpExt + AssignedAddrIpExt + gmp::IpExt + DadIpExt {
305 type State<BT: IpDeviceStateBindingsTypes>: AsRef<IpDeviceState<Self, BT>>
307 + AsMut<IpDeviceState<Self, BT>>;
308 type Configuration: AsRef<IpDeviceConfiguration>
310 + AsMut<IpDeviceConfiguration>
311 + Clone
312 + Debug
313 + Eq
314 + PartialEq;
315 type Timer<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>: Into<IpDeviceTimerId<Self, D, BT>>
317 + From<IpDeviceTimerId<Self, D, BT>>
318 + Clone
319 + Eq
320 + PartialEq
321 + Debug
322 + Hash;
323 type ManualAddressConfig<I: Instant>: Default + Debug + Into<Self::AddressConfig<I>>;
325 type ConfigurationUpdate: From<IpDeviceConfigurationUpdate>
327 + AsRef<IpDeviceConfigurationUpdate>
328 + Debug;
329
330 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I>;
332
333 fn timer_device_id<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
335 timer: &Self::Timer<D, BT>,
336 ) -> Option<D::Strong>;
337}
338
339impl IpDeviceIpExt for Ipv4 {
340 type State<BT: IpDeviceStateBindingsTypes> = Ipv4DeviceState<BT>;
341 type Configuration = Ipv4DeviceConfiguration;
342 type Timer<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> = Ipv4DeviceTimerId<D, BT>;
343 type ManualAddressConfig<I: Instant> = Ipv4AddrConfig<I>;
344 type ConfigurationUpdate = Ipv4DeviceConfigurationUpdate;
345
346 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
347 config.properties
348 }
349
350 fn timer_device_id<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
351 timer: &Self::Timer<D, BT>,
352 ) -> Option<D::Strong> {
353 timer.device_id()
354 }
355}
356
357impl IpDeviceIpExt for Ipv6 {
358 type State<BT: IpDeviceStateBindingsTypes> = Ipv6DeviceState<BT>;
359 type Configuration = Ipv6DeviceConfiguration;
360 type Timer<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes> = Ipv6DeviceTimerId<D, BT>;
361 type ManualAddressConfig<I: Instant> = Ipv6AddrManualConfig<I>;
362 type ConfigurationUpdate = Ipv6DeviceConfigurationUpdate;
363
364 fn get_common_props<I: Instant>(config: &Self::AddressConfig<I>) -> CommonAddressProperties<I> {
365 CommonAddressProperties {
366 valid_until: config.valid_until(),
367 preferred_lifetime: config.preferred_lifetime(),
368 }
369 }
370
371 fn timer_device_id<D: WeakDeviceIdentifier, BT: IpDeviceStateBindingsTypes>(
372 timer: &Self::Timer<D, BT>,
373 ) -> Option<D::Strong> {
374 timer.device_id()
375 }
376}
377#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
379pub enum IpAddressState {
380 Unavailable,
382 Assigned,
385 Tentative,
389}
390
391#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
393pub enum AddressRemovedReason {
394 Manual,
396 DadFailed,
398 Forfeited,
401}
402
403#[derive(Debug, Eq, Hash, PartialEq, GenericOverIp)]
404#[generic_over_ip(I, Ip)]
405pub enum IpDeviceEvent<DeviceId, I: Ip, Instant> {
407 AddressAdded {
409 device: DeviceId,
411 addr: AddrSubnet<I::Addr>,
413 state: IpAddressState,
415 valid_until: Lifetime<Instant>,
417 preferred_lifetime: PreferredLifetime<Instant>,
419 },
420 AddressRemoved {
422 device: DeviceId,
424 addr: SpecifiedAddr<I::Addr>,
426 reason: AddressRemovedReason,
428 },
429 AddressStateChanged {
431 device: DeviceId,
433 addr: SpecifiedAddr<I::Addr>,
435 state: IpAddressState,
437 },
438 AddressPropertiesChanged {
440 device: DeviceId,
442 addr: SpecifiedAddr<I::Addr>,
444 valid_until: Lifetime<Instant>,
446 preferred_lifetime: PreferredLifetime<Instant>,
448 },
449 EnabledChanged {
451 device: DeviceId,
453 ip_enabled: bool,
455 },
456}
457
458impl<DeviceId, I: Ip, Instant> IpDeviceEvent<DeviceId, I, Instant> {
459 pub fn map_device<N, F: FnOnce(DeviceId) -> N>(self, map: F) -> IpDeviceEvent<N, I, Instant> {
461 match self {
462 IpDeviceEvent::AddressAdded {
463 device,
464 addr,
465 state,
466 valid_until,
467 preferred_lifetime,
468 } => IpDeviceEvent::AddressAdded {
469 device: map(device),
470 addr,
471 state,
472 valid_until,
473 preferred_lifetime,
474 },
475 IpDeviceEvent::AddressRemoved { device, addr, reason } => {
476 IpDeviceEvent::AddressRemoved { device: map(device), addr, reason }
477 }
478 IpDeviceEvent::AddressStateChanged { device, addr, state } => {
479 IpDeviceEvent::AddressStateChanged { device: map(device), addr, state }
480 }
481 IpDeviceEvent::EnabledChanged { device, ip_enabled } => {
482 IpDeviceEvent::EnabledChanged { device: map(device), ip_enabled }
483 }
484 IpDeviceEvent::AddressPropertiesChanged {
485 device,
486 addr,
487 valid_until,
488 preferred_lifetime,
489 } => IpDeviceEvent::AddressPropertiesChanged {
490 device: map(device),
491 addr,
492 valid_until,
493 preferred_lifetime,
494 },
495 }
496 }
497}
498
499pub trait IpDeviceBindingsContext<I: IpDeviceIpExt, D: StrongDeviceIdentifier>:
501 IpDeviceStateBindingsTypes
502 + DeferredResourceRemovalContext
503 + TimerContext
504 + RngContext
505 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>
506{
507}
508impl<
509 D: StrongDeviceIdentifier,
510 I: IpDeviceIpExt,
511 BC: IpDeviceStateBindingsTypes
512 + DeferredResourceRemovalContext
513 + TimerContext
514 + RngContext
515 + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>,
516> IpDeviceBindingsContext<I, D> for BC
517{
518}
519
520pub trait IpDeviceAddressContext<I: IpDeviceIpExt, BT: InstantBindingsTypes>:
522 IpDeviceAddressIdContext<I>
523{
524 fn with_ip_address_data<O, F: FnOnce(&IpAddressData<I, BT::Instant>) -> O>(
527 &mut self,
528 device_id: &Self::DeviceId,
529 addr_id: &Self::AddressId,
530 cb: F,
531 ) -> O;
532
533 fn with_ip_address_data_mut<O, F: FnOnce(&mut IpAddressData<I, BT::Instant>) -> O>(
536 &mut self,
537 device_id: &Self::DeviceId,
538 addr_id: &Self::AddressId,
539 cb: F,
540 ) -> O;
541}
542
543pub trait IpDeviceStateContext<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
545 IpDeviceAddressContext<I, BT>
546{
547 type IpDeviceAddressCtx<'a>: IpDeviceAddressContext<I, BT, DeviceId = Self::DeviceId, AddressId = Self::AddressId>;
549
550 fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
557 &mut self,
558 device_id: &Self::DeviceId,
559 cb: F,
560 ) -> O;
561
562 fn add_ip_address(
564 &mut self,
565 device_id: &Self::DeviceId,
566 addr: AddrSubnet<I::Addr, I::AssignedWitness>,
567 config: I::AddressConfig<BT::Instant>,
568 ) -> Result<Self::AddressId, ExistsError>;
569
570 fn remove_ip_address(
572 &mut self,
573 device_id: &Self::DeviceId,
574 addr: Self::AddressId,
575 ) -> RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BT>;
576
577 fn get_address_id(
579 &mut self,
580 device_id: &Self::DeviceId,
581 addr: SpecifiedAddr<I::Addr>,
582 ) -> Result<Self::AddressId, NotFoundError>;
583
584 type AddressIdsIter<'a>: Iterator<Item = Self::AddressId> + 'a;
586
587 fn with_address_ids<
590 O,
591 F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
592 >(
593 &mut self,
594 device_id: &Self::DeviceId,
595 cb: F,
596 ) -> O;
597
598 fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
601 &mut self,
602 device_id: &Self::DeviceId,
603 cb: F,
604 ) -> O;
605
606 fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
609 &mut self,
610 device_id: &Self::DeviceId,
611 cb: F,
612 ) -> O;
613
614 fn join_link_multicast_group(
617 &mut self,
618 bindings_ctx: &mut BT,
619 device_id: &Self::DeviceId,
620 multicast_addr: MulticastAddr<I::Addr>,
621 );
622
623 fn leave_link_multicast_group(
626 &mut self,
627 bindings_ctx: &mut BT,
628 device_id: &Self::DeviceId,
629 multicast_addr: MulticastAddr<I::Addr>,
630 );
631}
632
633pub trait WithIpDeviceConfigurationMutInner<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
636 DeviceIdContext<AnyDevice>
637{
638 type IpDeviceStateCtx<'s>: IpDeviceStateContext<I, BT, DeviceId = Self::DeviceId>
640 + GmpHandler<I, BT>
641 + NudIpHandler<I, BT>
642 + DadHandler<I, BT>
643 + 's
644 where
645 Self: 's;
646
647 fn ip_device_configuration_and_ctx(
650 &mut self,
651 ) -> (&I::Configuration, Self::IpDeviceStateCtx<'_>);
652
653 fn with_configuration_and_flags_mut<
656 O,
657 F: FnOnce(&mut I::Configuration, &mut IpDeviceFlags) -> O,
658 >(
659 &mut self,
660 device_id: &Self::DeviceId,
661 cb: F,
662 ) -> O;
663}
664
665pub trait IpDeviceConfigurationContext<
667 I: IpDeviceIpExt,
668 BC: IpDeviceBindingsContext<I, Self::DeviceId>,
669>: IpDeviceStateContext<I, BC> + IpDeviceMtuContext<I> + DeviceIdContext<AnyDevice>
670{
671 type DevicesIter<'s>: Iterator<Item = Self::DeviceId> + 's;
673 type WithIpDeviceConfigurationInnerCtx<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
675 + GmpHandler<I, BC>
676 + NudIpHandler<I, BC>
677 + DadHandler<I, BC>
678 + IpAddressRemovalHandler<I, BC>
679 + IpDeviceMtuContext<I>
680 + 's;
681 type WithIpDeviceConfigurationMutInner<'s>: WithIpDeviceConfigurationMutInner<I, BC, DeviceId = Self::DeviceId>
683 + 's;
684 type DeviceAddressAndGroupsAccessor<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId>
686 + 's;
687
688 fn with_ip_device_configuration<
691 O,
692 F: FnOnce(&I::Configuration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
693 >(
694 &mut self,
695 device_id: &Self::DeviceId,
696 cb: F,
697 ) -> O;
698
699 fn with_ip_device_configuration_mut<
701 O,
702 F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
703 >(
704 &mut self,
705 device_id: &Self::DeviceId,
706 cb: F,
707 ) -> O;
708
709 fn with_devices_and_state<
712 O,
713 F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
714 >(
715 &mut self,
716 cb: F,
717 ) -> O;
718
719 fn loopback_id(&mut self) -> Option<Self::DeviceId>;
722}
723
724pub trait WithIpv6DeviceConfigurationMutInner<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
727 WithIpDeviceConfigurationMutInner<Ipv6, BC>
728{
729 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId>
731 + GmpHandler<Ipv6, BC>
732 + NudIpHandler<Ipv6, BC>
733 + DadHandler<Ipv6, BC>
734 + RsHandler<BC>
735 + SlaacHandler<BC>
736 + RouteDiscoveryHandler<BC>
737 + 's
738 where
739 Self: 's;
740
741 fn ipv6_device_configuration_and_ctx(
744 &mut self,
745 ) -> (&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>);
746}
747
748pub trait Ipv6DeviceConfigurationContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
750 IpDeviceConfigurationContext<Ipv6, BC>
751{
752 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
754 + GmpHandler<Ipv6, BC>
755 + MldPacketHandler<BC, Self::DeviceId>
756 + NudIpHandler<Ipv6, BC>
757 + DadHandler<Ipv6, BC>
758 + RsHandler<BC>
759 + SlaacHandler<BC>
760 + RouteDiscoveryHandler<BC>
761 + 's;
762 type WithIpv6DeviceConfigurationMutInner<'s>: WithIpv6DeviceConfigurationMutInner<BC, DeviceId = Self::DeviceId>
764 + 's;
765
766 fn with_ipv6_device_configuration<
769 O,
770 F: FnOnce(&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) -> O,
771 >(
772 &mut self,
773 device_id: &Self::DeviceId,
774 cb: F,
775 ) -> O;
776
777 fn with_ipv6_device_configuration_mut<
779 O,
780 F: FnOnce(Self::WithIpv6DeviceConfigurationMutInner<'_>) -> O,
781 >(
782 &mut self,
783 device_id: &Self::DeviceId,
784 cb: F,
785 ) -> O;
786}
787
788pub trait Ipv6LinkLayerAddr {
790 fn as_bytes(&self) -> &[u8];
792
793 fn eui64_iid(&self) -> [u8; 8];
795}
796
797pub trait Ipv6DeviceContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
799 IpDeviceStateContext<Ipv6, BC>
800{
801 type LinkLayerAddr: Ipv6LinkLayerAddr;
803
804 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
807
808 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
810
811 fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
813 &mut self,
814 device_id: &Self::DeviceId,
815 cb: F,
816 ) -> O;
817
818 fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
820 &mut self,
821 device_id: &Self::DeviceId,
822 cb: F,
823 ) -> O;
824}
825
826pub trait IpDeviceHandler<I: IpDeviceIpExt, BC>: DeviceIdContext<AnyDevice> {
828 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool;
830
831 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8);
833
834 fn handle_received_dad_packet(
849 &mut self,
850 bindings_ctx: &mut BC,
851 device_id: &Self::DeviceId,
852 addr: SpecifiedAddr<I::Addr>,
853 packet_data: I::ReceivedPacketData<'_>,
854 ) -> Option<IpAddressState>;
855}
856
857impl<
858 I: IpDeviceIpExt,
859 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
860 CC: IpDeviceConfigurationContext<I, BC> + ResourceCounterContext<CC::DeviceId, IpCounters<I>>,
861> IpDeviceHandler<I, BC> for CC
862{
863 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool {
864 is_ip_unicast_forwarding_enabled(self, device_id)
865 }
866
867 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8) {
868 self.with_default_hop_limit_mut(device_id, |default_hop_limit| {
869 *default_hop_limit = hop_limit
870 })
871 }
872
873 fn handle_received_dad_packet(
874 &mut self,
875 bindings_ctx: &mut BC,
876 device_id: &Self::DeviceId,
877 addr: SpecifiedAddr<I::Addr>,
878 packet_data: I::ReceivedPacketData<'_>,
879 ) -> Option<IpAddressState> {
880 let addr_id = match self.get_address_id(device_id, addr) {
881 Ok(o) => o,
882 Err(NotFoundError) => return None,
883 };
884
885 let orig_state =
886 match self.with_ip_device_configuration(device_id, |_config, mut core_ctx| {
887 core_ctx.handle_incoming_packet(bindings_ctx, device_id, &addr_id, packet_data)
888 }) {
889 DadIncomingPacketResult::Assigned { should_remove } => {
890 if !should_remove {
891 return Some(IpAddressState::Assigned);
893 } else {
894 IpAddressState::Assigned
905 }
906 }
907 DadIncomingPacketResult::Tentative { meta } => {
908 #[derive(GenericOverIp)]
909 #[generic_over_ip(I, Ip)]
910 struct Wrapped<I: IpDeviceIpExt>(I::IncomingPacketResultMeta);
911 let is_looped_back = I::map_ip_in(
912 Wrapped(meta),
913 |Wrapped(())| false,
916 |Wrapped(Ipv6PacketResultMetadata { matched_nonce })| matched_nonce,
929 );
930
931 if is_looped_back {
932 self.increment_both(device_id, |c| {
934 #[derive(GenericOverIp)]
935 #[generic_over_ip(I, Ip)]
936 struct InCounters<'a, I: IpDeviceIpExt>(
937 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<
938 Counter,
939 >,
940 );
941 I::map_ip_in::<_, _>(
942 InCounters(&c.version_rx),
943 |_counters| {
944 unreachable!("Looped back ARP probes are dropped in ARP")
945 },
946 |InCounters(counters)| &counters.drop_looped_back_dad_probe,
947 )
948 });
949
950 return Some(IpAddressState::Tentative);
953 } else {
954 IpAddressState::Tentative
956 }
957 }
958 DadIncomingPacketResult::Uninitialized => IpAddressState::Unavailable,
959 };
960
961 let removal_reason = match orig_state {
964 IpAddressState::Assigned => AddressRemovedReason::Forfeited,
967 IpAddressState::Tentative | IpAddressState::Unavailable => {
970 AddressRemovedReason::DadFailed
971 }
972 };
973 match del_ip_addr(
974 self,
975 bindings_ctx,
976 device_id,
977 DelIpAddr::AddressId(addr_id),
978 removal_reason,
979 ) {
980 Ok(result) => {
981 bindings_ctx.defer_removal_result(result);
982 Some(orig_state)
983 }
984 Err(NotFoundError) => {
985 None
987 }
988 }
989 }
990}
991
992pub fn receive_igmp_packet<CC, BC, B, H>(
994 core_ctx: &mut CC,
995 bindings_ctx: &mut BC,
996 device: &CC::DeviceId,
997 src_ip: Ipv4SourceAddr,
998 dst_ip: SpecifiedAddr<Ipv4Addr>,
999 buffer: B,
1000 info: &LocalDeliveryPacketInfo<Ipv4, H>,
1001) where
1002 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1003 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1004 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>: IpDeviceStateContext<Ipv4, BC, DeviceId = CC::DeviceId>
1005 + IgmpPacketHandler<BC, CC::DeviceId>,
1006 B: BufferMut,
1007 H: IpHeaderInfo<Ipv4>,
1008{
1009 core_ctx.with_ip_device_configuration(device, |_config, mut core_ctx| {
1010 IgmpPacketHandler::receive_igmp_packet(
1011 &mut core_ctx,
1012 bindings_ctx,
1013 device,
1014 src_ip,
1015 dst_ip,
1016 buffer,
1017 info,
1018 )
1019 })
1020}
1021
1022pub trait Ipv6DeviceHandler<BC>: IpDeviceHandler<Ipv6, BC> {
1024 type LinkLayerAddr: Ipv6LinkLayerAddr;
1026
1027 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
1030
1031 fn set_discovered_retrans_timer(
1033 &mut self,
1034 bindings_ctx: &mut BC,
1035 device_id: &Self::DeviceId,
1036 retrans_timer: NonZeroDuration,
1037 );
1038
1039 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
1041
1042 fn update_discovered_ipv6_route(
1044 &mut self,
1045 bindings_ctx: &mut BC,
1046 device_id: &Self::DeviceId,
1047 route: Ipv6DiscoveredRoute,
1048 lifetime: Option<NonZeroNdpLifetime>,
1049 );
1050
1051 fn apply_slaac_update(
1053 &mut self,
1054 bindings_ctx: &mut BC,
1055 device_id: &Self::DeviceId,
1056 prefix: Subnet<Ipv6Addr>,
1057 preferred_lifetime: Option<NonZeroNdpLifetime>,
1058 valid_lifetime: Option<NonZeroNdpLifetime>,
1059 );
1060
1061 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
1063 &mut self,
1064 bindings_ctx: &mut BC,
1065 device: &Self::DeviceId,
1066 src_ip: Ipv6SourceAddr,
1067 dst_ip: SpecifiedAddr<Ipv6Addr>,
1068 packet: MldPacket<B>,
1069 header_info: &H,
1070 );
1071}
1072
1073impl<
1074 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1075 CC: Ipv6DeviceContext<BC>
1076 + Ipv6DeviceConfigurationContext<BC>
1077 + ResourceCounterContext<CC::DeviceId, IpCounters<Ipv6>>,
1078> Ipv6DeviceHandler<BC> for CC
1079{
1080 type LinkLayerAddr = CC::LinkLayerAddr;
1081
1082 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<CC::LinkLayerAddr> {
1083 Ipv6DeviceContext::get_link_layer_addr(self, device_id)
1084 }
1085
1086 fn set_discovered_retrans_timer(
1087 &mut self,
1088 _bindings_ctx: &mut BC,
1089 device_id: &Self::DeviceId,
1090 retrans_timer: NonZeroDuration,
1091 ) {
1092 self.with_network_learned_parameters_mut(device_id, |state| {
1093 state.retrans_timer = Some(retrans_timer)
1094 })
1095 }
1096
1097 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
1098 Ipv6DeviceContext::set_link_mtu(self, device_id, mtu)
1099 }
1100
1101 fn update_discovered_ipv6_route(
1102 &mut self,
1103 bindings_ctx: &mut BC,
1104 device_id: &Self::DeviceId,
1105 route: Ipv6DiscoveredRoute,
1106 lifetime: Option<NonZeroNdpLifetime>,
1107 ) {
1108 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1109 RouteDiscoveryHandler::update_route(
1110 &mut core_ctx,
1111 bindings_ctx,
1112 device_id,
1113 route,
1114 lifetime,
1115 )
1116 })
1117 }
1118
1119 fn apply_slaac_update(
1120 &mut self,
1121 bindings_ctx: &mut BC,
1122 device_id: &Self::DeviceId,
1123 prefix: Subnet<Ipv6Addr>,
1124 preferred_lifetime: Option<NonZeroNdpLifetime>,
1125 valid_lifetime: Option<NonZeroNdpLifetime>,
1126 ) {
1127 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1128 SlaacHandler::apply_slaac_update(
1129 &mut core_ctx,
1130 bindings_ctx,
1131 device_id,
1132 prefix,
1133 preferred_lifetime,
1134 valid_lifetime,
1135 )
1136 })
1137 }
1138
1139 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
1140 &mut self,
1141 bindings_ctx: &mut BC,
1142 device: &Self::DeviceId,
1143 src_ip: Ipv6SourceAddr,
1144 dst_ip: SpecifiedAddr<Ipv6Addr>,
1145 packet: MldPacket<B>,
1146 header_info: &H,
1147 ) {
1148 self.with_ipv6_device_configuration(device, |_config, mut core_ctx| {
1149 MldPacketHandler::receive_mld_packet(
1150 &mut core_ctx,
1151 bindings_ctx,
1152 device,
1153 src_ip,
1154 dst_ip,
1155 packet,
1156 header_info,
1157 )
1158 })
1159 }
1160}
1161
1162pub trait IpDeviceSendContext<I: IpExt, BC: TxMetadataBindingsTypes>:
1164 DeviceIdContext<AnyDevice>
1165{
1166 fn send_ip_frame<S>(
1168 &mut self,
1169 bindings_ctx: &mut BC,
1170 device_id: &Self::DeviceId,
1171 destination: IpPacketDestination<I, &Self::DeviceId>,
1172 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
1173 body: S,
1174 egress_proof: ProofOfEgressCheck,
1175 ) -> Result<(), SendFrameError<S>>
1176 where
1177 S: Serializer,
1178 S::Buffer: BufferMut;
1179}
1180
1181fn enable_ipv6_device_with_config<
1182 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1183 CC: Ipv6DeviceContext<BC>
1184 + GmpHandler<Ipv6, BC>
1185 + RsHandler<BC>
1186 + DadHandler<Ipv6, BC>
1187 + SlaacHandler<BC>,
1188>(
1189 core_ctx: &mut CC,
1190 bindings_ctx: &mut BC,
1191 device_id: &CC::DeviceId,
1192 config: &Ipv6DeviceConfiguration,
1193) {
1194 join_ip_multicast_with_config(
1196 core_ctx,
1197 bindings_ctx,
1198 device_id,
1199 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1200 config,
1201 );
1202 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1203
1204 core_ctx
1211 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1212 .into_iter()
1213 .for_each(|addr_id| {
1214 let needs_dad = DadHandler::initialize_duplicate_address_detection(
1215 core_ctx,
1216 bindings_ctx,
1217 device_id,
1218 &addr_id,
1219 |state| IpDeviceEvent::AddressStateChanged {
1220 device: device_id.clone(),
1221 addr: addr_id.addr().into(),
1222 state,
1223 },
1224 );
1225 match needs_dad {
1226 NeedsDad::Yes(token) => {
1227 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1228 }
1229 NeedsDad::No => {}
1230 }
1231 });
1232
1233 if core_ctx.get_link_layer_addr(device_id).is_some() {
1236 SlaacHandler::generate_link_local_address(core_ctx, bindings_ctx, device_id);
1237 }
1238
1239 RsHandler::start_router_solicitation(core_ctx, bindings_ctx, device_id);
1240}
1241
1242fn disable_ipv6_device_with_config<
1243 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1244 CC: Ipv6DeviceContext<BC>
1245 + GmpHandler<Ipv6, BC>
1246 + RsHandler<BC>
1247 + DadHandler<Ipv6, BC>
1248 + RouteDiscoveryHandler<BC>
1249 + SlaacHandler<BC>
1250 + NudIpHandler<Ipv6, BC>,
1251>(
1252 core_ctx: &mut CC,
1253 bindings_ctx: &mut BC,
1254 device_id: &CC::DeviceId,
1255 device_config: &Ipv6DeviceConfiguration,
1256) {
1257 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1258
1259 SlaacHandler::remove_all_slaac_addresses(core_ctx, bindings_ctx, device_id);
1260
1261 RouteDiscoveryHandler::invalidate_routes(core_ctx, bindings_ctx, device_id);
1262
1263 RsHandler::stop_router_solicitation(core_ctx, bindings_ctx, device_id);
1264
1265 core_ctx.with_network_learned_parameters_mut(device_id, |params| params.reset());
1268
1269 core_ctx
1272 .with_address_ids(device_id, |addrs, core_ctx| {
1273 addrs
1274 .map(|addr_id| {
1275 core_ctx.with_ip_address_data(
1276 device_id,
1277 &addr_id,
1278 |IpAddressData { flags: _, config }| (addr_id.clone(), *config),
1279 )
1280 })
1281 .collect::<Vec<_>>()
1282 })
1283 .into_iter()
1284 .for_each(|(addr_id, config)| {
1285 if config
1286 .is_some_and(|config| config.is_slaac() && addr_id.addr().addr().is_link_local())
1287 {
1288 del_ip_addr_inner_and_notify_handler(
1289 core_ctx,
1290 bindings_ctx,
1291 device_id,
1292 DelIpAddr::AddressId(addr_id),
1293 AddressRemovedReason::Manual,
1294 device_config,
1295 )
1296 .map(|remove_result| {
1297 bindings_ctx.defer_removal_result(remove_result);
1298 })
1299 .unwrap_or_else(|NotFoundError| {
1300 })
1304 } else {
1305 DadHandler::stop_duplicate_address_detection(
1306 core_ctx,
1307 bindings_ctx,
1308 device_id,
1309 &addr_id,
1310 );
1311 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1312 device: device_id.clone(),
1313 addr: addr_id.addr().into(),
1314 state: IpAddressState::Unavailable,
1315 });
1316 }
1317 });
1318
1319 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1320 leave_ip_multicast_with_config(
1321 core_ctx,
1322 bindings_ctx,
1323 device_id,
1324 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1325 device_config,
1326 );
1327}
1328
1329fn enable_ipv4_device_with_config<
1330 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1331 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC> + DadHandler<Ipv4, BC>,
1332>(
1333 core_ctx: &mut CC,
1334 bindings_ctx: &mut BC,
1335 device_id: &CC::DeviceId,
1336 config: &Ipv4DeviceConfiguration,
1337) {
1338 join_ip_multicast_with_config(
1340 core_ctx,
1341 bindings_ctx,
1342 device_id,
1343 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1344 config,
1345 );
1346 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1347 core_ctx
1348 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1349 .into_iter()
1350 .for_each(|addr_id| {
1351 let needs_dad = DadHandler::initialize_duplicate_address_detection(
1352 core_ctx,
1353 bindings_ctx,
1354 device_id,
1355 &addr_id,
1356 |state| IpDeviceEvent::AddressStateChanged {
1357 device: device_id.clone(),
1358 addr: addr_id.addr().into(),
1359 state,
1360 },
1361 );
1362 match needs_dad {
1363 NeedsDad::Yes(token) => {
1364 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1365 }
1366 NeedsDad::No => {}
1367 }
1368 })
1369}
1370
1371fn disable_ipv4_device_with_config<
1372 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1373 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC> + NudIpHandler<Ipv4, BC>,
1374>(
1375 core_ctx: &mut CC,
1376 bindings_ctx: &mut BC,
1377 device_id: &CC::DeviceId,
1378 config: &Ipv4DeviceConfiguration,
1379) {
1380 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1381 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1382 leave_ip_multicast_with_config(
1383 core_ctx,
1384 bindings_ctx,
1385 device_id,
1386 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1387 config,
1388 );
1389 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1390 addrs.for_each(|addr| {
1391 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1392 device: device_id.clone(),
1393 addr: addr.addr().into(),
1394 state: IpAddressState::Unavailable,
1395 });
1396 })
1397 })
1398}
1399
1400pub fn get_ipv4_addr_subnet<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv4, BT>>(
1402 core_ctx: &mut CC,
1403 device_id: &CC::DeviceId,
1404) -> Option<AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> {
1405 core_ctx.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next().map(|a| a.addr_sub()))
1406}
1407
1408pub fn get_ipv6_hop_limit<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv6, BT>>(
1410 core_ctx: &mut CC,
1411 device: &CC::DeviceId,
1412) -> NonZeroU8 {
1413 core_ctx.with_default_hop_limit(device, Clone::clone)
1414}
1415
1416pub fn is_ip_unicast_forwarding_enabled<
1418 I: IpDeviceIpExt,
1419 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1420 CC: IpDeviceConfigurationContext<I, BC>,
1421>(
1422 core_ctx: &mut CC,
1423 device_id: &CC::DeviceId,
1424) -> bool {
1425 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1426 AsRef::<IpDeviceConfiguration>::as_ref(state).unicast_forwarding_enabled
1427 })
1428}
1429
1430pub fn is_ip_multicast_forwarding_enabled<
1432 I: IpDeviceIpExt,
1433 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1434 CC: IpDeviceConfigurationContext<I, BC>,
1435>(
1436 core_ctx: &mut CC,
1437 device_id: &CC::DeviceId,
1438) -> bool {
1439 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1440 AsRef::<IpDeviceConfiguration>::as_ref(state).multicast_forwarding_enabled
1441 })
1442}
1443
1444pub fn join_ip_multicast_with_config<
1451 I: IpDeviceIpExt,
1452 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1453 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1454>(
1455 core_ctx: &mut CC,
1456 bindings_ctx: &mut BC,
1457 device_id: &CC::DeviceId,
1458 multicast_addr: MulticastAddr<I::Addr>,
1459 _config: &I::Configuration,
1460) {
1461 match core_ctx.gmp_join_group(bindings_ctx, device_id, multicast_addr) {
1462 GroupJoinResult::Joined(()) => {
1463 core_ctx.join_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1464 }
1465 GroupJoinResult::AlreadyMember => {}
1466 }
1467}
1468
1469pub fn join_ip_multicast<
1480 I: IpDeviceIpExt,
1481 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1482 CC: IpDeviceConfigurationContext<I, BC>,
1483>(
1484 core_ctx: &mut CC,
1485 bindings_ctx: &mut BC,
1486 device_id: &CC::DeviceId,
1487 multicast_addr: MulticastAddr<I::Addr>,
1488) {
1489 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1490 join_ip_multicast_with_config(
1491 &mut core_ctx,
1492 bindings_ctx,
1493 device_id,
1494 multicast_addr,
1495 config,
1496 )
1497 })
1498}
1499
1500pub fn leave_ip_multicast_with_config<
1507 I: IpDeviceIpExt,
1508 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1509 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1510>(
1511 core_ctx: &mut CC,
1512 bindings_ctx: &mut BC,
1513 device_id: &CC::DeviceId,
1514 multicast_addr: MulticastAddr<I::Addr>,
1515 _config: &I::Configuration,
1516) {
1517 match core_ctx.gmp_leave_group(bindings_ctx, device_id, multicast_addr) {
1518 GroupLeaveResult::Left(()) => {
1519 core_ctx.leave_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1520 }
1521 GroupLeaveResult::StillMember => {}
1522 GroupLeaveResult::NotMember => panic!(
1523 "attempted to leave IP multicast group we were not a member of: {}",
1524 multicast_addr,
1525 ),
1526 }
1527}
1528
1529pub fn leave_ip_multicast<
1544 I: IpDeviceIpExt,
1545 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1546 CC: IpDeviceConfigurationContext<I, BC>,
1547>(
1548 core_ctx: &mut CC,
1549 bindings_ctx: &mut BC,
1550 device_id: &CC::DeviceId,
1551 multicast_addr: MulticastAddr<I::Addr>,
1552) {
1553 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1554 leave_ip_multicast_with_config(
1555 &mut core_ctx,
1556 bindings_ctx,
1557 device_id,
1558 multicast_addr,
1559 config,
1560 )
1561 })
1562}
1563
1564pub fn add_ip_addr_subnet_with_config<
1571 I: IpDeviceIpExt,
1572 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1573 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1574>(
1575 core_ctx: &mut CC,
1576 bindings_ctx: &mut BC,
1577 device_id: &CC::DeviceId,
1578 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1579 addr_config: I::AddressConfig<BC::Instant>,
1580 _device_config: &I::Configuration,
1581) -> Result<CC::AddressId, ExistsError> {
1582 info!("adding addr {addr_sub:?} config {addr_config:?} to device {device_id:?}");
1583 let CommonAddressProperties { valid_until, preferred_lifetime } =
1584 I::get_common_props(&addr_config);
1585 let addr_id = core_ctx.add_ip_address(device_id, addr_sub, addr_config)?;
1586 assert_eq!(addr_id.addr().addr(), addr_sub.addr().get());
1587
1588 let ip_enabled =
1589 core_ctx.with_ip_device_flags(device_id, |IpDeviceFlags { ip_enabled }| *ip_enabled);
1590
1591 let needs_dad = if ip_enabled {
1592 DadHandler::initialize_duplicate_address_detection(
1593 core_ctx,
1594 bindings_ctx,
1595 device_id,
1596 &addr_id,
1597 |state| IpDeviceEvent::AddressAdded {
1598 device: device_id.clone(),
1599 addr: addr_sub.to_witness(),
1600 state,
1601 valid_until,
1602 preferred_lifetime,
1603 },
1604 )
1605 } else {
1606 bindings_ctx.on_event(IpDeviceEvent::AddressAdded {
1613 device: device_id.clone(),
1614 addr: addr_sub.to_witness(),
1615 state: IpAddressState::Unavailable,
1616 valid_until,
1617 preferred_lifetime,
1618 });
1619 NeedsDad::No
1620 };
1621
1622 match needs_dad {
1623 NeedsDad::Yes(token) => {
1624 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1625 }
1626 NeedsDad::No => {}
1627 }
1628
1629 Ok(addr_id)
1630}
1631
1632pub trait IpAddressRemovalHandler<I: IpDeviceIpExt, BC: InstantBindingsTypes>:
1634 DeviceIdContext<AnyDevice>
1635{
1636 fn on_address_removed(
1639 &mut self,
1640 bindings_ctx: &mut BC,
1641 device_id: &Self::DeviceId,
1642 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1643 config: I::AddressConfig<BC::Instant>,
1644 reason: AddressRemovedReason,
1645 );
1646}
1647
1648impl<CC: DeviceIdContext<AnyDevice>, BC: InstantBindingsTypes> IpAddressRemovalHandler<Ipv4, BC>
1650 for CC
1651{
1652 fn on_address_removed(
1653 &mut self,
1654 _bindings_ctx: &mut BC,
1655 _device_id: &Self::DeviceId,
1656 _addr_sub: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
1657 _config: Ipv4AddrConfig<BC::Instant>,
1658 _reason: AddressRemovedReason,
1659 ) {
1660 }
1662}
1663
1664impl<CC: SlaacHandler<BC>, BC: InstantContext> IpAddressRemovalHandler<Ipv6, BC> for CC {
1666 fn on_address_removed(
1667 &mut self,
1668 bindings_ctx: &mut BC,
1669 device_id: &Self::DeviceId,
1670 addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
1671 config: Ipv6AddrConfig<BC::Instant>,
1672 reason: AddressRemovedReason,
1673 ) {
1674 match config {
1675 Ipv6AddrConfig::Slaac(config) => SlaacHandler::on_address_removed(
1676 self,
1677 bindings_ctx,
1678 device_id,
1679 addr_sub,
1680 config,
1681 reason,
1682 ),
1683 Ipv6AddrConfig::Manual(_manual_config) => (),
1684 }
1685 }
1686}
1687
1688#[allow(missing_docs)]
1690pub enum DelIpAddr<Id, A> {
1691 SpecifiedAddr(SpecifiedAddr<A>),
1692 AddressId(Id),
1693}
1694
1695impl<Id: IpAddressId<A>, A: IpAddress<Version: AssignedAddrIpExt>> Display for DelIpAddr<Id, A> {
1696 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1697 match self {
1698 DelIpAddr::SpecifiedAddr(addr) => write!(f, "{}", *addr),
1699 DelIpAddr::AddressId(id) => write!(f, "{}", id.addr()),
1700 }
1701 }
1702}
1703
1704pub fn del_ip_addr_inner<
1707 I: IpDeviceIpExt,
1708 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1709 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1710>(
1711 core_ctx: &mut CC,
1712 bindings_ctx: &mut BC,
1713 device_id: &CC::DeviceId,
1714 addr: DelIpAddr<CC::AddressId, I::Addr>,
1715 reason: AddressRemovedReason,
1716 _config: &I::Configuration,
1718) -> Result<
1719 (
1720 AddrSubnet<I::Addr, I::AssignedWitness>,
1721 I::AddressConfig<BC::Instant>,
1722 RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>,
1723 ),
1724 NotFoundError,
1725> {
1726 let addr_id = match addr {
1727 DelIpAddr::SpecifiedAddr(addr) => core_ctx.get_address_id(device_id, addr)?,
1728 DelIpAddr::AddressId(id) => id,
1729 };
1730 DadHandler::stop_duplicate_address_detection(core_ctx, bindings_ctx, device_id, &addr_id);
1731 let addr_config = core_ctx
1735 .with_ip_address_data_mut(device_id, &addr_id, |addr_data| addr_data.config.take())
1736 .ok_or(NotFoundError)?;
1737
1738 let addr_sub = addr_id.addr_sub();
1739 let result = core_ctx.remove_ip_address(device_id, addr_id);
1740
1741 bindings_ctx.on_event(IpDeviceEvent::AddressRemoved {
1742 device: device_id.clone(),
1743 addr: addr_sub.addr().into(),
1744 reason,
1745 });
1746
1747 Ok((addr_sub, addr_config, result))
1748}
1749
1750fn del_ip_addr<
1752 I: IpDeviceIpExt,
1753 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1754 CC: IpDeviceConfigurationContext<I, BC>,
1755>(
1756 core_ctx: &mut CC,
1757 bindings_ctx: &mut BC,
1758 device_id: &CC::DeviceId,
1759 addr: DelIpAddr<CC::AddressId, I::Addr>,
1760 reason: AddressRemovedReason,
1761) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1762 info!("removing addr {addr} from device {device_id:?}");
1763 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1764 del_ip_addr_inner_and_notify_handler(
1765 &mut core_ctx,
1766 bindings_ctx,
1767 device_id,
1768 addr,
1769 reason,
1770 config,
1771 )
1772 })
1773}
1774
1775fn del_ip_addr_inner_and_notify_handler<
1778 I: IpDeviceIpExt,
1779 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1780 CC: IpDeviceStateContext<I, BC>
1781 + GmpHandler<I, BC>
1782 + DadHandler<I, BC>
1783 + IpAddressRemovalHandler<I, BC>,
1784>(
1785 core_ctx: &mut CC,
1786 bindings_ctx: &mut BC,
1787 device_id: &CC::DeviceId,
1788 addr: DelIpAddr<CC::AddressId, I::Addr>,
1789 reason: AddressRemovedReason,
1790 config: &I::Configuration,
1791) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1792 del_ip_addr_inner(core_ctx, bindings_ctx, device_id, addr, reason, config).map(
1793 |(addr_sub, config, result)| {
1794 core_ctx.on_address_removed(bindings_ctx, device_id, addr_sub, config, reason);
1795 result
1796 },
1797 )
1798}
1799
1800pub fn is_ip_device_enabled<
1802 I: IpDeviceIpExt,
1803 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1804 CC: IpDeviceStateContext<I, BC>,
1805>(
1806 core_ctx: &mut CC,
1807 device_id: &CC::DeviceId,
1808) -> bool {
1809 core_ctx.with_ip_device_flags(device_id, |flags| flags.ip_enabled)
1810}
1811
1812pub fn clear_ipv4_device_state<
1814 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1815 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1816>(
1817 core_ctx: &mut CC,
1818 bindings_ctx: &mut BC,
1819 device_id: &CC::DeviceId,
1820) {
1821 core_ctx.with_ip_device_configuration_mut(device_id, |mut core_ctx| {
1822 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1823 let IpDeviceFlags { ip_enabled } = flags;
1826 core::mem::replace(ip_enabled, false)
1827 });
1828
1829 let (config, mut core_ctx) = core_ctx.ip_device_configuration_and_ctx();
1830 let core_ctx = &mut core_ctx;
1831 if ip_enabled {
1832 disable_ipv4_device_with_config(core_ctx, bindings_ctx, device_id, config);
1833 }
1834 })
1835}
1836
1837pub fn clear_ipv6_device_state<
1839 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1840 CC: Ipv6DeviceConfigurationContext<BC>,
1841>(
1842 core_ctx: &mut CC,
1843 bindings_ctx: &mut BC,
1844 device_id: &CC::DeviceId,
1845) {
1846 core_ctx.with_ipv6_device_configuration_mut(device_id, |mut core_ctx| {
1847 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1848 let IpDeviceFlags { ip_enabled } = flags;
1851 core::mem::replace(ip_enabled, false)
1852 });
1853
1854 let (config, mut core_ctx) = core_ctx.ipv6_device_configuration_and_ctx();
1855 let core_ctx = &mut core_ctx;
1856 if ip_enabled {
1857 disable_ipv6_device_with_config(core_ctx, bindings_ctx, device_id, config);
1858 }
1859 })
1860}
1861
1862pub fn on_arp_packet<CC, BC>(
1866 core_ctx: &mut CC,
1867 bindings_ctx: &mut BC,
1868 device_id: &CC::DeviceId,
1869 sender_addr: Ipv4Addr,
1870 target_addr: Ipv4Addr,
1871 is_arp_probe: bool,
1872) -> bool
1873where
1874 CC: IpDeviceHandler<Ipv4, BC> + IpDeviceStateContext<Ipv4, BC>,
1875 BC: IpDeviceStateBindingsTypes,
1876{
1877 if let Some(sender_addr) = SpecifiedAddr::new(sender_addr) {
1883 let sender_addr_state = IpDeviceHandler::<Ipv4, _>::handle_received_dad_packet(
1884 core_ctx,
1885 bindings_ctx,
1886 &device_id,
1887 sender_addr,
1888 Ipv4DadAddressInfo::SourceAddr,
1889 );
1890 match sender_addr_state {
1891 None => {}
1892 Some(IpAddressState::Assigned) => {
1901 info!("DAD received conflicting ARP packet for assigned addr=({sender_addr})");
1902 }
1903 Some(IpAddressState::Tentative) => {
1904 debug!("DAD received conflicting ARP packet for tentative addr=({sender_addr})");
1905 }
1906 Some(IpAddressState::Unavailable) => {
1907 debug!("DAD received conflicting ARP packet for unavailable addr=({sender_addr})");
1908 }
1909 }
1910 }
1911
1912 let Some(target_addr) = SpecifiedAddr::new(target_addr) else {
1913 return false;
1914 };
1915
1916 if is_arp_probe {
1922 let target_addr_state = IpDeviceHandler::<Ipv4, _>::handle_received_dad_packet(
1923 core_ctx,
1924 bindings_ctx,
1925 &device_id,
1926 target_addr,
1927 Ipv4DadAddressInfo::TargetAddr,
1928 );
1929 let assigned = match target_addr_state {
1930 None => false,
1931 Some(IpAddressState::Assigned) => true,
1934 Some(IpAddressState::Tentative) => {
1935 debug!("DAD received conflicting ARP packet for tentative addr=({target_addr})");
1936 false
1937 }
1938 Some(IpAddressState::Unavailable) => {
1939 debug!("DAD received conflicting ARP packet for unavailable addr=({target_addr})");
1940 false
1941 }
1942 };
1943 assigned
1944 } else {
1945 let addr_id = match core_ctx.get_address_id(device_id, target_addr) {
1948 Ok(o) => o,
1949 Err(NotFoundError) => return false,
1950 };
1951
1952 core_ctx.with_ip_address_data(
1953 device_id,
1954 &addr_id,
1955 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
1956 )
1957 }
1958}
1959
1960#[cfg(any(test, feature = "testutils"))]
1961pub(crate) mod testutil {
1962 use alloc::boxed::Box;
1963
1964 use crate::device::IpAddressFlags;
1965
1966 use super::*;
1967
1968 pub fn with_assigned_ipv4_addr_subnets<
1971 BT: IpDeviceStateBindingsTypes,
1972 CC: IpDeviceStateContext<Ipv4, BT>,
1973 O,
1974 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> + '_>) -> O,
1975 >(
1976 core_ctx: &mut CC,
1977 device_id: &CC::DeviceId,
1978 cb: F,
1979 ) -> O {
1980 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1981 cb(Box::new(addrs.map(|a| a.addr_sub())))
1982 })
1983 }
1984
1985 pub fn with_assigned_ipv6_addr_subnets<
1997 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1998 CC: Ipv6DeviceContext<BC>,
1999 O,
2000 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>> + '_>) -> O,
2001 >(
2002 core_ctx: &mut CC,
2003 device_id: &CC::DeviceId,
2004 cb: F,
2005 ) -> O {
2006 core_ctx.with_address_ids(device_id, |addrs, core_ctx| {
2007 cb(Box::new(addrs.filter_map(|addr_id| {
2008 core_ctx
2009 .with_ip_address_data(
2010 device_id,
2011 &addr_id,
2012 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
2013 )
2014 .then(|| addr_id.addr_sub())
2015 })))
2016 })
2017 }
2018}