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