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