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