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