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