1use alloc::vec::Vec;
9use lock_order::lock::LockLevelFor;
10use lock_order::relation::LockBefore;
11
12use log::debug;
13use net_types::ethernet::Mac;
14use net_types::ip::{Ip, IpMarked, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
15use net_types::{SpecifiedAddr, UnicastAddr, Witness};
16use netstack3_base::socket::SocketIpAddr;
17use netstack3_base::{CoreTimerContext, CounterContext, DeviceIdContext, Marks, SendFrameError};
18use netstack3_device::ethernet::{
19 self, DynamicEthernetDeviceState, EthernetDeviceId, EthernetIpLinkDeviceDynamicStateContext,
20 EthernetIpLinkDeviceStaticStateContext, EthernetLinkDevice, EthernetTimerId,
21 EthernetWeakDeviceId, StaticEthernetDeviceState,
22};
23use netstack3_device::queue::{
24 BufVecU8Allocator, DequeueState, TransmitDequeueContext, TransmitQueueCommon,
25 TransmitQueueContext, TransmitQueueState,
26};
27use netstack3_device::socket::{ParseSentFrameError, SentFrame};
28use netstack3_device::{
29 ArpConfigContext, ArpContext, ArpNudCtx, ArpSenderContext, ArpState,
30 DeviceLayerEventDispatcher, DeviceLayerTimerId, DeviceSendFrameError, IpLinkDeviceState,
31};
32use netstack3_ip::icmp::{self, NdpCounters};
33use netstack3_ip::nud::{
34 DelegateNudContext, NudConfigContext, NudContext, NudIcmpContext, NudSenderContext, NudState,
35 NudUserConfig, UseDelegateNudContext,
36};
37use netstack3_ip::IpDeviceEgressStateContext;
38use packet::{Buf, BufferMut, InnerPacketBuilder as _, Serializer};
39use packet_formats::ethernet::EtherType;
40use packet_formats::icmp::ndp::options::NdpOptionBuilder;
41use packet_formats::icmp::ndp::{NeighborSolicitation, OptionSequenceBuilder};
42use packet_formats::icmp::IcmpZeroCode;
43use packet_formats::ipv4::Ipv4FragmentType;
44use packet_formats::utils::NonZeroDuration;
45
46use crate::context::prelude::*;
47use crate::context::WrapLockLevel;
48use crate::device::integration;
49use crate::{BindingsContext, BindingsTypes, CoreCtx};
50
51pub struct CoreCtxWithDeviceId<'a, CC: DeviceIdContext<EthernetLinkDevice>> {
52 core_ctx: &'a mut CC,
53 device_id: &'a CC::DeviceId,
54}
55
56impl<'a, CC: DeviceIdContext<EthernetLinkDevice>> DeviceIdContext<EthernetLinkDevice>
57 for CoreCtxWithDeviceId<'a, CC>
58{
59 type DeviceId = CC::DeviceId;
60 type WeakDeviceId = CC::WeakDeviceId;
61}
62
63impl<BC: BindingsContext, L> EthernetIpLinkDeviceStaticStateContext for CoreCtx<'_, BC, L> {
64 fn with_static_ethernet_device_state<O, F: FnOnce(&StaticEthernetDeviceState) -> O>(
65 &mut self,
66 device_id: &EthernetDeviceId<BC>,
67 cb: F,
68 ) -> O {
69 let state = integration::device_state(self, device_id);
70 cb(&state.unlocked_access::<crate::lock_ordering::UnlockedState>().link.static_state)
71 }
72}
73
74impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetDeviceDynamicState>>
75 EthernetIpLinkDeviceDynamicStateContext<BC> for CoreCtx<'_, BC, L>
76{
77 fn with_ethernet_state<
78 O,
79 F: FnOnce(&StaticEthernetDeviceState, &DynamicEthernetDeviceState) -> O,
80 >(
81 &mut self,
82 device_id: &EthernetDeviceId<BC>,
83 cb: F,
84 ) -> O {
85 let mut state = integration::device_state(self, device_id);
86 let (dynamic_state, locked) =
87 state.read_lock_and::<crate::lock_ordering::EthernetDeviceDynamicState>();
88 cb(
89 &locked.unlocked_access::<crate::lock_ordering::UnlockedState>().link.static_state,
90 &dynamic_state,
91 )
92 }
93
94 fn with_ethernet_state_mut<
95 O,
96 F: FnOnce(&StaticEthernetDeviceState, &mut DynamicEthernetDeviceState) -> O,
97 >(
98 &mut self,
99 device_id: &EthernetDeviceId<BC>,
100 cb: F,
101 ) -> O {
102 let mut state = integration::device_state(self, device_id);
103 let (mut dynamic_state, locked) =
104 state.write_lock_and::<crate::lock_ordering::EthernetDeviceDynamicState>();
105 cb(
106 &locked.unlocked_access::<crate::lock_ordering::UnlockedState>().link.static_state,
107 &mut dynamic_state,
108 )
109 }
110}
111
112impl<BT: BindingsTypes, L> CoreTimerContext<EthernetTimerId<EthernetWeakDeviceId<BT>>, BT>
113 for CoreCtx<'_, BT, L>
114{
115 fn convert_timer(dispatch_id: EthernetTimerId<EthernetWeakDeviceId<BT>>) -> BT::DispatchId {
116 DeviceLayerTimerId::from(dispatch_id).into()
117 }
118}
119
120impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::FilterState<Ipv6>>>
121 NudContext<Ipv6, EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
122{
123 type ConfigCtx<'a> = CoreCtxWithDeviceId<
124 'a,
125 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv6Nud>>,
126 >;
127
128 type SenderCtx<'a> = CoreCtxWithDeviceId<
129 'a,
130 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv6Nud>>,
131 >;
132
133 fn with_nud_state_mut_and_sender_ctx<
134 O,
135 F: FnOnce(&mut NudState<Ipv6, EthernetLinkDevice, BC>, &mut Self::SenderCtx<'_>) -> O,
136 >(
137 &mut self,
138 device_id: &EthernetDeviceId<BC>,
139 cb: F,
140 ) -> O {
141 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
142 let (mut nud, mut locked) = core_ctx_and_resource
143 .lock_with_and::<crate::lock_ordering::EthernetIpv6Nud, _>(|c| c.right());
144 let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
145 cb(&mut nud, &mut locked)
146 }
147
148 fn with_nud_state_mut<
149 O,
150 F: FnOnce(&mut NudState<Ipv6, EthernetLinkDevice, BC>, &mut Self::ConfigCtx<'_>) -> O,
151 >(
152 &mut self,
153 device_id: &EthernetDeviceId<BC>,
154 cb: F,
155 ) -> O {
156 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
157 let (mut nud, mut locked) = core_ctx_and_resource
158 .lock_with_and::<crate::lock_ordering::EthernetIpv6Nud, _>(|c| c.right());
159 let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
160 cb(&mut nud, &mut locked)
161 }
162
163 fn with_nud_state<O, F: FnOnce(&NudState<Ipv6, EthernetLinkDevice, BC>) -> O>(
164 &mut self,
165 device_id: &EthernetDeviceId<BC>,
166 cb: F,
167 ) -> O {
168 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
169 let nud = core_ctx_and_resource
170 .lock_with::<crate::lock_ordering::EthernetIpv6Nud, _>(|c| c.right());
171 cb(&nud)
172 }
173
174 fn send_neighbor_solicitation(
175 &mut self,
176 bindings_ctx: &mut BC,
177 device_id: &EthernetDeviceId<BC>,
178 lookup_addr: SpecifiedAddr<Ipv6Addr>,
179 remote_link_addr: Option<Mac>,
180 ) {
181 let dst_ip = match remote_link_addr {
182 Some(_) => lookup_addr,
187 None => lookup_addr.to_solicited_node_address().into_specified(),
188 };
189 let src_ip = IpDeviceEgressStateContext::<Ipv6>::get_local_addr_for_remote(
190 self,
191 &device_id.clone().into(),
192 Some(dst_ip),
193 );
194 let src_ip = match src_ip {
195 Some(s) => s,
196 None => return,
197 };
198
199 let mac = ethernet::get_mac(self, device_id);
200
201 CounterContext::<NdpCounters>::counters(self).tx.neighbor_solicitation.increment();
202 debug!("sending NDP solicitation for {lookup_addr} to {dst_ip}");
203 let _: Result<(), _> = icmp::send_ndp_packet(
206 self,
207 bindings_ctx,
208 &device_id.clone().into(),
209 Some(src_ip.into()),
210 dst_ip,
211 OptionSequenceBuilder::<_>::new(
212 [NdpOptionBuilder::SourceLinkLayerAddress(mac.bytes().as_ref())].iter(),
213 )
214 .into_serializer(),
215 icmp::NdpMessage::NeighborSolicitation {
216 message: NeighborSolicitation::new(lookup_addr.get()),
217 code: IcmpZeroCode,
218 },
219 );
220 }
221}
222
223impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv6>>>
224 NudIcmpContext<Ipv6, EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
225{
226 fn send_icmp_dest_unreachable(
227 &mut self,
228 bindings_ctx: &mut BC,
229 frame: Buf<Vec<u8>>,
230 device_id: Option<&Self::DeviceId>,
231 original_src_ip: SocketIpAddr<Ipv6Addr>,
232 original_dst_ip: SocketIpAddr<Ipv6Addr>,
233 _: (),
234 ) {
235 icmp::send_icmpv6_address_unreachable(
236 self,
237 bindings_ctx,
238 device_id.map(|device_id| device_id.clone().into()).as_ref(),
239 None,
244 original_src_ip,
245 original_dst_ip,
246 frame,
247 &Marks::default(),
253 );
254 }
255}
256
257impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::Ipv6DeviceLearnedParams>>
258 NudConfigContext<Ipv6> for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
259{
260 fn retransmit_timeout(&mut self) -> NonZeroDuration {
261 let Self { device_id, core_ctx } = self;
262 let mut state = integration::device_state(core_ctx, device_id);
263 let mut state = state.cast();
264 let x = state
266 .read_lock::<crate::lock_ordering::Ipv6DeviceLearnedParams>()
267 .retrans_timer_or_default();
268 x
269 }
270
271 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
272 let Self { device_id, core_ctx } = self;
273 let mut state = integration::device_state(core_ctx, device_id);
274 let x = state.read_lock::<crate::lock_ordering::NudConfig<Ipv6>>();
275 cb(&*x)
276 }
277}
278
279impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::AllDeviceSockets>>
280 NudSenderContext<Ipv6, EthernetLinkDevice, BC> for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
281{
282 fn send_ip_packet_to_neighbor_link_addr<S>(
283 &mut self,
284 bindings_ctx: &mut BC,
285 dst_mac: Mac,
286 body: S,
287 meta: BC::TxMetadata,
288 ) -> Result<(), SendFrameError<S>>
289 where
290 S: Serializer,
291 S::Buffer: BufferMut,
292 {
293 let Self { device_id, core_ctx } = self;
294 ethernet::send_as_ethernet_frame_to_dst(
295 *core_ctx,
296 bindings_ctx,
297 device_id,
298 dst_mac,
299 body,
300 EtherType::Ipv6,
301 meta,
302 )
303 }
304}
305
306impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv4>>>
307 ArpContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
308{
309 type ConfigCtx<'a> = CoreCtxWithDeviceId<
310 'a,
311 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv4Arp>>,
312 >;
313
314 type ArpSenderCtx<'a> = CoreCtxWithDeviceId<
315 'a,
316 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv4Arp>>,
317 >;
318
319 fn with_arp_state_mut_and_sender_ctx<
320 O,
321 F: FnOnce(&mut ArpState<EthernetLinkDevice, BC>, &mut Self::ArpSenderCtx<'_>) -> O,
322 >(
323 &mut self,
324 device_id: &EthernetDeviceId<BC>,
325 cb: F,
326 ) -> O {
327 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
328 let (mut arp, mut locked) = core_ctx_and_resource
329 .lock_with_and::<crate::lock_ordering::EthernetIpv4Arp, _>(|c| c.right());
330 let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
331 cb(&mut arp, &mut locked)
332 }
333
334 fn addr_on_interface(&mut self, device_id: &EthernetDeviceId<BC>, addr: Ipv4Addr) -> bool {
335 let mut state = integration::device_state(self, device_id);
336 let mut state = state.cast();
337 let ipv4 = state.read_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>();
338 let x = ipv4.iter().any(|a| {
340 let a: Ipv4Addr = a.addr().get();
341 a == addr
342 });
343 x
344 }
345
346 fn get_protocol_addr(&mut self, device_id: &EthernetDeviceId<BC>) -> Option<Ipv4Addr> {
347 let mut state = integration::device_state(self, device_id);
348 let mut state = state.cast();
349 let ipv4 = state.read_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>();
350 let x = ipv4.iter().next().map(|addr| addr.addr().get());
352 x
353 }
354
355 fn get_hardware_addr(
356 &mut self,
357 _bindings_ctx: &mut BC,
358 device_id: &EthernetDeviceId<BC>,
359 ) -> UnicastAddr<Mac> {
360 ethernet::get_mac(self, device_id)
361 }
362
363 fn with_arp_state_mut<
364 O,
365 F: FnOnce(&mut ArpState<EthernetLinkDevice, BC>, &mut Self::ConfigCtx<'_>) -> O,
366 >(
367 &mut self,
368 device_id: &EthernetDeviceId<BC>,
369 cb: F,
370 ) -> O {
371 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
372 let (mut arp, mut locked) = core_ctx_and_resource
373 .lock_with_and::<crate::lock_ordering::EthernetIpv4Arp, _>(|c| c.right());
374 let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
375 cb(&mut arp, &mut locked)
376 }
377
378 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, BC>) -> O>(
379 &mut self,
380 device_id: &EthernetDeviceId<BC>,
381 cb: F,
382 ) -> O {
383 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
384 let arp = core_ctx_and_resource
385 .lock_with::<crate::lock_ordering::EthernetIpv4Arp, _>(|c| c.right());
386 cb(&arp)
387 }
388}
389
390impl<BT: BindingsTypes, L> UseDelegateNudContext for CoreCtx<'_, BT, L> {}
391impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv4>>>
392 DelegateNudContext<Ipv4> for CoreCtx<'_, BC, L>
393{
394 type Delegate<T> = ArpNudCtx<T>;
395}
396
397impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv4>>>
398 NudIcmpContext<Ipv4, EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
399{
400 fn send_icmp_dest_unreachable(
401 &mut self,
402 bindings_ctx: &mut BC,
403 frame: Buf<Vec<u8>>,
404 device_id: Option<&Self::DeviceId>,
405 original_src_ip: SocketIpAddr<Ipv4Addr>,
406 original_dst_ip: SocketIpAddr<Ipv4Addr>,
407 (header_len, fragment_type): (usize, Ipv4FragmentType),
408 ) {
409 icmp::send_icmpv4_host_unreachable(
410 self,
411 bindings_ctx,
412 device_id.map(|device_id| device_id.clone().into()).as_ref(),
413 None,
418 original_src_ip,
419 original_dst_ip,
420 frame,
421 header_len,
422 fragment_type,
423 &Marks::default(),
429 );
430 }
431}
432
433impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::NudConfig<Ipv4>>> ArpConfigContext
434 for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
435{
436 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
437 let Self { device_id, core_ctx } = self;
438 let mut state = integration::device_state(core_ctx, device_id);
439 let x = state.read_lock::<crate::lock_ordering::NudConfig<Ipv4>>();
440 cb(&*x)
441 }
442}
443
444impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::AllDeviceSockets>>
445 ArpSenderContext<EthernetLinkDevice, BC> for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
446{
447 fn send_ip_packet_to_neighbor_link_addr<S>(
448 &mut self,
449 bindings_ctx: &mut BC,
450 dst_mac: Mac,
451 body: S,
452 meta: BC::TxMetadata,
453 ) -> Result<(), SendFrameError<S>>
454 where
455 S: Serializer,
456 S::Buffer: BufferMut,
457 {
458 let Self { device_id, core_ctx } = self;
459 ethernet::send_as_ethernet_frame_to_dst(
460 *core_ctx,
461 bindings_ctx,
462 device_id,
463 dst_mac,
464 body,
465 EtherType::Ipv4,
466 meta,
467 )
468 }
469}
470
471impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetTxQueue>>
472 TransmitQueueCommon<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
473{
474 type Meta = BC::TxMetadata;
475 type Allocator = BufVecU8Allocator;
476 type Buffer = Buf<Vec<u8>>;
477 type DequeueContext = BC::DequeueContext;
478
479 fn parse_outgoing_frame<'a, 'b>(
480 buf: &'a [u8],
481 _meta: &'b Self::Meta,
482 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
483 SentFrame::try_parse_as_ethernet(buf)
484 }
485}
486
487impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetTxQueue>>
488 TransmitQueueContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
489{
490 fn with_transmit_queue_mut<
491 O,
492 F: FnOnce(&mut TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
493 >(
494 &mut self,
495 device_id: &EthernetDeviceId<BC>,
496 cb: F,
497 ) -> O {
498 let mut state = integration::device_state(self, device_id);
499 let mut x = state.lock::<crate::lock_ordering::EthernetTxQueue>();
500 cb(&mut x)
501 }
502
503 fn with_transmit_queue<
504 O,
505 F: FnOnce(&TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
506 >(
507 &mut self,
508 device_id: &EthernetDeviceId<BC>,
509 cb: F,
510 ) -> O {
511 let mut state = integration::device_state(self, device_id);
512 let x = state.lock::<crate::lock_ordering::EthernetTxQueue>();
513 cb(&x)
514 }
515
516 fn send_frame(
517 &mut self,
518 bindings_ctx: &mut BC,
519 device_id: &Self::DeviceId,
520 dequeue_context: Option<&mut BC::DequeueContext>,
521 _meta: Self::Meta,
522 buf: Self::Buffer,
523 ) -> Result<(), DeviceSendFrameError> {
524 DeviceLayerEventDispatcher::send_ethernet_frame(
525 bindings_ctx,
526 device_id,
527 buf,
528 dequeue_context,
529 )
530 }
531}
532
533impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetTxDequeue>>
534 TransmitDequeueContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
535{
536 type TransmitQueueCtx<'a> =
537 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetTxDequeue>>;
538
539 fn with_dequed_packets_and_tx_queue_ctx<
540 O,
541 F: FnOnce(&mut DequeueState<Self::Meta, Self::Buffer>, &mut Self::TransmitQueueCtx<'_>) -> O,
542 >(
543 &mut self,
544 device_id: &Self::DeviceId,
545 cb: F,
546 ) -> O {
547 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
548 let (mut x, mut locked) = core_ctx_and_resource
549 .lock_with_and::<crate::lock_ordering::EthernetTxDequeue, _>(|c| c.right());
550 cb(&mut x, &mut locked.cast_core_ctx())
551 }
552}
553
554impl<I: Ip, BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
555 for crate::lock_ordering::NudConfig<I>
556{
557 type Data = IpMarked<I, NudUserConfig>;
558}
559
560impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
561 for crate::lock_ordering::EthernetDeviceDynamicState
562{
563 type Data = DynamicEthernetDeviceState;
564}
565
566impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
567 for crate::lock_ordering::EthernetIpv6Nud
568{
569 type Data = NudState<Ipv6, EthernetLinkDevice, BT>;
570}
571
572impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
573 for crate::lock_ordering::EthernetIpv4Arp
574{
575 type Data = ArpState<EthernetLinkDevice, BT>;
576}
577
578impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
579 for crate::lock_ordering::EthernetTxQueue
580{
581 type Data = TransmitQueueState<BT::TxMetadata, Buf<Vec<u8>>, BufVecU8Allocator>;
582}
583
584impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
585 for crate::lock_ordering::EthernetTxDequeue
586{
587 type Data = DequeueState<BT::TxMetadata, Buf<Vec<u8>>>;
588}