1use core::borrow::Borrow;
8use core::marker::PhantomData;
9use core::num::NonZeroU8;
10use core::ops::{Deref as _, DerefMut as _};
11use core::sync::atomic::AtomicU16;
12
13use lock_order::lock::{LockLevelFor, UnlockedAccess};
14use lock_order::relation::LockBefore;
15use log::debug;
16use net_types::ip::{AddrSubnet, Ip, IpMarked, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Mtu};
17use net_types::{LinkLocalUnicastAddr, MulticastAddr, SpecifiedAddr, UnicastAddr, Witness as _};
18use netstack3_base::{
19 AnyDevice, CoreTimerContext, CounterContext, DeviceIdContext, ExistsError, IpAddressId as _,
20 IpDeviceAddr, IpDeviceAddressIdContext, Ipv4DeviceAddr, Ipv6DeviceAddr,
21 NetworkPartialSerializer, NetworkSerializer, NotFoundError, RemoveResourceResultWithContext,
22 ResourceCounterContext,
23};
24use netstack3_device::ethernet::EthernetDeviceId;
25use netstack3_device::{DeviceId, WeakDeviceId};
26use netstack3_filter::FilterImpl;
27use netstack3_ip::device::{
28 self, AddressRemovedReason, DadAddressContext, DadAddressStateRef, DadContext, DadState,
29 DadStateRef, DadTimerId, DefaultHopLimit, DelIpAddr, DualStackIpDeviceState, IpAddressData,
30 IpAddressEntry, IpAddressFlags, IpDeviceAddresses, IpDeviceConfiguration, IpDeviceFlags,
31 IpDeviceIpExt, IpDeviceMulticastGroups, IpDeviceStateBindingsTypes, IpDeviceStateContext,
32 IpDeviceStateIpExt, IpDeviceTimerId, Ipv4DadSendData, Ipv4DeviceConfiguration,
33 Ipv4DeviceTimerId, Ipv6AddrConfig, Ipv6AddrSlaacConfig, Ipv6DadAddressContext, Ipv6DadSendData,
34 Ipv6DeviceConfiguration, Ipv6DeviceTimerId, Ipv6DiscoveredRoute, Ipv6DiscoveredRouteProperties,
35 Ipv6DiscoveredRoutesContext, Ipv6NetworkLearnedParameters, Ipv6RouteDiscoveryContext,
36 Ipv6RouteDiscoveryState, RsContext, RsState, RsTimerId, SlaacAddressEntry,
37 SlaacAddressEntryMut, SlaacAddresses, SlaacConfigAndState, SlaacContext, SlaacCounters,
38 SlaacState, WeakAddressId, add_ip_addr_subnet_with_config, del_ip_addr_inner,
39 get_ipv6_hop_limit, is_ip_device_enabled, is_ip_multicast_forwarding_enabled,
40 is_ip_unicast_forwarding_enabled, join_ip_multicast_with_config,
41 leave_ip_multicast_with_config,
42};
43use netstack3_ip::gmp::{
44 GmpGroupState, GmpState, GmpStateRef, IgmpContext, IgmpContextMarker, IgmpSendContext,
45 IgmpStateContext, IgmpTypeLayout, MldContext, MldContextMarker, MldSendContext,
46 MldStateContext, MldTypeLayout, MulticastGroupSet,
47};
48use netstack3_ip::nud::{self, ConfirmationFlags, NudCounters, NudIpHandler};
49use netstack3_ip::{
50 self as ip, AddableMetric, AddressStatus, DEFAULT_TTL, FilterHandlerProvider, IpDeviceContext,
51 IpDeviceEgressStateContext, IpDeviceIngressStateContext, IpLayerIpExt, IpSasHandler,
52 IpSendFrameError, Ipv4PresentAddressStatus,
53};
54use packet::{EmptyBuf, InnerPacketBuilder};
55use packet_formats::icmp::IcmpZeroCode;
56use packet_formats::icmp::ndp::options::{NdpNonce, NdpOptionBuilder};
57use packet_formats::icmp::ndp::{OptionSequenceBuilder, RouterSolicitation};
58use packet_formats::utils::NonZeroDuration;
59
60use crate::context::WrapLockLevel;
61use crate::context::prelude::*;
62use crate::{BindingsContext, BindingsTypes, CoreCtx, IpExt};
63
64pub struct SlaacAddrs<'a, BC: BindingsContext> {
65 pub(crate) core_ctx: CoreCtxWithIpDeviceConfiguration<
66 'a,
67 &'a Ipv6DeviceConfiguration,
68 WrapLockLevel<crate::lock_ordering::Ipv6DeviceSlaac>,
69 BC,
70 >,
71 pub(crate) device_id: DeviceId<BC>,
72 pub(crate) config: &'a Ipv6DeviceConfiguration,
73}
74
75pub struct SlaacAddrsIter<'x, BC: BindingsContext> {
81 core_ctx: CoreCtx<'x, BC, WrapLockLevel<crate::lock_ordering::IpDeviceAddresses<Ipv6>>>,
82 addrs: ip::device::AddressIdIter<'x, Ipv6, BC>,
83 device_id: &'x DeviceId<BC>,
84}
85
86impl<'x, BC> Iterator for SlaacAddrsIter<'x, BC>
87where
88 BC: BindingsContext,
89{
90 type Item = SlaacAddressEntry<BC::Instant>;
91 fn next(&mut self) -> Option<Self::Item> {
92 let Self { core_ctx, addrs, device_id } = self;
93 addrs.by_ref().find_map(|addr_id| {
96 device::IpDeviceAddressContext::<Ipv6, _>::with_ip_address_data(
97 core_ctx,
98 device_id,
99 &addr_id,
100 |IpAddressData { flags: IpAddressFlags { assigned: _ }, config }| {
101 let addr_sub = addr_id.addr_sub();
102 match config {
103 Some(Ipv6AddrConfig::Slaac(config)) => {
104 Some(SlaacAddressEntry { addr_sub: addr_sub, config: *config })
105 }
106 None | Some(Ipv6AddrConfig::Manual(_)) => None,
107 }
108 },
109 )
110 })
111 }
112}
113
114impl<'a, BC: BindingsContext> CounterContext<SlaacCounters> for SlaacAddrs<'a, BC> {
115 fn counters(&self) -> &SlaacCounters {
116 &self
117 .core_ctx
118 .core_ctx
119 .unlocked_access::<crate::lock_ordering::UnlockedState>()
120 .ipv6
121 .slaac_counters
122 }
123}
124
125impl<'a, BC: BindingsContext> SlaacAddresses<BC> for SlaacAddrs<'a, BC> {
126 fn for_each_addr_mut<F: FnMut(SlaacAddressEntryMut<'_, BC::Instant>)>(&mut self, mut cb: F) {
127 let SlaacAddrs { core_ctx, device_id, config: _ } = self;
128 let CoreCtxWithIpDeviceConfiguration { config: _, core_ctx } = core_ctx;
129 let mut state = crate::device::integration::ip_device_state(core_ctx, device_id);
130 let (addrs, mut locked) =
131 state.read_lock_and::<crate::lock_ordering::IpDeviceAddresses<Ipv6>>();
132 addrs.iter().for_each(|entry| {
133 let addr_sub = *entry.addr_sub();
134 let mut locked = locked.adopt(&**entry);
135 let mut state = locked
136 .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv6>, _>(|c| {
137 c.right()
138 });
139 let IpAddressData { config, flags: IpAddressFlags { assigned: _ } } = &mut *state;
140
141 match config {
142 Some(Ipv6AddrConfig::Slaac(config)) => {
143 cb(SlaacAddressEntryMut { addr_sub, config })
144 }
145 None | Some(Ipv6AddrConfig::Manual(_)) => {}
146 }
147 })
148 }
149
150 type AddrsIter<'x> = SlaacAddrsIter<'x, BC>;
151
152 fn with_addrs<O, F: FnOnce(Self::AddrsIter<'_>) -> O>(&mut self, cb: F) -> O {
153 let SlaacAddrs { core_ctx, device_id, config: _ } = self;
154 device::IpDeviceStateContext::<Ipv6, BC>::with_address_ids(
155 core_ctx,
156 device_id,
157 |addrs, core_ctx| {
158 cb(SlaacAddrsIter { core_ctx: core_ctx.as_owned(), addrs, device_id })
159 },
160 )
161 }
162
163 fn add_addr_sub_and_then<O, F: FnOnce(SlaacAddressEntryMut<'_, BC::Instant>, &mut BC) -> O>(
164 &mut self,
165 bindings_ctx: &mut BC,
166 add_addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
167 slaac_config: Ipv6AddrSlaacConfig<BC::Instant>,
168 and_then: F,
169 ) -> Result<O, ExistsError> {
170 let SlaacAddrs { core_ctx, device_id, config } = self;
171
172 add_ip_addr_subnet_with_config::<Ipv6, _, _>(
173 core_ctx,
174 bindings_ctx,
175 device_id,
176 add_addr_sub.to_witness(),
177 Ipv6AddrConfig::Slaac(slaac_config),
178 config,
179 )
180 .map(|entry| {
181 let addr_sub = entry.addr_sub();
182 let mut locked = core_ctx.core_ctx.adopt(entry.deref());
183 let mut state = locked
184 .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv6>, _>(|c| {
185 c.right()
186 });
187 let IpAddressData { config, flags: _ } = &mut *state;
188 let config = assert_matches::assert_matches!(
189 config,
190 Some(Ipv6AddrConfig::Slaac(c)) => c
191 );
192 and_then(SlaacAddressEntryMut { addr_sub: addr_sub, config }, bindings_ctx)
193 })
194 }
195
196 fn remove_addr(
197 &mut self,
198 bindings_ctx: &mut BC,
199 addr: &Ipv6DeviceAddr,
200 ) -> Result<
201 (AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>, Ipv6AddrSlaacConfig<BC::Instant>),
202 NotFoundError,
203 > {
204 let SlaacAddrs { core_ctx, device_id, config } = self;
205 del_ip_addr_inner::<Ipv6, _, _>(
206 core_ctx,
207 bindings_ctx,
208 device_id,
209 DelIpAddr::SpecifiedAddr(addr.into_specified()),
210 AddressRemovedReason::Manual,
211 config,
212 )
213 .map(|(addr_sub, config, result)| {
214 assert_eq!(&addr_sub.addr(), addr);
215 bindings_ctx.defer_removal_result(result);
216 match config {
217 Ipv6AddrConfig::Slaac(config) => (addr_sub, config),
218 Ipv6AddrConfig::Manual(_manual_config) => {
219 unreachable!(
220 "address {addr_sub} on device {device_id:?} should have been a SLAAC \
221 address; config = {config:?}",
222 );
223 }
224 }
225 })
226 }
227}
228
229impl<BT: BindingsTypes, L> IgmpContextMarker for CoreCtx<'_, BT, L> {}
230
231impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv4>>>
232 IgmpStateContext<BC> for CoreCtx<'_, BC, L>
233{
234 fn with_igmp_state<
235 O,
236 F: FnOnce(
237 &MulticastGroupSet<Ipv4Addr, GmpGroupState<Ipv4, BC>>,
238 &GmpState<Ipv4, IgmpTypeLayout, BC>,
239 ) -> O,
240 >(
241 &mut self,
242 device: &Self::DeviceId,
243 cb: F,
244 ) -> O {
245 let mut state = crate::device::integration::ip_device_state(self, device);
246 let state = state.read_lock::<crate::lock_ordering::IpDeviceGmp<Ipv4>>();
247 let IpDeviceMulticastGroups { groups, gmp, .. } = &*state;
248 cb(groups, gmp)
249 }
250}
251
252impl<BT: BindingsTypes, L> MldContextMarker for CoreCtx<'_, BT, L> {}
253
254impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv6>>>
255 MldStateContext<BC> for CoreCtx<'_, BC, L>
256{
257 fn with_mld_state<
258 O,
259 F: FnOnce(
260 &MulticastGroupSet<Ipv6Addr, GmpGroupState<Ipv6, BC>>,
261 &GmpState<Ipv6, MldTypeLayout, BC>,
262 ) -> O,
263 >(
264 &mut self,
265 device: &Self::DeviceId,
266 cb: F,
267 ) -> O {
268 let mut state = crate::device::integration::ip_device_state(self, device);
269 let state = state.read_lock::<crate::lock_ordering::IpDeviceGmp<Ipv6>>();
270 let IpDeviceMulticastGroups { groups, gmp, .. } = &*state;
271 cb(groups, gmp)
272 }
273}
274
275pub struct FilterPresentWithDevices<
281 I: IpLayerIpExt,
282 Devices: Iterator<Item = Accessor::DeviceId>,
283 Accessor: DeviceIdContext<AnyDevice>,
284 BT,
285> {
286 devices: Devices,
287 addr: SpecifiedAddr<I::Addr>,
288 state_accessor: Accessor,
289 assignment_state: fn(
290 &mut Accessor,
291 &Accessor::DeviceId,
292 SpecifiedAddr<I::Addr>,
293 ) -> AddressStatus<I::AddressStatus>,
294 _marker: PhantomData<BT>,
295}
296
297impl<
298 I: IpLayerIpExt,
299 Devices: Iterator<Item = Accessor::DeviceId>,
300 Accessor: DeviceIdContext<AnyDevice>,
301 BT,
302> FilterPresentWithDevices<I, Devices, Accessor, BT>
303{
304 fn new(
305 devices: Devices,
306 state_accessor: Accessor,
307 assignment_state: fn(
308 &mut Accessor,
309 &Accessor::DeviceId,
310 SpecifiedAddr<I::Addr>,
311 ) -> AddressStatus<I::AddressStatus>,
312 addr: SpecifiedAddr<I::Addr>,
313 ) -> Self {
314 Self { devices, addr, state_accessor, assignment_state, _marker: PhantomData }
315 }
316}
317
318impl<
319 's,
320 BT: IpDeviceStateBindingsTypes,
321 I: Ip + IpLayerIpExt + IpDeviceIpExt,
322 Devices: Iterator<Item = Accessor::DeviceId>,
323 Accessor: IpDeviceStateContext<I, BT>,
324> Iterator for FilterPresentWithDevices<I, Devices, Accessor, BT>
325where
326 <I as IpDeviceIpExt>::State<BT>: 's,
327{
328 type Item = (Accessor::DeviceId, I::AddressStatus);
329 fn next(&mut self) -> Option<Self::Item> {
330 let Self { devices, addr, state_accessor, assignment_state, _marker } = self;
331 devices
332 .filter_map(|d| match assignment_state(state_accessor, &d, *addr) {
333 AddressStatus::Present(status) => Some((d, status)),
334 AddressStatus::Unassigned => None,
335 })
336 .next()
337 }
338}
339
340impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv4>>>
341 IpDeviceEgressStateContext<Ipv4> for CoreCtx<'_, BC, L>
342{
343 fn with_next_packet_id<O, F: FnOnce(&AtomicU16) -> O>(&self, cb: F) -> O {
344 cb(&self.unlocked_access::<crate::lock_ordering::UnlockedState>().ipv4.next_packet_id)
345 }
346
347 fn get_local_addr_for_remote(
348 &mut self,
349 device_id: &Self::DeviceId,
350 remote: Option<SpecifiedAddr<Ipv4Addr>>,
351 ) -> Option<IpDeviceAddr<Ipv4Addr>> {
352 IpSasHandler::<Ipv4, _>::get_local_addr_for_remote(self, device_id, remote)
353 }
354
355 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
356 DEFAULT_TTL
357 }
358}
359
360impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv4>>>
361 IpDeviceIngressStateContext<Ipv4> for CoreCtx<'_, BC, L>
362{
363 fn address_status_for_device(
364 &mut self,
365 dst_ip: SpecifiedAddr<Ipv4Addr>,
366 device_id: &Self::DeviceId,
367 ) -> AddressStatus<Ipv4PresentAddressStatus> {
368 AddressStatus::from_context_addr_v4(self, device_id, dst_ip)
369 }
370}
371
372impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>>
373 IpDeviceContext<Ipv4> for CoreCtx<'_, BC, L>
374{
375 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
376 is_ip_device_enabled::<Ipv4, _, _>(self, device_id)
377 }
378
379 type DeviceAndAddressStatusIter<'a> = FilterPresentWithDevices<
380 Ipv4,
381 <Self as device::IpDeviceConfigurationContext<Ipv4, BC>>::DevicesIter<'a>,
382 <Self as device::IpDeviceConfigurationContext<Ipv4, BC>>::DeviceAddressAndGroupsAccessor<
383 'a,
384 >,
385 BC,
386 >;
387
388 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
389 &mut self,
390 addr: SpecifiedAddr<Ipv4Addr>,
391 cb: F,
392 ) -> R {
393 device::IpDeviceConfigurationContext::<Ipv4, _>::with_devices_and_state(
394 self,
395 |devices, state| {
396 cb(FilterPresentWithDevices::new(
397 devices,
398 state,
399 AddressStatus::from_context_addr_v4,
400 addr,
401 ))
402 },
403 )
404 }
405
406 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
407 is_ip_unicast_forwarding_enabled::<Ipv4, _, _>(self, device_id)
408 }
409}
410
411impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv6>>>
412 IpDeviceEgressStateContext<Ipv6> for CoreCtx<'_, BC, L>
413{
414 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
415 cb(&())
416 }
417
418 fn get_local_addr_for_remote(
419 &mut self,
420 device_id: &Self::DeviceId,
421 remote: Option<SpecifiedAddr<Ipv6Addr>>,
422 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
423 ip::IpSasHandler::<Ipv6, _>::get_local_addr_for_remote(self, device_id, remote)
424 }
425
426 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8 {
427 get_ipv6_hop_limit(self, device_id)
428 }
429}
430
431impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv6>>>
432 IpDeviceIngressStateContext<Ipv6> for CoreCtx<'_, BC, L>
433{
434 fn address_status_for_device(
435 &mut self,
436 addr: SpecifiedAddr<Ipv6Addr>,
437 device_id: &Self::DeviceId,
438 ) -> AddressStatus<<Ipv6 as IpLayerIpExt>::AddressStatus> {
439 AddressStatus::from_context_addr_v6(self, device_id, addr)
440 }
441}
442
443impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>>
444 ip::IpDeviceContext<Ipv6> for CoreCtx<'_, BC, L>
445{
446 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
447 is_ip_device_enabled::<Ipv6, _, _>(self, device_id)
448 }
449
450 type DeviceAndAddressStatusIter<'a> = FilterPresentWithDevices<
451 Ipv6,
452 <Self as device::IpDeviceConfigurationContext<Ipv6, BC>>::DevicesIter<'a>,
453 <Self as device::IpDeviceConfigurationContext<Ipv6, BC>>::DeviceAddressAndGroupsAccessor<
454 'a,
455 >,
456 BC,
457 >;
458
459 fn with_address_statuses<F: FnOnce(Self::DeviceAndAddressStatusIter<'_>) -> R, R>(
460 &mut self,
461 addr: SpecifiedAddr<Ipv6Addr>,
462 cb: F,
463 ) -> R {
464 device::IpDeviceConfigurationContext::<Ipv6, _>::with_devices_and_state(
465 self,
466 |devices, state| {
467 cb(FilterPresentWithDevices::new(
468 devices,
469 state,
470 AddressStatus::from_context_addr_v6,
471 addr,
472 ))
473 },
474 )
475 }
476
477 fn is_device_unicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
478 is_ip_unicast_forwarding_enabled::<Ipv6, _, _>(self, device_id)
479 }
480}
481
482#[netstack3_macros::instantiate_ip_impl_block(I)]
483impl<I: IpExt, BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<I>>>
484 ip::IpDeviceConfirmReachableContext<I, BC> for CoreCtx<'_, BC, L>
485{
486 fn confirm_reachable(
487 &mut self,
488 bindings_ctx: &mut BC,
489 device: &Self::DeviceId,
490 neighbor: SpecifiedAddr<<I as Ip>::Addr>,
491 ) {
492 match device {
493 DeviceId::Ethernet(id) => {
494 nud::confirm_reachable::<I, _, _, _>(self, bindings_ctx, id, neighbor)
495 }
496 DeviceId::Loopback(_) | DeviceId::PureIp(_) | DeviceId::Blackhole(_) => {}
498 }
499 }
500}
501
502impl<I: IpExt, BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>>
503 ip::IpDeviceMtuContext<I> for CoreCtx<'_, BC, L>
504{
505 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu {
506 crate::device::integration::get_mtu(self, device_id)
507 }
508}
509
510#[netstack3_macros::instantiate_ip_impl_block(I)]
511impl<I: IpExt, BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<I>>>
512 ip::multicast_forwarding::MulticastForwardingDeviceContext<I> for CoreCtx<'_, BC, L>
513{
514 fn is_device_multicast_forwarding_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
515 is_ip_multicast_forwarding_enabled::<I, _, _>(self, device_id)
516 }
517}
518
519pub struct CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC: BindingsContext> {
520 pub config: Config,
521 pub core_ctx: CoreCtx<'a, BC, L>,
522}
523
524impl<'a, Config, L, BC: BindingsContext, T> CounterContext<T>
525 for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
526where
527 CoreCtx<'a, BC, L>: CounterContext<T>,
528{
529 fn counters(&self) -> &T {
530 self.core_ctx.counters()
531 }
532}
533
534impl<'a, Config, L, BC: BindingsContext, R, T> ResourceCounterContext<R, T>
535 for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
536where
537 CoreCtx<'a, BC, L>: ResourceCounterContext<R, T>,
538{
539 fn per_resource_counters<'b>(&'b self, resource: &'b R) -> &'b T {
540 self.core_ctx.per_resource_counters(resource)
541 }
542}
543
544impl<'a, Config, L, BC: BindingsContext, T> CoreTimerContext<T, BC>
545 for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
546where
547 CoreCtx<'a, BC, L>: CoreTimerContext<T, BC>,
548{
549 fn convert_timer(dispatch_id: T) -> BC::DispatchId {
550 <CoreCtx<'a, BC, L> as CoreTimerContext<T, BC>>::convert_timer(dispatch_id)
551 }
552}
553
554#[netstack3_macros::instantiate_ip_impl_block(I)]
555impl<'a, I: gmp::IpExt + IpDeviceIpExt, BC: BindingsContext>
556 device::WithIpDeviceConfigurationMutInner<I, BC>
557 for CoreCtxWithIpDeviceConfiguration<
558 'a,
559 &mut <I as IpDeviceIpExt>::Configuration,
560 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<I>>,
561 BC,
562 >
563{
564 type IpDeviceStateCtx<'s>
565 = CoreCtxWithIpDeviceConfiguration<
566 's,
567 &'s <I as IpDeviceIpExt>::Configuration,
568 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<I>>,
569 BC,
570 >
571 where
572 Self: 's;
573
574 fn ip_device_configuration_and_ctx(
575 &mut self,
576 ) -> (&<I as IpDeviceIpExt>::Configuration, Self::IpDeviceStateCtx<'_>) {
577 let Self { config, core_ctx } = self;
578 let config = &**config;
579 (config, CoreCtxWithIpDeviceConfiguration { config, core_ctx: core_ctx.as_owned() })
580 }
581
582 fn with_configuration_and_flags_mut<
583 O,
584 F: FnOnce(&mut <I as IpDeviceIpExt>::Configuration, &mut IpDeviceFlags) -> O,
585 >(
586 &mut self,
587 device_id: &Self::DeviceId,
588 cb: F,
589 ) -> O {
590 let Self { config, core_ctx } = self;
591 let mut state = crate::device::integration::ip_device_state(core_ctx, device_id);
592 let mut flags = state.lock::<crate::lock_ordering::IpDeviceFlags<I>>();
593 cb(*config, &mut *flags)
594 }
595}
596
597impl<'a, BC: BindingsContext> device::WithIpv6DeviceConfigurationMutInner<BC>
598 for CoreCtxWithIpDeviceConfiguration<
599 'a,
600 &mut Ipv6DeviceConfiguration,
601 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
602 BC,
603 >
604{
605 type Ipv6DeviceStateCtx<'s>
606 = CoreCtxWithIpDeviceConfiguration<
607 's,
608 &'s Ipv6DeviceConfiguration,
609 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
610 BC,
611 >
612 where
613 Self: 's;
614
615 fn ipv6_device_configuration_and_ctx(
616 &mut self,
617 ) -> (&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) {
618 let Self { config, core_ctx } = self;
619 let config = &**config;
620 (config, CoreCtxWithIpDeviceConfiguration { config, core_ctx: core_ctx.as_owned() })
621 }
622}
623
624impl<'a, Config, BC: BindingsContext, L> DeviceIdContext<AnyDevice>
625 for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
626{
627 type DeviceId = <CoreCtx<'a, BC, L> as DeviceIdContext<AnyDevice>>::DeviceId;
628 type WeakDeviceId = <CoreCtx<'a, BC, L> as DeviceIdContext<AnyDevice>>::WeakDeviceId;
629}
630
631impl<'a, Config: Borrow<Ipv6DeviceConfiguration>, BC: BindingsContext> SlaacContext<BC>
632 for CoreCtxWithIpDeviceConfiguration<
633 'a,
634 Config,
635 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
636 BC,
637 >
638{
639 type LinkLayerAddr = <Self as device::Ipv6DeviceContext<BC>>::LinkLayerAddr;
640
641 type SlaacAddrs<'s> = SlaacAddrs<'s, BC>;
642
643 fn with_slaac_addrs_mut_and_configs<
644 O,
645 F: FnOnce(
646 &mut Self::SlaacAddrs<'_>,
647 SlaacConfigAndState<Self::LinkLayerAddr, BC>,
648 &mut SlaacState<BC>,
649 ) -> O,
650 >(
651 &mut self,
652 device_id: &Self::DeviceId,
653 cb: F,
654 ) -> O {
655 let Self { config, core_ctx } = self;
656 let retrans_timer = get_retrans_timer(core_ctx, device_id).get();
657 let link_layer_addr = device::Ipv6DeviceContext::get_link_layer_addr(core_ctx, device_id);
663
664 let config = Borrow::borrow(config);
665 let Ipv6DeviceConfiguration {
666 max_router_solicitations: _,
667 slaac_config,
668 route_discovery_config: _,
669 ip_config:
670 IpDeviceConfiguration {
671 unicast_forwarding_enabled: _,
672 multicast_forwarding_enabled: _,
673 gmp_enabled: _,
674 dad_transmits,
675 },
676 } = *config;
677
678 let ipv6_state = &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().ipv6;
679 let stable_secret_key = ipv6_state.slaac_stable_secret_key;
680 let temp_secret_key = ipv6_state.slaac_temp_secret_key;
681 let mut core_ctx_and_resource =
682 crate::device::integration::ip_device_state_and_core_ctx(core_ctx, device_id);
683 let (mut state, mut locked) = core_ctx_and_resource
684 .lock_with_and::<crate::lock_ordering::Ipv6DeviceSlaac, _>(|x| x.right());
685 let core_ctx =
686 CoreCtxWithIpDeviceConfiguration { config, core_ctx: locked.cast_core_ctx() };
687
688 let mut addrs = SlaacAddrs { core_ctx, device_id: device_id.clone(), config };
689
690 cb(
691 &mut addrs,
692 SlaacConfigAndState {
693 config: slaac_config,
694 dad_transmits,
695 retrans_timer,
696 link_layer_addr,
697 temp_secret_key,
698 stable_secret_key,
699 _marker: PhantomData,
700 },
701 &mut state,
702 )
703 }
704}
705
706fn into_arp_compatible_device<BT: BindingsTypes>(
708 device_id: &DeviceId<BT>,
709) -> Option<&EthernetDeviceId<BT>> {
710 match device_id {
711 DeviceId::Loopback(_) | DeviceId::PureIp(_) | DeviceId::Blackhole(_) => None,
712 DeviceId::Ethernet(id) => Some(id),
716 }
717}
718
719impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddressData<Ipv4>>>
720 DadAddressContext<Ipv4, BC>
721 for CoreCtxWithIpDeviceConfiguration<'_, &'_ Ipv4DeviceConfiguration, L, BC>
722{
723 fn with_address_assigned<O, F: FnOnce(&mut bool) -> O>(
724 &mut self,
725 _: &Self::DeviceId,
726 addr: &Self::AddressId,
727 cb: F,
728 ) -> O {
729 let mut locked = self.core_ctx.adopt(addr.deref());
730 let mut state = locked
731 .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv4>, _>(|c| c.right());
732 let IpAddressData { flags: IpAddressFlags { assigned }, config: _ } = &mut *state;
733
734 cb(assigned)
735 }
736
737 fn should_perform_dad(&mut self, device: &Self::DeviceId, addr: &Self::AddressId) -> bool {
738 if into_arp_compatible_device(device).is_none() {
741 return false;
742 }
743
744 let mut locked = self.core_ctx.adopt(addr.deref());
745 let state = locked
746 .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv4>, _>(|c| c.right());
747 state.should_perform_dad()
748 }
749}
750
751impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddressData<Ipv6>>>
752 DadAddressContext<Ipv6, BC>
753 for CoreCtxWithIpDeviceConfiguration<'_, &'_ Ipv6DeviceConfiguration, L, BC>
754{
755 fn with_address_assigned<O, F: FnOnce(&mut bool) -> O>(
756 &mut self,
757 _: &Self::DeviceId,
758 addr: &Self::AddressId,
759 cb: F,
760 ) -> O {
761 let mut locked = self.core_ctx.adopt(addr.deref());
762 let mut state = locked
763 .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv6>, _>(|c| c.right());
764 let IpAddressData { flags: IpAddressFlags { assigned }, config: _ } = &mut *state;
765
766 cb(assigned)
767 }
768
769 fn should_perform_dad(&mut self, _: &Self::DeviceId, addr: &Self::AddressId) -> bool {
770 let mut locked = self.core_ctx.adopt(addr.deref());
771 let state = locked
772 .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<Ipv6>, _>(|c| c.right());
773 state.should_perform_dad()
774 }
775}
776
777impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv6>>>
778 Ipv6DadAddressContext<BC>
779 for CoreCtxWithIpDeviceConfiguration<'_, &'_ Ipv6DeviceConfiguration, L, BC>
780{
781 fn join_multicast_group(
782 &mut self,
783 bindings_ctx: &mut BC,
784 device_id: &Self::DeviceId,
785 multicast_addr: MulticastAddr<Ipv6Addr>,
786 ) {
787 let Self { config, core_ctx } = self;
788 let config = Borrow::borrow(&*config);
789 join_ip_multicast_with_config(
790 &mut CoreCtxWithIpDeviceConfiguration { config, core_ctx: core_ctx.as_owned() },
791 bindings_ctx,
792 device_id,
793 multicast_addr,
794 config,
795 )
796 }
797
798 fn leave_multicast_group(
799 &mut self,
800 bindings_ctx: &mut BC,
801 device_id: &Self::DeviceId,
802 multicast_addr: MulticastAddr<Ipv6Addr>,
803 ) {
804 let Self { config, core_ctx } = self;
805 let config = Borrow::borrow(&*config);
806 leave_ip_multicast_with_config(
807 &mut CoreCtxWithIpDeviceConfiguration { config, core_ctx: core_ctx.as_owned() },
808 bindings_ctx,
809 device_id,
810 multicast_addr,
811 config,
812 )
813 }
814}
815
816impl<
817 'a,
818 Config: Borrow<Ipv4DeviceConfiguration>,
819 BC: BindingsContext,
820 L: LockBefore<crate::lock_ordering::IpDeviceAddressDad<Ipv4>>,
821> DadContext<Ipv4, BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
822{
823 type DadAddressCtx<'b> = CoreCtxWithIpDeviceConfiguration<
824 'b,
825 &'b Ipv4DeviceConfiguration,
826 WrapLockLevel<crate::lock_ordering::IpDeviceAddressDad<Ipv4>>,
827 BC,
828 >;
829
830 fn with_dad_state<O, F: FnOnce(DadStateRef<'_, Ipv4, Self::DadAddressCtx<'_>, BC>) -> O>(
831 &mut self,
832 _device_id: &Self::DeviceId,
833 addr: &Self::AddressId,
834 cb: F,
835 ) -> O {
836 let Self { config, core_ctx } = self;
837 let mut core_ctx = core_ctx.adopt(addr.deref());
838 let config = Borrow::borrow(&*config);
839
840 let (mut dad_state, mut locked) = core_ctx
841 .lock_with_and::<crate::lock_ordering::IpDeviceAddressDad<Ipv4>, _>(|c| c.right());
842 let mut core_ctx =
843 CoreCtxWithIpDeviceConfiguration { config, core_ctx: locked.cast_core_ctx() };
844
845 cb(DadStateRef {
846 state: DadAddressStateRef { dad_state: dad_state.deref_mut(), core_ctx: &mut core_ctx },
847 retrans_timer_data: &(),
854 max_dad_transmits: &config.ip_config.dad_transmits,
855 })
856 }
857
858 fn send_dad_probe(
859 &mut self,
860 bindings_ctx: &mut BC,
861 device_id: &Self::DeviceId,
862 data: Ipv4DadSendData,
863 ) {
864 let device_id = into_arp_compatible_device(device_id).unwrap_or_else(|| {
868 panic!("shouldn't run IPv4 DAD on devices that don't support ARP. dev={device_id:?}")
869 });
870
871 let target_link_addr = None;
884
885 let (sender_ip, target_ip) = data.into_sender_and_target_addr();
886
887 let Self { config: _, core_ctx } = self;
888 netstack3_device::send_arp_request(
889 core_ctx,
890 bindings_ctx,
891 device_id,
892 sender_ip,
893 target_ip,
894 target_link_addr,
895 )
896 }
897}
898
899fn get_retrans_timer<
900 'a,
901 BC: BindingsContext,
902 L: LockBefore<crate::lock_ordering::IpDeviceAddresses<Ipv6>>,
903>(
904 core_ctx: &mut CoreCtx<'a, BC, L>,
905 device_id: &DeviceId<BC>,
906) -> NonZeroDuration {
907 device::Ipv6DeviceContext::<BC>::with_network_learned_parameters(core_ctx, device_id, |p| {
908 p.retrans_timer()
909 })
910 .unwrap_or_else(|| match device_id {
911 DeviceId::Ethernet(base_device_id) => {
912 crate::device::integration::device_state(core_ctx, base_device_id)
913 .read_lock::<crate::lock_ordering::NudConfig<Ipv6>>()
914 .retrans_timer
915 }
916 DeviceId::Loopback(_) | DeviceId::PureIp(_) | DeviceId::Blackhole(_) => {
917 nud::DEFAULT_RETRANS_TIMER
918 }
919 })
920}
921
922impl<
923 'a,
924 Config: Borrow<Ipv6DeviceConfiguration>,
925 BC: BindingsContext,
926 L: LockBefore<crate::lock_ordering::IpDeviceAddressDad<Ipv6>>,
927> DadContext<Ipv6, BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
928{
929 type DadAddressCtx<'b> = CoreCtxWithIpDeviceConfiguration<
930 'b,
931 &'b Ipv6DeviceConfiguration,
932 WrapLockLevel<crate::lock_ordering::IpDeviceAddressDad<Ipv6>>,
933 BC,
934 >;
935
936 fn with_dad_state<O, F: FnOnce(DadStateRef<'_, Ipv6, Self::DadAddressCtx<'_>, BC>) -> O>(
937 &mut self,
938 device_id: &Self::DeviceId,
939 addr: &Self::AddressId,
940 cb: F,
941 ) -> O {
942 let Self { config, core_ctx } = self;
943 let retrans_timer = get_retrans_timer(core_ctx, device_id);
944
945 let mut core_ctx = core_ctx.adopt(addr.deref());
946 let config = Borrow::borrow(&*config);
947
948 let (mut dad_state, mut locked) = core_ctx
949 .lock_with_and::<crate::lock_ordering::IpDeviceAddressDad<Ipv6>, _>(|c| c.right());
950 let mut core_ctx =
951 CoreCtxWithIpDeviceConfiguration { config, core_ctx: locked.cast_core_ctx() };
952
953 cb(DadStateRef {
954 state: DadAddressStateRef { dad_state: dad_state.deref_mut(), core_ctx: &mut core_ctx },
955 retrans_timer_data: &retrans_timer,
956 max_dad_transmits: &config.ip_config.dad_transmits,
957 })
958 }
959 fn send_dad_probe(
964 &mut self,
965 bindings_ctx: &mut BC,
966 device_id: &Self::DeviceId,
967 Ipv6DadSendData { dst_ip, message, nonce }: Ipv6DadSendData,
968 ) {
969 let src_ip = None;
985 let options = [NdpOptionBuilder::Nonce(NdpNonce::from(&nonce))];
986
987 let result = ip::icmp::send_ndp_packet(
988 self,
989 bindings_ctx,
990 device_id,
991 src_ip,
992 dst_ip.into_specified(),
993 OptionSequenceBuilder::new(options.iter()).into_serializer(),
994 ip::icmp::NdpMessage::NeighborSolicitation { message, code: IcmpZeroCode },
995 );
996 match result {
997 Ok(()) => {}
998 Err(IpSendFrameError { serializer: _, error }) => {
999 debug!("error sending DAD packet: {error:?}")
1002 }
1003 }
1004 }
1005}
1006
1007impl<'a, Config: Borrow<Ipv6DeviceConfiguration>, BC: BindingsContext> RsContext<BC>
1008 for CoreCtxWithIpDeviceConfiguration<
1009 'a,
1010 Config,
1011 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
1012 BC,
1013 >
1014{
1015 type LinkLayerAddr = <CoreCtx<
1016 'a,
1017 BC,
1018 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
1019 > as device::Ipv6DeviceContext<BC>>::LinkLayerAddr;
1020
1021 fn with_rs_state_mut_and_max<O, F: FnOnce(&mut RsState<BC>, Option<NonZeroU8>) -> O>(
1022 &mut self,
1023 device_id: &Self::DeviceId,
1024 cb: F,
1025 ) -> O {
1026 let Self { config, core_ctx } = self;
1027 let mut state = crate::device::integration::ip_device_state(core_ctx, device_id);
1028 let mut state = state.lock::<crate::lock_ordering::Ipv6DeviceRouterSolicitations>();
1029 cb(&mut state, Borrow::borrow(&*config).max_router_solicitations)
1030 }
1031
1032 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr> {
1033 let Self { config: _, core_ctx } = self;
1034 device::Ipv6DeviceContext::get_link_layer_addr(core_ctx, device_id)
1035 }
1036
1037 fn send_rs_packet<
1038 S: NetworkSerializer<Buffer = EmptyBuf> + NetworkPartialSerializer,
1039 F: FnOnce(Option<UnicastAddr<Ipv6Addr>>) -> S,
1040 >(
1041 &mut self,
1042 bindings_ctx: &mut BC,
1043 device_id: &Self::DeviceId,
1044 message: RouterSolicitation,
1045 body: F,
1046 ) -> Result<(), IpSendFrameError<S>> {
1047 let Self { config: _, core_ctx } = self;
1048
1049 let dst_ip = Ipv6::ALL_ROUTERS_LINK_LOCAL_MULTICAST_ADDRESS.into_specified();
1050 let src_ip = ip::IpSasHandler::<Ipv6, _>::get_local_addr_for_remote(
1051 core_ctx,
1052 device_id,
1053 Some(dst_ip),
1054 )
1055 .and_then(|addr| UnicastAddr::new(addr.addr()));
1056 ip::icmp::send_ndp_packet(
1057 core_ctx,
1058 bindings_ctx,
1059 device_id,
1060 src_ip.map(UnicastAddr::into_specified),
1061 dst_ip,
1062 body(src_ip),
1063 ip::icmp::NdpMessage::RouterSolicitation { message, code: IcmpZeroCode },
1064 )
1065 }
1066}
1067
1068impl<
1069 I: IpExt,
1070 Config,
1071 BC: BindingsContext,
1072 L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>,
1073> ip::IpDeviceMtuContext<I> for CoreCtxWithIpDeviceConfiguration<'_, Config, L, BC>
1074{
1075 fn get_mtu(&mut self, device_id: &Self::DeviceId) -> Mtu {
1076 ip::IpDeviceMtuContext::<I>::get_mtu(&mut self.core_ctx, device_id)
1077 }
1078}
1079
1080impl<L, BT: BindingsTypes> CoreTimerContext<RsTimerId<WeakDeviceId<BT>>, BT>
1081 for CoreCtx<'_, BT, L>
1082{
1083 fn convert_timer(dispatch_id: RsTimerId<WeakDeviceId<BT>>) -> BT::DispatchId {
1084 IpDeviceTimerId::<Ipv6, _, _>::from(Ipv6DeviceTimerId::from(dispatch_id)).into()
1085 }
1086}
1087
1088impl<BC: BindingsContext> Ipv6DiscoveredRoutesContext<BC>
1089 for CoreCtx<'_, BC, WrapLockLevel<crate::lock_ordering::Ipv6DeviceRouteDiscovery>>
1090{
1091 fn add_discovered_ipv6_route(
1092 &mut self,
1093 bindings_ctx: &mut BC,
1094 device_id: &Self::DeviceId,
1095 Ipv6DiscoveredRoute { subnet, gateway }: Ipv6DiscoveredRoute,
1096 Ipv6DiscoveredRouteProperties { route_preference }: Ipv6DiscoveredRouteProperties,
1097 ) {
1098 let device_id = device_id.clone();
1099 let entry = ip::AddableEntry {
1100 subnet,
1101 device: device_id,
1102 gateway: gateway.map(|g| (*g).into_specified()),
1103 metric: AddableMetric::MetricTracksInterface,
1104 route_preference,
1105 };
1106
1107 ip::request_context_add_route::<Ipv6, _, _>(bindings_ctx, entry);
1108 }
1109
1110 fn del_discovered_ipv6_route(
1111 &mut self,
1112 bindings_ctx: &mut BC,
1113 device_id: &Self::DeviceId,
1114 Ipv6DiscoveredRoute { subnet, gateway }: Ipv6DiscoveredRoute,
1115 ) {
1116 ip::request_context_del_routes::<Ipv6, _, _>(
1117 bindings_ctx,
1118 subnet,
1119 device_id.clone(),
1120 gateway.map(|g| (*g).into_specified()),
1121 );
1122 }
1123}
1124
1125impl<'a, Config, BC: BindingsContext> Ipv6RouteDiscoveryContext<BC>
1126 for CoreCtxWithIpDeviceConfiguration<
1127 'a,
1128 Config,
1129 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
1130 BC,
1131 >
1132{
1133 type WithDiscoveredRoutesMutCtx<'b> =
1134 CoreCtx<'b, BC, WrapLockLevel<crate::lock_ordering::Ipv6DeviceRouteDiscovery>>;
1135
1136 fn with_discovered_routes_mut<
1137 O,
1138 F: FnOnce(&mut Ipv6RouteDiscoveryState<BC>, &mut Self::WithDiscoveredRoutesMutCtx<'_>) -> O,
1139 >(
1140 &mut self,
1141 device_id: &Self::DeviceId,
1142 cb: F,
1143 ) -> O {
1144 let Self { config: _, core_ctx } = self;
1145 let mut core_ctx_and_resource =
1146 crate::device::integration::ip_device_state_and_core_ctx(core_ctx, device_id);
1147
1148 let (mut state, mut locked) =
1149 core_ctx_and_resource
1150 .lock_with_and::<crate::lock_ordering::Ipv6DeviceRouteDiscovery, _>(|x| x.right());
1151 cb(&mut state, &mut locked.cast_core_ctx())
1152 }
1153}
1154
1155impl<'a, Config, BC: BindingsContext> device::Ipv6DeviceContext<BC>
1156 for CoreCtxWithIpDeviceConfiguration<
1157 'a,
1158 Config,
1159 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
1160 BC,
1161 >
1162{
1163 type LinkLayerAddr = <CoreCtx<
1164 'a,
1165 BC,
1166 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
1167 > as device::Ipv6DeviceContext<BC>>::LinkLayerAddr;
1168
1169 fn get_link_layer_addr(&mut self, device_id: &Self::DeviceId) -> Option<Self::LinkLayerAddr> {
1170 let Self { config: _, core_ctx } = self;
1171 device::Ipv6DeviceContext::get_link_layer_addr(core_ctx, device_id)
1172 }
1173
1174 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
1175 let Self { config: _, core_ctx } = self;
1176 device::Ipv6DeviceContext::set_link_mtu(core_ctx, device_id, mtu)
1177 }
1178
1179 fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
1180 &mut self,
1181 device_id: &Self::DeviceId,
1182 cb: F,
1183 ) -> O {
1184 let Self { config: _, core_ctx } = self;
1185 device::Ipv6DeviceContext::with_network_learned_parameters(core_ctx, device_id, cb)
1186 }
1187
1188 fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
1189 &mut self,
1190 device_id: &Self::DeviceId,
1191 cb: F,
1192 ) -> O {
1193 let Self { config: _, core_ctx } = self;
1194 device::Ipv6DeviceContext::with_network_learned_parameters_mut(core_ctx, device_id, cb)
1195 }
1196}
1197
1198impl<'a, Config, I: IpDeviceIpExt, L, BC: BindingsContext> IpDeviceAddressIdContext<I>
1199 for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1200where
1201 CoreCtx<'a, BC, L>: IpDeviceAddressIdContext<I>,
1202{
1203 type AddressId = <CoreCtx<'a, BC, L> as IpDeviceAddressIdContext<I>>::AddressId;
1204 type WeakAddressId = <CoreCtx<'a, BC, L> as IpDeviceAddressIdContext<I>>::WeakAddressId;
1205}
1206
1207impl<'a, Config, I: IpDeviceIpExt, BC: BindingsContext, L> device::IpDeviceAddressContext<I, BC>
1208 for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1209where
1210 CoreCtx<'a, BC, L>: device::IpDeviceAddressContext<I, BC>,
1211{
1212 fn with_ip_address_data<O, F: FnOnce(&IpAddressData<I, BC::Instant>) -> O>(
1213 &mut self,
1214 device_id: &Self::DeviceId,
1215 addr_id: &Self::AddressId,
1216 cb: F,
1217 ) -> O {
1218 let Self { config: _, core_ctx } = self;
1219 device::IpDeviceAddressContext::<I, BC>::with_ip_address_data(
1220 core_ctx, device_id, addr_id, cb,
1221 )
1222 }
1223
1224 fn with_ip_address_data_mut<O, F: FnOnce(&mut IpAddressData<I, BC::Instant>) -> O>(
1225 &mut self,
1226 device_id: &Self::DeviceId,
1227 addr_id: &Self::AddressId,
1228 cb: F,
1229 ) -> O {
1230 let Self { config: _, core_ctx } = self;
1231 device::IpDeviceAddressContext::<I, BC>::with_ip_address_data_mut(
1232 core_ctx, device_id, addr_id, cb,
1233 )
1234 }
1235}
1236
1237impl<'a, Config, I: IpDeviceIpExt, BC: BindingsContext, L> device::IpDeviceAddAddressContext<I, BC>
1238 for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1239where
1240 CoreCtx<'a, BC, L>: device::IpDeviceAddAddressContext<I, BC>,
1241{
1242 fn add_ip_address(
1243 &mut self,
1244 device_id: &Self::DeviceId,
1245 addr: AddrSubnet<I::Addr, I::AssignedWitness>,
1246 config: I::AddressConfig<BC::Instant>,
1247 ) -> Result<Self::AddressId, ExistsError> {
1248 let Self { config: _, core_ctx } = self;
1249 device::IpDeviceAddAddressContext::<I, BC>::add_ip_address(
1250 core_ctx, device_id, addr, config,
1251 )
1252 }
1253}
1254
1255impl<'a, Config, I: IpDeviceIpExt, BC: BindingsContext, L> device::IpDeviceStateContext<I, BC>
1256 for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1257where
1258 CoreCtx<'a, BC, L>: device::IpDeviceStateContext<I, BC>,
1259{
1260 type IpDeviceAddressCtx<'b> =
1261 <CoreCtx<'a, BC, L> as device::IpDeviceStateContext<I, BC>>::IpDeviceAddressCtx<'b>;
1262
1263 fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
1264 &mut self,
1265 device_id: &Self::DeviceId,
1266 cb: F,
1267 ) -> O {
1268 let Self { config: _, core_ctx } = self;
1269 device::IpDeviceStateContext::<I, BC>::with_ip_device_flags(core_ctx, device_id, cb)
1270 }
1271
1272 fn remove_ip_address(
1273 &mut self,
1274 device_id: &Self::DeviceId,
1275 addr: Self::AddressId,
1276 ) -> RemoveResourceResultWithContext<AddrSubnet<I::Addr>, BC> {
1277 let Self { config: _, core_ctx } = self;
1278 device::IpDeviceStateContext::<I, BC>::remove_ip_address(core_ctx, device_id, addr)
1279 }
1280
1281 fn get_address_id(
1282 &mut self,
1283 device_id: &Self::DeviceId,
1284 addr: SpecifiedAddr<I::Addr>,
1285 ) -> Result<Self::AddressId, NotFoundError> {
1286 let Self { config: _, core_ctx } = self;
1287 device::IpDeviceStateContext::<I, BC>::get_address_id(core_ctx, device_id, addr)
1288 }
1289
1290 type AddressIdsIter<'b> =
1291 <CoreCtx<'a, BC, L> as device::IpDeviceStateContext<I, BC>>::AddressIdsIter<'b>;
1292 fn with_address_ids<
1293 O,
1294 F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
1295 >(
1296 &mut self,
1297 device_id: &Self::DeviceId,
1298 cb: F,
1299 ) -> O {
1300 let Self { config: _, core_ctx } = self;
1301 device::IpDeviceStateContext::<I, BC>::with_address_ids(core_ctx, device_id, cb)
1302 }
1303
1304 fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
1305 &mut self,
1306 device_id: &Self::DeviceId,
1307 cb: F,
1308 ) -> O {
1309 let Self { config: _, core_ctx } = self;
1310 device::IpDeviceStateContext::<I, BC>::with_default_hop_limit(core_ctx, device_id, cb)
1311 }
1312
1313 fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
1314 &mut self,
1315 device_id: &Self::DeviceId,
1316 cb: F,
1317 ) -> O {
1318 let Self { config: _, core_ctx } = self;
1319 device::IpDeviceStateContext::<I, BC>::with_default_hop_limit_mut(core_ctx, device_id, cb)
1320 }
1321
1322 fn join_link_multicast_group(
1323 &mut self,
1324 bindings_ctx: &mut BC,
1325 device_id: &Self::DeviceId,
1326 multicast_addr: MulticastAddr<I::Addr>,
1327 ) {
1328 let Self { config: _, core_ctx } = self;
1329 device::IpDeviceStateContext::<I, BC>::join_link_multicast_group(
1330 core_ctx,
1331 bindings_ctx,
1332 device_id,
1333 multicast_addr,
1334 )
1335 }
1336
1337 fn leave_link_multicast_group(
1338 &mut self,
1339 bindings_ctx: &mut BC,
1340 device_id: &Self::DeviceId,
1341 multicast_addr: MulticastAddr<I::Addr>,
1342 ) {
1343 let Self { config: _, core_ctx } = self;
1344 device::IpDeviceStateContext::<I, BC>::leave_link_multicast_group(
1345 core_ctx,
1346 bindings_ctx,
1347 device_id,
1348 multicast_addr,
1349 )
1350 }
1351}
1352
1353impl<BC: BindingsContext, Config, L> IgmpContextMarker
1354 for CoreCtxWithIpDeviceConfiguration<'_, Config, L, BC>
1355{
1356}
1357
1358impl<'a, Config: Borrow<Ipv4DeviceConfiguration>, BC: BindingsContext> IgmpContext<BC>
1359 for CoreCtxWithIpDeviceConfiguration<
1360 'a,
1361 Config,
1362 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>,
1363 BC,
1364 >
1365{
1366 type SendContext<'b> = CoreCtx<'b, BC, WrapLockLevel<crate::lock_ordering::IpDeviceGmp<Ipv4>>>;
1367
1368 fn with_igmp_state_mut<
1371 O,
1372 F: for<'b> FnOnce(Self::SendContext<'b>, GmpStateRef<'b, Ipv4, IgmpTypeLayout, BC>) -> O,
1373 >(
1374 &mut self,
1375 device: &Self::DeviceId,
1376 cb: F,
1377 ) -> O {
1378 let Self { config, core_ctx } = self;
1379 let Ipv4DeviceConfiguration { ip_config: IpDeviceConfiguration { gmp_enabled, .. } } =
1380 Borrow::borrow(&*config);
1381
1382 let mut state = crate::device::integration::ip_device_state_and_core_ctx(core_ctx, device);
1383 let ip_enabled = state
1389 .lock_with::<crate::lock_ordering::IpDeviceFlags<Ipv4>, _>(|x| x.right())
1390 .ip_enabled;
1391 let (mut state, mut locked) =
1392 state.write_lock_with_and::<crate::lock_ordering::IpDeviceGmp<Ipv4>, _>(|x| x.right());
1393 let IpDeviceMulticastGroups { groups, gmp, gmp_config } = &mut *state;
1394 let enabled = ip_enabled && *gmp_enabled;
1395 cb(locked.cast_core_ctx(), GmpStateRef { enabled, groups, gmp, config: gmp_config })
1396 }
1397}
1398
1399impl<'a, BC: BindingsContext> IgmpSendContext<BC>
1400 for CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpDeviceGmp<Ipv4>>>
1401{
1402 fn get_ip_addr_subnet(
1403 &mut self,
1404 device: &Self::DeviceId,
1405 ) -> Option<AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>> {
1406 ip::device::get_ipv4_addr_subnet(self, device)
1407 }
1408}
1409
1410impl<BC: BindingsContext, Config, L> MldContextMarker
1411 for CoreCtxWithIpDeviceConfiguration<'_, Config, L, BC>
1412{
1413}
1414
1415impl<
1416 'a,
1417 Config: Borrow<Ipv6DeviceConfiguration>,
1418 BC: BindingsContext,
1419 L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv6>>,
1420> MldContext<BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1421{
1422 type SendContext<'b> = CoreCtx<'b, BC, WrapLockLevel<crate::lock_ordering::IpDeviceGmp<Ipv6>>>;
1423
1424 fn with_mld_state_mut<
1425 O,
1426 F: FnOnce(Self::SendContext<'_>, GmpStateRef<'_, Ipv6, MldTypeLayout, BC>) -> O,
1427 >(
1428 &mut self,
1429 device: &Self::DeviceId,
1430 cb: F,
1431 ) -> O {
1432 let Self { config, core_ctx } = self;
1433 let Ipv6DeviceConfiguration {
1434 max_router_solicitations: _,
1435 slaac_config: _,
1436 route_discovery_config: _,
1437 ip_config: IpDeviceConfiguration { gmp_enabled, .. },
1438 } = Borrow::borrow(&*config);
1439
1440 let mut state = crate::device::integration::ip_device_state_and_core_ctx(core_ctx, device);
1441 let ip_enabled = state
1442 .lock_with::<crate::lock_ordering::IpDeviceFlags<Ipv6>, _>(|x| x.right())
1443 .ip_enabled;
1444 let (mut state, mut locked) =
1445 state.write_lock_with_and::<crate::lock_ordering::IpDeviceGmp<Ipv6>, _>(|x| x.right());
1446 let IpDeviceMulticastGroups { groups, gmp, gmp_config } = &mut *state;
1447 let enabled = ip_enabled && *gmp_enabled;
1448 cb(locked.cast_core_ctx(), GmpStateRef { enabled, groups, gmp, config: gmp_config })
1449 }
1450}
1451
1452impl<'a, BC: BindingsContext> MldSendContext<BC>
1453 for CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpDeviceGmp<Ipv6>>>
1454{
1455 fn get_ipv6_link_local_addr(
1456 &mut self,
1457 device: &Self::DeviceId,
1458 ) -> Option<LinkLocalUnicastAddr<Ipv6Addr>> {
1459 device::IpDeviceStateContext::<Ipv6, BC>::with_address_ids(
1460 self,
1461 device,
1462 |mut addrs, core_ctx| {
1463 addrs.find_map(|addr_id| {
1464 device::IpDeviceAddressContext::<Ipv6, _>::with_ip_address_data(
1465 core_ctx,
1466 device,
1467 &addr_id,
1468 |IpAddressData { flags: IpAddressFlags { assigned }, config: _ }| {
1469 if *assigned {
1470 LinkLocalUnicastAddr::new(addr_id.addr_sub().addr().get())
1471 } else {
1472 None
1473 }
1474 },
1475 )
1476 })
1477 },
1478 )
1479 }
1480}
1481
1482impl<'a, Config, I: IpDeviceIpExt, BC: BindingsContext, L> NudIpHandler<I, BC>
1483 for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1484where
1485 CoreCtx<'a, BC, L>: NudIpHandler<I, BC>,
1486{
1487 fn handle_neighbor_probe(
1488 &mut self,
1489 bindings_ctx: &mut BC,
1490 device_id: &Self::DeviceId,
1491 neighbor: SpecifiedAddr<I::Addr>,
1492 link_addr: &[u8],
1493 ) {
1494 let Self { config: _, core_ctx } = self;
1495 NudIpHandler::<I, BC>::handle_neighbor_probe(
1496 core_ctx,
1497 bindings_ctx,
1498 device_id,
1499 neighbor,
1500 link_addr,
1501 )
1502 }
1503
1504 fn handle_neighbor_confirmation(
1505 &mut self,
1506 bindings_ctx: &mut BC,
1507 device_id: &Self::DeviceId,
1508 neighbor: SpecifiedAddr<I::Addr>,
1509 link_addr: Option<&[u8]>,
1510 flags: ConfirmationFlags,
1511 ) {
1512 let Self { config: _, core_ctx } = self;
1513 NudIpHandler::<I, BC>::handle_neighbor_confirmation(
1514 core_ctx,
1515 bindings_ctx,
1516 device_id,
1517 neighbor,
1518 link_addr,
1519 flags,
1520 )
1521 }
1522
1523 fn flush_neighbor_table(&mut self, bindings_ctx: &mut BC, device_id: &Self::DeviceId) {
1524 let Self { config: _, core_ctx } = self;
1525 NudIpHandler::<I, BC>::flush_neighbor_table(core_ctx, bindings_ctx, device_id)
1526 }
1527}
1528
1529#[netstack3_macros::instantiate_ip_impl_block(I)]
1530impl<'a, I: IpExt, Config, BC: BindingsContext, L: LockBefore<crate::lock_ordering::FilterState<I>>>
1531 FilterHandlerProvider<I, BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1532{
1533 type Handler<'b>
1534 = FilterImpl<'b, CoreCtx<'a, BC, L>>
1535 where
1536 Self: 'b;
1537
1538 fn filter_handler(&mut self) -> Self::Handler<'_> {
1539 let Self { config: _, core_ctx } = self;
1540 FilterHandlerProvider::<I, BC>::filter_handler(core_ctx)
1541 }
1542}
1543
1544#[netstack3_macros::instantiate_ip_impl_block(I)]
1545impl<
1546 'a,
1547 I: IpLayerIpExt,
1548 Config,
1549 BC: BindingsContext,
1550 L: LockBefore<crate::lock_ordering::IpDeviceGmp<I>>,
1551> IpDeviceEgressStateContext<I> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1552{
1553 fn with_next_packet_id<O, F: FnOnce(&<I as IpLayerIpExt>::PacketIdState) -> O>(
1554 &self,
1555 cb: F,
1556 ) -> O {
1557 let Self { config: _, core_ctx } = self;
1558 IpDeviceEgressStateContext::<I>::with_next_packet_id(core_ctx, cb)
1559 }
1560
1561 fn get_local_addr_for_remote(
1562 &mut self,
1563 device_id: &Self::DeviceId,
1564 remote: Option<SpecifiedAddr<<I as Ip>::Addr>>,
1565 ) -> Option<IpDeviceAddr<<I as Ip>::Addr>> {
1566 let Self { config: _, core_ctx } = self;
1567 IpDeviceEgressStateContext::<I>::get_local_addr_for_remote(core_ctx, device_id, remote)
1568 }
1569
1570 fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8 {
1571 let Self { config: _, core_ctx } = self;
1572 IpDeviceEgressStateContext::<I>::get_hop_limit(core_ctx, device_id)
1573 }
1574}
1575
1576#[netstack3_macros::instantiate_ip_impl_block(I)]
1577impl<
1578 'a,
1579 I: IpLayerIpExt,
1580 Config,
1581 BC: BindingsContext,
1582 L: LockBefore<crate::lock_ordering::IpDeviceGmp<I>>,
1583> IpDeviceIngressStateContext<I> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
1584{
1585 fn address_status_for_device(
1586 &mut self,
1587 dst_ip: SpecifiedAddr<<I as Ip>::Addr>,
1588 device_id: &Self::DeviceId,
1589 ) -> AddressStatus<<I as IpLayerIpExt>::AddressStatus> {
1590 let Self { config: _, core_ctx } = self;
1591 IpDeviceIngressStateContext::<I>::address_status_for_device(core_ctx, dst_ip, device_id)
1592 }
1593}
1594
1595impl<BC: BindingsContext, I: Ip, L> CounterContext<NudCounters<I>> for CoreCtx<'_, BC, L> {
1596 fn counters(&self) -> &NudCounters<I> {
1597 self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.nud_counters::<I>()
1598 }
1599}
1600
1601impl<L, BT: BindingsTypes>
1602 CoreTimerContext<DadTimerId<Ipv4, WeakDeviceId<BT>, WeakAddressId<Ipv4, BT>>, BT>
1603 for CoreCtx<'_, BT, L>
1604{
1605 fn convert_timer(
1606 dispatch_id: DadTimerId<Ipv4, WeakDeviceId<BT>, WeakAddressId<Ipv4, BT>>,
1607 ) -> BT::DispatchId {
1608 IpDeviceTimerId::<Ipv4, _, _>::from(Ipv4DeviceTimerId::from(dispatch_id)).into()
1609 }
1610}
1611
1612impl<L, BT: BindingsTypes>
1613 CoreTimerContext<DadTimerId<Ipv6, WeakDeviceId<BT>, WeakAddressId<Ipv6, BT>>, BT>
1614 for CoreCtx<'_, BT, L>
1615{
1616 fn convert_timer(
1617 dispatch_id: DadTimerId<Ipv6, WeakDeviceId<BT>, WeakAddressId<Ipv6, BT>>,
1618 ) -> BT::DispatchId {
1619 IpDeviceTimerId::<Ipv6, _, _>::from(Ipv6DeviceTimerId::from(dispatch_id)).into()
1620 }
1621}
1622
1623impl<I: IpDeviceIpExt, BT: BindingsTypes, L>
1624 CoreTimerContext<IpDeviceTimerId<I, WeakDeviceId<BT>, BT>, BT> for CoreCtx<'_, BT, L>
1625{
1626 fn convert_timer(dispatch_id: IpDeviceTimerId<I, WeakDeviceId<BT>, BT>) -> BT::DispatchId {
1627 dispatch_id.into()
1628 }
1629}
1630
1631impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1632 for crate::lock_ordering::IpDeviceAddresses<I>
1633{
1634 type Data = IpDeviceAddresses<I, BT>;
1635}
1636
1637impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1638 for crate::lock_ordering::IpDeviceGmp<I>
1639{
1640 type Data = IpDeviceMulticastGroups<I, BT>;
1641}
1642
1643impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1644 for crate::lock_ordering::IpDeviceDefaultHopLimit<I>
1645{
1646 type Data = DefaultHopLimit<I>;
1647}
1648
1649impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1650 for crate::lock_ordering::IpDeviceFlags<I>
1651{
1652 type Data = IpMarked<I, IpDeviceFlags>;
1653}
1654
1655impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1656 for crate::lock_ordering::Ipv6DeviceSlaac
1657{
1658 type Data = SlaacState<BT>;
1659}
1660
1661impl<BT: IpDeviceStateBindingsTypes> UnlockedAccess<crate::lock_ordering::UnlockedState>
1670 for DualStackIpDeviceState<BT>
1671{
1672 type Data = DualStackIpDeviceState<BT>;
1673 type Guard<'l>
1674 = &'l DualStackIpDeviceState<BT>
1675 where
1676 Self: 'l;
1677
1678 fn access(&self) -> Self::Guard<'_> {
1679 &self
1680 }
1681}
1682
1683impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1684 for crate::lock_ordering::IpDeviceConfiguration<Ipv4>
1685{
1686 type Data = Ipv4DeviceConfiguration;
1687}
1688
1689impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1690 for crate::lock_ordering::Ipv6DeviceLearnedParams
1691{
1692 type Data = Ipv6NetworkLearnedParameters;
1693}
1694
1695impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1696 for crate::lock_ordering::Ipv6DeviceRouteDiscovery
1697{
1698 type Data = Ipv6RouteDiscoveryState<BT>;
1699}
1700
1701impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1702 for crate::lock_ordering::Ipv6DeviceRouterSolicitations
1703{
1704 type Data = RsState<BT>;
1705}
1706
1707impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<DualStackIpDeviceState<BT>>
1708 for crate::lock_ordering::IpDeviceConfiguration<Ipv6>
1709{
1710 type Data = Ipv6DeviceConfiguration;
1711}
1712
1713impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<IpAddressEntry<Ipv4, BT>>
1714 for crate::lock_ordering::IpDeviceAddressDad<Ipv4>
1715{
1716 type Data = DadState<Ipv4, BT>;
1717}
1718
1719impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<IpAddressEntry<Ipv4, BT>>
1720 for crate::lock_ordering::IpDeviceAddressData<Ipv4>
1721{
1722 type Data = IpAddressData<Ipv4, BT::Instant>;
1723}
1724
1725impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<IpAddressEntry<Ipv6, BT>>
1726 for crate::lock_ordering::IpDeviceAddressDad<Ipv6>
1727{
1728 type Data = DadState<Ipv6, BT>;
1729}
1730
1731impl<BT: IpDeviceStateBindingsTypes> LockLevelFor<IpAddressEntry<Ipv6, BT>>
1732 for crate::lock_ordering::IpDeviceAddressData<Ipv6>
1733{
1734 type Data = IpAddressData<Ipv6, BT::Instant>;
1735}
1736
1737impl<BT: BindingsTypes, L> CounterContext<SlaacCounters> for CoreCtx<'_, BT, L> {
1738 fn counters(&self) -> &SlaacCounters {
1739 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().ipv6.slaac_counters
1740 }
1741}