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