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