1use alloc::boxed::Box;
8use core::convert::TryInto as _;
9use core::num::NonZeroU8;
10
11use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
12use log::{debug, error, trace};
13use net_types::ip::{
14 GenericOverIp, Ip, IpAddress, IpMarked, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr, Mtu,
15 SubnetError,
16};
17use net_types::{
18 LinkLocalAddress, LinkLocalUnicastAddr, MulticastAddress, SpecifiedAddr, UnicastAddr, Witness,
19};
20use netstack3_base::socket::{AddrIsMappedError, SocketIpAddr, SocketIpAddrExt as _};
21use netstack3_base::sync::Mutex;
22use netstack3_base::{
23 AnyDevice, Counter, CounterContext, DeviceIdContext, EitherDeviceId, FrameDestination,
24 IcmpIpExt, Icmpv4ErrorCode, Icmpv6ErrorCode, InstantBindingsTypes, InstantContext,
25 IpDeviceAddr, IpExt, Marks, RngContext, TokenBucket, TxMetadataBindingsTypes,
26};
27use netstack3_filter::{self as filter, TransportPacketSerializer};
28use packet::{
29 BufferMut, InnerPacketBuilder as _, ParsablePacket as _, ParseBuffer, Serializer,
30 TruncateDirection, TruncatingSerializer,
31};
32use packet_formats::icmp::ndp::options::{NdpOption, NdpOptionBuilder};
33use packet_formats::icmp::ndp::{
34 NdpPacket, NeighborAdvertisement, NonZeroNdpLifetime, OptionSequenceBuilder,
35};
36use packet_formats::icmp::{
37 peek_message_type, IcmpDestUnreachable, IcmpEchoRequest, IcmpMessage, IcmpMessageType,
38 IcmpPacket, IcmpPacketBuilder, IcmpPacketRaw, IcmpParseArgs, IcmpTimeExceeded, IcmpZeroCode,
39 Icmpv4DestUnreachableCode, Icmpv4Packet, Icmpv4ParameterProblem, Icmpv4ParameterProblemCode,
40 Icmpv4TimeExceededCode, Icmpv6DestUnreachableCode, Icmpv6Packet, Icmpv6PacketTooBig,
41 Icmpv6ParameterProblem, Icmpv6ParameterProblemCode, Icmpv6TimeExceededCode, MessageBody,
42 OriginalPacket,
43};
44use packet_formats::ip::{DscpAndEcn, IpPacket, Ipv4Proto, Ipv6Proto};
45use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Header, Ipv4OnlyMeta};
46use packet_formats::ipv6::{ExtHdrParseError, Ipv6Header};
47use zerocopy::SplitByteSlice;
48
49use crate::internal::base::{
50 AddressStatus, IpDeviceIngressStateContext, IpLayerHandler, IpPacketDestination,
51 IpSendFrameError, IpTransportContext, Ipv6PresentAddressStatus, NdpBindingsContext,
52 RouterAdvertisementEvent, SendIpPacketMeta, TransportReceiveError, IPV6_DEFAULT_SUBNET,
53};
54use crate::internal::device::nud::{ConfirmationFlags, NudIpHandler};
55use crate::internal::device::route_discovery::Ipv6DiscoveredRoute;
56use crate::internal::device::{
57 IpAddressState, IpDeviceHandler, Ipv6DeviceHandler, Ipv6LinkLayerAddr,
58};
59use crate::internal::local_delivery::{IpHeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta};
60use crate::internal::path_mtu::PmtuHandler;
61use crate::internal::socket::{
62 DelegatedRouteResolutionOptions, DelegatedSendOptions, IpSocketHandler, OptionDelegationMarker,
63 RouteResolutionOptions, SendOptions,
64};
65
66pub const REQUIRED_NDP_IP_PACKET_HOP_LIMIT: u8 = 255;
78
79pub const DEFAULT_ERRORS_PER_SECOND: u64 = 2 << 16;
83#[derive(GenericOverIp)]
85#[generic_over_ip(I, Ip)]
86pub struct IcmpState<I: IpExt, BT: IcmpBindingsTypes> {
87 error_send_bucket: Mutex<IpMarked<I, TokenBucket<BT::Instant>>>,
88 pub tx_counters: IcmpTxCounters<I>,
90 pub rx_counters: IcmpRxCounters<I>,
92}
93
94impl<I, BT> OrderedLockAccess<IpMarked<I, TokenBucket<BT::Instant>>> for IcmpState<I, BT>
95where
96 I: IpExt,
97 BT: IcmpBindingsTypes,
98{
99 type Lock = Mutex<IpMarked<I, TokenBucket<BT::Instant>>>;
100 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
101 OrderedLockRef::new(&self.error_send_bucket)
102 }
103}
104
105pub type IcmpTxCounters<I> = IpMarked<I, IcmpTxCountersInner>;
107
108#[derive(Default)]
110pub struct IcmpTxCountersInner {
111 pub reply: Counter,
113 pub protocol_unreachable: Counter,
115 pub address_unreachable: Counter,
117 pub port_unreachable: Counter,
119 pub net_unreachable: Counter,
121 pub ttl_expired: Counter,
123 pub packet_too_big: Counter,
125 pub parameter_problem: Counter,
127 pub dest_unreachable: Counter,
129 pub error: Counter,
131}
132
133pub type IcmpRxCounters<I> = IpMarked<I, IcmpRxCountersInner>;
135
136#[derive(Default)]
138pub struct IcmpRxCountersInner {
139 pub error: Counter,
141 pub error_delivered_to_transport_layer: Counter,
143 pub error_delivered_to_socket: Counter,
145 pub echo_request: Counter,
147 pub echo_reply: Counter,
149 pub timestamp_request: Counter,
151 pub dest_unreachable: Counter,
153 pub time_exceeded: Counter,
155 pub parameter_problem: Counter,
157 pub packet_too_big: Counter,
159}
160
161#[derive(Default)]
163pub struct NdpRxCounters {
164 pub neighbor_solicitation: Counter,
166 pub neighbor_advertisement: Counter,
168 pub router_advertisement: Counter,
170 pub router_solicitation: Counter,
172}
173
174#[derive(Default)]
176pub struct NdpTxCounters {
177 pub neighbor_advertisement: Counter,
179 pub neighbor_solicitation: Counter,
181}
182
183#[derive(Default)]
185pub struct NdpCounters {
186 pub rx: NdpRxCounters,
188 pub tx: NdpTxCounters,
190}
191
192#[derive(Copy, Clone)]
194pub struct Icmpv4StateBuilder {
195 send_timestamp_reply: bool,
196 errors_per_second: u64,
197}
198
199impl Default for Icmpv4StateBuilder {
200 fn default() -> Icmpv4StateBuilder {
201 Icmpv4StateBuilder {
202 send_timestamp_reply: false,
203 errors_per_second: DEFAULT_ERRORS_PER_SECOND,
204 }
205 }
206}
207
208impl Icmpv4StateBuilder {
209 pub fn send_timestamp_reply(&mut self, send_timestamp_reply: bool) -> &mut Self {
216 self.send_timestamp_reply = send_timestamp_reply;
217 self
218 }
219
220 pub fn build<BT: IcmpBindingsTypes>(self) -> Icmpv4State<BT> {
222 Icmpv4State {
223 inner: IcmpState {
224 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
225 self.errors_per_second,
226 ))),
227 tx_counters: Default::default(),
228 rx_counters: Default::default(),
229 },
230 send_timestamp_reply: self.send_timestamp_reply,
231 }
232 }
233}
234
235pub struct Icmpv4State<BT: IcmpBindingsTypes> {
237 pub inner: IcmpState<Ipv4, BT>,
239 pub send_timestamp_reply: bool,
241}
242
243impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
244 fn as_ref(&self) -> &IcmpState<Ipv4, BT> {
245 &self.inner
246 }
247}
248
249impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
250 fn as_mut(&mut self) -> &mut IcmpState<Ipv4, BT> {
251 &mut self.inner
252 }
253}
254
255#[derive(Copy, Clone)]
257pub(crate) struct Icmpv6StateBuilder {
258 errors_per_second: u64,
259}
260
261impl Default for Icmpv6StateBuilder {
262 fn default() -> Icmpv6StateBuilder {
263 Icmpv6StateBuilder { errors_per_second: DEFAULT_ERRORS_PER_SECOND }
264 }
265}
266
267impl Icmpv6StateBuilder {
268 pub(crate) fn build<BT: IcmpBindingsTypes>(self) -> Icmpv6State<BT> {
269 Icmpv6State {
270 inner: IcmpState {
271 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
272 self.errors_per_second,
273 ))),
274 tx_counters: Default::default(),
275 rx_counters: Default::default(),
276 },
277 ndp_counters: Default::default(),
278 }
279 }
280}
281
282pub struct Icmpv6State<BT: IcmpBindingsTypes> {
284 pub inner: IcmpState<Ipv6, BT>,
286 pub ndp_counters: NdpCounters,
288}
289
290impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
291 fn as_ref(&self) -> &IcmpState<Ipv6, BT> {
292 &self.inner
293 }
294}
295
296impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
297 fn as_mut(&mut self) -> &mut IcmpState<Ipv6, BT> {
298 &mut self.inner
299 }
300}
301
302pub trait IcmpHandlerIpExt: IpExt {
304 type SourceAddress: Witness<Self::Addr>;
305 type IcmpError;
306
307 fn received_source_as_icmp_source(src: Self::RecvSrcAddr) -> Option<Self::SourceAddress>;
309
310 fn new_ttl_expired<B: SplitByteSlice>(
312 proto: Self::Proto,
313 header_len: usize,
314 meta: <Self::Packet<B> as IpPacket<B, Self>>::VersionSpecificMeta,
315 ) -> Self::IcmpError;
316
317 fn new_mtu_exceeded(proto: Self::Proto, header_len: usize, mtu: Mtu)
319 -> Option<Self::IcmpError>;
320}
321
322impl IcmpHandlerIpExt for Ipv4 {
323 type SourceAddress = SpecifiedAddr<Ipv4Addr>;
324 type IcmpError = Icmpv4Error;
325 fn received_source_as_icmp_source(src: Ipv4Addr) -> Option<SpecifiedAddr<Ipv4Addr>> {
326 SpecifiedAddr::new(src)
327 }
328 fn new_ttl_expired<B: SplitByteSlice>(
329 proto: Ipv4Proto,
330 header_len: usize,
331 Ipv4OnlyMeta { id: _, fragment_type }: Ipv4OnlyMeta,
332 ) -> Icmpv4Error {
333 Icmpv4Error { kind: Icmpv4ErrorKind::TtlExpired { proto, fragment_type }, header_len }
334 }
335 fn new_mtu_exceeded(_proto: Ipv4Proto, _header_len: usize, _mtu: Mtu) -> Option<Icmpv4Error> {
336 None
338 }
339}
340
341impl IcmpHandlerIpExt for Ipv6 {
342 type SourceAddress = UnicastAddr<Ipv6Addr>;
343 type IcmpError = Icmpv6ErrorKind;
344 fn received_source_as_icmp_source(src: Ipv6SourceAddr) -> Option<UnicastAddr<Ipv6Addr>> {
345 match src {
346 Ipv6SourceAddr::Unicast(src) => Some(src.get()),
347 Ipv6SourceAddr::Unspecified => None,
348 }
349 }
350 fn new_ttl_expired<B: SplitByteSlice>(
351 proto: Ipv6Proto,
352 header_len: usize,
353 _meta: (),
354 ) -> Icmpv6ErrorKind {
355 Icmpv6ErrorKind::TtlExpired { proto, header_len }
356 }
357 fn new_mtu_exceeded(proto: Ipv6Proto, header_len: usize, mtu: Mtu) -> Option<Icmpv6ErrorKind> {
358 Some(Icmpv6ErrorKind::PacketTooBig { proto, header_len, mtu })
359 }
360}
361
362pub(crate) enum Icmpv4ErrorKind {
364 ParameterProblem {
365 code: Icmpv4ParameterProblemCode,
366 pointer: u8,
367 fragment_type: Ipv4FragmentType,
368 },
369 TtlExpired {
370 proto: Ipv4Proto,
371 fragment_type: Ipv4FragmentType,
372 },
373 NetUnreachable {
374 proto: Ipv4Proto,
375 fragment_type: Ipv4FragmentType,
376 },
377 ProtocolUnreachable,
378 PortUnreachable,
379}
380
381pub struct Icmpv4Error {
383 pub(super) kind: Icmpv4ErrorKind,
384 pub(super) header_len: usize,
385}
386
387pub enum Icmpv6ErrorKind {
389 ParameterProblem { code: Icmpv6ParameterProblemCode, pointer: u32, allow_dst_multicast: bool },
390 TtlExpired { proto: Ipv6Proto, header_len: usize },
391 NetUnreachable { proto: Ipv6Proto, header_len: usize },
392 PacketTooBig { proto: Ipv6Proto, header_len: usize, mtu: Mtu },
393 ProtocolUnreachable { header_len: usize },
394 PortUnreachable,
395}
396
397pub trait IcmpErrorHandler<I: IcmpHandlerIpExt, BC>: DeviceIdContext<AnyDevice> {
399 fn send_icmp_error_message<B: BufferMut>(
404 &mut self,
405 bindings_ctx: &mut BC,
406 device: &Self::DeviceId,
407 frame_dst: Option<FrameDestination>,
408 src_ip: I::SourceAddress,
409 dst_ip: SpecifiedAddr<I::Addr>,
410 original_packet: B,
411 error: I::IcmpError,
412 marks: &Marks,
413 );
414}
415
416impl<
417 BC: IcmpBindingsContext,
418 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
419 > IcmpErrorHandler<Ipv4, BC> for CC
420{
421 fn send_icmp_error_message<B: BufferMut>(
422 &mut self,
423 bindings_ctx: &mut BC,
424 device: &CC::DeviceId,
425 frame_dst: Option<FrameDestination>,
426 src_ip: SpecifiedAddr<Ipv4Addr>,
427 dst_ip: SpecifiedAddr<Ipv4Addr>,
428 original_packet: B,
429 Icmpv4Error { kind, header_len }: Icmpv4Error,
430 marks: &Marks,
431 ) {
432 let src_ip = SocketIpAddr::new_ipv4_specified(src_ip);
433 let dst_ip = SocketIpAddr::new_ipv4_specified(dst_ip);
434 match kind {
435 Icmpv4ErrorKind::ParameterProblem { code, pointer, fragment_type } => {
436 send_icmpv4_parameter_problem(
437 self,
438 bindings_ctx,
439 device,
440 frame_dst,
441 src_ip,
442 dst_ip,
443 code,
444 Icmpv4ParameterProblem::new(pointer),
445 original_packet,
446 header_len,
447 fragment_type,
448 marks,
449 )
450 }
451 Icmpv4ErrorKind::TtlExpired { proto, fragment_type } => send_icmpv4_ttl_expired(
452 self,
453 bindings_ctx,
454 device,
455 frame_dst,
456 src_ip,
457 dst_ip,
458 proto,
459 original_packet,
460 header_len,
461 fragment_type,
462 marks,
463 ),
464 Icmpv4ErrorKind::NetUnreachable { proto, fragment_type } => {
465 send_icmpv4_net_unreachable(
466 self,
467 bindings_ctx,
468 device,
469 frame_dst,
470 src_ip,
471 dst_ip,
472 proto,
473 original_packet,
474 header_len,
475 fragment_type,
476 marks,
477 )
478 }
479 Icmpv4ErrorKind::ProtocolUnreachable => send_icmpv4_protocol_unreachable(
480 self,
481 bindings_ctx,
482 device,
483 frame_dst,
484 src_ip,
485 dst_ip,
486 original_packet,
487 header_len,
488 marks,
489 ),
490 Icmpv4ErrorKind::PortUnreachable => send_icmpv4_port_unreachable(
491 self,
492 bindings_ctx,
493 device,
494 frame_dst,
495 src_ip,
496 dst_ip,
497 original_packet,
498 header_len,
499 marks,
500 ),
501 }
502 }
503}
504
505impl<
506 BC: IcmpBindingsContext,
507 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
508 > IcmpErrorHandler<Ipv6, BC> for CC
509{
510 fn send_icmp_error_message<B: BufferMut>(
511 &mut self,
512 bindings_ctx: &mut BC,
513 device: &CC::DeviceId,
514 frame_dst: Option<FrameDestination>,
515 src_ip: UnicastAddr<Ipv6Addr>,
516 dst_ip: SpecifiedAddr<Ipv6Addr>,
517 original_packet: B,
518 error: Icmpv6ErrorKind,
519 marks: &Marks,
520 ) {
521 let src_ip: SocketIpAddr<Ipv6Addr> = match src_ip.into_specified().try_into() {
522 Ok(addr) => addr,
523 Err(AddrIsMappedError {}) => {
524 trace!("send_icmpv6_error_message: src_ip is mapped");
525 return;
526 }
527 };
528 let dst_ip: SocketIpAddr<Ipv6Addr> = match dst_ip.try_into() {
529 Ok(addr) => addr,
530 Err(AddrIsMappedError {}) => {
531 trace!("send_icmpv6_error_message: dst_ip is mapped");
532 return;
533 }
534 };
535
536 match error {
537 Icmpv6ErrorKind::ParameterProblem { code, pointer, allow_dst_multicast } => {
538 send_icmpv6_parameter_problem(
539 self,
540 bindings_ctx,
541 device,
542 frame_dst,
543 src_ip,
544 dst_ip,
545 code,
546 Icmpv6ParameterProblem::new(pointer),
547 original_packet,
548 allow_dst_multicast,
549 marks,
550 )
551 }
552 Icmpv6ErrorKind::TtlExpired { proto, header_len } => send_icmpv6_ttl_expired(
553 self,
554 bindings_ctx,
555 device,
556 frame_dst,
557 src_ip,
558 dst_ip,
559 proto,
560 original_packet,
561 header_len,
562 marks,
563 ),
564 Icmpv6ErrorKind::NetUnreachable { proto, header_len } => send_icmpv6_net_unreachable(
565 self,
566 bindings_ctx,
567 device,
568 frame_dst,
569 src_ip,
570 dst_ip,
571 proto,
572 original_packet,
573 header_len,
574 marks,
575 ),
576 Icmpv6ErrorKind::PacketTooBig { proto, header_len, mtu } => send_icmpv6_packet_too_big(
577 self,
578 bindings_ctx,
579 device,
580 frame_dst,
581 src_ip,
582 dst_ip,
583 proto,
584 mtu,
585 original_packet,
586 header_len,
587 marks,
588 ),
589 Icmpv6ErrorKind::ProtocolUnreachable { header_len } => {
590 send_icmpv6_protocol_unreachable(
591 self,
592 bindings_ctx,
593 device,
594 frame_dst,
595 src_ip,
596 dst_ip,
597 original_packet,
598 header_len,
599 marks,
600 )
601 }
602 Icmpv6ErrorKind::PortUnreachable => send_icmpv6_port_unreachable(
603 self,
604 bindings_ctx,
605 device,
606 frame_dst,
607 src_ip,
608 dst_ip,
609 original_packet,
610 marks,
611 ),
612 }
613 }
614}
615
616pub trait IcmpBindingsContext: InstantContext + RngContext + IcmpBindingsTypes {}
619impl<BC> IcmpBindingsContext for BC where
620 BC: InstantContext + RngContext + IcmpBindingsTypes + IcmpBindingsTypes
621{
622}
623
624pub trait IcmpBindingsTypes: InstantBindingsTypes + TxMetadataBindingsTypes {}
626impl<BT: InstantBindingsTypes + TxMetadataBindingsTypes> IcmpBindingsTypes for BT {}
627
628pub trait IcmpStateContext {}
636
637pub trait EchoTransportContextMarker {}
647
648pub trait InnerIcmpContext<I: IpExt, BC: IcmpBindingsTypes>: IpSocketHandler<I, BC> {
651 type EchoTransportContext: IpTransportContext<I, BC, Self> + EchoTransportContextMarker;
654
655 fn receive_icmp_error(
685 &mut self,
686 bindings_ctx: &mut BC,
687 device: &Self::DeviceId,
688 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
689 original_dst_ip: SpecifiedAddr<I::Addr>,
690 original_proto: I::Proto,
691 original_body: &[u8],
692 err: I::ErrorCode,
693 );
694
695 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
698 &mut self,
699 cb: F,
700 ) -> O;
701}
702
703pub trait InnerIcmpv4Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv4, BC> {
707 fn should_send_timestamp_reply(&self) -> bool;
709}
710
711pub trait InnerIcmpv6Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv6, BC> {}
715impl<BC: IcmpBindingsTypes, CC: InnerIcmpContext<Ipv6, BC>> InnerIcmpv6Context<BC> for CC {}
716
717macro_rules! try_send_error {
731 ($core_ctx:expr, $bindings_ctx:expr, $e:expr) => {{
732 let send = $core_ctx.with_error_send_bucket_mut(|error_send_bucket| {
733 error_send_bucket.try_take($bindings_ctx)
734 });
735
736 if send {
737 $core_ctx.counters().error.increment();
738 $e
739 } else {
740 trace!("ip::icmp::try_send_error!: dropping rate-limited ICMP error message");
741 Ok(())
742 }
743 }};
744}
745
746pub enum IcmpIpTransportContext {}
748
749fn receive_ip_transport_icmp_error<
750 I: IpExt,
751 CC: InnerIcmpContext<I, BC> + CounterContext<IcmpRxCounters<I>>,
752 BC: IcmpBindingsContext,
753>(
754 core_ctx: &mut CC,
755 bindings_ctx: &mut BC,
756 device: &CC::DeviceId,
757 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
758 original_dst_ip: SpecifiedAddr<I::Addr>,
759 original_body: &[u8],
760 err: I::ErrorCode,
761) {
762 core_ctx.counters().error_delivered_to_transport_layer.increment();
763 trace!("IcmpIpTransportContext::receive_icmp_error({:?})", err);
764
765 let mut parse_body = original_body;
766 match parse_body.parse::<IcmpPacketRaw<I, _, IcmpEchoRequest>>() {
767 Ok(_echo_request) => (),
770 Err(_) => {
771 return;
775 }
776 }
777
778 <CC::EchoTransportContext as IpTransportContext<I, BC, CC>>::receive_icmp_error(
779 core_ctx,
780 bindings_ctx,
781 device,
782 original_src_ip,
783 original_dst_ip,
784 original_body,
785 err,
786 );
787}
788
789impl<
790 BC: IcmpBindingsContext,
791 CC: InnerIcmpv4Context<BC>
792 + PmtuHandler<Ipv4, BC>
793 + CounterContext<IcmpRxCounters<Ipv4>>
794 + CounterContext<IcmpTxCounters<Ipv4>>,
795 > IpTransportContext<Ipv4, BC, CC> for IcmpIpTransportContext
796{
797 fn receive_icmp_error(
798 core_ctx: &mut CC,
799 bindings_ctx: &mut BC,
800 device: &CC::DeviceId,
801 original_src_ip: Option<SpecifiedAddr<Ipv4Addr>>,
802 original_dst_ip: SpecifiedAddr<Ipv4Addr>,
803 original_body: &[u8],
804 err: Icmpv4ErrorCode,
805 ) {
806 receive_ip_transport_icmp_error(
807 core_ctx,
808 bindings_ctx,
809 device,
810 original_src_ip,
811 original_dst_ip,
812 original_body,
813 err,
814 )
815 }
816
817 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv4>>(
818 core_ctx: &mut CC,
819 bindings_ctx: &mut BC,
820 device: &CC::DeviceId,
821 src_ip: Ipv4Addr,
822 dst_ip: SpecifiedAddr<Ipv4Addr>,
823 mut buffer: B,
824 info: &LocalDeliveryPacketInfo<Ipv4, H>,
825 ) -> Result<(), (B, TransportReceiveError)> {
826 let LocalDeliveryPacketInfo { meta, header_info: _, marks } = info;
827 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
828 if let Some(delivery) = transparent_override {
829 unreachable!(
830 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
831 transparent proxy rules can only be configured for TCP and UDP packets"
832 );
833 }
834
835 trace!(
836 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet({}, {})",
837 src_ip,
838 dst_ip
839 );
840 let packet =
841 match buffer.parse_with::<_, Icmpv4Packet<_>>(IcmpParseArgs::new(src_ip, dst_ip)) {
842 Ok(packet) => packet,
843 Err(_) => return Ok(()), };
845
846 match packet {
847 Icmpv4Packet::EchoRequest(echo_request) => {
848 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_request.increment();
849
850 if let Some(src_ip) = SpecifiedAddr::new(src_ip) {
851 let req = *echo_request.message();
852 let code = echo_request.code();
853 let (local_ip, remote_ip) = (dst_ip, src_ip);
854 debug!(
855 "replying to ICMP echo request from {remote_ip} to {local_ip}%{device:?}: \
856 id={}, seq={}",
857 req.id(),
858 req.seq()
859 );
860 send_icmp_reply(
861 core_ctx,
862 bindings_ctx,
863 device,
864 SocketIpAddr::new_ipv4_specified(remote_ip),
865 SocketIpAddr::new_ipv4_specified(local_ip),
866 |src_ip| {
867 buffer.encapsulate(IcmpPacketBuilder::<Ipv4, _>::new(
868 src_ip,
869 remote_ip,
870 code,
871 req.reply(),
872 ))
873 },
874 &WithMarks(marks),
875 );
876 } else {
877 trace!(
878 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
879 Received echo request with an unspecified source address"
880 );
881 }
882 }
883 Icmpv4Packet::EchoReply(echo_reply) => {
884 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_reply.increment();
885 trace!(
886 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
887 Received an EchoReply message"
888 );
889 let parse_metadata = echo_reply.parse_metadata();
890 buffer.undo_parse(parse_metadata);
891 return <CC::EchoTransportContext
892 as IpTransportContext<Ipv4, BC, CC>>::receive_ip_packet(
893 core_ctx,
894 bindings_ctx,
895 device,
896 src_ip,
897 dst_ip,
898 buffer,
899 info,
900 );
901 }
902 Icmpv4Packet::TimestampRequest(timestamp_request) => {
903 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
904 .timestamp_request
905 .increment();
906 if let Some(src_ip) = SpecifiedAddr::new(src_ip) {
907 if core_ctx.should_send_timestamp_reply() {
908 trace!(
909 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
910 receive_ip_packet: Responding to Timestamp Request message"
911 );
912 const NOW: u32 = 0x80000000;
931 let reply = timestamp_request.message().reply(NOW, NOW);
932 let (local_ip, remote_ip) = (dst_ip, src_ip);
933 buffer.shrink_front_to(0);
940 send_icmp_reply(
941 core_ctx,
942 bindings_ctx,
943 device,
944 SocketIpAddr::new_ipv4_specified(remote_ip),
945 SocketIpAddr::new_ipv4_specified(local_ip),
946 |src_ip| {
947 buffer.encapsulate(IcmpPacketBuilder::<Ipv4, _>::new(
948 src_ip,
949 remote_ip,
950 IcmpZeroCode,
951 reply,
952 ))
953 },
954 &WithMarks(marks),
955 );
956 } else {
957 trace!(
958 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
959 receive_ip_packet: Silently ignoring Timestamp Request message"
960 );
961 }
962 } else {
963 trace!(
964 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
965 receive_ip_packet: Received timestamp request with an unspecified source \
966 address"
967 );
968 }
969 }
970 Icmpv4Packet::TimestampReply(_) => {
971 debug!(
974 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
975 Received unsolicited Timestamp Reply message"
976 );
977 }
978 Icmpv4Packet::DestUnreachable(dest_unreachable) => {
979 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
980 .dest_unreachable
981 .increment();
982 trace!(
983 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
984 Received a Destination Unreachable message"
985 );
986
987 if dest_unreachable.code() == Icmpv4DestUnreachableCode::FragmentationRequired {
988 if let Some(next_hop_mtu) = dest_unreachable.message().next_hop_mtu() {
989 core_ctx.update_pmtu_if_less(
1000 bindings_ctx,
1001 dst_ip.get(),
1002 src_ip,
1003 Mtu::new(u32::from(next_hop_mtu.get())),
1004 );
1005 } else {
1006 let (original_packet_buf, inner_body) = dest_unreachable.body().bytes();
1028 debug_assert!(inner_body.is_none());
1030 if original_packet_buf.len() >= 4 {
1031 let total_len =
1035 u16::from_be_bytes(original_packet_buf[2..4].try_into().unwrap());
1036
1037 trace!(
1038 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1039 receive_ip_packet: Next-Hop MTU is 0 so using the next best PMTU \
1040 value from {total_len}"
1041 );
1042
1043 core_ctx.update_pmtu_next_lower(
1044 bindings_ctx,
1045 dst_ip.get(),
1046 src_ip,
1047 Mtu::new(u32::from(total_len)),
1048 );
1049 } else {
1050 trace!(
1055 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1056 receive_ip_packet: Original packet buf is too small to get \
1057 original packet len so ignoring"
1058 );
1059 }
1060 }
1061 }
1062
1063 receive_icmpv4_error(
1064 core_ctx,
1065 bindings_ctx,
1066 device,
1067 &dest_unreachable,
1068 Icmpv4ErrorCode::DestUnreachable(dest_unreachable.code()),
1069 );
1070 }
1071 Icmpv4Packet::TimeExceeded(time_exceeded) => {
1072 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1073 .time_exceeded
1074 .increment();
1075 trace!(
1076 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1077 Received a Time Exceeded message"
1078 );
1079
1080 receive_icmpv4_error(
1081 core_ctx,
1082 bindings_ctx,
1083 device,
1084 &time_exceeded,
1085 Icmpv4ErrorCode::TimeExceeded(time_exceeded.code()),
1086 );
1087 }
1088 Icmpv4Packet::Redirect(_) => {
1090 debug!(
1091 "Unimplemented: <IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1092 receive_ip_packet::redirect"
1093 )
1094 }
1095 Icmpv4Packet::ParameterProblem(parameter_problem) => {
1096 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1097 .parameter_problem
1098 .increment();
1099 trace!(
1100 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1101 Received a Parameter Problem message"
1102 );
1103
1104 receive_icmpv4_error(
1105 core_ctx,
1106 bindings_ctx,
1107 device,
1108 ¶meter_problem,
1109 Icmpv4ErrorCode::ParameterProblem(parameter_problem.code()),
1110 );
1111 }
1112 }
1113
1114 Ok(())
1115 }
1116}
1117
1118pub fn send_ndp_packet<BC, CC, S, M>(
1120 core_ctx: &mut CC,
1121 bindings_ctx: &mut BC,
1122 device_id: &CC::DeviceId,
1123 src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1124 dst_ip: SpecifiedAddr<Ipv6Addr>,
1125 body: S,
1126 code: M::Code,
1127 message: M,
1128) -> Result<(), IpSendFrameError<S>>
1129where
1130 CC: IpLayerHandler<Ipv6, BC>,
1131 S: Serializer,
1132 S::Buffer: BufferMut,
1133 M: filter::IcmpMessage<Ipv6>,
1134{
1135 IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
1137 core_ctx,
1138 bindings_ctx,
1139 SendIpPacketMeta {
1140 device: device_id,
1141 src_ip,
1142 dst_ip,
1143 destination: IpPacketDestination::from_addr(dst_ip),
1144 ttl: NonZeroU8::new(REQUIRED_NDP_IP_PACKET_HOP_LIMIT),
1145 proto: Ipv6Proto::Icmpv6,
1146 mtu: Mtu::no_limit(),
1147 dscp_and_ecn: DscpAndEcn::default(),
1148 },
1149 body.encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
1150 src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
1151 dst_ip.get(),
1152 code,
1153 message,
1154 )),
1155 )
1156 .map_err(|s| s.into_inner())
1157}
1158
1159fn send_neighbor_advertisement<
1160 BC,
1161 CC: Ipv6DeviceHandler<BC>
1162 + IpDeviceHandler<Ipv6, BC>
1163 + IpLayerHandler<Ipv6, BC>
1164 + CounterContext<NdpCounters>,
1165>(
1166 core_ctx: &mut CC,
1167 bindings_ctx: &mut BC,
1168 device_id: &CC::DeviceId,
1169 solicited: bool,
1170 device_addr: UnicastAddr<Ipv6Addr>,
1171 dst_ip: SpecifiedAddr<Ipv6Addr>,
1172) {
1173 core_ctx.counters().tx.neighbor_advertisement.increment();
1174 debug!("send_neighbor_advertisement from {:?} to {:?}", device_addr, dst_ip);
1175 debug_assert!(dst_ip.is_valid_unicast() || (!solicited && dst_ip.is_multicast()));
1182
1183 let src_ll = core_ctx.get_link_layer_addr(&device_id);
1190
1191 let advertisement = NeighborAdvertisement::new(
1193 core_ctx.is_router_device(&device_id),
1194 solicited,
1195 false,
1196 device_addr.get(),
1197 );
1198 let _: Result<(), _> = send_ndp_packet(
1199 core_ctx,
1200 bindings_ctx,
1201 &device_id,
1202 Some(device_addr.into_specified()),
1203 dst_ip,
1204 OptionSequenceBuilder::new(
1205 src_ll
1206 .as_ref()
1207 .map(Ipv6LinkLayerAddr::as_bytes)
1208 .map(NdpOptionBuilder::TargetLinkLayerAddress)
1209 .iter(),
1210 )
1211 .into_serializer(),
1212 IcmpZeroCode,
1213 advertisement,
1214 );
1215}
1216
1217fn receive_ndp_packet<
1218 B: SplitByteSlice,
1219 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1220 CC: InnerIcmpv6Context<BC>
1221 + Ipv6DeviceHandler<BC>
1222 + IpDeviceHandler<Ipv6, BC>
1223 + IpDeviceIngressStateContext<Ipv6>
1224 + NudIpHandler<Ipv6, BC>
1225 + IpLayerHandler<Ipv6, BC>
1226 + CounterContext<NdpCounters>,
1227>(
1228 core_ctx: &mut CC,
1229 bindings_ctx: &mut BC,
1230 device_id: &CC::DeviceId,
1231 src_ip: Ipv6SourceAddr,
1232 packet: NdpPacket<B>,
1233) {
1234 match packet {
1238 NdpPacket::RouterSolicitation(_) | NdpPacket::Redirect(_) => {}
1239 NdpPacket::NeighborSolicitation(ref p) => {
1240 let target_address = p.message().target_address();
1241 let target_address = match UnicastAddr::new(*target_address) {
1242 Some(a) => a,
1243 None => {
1244 trace!(
1245 "dropping NS from {} with non-unicast target={:?}",
1246 src_ip,
1247 target_address
1248 );
1249 return;
1250 }
1251 };
1252
1253 core_ctx.counters().rx.neighbor_solicitation.increment();
1254
1255 match src_ip {
1256 Ipv6SourceAddr::Unspecified => {
1257 match Ipv6DeviceHandler::handle_received_dad_neighbor_solicitation(
1267 core_ctx,
1268 bindings_ctx,
1269 &device_id,
1270 target_address,
1271 p.body().iter().find_map(|option| option.nonce()),
1272 ) {
1273 IpAddressState::Assigned => {
1274 send_neighbor_advertisement(
1278 core_ctx,
1279 bindings_ctx,
1280 &device_id,
1281 false,
1282 target_address,
1283 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified(),
1284 );
1285 }
1286 IpAddressState::Tentative => {
1287 }
1290 IpAddressState::Unavailable => {
1291 }
1294 }
1295
1296 return;
1297 }
1298 Ipv6SourceAddr::Unicast(src_ip) => {
1299 match core_ctx
1301 .address_status_for_device(target_address.into_specified(), device_id)
1302 {
1303 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned) => {}
1304 AddressStatus::Present(
1305 Ipv6PresentAddressStatus::UnicastTentative
1306 | Ipv6PresentAddressStatus::Multicast,
1307 )
1308 | AddressStatus::Unassigned => {
1309 return;
1313 }
1314 }
1315
1316 let link_addr = p.body().iter().find_map(|o| o.source_link_layer_address());
1317
1318 if let Some(link_addr) = link_addr {
1319 NudIpHandler::handle_neighbor_probe(
1320 core_ctx,
1321 bindings_ctx,
1322 &device_id,
1323 src_ip.into_specified(),
1324 link_addr,
1325 );
1326 }
1327
1328 send_neighbor_advertisement(
1329 core_ctx,
1330 bindings_ctx,
1331 &device_id,
1332 true,
1333 target_address,
1334 src_ip.into_specified(),
1335 );
1336 }
1337 }
1338 }
1339 NdpPacket::NeighborAdvertisement(ref p) => {
1340 let target_address = p.message().target_address();
1344
1345 let src_ip = match src_ip {
1346 Ipv6SourceAddr::Unicast(src_ip) => src_ip,
1347 Ipv6SourceAddr::Unspecified => {
1348 trace!("dropping NA with unspecified source and target = {:?}", target_address);
1349 return;
1350 }
1351 };
1352
1353 let target_address = match UnicastAddr::new(*target_address) {
1354 Some(a) => a,
1355 None => {
1356 trace!(
1357 "dropping NA from {} with non-unicast target={:?}",
1358 src_ip,
1359 target_address
1360 );
1361 return;
1362 }
1363 };
1364
1365 core_ctx.counters().rx.neighbor_advertisement.increment();
1366
1367 match Ipv6DeviceHandler::handle_received_neighbor_advertisement(
1368 core_ctx,
1369 bindings_ctx,
1370 &device_id,
1371 target_address,
1372 ) {
1373 IpAddressState::Assigned => {
1374 error!(
1392 "NA from {src_ip} with target address {target_address} that is also \
1393 assigned on device {device_id:?}",
1394 );
1395 }
1396 IpAddressState::Tentative => {
1397 return;
1400 }
1401 IpAddressState::Unavailable => {
1402 }
1406 }
1407
1408 let link_addr = p.body().iter().find_map(|o| o.target_link_layer_address());
1409 let link_addr = match link_addr {
1410 Some(a) => a,
1411 None => {
1412 trace!(
1413 "dropping NA from {} targetting {} with no TLL option",
1414 src_ip,
1415 target_address
1416 );
1417 return;
1418 }
1419 };
1420
1421 NudIpHandler::handle_neighbor_confirmation(
1422 core_ctx,
1423 bindings_ctx,
1424 &device_id,
1425 target_address.into_specified(),
1426 link_addr,
1427 ConfirmationFlags {
1428 solicited_flag: p.message().solicited_flag(),
1429 override_flag: p.message().override_flag(),
1430 },
1431 );
1432 }
1433 NdpPacket::RouterAdvertisement(ref p) => {
1434 let src_ip = match src_ip {
1447 Ipv6SourceAddr::Unicast(ip) => match LinkLocalUnicastAddr::new(*ip) {
1448 Some(ip) => ip,
1449 None => return,
1450 },
1451 Ipv6SourceAddr::Unspecified => return,
1452 };
1453
1454 let ra = p.message();
1455 debug!("received router advertisement from {:?}: {:?}", src_ip, ra);
1456 core_ctx.counters().rx.router_advertisement.increment();
1457
1458 if let Some(retransmit_timer) = ra.retransmit_timer() {
1465 Ipv6DeviceHandler::set_discovered_retrans_timer(
1466 core_ctx,
1467 bindings_ctx,
1468 &device_id,
1469 retransmit_timer,
1470 );
1471 }
1472
1473 if let Some(hop_limit) = ra.current_hop_limit() {
1480 trace!("receive_ndp_packet: NDP RA: updating device's hop limit to {:?} for router: {:?}", ra.current_hop_limit(), src_ip);
1481 IpDeviceHandler::set_default_hop_limit(core_ctx, &device_id, hop_limit);
1482 }
1483
1484 Ipv6DeviceHandler::update_discovered_ipv6_route(
1486 core_ctx,
1487 bindings_ctx,
1488 &device_id,
1489 Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) },
1490 p.message().router_lifetime().map(NonZeroNdpLifetime::Finite),
1491 );
1492
1493 for option in p.body().iter() {
1494 match option {
1495 NdpOption::TargetLinkLayerAddress(_)
1496 | NdpOption::RedirectedHeader { .. }
1497 | NdpOption::RecursiveDnsServer(_)
1498 | NdpOption::Nonce(_) => {}
1499 NdpOption::SourceLinkLayerAddress(addr) => {
1500 debug!("processing SourceLinkLayerAddress option in RA: {:?}", addr);
1501 NudIpHandler::handle_neighbor_probe(
1527 core_ctx,
1528 bindings_ctx,
1529 &device_id,
1530 {
1531 let src_ip: UnicastAddr<_> = src_ip.into_addr();
1532 src_ip.into_specified()
1533 },
1534 addr,
1535 );
1536 }
1537 NdpOption::PrefixInformation(prefix_info) => {
1538 debug!("processing Prefix Information option in RA: {:?}", prefix_info);
1539 if prefix_info.prefix().is_link_local() {
1557 continue;
1558 }
1559
1560 let subnet = match prefix_info.subnet() {
1561 Ok(subnet) => subnet,
1562 Err(err) => match err {
1563 SubnetError::PrefixTooLong | SubnetError::HostBitsSet => continue,
1564 },
1565 };
1566
1567 match UnicastAddr::new(subnet.network()) {
1568 Some(UnicastAddr { .. }) => {}
1569 None => continue,
1570 }
1571
1572 let valid_lifetime = prefix_info.valid_lifetime();
1573
1574 if prefix_info.on_link_flag() {
1575 Ipv6DeviceHandler::update_discovered_ipv6_route(
1577 core_ctx,
1578 bindings_ctx,
1579 &device_id,
1580 Ipv6DiscoveredRoute { subnet, gateway: None },
1581 valid_lifetime,
1582 )
1583 }
1584
1585 if prefix_info.autonomous_address_configuration_flag() {
1586 Ipv6DeviceHandler::apply_slaac_update(
1587 core_ctx,
1588 bindings_ctx,
1589 &device_id,
1590 subnet,
1591 prefix_info.preferred_lifetime(),
1592 valid_lifetime,
1593 );
1594 }
1595 }
1596 NdpOption::RouteInformation(rio) => {
1597 debug!("processing Route Information option in RA: {:?}", rio);
1598 Ipv6DeviceHandler::update_discovered_ipv6_route(
1600 core_ctx,
1601 bindings_ctx,
1602 &device_id,
1603 Ipv6DiscoveredRoute {
1604 subnet: rio.prefix().clone(),
1605 gateway: Some(src_ip),
1606 },
1607 rio.route_lifetime(),
1608 )
1609 }
1610 NdpOption::Mtu(mtu) => {
1611 debug!("processing MTU option in RA: {:?}", mtu);
1612 Ipv6DeviceHandler::set_link_mtu(core_ctx, &device_id, Mtu::new(mtu));
1616 }
1617 }
1618 }
1619
1620 bindings_ctx.on_event(RouterAdvertisementEvent {
1621 options_bytes: Box::from(p.body().bytes()),
1622 source: **src_ip,
1623 device: device_id.clone(),
1624 });
1625 }
1626 }
1627}
1628
1629impl<
1630 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1631 CC: InnerIcmpv6Context<BC>
1632 + InnerIcmpContext<Ipv6, BC>
1633 + Ipv6DeviceHandler<BC>
1634 + IpDeviceHandler<Ipv6, BC>
1635 + IpDeviceIngressStateContext<Ipv6>
1636 + PmtuHandler<Ipv6, BC>
1637 + NudIpHandler<Ipv6, BC>
1638 + IpLayerHandler<Ipv6, BC>
1639 + CounterContext<IcmpRxCounters<Ipv6>>
1640 + CounterContext<IcmpTxCounters<Ipv6>>
1641 + CounterContext<NdpCounters>,
1642 > IpTransportContext<Ipv6, BC, CC> for IcmpIpTransportContext
1643{
1644 fn receive_icmp_error(
1645 core_ctx: &mut CC,
1646 bindings_ctx: &mut BC,
1647 device: &CC::DeviceId,
1648 original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1649 original_dst_ip: SpecifiedAddr<Ipv6Addr>,
1650 original_body: &[u8],
1651 err: Icmpv6ErrorCode,
1652 ) {
1653 receive_ip_transport_icmp_error(
1654 core_ctx,
1655 bindings_ctx,
1656 device,
1657 original_src_ip,
1658 original_dst_ip,
1659 original_body,
1660 err,
1661 )
1662 }
1663
1664 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
1665 core_ctx: &mut CC,
1666 bindings_ctx: &mut BC,
1667 device: &CC::DeviceId,
1668 src_ip: Ipv6SourceAddr,
1669 dst_ip: SpecifiedAddr<Ipv6Addr>,
1670 mut buffer: B,
1671 info: &LocalDeliveryPacketInfo<Ipv6, H>,
1672 ) -> Result<(), (B, TransportReceiveError)> {
1673 let LocalDeliveryPacketInfo { meta, header_info, marks } = info;
1674 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
1675 if let Some(delivery) = transparent_override {
1676 unreachable!(
1677 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
1678 transparent proxy rules can only be configured for TCP and UDP packets"
1679 );
1680 }
1681
1682 trace!(
1683 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet({:?}, {})",
1684 src_ip,
1685 dst_ip
1686 );
1687
1688 let packet = match buffer
1689 .parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(src_ip.get(), dst_ip))
1690 {
1691 Ok(packet) => packet,
1692 Err(_) => return Ok(()), };
1694
1695 match packet {
1696 Icmpv6Packet::EchoRequest(echo_request) => {
1697 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_request.increment();
1698
1699 if let Some(src_ip) = SocketIpAddr::new_from_ipv6_source(src_ip) {
1700 match SocketIpAddr::try_from(dst_ip) {
1701 Ok(dst_ip) => {
1702 let req = *echo_request.message();
1703 let code = echo_request.code();
1704 let (local_ip, remote_ip) = (dst_ip, src_ip);
1705 debug!(
1706 "replying to ICMP echo request from {remote_ip}: id={}, seq={}",
1707 req.id(),
1708 req.seq()
1709 );
1710 send_icmp_reply(
1711 core_ctx,
1712 bindings_ctx,
1713 device,
1714 remote_ip,
1715 local_ip,
1716 |src_ip| {
1717 buffer.encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
1718 src_ip,
1719 remote_ip.addr(),
1720 code,
1721 req.reply(),
1722 ))
1723 },
1724 &WithMarks(marks),
1725 );
1726 }
1727 Err(AddrIsMappedError {}) => {
1728 trace!("IpTransportContext<Ipv6>::receive_ip_packet: Received echo request with an ipv4-mapped-ipv6 destination address");
1729 }
1730 }
1731 } else {
1732 trace!("<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received echo request with an unspecified source address");
1733 }
1734 }
1735 Icmpv6Packet::EchoReply(echo_reply) => {
1736 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_reply.increment();
1737 trace!("<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received an EchoReply message");
1738 let parse_metadata = echo_reply.parse_metadata();
1739 buffer.undo_parse(parse_metadata);
1740 return <CC::EchoTransportContext
1741 as IpTransportContext<Ipv6, BC, CC>>::receive_ip_packet(
1742 core_ctx,
1743 bindings_ctx,
1744 device,
1745 src_ip,
1746 dst_ip,
1747 buffer,
1748 info
1749 );
1750 }
1751 Icmpv6Packet::Ndp(packet) => {
1752 receive_ndp_packet(core_ctx, bindings_ctx, device, src_ip, packet)
1753 }
1754 Icmpv6Packet::PacketTooBig(packet_too_big) => {
1755 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
1756 .packet_too_big
1757 .increment();
1758 trace!("<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received a Packet Too Big message");
1759 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
1760 core_ctx.update_pmtu_if_less(
1770 bindings_ctx,
1771 dst_ip.get(),
1772 src_ip.get(),
1773 Mtu::new(packet_too_big.message().mtu()),
1774 );
1775 }
1776 receive_icmpv6_error(
1777 core_ctx,
1778 bindings_ctx,
1779 device,
1780 &packet_too_big,
1781 Icmpv6ErrorCode::PacketTooBig,
1782 );
1783 }
1784 Icmpv6Packet::Mld(packet) => {
1785 core_ctx.receive_mld_packet(
1786 bindings_ctx,
1787 &device,
1788 src_ip,
1789 dst_ip,
1790 packet,
1791 header_info,
1792 );
1793 }
1794 Icmpv6Packet::DestUnreachable(dest_unreachable) => receive_icmpv6_error(
1795 core_ctx,
1796 bindings_ctx,
1797 device,
1798 &dest_unreachable,
1799 Icmpv6ErrorCode::DestUnreachable(dest_unreachable.code()),
1800 ),
1801 Icmpv6Packet::TimeExceeded(time_exceeded) => receive_icmpv6_error(
1802 core_ctx,
1803 bindings_ctx,
1804 device,
1805 &time_exceeded,
1806 Icmpv6ErrorCode::TimeExceeded(time_exceeded.code()),
1807 ),
1808 Icmpv6Packet::ParameterProblem(parameter_problem) => receive_icmpv6_error(
1809 core_ctx,
1810 bindings_ctx,
1811 device,
1812 ¶meter_problem,
1813 Icmpv6ErrorCode::ParameterProblem(parameter_problem.code()),
1814 ),
1815 }
1816
1817 Ok(())
1818 }
1819}
1820
1821#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1822struct WithMarks<'a>(&'a Marks);
1823
1824impl<'a> OptionDelegationMarker for WithMarks<'a> {}
1825
1826impl<'a, I: IpExt> DelegatedRouteResolutionOptions<I> for WithMarks<'a> {
1827 fn marks(&self) -> &Marks {
1828 let Self(marks) = self;
1829 marks
1830 }
1831}
1832
1833impl<'a, I: IpExt> DelegatedSendOptions<I> for WithMarks<'a> {}
1834
1835fn send_icmp_reply<I, BC, CC, S, F, O>(
1846 core_ctx: &mut CC,
1847 bindings_ctx: &mut BC,
1848 device: &CC::DeviceId,
1849 original_src_ip: SocketIpAddr<I::Addr>,
1850 original_dst_ip: SocketIpAddr<I::Addr>,
1851 get_body_from_src_ip: F,
1852 ip_options: &O,
1853) where
1854 I: IpExt,
1855 CC: IpSocketHandler<I, BC> + DeviceIdContext<AnyDevice> + CounterContext<IcmpTxCounters<I>>,
1856 BC: TxMetadataBindingsTypes,
1857 S: TransportPacketSerializer<I>,
1858 S::Buffer: BufferMut,
1859 F: FnOnce(SpecifiedAddr<I::Addr>) -> S,
1860 O: SendOptions<I> + RouteResolutionOptions<I>,
1861{
1862 trace!("send_icmp_reply({:?}, {}, {})", device, original_src_ip, original_dst_ip);
1863 core_ctx.counters().reply.increment();
1864 let tx_metadata: BC::TxMetadata = Default::default();
1865
1866 let egress_device = (original_dst_ip.as_ref().is_multicast()
1870 || original_dst_ip.as_ref().must_have_zone())
1871 .then_some(EitherDeviceId::Strong(device));
1872
1873 core_ctx
1874 .send_oneshot_ip_packet(
1875 bindings_ctx,
1876 egress_device,
1877 IpDeviceAddr::new_from_socket_ip_addr(original_dst_ip),
1878 original_src_ip,
1879 I::ICMP_IP_PROTO,
1880 ip_options,
1881 tx_metadata,
1882 |src_ip| get_body_from_src_ip(src_ip.into()),
1883 )
1884 .unwrap_or_else(|err| {
1885 debug!("failed to send ICMP reply: {}", err);
1886 })
1887}
1888
1889fn receive_icmpv4_error<
1894 BC: IcmpBindingsContext,
1895 CC: InnerIcmpv4Context<BC>,
1896 B: SplitByteSlice,
1897 M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>,
1898>(
1899 core_ctx: &mut CC,
1900 bindings_ctx: &mut BC,
1901 device: &CC::DeviceId,
1902 packet: &IcmpPacket<Ipv4, B, M>,
1903 err: Icmpv4ErrorCode,
1904) {
1905 packet.with_original_packet(|res| match res {
1906 Ok(original_packet) => {
1907 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
1908 Some(ip) => ip,
1909 None => {
1910 trace!("receive_icmpv4_error: Got ICMP error message whose original IPv4 packet contains an unspecified destination address; discarding");
1911 return;
1912 },
1913 };
1914 InnerIcmpContext::receive_icmp_error(
1915 core_ctx,
1916 bindings_ctx,
1917 device,
1918 SpecifiedAddr::new(original_packet.src_ip()),
1919 dst_ip,
1920 original_packet.proto(),
1921 original_packet.body().into_inner(),
1922 err,
1923 );
1924 }
1925 Err(_) => debug!(
1926 "receive_icmpv4_error: Got ICMP error message with unparsable original IPv4 packet"
1927 ),
1928 })
1929}
1930
1931fn receive_icmpv6_error<
1936 BC: IcmpBindingsContext,
1937 CC: InnerIcmpv6Context<BC>,
1938 B: SplitByteSlice,
1939 M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>,
1940>(
1941 core_ctx: &mut CC,
1942 bindings_ctx: &mut BC,
1943 device: &CC::DeviceId,
1944 packet: &IcmpPacket<Ipv6, B, M>,
1945 err: Icmpv6ErrorCode,
1946) {
1947 packet.with_original_packet(|res| match res {
1948 Ok(original_packet) => {
1949 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
1950 Some(ip)=>ip,
1951 None => {
1952 trace!("receive_icmpv6_error: Got ICMP error message whose original IPv6 packet contains an unspecified destination address; discarding");
1953 return;
1954 },
1955 };
1956 match original_packet.body_proto() {
1957 Ok((body, proto)) => {
1958 InnerIcmpContext::receive_icmp_error(
1959 core_ctx,
1960 bindings_ctx,
1961 device,
1962 SpecifiedAddr::new(original_packet.src_ip()),
1963 dst_ip,
1964 proto,
1965 body.into_inner(),
1966 err,
1967 );
1968 }
1969 Err(ExtHdrParseError) => {
1970 trace!("receive_icmpv6_error: We could not parse the original packet's extension headers, and so we don't know where the original packet's body begins; discarding");
1971 return;
1974 }
1975 }
1976 }
1977 Err(_body) => debug!(
1978 "receive_icmpv6_error: Got ICMPv6 error message with unparsable original IPv6 packet"
1979 ),
1980 })
1981}
1982
1983pub fn send_icmpv4_host_unreachable<
2001 B: BufferMut,
2002 BC: IcmpBindingsContext,
2003 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2004>(
2005 core_ctx: &mut CC,
2006 bindings_ctx: &mut BC,
2007 device: Option<&CC::DeviceId>,
2008 frame_dst: Option<FrameDestination>,
2009 src_ip: SocketIpAddr<Ipv4Addr>,
2010 dst_ip: SocketIpAddr<Ipv4Addr>,
2011 original_packet: B,
2012 header_len: usize,
2013 fragment_type: Ipv4FragmentType,
2014 marks: &Marks,
2015) {
2016 core_ctx.counters().address_unreachable.increment();
2017
2018 send_icmpv4_dest_unreachable(
2019 core_ctx,
2020 bindings_ctx,
2021 device,
2022 frame_dst,
2023 src_ip,
2024 dst_ip,
2025 Icmpv4DestUnreachableCode::DestHostUnreachable,
2026 original_packet,
2027 header_len,
2028 fragment_type,
2029 marks,
2030 );
2031}
2032
2033pub fn send_icmpv6_address_unreachable<
2044 B: BufferMut,
2045 BC: IcmpBindingsContext,
2046 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2047>(
2048 core_ctx: &mut CC,
2049 bindings_ctx: &mut BC,
2050 device: Option<&CC::DeviceId>,
2051 frame_dst: Option<FrameDestination>,
2052 src_ip: SocketIpAddr<Ipv6Addr>,
2053 dst_ip: SocketIpAddr<Ipv6Addr>,
2054 original_packet: B,
2055 marks: &Marks,
2056) {
2057 core_ctx.counters().address_unreachable.increment();
2058
2059 send_icmpv6_dest_unreachable(
2060 core_ctx,
2061 bindings_ctx,
2062 device,
2063 frame_dst,
2064 src_ip,
2065 dst_ip,
2066 Icmpv6DestUnreachableCode::AddrUnreachable,
2067 original_packet,
2068 marks,
2069 );
2070}
2071
2072pub(crate) fn send_icmpv4_protocol_unreachable<
2084 B: BufferMut,
2085 BC: IcmpBindingsContext,
2086 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2087>(
2088 core_ctx: &mut CC,
2089 bindings_ctx: &mut BC,
2090 device: &CC::DeviceId,
2091 frame_dst: Option<FrameDestination>,
2092 src_ip: SocketIpAddr<Ipv4Addr>,
2093 dst_ip: SocketIpAddr<Ipv4Addr>,
2094 original_packet: B,
2095 header_len: usize,
2096 marks: &Marks,
2097) {
2098 core_ctx.counters().protocol_unreachable.increment();
2099
2100 send_icmpv4_dest_unreachable(
2101 core_ctx,
2102 bindings_ctx,
2103 Some(device),
2104 frame_dst,
2105 src_ip,
2106 dst_ip,
2107 Icmpv4DestUnreachableCode::DestProtocolUnreachable,
2108 original_packet,
2109 header_len,
2110 Ipv4FragmentType::InitialFragment,
2116 marks,
2117 );
2118}
2119
2120pub(crate) fn send_icmpv6_protocol_unreachable<
2130 B: BufferMut,
2131 BC: IcmpBindingsContext,
2132 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2133>(
2134 core_ctx: &mut CC,
2135 bindings_ctx: &mut BC,
2136 device: &CC::DeviceId,
2137 frame_dst: Option<FrameDestination>,
2138 src_ip: SocketIpAddr<Ipv6Addr>,
2139 dst_ip: SocketIpAddr<Ipv6Addr>,
2140 original_packet: B,
2141 header_len: usize,
2142 marks: &Marks,
2143) {
2144 core_ctx.counters().protocol_unreachable.increment();
2145
2146 send_icmpv6_parameter_problem(
2147 core_ctx,
2148 bindings_ctx,
2149 device,
2150 frame_dst,
2151 src_ip,
2152 dst_ip,
2153 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2154 Icmpv6ParameterProblem::new(header_len as u32),
2168 original_packet,
2169 false,
2170 marks,
2171 );
2172}
2173
2174pub(crate) fn send_icmpv4_port_unreachable<
2186 B: BufferMut,
2187 BC: IcmpBindingsContext,
2188 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2189>(
2190 core_ctx: &mut CC,
2191 bindings_ctx: &mut BC,
2192 device: &CC::DeviceId,
2193 frame_dst: Option<FrameDestination>,
2194 src_ip: SocketIpAddr<Ipv4Addr>,
2195 dst_ip: SocketIpAddr<Ipv4Addr>,
2196 original_packet: B,
2197 header_len: usize,
2198 marks: &Marks,
2199) {
2200 core_ctx.counters().port_unreachable.increment();
2201
2202 send_icmpv4_dest_unreachable(
2203 core_ctx,
2204 bindings_ctx,
2205 Some(device),
2206 frame_dst,
2207 src_ip,
2208 dst_ip,
2209 Icmpv4DestUnreachableCode::DestPortUnreachable,
2210 original_packet,
2211 header_len,
2212 Ipv4FragmentType::InitialFragment,
2218 marks,
2219 );
2220}
2221
2222pub(crate) fn send_icmpv6_port_unreachable<
2231 B: BufferMut,
2232 BC: IcmpBindingsContext,
2233 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2234>(
2235 core_ctx: &mut CC,
2236 bindings_ctx: &mut BC,
2237 device: &CC::DeviceId,
2238 frame_dst: Option<FrameDestination>,
2239 src_ip: SocketIpAddr<Ipv6Addr>,
2240 dst_ip: SocketIpAddr<Ipv6Addr>,
2241 original_packet: B,
2242 marks: &Marks,
2243) {
2244 core_ctx.counters().port_unreachable.increment();
2245
2246 send_icmpv6_dest_unreachable(
2247 core_ctx,
2248 bindings_ctx,
2249 Some(device),
2250 frame_dst,
2251 src_ip,
2252 dst_ip,
2253 Icmpv6DestUnreachableCode::PortUnreachable,
2254 original_packet,
2255 marks,
2256 );
2257}
2258
2259pub(crate) fn send_icmpv4_net_unreachable<
2271 B: BufferMut,
2272 BC: IcmpBindingsContext,
2273 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2274>(
2275 core_ctx: &mut CC,
2276 bindings_ctx: &mut BC,
2277 device: &CC::DeviceId,
2278 frame_dst: Option<FrameDestination>,
2279 src_ip: SocketIpAddr<Ipv4Addr>,
2280 dst_ip: SocketIpAddr<Ipv4Addr>,
2281 proto: Ipv4Proto,
2282 original_packet: B,
2283 header_len: usize,
2284 fragment_type: Ipv4FragmentType,
2285 marks: &Marks,
2286) {
2287 core_ctx.counters().net_unreachable.increment();
2288
2289 if is_icmp_error_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..]) {
2292 return;
2293 }
2294
2295 send_icmpv4_dest_unreachable(
2296 core_ctx,
2297 bindings_ctx,
2298 Some(device),
2299 frame_dst,
2300 src_ip,
2301 dst_ip,
2302 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
2303 original_packet,
2304 header_len,
2305 fragment_type,
2306 marks,
2307 );
2308}
2309
2310pub(crate) fn send_icmpv6_net_unreachable<
2321 B: BufferMut,
2322 BC: IcmpBindingsContext,
2323 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2324>(
2325 core_ctx: &mut CC,
2326 bindings_ctx: &mut BC,
2327 device: &CC::DeviceId,
2328 frame_dst: Option<FrameDestination>,
2329 src_ip: SocketIpAddr<Ipv6Addr>,
2330 dst_ip: SocketIpAddr<Ipv6Addr>,
2331 proto: Ipv6Proto,
2332 original_packet: B,
2333 header_len: usize,
2334 marks: &Marks,
2335) {
2336 core_ctx.counters().net_unreachable.increment();
2337
2338 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2341 return;
2342 }
2343
2344 send_icmpv6_dest_unreachable(
2345 core_ctx,
2346 bindings_ctx,
2347 Some(device),
2348 frame_dst,
2349 src_ip,
2350 dst_ip,
2351 Icmpv6DestUnreachableCode::NoRoute,
2352 original_packet,
2353 marks,
2354 );
2355}
2356
2357pub(crate) fn send_icmpv4_ttl_expired<
2369 B: BufferMut,
2370 BC: IcmpBindingsContext,
2371 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2372>(
2373 core_ctx: &mut CC,
2374 bindings_ctx: &mut BC,
2375 device: &CC::DeviceId,
2376 frame_dst: Option<FrameDestination>,
2377 src_ip: SocketIpAddr<Ipv4Addr>,
2378 dst_ip: SocketIpAddr<Ipv4Addr>,
2379 proto: Ipv4Proto,
2380 original_packet: B,
2381 header_len: usize,
2382 fragment_type: Ipv4FragmentType,
2383 marks: &Marks,
2384) {
2385 core_ctx.counters().ttl_expired.increment();
2386
2387 if is_icmp_error_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..]) {
2390 return;
2391 }
2392
2393 send_icmpv4_error_message(
2394 core_ctx,
2395 bindings_ctx,
2396 Some(device),
2397 frame_dst,
2398 src_ip,
2399 dst_ip,
2400 Icmpv4TimeExceededCode::TtlExpired,
2401 IcmpTimeExceeded::default(),
2402 original_packet,
2403 header_len,
2404 fragment_type,
2405 marks,
2406 )
2407}
2408
2409pub(crate) fn send_icmpv6_ttl_expired<
2420 B: BufferMut,
2421 BC: IcmpBindingsContext,
2422 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2423>(
2424 core_ctx: &mut CC,
2425 bindings_ctx: &mut BC,
2426 device: &CC::DeviceId,
2427 frame_dst: Option<FrameDestination>,
2428 src_ip: SocketIpAddr<Ipv6Addr>,
2429 dst_ip: SocketIpAddr<Ipv6Addr>,
2430 proto: Ipv6Proto,
2431 original_packet: B,
2432 header_len: usize,
2433 marks: &Marks,
2434) {
2435 core_ctx.counters().ttl_expired.increment();
2436
2437 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2440 return;
2441 }
2442
2443 send_icmpv6_error_message(
2444 core_ctx,
2445 bindings_ctx,
2446 Some(device),
2447 frame_dst,
2448 src_ip,
2449 dst_ip,
2450 Icmpv6TimeExceededCode::HopLimitExceeded,
2451 IcmpTimeExceeded::default(),
2452 original_packet,
2453 false, marks,
2455 )
2456}
2457
2458pub(crate) fn send_icmpv6_packet_too_big<
2468 B: BufferMut,
2469 BC: IcmpBindingsContext,
2470 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2471>(
2472 core_ctx: &mut CC,
2473 bindings_ctx: &mut BC,
2474 device: &CC::DeviceId,
2475 frame_dst: Option<FrameDestination>,
2476 src_ip: SocketIpAddr<Ipv6Addr>,
2477 dst_ip: SocketIpAddr<Ipv6Addr>,
2478 proto: Ipv6Proto,
2479 mtu: Mtu,
2480 original_packet: B,
2481 header_len: usize,
2482 marks: &Marks,
2483) {
2484 core_ctx.counters().packet_too_big.increment();
2485 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2488 return;
2489 }
2490
2491 send_icmpv6_error_message(
2492 core_ctx,
2493 bindings_ctx,
2494 Some(device),
2495 frame_dst,
2496 src_ip,
2497 dst_ip,
2498 IcmpZeroCode,
2499 Icmpv6PacketTooBig::new(mtu.into()),
2500 original_packet,
2501 true, marks,
2521 )
2522}
2523
2524pub(crate) fn send_icmpv4_parameter_problem<
2525 B: BufferMut,
2526 BC: IcmpBindingsContext,
2527 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2528>(
2529 core_ctx: &mut CC,
2530 bindings_ctx: &mut BC,
2531 device: &CC::DeviceId,
2532 frame_dst: Option<FrameDestination>,
2533 src_ip: SocketIpAddr<Ipv4Addr>,
2534 dst_ip: SocketIpAddr<Ipv4Addr>,
2535 code: Icmpv4ParameterProblemCode,
2536 parameter_problem: Icmpv4ParameterProblem,
2537 original_packet: B,
2538 header_len: usize,
2539 fragment_type: Ipv4FragmentType,
2540 marks: &Marks,
2541) {
2542 core_ctx.counters().parameter_problem.increment();
2543
2544 send_icmpv4_error_message(
2545 core_ctx,
2546 bindings_ctx,
2547 Some(device),
2548 frame_dst,
2549 src_ip,
2550 dst_ip,
2551 code,
2552 parameter_problem,
2553 original_packet,
2554 header_len,
2555 fragment_type,
2556 marks,
2557 )
2558}
2559
2560pub(crate) fn send_icmpv6_parameter_problem<
2571 B: BufferMut,
2572 BC: IcmpBindingsContext,
2573 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2574>(
2575 core_ctx: &mut CC,
2576 bindings_ctx: &mut BC,
2577 device: &CC::DeviceId,
2578 frame_dst: Option<FrameDestination>,
2579 src_ip: SocketIpAddr<Ipv6Addr>,
2580 dst_ip: SocketIpAddr<Ipv6Addr>,
2581 code: Icmpv6ParameterProblemCode,
2582 parameter_problem: Icmpv6ParameterProblem,
2583 original_packet: B,
2584 allow_dst_multicast: bool,
2585 marks: &Marks,
2586) {
2587 assert!(!allow_dst_multicast || code == Icmpv6ParameterProblemCode::UnrecognizedIpv6Option);
2592
2593 core_ctx.counters().parameter_problem.increment();
2594
2595 send_icmpv6_error_message(
2596 core_ctx,
2597 bindings_ctx,
2598 Some(device),
2599 frame_dst,
2600 src_ip,
2601 dst_ip,
2602 code,
2603 parameter_problem,
2604 original_packet,
2605 allow_dst_multicast,
2606 marks,
2607 )
2608}
2609
2610fn send_icmpv4_dest_unreachable<
2611 B: BufferMut,
2612 BC: IcmpBindingsContext,
2613 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2614>(
2615 core_ctx: &mut CC,
2616 bindings_ctx: &mut BC,
2617 device: Option<&CC::DeviceId>,
2618 frame_dst: Option<FrameDestination>,
2619 src_ip: SocketIpAddr<Ipv4Addr>,
2620 dst_ip: SocketIpAddr<Ipv4Addr>,
2621 code: Icmpv4DestUnreachableCode,
2622 original_packet: B,
2623 header_len: usize,
2624 fragment_type: Ipv4FragmentType,
2625 marks: &Marks,
2626) {
2627 core_ctx.counters().dest_unreachable.increment();
2628 send_icmpv4_error_message(
2629 core_ctx,
2630 bindings_ctx,
2631 device,
2632 frame_dst,
2633 src_ip,
2634 dst_ip,
2635 code,
2636 IcmpDestUnreachable::default(),
2637 original_packet,
2638 header_len,
2639 fragment_type,
2640 marks,
2641 )
2642}
2643
2644fn send_icmpv6_dest_unreachable<
2645 B: BufferMut,
2646 BC: IcmpBindingsContext,
2647 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2648>(
2649 core_ctx: &mut CC,
2650 bindings_ctx: &mut BC,
2651 device: Option<&CC::DeviceId>,
2652 frame_dst: Option<FrameDestination>,
2653 src_ip: SocketIpAddr<Ipv6Addr>,
2654 dst_ip: SocketIpAddr<Ipv6Addr>,
2655 code: Icmpv6DestUnreachableCode,
2656 original_packet: B,
2657 marks: &Marks,
2658) {
2659 send_icmpv6_error_message(
2660 core_ctx,
2661 bindings_ctx,
2662 device,
2663 frame_dst,
2664 src_ip,
2665 dst_ip,
2666 code,
2667 IcmpDestUnreachable::default(),
2668 original_packet,
2669 false, marks,
2671 )
2672}
2673
2674fn send_icmpv4_error_message<
2675 B: BufferMut,
2676 M: filter::IcmpMessage<Ipv4>,
2677 BC: IcmpBindingsContext,
2678 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2679>(
2680 core_ctx: &mut CC,
2681 bindings_ctx: &mut BC,
2682 device: Option<&CC::DeviceId>,
2683 frame_dst: Option<FrameDestination>,
2684 original_src_ip: SocketIpAddr<Ipv4Addr>,
2685 original_dst_ip: SocketIpAddr<Ipv4Addr>,
2686 code: M::Code,
2687 message: M,
2688 mut original_packet: B,
2689 header_len: usize,
2690 fragment_type: Ipv4FragmentType,
2691 marks: &Marks,
2692) {
2693 if !should_send_icmpv4_error(
2697 frame_dst,
2698 original_src_ip.into(),
2699 original_dst_ip.into(),
2700 fragment_type,
2701 ) {
2702 return;
2703 }
2704
2705 original_packet.shrink_back_to(header_len + 64);
2708
2709 let tx_metadata: BC::TxMetadata = Default::default();
2710 let _ = try_send_error!(
2713 core_ctx,
2714 bindings_ctx,
2715 core_ctx.send_oneshot_ip_packet(
2716 bindings_ctx,
2717 device.map(EitherDeviceId::Strong),
2718 None,
2719 original_src_ip,
2720 Ipv4Proto::Icmp,
2721 &WithMarks(marks),
2722 tx_metadata,
2723 |local_ip| {
2724 original_packet.encapsulate(IcmpPacketBuilder::<Ipv4, _>::new(
2725 local_ip.addr(),
2726 original_src_ip.addr(),
2727 code,
2728 message,
2729 ))
2730 },
2731 )
2732 );
2733}
2734
2735fn send_icmpv6_error_message<
2736 B: BufferMut,
2737 M: filter::IcmpMessage<Ipv6>,
2738 BC: IcmpBindingsContext,
2739 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2740>(
2741 core_ctx: &mut CC,
2742 bindings_ctx: &mut BC,
2743 device: Option<&CC::DeviceId>,
2744 frame_dst: Option<FrameDestination>,
2745 original_src_ip: SocketIpAddr<Ipv6Addr>,
2746 original_dst_ip: SocketIpAddr<Ipv6Addr>,
2747 code: M::Code,
2748 message: M,
2749 original_packet: B,
2750 allow_dst_multicast: bool,
2751 marks: &Marks,
2752) {
2753 if !should_send_icmpv6_error(
2757 frame_dst,
2758 original_src_ip.into(),
2759 original_dst_ip.into(),
2760 allow_dst_multicast,
2761 ) {
2762 return;
2763 }
2764
2765 struct Icmpv6ErrorOptions<'a>(&'a Marks);
2766 impl<'a> OptionDelegationMarker for Icmpv6ErrorOptions<'a> {}
2767 impl<'a> DelegatedSendOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2768 fn mtu(&self) -> Mtu {
2769 Ipv6::MINIMUM_LINK_MTU
2770 }
2771 }
2772 impl<'a> DelegatedRouteResolutionOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2773 fn marks(&self) -> &Marks {
2774 let Self(marks) = self;
2775 marks
2776 }
2777 }
2778
2779 let tx_metadata: BC::TxMetadata = Default::default();
2780 let _ = try_send_error!(
2783 core_ctx,
2784 bindings_ctx,
2785 core_ctx.send_oneshot_ip_packet(
2786 bindings_ctx,
2787 device.map(EitherDeviceId::Strong),
2788 None,
2789 original_src_ip,
2790 Ipv6Proto::Icmpv6,
2791 &Icmpv6ErrorOptions(marks),
2792 tx_metadata,
2793 |local_ip| {
2794 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
2795 local_ip.addr(),
2796 original_src_ip.addr(),
2797 code,
2798 message,
2799 );
2800
2801 TruncatingSerializer::new(original_packet, TruncateDirection::DiscardBack)
2804 .encapsulate(icmp_builder)
2805 },
2806 )
2807 );
2808}
2809
2810fn should_send_icmpv4_error(
2828 frame_dst: Option<FrameDestination>,
2829 src_ip: SpecifiedAddr<Ipv4Addr>,
2830 dst_ip: SpecifiedAddr<Ipv4Addr>,
2831 fragment_type: Ipv4FragmentType,
2832) -> bool {
2833 fragment_type == Ipv4FragmentType::InitialFragment
2853 && !(dst_ip.is_multicast()
2854 || dst_ip.is_limited_broadcast()
2855 || frame_dst.is_some_and(|dst| dst.is_broadcast())
2856 || src_ip.is_loopback()
2857 || src_ip.is_limited_broadcast()
2858 || src_ip.is_multicast()
2859 || src_ip.is_class_e())
2860}
2861
2862fn should_send_icmpv6_error(
2889 frame_dst: Option<FrameDestination>,
2890 src_ip: SpecifiedAddr<Ipv6Addr>,
2891 dst_ip: SpecifiedAddr<Ipv6Addr>,
2892 allow_dst_multicast: bool,
2893) -> bool {
2894 let multicast_frame_dst = match frame_dst {
2897 Some(FrameDestination::Individual { local: _ }) | None => false,
2898 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
2899 };
2900 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
2901 return false;
2902 }
2903 if src_ip.is_loopback() || src_ip.is_multicast() {
2904 return false;
2905 }
2906 true
2907}
2908
2909fn is_icmp_error_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
2921 proto == I::ICMP_IP_PROTO
2922 && peek_message_type::<I::IcmpMessageType>(buf).map(IcmpMessageType::is_err).unwrap_or(true)
2923}
2924
2925#[cfg(any(test, feature = "testutils"))]
2927pub(crate) mod testutil {
2928 use alloc::vec::Vec;
2929 use net_types::ethernet::Mac;
2930 use net_types::ip::{Ipv6, Ipv6Addr};
2931 use packet::{Buf, InnerPacketBuilder as _, Serializer as _};
2932 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
2933 use packet_formats::icmp::ndp::{
2934 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
2935 };
2936 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
2937 use packet_formats::ip::Ipv6Proto;
2938 use packet_formats::ipv6::Ipv6PacketBuilder;
2939
2940 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
2941
2942 pub fn neighbor_advertisement_ip_packet(
2945 src_ip: Ipv6Addr,
2946 dst_ip: Ipv6Addr,
2947 router_flag: bool,
2948 solicited_flag: bool,
2949 override_flag: bool,
2950 mac: Mac,
2951 ) -> Buf<Vec<u8>> {
2952 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
2953 .into_serializer()
2954 .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
2955 src_ip,
2956 dst_ip,
2957 IcmpZeroCode,
2958 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
2959 ))
2960 .encapsulate(Ipv6PacketBuilder::new(
2961 src_ip,
2962 dst_ip,
2963 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2964 Ipv6Proto::Icmpv6,
2965 ))
2966 .serialize_vec_outer()
2967 .unwrap()
2968 .unwrap_b()
2969 }
2970
2971 pub fn neighbor_solicitation_ip_packet(
2974 src_ip: Ipv6Addr,
2975 dst_ip: Ipv6Addr,
2976 target_addr: Ipv6Addr,
2977 mac: Mac,
2978 ) -> Buf<Vec<u8>> {
2979 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
2980 .into_serializer()
2981 .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
2982 src_ip,
2983 dst_ip,
2984 IcmpZeroCode,
2985 NeighborSolicitation::new(target_addr),
2986 ))
2987 .encapsulate(Ipv6PacketBuilder::new(
2988 src_ip,
2989 dst_ip,
2990 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2991 Ipv6Proto::Icmpv6,
2992 ))
2993 .serialize_vec_outer()
2994 .unwrap()
2995 .unwrap_b()
2996 }
2997}
2998
2999#[cfg(test)]
3000mod tests {
3001 use alloc::vec;
3002 use alloc::vec::Vec;
3003 use packet_formats::icmp::ndp::options::NdpNonce;
3004
3005 use core::fmt::Debug;
3006 use core::time::Duration;
3007
3008 use net_types::ip::Subnet;
3009 use netstack3_base::testutil::{
3010 set_logger_for_test, FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant,
3011 FakeTxMetadata, FakeWeakDeviceId, TestIpExt, TEST_ADDRS_V4, TEST_ADDRS_V6,
3012 };
3013 use netstack3_base::{CtxPair, Uninstantiable};
3014 use packet::Buf;
3015 use packet_formats::icmp::mld::MldPacket;
3016 use packet_formats::ip::IpProto;
3017 use packet_formats::utils::NonZeroDuration;
3018
3019 use super::*;
3020 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
3021 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
3022 use crate::internal::socket::{
3023 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
3024 };
3025 use crate::socket::RouteResolutionOptions;
3026
3027 type InnerIpSocketCtx<I> = FakeCoreCtx<
3029 FakeIpSocketCtx<I, FakeDeviceId>,
3030 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
3031 FakeDeviceId,
3032 >;
3033
3034 pub(super) struct FakeIcmpCoreCtx<I: IpExt> {
3036 ip_socket_ctx: InnerIpSocketCtx<I>,
3037 icmp: FakeIcmpCoreCtxState<I>,
3038 }
3039
3040 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
3042 (),
3043 RouterAdvertisementEvent<FakeDeviceId>,
3044 FakeIcmpBindingsCtxState<I>,
3045 (),
3046 >;
3047
3048 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
3052
3053 pub(super) struct FakeIcmpCoreCtxState<I: IpExt> {
3054 error_send_bucket: TokenBucket<FakeInstant>,
3055 receive_icmp_error: Vec<I::ErrorCode>,
3056 rx_counters: IcmpRxCounters<I>,
3057 tx_counters: IcmpTxCounters<I>,
3058 ndp_counters: NdpCounters,
3059 }
3060
3061 impl<I: TestIpExt + IpExt> FakeIcmpCoreCtx<I> {
3062 fn with_errors_per_second(errors_per_second: u64) -> Self {
3063 Self {
3064 icmp: FakeIcmpCoreCtxState {
3065 error_send_bucket: TokenBucket::new(errors_per_second),
3066 receive_icmp_error: Default::default(),
3067 rx_counters: Default::default(),
3068 tx_counters: Default::default(),
3069 ndp_counters: Default::default(),
3070 },
3071 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
3072 core::iter::once(FakeDeviceConfig {
3073 device: FakeDeviceId,
3074 local_ips: vec![I::TEST_ADDRS.local_ip],
3075 remote_ips: vec![I::TEST_ADDRS.remote_ip],
3076 }),
3077 )),
3078 }
3079 }
3080 }
3081
3082 impl<I: TestIpExt + IpExt> Default for FakeIcmpCoreCtx<I> {
3083 fn default() -> Self {
3084 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
3085 }
3086 }
3087
3088 impl<I: IpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
3089 type DeviceId = FakeDeviceId;
3090 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
3091 }
3092
3093 impl<I: IpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
3094 impl<I: IpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
3095
3096 impl<I: IpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
3097 fn counters(&self) -> &IcmpRxCounters<I> {
3098 &self.icmp.rx_counters
3099 }
3100 }
3101
3102 impl<I: IpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
3103 fn counters(&self) -> &IcmpTxCounters<I> {
3104 &self.icmp.tx_counters
3105 }
3106 }
3107
3108 impl<I: IpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
3109 fn counters(&self) -> &NdpCounters {
3110 &self.icmp.ndp_counters
3111 }
3112 }
3113
3114 pub enum FakeEchoIpTransportContext {}
3115
3116 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
3117
3118 impl<I: IpExt> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
3119 for FakeEchoIpTransportContext
3120 {
3121 fn receive_icmp_error(
3122 core_ctx: &mut FakeIcmpCoreCtx<I>,
3123 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3124 _device: &FakeDeviceId,
3125 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3126 _original_dst_ip: SpecifiedAddr<I::Addr>,
3127 _original_body: &[u8],
3128 _err: I::ErrorCode,
3129 ) {
3130 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
3131 }
3132
3133 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
3134 _core_ctx: &mut FakeIcmpCoreCtx<I>,
3135 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3136 _device: &FakeDeviceId,
3137 _src_ip: I::RecvSrcAddr,
3138 _dst_ip: SpecifiedAddr<I::Addr>,
3139 _buffer: B,
3140 _info: &LocalDeliveryPacketInfo<I, H>,
3141 ) -> Result<(), (B, TransportReceiveError)> {
3142 unimplemented!()
3143 }
3144 }
3145
3146 impl<I: IpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3147 type EchoTransportContext = FakeEchoIpTransportContext;
3148
3149 fn receive_icmp_error(
3150 &mut self,
3151 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3152 device: &Self::DeviceId,
3153 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3154 original_dst_ip: SpecifiedAddr<I::Addr>,
3155 original_proto: I::Proto,
3156 original_body: &[u8],
3157 err: I::ErrorCode,
3158 ) {
3159 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
3160 self.icmp.receive_icmp_error.push(err);
3161 if original_proto == I::ICMP_IP_PROTO {
3162 receive_ip_transport_icmp_error(
3163 self,
3164 bindings_ctx,
3165 device,
3166 original_src_ip,
3167 original_dst_ip,
3168 original_body,
3169 err,
3170 )
3171 }
3172 }
3173
3174 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
3175 &mut self,
3176 cb: F,
3177 ) -> O {
3178 cb(&mut self.icmp.error_send_bucket)
3179 }
3180 }
3181
3182 #[test]
3183 fn test_should_send_icmpv4_error() {
3184 let src_ip = TEST_ADDRS_V4.local_ip;
3185 let dst_ip = TEST_ADDRS_V4.remote_ip;
3186 let frame_dst = FrameDestination::Individual { local: true };
3187 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
3188 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
3189
3190 assert!(should_send_icmpv4_error(
3192 Some(frame_dst),
3193 src_ip,
3194 dst_ip,
3195 Ipv4FragmentType::InitialFragment
3196 ));
3197 assert!(should_send_icmpv4_error(None, src_ip, dst_ip, Ipv4FragmentType::InitialFragment));
3198 assert!(!should_send_icmpv4_error(
3199 Some(frame_dst),
3200 src_ip,
3201 dst_ip,
3202 Ipv4FragmentType::NonInitialFragment
3203 ));
3204
3205 assert!(!should_send_icmpv4_error(
3207 Some(frame_dst),
3208 src_ip,
3209 Ipv4::LIMITED_BROADCAST_ADDRESS,
3210 Ipv4FragmentType::InitialFragment
3211 ));
3212 assert!(!should_send_icmpv4_error(
3213 Some(frame_dst),
3214 src_ip,
3215 Ipv4::LIMITED_BROADCAST_ADDRESS,
3216 Ipv4FragmentType::NonInitialFragment
3217 ));
3218
3219 assert!(!should_send_icmpv4_error(
3221 Some(frame_dst),
3222 src_ip,
3223 multicast_ip_1,
3224 Ipv4FragmentType::InitialFragment
3225 ));
3226 assert!(!should_send_icmpv4_error(
3227 Some(frame_dst),
3228 src_ip,
3229 multicast_ip_1,
3230 Ipv4FragmentType::NonInitialFragment
3231 ));
3232
3233 assert!(!should_send_icmpv4_error(
3235 Some(FrameDestination::Broadcast),
3236 src_ip,
3237 dst_ip,
3238 Ipv4FragmentType::InitialFragment
3239 ));
3240 assert!(!should_send_icmpv4_error(
3241 Some(FrameDestination::Broadcast),
3242 src_ip,
3243 dst_ip,
3244 Ipv4FragmentType::NonInitialFragment
3245 ));
3246
3247 assert!(!should_send_icmpv4_error(
3249 Some(frame_dst),
3250 Ipv4::LOOPBACK_ADDRESS,
3251 dst_ip,
3252 Ipv4FragmentType::InitialFragment
3253 ));
3254 assert!(!should_send_icmpv4_error(
3255 Some(frame_dst),
3256 Ipv4::LOOPBACK_ADDRESS,
3257 dst_ip,
3258 Ipv4FragmentType::NonInitialFragment
3259 ));
3260
3261 assert!(!should_send_icmpv4_error(
3263 Some(frame_dst),
3264 Ipv4::LIMITED_BROADCAST_ADDRESS,
3265 dst_ip,
3266 Ipv4FragmentType::InitialFragment
3267 ));
3268 assert!(!should_send_icmpv4_error(
3269 Some(frame_dst),
3270 Ipv4::LIMITED_BROADCAST_ADDRESS,
3271 dst_ip,
3272 Ipv4FragmentType::NonInitialFragment
3273 ));
3274
3275 assert!(!should_send_icmpv4_error(
3277 Some(frame_dst),
3278 multicast_ip_2,
3279 dst_ip,
3280 Ipv4FragmentType::InitialFragment
3281 ));
3282 assert!(!should_send_icmpv4_error(
3283 Some(frame_dst),
3284 multicast_ip_2,
3285 dst_ip,
3286 Ipv4FragmentType::NonInitialFragment
3287 ));
3288
3289 assert!(!should_send_icmpv4_error(
3291 Some(frame_dst),
3292 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
3293 dst_ip,
3294 Ipv4FragmentType::InitialFragment
3295 ));
3296 assert!(!should_send_icmpv4_error(
3297 Some(frame_dst),
3298 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
3299 dst_ip,
3300 Ipv4FragmentType::NonInitialFragment
3301 ));
3302 }
3303
3304 #[test]
3305 fn test_should_send_icmpv6_error() {
3306 let src_ip = TEST_ADDRS_V6.local_ip;
3307 let dst_ip = TEST_ADDRS_V6.remote_ip;
3308 let frame_dst = FrameDestination::Individual { local: true };
3309 let multicast_ip_1 =
3310 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
3311 let multicast_ip_2 =
3312 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
3313
3314 assert!(should_send_icmpv6_error(
3316 Some(frame_dst),
3317 src_ip,
3318 dst_ip,
3319 false ));
3321 assert!(should_send_icmpv6_error(None, src_ip, dst_ip, false ));
3322 assert!(should_send_icmpv6_error(
3323 Some(frame_dst),
3324 src_ip,
3325 dst_ip,
3326 true ));
3328
3329 assert!(!should_send_icmpv6_error(
3332 Some(frame_dst),
3333 src_ip,
3334 multicast_ip_1,
3335 false ));
3337 assert!(should_send_icmpv6_error(
3338 Some(frame_dst),
3339 src_ip,
3340 multicast_ip_1,
3341 true ));
3343
3344 assert!(!should_send_icmpv6_error(
3347 Some(FrameDestination::Broadcast),
3348 src_ip,
3349 dst_ip,
3350 false ));
3352 assert!(should_send_icmpv6_error(
3353 Some(FrameDestination::Broadcast),
3354 src_ip,
3355 dst_ip,
3356 true ));
3358
3359 assert!(!should_send_icmpv6_error(
3361 Some(frame_dst),
3362 Ipv6::LOOPBACK_ADDRESS,
3363 dst_ip,
3364 false ));
3366 assert!(!should_send_icmpv6_error(
3367 Some(frame_dst),
3368 Ipv6::LOOPBACK_ADDRESS,
3369 dst_ip,
3370 true ));
3372
3373 assert!(!should_send_icmpv6_error(
3375 Some(frame_dst),
3376 multicast_ip_2,
3377 dst_ip,
3378 false ));
3380 assert!(!should_send_icmpv6_error(
3381 Some(frame_dst),
3382 multicast_ip_2,
3383 dst_ip,
3384 true ));
3386
3387 assert!(!should_send_icmpv6_error(
3390 Some(FrameDestination::Broadcast),
3391 multicast_ip_2,
3392 dst_ip,
3393 false ));
3395 assert!(!should_send_icmpv6_error(
3396 Some(FrameDestination::Broadcast),
3397 multicast_ip_2,
3398 dst_ip,
3399 true ));
3401 assert!(!should_send_icmpv6_error(
3402 Some(frame_dst),
3403 multicast_ip_2,
3404 multicast_ip_1,
3405 false ));
3407 assert!(!should_send_icmpv6_error(
3408 Some(frame_dst),
3409 multicast_ip_2,
3410 multicast_ip_1,
3411 true ));
3413 }
3414
3415 #[derive(Default)]
3422 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3423 _marker: core::marker::PhantomData<I>,
3424 }
3425
3426 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3427 fn should_send_timestamp_reply(&self) -> bool {
3428 false
3429 }
3430 }
3431 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3432 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3433
3434 impl<I: IpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3435 fn new_ip_socket<O>(
3436 &mut self,
3437 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3438 device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
3439 local_ip: Option<IpDeviceAddr<I::Addr>>,
3440 remote_ip: SocketIpAddr<I::Addr>,
3441 proto: I::Proto,
3442 options: &O,
3443 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3444 where
3445 O: RouteResolutionOptions<I>,
3446 {
3447 self.ip_socket_ctx.new_ip_socket(
3448 bindings_ctx,
3449 device,
3450 local_ip,
3451 remote_ip,
3452 proto,
3453 options,
3454 )
3455 }
3456
3457 fn send_ip_packet<S, O>(
3458 &mut self,
3459 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3460 socket: &IpSock<I, Self::WeakDeviceId>,
3461 body: S,
3462 options: &O,
3463 tx_meta: FakeTxMetadata,
3464 ) -> Result<(), IpSockSendError>
3465 where
3466 S: TransportPacketSerializer<I>,
3467 S::Buffer: BufferMut,
3468 O: SendOptions<I> + RouteResolutionOptions<I>,
3469 {
3470 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3471 }
3472
3473 fn confirm_reachable<O>(
3474 &mut self,
3475 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3476 socket: &IpSock<I, Self::WeakDeviceId>,
3477 options: &O,
3478 ) where
3479 O: RouteResolutionOptions<I>,
3480 {
3481 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3482 }
3483 }
3484
3485 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3486 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3487 unimplemented!()
3488 }
3489
3490 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3491 unreachable!()
3492 }
3493 }
3494
3495 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3496 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3497 cb(&())
3498 }
3499
3500 fn get_local_addr_for_remote(
3501 &mut self,
3502 _device_id: &Self::DeviceId,
3503 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3504 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3505 unimplemented!()
3506 }
3507
3508 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3509 unimplemented!()
3510 }
3511 }
3512
3513 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3514 fn address_status_for_device(
3515 &mut self,
3516 _addr: SpecifiedAddr<Ipv6Addr>,
3517 _device_id: &Self::DeviceId,
3518 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3519 unimplemented!()
3520 }
3521 }
3522
3523 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3524 type LinkLayerAddr = Uninstantiable;
3525
3526 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3527 unimplemented!()
3528 }
3529
3530 fn set_discovered_retrans_timer(
3531 &mut self,
3532 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3533 _device_id: &Self::DeviceId,
3534 _retrans_timer: NonZeroDuration,
3535 ) {
3536 unimplemented!()
3537 }
3538
3539 fn handle_received_dad_neighbor_solicitation(
3540 &mut self,
3541 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3542 _device_id: &Self::DeviceId,
3543 _addr: UnicastAddr<Ipv6Addr>,
3544 _nonce: Option<NdpNonce<&'_ [u8]>>,
3545 ) -> IpAddressState {
3546 unimplemented!()
3547 }
3548
3549 fn handle_received_neighbor_advertisement(
3550 &mut self,
3551 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3552 _device_id: &Self::DeviceId,
3553 _addr: UnicastAddr<Ipv6Addr>,
3554 ) -> IpAddressState {
3555 unimplemented!()
3556 }
3557
3558 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3559 unimplemented!()
3560 }
3561
3562 fn update_discovered_ipv6_route(
3563 &mut self,
3564 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3565 _device_id: &Self::DeviceId,
3566 _route: Ipv6DiscoveredRoute,
3567 _lifetime: Option<NonZeroNdpLifetime>,
3568 ) {
3569 unimplemented!()
3570 }
3571
3572 fn apply_slaac_update(
3573 &mut self,
3574 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3575 _device_id: &Self::DeviceId,
3576 _subnet: Subnet<Ipv6Addr>,
3577 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3578 _valid_lifetime: Option<NonZeroNdpLifetime>,
3579 ) {
3580 unimplemented!()
3581 }
3582
3583 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3584 &mut self,
3585 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3586 _device: &FakeDeviceId,
3587 _src_ip: Ipv6SourceAddr,
3588 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3589 _packet: MldPacket<B>,
3590 _header_info: &H,
3591 ) {
3592 unimplemented!()
3593 }
3594 }
3595
3596 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3597 fn send_ip_packet_from_device<S>(
3598 &mut self,
3599 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3600 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3601 _body: S,
3602 ) -> Result<(), IpSendFrameError<S>> {
3603 unimplemented!()
3604 }
3605
3606 fn send_ip_frame<S>(
3607 &mut self,
3608 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3609 _device: &Self::DeviceId,
3610 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3611 _body: S,
3612 ) -> Result<(), IpSendFrameError<S>>
3613 where
3614 S: Serializer,
3615 S::Buffer: BufferMut,
3616 {
3617 unimplemented!()
3618 }
3619 }
3620
3621 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3622 fn handle_neighbor_probe(
3623 &mut self,
3624 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3625 _device_id: &Self::DeviceId,
3626 _neighbor: SpecifiedAddr<Ipv6Addr>,
3627 _link_addr: &[u8],
3628 ) {
3629 unimplemented!()
3630 }
3631
3632 fn handle_neighbor_confirmation(
3633 &mut self,
3634 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3635 _device_id: &Self::DeviceId,
3636 _neighbor: SpecifiedAddr<Ipv6Addr>,
3637 _link_addr: &[u8],
3638 _flags: ConfirmationFlags,
3639 ) {
3640 unimplemented!()
3641 }
3642
3643 fn flush_neighbor_table(
3644 &mut self,
3645 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3646 _device_id: &Self::DeviceId,
3647 ) {
3648 unimplemented!()
3649 }
3650 }
3651
3652 #[test]
3653 fn test_receive_icmpv4_error() {
3654 const ICMP_ID: u16 = 0x0F;
3657 const SEQ_NUM: u16 = 0xF0;
3658
3659 fn test_receive_icmpv4_error_helper<
3674 C: Debug,
3675 M: IcmpMessage<Ipv4, Code = C> + Debug,
3676 F: Fn(&FakeIcmpCtx<Ipv4>),
3677 >(
3678 original_packet: &mut [u8],
3679 code: C,
3680 msg: M,
3681 f: F,
3682 ) {
3683 set_logger_for_test();
3684
3685 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3686
3687 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3688 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3689 core_ctx,
3690 bindings_ctx,
3691 &FakeDeviceId,
3692 TEST_ADDRS_V4.remote_ip.get(),
3693 TEST_ADDRS_V4.local_ip,
3694 Buf::new(original_packet, ..)
3695 .encapsulate(IcmpPacketBuilder::new(
3696 TEST_ADDRS_V4.remote_ip,
3697 TEST_ADDRS_V4.local_ip,
3698 code,
3699 msg,
3700 ))
3701 .serialize_vec_outer()
3702 .unwrap(),
3703 &LocalDeliveryPacketInfo::default(),
3704 )
3705 .unwrap();
3706 f(&ctx);
3707 }
3708 let mut buffer = Buf::new(&mut [], ..)
3721 .encapsulate(IcmpPacketBuilder::<Ipv4, _>::new(
3722 TEST_ADDRS_V4.local_ip,
3723 TEST_ADDRS_V4.remote_ip,
3724 IcmpZeroCode,
3725 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3726 ))
3727 .encapsulate(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3728 TEST_ADDRS_V4.local_ip,
3729 TEST_ADDRS_V4.remote_ip,
3730 64,
3731 Ipv4Proto::Icmp,
3732 ))
3733 .serialize_vec_outer()
3734 .unwrap();
3735
3736 test_receive_icmpv4_error_helper(
3737 buffer.as_mut(),
3738 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3739 IcmpDestUnreachable::default(),
3740 |CtxPair { core_ctx, bindings_ctx: _ }| {
3741 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3742 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3743 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3744 let err = Icmpv4ErrorCode::DestUnreachable(
3745 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3746 );
3747 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3748 },
3749 );
3750
3751 test_receive_icmpv4_error_helper(
3752 buffer.as_mut(),
3753 Icmpv4TimeExceededCode::TtlExpired,
3754 IcmpTimeExceeded::default(),
3755 |CtxPair { core_ctx, bindings_ctx: _ }| {
3756 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3757 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3758 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3759 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3760 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3761 },
3762 );
3763
3764 test_receive_icmpv4_error_helper(
3765 buffer.as_mut(),
3766 Icmpv4ParameterProblemCode::PointerIndicatesError,
3767 Icmpv4ParameterProblem::new(0),
3768 |CtxPair { core_ctx, bindings_ctx: _ }| {
3769 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3770 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3771 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3772 let err = Icmpv4ErrorCode::ParameterProblem(
3773 Icmpv4ParameterProblemCode::PointerIndicatesError,
3774 );
3775 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3776 },
3777 );
3778
3779 let mut buffer = Buf::new(&mut [], ..)
3786 .encapsulate(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3787 TEST_ADDRS_V4.local_ip,
3788 TEST_ADDRS_V4.remote_ip,
3789 64,
3790 Ipv4Proto::Icmp,
3791 ))
3792 .serialize_vec_outer()
3793 .unwrap();
3794
3795 test_receive_icmpv4_error_helper(
3796 buffer.as_mut(),
3797 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3798 IcmpDestUnreachable::default(),
3799 |CtxPair { core_ctx, bindings_ctx: _ }| {
3800 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3801 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3802 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3803 let err = Icmpv4ErrorCode::DestUnreachable(
3804 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3805 );
3806 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3807 },
3808 );
3809
3810 test_receive_icmpv4_error_helper(
3811 buffer.as_mut(),
3812 Icmpv4TimeExceededCode::TtlExpired,
3813 IcmpTimeExceeded::default(),
3814 |CtxPair { core_ctx, bindings_ctx: _ }| {
3815 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3816 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3817 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3818 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3819 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3820 },
3821 );
3822
3823 test_receive_icmpv4_error_helper(
3824 buffer.as_mut(),
3825 Icmpv4ParameterProblemCode::PointerIndicatesError,
3826 Icmpv4ParameterProblem::new(0),
3827 |CtxPair { core_ctx, bindings_ctx: _ }| {
3828 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3829 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3830 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3831 let err = Icmpv4ErrorCode::ParameterProblem(
3832 Icmpv4ParameterProblemCode::PointerIndicatesError,
3833 );
3834 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3835 },
3836 );
3837
3838 let mut buffer = Buf::new(&mut [], ..)
3844 .encapsulate(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3845 TEST_ADDRS_V4.local_ip,
3846 TEST_ADDRS_V4.remote_ip,
3847 64,
3848 IpProto::Udp.into(),
3849 ))
3850 .serialize_vec_outer()
3851 .unwrap();
3852
3853 test_receive_icmpv4_error_helper(
3854 buffer.as_mut(),
3855 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3856 IcmpDestUnreachable::default(),
3857 |CtxPair { core_ctx, bindings_ctx: _ }| {
3858 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3859 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3860 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3861 let err = Icmpv4ErrorCode::DestUnreachable(
3862 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3863 );
3864 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3865 },
3866 );
3867
3868 test_receive_icmpv4_error_helper(
3869 buffer.as_mut(),
3870 Icmpv4TimeExceededCode::TtlExpired,
3871 IcmpTimeExceeded::default(),
3872 |CtxPair { core_ctx, bindings_ctx: _ }| {
3873 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3874 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3875 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3876 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3877 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3878 },
3879 );
3880
3881 test_receive_icmpv4_error_helper(
3882 buffer.as_mut(),
3883 Icmpv4ParameterProblemCode::PointerIndicatesError,
3884 Icmpv4ParameterProblem::new(0),
3885 |CtxPair { core_ctx, bindings_ctx: _ }| {
3886 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3887 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3888 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3889 let err = Icmpv4ErrorCode::ParameterProblem(
3890 Icmpv4ParameterProblemCode::PointerIndicatesError,
3891 );
3892 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3893 },
3894 );
3895 }
3896
3897 #[test]
3898 fn test_receive_icmpv6_error() {
3899 const ICMP_ID: u16 = 0x0F;
3902 const SEQ_NUM: u16 = 0xF0;
3903
3904 fn test_receive_icmpv6_error_helper<
3919 C: Debug,
3920 M: IcmpMessage<Ipv6, Code = C> + Debug,
3921 F: Fn(&FakeIcmpCtx<Ipv6>),
3922 >(
3923 original_packet: &mut [u8],
3924 code: C,
3925 msg: M,
3926 f: F,
3927 ) {
3928 set_logger_for_test();
3929
3930 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
3931 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3932 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
3933 core_ctx,
3934 bindings_ctx,
3935 &FakeDeviceId,
3936 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
3937 TEST_ADDRS_V6.local_ip,
3938 Buf::new(original_packet, ..)
3939 .encapsulate(IcmpPacketBuilder::new(
3940 TEST_ADDRS_V6.remote_ip,
3941 TEST_ADDRS_V6.local_ip,
3942 code,
3943 msg,
3944 ))
3945 .serialize_vec_outer()
3946 .unwrap(),
3947 &LocalDeliveryPacketInfo::default(),
3948 )
3949 .unwrap();
3950 f(&ctx);
3951 }
3952 let mut buffer = Buf::new(&mut [], ..)
3965 .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
3966 TEST_ADDRS_V6.local_ip,
3967 TEST_ADDRS_V6.remote_ip,
3968 IcmpZeroCode,
3969 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3970 ))
3971 .encapsulate(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3972 TEST_ADDRS_V6.local_ip,
3973 TEST_ADDRS_V6.remote_ip,
3974 64,
3975 Ipv6Proto::Icmpv6,
3976 ))
3977 .serialize_vec_outer()
3978 .unwrap();
3979
3980 test_receive_icmpv6_error_helper(
3981 buffer.as_mut(),
3982 Icmpv6DestUnreachableCode::NoRoute,
3983 IcmpDestUnreachable::default(),
3984 |CtxPair { core_ctx, bindings_ctx: _ }| {
3985 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3986 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3987 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3988 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3989 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3990 },
3991 );
3992
3993 test_receive_icmpv6_error_helper(
3994 buffer.as_mut(),
3995 Icmpv6TimeExceededCode::HopLimitExceeded,
3996 IcmpTimeExceeded::default(),
3997 |CtxPair { core_ctx, bindings_ctx: _ }| {
3998 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3999 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4000 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4001 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4002 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4003 },
4004 );
4005
4006 test_receive_icmpv6_error_helper(
4007 buffer.as_mut(),
4008 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4009 Icmpv6ParameterProblem::new(0),
4010 |CtxPair { core_ctx, bindings_ctx: _ }| {
4011 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4012 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4013 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4014 let err = Icmpv6ErrorCode::ParameterProblem(
4015 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4016 );
4017 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4018 },
4019 );
4020
4021 let mut buffer = Buf::new(&mut [], ..)
4028 .encapsulate(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4029 TEST_ADDRS_V6.local_ip,
4030 TEST_ADDRS_V6.remote_ip,
4031 64,
4032 Ipv6Proto::Icmpv6,
4033 ))
4034 .serialize_vec_outer()
4035 .unwrap();
4036
4037 test_receive_icmpv6_error_helper(
4038 buffer.as_mut(),
4039 Icmpv6DestUnreachableCode::NoRoute,
4040 IcmpDestUnreachable::default(),
4041 |CtxPair { core_ctx, bindings_ctx: _ }| {
4042 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4043 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4044 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4045 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4046 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4047 },
4048 );
4049
4050 test_receive_icmpv6_error_helper(
4051 buffer.as_mut(),
4052 Icmpv6TimeExceededCode::HopLimitExceeded,
4053 IcmpTimeExceeded::default(),
4054 |CtxPair { core_ctx, bindings_ctx: _ }| {
4055 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4056 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4057 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4058 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4059 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4060 },
4061 );
4062
4063 test_receive_icmpv6_error_helper(
4064 buffer.as_mut(),
4065 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4066 Icmpv6ParameterProblem::new(0),
4067 |CtxPair { core_ctx, bindings_ctx: _ }| {
4068 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4069 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4070 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4071 let err = Icmpv6ErrorCode::ParameterProblem(
4072 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4073 );
4074 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4075 },
4076 );
4077
4078 let mut buffer = Buf::new(&mut [], ..)
4084 .encapsulate(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4085 TEST_ADDRS_V6.local_ip,
4086 TEST_ADDRS_V6.remote_ip,
4087 64,
4088 IpProto::Udp.into(),
4089 ))
4090 .serialize_vec_outer()
4091 .unwrap();
4092
4093 test_receive_icmpv6_error_helper(
4094 buffer.as_mut(),
4095 Icmpv6DestUnreachableCode::NoRoute,
4096 IcmpDestUnreachable::default(),
4097 |CtxPair { core_ctx, bindings_ctx: _ }| {
4098 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4099 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4100 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4101 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4102 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4103 },
4104 );
4105
4106 test_receive_icmpv6_error_helper(
4107 buffer.as_mut(),
4108 Icmpv6TimeExceededCode::HopLimitExceeded,
4109 IcmpTimeExceeded::default(),
4110 |CtxPair { core_ctx, bindings_ctx: _ }| {
4111 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4112 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4113 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4114 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4115 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4116 },
4117 );
4118
4119 test_receive_icmpv6_error_helper(
4120 buffer.as_mut(),
4121 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4122 Icmpv6ParameterProblem::new(0),
4123 |CtxPair { core_ctx, bindings_ctx: _ }| {
4124 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4125 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4126 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4127 let err = Icmpv6ErrorCode::ParameterProblem(
4128 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4129 );
4130 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4131 },
4132 );
4133 }
4134
4135 #[test]
4136 fn test_error_rate_limit() {
4137 set_logger_for_test();
4138
4139 fn send_icmpv4_ttl_expired_helper(
4141 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4142 ) {
4143 send_icmpv4_ttl_expired(
4144 core_ctx,
4145 bindings_ctx,
4146 &FakeDeviceId,
4147 Some(FrameDestination::Individual { local: true }),
4148 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4149 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4150 IpProto::Udp.into(),
4151 Buf::new(&mut [], ..),
4152 0,
4153 Ipv4FragmentType::InitialFragment,
4154 &Default::default(),
4155 );
4156 }
4157
4158 fn send_icmpv4_parameter_problem_helper(
4160 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4161 ) {
4162 send_icmpv4_parameter_problem(
4163 core_ctx,
4164 bindings_ctx,
4165 &FakeDeviceId,
4166 Some(FrameDestination::Individual { local: true }),
4167 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4168 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4169 Icmpv4ParameterProblemCode::PointerIndicatesError,
4170 Icmpv4ParameterProblem::new(0),
4171 Buf::new(&mut [], ..),
4172 0,
4173 Ipv4FragmentType::InitialFragment,
4174 &Default::default(),
4175 );
4176 }
4177
4178 fn send_icmpv4_dest_unreachable_helper(
4180 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4181 ) {
4182 send_icmpv4_dest_unreachable(
4183 core_ctx,
4184 bindings_ctx,
4185 Some(&FakeDeviceId),
4186 Some(FrameDestination::Individual { local: true }),
4187 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4188 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4189 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4190 Buf::new(&mut [], ..),
4191 0,
4192 Ipv4FragmentType::InitialFragment,
4193 &Default::default(),
4194 );
4195 }
4196
4197 fn send_icmpv6_ttl_expired_helper(
4199 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4200 ) {
4201 send_icmpv6_ttl_expired(
4202 core_ctx,
4203 bindings_ctx,
4204 &FakeDeviceId,
4205 Some(FrameDestination::Individual { local: true }),
4206 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4207 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4208 IpProto::Udp.into(),
4209 Buf::new(&mut [], ..),
4210 0,
4211 &Default::default(),
4212 );
4213 }
4214
4215 fn send_icmpv6_packet_too_big_helper(
4217 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4218 ) {
4219 send_icmpv6_packet_too_big(
4220 core_ctx,
4221 bindings_ctx,
4222 &FakeDeviceId,
4223 Some(FrameDestination::Individual { local: true }),
4224 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4225 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4226 IpProto::Udp.into(),
4227 Mtu::new(0),
4228 Buf::new(&mut [], ..),
4229 0,
4230 &Default::default(),
4231 );
4232 }
4233
4234 fn send_icmpv6_parameter_problem_helper(
4236 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4237 ) {
4238 send_icmpv6_parameter_problem(
4239 core_ctx,
4240 bindings_ctx,
4241 &FakeDeviceId,
4242 Some(FrameDestination::Individual { local: true }),
4243 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4244 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4245 Icmpv6ParameterProblemCode::ErroneousHeaderField,
4246 Icmpv6ParameterProblem::new(0),
4247 Buf::new(&mut [], ..),
4248 false,
4249 &Default::default(),
4250 );
4251 }
4252
4253 fn send_icmpv6_dest_unreachable_helper(
4255 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4256 ) {
4257 send_icmpv6_dest_unreachable(
4258 core_ctx,
4259 bindings_ctx,
4260 Some(&FakeDeviceId),
4261 Some(FrameDestination::Individual { local: true }),
4262 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4263 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4264 Icmpv6DestUnreachableCode::NoRoute,
4265 Buf::new(&mut [], ..),
4266 &Default::default(),
4267 );
4268 }
4269
4270 fn run_test<I: IpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
4274 with_errors_per_second: W,
4275 send: S,
4276 ) {
4277 const ERRORS_PER_SECOND: u64 = 64;
4291
4292 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
4293
4294 for i in 0..ERRORS_PER_SECOND {
4295 send(&mut ctx);
4296 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
4297 }
4298
4299 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4300 send(&mut ctx);
4301 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4302
4303 let mut ctx = with_errors_per_second(0);
4307 send(&mut ctx);
4308 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4309 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4310 send(&mut ctx);
4311 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4312 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4313 send(&mut ctx);
4314 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4315 }
4316
4317 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
4318 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4319 }
4320 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
4321 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
4322 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
4323
4324 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
4325 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4326 }
4327
4328 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
4329 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
4330 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
4331 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
4332 }
4333}