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::device::AssignedAddressState;
33use netstack3_ip::icmp::{self, NdpCounters};
34use netstack3_ip::nud::{
35 DelegateNudContext, NudConfigContext, NudContext, NudIcmpContext, NudSenderContext, NudState,
36 NudUserConfig, UseDelegateNudContext,
37};
38use netstack3_ip::IpDeviceEgressStateContext;
39use packet::{Buf, BufferMut, InnerPacketBuilder as _, Serializer};
40use packet_formats::ethernet::EtherType;
41use packet_formats::icmp::ndp::options::NdpOptionBuilder;
42use packet_formats::icmp::ndp::{NeighborSolicitation, OptionSequenceBuilder};
43use packet_formats::icmp::IcmpZeroCode;
44use packet_formats::ipv4::Ipv4FragmentType;
45use packet_formats::utils::NonZeroDuration;
46
47use crate::context::prelude::*;
48use crate::context::WrapLockLevel;
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 IcmpZeroCode,
217 NeighborSolicitation::new(lookup_addr.get()),
218 );
219 }
220}
221
222impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv6>>>
223 NudIcmpContext<Ipv6, EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
224{
225 fn send_icmp_dest_unreachable(
226 &mut self,
227 bindings_ctx: &mut BC,
228 frame: Buf<Vec<u8>>,
229 device_id: Option<&Self::DeviceId>,
230 original_src_ip: SocketIpAddr<Ipv6Addr>,
231 original_dst_ip: SocketIpAddr<Ipv6Addr>,
232 _: (),
233 ) {
234 icmp::send_icmpv6_address_unreachable(
235 self,
236 bindings_ctx,
237 device_id.map(|device_id| device_id.clone().into()).as_ref(),
238 None,
243 original_src_ip,
244 original_dst_ip,
245 frame,
246 &Marks::default(),
252 );
253 }
254}
255
256impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::Ipv6DeviceLearnedParams>>
257 NudConfigContext<Ipv6> for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
258{
259 fn retransmit_timeout(&mut self) -> NonZeroDuration {
260 let Self { device_id, core_ctx } = self;
261 let mut state = integration::device_state(core_ctx, device_id);
262 let mut state = state.cast();
263 let x = state
265 .read_lock::<crate::lock_ordering::Ipv6DeviceLearnedParams>()
266 .retrans_timer_or_default();
267 x
268 }
269
270 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
271 let Self { device_id, core_ctx } = self;
272 let mut state = integration::device_state(core_ctx, device_id);
273 let x = state.read_lock::<crate::lock_ordering::NudConfig<Ipv6>>();
274 cb(&*x)
275 }
276}
277
278impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::AllDeviceSockets>>
279 NudSenderContext<Ipv6, EthernetLinkDevice, BC> for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
280{
281 fn send_ip_packet_to_neighbor_link_addr<S>(
282 &mut self,
283 bindings_ctx: &mut BC,
284 dst_mac: Mac,
285 body: S,
286 meta: BC::TxMetadata,
287 ) -> Result<(), SendFrameError<S>>
288 where
289 S: Serializer,
290 S::Buffer: BufferMut,
291 {
292 let Self { device_id, core_ctx } = self;
293 ethernet::send_as_ethernet_frame_to_dst(
294 *core_ctx,
295 bindings_ctx,
296 device_id,
297 dst_mac,
298 body,
299 EtherType::Ipv6,
300 meta,
301 )
302 }
303}
304
305impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv4>>>
306 ArpContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
307{
308 type ConfigCtx<'a> = CoreCtxWithDeviceId<
309 'a,
310 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv4Arp>>,
311 >;
312
313 type ArpSenderCtx<'a> = CoreCtxWithDeviceId<
314 'a,
315 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetIpv4Arp>>,
316 >;
317
318 fn with_arp_state_mut_and_sender_ctx<
319 O,
320 F: FnOnce(&mut ArpState<EthernetLinkDevice, BC>, &mut Self::ArpSenderCtx<'_>) -> O,
321 >(
322 &mut self,
323 device_id: &EthernetDeviceId<BC>,
324 cb: F,
325 ) -> O {
326 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
327 let (mut arp, mut locked) = core_ctx_and_resource
328 .lock_with_and::<crate::lock_ordering::EthernetIpv4Arp, _>(|c| c.right());
329 let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
330 cb(&mut arp, &mut locked)
331 }
332
333 fn addr_on_interface(&mut self, device_id: &EthernetDeviceId<BC>, addr: Ipv4Addr) -> bool {
334 let mut state = integration::device_state(self, device_id);
335 let mut state = state.cast();
336 let ipv4 = state.read_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>();
337 let x = ipv4.iter().map(|addr| addr.addr().addr()).any(|a| a == addr);
339 x
340 }
341
342 fn get_protocol_addr(&mut self, device_id: &EthernetDeviceId<BC>) -> Option<Ipv4Addr> {
343 let mut state = integration::device_state(self, device_id);
344 let mut state = state.cast();
345 let ipv4 = state.read_lock::<crate::lock_ordering::IpDeviceAddresses<Ipv4>>();
346 let x = ipv4.iter().next().map(|addr| addr.addr().addr());
348 x
349 }
350
351 fn get_hardware_addr(
352 &mut self,
353 _bindings_ctx: &mut BC,
354 device_id: &EthernetDeviceId<BC>,
355 ) -> UnicastAddr<Mac> {
356 ethernet::get_mac(self, device_id)
357 }
358
359 fn with_arp_state_mut<
360 O,
361 F: FnOnce(&mut ArpState<EthernetLinkDevice, BC>, &mut Self::ConfigCtx<'_>) -> O,
362 >(
363 &mut self,
364 device_id: &EthernetDeviceId<BC>,
365 cb: F,
366 ) -> O {
367 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
368 let (mut arp, mut locked) = core_ctx_and_resource
369 .lock_with_and::<crate::lock_ordering::EthernetIpv4Arp, _>(|c| c.right());
370 let mut locked = CoreCtxWithDeviceId { device_id, core_ctx: &mut locked.cast_core_ctx() };
371 cb(&mut arp, &mut locked)
372 }
373
374 fn with_arp_state<O, F: FnOnce(&ArpState<EthernetLinkDevice, BC>) -> O>(
375 &mut self,
376 device_id: &EthernetDeviceId<BC>,
377 cb: F,
378 ) -> O {
379 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
380 let arp = core_ctx_and_resource
381 .lock_with::<crate::lock_ordering::EthernetIpv4Arp, _>(|c| c.right());
382 cb(&arp)
383 }
384}
385
386impl<BT: BindingsTypes, L> UseDelegateNudContext for CoreCtx<'_, BT, L> {}
387impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv4>>>
388 DelegateNudContext<Ipv4> for CoreCtx<'_, BC, L>
389{
390 type Delegate<T> = ArpNudCtx<T>;
391}
392
393impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv4>>>
394 NudIcmpContext<Ipv4, EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
395{
396 fn send_icmp_dest_unreachable(
397 &mut self,
398 bindings_ctx: &mut BC,
399 frame: Buf<Vec<u8>>,
400 device_id: Option<&Self::DeviceId>,
401 original_src_ip: SocketIpAddr<Ipv4Addr>,
402 original_dst_ip: SocketIpAddr<Ipv4Addr>,
403 (header_len, fragment_type): (usize, Ipv4FragmentType),
404 ) {
405 icmp::send_icmpv4_host_unreachable(
406 self,
407 bindings_ctx,
408 device_id.map(|device_id| device_id.clone().into()).as_ref(),
409 None,
414 original_src_ip,
415 original_dst_ip,
416 frame,
417 header_len,
418 fragment_type,
419 &Marks::default(),
425 );
426 }
427}
428
429impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::NudConfig<Ipv4>>> ArpConfigContext
430 for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
431{
432 fn with_nud_user_config<O, F: FnOnce(&NudUserConfig) -> O>(&mut self, cb: F) -> O {
433 let Self { device_id, core_ctx } = self;
434 let mut state = integration::device_state(core_ctx, device_id);
435 let x = state.read_lock::<crate::lock_ordering::NudConfig<Ipv4>>();
436 cb(&*x)
437 }
438}
439
440impl<'a, BC: BindingsContext, L: LockBefore<crate::lock_ordering::AllDeviceSockets>>
441 ArpSenderContext<EthernetLinkDevice, BC> for CoreCtxWithDeviceId<'a, CoreCtx<'a, BC, L>>
442{
443 fn send_ip_packet_to_neighbor_link_addr<S>(
444 &mut self,
445 bindings_ctx: &mut BC,
446 dst_mac: Mac,
447 body: S,
448 meta: BC::TxMetadata,
449 ) -> Result<(), SendFrameError<S>>
450 where
451 S: Serializer,
452 S::Buffer: BufferMut,
453 {
454 let Self { device_id, core_ctx } = self;
455 ethernet::send_as_ethernet_frame_to_dst(
456 *core_ctx,
457 bindings_ctx,
458 device_id,
459 dst_mac,
460 body,
461 EtherType::Ipv4,
462 meta,
463 )
464 }
465}
466
467impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetTxQueue>>
468 TransmitQueueCommon<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
469{
470 type Meta = BC::TxMetadata;
471 type Allocator = BufVecU8Allocator;
472 type Buffer = Buf<Vec<u8>>;
473 type DequeueContext = BC::DequeueContext;
474
475 fn parse_outgoing_frame<'a, 'b>(
476 buf: &'a [u8],
477 _meta: &'b Self::Meta,
478 ) -> Result<SentFrame<&'a [u8]>, ParseSentFrameError> {
479 SentFrame::try_parse_as_ethernet(buf)
480 }
481}
482
483impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetTxQueue>>
484 TransmitQueueContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
485{
486 fn with_transmit_queue_mut<
487 O,
488 F: FnOnce(&mut TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
489 >(
490 &mut self,
491 device_id: &EthernetDeviceId<BC>,
492 cb: F,
493 ) -> O {
494 let mut state = integration::device_state(self, device_id);
495 let mut x = state.lock::<crate::lock_ordering::EthernetTxQueue>();
496 cb(&mut x)
497 }
498
499 fn with_transmit_queue<
500 O,
501 F: FnOnce(&TransmitQueueState<Self::Meta, Self::Buffer, Self::Allocator>) -> O,
502 >(
503 &mut self,
504 device_id: &EthernetDeviceId<BC>,
505 cb: F,
506 ) -> O {
507 let mut state = integration::device_state(self, device_id);
508 let x = state.lock::<crate::lock_ordering::EthernetTxQueue>();
509 cb(&x)
510 }
511
512 fn send_frame(
513 &mut self,
514 bindings_ctx: &mut BC,
515 device_id: &Self::DeviceId,
516 dequeue_context: Option<&mut BC::DequeueContext>,
517 _meta: Self::Meta,
518 buf: Self::Buffer,
519 ) -> Result<(), DeviceSendFrameError> {
520 DeviceLayerEventDispatcher::send_ethernet_frame(
521 bindings_ctx,
522 device_id,
523 buf,
524 dequeue_context,
525 )
526 }
527}
528
529impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetTxDequeue>>
530 TransmitDequeueContext<EthernetLinkDevice, BC> for CoreCtx<'_, BC, L>
531{
532 type TransmitQueueCtx<'a> =
533 CoreCtx<'a, BC, WrapLockLevel<crate::lock_ordering::EthernetTxDequeue>>;
534
535 fn with_dequed_packets_and_tx_queue_ctx<
536 O,
537 F: FnOnce(&mut DequeueState<Self::Meta, Self::Buffer>, &mut Self::TransmitQueueCtx<'_>) -> O,
538 >(
539 &mut self,
540 device_id: &Self::DeviceId,
541 cb: F,
542 ) -> O {
543 let mut core_ctx_and_resource = integration::device_state_and_core_ctx(self, device_id);
544 let (mut x, mut locked) = core_ctx_and_resource
545 .lock_with_and::<crate::lock_ordering::EthernetTxDequeue, _>(|c| c.right());
546 cb(&mut x, &mut locked.cast_core_ctx())
547 }
548}
549
550impl<I: Ip, BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
551 for crate::lock_ordering::NudConfig<I>
552{
553 type Data = IpMarked<I, NudUserConfig>;
554}
555
556impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
557 for crate::lock_ordering::EthernetDeviceDynamicState
558{
559 type Data = DynamicEthernetDeviceState;
560}
561
562impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
563 for crate::lock_ordering::EthernetIpv6Nud
564{
565 type Data = NudState<Ipv6, EthernetLinkDevice, BT>;
566}
567
568impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
569 for crate::lock_ordering::EthernetIpv4Arp
570{
571 type Data = ArpState<EthernetLinkDevice, BT>;
572}
573
574impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
575 for crate::lock_ordering::EthernetTxQueue
576{
577 type Data = TransmitQueueState<BT::TxMetadata, Buf<Vec<u8>>, BufVecU8Allocator>;
578}
579
580impl<BT: BindingsTypes> LockLevelFor<IpLinkDeviceState<EthernetLinkDevice, BT>>
581 for crate::lock_ordering::EthernetTxDequeue
582{
583 type Data = DequeueState<BT::TxMetadata, Buf<Vec<u8>>>;
584}