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