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