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 remove_ip_address(
564 &mut self,
565 device_id: &Self::DeviceId,
566 addr: Self::AddressId,
567 ) -> RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BT>;
568
569 fn get_address_id(
571 &mut self,
572 device_id: &Self::DeviceId,
573 addr: SpecifiedAddr<I::Addr>,
574 ) -> Result<Self::AddressId, NotFoundError>;
575
576 type AddressIdsIter<'a>: Iterator<Item = Self::AddressId> + 'a;
578
579 fn with_address_ids<
582 O,
583 F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
584 >(
585 &mut self,
586 device_id: &Self::DeviceId,
587 cb: F,
588 ) -> O;
589
590 fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
593 &mut self,
594 device_id: &Self::DeviceId,
595 cb: F,
596 ) -> O;
597
598 fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
601 &mut self,
602 device_id: &Self::DeviceId,
603 cb: F,
604 ) -> O;
605
606 fn join_link_multicast_group(
609 &mut self,
610 bindings_ctx: &mut BT,
611 device_id: &Self::DeviceId,
612 multicast_addr: MulticastAddr<I::Addr>,
613 );
614
615 fn leave_link_multicast_group(
618 &mut self,
619 bindings_ctx: &mut BT,
620 device_id: &Self::DeviceId,
621 multicast_addr: MulticastAddr<I::Addr>,
622 );
623}
624
625pub trait IpDeviceAddAddressContext<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
631 IpDeviceAddressContext<I, BT>
632{
633 fn add_ip_address(
635 &mut self,
636 device_id: &Self::DeviceId,
637 addr: AddrSubnet<I::Addr, I::AssignedWitness>,
638 config: I::AddressConfig<BT::Instant>,
639 ) -> Result<Self::AddressId, ExistsError>;
640}
641
642pub trait WithIpDeviceConfigurationMutInner<I: IpDeviceIpExt, BT: IpDeviceStateBindingsTypes>:
645 DeviceIdContext<AnyDevice>
646{
647 type IpDeviceStateCtx<'s>: IpDeviceStateContext<I, BT, DeviceId = Self::DeviceId>
649 + IpDeviceAddAddressContext<I, BT>
650 + GmpHandler<I, BT>
651 + NudIpHandler<I, BT>
652 + DadHandler<I, BT>
653 + 's
654 where
655 Self: 's;
656
657 fn ip_device_configuration_and_ctx(
660 &mut self,
661 ) -> (&I::Configuration, Self::IpDeviceStateCtx<'_>);
662
663 fn with_configuration_and_flags_mut<
666 O,
667 F: FnOnce(&mut I::Configuration, &mut IpDeviceFlags) -> O,
668 >(
669 &mut self,
670 device_id: &Self::DeviceId,
671 cb: F,
672 ) -> O;
673}
674
675pub trait IpDeviceConfigurationContext<
677 I: IpDeviceIpExt,
678 BC: IpDeviceBindingsContext<I, Self::DeviceId>,
679>: IpDeviceStateContext<I, BC> + IpDeviceMtuContext<I> + DeviceIdContext<AnyDevice>
680{
681 type DevicesIter<'s>: Iterator<Item = Self::DeviceId> + 's;
683 type WithIpDeviceConfigurationInnerCtx<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
685 + GmpHandler<I, BC>
686 + NudIpHandler<I, BC>
687 + DadHandler<I, BC>
688 + IpAddressRemovalHandler<I, BC>
689 + IpDeviceMtuContext<I>
690 + 's;
691 type WithIpDeviceConfigurationMutInner<'s>: WithIpDeviceConfigurationMutInner<I, BC, DeviceId = Self::DeviceId>
693 + 's;
694 type DeviceAddressAndGroupsAccessor<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId>
696 + 's;
697
698 fn with_ip_device_configuration<
701 O,
702 F: FnOnce(&I::Configuration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
703 >(
704 &mut self,
705 device_id: &Self::DeviceId,
706 cb: F,
707 ) -> O;
708
709 fn with_ip_device_configuration_mut<
711 O,
712 F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
713 >(
714 &mut self,
715 device_id: &Self::DeviceId,
716 cb: F,
717 ) -> O;
718
719 fn with_devices_and_state<
722 O,
723 F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
724 >(
725 &mut self,
726 cb: F,
727 ) -> O;
728
729 fn loopback_id(&mut self) -> Option<Self::DeviceId>;
732}
733
734pub trait WithIpv6DeviceConfigurationMutInner<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
737 WithIpDeviceConfigurationMutInner<Ipv6, BC>
738{
739 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId>
741 + GmpHandler<Ipv6, BC>
742 + NudIpHandler<Ipv6, BC>
743 + DadHandler<Ipv6, BC>
744 + RsHandler<BC>
745 + SlaacHandler<BC>
746 + RouteDiscoveryHandler<BC>
747 + 's
748 where
749 Self: 's;
750
751 fn ipv6_device_configuration_and_ctx(
754 &mut self,
755 ) -> (&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>);
756}
757
758pub trait Ipv6DeviceConfigurationContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
760 IpDeviceConfigurationContext<Ipv6, BC>
761{
762 type Ipv6DeviceStateCtx<'s>: Ipv6DeviceContext<BC, DeviceId = Self::DeviceId, AddressId = Self::AddressId>
764 + GmpHandler<Ipv6, BC>
765 + MldPacketHandler<BC, Self::DeviceId>
766 + NudIpHandler<Ipv6, BC>
767 + DadHandler<Ipv6, BC>
768 + RsHandler<BC>
769 + SlaacHandler<BC>
770 + RouteDiscoveryHandler<BC>
771 + 's;
772 type WithIpv6DeviceConfigurationMutInner<'s>: WithIpv6DeviceConfigurationMutInner<BC, DeviceId = Self::DeviceId>
774 + 's;
775
776 fn with_ipv6_device_configuration<
779 O,
780 F: FnOnce(&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) -> O,
781 >(
782 &mut self,
783 device_id: &Self::DeviceId,
784 cb: F,
785 ) -> O;
786
787 fn with_ipv6_device_configuration_mut<
789 O,
790 F: FnOnce(Self::WithIpv6DeviceConfigurationMutInner<'_>) -> O,
791 >(
792 &mut self,
793 device_id: &Self::DeviceId,
794 cb: F,
795 ) -> O;
796}
797
798pub trait Ipv6LinkLayerAddr {
800 fn as_bytes(&self) -> &[u8];
802
803 fn eui64_iid(&self) -> [u8; 8];
805}
806
807pub trait Ipv6DeviceContext<BC: IpDeviceBindingsContext<Ipv6, Self::DeviceId>>:
809 IpDeviceStateContext<Ipv6, BC>
810{
811 type LinkLayerAddr: Ipv6LinkLayerAddr;
813
814 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
817
818 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
820
821 fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
823 &mut self,
824 device_id: &Self::DeviceId,
825 cb: F,
826 ) -> O;
827
828 fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
830 &mut self,
831 device_id: &Self::DeviceId,
832 cb: F,
833 ) -> O;
834}
835
836pub trait IpDeviceHandler<I: IpDeviceIpExt, BC>: DeviceIdContext<AnyDevice> {
838 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool;
840
841 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8);
843
844 fn handle_received_dad_packet(
859 &mut self,
860 bindings_ctx: &mut BC,
861 device_id: &Self::DeviceId,
862 addr: SpecifiedAddr<I::Addr>,
863 packet_data: I::ReceivedPacketData<'_>,
864 ) -> Option<IpAddressState>;
865}
866
867impl<
868 I: IpDeviceIpExt,
869 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
870 CC: IpDeviceConfigurationContext<I, BC> + ResourceCounterContext<CC::DeviceId, IpCounters<I>>,
871> IpDeviceHandler<I, BC> for CC
872{
873 fn is_router_device(&mut self, device_id: &Self::DeviceId) -> bool {
874 is_ip_unicast_forwarding_enabled(self, device_id)
875 }
876
877 fn set_default_hop_limit(&mut self, device_id: &Self::DeviceId, hop_limit: NonZeroU8) {
878 self.with_default_hop_limit_mut(device_id, |default_hop_limit| {
879 *default_hop_limit = hop_limit
880 })
881 }
882
883 fn handle_received_dad_packet(
884 &mut self,
885 bindings_ctx: &mut BC,
886 device_id: &Self::DeviceId,
887 addr: SpecifiedAddr<I::Addr>,
888 packet_data: I::ReceivedPacketData<'_>,
889 ) -> Option<IpAddressState> {
890 let addr_id = match self.get_address_id(device_id, addr) {
891 Ok(o) => o,
892 Err(NotFoundError) => return None,
893 };
894
895 let orig_state =
896 match self.with_ip_device_configuration(device_id, |_config, mut core_ctx| {
897 core_ctx.handle_incoming_packet(bindings_ctx, device_id, &addr_id, packet_data)
898 }) {
899 DadIncomingPacketResult::Assigned { should_remove } => {
900 if !should_remove {
901 return Some(IpAddressState::Assigned);
903 } else {
904 IpAddressState::Assigned
915 }
916 }
917 DadIncomingPacketResult::Tentative { meta } => {
918 #[derive(GenericOverIp)]
919 #[generic_over_ip(I, Ip)]
920 struct Wrapped<I: IpDeviceIpExt>(I::IncomingPacketResultMeta);
921 let is_looped_back = I::map_ip_in(
922 Wrapped(meta),
923 |Wrapped(())| false,
926 |Wrapped(Ipv6PacketResultMetadata { matched_nonce })| matched_nonce,
939 );
940
941 if is_looped_back {
942 self.increment_both(device_id, |c| {
944 #[derive(GenericOverIp)]
945 #[generic_over_ip(I, Ip)]
946 struct InCounters<'a, I: IpDeviceIpExt>(
947 &'a <I::RxCounters as CounterCollectionSpec>::CounterCollection<
948 Counter,
949 >,
950 );
951 I::map_ip_in::<_, _>(
952 InCounters(&c.version_rx),
953 |_counters| {
954 unreachable!("Looped back ARP probes are dropped in ARP")
955 },
956 |InCounters(counters)| &counters.drop_looped_back_dad_probe,
957 )
958 });
959
960 return Some(IpAddressState::Tentative);
963 } else {
964 IpAddressState::Tentative
966 }
967 }
968 DadIncomingPacketResult::Uninitialized => IpAddressState::Unavailable,
969 };
970
971 let removal_reason = match orig_state {
974 IpAddressState::Assigned => AddressRemovedReason::Forfeited,
977 IpAddressState::Tentative | IpAddressState::Unavailable => {
980 AddressRemovedReason::DadFailed
981 }
982 };
983 match del_ip_addr(
984 self,
985 bindings_ctx,
986 device_id,
987 DelIpAddr::AddressId(addr_id),
988 removal_reason,
989 ) {
990 Ok(result) => {
991 bindings_ctx.defer_removal_result(result);
992 Some(orig_state)
993 }
994 Err(NotFoundError) => {
995 None
997 }
998 }
999 }
1000}
1001
1002pub fn receive_igmp_packet<CC, BC, B, H>(
1004 core_ctx: &mut CC,
1005 bindings_ctx: &mut BC,
1006 device: &CC::DeviceId,
1007 src_ip: Ipv4SourceAddr,
1008 dst_ip: SpecifiedAddr<Ipv4Addr>,
1009 buffer: B,
1010 info: &LocalDeliveryPacketInfo<Ipv4, H>,
1011) where
1012 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1013 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1014 for<'a> CC::WithIpDeviceConfigurationInnerCtx<'a>: IpDeviceStateContext<Ipv4, BC, DeviceId = CC::DeviceId>
1015 + IgmpPacketHandler<BC, CC::DeviceId>,
1016 B: BufferMut,
1017 H: IpHeaderInfo<Ipv4>,
1018{
1019 core_ctx.with_ip_device_configuration(device, |_config, mut core_ctx| {
1020 IgmpPacketHandler::receive_igmp_packet(
1021 &mut core_ctx,
1022 bindings_ctx,
1023 device,
1024 src_ip,
1025 dst_ip,
1026 buffer,
1027 info,
1028 )
1029 })
1030}
1031
1032pub trait Ipv6DeviceHandler<BC>: IpDeviceHandler<Ipv6, BC> {
1034 type LinkLayerAddr: Ipv6LinkLayerAddr;
1036
1037 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr>;
1040
1041 fn set_discovered_retrans_timer(
1043 &mut self,
1044 bindings_ctx: &mut BC,
1045 device_id: &Self::DeviceId,
1046 retrans_timer: NonZeroDuration,
1047 );
1048
1049 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu);
1051
1052 fn update_discovered_ipv6_route(
1054 &mut self,
1055 bindings_ctx: &mut BC,
1056 device_id: &Self::DeviceId,
1057 route: Ipv6DiscoveredRoute,
1058 lifetime: Option<NonZeroNdpLifetime>,
1059 );
1060
1061 fn apply_slaac_update(
1063 &mut self,
1064 bindings_ctx: &mut BC,
1065 device_id: &Self::DeviceId,
1066 prefix: Subnet<Ipv6Addr>,
1067 preferred_lifetime: Option<NonZeroNdpLifetime>,
1068 valid_lifetime: Option<NonZeroNdpLifetime>,
1069 );
1070
1071 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
1073 &mut self,
1074 bindings_ctx: &mut BC,
1075 device: &Self::DeviceId,
1076 src_ip: Ipv6SourceAddr,
1077 dst_ip: SpecifiedAddr<Ipv6Addr>,
1078 packet: MldPacket<B>,
1079 header_info: &H,
1080 );
1081}
1082
1083impl<
1084 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1085 CC: Ipv6DeviceContext<BC>
1086 + Ipv6DeviceConfigurationContext<BC>
1087 + ResourceCounterContext<CC::DeviceId, IpCounters<Ipv6>>,
1088> Ipv6DeviceHandler<BC> for CC
1089{
1090 type LinkLayerAddr = CC::LinkLayerAddr;
1091
1092 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<CC::LinkLayerAddr> {
1093 Ipv6DeviceContext::get_link_layer_addr(self, device_id)
1094 }
1095
1096 fn set_discovered_retrans_timer(
1097 &mut self,
1098 _bindings_ctx: &mut BC,
1099 device_id: &Self::DeviceId,
1100 retrans_timer: NonZeroDuration,
1101 ) {
1102 self.with_network_learned_parameters_mut(device_id, |state| {
1103 state.retrans_timer = Some(retrans_timer)
1104 })
1105 }
1106
1107 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
1108 Ipv6DeviceContext::set_link_mtu(self, device_id, mtu)
1109 }
1110
1111 fn update_discovered_ipv6_route(
1112 &mut self,
1113 bindings_ctx: &mut BC,
1114 device_id: &Self::DeviceId,
1115 route: Ipv6DiscoveredRoute,
1116 lifetime: Option<NonZeroNdpLifetime>,
1117 ) {
1118 self.with_ipv6_device_configuration(device_id, |config, mut core_ctx| {
1119 RouteDiscoveryHandler::update_route(
1120 &mut core_ctx,
1121 bindings_ctx,
1122 device_id,
1123 route,
1124 lifetime,
1125 &config.route_discovery_config,
1126 )
1127 })
1128 }
1129
1130 fn apply_slaac_update(
1131 &mut self,
1132 bindings_ctx: &mut BC,
1133 device_id: &Self::DeviceId,
1134 prefix: Subnet<Ipv6Addr>,
1135 preferred_lifetime: Option<NonZeroNdpLifetime>,
1136 valid_lifetime: Option<NonZeroNdpLifetime>,
1137 ) {
1138 self.with_ipv6_device_configuration(device_id, |_config, mut core_ctx| {
1139 SlaacHandler::apply_slaac_update(
1140 &mut core_ctx,
1141 bindings_ctx,
1142 device_id,
1143 prefix,
1144 preferred_lifetime,
1145 valid_lifetime,
1146 )
1147 })
1148 }
1149
1150 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
1151 &mut self,
1152 bindings_ctx: &mut BC,
1153 device: &Self::DeviceId,
1154 src_ip: Ipv6SourceAddr,
1155 dst_ip: SpecifiedAddr<Ipv6Addr>,
1156 packet: MldPacket<B>,
1157 header_info: &H,
1158 ) {
1159 self.with_ipv6_device_configuration(device, |_config, mut core_ctx| {
1160 MldPacketHandler::receive_mld_packet(
1161 &mut core_ctx,
1162 bindings_ctx,
1163 device,
1164 src_ip,
1165 dst_ip,
1166 packet,
1167 header_info,
1168 )
1169 })
1170 }
1171}
1172
1173pub trait IpDeviceSendContext<I: IpExt, BC: TxMetadataBindingsTypes>:
1175 DeviceIdContext<AnyDevice>
1176{
1177 fn send_ip_frame<S>(
1179 &mut self,
1180 bindings_ctx: &mut BC,
1181 device_id: &Self::DeviceId,
1182 destination: IpPacketDestination<I, &Self::DeviceId>,
1183 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
1184 body: S,
1185 egress_proof: ProofOfEgressCheck,
1186 ) -> Result<(), SendFrameError<S>>
1187 where
1188 S: Serializer,
1189 S::Buffer: BufferMut;
1190}
1191
1192fn enable_ipv6_device_with_config<
1193 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1194 CC: Ipv6DeviceContext<BC>
1195 + GmpHandler<Ipv6, BC>
1196 + RsHandler<BC>
1197 + DadHandler<Ipv6, BC>
1198 + SlaacHandler<BC>,
1199>(
1200 core_ctx: &mut CC,
1201 bindings_ctx: &mut BC,
1202 device_id: &CC::DeviceId,
1203 config: &Ipv6DeviceConfiguration,
1204) {
1205 join_ip_multicast_with_config(
1207 core_ctx,
1208 bindings_ctx,
1209 device_id,
1210 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1211 config,
1212 );
1213 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1214
1215 core_ctx
1222 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1223 .into_iter()
1224 .for_each(|addr_id| {
1225 let needs_dad = DadHandler::initialize_duplicate_address_detection(
1226 core_ctx,
1227 bindings_ctx,
1228 device_id,
1229 &addr_id,
1230 |state| IpDeviceEvent::AddressStateChanged {
1231 device: device_id.clone(),
1232 addr: addr_id.addr().into(),
1233 state,
1234 },
1235 );
1236 match needs_dad {
1237 NeedsDad::Yes(token) => {
1238 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1239 }
1240 NeedsDad::No => {}
1241 }
1242 });
1243
1244 if core_ctx.get_link_layer_addr(device_id).is_some() {
1247 SlaacHandler::generate_link_local_address(core_ctx, bindings_ctx, device_id);
1248 }
1249
1250 RsHandler::start_router_solicitation(core_ctx, bindings_ctx, device_id);
1251}
1252
1253fn disable_ipv6_device_with_config<
1254 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1255 CC: Ipv6DeviceContext<BC>
1256 + GmpHandler<Ipv6, BC>
1257 + RsHandler<BC>
1258 + DadHandler<Ipv6, BC>
1259 + RouteDiscoveryHandler<BC>
1260 + SlaacHandler<BC>
1261 + NudIpHandler<Ipv6, BC>,
1262>(
1263 core_ctx: &mut CC,
1264 bindings_ctx: &mut BC,
1265 device_id: &CC::DeviceId,
1266 device_config: &Ipv6DeviceConfiguration,
1267) {
1268 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1269
1270 SlaacHandler::remove_all_slaac_addresses(core_ctx, bindings_ctx, device_id);
1271
1272 RouteDiscoveryHandler::invalidate_routes(core_ctx, bindings_ctx, device_id);
1273
1274 RsHandler::stop_router_solicitation(core_ctx, bindings_ctx, device_id);
1275
1276 core_ctx.with_network_learned_parameters_mut(device_id, |params| params.reset());
1279
1280 core_ctx
1283 .with_address_ids(device_id, |addrs, core_ctx| {
1284 addrs
1285 .map(|addr_id| {
1286 core_ctx.with_ip_address_data(
1287 device_id,
1288 &addr_id,
1289 |IpAddressData { flags: _, config }| (addr_id.clone(), *config),
1290 )
1291 })
1292 .collect::<Vec<_>>()
1293 })
1294 .into_iter()
1295 .for_each(|(addr_id, config)| {
1296 if config
1297 .is_some_and(|config| config.is_slaac() && addr_id.addr().addr().is_link_local())
1298 {
1299 del_ip_addr_inner_and_notify_handler(
1300 core_ctx,
1301 bindings_ctx,
1302 device_id,
1303 DelIpAddr::AddressId(addr_id),
1304 AddressRemovedReason::Manual,
1305 device_config,
1306 )
1307 .map(|remove_result| {
1308 bindings_ctx.defer_removal_result(remove_result);
1309 })
1310 .unwrap_or_else(|NotFoundError| {
1311 })
1315 } else {
1316 DadHandler::stop_duplicate_address_detection(
1317 core_ctx,
1318 bindings_ctx,
1319 device_id,
1320 &addr_id,
1321 );
1322 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1323 device: device_id.clone(),
1324 addr: addr_id.addr().into(),
1325 state: IpAddressState::Unavailable,
1326 });
1327 }
1328 });
1329
1330 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1331 leave_ip_multicast_with_config(
1332 core_ctx,
1333 bindings_ctx,
1334 device_id,
1335 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS,
1336 device_config,
1337 );
1338}
1339
1340fn enable_ipv4_device_with_config<
1341 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1342 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC> + DadHandler<Ipv4, BC>,
1343>(
1344 core_ctx: &mut CC,
1345 bindings_ctx: &mut BC,
1346 device_id: &CC::DeviceId,
1347 config: &Ipv4DeviceConfiguration,
1348) {
1349 join_ip_multicast_with_config(
1351 core_ctx,
1352 bindings_ctx,
1353 device_id,
1354 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1355 config,
1356 );
1357 GmpHandler::gmp_handle_maybe_enabled(core_ctx, bindings_ctx, device_id);
1358 core_ctx
1359 .with_address_ids(device_id, |addrs, _core_ctx| addrs.collect::<Vec<_>>())
1360 .into_iter()
1361 .for_each(|addr_id| {
1362 let needs_dad = DadHandler::initialize_duplicate_address_detection(
1363 core_ctx,
1364 bindings_ctx,
1365 device_id,
1366 &addr_id,
1367 |state| IpDeviceEvent::AddressStateChanged {
1368 device: device_id.clone(),
1369 addr: addr_id.addr().into(),
1370 state,
1371 },
1372 );
1373 match needs_dad {
1374 NeedsDad::Yes(token) => {
1375 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1376 }
1377 NeedsDad::No => {}
1378 }
1379 })
1380}
1381
1382fn disable_ipv4_device_with_config<
1383 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1384 CC: IpDeviceStateContext<Ipv4, BC> + GmpHandler<Ipv4, BC> + NudIpHandler<Ipv4, BC>,
1385>(
1386 core_ctx: &mut CC,
1387 bindings_ctx: &mut BC,
1388 device_id: &CC::DeviceId,
1389 config: &Ipv4DeviceConfiguration,
1390) {
1391 NudIpHandler::flush_neighbor_table(core_ctx, bindings_ctx, device_id);
1392 GmpHandler::gmp_handle_disabled(core_ctx, bindings_ctx, device_id);
1393 leave_ip_multicast_with_config(
1394 core_ctx,
1395 bindings_ctx,
1396 device_id,
1397 Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
1398 config,
1399 );
1400 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
1401 addrs.for_each(|addr| {
1402 bindings_ctx.on_event(IpDeviceEvent::AddressStateChanged {
1403 device: device_id.clone(),
1404 addr: addr.addr().into(),
1405 state: IpAddressState::Unavailable,
1406 });
1407 })
1408 })
1409}
1410
1411pub fn get_ipv4_addr_subnet<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv4, BT>>(
1413 core_ctx: &mut CC,
1414 device_id: &CC::DeviceId,
1415) -> Option<AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> {
1416 core_ctx.with_address_ids(device_id, |mut addrs, _core_ctx| addrs.next().map(|a| a.addr_sub()))
1417}
1418
1419pub fn get_ipv6_hop_limit<BT: IpDeviceStateBindingsTypes, CC: IpDeviceStateContext<Ipv6, BT>>(
1421 core_ctx: &mut CC,
1422 device: &CC::DeviceId,
1423) -> NonZeroU8 {
1424 core_ctx.with_default_hop_limit(device, Clone::clone)
1425}
1426
1427pub fn is_ip_unicast_forwarding_enabled<
1429 I: IpDeviceIpExt,
1430 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1431 CC: IpDeviceConfigurationContext<I, BC>,
1432>(
1433 core_ctx: &mut CC,
1434 device_id: &CC::DeviceId,
1435) -> bool {
1436 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1437 AsRef::<IpDeviceConfiguration>::as_ref(state).unicast_forwarding_enabled
1438 })
1439}
1440
1441pub fn is_ip_multicast_forwarding_enabled<
1443 I: IpDeviceIpExt,
1444 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1445 CC: IpDeviceConfigurationContext<I, BC>,
1446>(
1447 core_ctx: &mut CC,
1448 device_id: &CC::DeviceId,
1449) -> bool {
1450 core_ctx.with_ip_device_configuration(device_id, |state, _ctx| {
1451 AsRef::<IpDeviceConfiguration>::as_ref(state).multicast_forwarding_enabled
1452 })
1453}
1454
1455pub fn join_ip_multicast_with_config<
1462 I: IpDeviceIpExt,
1463 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1464 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1465>(
1466 core_ctx: &mut CC,
1467 bindings_ctx: &mut BC,
1468 device_id: &CC::DeviceId,
1469 multicast_addr: MulticastAddr<I::Addr>,
1470 _config: &I::Configuration,
1471) {
1472 match core_ctx.gmp_join_group(bindings_ctx, device_id, multicast_addr) {
1473 GroupJoinResult::Joined(()) => {
1474 core_ctx.join_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1475 }
1476 GroupJoinResult::AlreadyMember => {}
1477 }
1478}
1479
1480pub fn join_ip_multicast<
1491 I: IpDeviceIpExt,
1492 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1493 CC: IpDeviceConfigurationContext<I, BC>,
1494>(
1495 core_ctx: &mut CC,
1496 bindings_ctx: &mut BC,
1497 device_id: &CC::DeviceId,
1498 multicast_addr: MulticastAddr<I::Addr>,
1499) {
1500 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1501 join_ip_multicast_with_config(
1502 &mut core_ctx,
1503 bindings_ctx,
1504 device_id,
1505 multicast_addr,
1506 config,
1507 )
1508 })
1509}
1510
1511pub fn leave_ip_multicast_with_config<
1518 I: IpDeviceIpExt,
1519 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1520 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC>,
1521>(
1522 core_ctx: &mut CC,
1523 bindings_ctx: &mut BC,
1524 device_id: &CC::DeviceId,
1525 multicast_addr: MulticastAddr<I::Addr>,
1526 _config: &I::Configuration,
1527) {
1528 match core_ctx.gmp_leave_group(bindings_ctx, device_id, multicast_addr) {
1529 GroupLeaveResult::Left(()) => {
1530 core_ctx.leave_link_multicast_group(bindings_ctx, device_id, multicast_addr)
1531 }
1532 GroupLeaveResult::StillMember => {}
1533 GroupLeaveResult::NotMember => panic!(
1534 "attempted to leave IP multicast group we were not a member of: {}",
1535 multicast_addr,
1536 ),
1537 }
1538}
1539
1540pub fn leave_ip_multicast<
1555 I: IpDeviceIpExt,
1556 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1557 CC: IpDeviceConfigurationContext<I, BC>,
1558>(
1559 core_ctx: &mut CC,
1560 bindings_ctx: &mut BC,
1561 device_id: &CC::DeviceId,
1562 multicast_addr: MulticastAddr<I::Addr>,
1563) {
1564 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1565 leave_ip_multicast_with_config(
1566 &mut core_ctx,
1567 bindings_ctx,
1568 device_id,
1569 multicast_addr,
1570 config,
1571 )
1572 })
1573}
1574
1575pub fn add_ip_addr_subnet_with_config<
1584 I: IpDeviceIpExt,
1585 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1586 CC: IpDeviceStateContext<I, BC>
1587 + IpDeviceAddAddressContext<I, BC>
1588 + GmpHandler<I, BC>
1589 + DadHandler<I, BC>,
1590>(
1591 core_ctx: &mut CC,
1592 bindings_ctx: &mut BC,
1593 device_id: &CC::DeviceId,
1594 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1595 addr_config: I::AddressConfig<BC::Instant>,
1596 _device_config: &I::Configuration,
1597) -> Result<CC::AddressId, ExistsError> {
1598 info!("adding addr {addr_sub:?} config {addr_config:?} to device {device_id:?}");
1599 let CommonAddressProperties { valid_until, preferred_lifetime } =
1600 I::get_common_props(&addr_config);
1601 let addr_id = core_ctx.add_ip_address(device_id, addr_sub, addr_config)?;
1602 assert_eq!(addr_id.addr().addr(), addr_sub.addr().get());
1603
1604 let ip_enabled =
1605 core_ctx.with_ip_device_flags(device_id, |IpDeviceFlags { ip_enabled }| *ip_enabled);
1606
1607 let needs_dad = if ip_enabled {
1608 DadHandler::initialize_duplicate_address_detection(
1609 core_ctx,
1610 bindings_ctx,
1611 device_id,
1612 &addr_id,
1613 |state| IpDeviceEvent::AddressAdded {
1614 device: device_id.clone(),
1615 addr: addr_sub.to_witness(),
1616 state,
1617 valid_until,
1618 preferred_lifetime,
1619 },
1620 )
1621 } else {
1622 bindings_ctx.on_event(IpDeviceEvent::AddressAdded {
1629 device: device_id.clone(),
1630 addr: addr_sub.to_witness(),
1631 state: IpAddressState::Unavailable,
1632 valid_until,
1633 preferred_lifetime,
1634 });
1635 NeedsDad::No
1636 };
1637
1638 match needs_dad {
1639 NeedsDad::Yes(token) => {
1640 core_ctx.start_duplicate_address_detection(bindings_ctx, token);
1641 }
1642 NeedsDad::No => {}
1643 }
1644
1645 Ok(addr_id)
1646}
1647
1648pub trait IpAddressRemovalHandler<I: IpDeviceIpExt, BC: InstantBindingsTypes>:
1650 DeviceIdContext<AnyDevice>
1651{
1652 fn on_address_removed(
1655 &mut self,
1656 bindings_ctx: &mut BC,
1657 device_id: &Self::DeviceId,
1658 addr_sub: AddrSubnet<I::Addr, I::AssignedWitness>,
1659 config: I::AddressConfig<BC::Instant>,
1660 reason: AddressRemovedReason,
1661 );
1662}
1663
1664impl<CC: DeviceIdContext<AnyDevice>, BC: InstantBindingsTypes> IpAddressRemovalHandler<Ipv4, BC>
1666 for CC
1667{
1668 fn on_address_removed(
1669 &mut self,
1670 _bindings_ctx: &mut BC,
1671 _device_id: &Self::DeviceId,
1672 _addr_sub: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
1673 _config: Ipv4AddrConfig<BC::Instant>,
1674 _reason: AddressRemovedReason,
1675 ) {
1676 }
1678}
1679
1680impl<CC: SlaacHandler<BC>, BC: InstantContext> IpAddressRemovalHandler<Ipv6, BC> for CC {
1682 fn on_address_removed(
1683 &mut self,
1684 bindings_ctx: &mut BC,
1685 device_id: &Self::DeviceId,
1686 addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
1687 config: Ipv6AddrConfig<BC::Instant>,
1688 reason: AddressRemovedReason,
1689 ) {
1690 match config {
1691 Ipv6AddrConfig::Slaac(config) => SlaacHandler::on_address_removed(
1692 self,
1693 bindings_ctx,
1694 device_id,
1695 addr_sub,
1696 config,
1697 reason,
1698 ),
1699 Ipv6AddrConfig::Manual(_manual_config) => (),
1700 }
1701 }
1702}
1703
1704#[allow(missing_docs)]
1706pub enum DelIpAddr<Id, A> {
1707 SpecifiedAddr(SpecifiedAddr<A>),
1708 AddressId(Id),
1709}
1710
1711impl<Id: IpAddressId<A>, A: IpAddress<Version: AssignedAddrIpExt>> Display for DelIpAddr<Id, A> {
1712 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1713 match self {
1714 DelIpAddr::SpecifiedAddr(addr) => write!(f, "{}", *addr),
1715 DelIpAddr::AddressId(id) => write!(f, "{}", id.addr()),
1716 }
1717 }
1718}
1719
1720pub fn del_ip_addr_inner<
1723 I: IpDeviceIpExt,
1724 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1725 CC: IpDeviceStateContext<I, BC> + GmpHandler<I, BC> + DadHandler<I, BC>,
1726>(
1727 core_ctx: &mut CC,
1728 bindings_ctx: &mut BC,
1729 device_id: &CC::DeviceId,
1730 addr: DelIpAddr<CC::AddressId, I::Addr>,
1731 reason: AddressRemovedReason,
1732 _config: &I::Configuration,
1739) -> Result<
1740 (
1741 AddrSubnet<I::Addr, I::AssignedWitness>,
1742 I::AddressConfig<BC::Instant>,
1743 RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>,
1744 ),
1745 NotFoundError,
1746> {
1747 let addr_id = match addr {
1748 DelIpAddr::SpecifiedAddr(addr) => core_ctx.get_address_id(device_id, addr)?,
1749 DelIpAddr::AddressId(id) => id,
1750 };
1751 DadHandler::stop_duplicate_address_detection(core_ctx, bindings_ctx, device_id, &addr_id);
1752 let addr_config = core_ctx
1756 .with_ip_address_data_mut(device_id, &addr_id, |addr_data| addr_data.config.take())
1757 .ok_or(NotFoundError)?;
1758
1759 let addr_sub = addr_id.addr_sub();
1760 let result = core_ctx.remove_ip_address(device_id, addr_id);
1761
1762 bindings_ctx.on_event(IpDeviceEvent::AddressRemoved {
1763 device: device_id.clone(),
1764 addr: addr_sub.addr().into(),
1765 reason,
1766 });
1767
1768 Ok((addr_sub, addr_config, result))
1769}
1770
1771fn del_ip_addr<
1773 I: IpDeviceIpExt,
1774 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1775 CC: IpDeviceConfigurationContext<I, BC>,
1776>(
1777 core_ctx: &mut CC,
1778 bindings_ctx: &mut BC,
1779 device_id: &CC::DeviceId,
1780 addr: DelIpAddr<CC::AddressId, I::Addr>,
1781 reason: AddressRemovedReason,
1782) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1783 info!("removing addr {addr} from device {device_id:?}");
1784 core_ctx.with_ip_device_configuration(device_id, |config, mut core_ctx| {
1785 del_ip_addr_inner_and_notify_handler(
1786 &mut core_ctx,
1787 bindings_ctx,
1788 device_id,
1789 addr,
1790 reason,
1791 config,
1792 )
1793 })
1794}
1795
1796fn del_ip_addr_inner_and_notify_handler<
1799 I: IpDeviceIpExt,
1800 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1801 CC: IpDeviceStateContext<I, BC>
1802 + GmpHandler<I, BC>
1803 + DadHandler<I, BC>
1804 + IpAddressRemovalHandler<I, BC>,
1805>(
1806 core_ctx: &mut CC,
1807 bindings_ctx: &mut BC,
1808 device_id: &CC::DeviceId,
1809 addr: DelIpAddr<CC::AddressId, I::Addr>,
1810 reason: AddressRemovedReason,
1811 config: &I::Configuration,
1812) -> Result<RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC>, NotFoundError> {
1813 del_ip_addr_inner(core_ctx, bindings_ctx, device_id, addr, reason, config).map(
1814 |(addr_sub, config, result)| {
1815 core_ctx.on_address_removed(bindings_ctx, device_id, addr_sub, config, reason);
1816 result
1817 },
1818 )
1819}
1820
1821pub fn is_ip_device_enabled<
1823 I: IpDeviceIpExt,
1824 BC: IpDeviceBindingsContext<I, CC::DeviceId>,
1825 CC: IpDeviceStateContext<I, BC>,
1826>(
1827 core_ctx: &mut CC,
1828 device_id: &CC::DeviceId,
1829) -> bool {
1830 core_ctx.with_ip_device_flags(device_id, |flags| flags.ip_enabled)
1831}
1832
1833pub fn clear_ipv4_device_state<
1835 BC: IpDeviceBindingsContext<Ipv4, CC::DeviceId>,
1836 CC: IpDeviceConfigurationContext<Ipv4, BC>,
1837>(
1838 core_ctx: &mut CC,
1839 bindings_ctx: &mut BC,
1840 device_id: &CC::DeviceId,
1841) {
1842 core_ctx.with_ip_device_configuration_mut(device_id, |mut core_ctx| {
1843 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1844 let IpDeviceFlags { ip_enabled } = flags;
1847 core::mem::replace(ip_enabled, false)
1848 });
1849
1850 let (config, mut core_ctx) = core_ctx.ip_device_configuration_and_ctx();
1851 let core_ctx = &mut core_ctx;
1852 if ip_enabled {
1853 disable_ipv4_device_with_config(core_ctx, bindings_ctx, device_id, config);
1854 }
1855 })
1856}
1857
1858pub fn clear_ipv6_device_state<
1860 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
1861 CC: Ipv6DeviceConfigurationContext<BC>,
1862>(
1863 core_ctx: &mut CC,
1864 bindings_ctx: &mut BC,
1865 device_id: &CC::DeviceId,
1866) {
1867 core_ctx.with_ipv6_device_configuration_mut(device_id, |mut core_ctx| {
1868 let ip_enabled = core_ctx.with_configuration_and_flags_mut(device_id, |_config, flags| {
1869 let IpDeviceFlags { ip_enabled } = flags;
1872 core::mem::replace(ip_enabled, false)
1873 });
1874
1875 let (config, mut core_ctx) = core_ctx.ipv6_device_configuration_and_ctx();
1876 let core_ctx = &mut core_ctx;
1877 if ip_enabled {
1878 disable_ipv6_device_with_config(core_ctx, bindings_ctx, device_id, config);
1879 }
1880 })
1881}
1882
1883pub fn on_arp_packet<CC, BC>(
1887 core_ctx: &mut CC,
1888 bindings_ctx: &mut BC,
1889 device_id: &CC::DeviceId,
1890 sender_addr: Ipv4Addr,
1891 target_addr: Ipv4Addr,
1892 is_arp_probe: bool,
1893) -> bool
1894where
1895 CC: IpDeviceHandler<Ipv4, BC> + IpDeviceStateContext<Ipv4, BC>,
1896 BC: IpDeviceStateBindingsTypes,
1897{
1898 if let Some(sender_addr) = SpecifiedAddr::new(sender_addr) {
1904 let sender_addr_state = IpDeviceHandler::<Ipv4, _>::handle_received_dad_packet(
1905 core_ctx,
1906 bindings_ctx,
1907 &device_id,
1908 sender_addr,
1909 Ipv4DadAddressInfo::SourceAddr,
1910 );
1911 match sender_addr_state {
1912 None => {}
1913 Some(IpAddressState::Assigned) => {
1922 info!("DAD received conflicting ARP packet for assigned addr=({sender_addr})");
1923 }
1924 Some(IpAddressState::Tentative) => {
1925 debug!("DAD received conflicting ARP packet for tentative addr=({sender_addr})");
1926 }
1927 Some(IpAddressState::Unavailable) => {
1928 debug!("DAD received conflicting ARP packet for unavailable addr=({sender_addr})");
1929 }
1930 }
1931 }
1932
1933 let Some(target_addr) = SpecifiedAddr::new(target_addr) else {
1934 return false;
1935 };
1936
1937 if is_arp_probe {
1943 let target_addr_state = IpDeviceHandler::<Ipv4, _>::handle_received_dad_packet(
1944 core_ctx,
1945 bindings_ctx,
1946 &device_id,
1947 target_addr,
1948 Ipv4DadAddressInfo::TargetAddr,
1949 );
1950 let assigned = match target_addr_state {
1951 None => false,
1952 Some(IpAddressState::Assigned) => true,
1955 Some(IpAddressState::Tentative) => {
1956 debug!("DAD received conflicting ARP packet for tentative addr=({target_addr})");
1957 false
1958 }
1959 Some(IpAddressState::Unavailable) => {
1960 debug!("DAD received conflicting ARP packet for unavailable addr=({target_addr})");
1961 false
1962 }
1963 };
1964 assigned
1965 } else {
1966 let addr_id = match core_ctx.get_address_id(device_id, target_addr) {
1969 Ok(o) => o,
1970 Err(NotFoundError) => return false,
1971 };
1972
1973 core_ctx.with_ip_address_data(
1974 device_id,
1975 &addr_id,
1976 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
1977 )
1978 }
1979}
1980
1981#[cfg(any(test, feature = "testutils"))]
1982pub(crate) mod testutil {
1983 use alloc::boxed::Box;
1984
1985 use crate::device::IpAddressFlags;
1986
1987 use super::*;
1988
1989 pub fn with_assigned_ipv4_addr_subnets<
1992 BT: IpDeviceStateBindingsTypes,
1993 CC: IpDeviceStateContext<Ipv4, BT>,
1994 O,
1995 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> + '_>) -> O,
1996 >(
1997 core_ctx: &mut CC,
1998 device_id: &CC::DeviceId,
1999 cb: F,
2000 ) -> O {
2001 core_ctx.with_address_ids(device_id, |addrs, _core_ctx| {
2002 cb(Box::new(addrs.map(|a| a.addr_sub())))
2003 })
2004 }
2005
2006 pub fn with_assigned_ipv6_addr_subnets<
2018 BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId>,
2019 CC: Ipv6DeviceContext<BC>,
2020 O,
2021 F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>> + '_>) -> O,
2022 >(
2023 core_ctx: &mut CC,
2024 device_id: &CC::DeviceId,
2025 cb: F,
2026 ) -> O {
2027 core_ctx.with_address_ids(device_id, |addrs, core_ctx| {
2028 cb(Box::new(addrs.filter_map(|addr_id| {
2029 core_ctx
2030 .with_ip_address_data(
2031 device_id,
2032 &addr_id,
2033 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| *assigned,
2034 )
2035 .then(|| addr_id.addr_sub())
2036 })))
2037 })
2038 }
2039}