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