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