1use core::fmt::Debug;
8use core::num::NonZeroU8;
9use core::ops::Deref as _;
10
11use lock_order::lock::{DelegatedOrderedLockAccess, LockLevelFor, UnlockedAccess};
12use lock_order::relation::LockBefore;
13use log::debug;
14use net_types::ethernet::Mac;
15use net_types::ip::{
16 AddrSubnet, Ip, IpAddress, IpInvariant, IpVersion, IpVersionMarker, Ipv4, Ipv4Addr, Ipv6,
17 Ipv6Addr, Mtu,
18};
19use net_types::{MulticastAddr, SpecifiedAddr, Witness as _, map_ip_twice};
20use netstack3_base::{
21 AnyDevice, BroadcastIpExt, CounterContext, DeviceIdContext, ExistsError, IpAddressId,
22 IpDeviceAddressIdContext, Ipv4DeviceAddr, Ipv6DeviceAddr, NotFoundError, ReceivableFrameMeta,
23 RecvIpFrameMeta, ReferenceNotifiersExt, RemoveResourceResultWithContext,
24 ResourceCounterContext, SendFrameError, WeakDeviceIdentifier,
25};
26use netstack3_device::blackhole::{BlackholeDeviceCounters, BlackholeDeviceId};
27use netstack3_device::ethernet::{
28 self, EthernetDeviceCounters, EthernetDeviceId, EthernetIpLinkDeviceDynamicStateContext,
29 EthernetLinkDevice, EthernetPrimaryDeviceId, EthernetWeakDeviceId,
30};
31use netstack3_device::loopback::{self, LoopbackDevice, LoopbackDeviceId, LoopbackPrimaryDeviceId};
32use netstack3_device::pure_ip::{self, PureIpDeviceCounters, PureIpDeviceId};
33use netstack3_device::queue::TransmitQueueHandler;
34use netstack3_device::socket::{DeviceSocketCounters, DeviceSocketId, HeldDeviceSockets};
35use netstack3_device::{
36 ArpCounters, BaseDeviceId, DeviceCollectionContext, DeviceConfigurationContext, DeviceCounters,
37 DeviceId, DeviceLayerState, DeviceStateSpec, Devices, DevicesIter, IpLinkDeviceState,
38 IpLinkDeviceStateInner, Ipv6DeviceLinkLayerAddr, OriginTracker, OriginTrackerContext,
39 WeakDeviceId, for_any_device_id,
40};
41use netstack3_filter::ProofOfEgressCheck;
42use netstack3_ip::device::{
43 AddressId, AddressIdIter, DadState, DualStackIpDeviceState, IpAddressData, IpAddressEntry,
44 IpDeviceAddressContext, IpDeviceConfigurationContext, IpDeviceFlags, IpDeviceIpExt,
45 IpDeviceSendContext, IpDeviceStateContext, Ipv4AddrConfig, Ipv4DeviceConfiguration,
46 Ipv6AddrConfig, Ipv6DeviceConfiguration, Ipv6DeviceConfigurationContext, Ipv6DeviceContext,
47 Ipv6NetworkLearnedParameters, PrimaryAddressId, WeakAddressId,
48};
49use netstack3_ip::nud::{
50 ConfirmationFlags, DynamicNeighborUpdateSource, NudHandler, NudIpHandler, NudUserConfig,
51};
52use netstack3_ip::{
53 self as ip, DeviceIpLayerMetadata, IpPacketDestination, IpRoutingDeviceContext, RawMetric,
54};
55use packet::{BufferMut, Serializer};
56use packet_formats::ethernet::EthernetIpExt;
57
58use crate::context::prelude::*;
59use crate::context::{CoreCtxAndResource, Locked, WrapLockLevel};
60use crate::ip::integration::CoreCtxWithIpDeviceConfiguration;
61use crate::{BindingsContext, BindingsTypes, CoreCtx, StackState};
62
63fn bytes_to_mac(b: &[u8]) -> Option<Mac> {
64 (b.len() >= Mac::BYTES).then(|| {
65 Mac::new({
66 let mut bytes = [0; Mac::BYTES];
67 bytes.copy_from_slice(&b[..Mac::BYTES]);
68 bytes
69 })
70 })
71}
72
73impl<
74 I: Ip,
75 BC: BindingsContext,
76 L: LockBefore<crate::lock_ordering::EthernetIpv4Arp>
77 + LockBefore<crate::lock_ordering::EthernetIpv6Nud>,
78> NudIpHandler<I, BC> for CoreCtx<'_, BC, L>
79where
80 Self: NudHandler<I, EthernetLinkDevice, BC>
81 + DeviceIdContext<EthernetLinkDevice, DeviceId = EthernetDeviceId<BC>>,
82{
83 fn handle_neighbor_probe(
84 &mut self,
85 bindings_ctx: &mut BC,
86 device_id: &DeviceId<BC>,
87 neighbor: SpecifiedAddr<I::Addr>,
88 link_addr: &[u8],
89 ) {
90 match device_id {
91 DeviceId::Ethernet(id) => {
92 if let Some(link_address) = bytes_to_mac(link_addr) {
93 NudHandler::<I, EthernetLinkDevice, _>::handle_neighbor_update(
94 self,
95 bindings_ctx,
96 &id,
97 neighbor,
98 DynamicNeighborUpdateSource::Probe { link_address },
99 )
100 }
101 }
102 DeviceId::Loopback(LoopbackDeviceId { .. })
104 | DeviceId::Blackhole(BlackholeDeviceId { .. })
105 | DeviceId::PureIp(PureIpDeviceId { .. }) => {}
106 }
107 }
108
109 fn handle_neighbor_confirmation(
110 &mut self,
111 bindings_ctx: &mut BC,
112 device_id: &DeviceId<BC>,
113 neighbor: SpecifiedAddr<I::Addr>,
114 link_addr: Option<&[u8]>,
115 flags: ConfirmationFlags,
116 ) {
117 match device_id {
118 DeviceId::Ethernet(id) => {
119 let link_address = match link_addr {
120 Some(link_addr) => {
121 let Some(link_addr) = bytes_to_mac(link_addr) else {
123 return;
124 };
125 Some(link_addr)
126 }
127 None => None,
128 };
129
130 NudHandler::<I, EthernetLinkDevice, _>::handle_neighbor_update(
131 self,
132 bindings_ctx,
133 &id,
134 neighbor,
135 DynamicNeighborUpdateSource::Confirmation { link_address, flags },
136 )
137 }
138 DeviceId::Loopback(LoopbackDeviceId { .. })
140 | DeviceId::Blackhole(BlackholeDeviceId { .. })
141 | DeviceId::PureIp(PureIpDeviceId { .. }) => {}
142 }
143 }
144
145 fn flush_neighbor_table(&mut self, bindings_ctx: &mut BC, device_id: &DeviceId<BC>) {
146 match device_id {
147 DeviceId::Ethernet(id) => {
148 NudHandler::<I, EthernetLinkDevice, _>::flush(self, bindings_ctx, &id)
149 }
150 DeviceId::Loopback(LoopbackDeviceId { .. })
152 | DeviceId::Blackhole(BlackholeDeviceId { .. })
153 | DeviceId::PureIp(PureIpDeviceId { .. }) => {}
154 }
155 }
156}
157
158impl<I, D, L, BC> ReceivableFrameMeta<CoreCtx<'_, BC, L>, BC>
159 for RecvIpFrameMeta<D, DeviceIpLayerMetadata<BC>, I>
160where
161 BC: BindingsContext,
162 D: Into<DeviceId<BC>>,
163 L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv4>>,
164 I: Ip,
165{
166 fn receive_meta<B: BufferMut + Debug>(
167 self,
168 core_ctx: &mut CoreCtx<'_, BC, L>,
169 bindings_ctx: &mut BC,
170 frame: B,
171 ) {
172 let RecvIpFrameMeta {
173 device,
174 frame_dst,
175 ip_layer_metadata,
176 marker: IpVersionMarker { .. },
177 } = self;
178 let device = device.into();
179 match I::VERSION {
180 IpVersion::V4 => ip::receive_ipv4_packet(
181 core_ctx,
182 bindings_ctx,
183 &device,
184 frame_dst,
185 ip_layer_metadata,
186 frame,
187 ),
188 IpVersion::V6 => ip::receive_ipv6_packet(
189 core_ctx,
190 bindings_ctx,
191 &device,
192 frame_dst,
193 ip_layer_metadata,
194 frame,
195 ),
196 }
197 }
198}
199
200#[netstack3_macros::instantiate_ip_impl_block(I)]
201impl<I: BroadcastIpExt, BC: BindingsContext, L: LockBefore<crate::lock_ordering::FilterState<I>>>
202 IpDeviceSendContext<I, BC> for CoreCtx<'_, BC, L>
203{
204 fn send_ip_frame<S>(
205 &mut self,
206 bindings_ctx: &mut BC,
207 device: &DeviceId<BC>,
208 destination: IpPacketDestination<I, &DeviceId<BC>>,
209 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
210 body: S,
211 ProofOfEgressCheck { .. }: ProofOfEgressCheck,
212 ) -> Result<(), SendFrameError<S>>
213 where
214 S: Serializer,
215 S::Buffer: BufferMut,
216 {
217 send_ip_frame(self, bindings_ctx, device, destination, ip_layer_metadata, body)
218 }
219}
220
221#[netstack3_macros::instantiate_ip_impl_block(I)]
222impl<
223 I: BroadcastIpExt,
224 Config,
225 BC: BindingsContext,
226 L: LockBefore<crate::lock_ordering::FilterState<I>>,
227> IpDeviceSendContext<I, BC> for CoreCtxWithIpDeviceConfiguration<'_, Config, L, BC>
228{
229 fn send_ip_frame<S>(
230 &mut self,
231 bindings_ctx: &mut BC,
232 device: &DeviceId<BC>,
233 destination: IpPacketDestination<I, &DeviceId<BC>>,
234 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
235 body: S,
236 ProofOfEgressCheck { .. }: ProofOfEgressCheck,
237 ) -> Result<(), SendFrameError<S>>
238 where
239 S: Serializer,
240 S::Buffer: BufferMut,
241 {
242 let Self { config: _, core_ctx } = self;
243 send_ip_frame(core_ctx, bindings_ctx, device, destination, ip_layer_metadata, body)
244 }
245}
246
247impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>>
248 IpDeviceConfigurationContext<Ipv4, BC> for CoreCtx<'_, BC, L>
249{
250 type DevicesIter<'s> = DevicesIter<'s, BC>;
251 type WithIpDeviceConfigurationInnerCtx<'s> = CoreCtxWithIpDeviceConfiguration<
252 's,
253 &'s Ipv4DeviceConfiguration,
254 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>,
255 BC,
256 >;
257 type WithIpDeviceConfigurationMutInner<'s> = CoreCtxWithIpDeviceConfiguration<
258 's,
259 &'s mut Ipv4DeviceConfiguration,
260 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv4>>,
261 BC,
262 >;
263 type DeviceAddressAndGroupsAccessor<'s> =
264 CoreCtx<'s, BC, WrapLockLevel<crate::lock_ordering::DeviceLayerState>>;
265
266 fn with_ip_device_configuration<
267 O,
268 F: FnOnce(&Ipv4DeviceConfiguration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
269 >(
270 &mut self,
271 device_id: &Self::DeviceId,
272 cb: F,
273 ) -> O {
274 let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
275 let (state, mut locked) = core_ctx_and_resource
276 .read_lock_with_and::<crate::lock_ordering::IpDeviceConfiguration<Ipv4>, _>(|c| {
277 c.right()
278 });
279 cb(
280 &state,
281 CoreCtxWithIpDeviceConfiguration { config: &state, core_ctx: locked.cast_core_ctx() },
282 )
283 }
284
285 fn with_ip_device_configuration_mut<
286 O,
287 F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
288 >(
289 &mut self,
290 device_id: &Self::DeviceId,
291 cb: F,
292 ) -> O {
293 let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
294 let (mut state, mut locked) = core_ctx_and_resource
295 .write_lock_with_and::<crate::lock_ordering::IpDeviceConfiguration<Ipv4>, _>(
296 |c| c.right(),
297 );
298 cb(CoreCtxWithIpDeviceConfiguration {
299 config: &mut state,
300 core_ctx: locked.cast_core_ctx(),
301 })
302 }
303
304 fn with_devices_and_state<
305 O,
306 F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
307 >(
308 &mut self,
309 cb: F,
310 ) -> O {
311 let (devices, locked) = self.read_lock_and::<crate::lock_ordering::DeviceLayerState>();
312 cb(devices.iter(), locked)
313 }
314
315 fn loopback_id(&mut self) -> Option<Self::DeviceId> {
316 let devices = &*self.read_lock::<crate::lock_ordering::DeviceLayerState>();
317 devices.loopback.as_ref().map(|primary| DeviceId::Loopback(primary.clone_strong()))
318 }
319}
320
321impl<BC: BindingsContext, L> IpDeviceAddressIdContext<Ipv4> for CoreCtx<'_, BC, L> {
322 type AddressId = AddressId<Ipv4, BC>;
323 type WeakAddressId = WeakAddressId<Ipv4, BC>;
324}
325
326impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddresses<Ipv4>>>
327 IpDeviceStateContext<Ipv4, BC> for CoreCtx<'_, BC, L>
328{
329 type IpDeviceAddressCtx<'a> =
330 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpDeviceAddresses<Ipv4>>>;
331
332 fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
333 &mut self,
334 device_id: &Self::DeviceId,
335 cb: F,
336 ) -> O {
337 let mut state = ip_device_state(self, device_id);
338 let flags = &*state.lock::<crate::lock_ordering::IpDeviceFlags<Ipv4>>();
339 cb(flags)
340 }
341
342 fn add_ip_address(
343 &mut self,
344 device_id: &Self::DeviceId,
345 addr: AddrSubnet<Ipv4Addr, Ipv4DeviceAddr>,
346 config: Ipv4AddrConfig<BC::Instant>,
347 ) -> Result<Self::AddressId, ExistsError> {
348 let mut state = ip_device_state(self, device_id);
349 let addr_id = state
350 .write_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>()
351 .add(IpAddressEntry::new(addr, DadState::Uninitialized, config));
352 addr_id
353 }
354
355 fn remove_ip_address(
356 &mut self,
357 device_id: &Self::DeviceId,
358 addr: Self::AddressId,
359 ) -> RemoveResourceResultWithContext<AddrSubnet<Ipv4Addr>, BC> {
360 let mut state = ip_device_state(self, device_id);
361 let primary = state
362 .write_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>()
363 .remove(&addr.addr().addr())
364 .expect("should exist when address ID exists");
365 assert!(PrimaryAddressId::ptr_eq(&primary, &addr));
366 core::mem::drop(addr);
367
368 BC::unwrap_or_notify_with_new_reference_notifier(primary.into_inner(), |entry| {
369 entry.addr_sub().to_witness::<SpecifiedAddr<_>>()
370 })
371 }
372
373 fn get_address_id(
374 &mut self,
375 device_id: &Self::DeviceId,
376 addr: SpecifiedAddr<Ipv4Addr>,
377 ) -> Result<Self::AddressId, NotFoundError> {
378 let mut state = ip_device_state(self, device_id);
379 let addr_id = state
380 .read_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>()
381 .iter()
382 .find(|a| {
383 let a: Ipv4Addr = a.addr().get();
384 a == *addr
385 })
386 .map(PrimaryAddressId::clone_strong)
387 .ok_or(NotFoundError);
388 addr_id
389 }
390
391 type AddressIdsIter<'a> = AddressIdIter<'a, Ipv4, BC>;
392 fn with_address_ids<
393 O,
394 F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
395 >(
396 &mut self,
397 device_id: &Self::DeviceId,
398 cb: F,
399 ) -> O {
400 let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
401 let (state, mut locked) = core_ctx_and_resource
402 .read_lock_with_and::<crate::lock_ordering::IpDeviceAddresses<Ipv4>, _>(|c| c.right());
403 cb(state.strong_iter(), &mut locked.cast_core_ctx())
404 }
405
406 fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
407 &mut self,
408 device_id: &Self::DeviceId,
409 cb: F,
410 ) -> O {
411 let mut state = ip_device_state(self, device_id);
412 let mut state = state.read_lock::<crate::lock_ordering::IpDeviceDefaultHopLimit<Ipv4>>();
413 cb(&mut state)
414 }
415
416 fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
417 &mut self,
418 device_id: &Self::DeviceId,
419 cb: F,
420 ) -> O {
421 let mut state = ip_device_state(self, device_id);
422 let mut state = state.write_lock::<crate::lock_ordering::IpDeviceDefaultHopLimit<Ipv4>>();
423 cb(&mut state)
424 }
425
426 fn join_link_multicast_group(
427 &mut self,
428 bindings_ctx: &mut BC,
429 device_id: &Self::DeviceId,
430 multicast_addr: MulticastAddr<Ipv4Addr>,
431 ) {
432 join_link_multicast_group(self, bindings_ctx, device_id, multicast_addr)
433 }
434
435 fn leave_link_multicast_group(
436 &mut self,
437 bindings_ctx: &mut BC,
438 device_id: &Self::DeviceId,
439 multicast_addr: MulticastAddr<Ipv4Addr>,
440 ) {
441 leave_link_multicast_group(self, bindings_ctx, device_id, multicast_addr)
442 }
443}
444
445impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>>
446 Ipv6DeviceConfigurationContext<BC> for CoreCtx<'_, BC, L>
447{
448 type Ipv6DeviceStateCtx<'s> = CoreCtxWithIpDeviceConfiguration<
449 's,
450 &'s Ipv6DeviceConfiguration,
451 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
452 BC,
453 >;
454 type WithIpv6DeviceConfigurationMutInner<'s> = CoreCtxWithIpDeviceConfiguration<
455 's,
456 &'s mut Ipv6DeviceConfiguration,
457 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
458 BC,
459 >;
460
461 fn with_ipv6_device_configuration<
462 O,
463 F: FnOnce(&Ipv6DeviceConfiguration, Self::Ipv6DeviceStateCtx<'_>) -> O,
464 >(
465 &mut self,
466 device_id: &Self::DeviceId,
467 cb: F,
468 ) -> O {
469 IpDeviceConfigurationContext::<Ipv6, _>::with_ip_device_configuration(self, device_id, cb)
470 }
471
472 fn with_ipv6_device_configuration_mut<
473 O,
474 F: FnOnce(Self::WithIpv6DeviceConfigurationMutInner<'_>) -> O,
475 >(
476 &mut self,
477 device_id: &Self::DeviceId,
478 cb: F,
479 ) -> O {
480 IpDeviceConfigurationContext::<Ipv6, _>::with_ip_device_configuration_mut(
481 self, device_id, cb,
482 )
483 }
484}
485
486impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>>
487 IpDeviceConfigurationContext<Ipv6, BC> for CoreCtx<'_, BC, L>
488{
489 type DevicesIter<'s> = DevicesIter<'s, BC>;
490 type WithIpDeviceConfigurationInnerCtx<'s> = CoreCtxWithIpDeviceConfiguration<
491 's,
492 &'s Ipv6DeviceConfiguration,
493 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
494 BC,
495 >;
496 type WithIpDeviceConfigurationMutInner<'s> = CoreCtxWithIpDeviceConfiguration<
497 's,
498 &'s mut Ipv6DeviceConfiguration,
499 WrapLockLevel<crate::lock_ordering::IpDeviceConfiguration<Ipv6>>,
500 BC,
501 >;
502 type DeviceAddressAndGroupsAccessor<'s> =
503 CoreCtx<'s, BC, WrapLockLevel<crate::lock_ordering::DeviceLayerState>>;
504
505 fn with_ip_device_configuration<
506 O,
507 F: FnOnce(&Ipv6DeviceConfiguration, Self::WithIpDeviceConfigurationInnerCtx<'_>) -> O,
508 >(
509 &mut self,
510 device_id: &Self::DeviceId,
511 cb: F,
512 ) -> O {
513 let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
514 let (state, mut locked) = core_ctx_and_resource
515 .read_lock_with_and::<crate::lock_ordering::IpDeviceConfiguration<Ipv6>, _>(|c| {
516 c.right()
517 });
518 cb(
519 &state,
520 CoreCtxWithIpDeviceConfiguration { config: &state, core_ctx: locked.cast_core_ctx() },
521 )
522 }
523
524 fn with_ip_device_configuration_mut<
525 O,
526 F: FnOnce(Self::WithIpDeviceConfigurationMutInner<'_>) -> O,
527 >(
528 &mut self,
529 device_id: &Self::DeviceId,
530 cb: F,
531 ) -> O {
532 let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
533 let (mut state, mut locked) = core_ctx_and_resource
534 .write_lock_with_and::<crate::lock_ordering::IpDeviceConfiguration<Ipv6>, _>(
535 |c| c.right(),
536 );
537 cb(CoreCtxWithIpDeviceConfiguration {
538 config: &mut state,
539 core_ctx: locked.cast_core_ctx(),
540 })
541 }
542
543 fn with_devices_and_state<
544 O,
545 F: FnOnce(Self::DevicesIter<'_>, Self::DeviceAddressAndGroupsAccessor<'_>) -> O,
546 >(
547 &mut self,
548 cb: F,
549 ) -> O {
550 let (devices, locked) = self.read_lock_and::<crate::lock_ordering::DeviceLayerState>();
551 cb(devices.iter(), locked)
552 }
553
554 fn loopback_id(&mut self) -> Option<Self::DeviceId> {
555 let devices = &*self.read_lock::<crate::lock_ordering::DeviceLayerState>();
556 devices.loopback.as_ref().map(|primary| DeviceId::Loopback(primary.clone_strong()))
557 }
558}
559
560impl<BC: BindingsContext, L> IpDeviceAddressIdContext<Ipv6> for CoreCtx<'_, BC, L> {
561 type AddressId = AddressId<Ipv6, BC>;
562 type WeakAddressId = WeakAddressId<Ipv6, BC>;
563}
564
565#[netstack3_macros::instantiate_ip_impl_block(I)]
566impl<
567 I: IpLayerIpExt,
568 BC: BindingsContext,
569 L: LockBefore<crate::lock_ordering::IpDeviceAddressData<I>>,
570> IpDeviceAddressContext<I, BC> for CoreCtx<'_, BC, L>
571{
572 fn with_ip_address_data<O, F: FnOnce(&IpAddressData<I, BC::Instant>) -> O>(
573 &mut self,
574 _device_id: &Self::DeviceId,
575 addr_id: &Self::AddressId,
576 cb: F,
577 ) -> O {
578 let mut locked = self.adopt(addr_id.deref());
579 let x = cb(&locked
580 .read_lock_with::<crate::lock_ordering::IpDeviceAddressData<I>, _>(|c| c.right()));
581 x
582 }
583
584 fn with_ip_address_data_mut<O, F: FnOnce(&mut IpAddressData<I, BC::Instant>) -> O>(
585 &mut self,
586 _device_id: &Self::DeviceId,
587 addr_id: &Self::AddressId,
588 cb: F,
589 ) -> O {
590 let mut locked = self.adopt(addr_id.deref());
591 let x = cb(&mut locked
592 .write_lock_with::<crate::lock_ordering::IpDeviceAddressData<I>, _>(|c| c.right()));
593 x
594 }
595}
596
597impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddresses<Ipv6>>>
598 IpDeviceStateContext<Ipv6, BC> for CoreCtx<'_, BC, L>
599{
600 type IpDeviceAddressCtx<'a> =
601 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::IpDeviceAddresses<Ipv6>>>;
602
603 fn with_ip_device_flags<O, F: FnOnce(&IpDeviceFlags) -> O>(
604 &mut self,
605 device_id: &Self::DeviceId,
606 cb: F,
607 ) -> O {
608 let mut state = ip_device_state(self, device_id);
609 let flags = &*state.lock::<crate::lock_ordering::IpDeviceFlags<Ipv6>>();
610 cb(flags)
611 }
612
613 fn add_ip_address(
614 &mut self,
615 device_id: &Self::DeviceId,
616 addr: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
617 config: Ipv6AddrConfig<BC::Instant>,
618 ) -> Result<Self::AddressId, ExistsError> {
619 let mut state = ip_device_state(self, device_id);
620 let addr_id = state
621 .write_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv6>>()
622 .add(IpAddressEntry::new(addr, DadState::Uninitialized, config));
623 addr_id
624 }
625
626 fn remove_ip_address(
627 &mut self,
628 device_id: &Self::DeviceId,
629 addr: Self::AddressId,
630 ) -> RemoveResourceResultWithContext<AddrSubnet<Ipv6Addr>, BC> {
631 let mut state = ip_device_state(self, device_id);
632 let primary = state
633 .write_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv6>>()
634 .remove(&addr.addr().addr())
635 .expect("should exist when address ID exists");
636 assert!(PrimaryAddressId::ptr_eq(&primary, &addr));
637 core::mem::drop(addr);
638
639 BC::unwrap_or_notify_with_new_reference_notifier(primary.into_inner(), |entry| {
640 entry.addr_sub().to_witness::<SpecifiedAddr<_>>()
641 })
642 }
643
644 fn get_address_id(
645 &mut self,
646 device_id: &Self::DeviceId,
647 addr: SpecifiedAddr<Ipv6Addr>,
648 ) -> Result<Self::AddressId, NotFoundError> {
649 let mut state = ip_device_state(self, device_id);
650 let addr_id = state
651 .read_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv6>>()
652 .iter()
653 .find_map(|a| {
654 let inner: Ipv6Addr = a.addr().get();
655 (inner == *addr).then(|| PrimaryAddressId::clone_strong(a))
656 })
657 .ok_or(NotFoundError);
658 addr_id
659 }
660
661 type AddressIdsIter<'a> = AddressIdIter<'a, Ipv6, BC>;
662 fn with_address_ids<
663 O,
664 F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
665 >(
666 &mut self,
667 device_id: &Self::DeviceId,
668 cb: F,
669 ) -> O {
670 let mut core_ctx_and_resource = ip_device_state_and_core_ctx(self, device_id);
671 let (state, mut core_ctx) = core_ctx_and_resource
672 .read_lock_with_and::<crate::lock_ordering::IpDeviceAddresses<Ipv6>, _>(|c| c.right());
673 cb(state.strong_iter(), &mut core_ctx.cast_core_ctx())
674 }
675
676 fn with_default_hop_limit<O, F: FnOnce(&NonZeroU8) -> O>(
677 &mut self,
678 device_id: &Self::DeviceId,
679 cb: F,
680 ) -> O {
681 let mut state = ip_device_state(self, device_id);
682 let mut state = state.read_lock::<crate::lock_ordering::IpDeviceDefaultHopLimit<Ipv6>>();
683 cb(&mut state)
684 }
685
686 fn with_default_hop_limit_mut<O, F: FnOnce(&mut NonZeroU8) -> O>(
687 &mut self,
688 device_id: &Self::DeviceId,
689 cb: F,
690 ) -> O {
691 let mut state = ip_device_state(self, device_id);
692 let mut state = state.write_lock::<crate::lock_ordering::IpDeviceDefaultHopLimit<Ipv6>>();
693 cb(&mut state)
694 }
695
696 fn join_link_multicast_group(
697 &mut self,
698 bindings_ctx: &mut BC,
699 device_id: &Self::DeviceId,
700 multicast_addr: MulticastAddr<Ipv6Addr>,
701 ) {
702 join_link_multicast_group(self, bindings_ctx, device_id, multicast_addr)
703 }
704
705 fn leave_link_multicast_group(
706 &mut self,
707 bindings_ctx: &mut BC,
708 device_id: &Self::DeviceId,
709 multicast_addr: MulticastAddr<Ipv6Addr>,
710 ) {
711 leave_link_multicast_group(self, bindings_ctx, device_id, multicast_addr)
712 }
713}
714
715impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceAddresses<Ipv6>>>
716 Ipv6DeviceContext<BC> for CoreCtx<'_, BC, L>
717{
718 type LinkLayerAddr = Ipv6DeviceLinkLayerAddr;
719
720 fn get_link_layer_addr(
721 &mut self,
722 device_id: &Self::DeviceId,
723 ) -> Option<Ipv6DeviceLinkLayerAddr> {
724 match device_id {
725 DeviceId::Ethernet(id) => {
726 Some(Ipv6DeviceLinkLayerAddr::Mac(ethernet::get_mac(self, &id).get()))
727 }
728 DeviceId::Loopback(LoopbackDeviceId { .. })
729 | DeviceId::Blackhole(BlackholeDeviceId { .. })
730 | DeviceId::PureIp(PureIpDeviceId { .. }) => None,
731 }
732 }
733
734 fn set_link_mtu(&mut self, device_id: &Self::DeviceId, mtu: Mtu) {
735 if mtu < Ipv6::MINIMUM_LINK_MTU {
736 return;
737 }
738
739 match device_id {
740 DeviceId::Ethernet(id) => ethernet::set_mtu(self, &id, mtu),
741 DeviceId::Loopback(LoopbackDeviceId { .. }) => {}
742 DeviceId::PureIp(id) => pure_ip::set_mtu(self, &id, mtu),
743 DeviceId::Blackhole(BlackholeDeviceId { .. }) => {}
744 }
745 }
746
747 fn with_network_learned_parameters<O, F: FnOnce(&Ipv6NetworkLearnedParameters) -> O>(
748 &mut self,
749 device_id: &Self::DeviceId,
750 cb: F,
751 ) -> O {
752 let mut state = ip_device_state(self, device_id);
753 let state = state.read_lock::<crate::lock_ordering::Ipv6DeviceLearnedParams>();
754 cb(&state)
755 }
756
757 fn with_network_learned_parameters_mut<O, F: FnOnce(&mut Ipv6NetworkLearnedParameters) -> O>(
758 &mut self,
759 device_id: &Self::DeviceId,
760 cb: F,
761 ) -> O {
762 let mut state = ip_device_state(self, device_id);
763 let mut state = state.write_lock::<crate::lock_ordering::Ipv6DeviceLearnedParams>();
764 cb(&mut state)
765 }
766}
767
768impl<BT: BindingsTypes, L> DeviceIdContext<EthernetLinkDevice> for CoreCtx<'_, BT, L> {
769 type DeviceId = EthernetDeviceId<BT>;
770 type WeakDeviceId = EthernetWeakDeviceId<BT>;
771}
772
773impl<BT: BindingsTypes> DelegatedOrderedLockAccess<Devices<BT>> for StackState<BT> {
774 type Inner = DeviceLayerState<BT>;
775 fn delegate_ordered_lock_access(&self) -> &Self::Inner {
776 &self.device
777 }
778}
779
780impl<BT: BindingsTypes> LockLevelFor<StackState<BT>> for crate::lock_ordering::DeviceLayerState {
781 type Data = Devices<BT>;
782}
783
784impl<BT: BindingsTypes, L> DeviceIdContext<AnyDevice> for CoreCtx<'_, BT, L> {
785 type DeviceId = DeviceId<BT>;
786 type WeakDeviceId = WeakDeviceId<BT>;
787}
788
789impl<T, BT: BindingsTypes> UnlockedAccess<crate::lock_ordering::UnlockedState>
798 for IpLinkDeviceStateInner<T, BT>
799{
800 type Data = IpLinkDeviceStateInner<T, BT>;
801 type Guard<'l>
802 = &'l IpLinkDeviceStateInner<T, BT>
803 where
804 Self: 'l;
805
806 fn access(&self) -> Self::Guard<'_> {
807 &self
808 }
809}
810
811pub(crate) fn device_state<'a, BT: BindingsTypes, L, D: DeviceStateSpec>(
812 core_ctx: &'a mut CoreCtx<'_, BT, L>,
813 device_id: &'a BaseDeviceId<D, BT>,
814) -> Locked<&'a IpLinkDeviceState<D, BT>, L> {
815 let state = device_id.device_state(
816 &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
817 );
818 core_ctx.replace(state)
819}
820
821pub(crate) fn device_state_and_core_ctx<'a, BT: BindingsTypes, L, D: DeviceStateSpec>(
822 core_ctx: &'a mut CoreCtx<'_, BT, L>,
823 id: &'a BaseDeviceId<D, BT>,
824) -> CoreCtxAndResource<'a, BT, IpLinkDeviceState<D, BT>, L> {
825 let state = id.device_state(
826 &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
827 );
828 core_ctx.adopt(state)
829}
830
831pub(crate) fn ip_device_state<'a, BC: BindingsContext, L>(
832 core_ctx: &'a mut CoreCtx<'_, BC, L>,
833 device: &'a DeviceId<BC>,
834) -> Locked<&'a DualStackIpDeviceState<BC>, L> {
835 for_any_device_id!(
836 DeviceId,
837 device,
838 id => {
839 let state = id.device_state(
840 &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin
841 );
842 core_ctx.replace(state.as_ref())
843 }
844 )
845}
846
847pub(crate) fn ip_device_state_and_core_ctx<'a, BC: BindingsContext, L>(
848 core_ctx: &'a mut CoreCtx<'_, BC, L>,
849 device: &'a DeviceId<BC>,
850) -> CoreCtxAndResource<'a, BC, DualStackIpDeviceState<BC>, L> {
851 for_any_device_id!(
852 DeviceId,
853 device,
854 id => {
855 let state = id.device_state(
856 &core_ctx.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin
857 );
858 core_ctx.adopt(state.as_ref())
859 }
860 )
861}
862
863pub(crate) fn get_mtu<
864 BC: BindingsContext,
865 L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>,
866>(
867 core_ctx: &mut CoreCtx<'_, BC, L>,
868 device: &DeviceId<BC>,
869) -> Mtu {
870 match device {
871 DeviceId::Ethernet(id) => ethernet::get_mtu(core_ctx, &id),
872 DeviceId::Loopback(id) => device_state(core_ctx, id).cast_with(|s| &s.link.mtu).copied(),
873 DeviceId::PureIp(id) => pure_ip::get_mtu(core_ctx, &id),
874 DeviceId::Blackhole(_id) => Mtu::no_limit(),
875 }
876}
877
878fn join_link_multicast_group<
879 BC: BindingsContext,
880 A: IpAddress,
881 L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>,
882>(
883 core_ctx: &mut CoreCtx<'_, BC, L>,
884 bindings_ctx: &mut BC,
885 device_id: &DeviceId<BC>,
886 multicast_addr: MulticastAddr<A>,
887) {
888 match device_id {
889 DeviceId::Ethernet(id) => ethernet::join_link_multicast(
890 core_ctx,
891 bindings_ctx,
892 &id,
893 MulticastAddr::from(&multicast_addr),
894 ),
895 DeviceId::Loopback(LoopbackDeviceId { .. })
896 | DeviceId::PureIp(PureIpDeviceId { .. })
897 | DeviceId::Blackhole(BlackholeDeviceId { .. }) => {}
898 }
899}
900
901fn leave_link_multicast_group<
902 BC: BindingsContext,
903 A: IpAddress,
904 L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>,
905>(
906 core_ctx: &mut CoreCtx<'_, BC, L>,
907 bindings_ctx: &mut BC,
908 device_id: &DeviceId<BC>,
909 multicast_addr: MulticastAddr<A>,
910) {
911 match device_id {
912 DeviceId::Ethernet(id) => ethernet::leave_link_multicast(
913 core_ctx,
914 bindings_ctx,
915 &id,
916 MulticastAddr::from(&multicast_addr),
917 ),
918 DeviceId::Loopback(LoopbackDeviceId { .. })
919 | DeviceId::PureIp(PureIpDeviceId { .. })
920 | DeviceId::Blackhole(BlackholeDeviceId { .. }) => {}
921 }
922}
923
924fn send_ip_frame<BC, S, I, L>(
925 core_ctx: &mut CoreCtx<'_, BC, L>,
926 bindings_ctx: &mut BC,
927 device: &DeviceId<BC>,
928 destination: IpPacketDestination<I, &DeviceId<BC>>,
929 ip_layer_metadata: DeviceIpLayerMetadata<BC>,
930 body: S,
931) -> Result<(), SendFrameError<S>>
932where
933 BC: BindingsContext,
934 S: Serializer,
935 S::Buffer: BufferMut,
936 I: EthernetIpExt + BroadcastIpExt,
937 L: LockBefore<crate::lock_ordering::IpState<I>>
938 + LockBefore<crate::lock_ordering::LoopbackTxQueue>
939 + LockBefore<crate::lock_ordering::PureIpDeviceTxQueue>,
940 for<'a> CoreCtx<'a, BC, L>: EthernetIpLinkDeviceDynamicStateContext<BC, DeviceId = EthernetDeviceId<BC>>
941 + NudHandler<I, EthernetLinkDevice, BC>
942 + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = BC::TxMetadata>,
943{
944 match device {
945 DeviceId::Ethernet(id) => ethernet::send_ip_frame(
946 core_ctx,
947 bindings_ctx,
948 id,
949 destination,
950 body,
951 ip_layer_metadata.into_tx_metadata(),
952 ),
953 DeviceId::Loopback(id) => loopback::send_ip_frame(
954 core_ctx,
955 bindings_ctx,
956 id,
957 destination,
958 ip_layer_metadata,
959 body,
960 ),
961 DeviceId::PureIp(id) => pure_ip::send_ip_frame(
962 core_ctx,
963 bindings_ctx,
964 id,
965 destination,
966 body,
967 ip_layer_metadata.into_tx_metadata(),
968 ),
969 DeviceId::Blackhole(id) => {
970 debug!("dropping frame in send_ip_frame on blackhole device {id:?}");
972 core_ctx.increment_both(id, DeviceCounters::send_frame::<I>);
973 Ok(())
974 }
975 }
976}
977
978impl<'a, BT, L> DeviceCollectionContext<EthernetLinkDevice, BT> for CoreCtx<'a, BT, L>
979where
980 BT: BindingsTypes,
981 L: LockBefore<crate::lock_ordering::DeviceLayerState>,
982{
983 fn insert(&mut self, device: EthernetPrimaryDeviceId<BT>) {
984 let mut devices = self.write_lock::<crate::lock_ordering::DeviceLayerState>();
985 let strong = device.clone_strong();
986 assert!(devices.ethernet.insert(strong, device).is_none());
987 }
988
989 fn remove(&mut self, device: &EthernetDeviceId<BT>) -> Option<EthernetPrimaryDeviceId<BT>> {
990 let mut devices = self.write_lock::<crate::lock_ordering::DeviceLayerState>();
991 devices.ethernet.remove(device)
992 }
993}
994
995impl<'a, BT, L> DeviceCollectionContext<LoopbackDevice, BT> for CoreCtx<'a, BT, L>
996where
997 BT: BindingsTypes,
998 L: LockBefore<crate::lock_ordering::DeviceLayerState>,
999{
1000 fn insert(&mut self, device: LoopbackPrimaryDeviceId<BT>) {
1001 let mut devices = self.write_lock::<crate::lock_ordering::DeviceLayerState>();
1002 let prev = devices.loopback.replace(device);
1003 assert!(prev.is_none(), "can't install loopback device more than once");
1008 }
1009
1010 fn remove(&mut self, device: &LoopbackDeviceId<BT>) -> Option<LoopbackPrimaryDeviceId<BT>> {
1011 let mut devices = self.write_lock::<crate::lock_ordering::DeviceLayerState>();
1016 let primary = devices.loopback.take().expect("loopback device not installed");
1017 assert_eq!(device, &primary);
1018 Some(primary)
1019 }
1020}
1021
1022impl<'a, BT: BindingsTypes, L> OriginTrackerContext for CoreCtx<'a, BT, L> {
1023 fn origin_tracker(&mut self) -> OriginTracker {
1024 self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin.clone()
1025 }
1026}
1027
1028impl<'a, BT, L> DeviceConfigurationContext<EthernetLinkDevice> for CoreCtx<'a, BT, L>
1029where
1030 L: LockBefore<crate::lock_ordering::NudConfig<Ipv4>>
1031 + LockBefore<crate::lock_ordering::NudConfig<Ipv6>>,
1032 BT: BindingsTypes,
1033{
1034 fn with_nud_config<I: Ip, O, F: FnOnce(Option<&NudUserConfig>) -> O>(
1035 &mut self,
1036 device_id: &Self::DeviceId,
1037 f: F,
1038 ) -> O {
1039 let state = device_state(self, device_id);
1040 let IpInvariant(o) =
1043 map_ip_twice!(I, IpInvariant((state, f)), |IpInvariant((mut state, f))| {
1044 IpInvariant(f(Some(&*state.read_lock::<crate::lock_ordering::NudConfig<I>>())))
1045 });
1046 o
1047 }
1048
1049 fn with_nud_config_mut<I: Ip, O, F: FnOnce(Option<&mut NudUserConfig>) -> O>(
1050 &mut self,
1051 device_id: &Self::DeviceId,
1052 f: F,
1053 ) -> O {
1054 let state = device_state(self, device_id);
1055 let IpInvariant(o) =
1058 map_ip_twice!(I, IpInvariant((state, f)), |IpInvariant((mut state, f))| {
1059 IpInvariant(f(Some(&mut *state.write_lock::<crate::lock_ordering::NudConfig<I>>())))
1060 });
1061 o
1062 }
1063}
1064
1065impl<'a, BT, L> DeviceConfigurationContext<LoopbackDevice> for CoreCtx<'a, BT, L>
1066where
1067 BT: BindingsTypes,
1068{
1069 fn with_nud_config<I: Ip, O, F: FnOnce(Option<&NudUserConfig>) -> O>(
1070 &mut self,
1071 _device_id: &Self::DeviceId,
1072 f: F,
1073 ) -> O {
1074 f(None)
1076 }
1077
1078 fn with_nud_config_mut<I: Ip, O, F: FnOnce(Option<&mut NudUserConfig>) -> O>(
1079 &mut self,
1080 _device_id: &Self::DeviceId,
1081 f: F,
1082 ) -> O {
1083 f(None)
1085 }
1086}
1087
1088impl<BC: BindingsContext, L> CounterContext<EthernetDeviceCounters> for CoreCtx<'_, BC, L> {
1089 fn counters(&self) -> &EthernetDeviceCounters {
1090 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.ethernet_counters
1091 }
1092}
1093
1094impl<BC: BindingsContext, L> CounterContext<DeviceSocketCounters> for CoreCtx<'_, BC, L> {
1095 fn counters(&self) -> &DeviceSocketCounters {
1096 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.device_socket_counters
1097 }
1098}
1099
1100impl<BC: BindingsContext, L> CounterContext<PureIpDeviceCounters> for CoreCtx<'_, BC, L> {
1101 fn counters(&self) -> &PureIpDeviceCounters {
1102 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.pure_ip_counters
1103 }
1104}
1105
1106impl<'a, BC: BindingsContext, L> ResourceCounterContext<DeviceId<BC>, DeviceCounters>
1107 for CoreCtx<'a, BC, L>
1108{
1109 fn per_resource_counters<'b>(&'b self, device_id: &'b DeviceId<BC>) -> &'b DeviceCounters {
1110 for_any_device_id!(DeviceId, device_id, id => {
1111 let state = id.device_state(
1112 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1113 );
1114 &state.counters
1115 })
1116 }
1117}
1118
1119impl<'a, BC: BindingsContext, D: DeviceStateSpec, L>
1120 ResourceCounterContext<BaseDeviceId<D, BC>, DeviceCounters> for CoreCtx<'a, BC, L>
1121{
1122 fn per_resource_counters<'b>(
1123 &'b self,
1124 device_id: &'b BaseDeviceId<D, BC>,
1125 ) -> &'b DeviceCounters {
1126 let state = device_id.device_state(
1127 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1128 );
1129 &state.counters
1130 }
1131}
1132
1133impl<'a, BC: BindingsContext, L, D: WeakDeviceIdentifier>
1134 ResourceCounterContext<DeviceSocketId<D, BC>, DeviceSocketCounters> for CoreCtx<'a, BC, L>
1135{
1136 fn per_resource_counters<'b>(
1137 &'b self,
1138 socket_id: &'b DeviceSocketId<D, BC>,
1139 ) -> &'b DeviceSocketCounters {
1140 socket_id.counters()
1141 }
1142}
1143
1144impl<'a, BC: BindingsContext, L>
1145 ResourceCounterContext<EthernetDeviceId<BC>, EthernetDeviceCounters> for CoreCtx<'a, BC, L>
1146{
1147 fn per_resource_counters<'b>(
1148 &'b self,
1149 device_id: &'b EthernetDeviceId<BC>,
1150 ) -> &'b EthernetDeviceCounters {
1151 let state = device_id.device_state(
1152 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1153 );
1154 &state.link.counters
1155 }
1156}
1157
1158impl<'a, BC: BindingsContext, L>
1159 ResourceCounterContext<LoopbackDeviceId<BC>, EthernetDeviceCounters> for CoreCtx<'a, BC, L>
1160{
1161 fn per_resource_counters<'b>(
1162 &'b self,
1163 device_id: &'b LoopbackDeviceId<BC>,
1164 ) -> &'b EthernetDeviceCounters {
1165 let state = device_id.device_state(
1166 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1167 );
1168 &state.link.counters
1169 }
1170}
1171
1172impl<'a, BC: BindingsContext, L> ResourceCounterContext<PureIpDeviceId<BC>, PureIpDeviceCounters>
1173 for CoreCtx<'a, BC, L>
1174{
1175 fn per_resource_counters<'b>(
1176 &'b self,
1177 device_id: &'b PureIpDeviceId<BC>,
1178 ) -> &'b PureIpDeviceCounters {
1179 let state = device_id.device_state(
1180 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.origin,
1181 );
1182 &state.link.counters
1183 }
1184}
1185
1186impl<'a, BC: BindingsContext, L> CounterContext<BlackholeDeviceCounters> for CoreCtx<'a, BC, L> {
1188 fn counters(&self) -> &BlackholeDeviceCounters {
1189 &BlackholeDeviceCounters
1190 }
1191}
1192
1193impl<'a, BC: BindingsContext, L>
1194 ResourceCounterContext<BlackholeDeviceId<BC>, BlackholeDeviceCounters> for CoreCtx<'a, BC, L>
1195{
1196 fn per_resource_counters<'b>(
1197 &'b self,
1198 _device_id: &'b BlackholeDeviceId<BC>,
1199 ) -> &'b BlackholeDeviceCounters {
1200 &BlackholeDeviceCounters
1201 }
1202}
1203
1204impl<T, BT: BindingsTypes> LockLevelFor<IpLinkDeviceStateInner<T, BT>>
1205 for crate::lock_ordering::DeviceSockets
1206{
1207 type Data = HeldDeviceSockets<BT>;
1208}
1209
1210impl<BT: BindingsTypes, L> CounterContext<DeviceCounters> for CoreCtx<'_, BT, L> {
1211 fn counters(&self) -> &DeviceCounters {
1212 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.counters
1213 }
1214}
1215
1216impl<I: IpDeviceIpExt, BC: BindingsContext, L> IpRoutingDeviceContext<I> for CoreCtx<'_, BC, L>
1217where
1218 Self: IpDeviceStateContext<I, BC, DeviceId = DeviceId<BC>>,
1219{
1220 fn get_routing_metric(&mut self, device_id: &Self::DeviceId) -> RawMetric {
1221 let state = ip_device_state(self, device_id);
1222 *state.unlocked_access::<crate::lock_ordering::UnlockedState>().metric()
1223 }
1224
1225 fn is_ip_device_enabled(&mut self, device_id: &Self::DeviceId) -> bool {
1226 IpDeviceStateContext::<I, _>::with_ip_device_flags(
1227 self,
1228 device_id,
1229 |IpDeviceFlags { ip_enabled }| *ip_enabled,
1230 )
1231 }
1232}
1233
1234impl<BT: BindingsTypes, L> CounterContext<ArpCounters> for CoreCtx<'_, BT, L> {
1235 fn counters(&self) -> &ArpCounters {
1236 &self.unlocked_access::<crate::lock_ordering::UnlockedState>().device.arp_counters
1237 }
1238}