1use alloc::boxed::Box;
8use core::convert::TryInto as _;
9use core::num::{NonZeroU16, NonZeroU8};
10
11use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
12use log::{debug, error, trace};
13use net_types::ip::{
14 GenericOverIp, Ip, IpAddress, IpMarked, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr,
15 Ipv6SourceAddr, Mtu, SubnetError,
16};
17use net_types::{
18 LinkLocalAddress, LinkLocalUnicastAddr, MulticastAddress, NonMulticastAddr, SpecifiedAddr,
19 UnicastAddr, Witness,
20};
21use netstack3_base::socket::{AddrIsMappedError, SocketIpAddr, SocketIpAddrExt as _};
22use netstack3_base::sync::Mutex;
23use netstack3_base::{
24 AnyDevice, Counter, CounterContext, DeviceIdContext, EitherDeviceId, FrameDestination,
25 IcmpIpExt, Icmpv4ErrorCode, Icmpv6ErrorCode, InstantBindingsTypes, InstantContext,
26 IpDeviceAddr, IpExt, Marks, RngContext, TokenBucket, TxMetadataBindingsTypes,
27};
28use netstack3_filter::{FilterIpExt, TransportPacketSerializer};
29use packet::{
30 BufferMut, InnerPacketBuilder as _, ParsablePacket as _, ParseBuffer, Serializer,
31 TruncateDirection, TruncatingSerializer,
32};
33use packet_formats::icmp::ndp::options::{NdpOption, NdpOptionBuilder};
34use packet_formats::icmp::ndp::{
35 NdpPacket, NeighborAdvertisement, NeighborSolicitation, NonZeroNdpLifetime,
36 OptionSequenceBuilder, RouterSolicitation,
37};
38use packet_formats::icmp::{
39 peek_message_type, IcmpDestUnreachable, IcmpEchoRequest, IcmpMessage, IcmpMessageType,
40 IcmpPacket, IcmpPacketBuilder, IcmpPacketRaw, IcmpParseArgs, IcmpTimeExceeded, IcmpZeroCode,
41 Icmpv4DestUnreachableCode, Icmpv4Packet, Icmpv4ParameterProblem, Icmpv4ParameterProblemCode,
42 Icmpv4TimeExceededCode, Icmpv6DestUnreachableCode, Icmpv6Packet, Icmpv6PacketTooBig,
43 Icmpv6ParameterProblem, Icmpv6ParameterProblemCode, Icmpv6TimeExceededCode, MessageBody,
44 OriginalPacket,
45};
46use packet_formats::ip::{DscpAndEcn, IpPacket, Ipv4Proto, Ipv6Proto};
47use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Header, Ipv4OnlyMeta};
48use packet_formats::ipv6::{ExtHdrParseError, Ipv6Header};
49use zerocopy::SplitByteSlice;
50
51use crate::internal::base::{
52 AddressStatus, IpDeviceIngressStateContext, IpLayerHandler, IpPacketDestination,
53 IpSendFrameError, IpTransportContext, Ipv6PresentAddressStatus, NdpBindingsContext,
54 RouterAdvertisementEvent, SendIpPacketMeta, TransportReceiveError, IPV6_DEFAULT_SUBNET,
55};
56use crate::internal::device::nud::{ConfirmationFlags, NudIpHandler};
57use crate::internal::device::route_discovery::Ipv6DiscoveredRoute;
58use crate::internal::device::{
59 IpAddressState, IpDeviceHandler, Ipv6DeviceHandler, Ipv6LinkLayerAddr,
60};
61use crate::internal::local_delivery::{IpHeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta};
62use crate::internal::path_mtu::PmtuHandler;
63use crate::internal::socket::{
64 DelegatedRouteResolutionOptions, DelegatedSendOptions, IpSocketHandler, OptionDelegationMarker,
65 RouteResolutionOptions, SendOptions,
66};
67
68pub const REQUIRED_NDP_IP_PACKET_HOP_LIMIT: u8 = 255;
80
81pub const DEFAULT_ERRORS_PER_SECOND: u64 = 1000;
89#[derive(GenericOverIp)]
91#[generic_over_ip(I, Ip)]
92pub struct IcmpState<I: IpExt, BT: IcmpBindingsTypes> {
93 error_send_bucket: Mutex<IpMarked<I, TokenBucket<BT::Instant>>>,
94 pub tx_counters: IcmpTxCounters<I>,
96 pub rx_counters: IcmpRxCounters<I>,
98}
99
100impl<I, BT> OrderedLockAccess<IpMarked<I, TokenBucket<BT::Instant>>> for IcmpState<I, BT>
101where
102 I: IpExt,
103 BT: IcmpBindingsTypes,
104{
105 type Lock = Mutex<IpMarked<I, TokenBucket<BT::Instant>>>;
106 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
107 OrderedLockRef::new(&self.error_send_bucket)
108 }
109}
110
111pub type IcmpTxCounters<I> = IpMarked<I, IcmpTxCountersInner>;
113
114#[derive(Default)]
116pub struct IcmpTxCountersInner {
117 pub reply: Counter,
119 pub protocol_unreachable: Counter,
121 pub address_unreachable: Counter,
123 pub port_unreachable: Counter,
125 pub net_unreachable: Counter,
127 pub ttl_expired: Counter,
129 pub packet_too_big: Counter,
131 pub parameter_problem: Counter,
133 pub dest_unreachable: Counter,
135 pub error: Counter,
137}
138
139pub type IcmpRxCounters<I> = IpMarked<I, IcmpRxCountersInner>;
141
142#[derive(Default)]
144pub struct IcmpRxCountersInner {
145 pub error: Counter,
147 pub error_delivered_to_transport_layer: Counter,
149 pub error_delivered_to_socket: Counter,
151 pub echo_request: Counter,
153 pub echo_reply: Counter,
155 pub timestamp_request: Counter,
157 pub dest_unreachable: Counter,
159 pub time_exceeded: Counter,
161 pub parameter_problem: Counter,
163 pub packet_too_big: Counter,
165}
166
167#[derive(Default)]
169pub struct NdpRxCounters {
170 pub neighbor_solicitation: Counter,
172 pub neighbor_advertisement: Counter,
174 pub router_advertisement: Counter,
176 pub router_solicitation: Counter,
178}
179
180#[derive(Default)]
182pub struct NdpTxCounters {
183 pub neighbor_advertisement: Counter,
185 pub neighbor_solicitation: Counter,
187}
188
189#[derive(Default)]
191pub struct NdpCounters {
192 pub rx: NdpRxCounters,
194 pub tx: NdpTxCounters,
196}
197
198#[derive(Copy, Clone)]
200pub struct Icmpv4StateBuilder {
201 send_timestamp_reply: bool,
202 errors_per_second: u64,
203}
204
205impl Default for Icmpv4StateBuilder {
206 fn default() -> Icmpv4StateBuilder {
207 Icmpv4StateBuilder {
208 send_timestamp_reply: false,
209 errors_per_second: DEFAULT_ERRORS_PER_SECOND,
210 }
211 }
212}
213
214impl Icmpv4StateBuilder {
215 pub fn send_timestamp_reply(&mut self, send_timestamp_reply: bool) -> &mut Self {
222 self.send_timestamp_reply = send_timestamp_reply;
223 self
224 }
225
226 pub fn build<BT: IcmpBindingsTypes>(self) -> Icmpv4State<BT> {
228 Icmpv4State {
229 inner: IcmpState {
230 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
231 self.errors_per_second,
232 ))),
233 tx_counters: Default::default(),
234 rx_counters: Default::default(),
235 },
236 send_timestamp_reply: self.send_timestamp_reply,
237 }
238 }
239}
240
241pub struct Icmpv4State<BT: IcmpBindingsTypes> {
243 pub inner: IcmpState<Ipv4, BT>,
245 pub send_timestamp_reply: bool,
247}
248
249impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
250 fn as_ref(&self) -> &IcmpState<Ipv4, BT> {
251 &self.inner
252 }
253}
254
255impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
256 fn as_mut(&mut self) -> &mut IcmpState<Ipv4, BT> {
257 &mut self.inner
258 }
259}
260
261#[derive(Copy, Clone)]
263pub(crate) struct Icmpv6StateBuilder {
264 errors_per_second: u64,
265}
266
267impl Default for Icmpv6StateBuilder {
268 fn default() -> Icmpv6StateBuilder {
269 Icmpv6StateBuilder { errors_per_second: DEFAULT_ERRORS_PER_SECOND }
270 }
271}
272
273impl Icmpv6StateBuilder {
274 pub(crate) fn build<BT: IcmpBindingsTypes>(self) -> Icmpv6State<BT> {
275 Icmpv6State {
276 inner: IcmpState {
277 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
278 self.errors_per_second,
279 ))),
280 tx_counters: Default::default(),
281 rx_counters: Default::default(),
282 },
283 ndp_counters: Default::default(),
284 }
285 }
286}
287
288pub struct Icmpv6State<BT: IcmpBindingsTypes> {
290 pub inner: IcmpState<Ipv6, BT>,
292 pub ndp_counters: NdpCounters,
294}
295
296impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
297 fn as_ref(&self) -> &IcmpState<Ipv6, BT> {
298 &self.inner
299 }
300}
301
302impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
303 fn as_mut(&mut self) -> &mut IcmpState<Ipv6, BT> {
304 &mut self.inner
305 }
306}
307
308pub trait IcmpHandlerIpExt: IpExt {
310 type SourceAddress: Witness<Self::Addr>;
311 type IcmpError;
312
313 fn received_source_as_icmp_source(src: Self::RecvSrcAddr) -> Option<Self::SourceAddress>;
315
316 fn new_ttl_expired<B: SplitByteSlice>(
318 proto: Self::Proto,
319 header_len: usize,
320 meta: <Self::Packet<B> as IpPacket<B, Self>>::VersionSpecificMeta,
321 ) -> Self::IcmpError;
322
323 fn new_mtu_exceeded(proto: Self::Proto, header_len: usize, mtu: Mtu)
325 -> Option<Self::IcmpError>;
326}
327
328impl IcmpHandlerIpExt for Ipv4 {
329 type SourceAddress = NonMulticastAddr<SpecifiedAddr<Ipv4Addr>>;
330 type IcmpError = Icmpv4Error;
331 fn received_source_as_icmp_source(
332 src: Ipv4SourceAddr,
333 ) -> Option<NonMulticastAddr<SpecifiedAddr<Ipv4Addr>>> {
334 match src {
335 Ipv4SourceAddr::Specified(src) => Some(src),
336 Ipv4SourceAddr::Unspecified => None,
337 }
338 }
339 fn new_ttl_expired<B: SplitByteSlice>(
340 proto: Ipv4Proto,
341 header_len: usize,
342 Ipv4OnlyMeta { id: _, fragment_type }: Ipv4OnlyMeta,
343 ) -> Icmpv4Error {
344 Icmpv4Error { kind: Icmpv4ErrorKind::TtlExpired { proto, fragment_type }, header_len }
345 }
346 fn new_mtu_exceeded(_proto: Ipv4Proto, _header_len: usize, _mtu: Mtu) -> Option<Icmpv4Error> {
347 None
349 }
350}
351
352impl IcmpHandlerIpExt for Ipv6 {
353 type SourceAddress = UnicastAddr<Ipv6Addr>;
354 type IcmpError = Icmpv6ErrorKind;
355 fn received_source_as_icmp_source(src: Ipv6SourceAddr) -> Option<UnicastAddr<Ipv6Addr>> {
356 match src {
357 Ipv6SourceAddr::Unicast(src) => Some(src.get()),
358 Ipv6SourceAddr::Unspecified => None,
359 }
360 }
361 fn new_ttl_expired<B: SplitByteSlice>(
362 proto: Ipv6Proto,
363 header_len: usize,
364 _meta: (),
365 ) -> Icmpv6ErrorKind {
366 Icmpv6ErrorKind::TtlExpired { proto, header_len }
367 }
368 fn new_mtu_exceeded(proto: Ipv6Proto, header_len: usize, mtu: Mtu) -> Option<Icmpv6ErrorKind> {
369 Some(Icmpv6ErrorKind::PacketTooBig { proto, header_len, mtu })
370 }
371}
372
373pub(crate) enum Icmpv4ErrorKind {
375 ParameterProblem {
376 code: Icmpv4ParameterProblemCode,
377 pointer: u8,
378 fragment_type: Ipv4FragmentType,
379 },
380 TtlExpired {
381 proto: Ipv4Proto,
382 fragment_type: Ipv4FragmentType,
383 },
384 NetUnreachable {
385 proto: Ipv4Proto,
386 fragment_type: Ipv4FragmentType,
387 },
388 ProtocolUnreachable,
389 PortUnreachable,
390}
391
392pub struct Icmpv4Error {
394 pub(super) kind: Icmpv4ErrorKind,
395 pub(super) header_len: usize,
396}
397
398pub enum Icmpv6ErrorKind {
400 ParameterProblem { code: Icmpv6ParameterProblemCode, pointer: u32, allow_dst_multicast: bool },
401 TtlExpired { proto: Ipv6Proto, header_len: usize },
402 NetUnreachable { proto: Ipv6Proto, header_len: usize },
403 PacketTooBig { proto: Ipv6Proto, header_len: usize, mtu: Mtu },
404 ProtocolUnreachable { header_len: usize },
405 PortUnreachable,
406}
407
408pub trait IcmpErrorHandler<I: IcmpHandlerIpExt, BC>: DeviceIdContext<AnyDevice> {
410 fn send_icmp_error_message<B: BufferMut>(
415 &mut self,
416 bindings_ctx: &mut BC,
417 device: &Self::DeviceId,
418 frame_dst: Option<FrameDestination>,
419 src_ip: I::SourceAddress,
420 dst_ip: SpecifiedAddr<I::Addr>,
421 original_packet: B,
422 error: I::IcmpError,
423 marks: &Marks,
424 );
425}
426
427impl<
428 BC: IcmpBindingsContext,
429 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
430 > IcmpErrorHandler<Ipv4, BC> for CC
431{
432 fn send_icmp_error_message<B: BufferMut>(
433 &mut self,
434 bindings_ctx: &mut BC,
435 device: &CC::DeviceId,
436 frame_dst: Option<FrameDestination>,
437 src_ip: NonMulticastAddr<SpecifiedAddr<Ipv4Addr>>,
438 dst_ip: SpecifiedAddr<Ipv4Addr>,
439 original_packet: B,
440 Icmpv4Error { kind, header_len }: Icmpv4Error,
441 marks: &Marks,
442 ) {
443 let src_ip = SocketIpAddr::new_ipv4_specified(src_ip.get());
444 let dst_ip = SocketIpAddr::new_ipv4_specified(dst_ip);
445 match kind {
446 Icmpv4ErrorKind::ParameterProblem { code, pointer, fragment_type } => {
447 send_icmpv4_parameter_problem(
448 self,
449 bindings_ctx,
450 device,
451 frame_dst,
452 src_ip,
453 dst_ip,
454 code,
455 Icmpv4ParameterProblem::new(pointer),
456 original_packet,
457 header_len,
458 fragment_type,
459 marks,
460 )
461 }
462 Icmpv4ErrorKind::TtlExpired { proto, fragment_type } => send_icmpv4_ttl_expired(
463 self,
464 bindings_ctx,
465 device,
466 frame_dst,
467 src_ip,
468 dst_ip,
469 proto,
470 original_packet,
471 header_len,
472 fragment_type,
473 marks,
474 ),
475 Icmpv4ErrorKind::NetUnreachable { proto, fragment_type } => {
476 send_icmpv4_net_unreachable(
477 self,
478 bindings_ctx,
479 device,
480 frame_dst,
481 src_ip,
482 dst_ip,
483 proto,
484 original_packet,
485 header_len,
486 fragment_type,
487 marks,
488 )
489 }
490 Icmpv4ErrorKind::ProtocolUnreachable => send_icmpv4_protocol_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 Icmpv4ErrorKind::PortUnreachable => send_icmpv4_port_unreachable(
502 self,
503 bindings_ctx,
504 device,
505 frame_dst,
506 src_ip,
507 dst_ip,
508 original_packet,
509 header_len,
510 marks,
511 ),
512 }
513 }
514}
515
516impl<
517 BC: IcmpBindingsContext,
518 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
519 > IcmpErrorHandler<Ipv6, BC> for CC
520{
521 fn send_icmp_error_message<B: BufferMut>(
522 &mut self,
523 bindings_ctx: &mut BC,
524 device: &CC::DeviceId,
525 frame_dst: Option<FrameDestination>,
526 src_ip: UnicastAddr<Ipv6Addr>,
527 dst_ip: SpecifiedAddr<Ipv6Addr>,
528 original_packet: B,
529 error: Icmpv6ErrorKind,
530 marks: &Marks,
531 ) {
532 let src_ip: SocketIpAddr<Ipv6Addr> = match src_ip.into_specified().try_into() {
533 Ok(addr) => addr,
534 Err(AddrIsMappedError {}) => {
535 trace!("send_icmpv6_error_message: src_ip is mapped");
536 return;
537 }
538 };
539 let dst_ip: SocketIpAddr<Ipv6Addr> = match dst_ip.try_into() {
540 Ok(addr) => addr,
541 Err(AddrIsMappedError {}) => {
542 trace!("send_icmpv6_error_message: dst_ip is mapped");
543 return;
544 }
545 };
546
547 match error {
548 Icmpv6ErrorKind::ParameterProblem { code, pointer, allow_dst_multicast } => {
549 send_icmpv6_parameter_problem(
550 self,
551 bindings_ctx,
552 device,
553 frame_dst,
554 src_ip,
555 dst_ip,
556 code,
557 Icmpv6ParameterProblem::new(pointer),
558 original_packet,
559 allow_dst_multicast,
560 marks,
561 )
562 }
563 Icmpv6ErrorKind::TtlExpired { proto, header_len } => send_icmpv6_ttl_expired(
564 self,
565 bindings_ctx,
566 device,
567 frame_dst,
568 src_ip,
569 dst_ip,
570 proto,
571 original_packet,
572 header_len,
573 marks,
574 ),
575 Icmpv6ErrorKind::NetUnreachable { proto, header_len } => send_icmpv6_net_unreachable(
576 self,
577 bindings_ctx,
578 device,
579 frame_dst,
580 src_ip,
581 dst_ip,
582 proto,
583 original_packet,
584 header_len,
585 marks,
586 ),
587 Icmpv6ErrorKind::PacketTooBig { proto, header_len, mtu } => send_icmpv6_packet_too_big(
588 self,
589 bindings_ctx,
590 device,
591 frame_dst,
592 src_ip,
593 dst_ip,
594 proto,
595 mtu,
596 original_packet,
597 header_len,
598 marks,
599 ),
600 Icmpv6ErrorKind::ProtocolUnreachable { header_len } => {
601 send_icmpv6_protocol_unreachable(
602 self,
603 bindings_ctx,
604 device,
605 frame_dst,
606 src_ip,
607 dst_ip,
608 original_packet,
609 header_len,
610 marks,
611 )
612 }
613 Icmpv6ErrorKind::PortUnreachable => send_icmpv6_port_unreachable(
614 self,
615 bindings_ctx,
616 device,
617 frame_dst,
618 src_ip,
619 dst_ip,
620 original_packet,
621 marks,
622 ),
623 }
624 }
625}
626
627pub trait IcmpBindingsContext: InstantContext + RngContext + IcmpBindingsTypes {}
630impl<BC> IcmpBindingsContext for BC where
631 BC: InstantContext + RngContext + IcmpBindingsTypes + IcmpBindingsTypes
632{
633}
634
635pub trait IcmpBindingsTypes: InstantBindingsTypes + TxMetadataBindingsTypes {}
637impl<BT: InstantBindingsTypes + TxMetadataBindingsTypes> IcmpBindingsTypes for BT {}
638
639pub trait IcmpStateContext {}
647
648pub trait EchoTransportContextMarker {}
658
659pub trait InnerIcmpContext<I: IpExt + FilterIpExt, BC: IcmpBindingsTypes>:
662 IpSocketHandler<I, BC>
663{
664 type EchoTransportContext: IpTransportContext<I, BC, Self> + EchoTransportContextMarker;
667
668 fn receive_icmp_error(
698 &mut self,
699 bindings_ctx: &mut BC,
700 device: &Self::DeviceId,
701 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
702 original_dst_ip: SpecifiedAddr<I::Addr>,
703 original_proto: I::Proto,
704 original_body: &[u8],
705 err: I::ErrorCode,
706 );
707
708 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
711 &mut self,
712 cb: F,
713 ) -> O;
714}
715
716pub trait InnerIcmpv4Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv4, BC> {
720 fn should_send_timestamp_reply(&self) -> bool;
722}
723
724pub trait InnerIcmpv6Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv6, BC> {}
728impl<BC: IcmpBindingsTypes, CC: InnerIcmpContext<Ipv6, BC>> InnerIcmpv6Context<BC> for CC {}
729
730macro_rules! try_send_error {
744 ($core_ctx:expr, $bindings_ctx:expr, $e:expr) => {{
745 let send = $core_ctx.with_error_send_bucket_mut(|error_send_bucket| {
746 error_send_bucket.try_take($bindings_ctx)
747 });
748
749 if send {
750 $core_ctx.counters().error.increment();
751 $e
752 } else {
753 trace!("ip::icmp::try_send_error!: dropping rate-limited ICMP error message");
754 Ok(())
755 }
756 }};
757}
758
759pub enum IcmpIpTransportContext {}
761
762fn receive_ip_transport_icmp_error<
763 I: IpExt + FilterIpExt,
764 CC: InnerIcmpContext<I, BC> + CounterContext<IcmpRxCounters<I>>,
765 BC: IcmpBindingsContext,
766>(
767 core_ctx: &mut CC,
768 bindings_ctx: &mut BC,
769 device: &CC::DeviceId,
770 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
771 original_dst_ip: SpecifiedAddr<I::Addr>,
772 original_body: &[u8],
773 err: I::ErrorCode,
774) {
775 core_ctx.counters().error_delivered_to_transport_layer.increment();
776 trace!("IcmpIpTransportContext::receive_icmp_error({:?})", err);
777
778 let mut parse_body = original_body;
779 match parse_body.parse::<IcmpPacketRaw<I, _, IcmpEchoRequest>>() {
780 Ok(_echo_request) => (),
783 Err(_) => {
784 return;
788 }
789 }
790
791 <CC::EchoTransportContext as IpTransportContext<I, BC, CC>>::receive_icmp_error(
792 core_ctx,
793 bindings_ctx,
794 device,
795 original_src_ip,
796 original_dst_ip,
797 original_body,
798 err,
799 );
800}
801
802impl<
803 BC: IcmpBindingsContext,
804 CC: InnerIcmpv4Context<BC>
805 + PmtuHandler<Ipv4, BC>
806 + CounterContext<IcmpRxCounters<Ipv4>>
807 + CounterContext<IcmpTxCounters<Ipv4>>,
808 > IpTransportContext<Ipv4, BC, CC> for IcmpIpTransportContext
809{
810 fn receive_icmp_error(
811 core_ctx: &mut CC,
812 bindings_ctx: &mut BC,
813 device: &CC::DeviceId,
814 original_src_ip: Option<SpecifiedAddr<Ipv4Addr>>,
815 original_dst_ip: SpecifiedAddr<Ipv4Addr>,
816 original_body: &[u8],
817 err: Icmpv4ErrorCode,
818 ) {
819 receive_ip_transport_icmp_error(
820 core_ctx,
821 bindings_ctx,
822 device,
823 original_src_ip,
824 original_dst_ip,
825 original_body,
826 err,
827 )
828 }
829
830 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv4>>(
831 core_ctx: &mut CC,
832 bindings_ctx: &mut BC,
833 device: &CC::DeviceId,
834 src_ip: Ipv4SourceAddr,
835 dst_ip: SpecifiedAddr<Ipv4Addr>,
836 mut buffer: B,
837 info: &LocalDeliveryPacketInfo<Ipv4, H>,
838 ) -> Result<(), (B, TransportReceiveError)> {
839 let LocalDeliveryPacketInfo { meta, header_info: _, marks } = info;
840 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
841 if let Some(delivery) = transparent_override {
842 unreachable!(
843 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
844 transparent proxy rules can only be configured for TCP and UDP packets"
845 );
846 }
847
848 trace!(
849 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet({}, {})",
850 src_ip,
851 dst_ip
852 );
853 let packet =
854 match buffer.parse_with::<_, Icmpv4Packet<_>>(IcmpParseArgs::new(src_ip, dst_ip)) {
855 Ok(packet) => packet,
856 Err(_) => return Ok(()), };
858
859 match packet {
860 Icmpv4Packet::EchoRequest(echo_request) => {
861 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_request.increment();
862
863 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
864 let req = *echo_request.message();
865 let code = echo_request.code();
866 let (local_ip, remote_ip) = (dst_ip, src_ip);
867 debug!(
868 "replying to ICMP echo request from {remote_ip} to {local_ip}%{device:?}: \
869 id={}, seq={}",
870 req.id(),
871 req.seq()
872 );
873 send_icmp_reply(
874 core_ctx,
875 bindings_ctx,
876 device,
877 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
878 SocketIpAddr::new_ipv4_specified(local_ip),
879 |src_ip| {
880 buffer.encapsulate(IcmpPacketBuilder::<Ipv4, _>::new(
881 src_ip,
882 *remote_ip,
883 code,
884 req.reply(),
885 ))
886 },
887 &WithMarks(marks),
888 );
889 } else {
890 trace!(
891 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
892 Received echo request with an unspecified source address"
893 );
894 }
895 }
896 Icmpv4Packet::EchoReply(echo_reply) => {
897 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_reply.increment();
898 trace!(
899 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
900 Received an EchoReply message"
901 );
902 let parse_metadata = echo_reply.parse_metadata();
903 buffer.undo_parse(parse_metadata);
904 return <CC::EchoTransportContext
905 as IpTransportContext<Ipv4, BC, CC>>::receive_ip_packet(
906 core_ctx,
907 bindings_ctx,
908 device,
909 src_ip,
910 dst_ip,
911 buffer,
912 info,
913 );
914 }
915 Icmpv4Packet::TimestampRequest(timestamp_request) => {
916 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
917 .timestamp_request
918 .increment();
919 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
920 if core_ctx.should_send_timestamp_reply() {
921 trace!(
922 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
923 receive_ip_packet: Responding to Timestamp Request message"
924 );
925 const NOW: u32 = 0x80000000;
944 let reply = timestamp_request.message().reply(NOW, NOW);
945 let (local_ip, remote_ip) = (dst_ip, src_ip);
946 buffer.shrink_front_to(0);
953 send_icmp_reply(
954 core_ctx,
955 bindings_ctx,
956 device,
957 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
958 SocketIpAddr::new_ipv4_specified(local_ip),
959 |src_ip| {
960 buffer.encapsulate(IcmpPacketBuilder::<Ipv4, _>::new(
961 src_ip,
962 *remote_ip,
963 IcmpZeroCode,
964 reply,
965 ))
966 },
967 &WithMarks(marks),
968 );
969 } else {
970 trace!(
971 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
972 receive_ip_packet: Silently ignoring Timestamp Request message"
973 );
974 }
975 } else {
976 trace!(
977 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
978 receive_ip_packet: Received timestamp request with an unspecified source \
979 address"
980 );
981 }
982 }
983 Icmpv4Packet::TimestampReply(_) => {
984 debug!(
987 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
988 Received unsolicited Timestamp Reply message"
989 );
990 }
991 Icmpv4Packet::DestUnreachable(dest_unreachable) => {
992 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
993 .dest_unreachable
994 .increment();
995 trace!(
996 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
997 Received a Destination Unreachable message"
998 );
999
1000 let error = if dest_unreachable.code()
1001 == Icmpv4DestUnreachableCode::FragmentationRequired
1002 {
1003 let mtu = if let Some(next_hop_mtu) = dest_unreachable.message().next_hop_mtu()
1004 {
1005 core_ctx.update_pmtu_if_less(
1015 bindings_ctx,
1016 dst_ip.get(),
1017 src_ip.get(),
1018 Mtu::new(u32::from(next_hop_mtu.get())),
1019 )
1020 } else {
1021 let (original_packet_buf, inner_body) = dest_unreachable.body().bytes();
1043 debug_assert!(inner_body.is_none());
1045 if original_packet_buf.len() >= 4 {
1046 let total_len =
1050 u16::from_be_bytes(original_packet_buf[2..4].try_into().unwrap());
1051
1052 trace!(
1053 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1054 receive_ip_packet: Next-Hop MTU is 0 so using the next best PMTU \
1055 value from {total_len}"
1056 );
1057
1058 core_ctx.update_pmtu_next_lower(
1059 bindings_ctx,
1060 dst_ip.get(),
1061 src_ip.get(),
1062 Mtu::new(u32::from(total_len)),
1063 )
1064 } else {
1065 trace!(
1070 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1071 receive_ip_packet: Original packet buf is too small to get \
1072 original packet len so ignoring"
1073 );
1074 None
1075 }
1076 };
1077 mtu.and_then(|mtu| {
1078 let mtu = u16::try_from(mtu.get()).unwrap_or(u16::MAX);
1079 let mtu = NonZeroU16::new(mtu)?;
1080 Some(Icmpv4ErrorCode::DestUnreachable(
1081 dest_unreachable.code(),
1082 IcmpDestUnreachable::new_for_frag_req(mtu),
1083 ))
1084 })
1085 } else {
1086 Some(Icmpv4ErrorCode::DestUnreachable(
1087 dest_unreachable.code(),
1088 *dest_unreachable.message(),
1089 ))
1090 };
1091
1092 if let Some(error) = error {
1093 receive_icmpv4_error(core_ctx, bindings_ctx, device, &dest_unreachable, error);
1094 }
1095 }
1096 Icmpv4Packet::TimeExceeded(time_exceeded) => {
1097 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1098 .time_exceeded
1099 .increment();
1100 trace!(
1101 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1102 Received a Time Exceeded message"
1103 );
1104
1105 receive_icmpv4_error(
1106 core_ctx,
1107 bindings_ctx,
1108 device,
1109 &time_exceeded,
1110 Icmpv4ErrorCode::TimeExceeded(time_exceeded.code()),
1111 );
1112 }
1113 Icmpv4Packet::Redirect(_) => {
1115 debug!(
1116 "Unimplemented: <IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1117 receive_ip_packet::redirect"
1118 )
1119 }
1120 Icmpv4Packet::ParameterProblem(parameter_problem) => {
1121 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1122 .parameter_problem
1123 .increment();
1124 trace!(
1125 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1126 Received a Parameter Problem message"
1127 );
1128
1129 receive_icmpv4_error(
1130 core_ctx,
1131 bindings_ctx,
1132 device,
1133 ¶meter_problem,
1134 Icmpv4ErrorCode::ParameterProblem(parameter_problem.code()),
1135 );
1136 }
1137 }
1138
1139 Ok(())
1140 }
1141}
1142
1143#[allow(missing_docs)]
1146pub enum NdpMessage {
1147 NeighborSolicitation {
1148 message: NeighborSolicitation,
1149 code: <NeighborSolicitation as IcmpMessage<Ipv6>>::Code,
1150 },
1151
1152 RouterSolicitation {
1153 message: RouterSolicitation,
1154 code: <RouterSolicitation as IcmpMessage<Ipv6>>::Code,
1155 },
1156
1157 NeighborAdvertisement {
1158 message: NeighborAdvertisement,
1159 code: <NeighborAdvertisement as IcmpMessage<Ipv6>>::Code,
1160 },
1161}
1162
1163pub fn send_ndp_packet<BC, CC, S>(
1165 core_ctx: &mut CC,
1166 bindings_ctx: &mut BC,
1167 device_id: &CC::DeviceId,
1168 src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1169 dst_ip: SpecifiedAddr<Ipv6Addr>,
1170 body: S,
1171 message: NdpMessage,
1172) -> Result<(), IpSendFrameError<S>>
1173where
1174 CC: IpLayerHandler<Ipv6, BC>,
1175 S: Serializer,
1176 S::Buffer: BufferMut,
1177{
1178 macro_rules! send {
1179 ($message:expr, $code:expr) => {{
1180 IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
1182 core_ctx,
1183 bindings_ctx,
1184 SendIpPacketMeta {
1185 device: device_id,
1186 src_ip,
1187 dst_ip,
1188 destination: IpPacketDestination::from_addr(dst_ip),
1189 ttl: NonZeroU8::new(REQUIRED_NDP_IP_PACKET_HOP_LIMIT),
1190 proto: Ipv6Proto::Icmpv6,
1191 mtu: Mtu::no_limit(),
1192 dscp_and_ecn: DscpAndEcn::default(),
1193 },
1194 body.encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
1195 src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
1196 dst_ip.get(),
1197 $code,
1198 $message,
1199 )),
1200 )
1201 .map_err(|s| s.into_inner())
1202 }};
1203 }
1204
1205 match message {
1206 NdpMessage::NeighborSolicitation { message, code } => send!(message, code),
1207 NdpMessage::RouterSolicitation { message, code } => send!(message, code),
1208 NdpMessage::NeighborAdvertisement { message, code } => send!(message, code),
1209 }
1210}
1211
1212fn send_neighbor_advertisement<
1213 BC,
1214 CC: Ipv6DeviceHandler<BC>
1215 + IpDeviceHandler<Ipv6, BC>
1216 + IpLayerHandler<Ipv6, BC>
1217 + CounterContext<NdpCounters>,
1218>(
1219 core_ctx: &mut CC,
1220 bindings_ctx: &mut BC,
1221 device_id: &CC::DeviceId,
1222 solicited: bool,
1223 device_addr: UnicastAddr<Ipv6Addr>,
1224 dst_ip: SpecifiedAddr<Ipv6Addr>,
1225) {
1226 core_ctx.counters().tx.neighbor_advertisement.increment();
1227 debug!("send_neighbor_advertisement from {:?} to {:?}", device_addr, dst_ip);
1228 debug_assert!(dst_ip.is_valid_unicast() || (!solicited && dst_ip.is_multicast()));
1235
1236 let src_ll = core_ctx.get_link_layer_addr(&device_id);
1243
1244 let advertisement = NeighborAdvertisement::new(
1246 core_ctx.is_router_device(&device_id),
1247 solicited,
1248 false,
1249 device_addr.get(),
1250 );
1251 let _: Result<(), _> = send_ndp_packet(
1252 core_ctx,
1253 bindings_ctx,
1254 &device_id,
1255 Some(device_addr.into_specified()),
1256 dst_ip,
1257 OptionSequenceBuilder::new(
1258 src_ll
1259 .as_ref()
1260 .map(Ipv6LinkLayerAddr::as_bytes)
1261 .map(NdpOptionBuilder::TargetLinkLayerAddress)
1262 .iter(),
1263 )
1264 .into_serializer(),
1265 NdpMessage::NeighborAdvertisement { message: advertisement, code: IcmpZeroCode },
1266 );
1267}
1268
1269fn receive_ndp_packet<
1270 B: SplitByteSlice,
1271 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1272 CC: InnerIcmpv6Context<BC>
1273 + Ipv6DeviceHandler<BC>
1274 + IpDeviceHandler<Ipv6, BC>
1275 + IpDeviceIngressStateContext<Ipv6>
1276 + NudIpHandler<Ipv6, BC>
1277 + IpLayerHandler<Ipv6, BC>
1278 + CounterContext<NdpCounters>,
1279 H: IpHeaderInfo<Ipv6>,
1280>(
1281 core_ctx: &mut CC,
1282 bindings_ctx: &mut BC,
1283 device_id: &CC::DeviceId,
1284 src_ip: Ipv6SourceAddr,
1285 packet: NdpPacket<B>,
1286 header_info: &H,
1287) {
1288 if header_info.hop_limit() != REQUIRED_NDP_IP_PACKET_HOP_LIMIT {
1306 trace!("dropping NDP packet from {src_ip} with invalid hop limit");
1307 return;
1308 }
1309
1310 match packet {
1311 NdpPacket::RouterSolicitation(_) | NdpPacket::Redirect(_) => {}
1312 NdpPacket::NeighborSolicitation(ref p) => {
1313 let target_address = p.message().target_address();
1314 let target_address = match UnicastAddr::new(*target_address) {
1315 Some(a) => a,
1316 None => {
1317 trace!(
1318 "dropping NS from {} with non-unicast target={:?}",
1319 src_ip,
1320 target_address
1321 );
1322 return;
1323 }
1324 };
1325
1326 core_ctx.counters().rx.neighbor_solicitation.increment();
1327
1328 match src_ip {
1329 Ipv6SourceAddr::Unspecified => {
1330 match Ipv6DeviceHandler::handle_received_dad_neighbor_solicitation(
1340 core_ctx,
1341 bindings_ctx,
1342 &device_id,
1343 target_address,
1344 p.body().iter().find_map(|option| option.nonce()),
1345 ) {
1346 IpAddressState::Assigned => {
1347 send_neighbor_advertisement(
1351 core_ctx,
1352 bindings_ctx,
1353 &device_id,
1354 false,
1355 target_address,
1356 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified(),
1357 );
1358 }
1359 IpAddressState::Tentative => {
1360 }
1363 IpAddressState::Unavailable => {
1364 }
1367 }
1368
1369 return;
1370 }
1371 Ipv6SourceAddr::Unicast(src_ip) => {
1372 match core_ctx
1374 .address_status_for_device(target_address.into_specified(), device_id)
1375 {
1376 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned) => {}
1377 AddressStatus::Present(
1378 Ipv6PresentAddressStatus::UnicastTentative
1379 | Ipv6PresentAddressStatus::Multicast,
1380 )
1381 | AddressStatus::Unassigned => {
1382 return;
1386 }
1387 }
1388
1389 let link_addr = p.body().iter().find_map(|o| o.source_link_layer_address());
1390
1391 if let Some(link_addr) = link_addr {
1392 NudIpHandler::handle_neighbor_probe(
1393 core_ctx,
1394 bindings_ctx,
1395 &device_id,
1396 src_ip.into_specified(),
1397 link_addr,
1398 );
1399 }
1400
1401 send_neighbor_advertisement(
1402 core_ctx,
1403 bindings_ctx,
1404 &device_id,
1405 true,
1406 target_address,
1407 src_ip.into_specified(),
1408 );
1409 }
1410 }
1411 }
1412 NdpPacket::NeighborAdvertisement(ref p) => {
1413 let target_address = p.message().target_address();
1417
1418 let src_ip = match src_ip {
1419 Ipv6SourceAddr::Unicast(src_ip) => src_ip,
1420 Ipv6SourceAddr::Unspecified => {
1421 trace!("dropping NA with unspecified source and target = {:?}", target_address);
1422 return;
1423 }
1424 };
1425
1426 let target_address = match UnicastAddr::new(*target_address) {
1427 Some(a) => a,
1428 None => {
1429 trace!(
1430 "dropping NA from {} with non-unicast target={:?}",
1431 src_ip,
1432 target_address
1433 );
1434 return;
1435 }
1436 };
1437
1438 core_ctx.counters().rx.neighbor_advertisement.increment();
1439
1440 match Ipv6DeviceHandler::handle_received_neighbor_advertisement(
1441 core_ctx,
1442 bindings_ctx,
1443 &device_id,
1444 target_address,
1445 ) {
1446 IpAddressState::Assigned => {
1447 error!(
1465 "NA from {src_ip} with target address {target_address} that is also \
1466 assigned on device {device_id:?}",
1467 );
1468 }
1469 IpAddressState::Tentative => {
1470 return;
1473 }
1474 IpAddressState::Unavailable => {
1475 }
1479 }
1480
1481 let link_addr = p.body().iter().find_map(|o| o.target_link_layer_address());
1482 let link_addr = match link_addr {
1483 Some(a) => a,
1484 None => {
1485 trace!(
1486 "dropping NA from {} targetting {} with no TLL option",
1487 src_ip,
1488 target_address
1489 );
1490 return;
1491 }
1492 };
1493
1494 NudIpHandler::handle_neighbor_confirmation(
1495 core_ctx,
1496 bindings_ctx,
1497 &device_id,
1498 target_address.into_specified(),
1499 link_addr,
1500 ConfirmationFlags {
1501 solicited_flag: p.message().solicited_flag(),
1502 override_flag: p.message().override_flag(),
1503 },
1504 );
1505 }
1506 NdpPacket::RouterAdvertisement(ref p) => {
1507 let src_ip = match src_ip {
1520 Ipv6SourceAddr::Unicast(ip) => match LinkLocalUnicastAddr::new(*ip) {
1521 Some(ip) => ip,
1522 None => return,
1523 },
1524 Ipv6SourceAddr::Unspecified => return,
1525 };
1526
1527 let ra = p.message();
1528 debug!("received router advertisement from {:?}: {:?}", src_ip, ra);
1529 core_ctx.counters().rx.router_advertisement.increment();
1530
1531 if let Some(retransmit_timer) = ra.retransmit_timer() {
1538 Ipv6DeviceHandler::set_discovered_retrans_timer(
1539 core_ctx,
1540 bindings_ctx,
1541 &device_id,
1542 retransmit_timer,
1543 );
1544 }
1545
1546 if let Some(hop_limit) = ra.current_hop_limit() {
1553 trace!("receive_ndp_packet: NDP RA: updating device's hop limit to {:?} for router: {:?}", ra.current_hop_limit(), src_ip);
1554 IpDeviceHandler::set_default_hop_limit(core_ctx, &device_id, hop_limit);
1555 }
1556
1557 Ipv6DeviceHandler::update_discovered_ipv6_route(
1559 core_ctx,
1560 bindings_ctx,
1561 &device_id,
1562 Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) },
1563 p.message().router_lifetime().map(NonZeroNdpLifetime::Finite),
1564 );
1565
1566 for option in p.body().iter() {
1567 match option {
1568 NdpOption::TargetLinkLayerAddress(_)
1569 | NdpOption::RedirectedHeader { .. }
1570 | NdpOption::RecursiveDnsServer(_)
1571 | NdpOption::Nonce(_) => {}
1572 NdpOption::SourceLinkLayerAddress(addr) => {
1573 debug!("processing SourceLinkLayerAddress option in RA: {:?}", addr);
1574 NudIpHandler::handle_neighbor_probe(
1600 core_ctx,
1601 bindings_ctx,
1602 &device_id,
1603 {
1604 let src_ip: UnicastAddr<_> = src_ip.into_addr();
1605 src_ip.into_specified()
1606 },
1607 addr,
1608 );
1609 }
1610 NdpOption::PrefixInformation(prefix_info) => {
1611 debug!("processing Prefix Information option in RA: {:?}", prefix_info);
1612 if prefix_info.prefix().is_link_local() {
1630 continue;
1631 }
1632
1633 let subnet = match prefix_info.subnet() {
1634 Ok(subnet) => subnet,
1635 Err(err) => match err {
1636 SubnetError::PrefixTooLong | SubnetError::HostBitsSet => continue,
1637 },
1638 };
1639
1640 match UnicastAddr::new(subnet.network()) {
1641 Some(UnicastAddr { .. }) => {}
1642 None => continue,
1643 }
1644
1645 let valid_lifetime = prefix_info.valid_lifetime();
1646
1647 if prefix_info.on_link_flag() {
1648 Ipv6DeviceHandler::update_discovered_ipv6_route(
1650 core_ctx,
1651 bindings_ctx,
1652 &device_id,
1653 Ipv6DiscoveredRoute { subnet, gateway: None },
1654 valid_lifetime,
1655 )
1656 }
1657
1658 if prefix_info.autonomous_address_configuration_flag() {
1659 Ipv6DeviceHandler::apply_slaac_update(
1660 core_ctx,
1661 bindings_ctx,
1662 &device_id,
1663 subnet,
1664 prefix_info.preferred_lifetime(),
1665 valid_lifetime,
1666 );
1667 }
1668 }
1669 NdpOption::RouteInformation(rio) => {
1670 debug!("processing Route Information option in RA: {:?}", rio);
1671 Ipv6DeviceHandler::update_discovered_ipv6_route(
1673 core_ctx,
1674 bindings_ctx,
1675 &device_id,
1676 Ipv6DiscoveredRoute {
1677 subnet: rio.prefix().clone(),
1678 gateway: Some(src_ip),
1679 },
1680 rio.route_lifetime(),
1681 )
1682 }
1683 NdpOption::Mtu(mtu) => {
1684 debug!("processing MTU option in RA: {:?}", mtu);
1685 Ipv6DeviceHandler::set_link_mtu(core_ctx, &device_id, Mtu::new(mtu));
1689 }
1690 }
1691 }
1692
1693 bindings_ctx.on_event(RouterAdvertisementEvent {
1694 options_bytes: Box::from(p.body().bytes()),
1695 source: **src_ip,
1696 device: device_id.clone(),
1697 });
1698 }
1699 }
1700}
1701
1702impl<
1703 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1704 CC: InnerIcmpv6Context<BC>
1705 + InnerIcmpContext<Ipv6, BC>
1706 + Ipv6DeviceHandler<BC>
1707 + IpDeviceHandler<Ipv6, BC>
1708 + IpDeviceIngressStateContext<Ipv6>
1709 + PmtuHandler<Ipv6, BC>
1710 + NudIpHandler<Ipv6, BC>
1711 + IpLayerHandler<Ipv6, BC>
1712 + CounterContext<IcmpRxCounters<Ipv6>>
1713 + CounterContext<IcmpTxCounters<Ipv6>>
1714 + CounterContext<NdpCounters>,
1715 > IpTransportContext<Ipv6, BC, CC> for IcmpIpTransportContext
1716{
1717 fn receive_icmp_error(
1718 core_ctx: &mut CC,
1719 bindings_ctx: &mut BC,
1720 device: &CC::DeviceId,
1721 original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1722 original_dst_ip: SpecifiedAddr<Ipv6Addr>,
1723 original_body: &[u8],
1724 err: Icmpv6ErrorCode,
1725 ) {
1726 receive_ip_transport_icmp_error(
1727 core_ctx,
1728 bindings_ctx,
1729 device,
1730 original_src_ip,
1731 original_dst_ip,
1732 original_body,
1733 err,
1734 )
1735 }
1736
1737 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
1738 core_ctx: &mut CC,
1739 bindings_ctx: &mut BC,
1740 device: &CC::DeviceId,
1741 src_ip: Ipv6SourceAddr,
1742 dst_ip: SpecifiedAddr<Ipv6Addr>,
1743 mut buffer: B,
1744 info: &LocalDeliveryPacketInfo<Ipv6, H>,
1745 ) -> Result<(), (B, TransportReceiveError)> {
1746 let LocalDeliveryPacketInfo { meta, header_info, marks } = info;
1747 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
1748 if let Some(delivery) = transparent_override {
1749 unreachable!(
1750 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
1751 transparent proxy rules can only be configured for TCP and UDP packets"
1752 );
1753 }
1754
1755 trace!(
1756 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet({:?}, {})",
1757 src_ip,
1758 dst_ip
1759 );
1760
1761 let packet = match buffer
1762 .parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(src_ip.get(), dst_ip))
1763 {
1764 Ok(packet) => packet,
1765 Err(_) => return Ok(()), };
1767
1768 match packet {
1769 Icmpv6Packet::EchoRequest(echo_request) => {
1770 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_request.increment();
1771
1772 if let Some(src_ip) = SocketIpAddr::new_from_ipv6_source(src_ip) {
1773 match SocketIpAddr::try_from(dst_ip) {
1774 Ok(dst_ip) => {
1775 let req = *echo_request.message();
1776 let code = echo_request.code();
1777 let (local_ip, remote_ip) = (dst_ip, src_ip);
1778 debug!(
1779 "replying to ICMP echo request from {remote_ip}: id={}, seq={}",
1780 req.id(),
1781 req.seq()
1782 );
1783 send_icmp_reply(
1784 core_ctx,
1785 bindings_ctx,
1786 device,
1787 remote_ip,
1788 local_ip,
1789 |src_ip| {
1790 buffer.encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
1791 src_ip,
1792 remote_ip.addr(),
1793 code,
1794 req.reply(),
1795 ))
1796 },
1797 &WithMarks(marks),
1798 );
1799 }
1800 Err(AddrIsMappedError {}) => {
1801 trace!("IpTransportContext<Ipv6>::receive_ip_packet: Received echo request with an ipv4-mapped-ipv6 destination address");
1802 }
1803 }
1804 } else {
1805 trace!("<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received echo request with an unspecified source address");
1806 }
1807 }
1808 Icmpv6Packet::EchoReply(echo_reply) => {
1809 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_reply.increment();
1810 trace!("<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received an EchoReply message");
1811 let parse_metadata = echo_reply.parse_metadata();
1812 buffer.undo_parse(parse_metadata);
1813 return <CC::EchoTransportContext
1814 as IpTransportContext<Ipv6, BC, CC>>::receive_ip_packet(
1815 core_ctx,
1816 bindings_ctx,
1817 device,
1818 src_ip,
1819 dst_ip,
1820 buffer,
1821 info
1822 );
1823 }
1824 Icmpv6Packet::Ndp(packet) => {
1825 receive_ndp_packet(core_ctx, bindings_ctx, device, src_ip, packet, header_info)
1826 }
1827 Icmpv6Packet::PacketTooBig(packet_too_big) => {
1828 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
1829 .packet_too_big
1830 .increment();
1831 trace!("<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received a Packet Too Big message");
1832 let new_mtu = if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
1833 core_ctx.update_pmtu_if_less(
1843 bindings_ctx,
1844 dst_ip.get(),
1845 src_ip.get(),
1846 Mtu::new(packet_too_big.message().mtu()),
1847 )
1848 } else {
1849 None
1850 };
1851 if let Some(mtu) = new_mtu {
1852 receive_icmpv6_error(
1853 core_ctx,
1854 bindings_ctx,
1855 device,
1856 &packet_too_big,
1857 Icmpv6ErrorCode::PacketTooBig(mtu),
1858 );
1859 }
1860 }
1861 Icmpv6Packet::Mld(packet) => {
1862 core_ctx.receive_mld_packet(
1863 bindings_ctx,
1864 &device,
1865 src_ip,
1866 dst_ip,
1867 packet,
1868 header_info,
1869 );
1870 }
1871 Icmpv6Packet::DestUnreachable(dest_unreachable) => receive_icmpv6_error(
1872 core_ctx,
1873 bindings_ctx,
1874 device,
1875 &dest_unreachable,
1876 Icmpv6ErrorCode::DestUnreachable(dest_unreachable.code()),
1877 ),
1878 Icmpv6Packet::TimeExceeded(time_exceeded) => receive_icmpv6_error(
1879 core_ctx,
1880 bindings_ctx,
1881 device,
1882 &time_exceeded,
1883 Icmpv6ErrorCode::TimeExceeded(time_exceeded.code()),
1884 ),
1885 Icmpv6Packet::ParameterProblem(parameter_problem) => receive_icmpv6_error(
1886 core_ctx,
1887 bindings_ctx,
1888 device,
1889 ¶meter_problem,
1890 Icmpv6ErrorCode::ParameterProblem(parameter_problem.code()),
1891 ),
1892 }
1893
1894 Ok(())
1895 }
1896}
1897
1898#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1899struct WithMarks<'a>(&'a Marks);
1900
1901impl<'a> OptionDelegationMarker for WithMarks<'a> {}
1902
1903impl<'a, I: IpExt> DelegatedRouteResolutionOptions<I> for WithMarks<'a> {
1904 fn marks(&self) -> &Marks {
1905 let Self(marks) = self;
1906 marks
1907 }
1908}
1909
1910impl<'a, I: IpExt> DelegatedSendOptions<I> for WithMarks<'a> {}
1911
1912fn send_icmp_reply<I, BC, CC, S, F, O>(
1923 core_ctx: &mut CC,
1924 bindings_ctx: &mut BC,
1925 device: &CC::DeviceId,
1926 original_src_ip: SocketIpAddr<I::Addr>,
1927 original_dst_ip: SocketIpAddr<I::Addr>,
1928 get_body_from_src_ip: F,
1929 ip_options: &O,
1930) where
1931 I: IpExt + FilterIpExt,
1932 CC: IpSocketHandler<I, BC> + DeviceIdContext<AnyDevice> + CounterContext<IcmpTxCounters<I>>,
1933 BC: TxMetadataBindingsTypes,
1934 S: TransportPacketSerializer<I>,
1935 S::Buffer: BufferMut,
1936 F: FnOnce(SpecifiedAddr<I::Addr>) -> S,
1937 O: SendOptions<I> + RouteResolutionOptions<I>,
1938{
1939 trace!("send_icmp_reply({:?}, {}, {})", device, original_src_ip, original_dst_ip);
1940 core_ctx.counters().reply.increment();
1941 let tx_metadata: BC::TxMetadata = Default::default();
1942
1943 let egress_device = (original_dst_ip.as_ref().is_multicast()
1947 || original_dst_ip.as_ref().must_have_zone())
1948 .then_some(EitherDeviceId::Strong(device));
1949
1950 core_ctx
1951 .send_oneshot_ip_packet(
1952 bindings_ctx,
1953 egress_device,
1954 IpDeviceAddr::new_from_socket_ip_addr(original_dst_ip),
1955 original_src_ip,
1956 I::ICMP_IP_PROTO,
1957 ip_options,
1958 tx_metadata,
1959 |src_ip| get_body_from_src_ip(src_ip.into()),
1960 )
1961 .unwrap_or_else(|err| {
1962 debug!("failed to send ICMP reply: {}", err);
1963 })
1964}
1965
1966fn receive_icmpv4_error<
1971 BC: IcmpBindingsContext,
1972 CC: InnerIcmpv4Context<BC>,
1973 B: SplitByteSlice,
1974 M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>,
1975>(
1976 core_ctx: &mut CC,
1977 bindings_ctx: &mut BC,
1978 device: &CC::DeviceId,
1979 packet: &IcmpPacket<Ipv4, B, M>,
1980 err: Icmpv4ErrorCode,
1981) {
1982 packet.with_original_packet(|res| match res {
1983 Ok(original_packet) => {
1984 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
1985 Some(ip) => ip,
1986 None => {
1987 trace!("receive_icmpv4_error: Got ICMP error message whose original IPv4 packet contains an unspecified destination address; discarding");
1988 return;
1989 },
1990 };
1991 InnerIcmpContext::receive_icmp_error(
1992 core_ctx,
1993 bindings_ctx,
1994 device,
1995 SpecifiedAddr::new(original_packet.src_ip()),
1996 dst_ip,
1997 original_packet.proto(),
1998 original_packet.body().into_inner(),
1999 err,
2000 );
2001 }
2002 Err(_) => debug!(
2003 "receive_icmpv4_error: Got ICMP error message with unparsable original IPv4 packet"
2004 ),
2005 })
2006}
2007
2008fn receive_icmpv6_error<
2013 BC: IcmpBindingsContext,
2014 CC: InnerIcmpv6Context<BC>,
2015 B: SplitByteSlice,
2016 M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>,
2017>(
2018 core_ctx: &mut CC,
2019 bindings_ctx: &mut BC,
2020 device: &CC::DeviceId,
2021 packet: &IcmpPacket<Ipv6, B, M>,
2022 err: Icmpv6ErrorCode,
2023) {
2024 packet.with_original_packet(|res| match res {
2025 Ok(original_packet) => {
2026 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2027 Some(ip)=>ip,
2028 None => {
2029 trace!("receive_icmpv6_error: Got ICMP error message whose original IPv6 packet contains an unspecified destination address; discarding");
2030 return;
2031 },
2032 };
2033 match original_packet.body_proto() {
2034 Ok((body, proto)) => {
2035 InnerIcmpContext::receive_icmp_error(
2036 core_ctx,
2037 bindings_ctx,
2038 device,
2039 SpecifiedAddr::new(original_packet.src_ip()),
2040 dst_ip,
2041 proto,
2042 body.into_inner(),
2043 err,
2044 );
2045 }
2046 Err(ExtHdrParseError) => {
2047 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");
2048 return;
2051 }
2052 }
2053 }
2054 Err(_body) => debug!(
2055 "receive_icmpv6_error: Got ICMPv6 error message with unparsable original IPv6 packet"
2056 ),
2057 })
2058}
2059
2060pub fn send_icmpv4_host_unreachable<
2078 B: BufferMut,
2079 BC: IcmpBindingsContext,
2080 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2081>(
2082 core_ctx: &mut CC,
2083 bindings_ctx: &mut BC,
2084 device: Option<&CC::DeviceId>,
2085 frame_dst: Option<FrameDestination>,
2086 src_ip: SocketIpAddr<Ipv4Addr>,
2087 dst_ip: SocketIpAddr<Ipv4Addr>,
2088 original_packet: B,
2089 header_len: usize,
2090 fragment_type: Ipv4FragmentType,
2091 marks: &Marks,
2092) {
2093 core_ctx.counters().address_unreachable.increment();
2094
2095 send_icmpv4_dest_unreachable(
2096 core_ctx,
2097 bindings_ctx,
2098 device,
2099 frame_dst,
2100 src_ip,
2101 dst_ip,
2102 Icmpv4DestUnreachableCode::DestHostUnreachable,
2103 original_packet,
2104 header_len,
2105 fragment_type,
2106 marks,
2107 );
2108}
2109
2110pub fn send_icmpv6_address_unreachable<
2121 B: BufferMut,
2122 BC: IcmpBindingsContext,
2123 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2124>(
2125 core_ctx: &mut CC,
2126 bindings_ctx: &mut BC,
2127 device: Option<&CC::DeviceId>,
2128 frame_dst: Option<FrameDestination>,
2129 src_ip: SocketIpAddr<Ipv6Addr>,
2130 dst_ip: SocketIpAddr<Ipv6Addr>,
2131 original_packet: B,
2132 marks: &Marks,
2133) {
2134 core_ctx.counters().address_unreachable.increment();
2135
2136 send_icmpv6_dest_unreachable(
2137 core_ctx,
2138 bindings_ctx,
2139 device,
2140 frame_dst,
2141 src_ip,
2142 dst_ip,
2143 Icmpv6DestUnreachableCode::AddrUnreachable,
2144 original_packet,
2145 marks,
2146 );
2147}
2148
2149pub(crate) fn send_icmpv4_protocol_unreachable<
2161 B: BufferMut,
2162 BC: IcmpBindingsContext,
2163 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2164>(
2165 core_ctx: &mut CC,
2166 bindings_ctx: &mut BC,
2167 device: &CC::DeviceId,
2168 frame_dst: Option<FrameDestination>,
2169 src_ip: SocketIpAddr<Ipv4Addr>,
2170 dst_ip: SocketIpAddr<Ipv4Addr>,
2171 original_packet: B,
2172 header_len: usize,
2173 marks: &Marks,
2174) {
2175 core_ctx.counters().protocol_unreachable.increment();
2176
2177 send_icmpv4_dest_unreachable(
2178 core_ctx,
2179 bindings_ctx,
2180 Some(device),
2181 frame_dst,
2182 src_ip,
2183 dst_ip,
2184 Icmpv4DestUnreachableCode::DestProtocolUnreachable,
2185 original_packet,
2186 header_len,
2187 Ipv4FragmentType::InitialFragment,
2193 marks,
2194 );
2195}
2196
2197pub(crate) fn send_icmpv6_protocol_unreachable<
2207 B: BufferMut,
2208 BC: IcmpBindingsContext,
2209 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2210>(
2211 core_ctx: &mut CC,
2212 bindings_ctx: &mut BC,
2213 device: &CC::DeviceId,
2214 frame_dst: Option<FrameDestination>,
2215 src_ip: SocketIpAddr<Ipv6Addr>,
2216 dst_ip: SocketIpAddr<Ipv6Addr>,
2217 original_packet: B,
2218 header_len: usize,
2219 marks: &Marks,
2220) {
2221 core_ctx.counters().protocol_unreachable.increment();
2222
2223 send_icmpv6_parameter_problem(
2224 core_ctx,
2225 bindings_ctx,
2226 device,
2227 frame_dst,
2228 src_ip,
2229 dst_ip,
2230 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2231 Icmpv6ParameterProblem::new(header_len as u32),
2245 original_packet,
2246 false,
2247 marks,
2248 );
2249}
2250
2251pub(crate) fn send_icmpv4_port_unreachable<
2263 B: BufferMut,
2264 BC: IcmpBindingsContext,
2265 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2266>(
2267 core_ctx: &mut CC,
2268 bindings_ctx: &mut BC,
2269 device: &CC::DeviceId,
2270 frame_dst: Option<FrameDestination>,
2271 src_ip: SocketIpAddr<Ipv4Addr>,
2272 dst_ip: SocketIpAddr<Ipv4Addr>,
2273 original_packet: B,
2274 header_len: usize,
2275 marks: &Marks,
2276) {
2277 core_ctx.counters().port_unreachable.increment();
2278
2279 send_icmpv4_dest_unreachable(
2280 core_ctx,
2281 bindings_ctx,
2282 Some(device),
2283 frame_dst,
2284 src_ip,
2285 dst_ip,
2286 Icmpv4DestUnreachableCode::DestPortUnreachable,
2287 original_packet,
2288 header_len,
2289 Ipv4FragmentType::InitialFragment,
2295 marks,
2296 );
2297}
2298
2299pub(crate) fn send_icmpv6_port_unreachable<
2308 B: BufferMut,
2309 BC: IcmpBindingsContext,
2310 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2311>(
2312 core_ctx: &mut CC,
2313 bindings_ctx: &mut BC,
2314 device: &CC::DeviceId,
2315 frame_dst: Option<FrameDestination>,
2316 src_ip: SocketIpAddr<Ipv6Addr>,
2317 dst_ip: SocketIpAddr<Ipv6Addr>,
2318 original_packet: B,
2319 marks: &Marks,
2320) {
2321 core_ctx.counters().port_unreachable.increment();
2322
2323 send_icmpv6_dest_unreachable(
2324 core_ctx,
2325 bindings_ctx,
2326 Some(device),
2327 frame_dst,
2328 src_ip,
2329 dst_ip,
2330 Icmpv6DestUnreachableCode::PortUnreachable,
2331 original_packet,
2332 marks,
2333 );
2334}
2335
2336pub(crate) fn send_icmpv4_net_unreachable<
2348 B: BufferMut,
2349 BC: IcmpBindingsContext,
2350 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2351>(
2352 core_ctx: &mut CC,
2353 bindings_ctx: &mut BC,
2354 device: &CC::DeviceId,
2355 frame_dst: Option<FrameDestination>,
2356 src_ip: SocketIpAddr<Ipv4Addr>,
2357 dst_ip: SocketIpAddr<Ipv4Addr>,
2358 proto: Ipv4Proto,
2359 original_packet: B,
2360 header_len: usize,
2361 fragment_type: Ipv4FragmentType,
2362 marks: &Marks,
2363) {
2364 core_ctx.counters().net_unreachable.increment();
2365
2366 if is_icmp_error_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..]) {
2369 return;
2370 }
2371
2372 send_icmpv4_dest_unreachable(
2373 core_ctx,
2374 bindings_ctx,
2375 Some(device),
2376 frame_dst,
2377 src_ip,
2378 dst_ip,
2379 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
2380 original_packet,
2381 header_len,
2382 fragment_type,
2383 marks,
2384 );
2385}
2386
2387pub(crate) fn send_icmpv6_net_unreachable<
2398 B: BufferMut,
2399 BC: IcmpBindingsContext,
2400 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2401>(
2402 core_ctx: &mut CC,
2403 bindings_ctx: &mut BC,
2404 device: &CC::DeviceId,
2405 frame_dst: Option<FrameDestination>,
2406 src_ip: SocketIpAddr<Ipv6Addr>,
2407 dst_ip: SocketIpAddr<Ipv6Addr>,
2408 proto: Ipv6Proto,
2409 original_packet: B,
2410 header_len: usize,
2411 marks: &Marks,
2412) {
2413 core_ctx.counters().net_unreachable.increment();
2414
2415 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2418 return;
2419 }
2420
2421 send_icmpv6_dest_unreachable(
2422 core_ctx,
2423 bindings_ctx,
2424 Some(device),
2425 frame_dst,
2426 src_ip,
2427 dst_ip,
2428 Icmpv6DestUnreachableCode::NoRoute,
2429 original_packet,
2430 marks,
2431 );
2432}
2433
2434pub(crate) fn send_icmpv4_ttl_expired<
2446 B: BufferMut,
2447 BC: IcmpBindingsContext,
2448 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2449>(
2450 core_ctx: &mut CC,
2451 bindings_ctx: &mut BC,
2452 device: &CC::DeviceId,
2453 frame_dst: Option<FrameDestination>,
2454 src_ip: SocketIpAddr<Ipv4Addr>,
2455 dst_ip: SocketIpAddr<Ipv4Addr>,
2456 proto: Ipv4Proto,
2457 original_packet: B,
2458 header_len: usize,
2459 fragment_type: Ipv4FragmentType,
2460 marks: &Marks,
2461) {
2462 core_ctx.counters().ttl_expired.increment();
2463
2464 if is_icmp_error_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..]) {
2467 return;
2468 }
2469
2470 send_icmpv4_error_message(
2471 core_ctx,
2472 bindings_ctx,
2473 Some(device),
2474 frame_dst,
2475 src_ip,
2476 dst_ip,
2477 Icmpv4ErrorMessage::TimeExceeded {
2478 message: IcmpTimeExceeded::default(),
2479 code: Icmpv4TimeExceededCode::TtlExpired,
2480 },
2481 original_packet,
2482 header_len,
2483 fragment_type,
2484 marks,
2485 )
2486}
2487
2488pub(crate) fn send_icmpv6_ttl_expired<
2499 B: BufferMut,
2500 BC: IcmpBindingsContext,
2501 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2502>(
2503 core_ctx: &mut CC,
2504 bindings_ctx: &mut BC,
2505 device: &CC::DeviceId,
2506 frame_dst: Option<FrameDestination>,
2507 src_ip: SocketIpAddr<Ipv6Addr>,
2508 dst_ip: SocketIpAddr<Ipv6Addr>,
2509 proto: Ipv6Proto,
2510 original_packet: B,
2511 header_len: usize,
2512 marks: &Marks,
2513) {
2514 core_ctx.counters().ttl_expired.increment();
2515
2516 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2519 return;
2520 }
2521
2522 send_icmpv6_error_message(
2523 core_ctx,
2524 bindings_ctx,
2525 Some(device),
2526 frame_dst,
2527 src_ip,
2528 dst_ip,
2529 Icmpv6ErrorMessage::TimeExceeded {
2530 message: IcmpTimeExceeded::default(),
2531 code: Icmpv6TimeExceededCode::HopLimitExceeded,
2532 },
2533 original_packet,
2534 false, marks,
2536 )
2537}
2538
2539pub(crate) fn send_icmpv6_packet_too_big<
2549 B: BufferMut,
2550 BC: IcmpBindingsContext,
2551 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2552>(
2553 core_ctx: &mut CC,
2554 bindings_ctx: &mut BC,
2555 device: &CC::DeviceId,
2556 frame_dst: Option<FrameDestination>,
2557 src_ip: SocketIpAddr<Ipv6Addr>,
2558 dst_ip: SocketIpAddr<Ipv6Addr>,
2559 proto: Ipv6Proto,
2560 mtu: Mtu,
2561 original_packet: B,
2562 header_len: usize,
2563 marks: &Marks,
2564) {
2565 core_ctx.counters().packet_too_big.increment();
2566 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2569 return;
2570 }
2571
2572 send_icmpv6_error_message(
2573 core_ctx,
2574 bindings_ctx,
2575 Some(device),
2576 frame_dst,
2577 src_ip,
2578 dst_ip,
2579 Icmpv6ErrorMessage::PacketTooBig {
2580 message: Icmpv6PacketTooBig::new(mtu.into()),
2581 code: IcmpZeroCode,
2582 },
2583 original_packet,
2584 true, marks,
2604 )
2605}
2606
2607pub(crate) fn send_icmpv4_parameter_problem<
2608 B: BufferMut,
2609 BC: IcmpBindingsContext,
2610 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2611>(
2612 core_ctx: &mut CC,
2613 bindings_ctx: &mut BC,
2614 device: &CC::DeviceId,
2615 frame_dst: Option<FrameDestination>,
2616 src_ip: SocketIpAddr<Ipv4Addr>,
2617 dst_ip: SocketIpAddr<Ipv4Addr>,
2618 code: Icmpv4ParameterProblemCode,
2619 parameter_problem: Icmpv4ParameterProblem,
2620 original_packet: B,
2621 header_len: usize,
2622 fragment_type: Ipv4FragmentType,
2623 marks: &Marks,
2624) {
2625 core_ctx.counters().parameter_problem.increment();
2626
2627 send_icmpv4_error_message(
2628 core_ctx,
2629 bindings_ctx,
2630 Some(device),
2631 frame_dst,
2632 src_ip,
2633 dst_ip,
2634 Icmpv4ErrorMessage::ParameterProblem { message: parameter_problem, code },
2635 original_packet,
2636 header_len,
2637 fragment_type,
2638 marks,
2639 )
2640}
2641
2642pub(crate) fn send_icmpv6_parameter_problem<
2653 B: BufferMut,
2654 BC: IcmpBindingsContext,
2655 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2656>(
2657 core_ctx: &mut CC,
2658 bindings_ctx: &mut BC,
2659 device: &CC::DeviceId,
2660 frame_dst: Option<FrameDestination>,
2661 src_ip: SocketIpAddr<Ipv6Addr>,
2662 dst_ip: SocketIpAddr<Ipv6Addr>,
2663 code: Icmpv6ParameterProblemCode,
2664 parameter_problem: Icmpv6ParameterProblem,
2665 original_packet: B,
2666 allow_dst_multicast: bool,
2667 marks: &Marks,
2668) {
2669 assert!(!allow_dst_multicast || code == Icmpv6ParameterProblemCode::UnrecognizedIpv6Option);
2674
2675 core_ctx.counters().parameter_problem.increment();
2676
2677 send_icmpv6_error_message(
2678 core_ctx,
2679 bindings_ctx,
2680 Some(device),
2681 frame_dst,
2682 src_ip,
2683 dst_ip,
2684 Icmpv6ErrorMessage::ParameterProblem { message: parameter_problem, code },
2685 original_packet,
2686 allow_dst_multicast,
2687 marks,
2688 )
2689}
2690
2691fn send_icmpv4_dest_unreachable<
2692 B: BufferMut,
2693 BC: IcmpBindingsContext,
2694 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2695>(
2696 core_ctx: &mut CC,
2697 bindings_ctx: &mut BC,
2698 device: Option<&CC::DeviceId>,
2699 frame_dst: Option<FrameDestination>,
2700 src_ip: SocketIpAddr<Ipv4Addr>,
2701 dst_ip: SocketIpAddr<Ipv4Addr>,
2702 code: Icmpv4DestUnreachableCode,
2703 original_packet: B,
2704 header_len: usize,
2705 fragment_type: Ipv4FragmentType,
2706 marks: &Marks,
2707) {
2708 core_ctx.counters().dest_unreachable.increment();
2709 send_icmpv4_error_message(
2710 core_ctx,
2711 bindings_ctx,
2712 device,
2713 frame_dst,
2714 src_ip,
2715 dst_ip,
2716 Icmpv4ErrorMessage::DestUnreachable { message: IcmpDestUnreachable::default(), code },
2717 original_packet,
2718 header_len,
2719 fragment_type,
2720 marks,
2721 )
2722}
2723
2724fn send_icmpv6_dest_unreachable<
2725 B: BufferMut,
2726 BC: IcmpBindingsContext,
2727 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2728>(
2729 core_ctx: &mut CC,
2730 bindings_ctx: &mut BC,
2731 device: Option<&CC::DeviceId>,
2732 frame_dst: Option<FrameDestination>,
2733 src_ip: SocketIpAddr<Ipv6Addr>,
2734 dst_ip: SocketIpAddr<Ipv6Addr>,
2735 code: Icmpv6DestUnreachableCode,
2736 original_packet: B,
2737 marks: &Marks,
2738) {
2739 send_icmpv6_error_message(
2740 core_ctx,
2741 bindings_ctx,
2742 device,
2743 frame_dst,
2744 src_ip,
2745 dst_ip,
2746 Icmpv6ErrorMessage::DestUnreachable { message: IcmpDestUnreachable::default(), code },
2747 original_packet,
2748 false, marks,
2750 )
2751}
2752
2753#[allow(missing_docs)]
2756enum Icmpv4ErrorMessage {
2757 TimeExceeded {
2758 message: IcmpTimeExceeded,
2759 code: <IcmpTimeExceeded as IcmpMessage<Ipv4>>::Code,
2760 },
2761 ParameterProblem {
2762 message: Icmpv4ParameterProblem,
2763 code: <Icmpv4ParameterProblem as IcmpMessage<Ipv4>>::Code,
2764 },
2765 DestUnreachable {
2766 message: IcmpDestUnreachable,
2767 code: <IcmpDestUnreachable as IcmpMessage<Ipv4>>::Code,
2768 },
2769}
2770
2771fn send_icmpv4_error_message<
2772 B: BufferMut,
2773 BC: IcmpBindingsContext,
2774 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2775>(
2776 core_ctx: &mut CC,
2777 bindings_ctx: &mut BC,
2778 device: Option<&CC::DeviceId>,
2779 frame_dst: Option<FrameDestination>,
2780 original_src_ip: SocketIpAddr<Ipv4Addr>,
2781 original_dst_ip: SocketIpAddr<Ipv4Addr>,
2782 message: Icmpv4ErrorMessage,
2783 mut original_packet: B,
2784 header_len: usize,
2785 fragment_type: Ipv4FragmentType,
2786 marks: &Marks,
2787) {
2788 if !should_send_icmpv4_error(
2792 frame_dst,
2793 original_src_ip.into(),
2794 original_dst_ip.into(),
2795 fragment_type,
2796 ) {
2797 return;
2798 }
2799
2800 original_packet.shrink_back_to(header_len + 64);
2803
2804 let tx_metadata: BC::TxMetadata = Default::default();
2805
2806 macro_rules! send {
2807 ($message:expr, $code:expr) => {{
2808 let _ = try_send_error!(
2811 core_ctx,
2812 bindings_ctx,
2813 core_ctx.send_oneshot_ip_packet(
2814 bindings_ctx,
2815 device.map(EitherDeviceId::Strong),
2816 None,
2817 original_src_ip,
2818 Ipv4Proto::Icmp,
2819 &WithMarks(marks),
2820 tx_metadata,
2821 |local_ip| {
2822 original_packet.encapsulate(IcmpPacketBuilder::<Ipv4, _>::new(
2823 local_ip.addr(),
2824 original_src_ip.addr(),
2825 $code,
2826 $message,
2827 ))
2828 },
2829 )
2830 );
2831 }};
2832 }
2833
2834 match message {
2835 Icmpv4ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2836 Icmpv4ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2837 Icmpv4ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2838 }
2839}
2840
2841#[allow(missing_docs)]
2844enum Icmpv6ErrorMessage {
2845 TimeExceeded {
2846 message: IcmpTimeExceeded,
2847 code: <IcmpTimeExceeded as IcmpMessage<Ipv6>>::Code,
2848 },
2849 PacketTooBig {
2850 message: Icmpv6PacketTooBig,
2851 code: <Icmpv6PacketTooBig as IcmpMessage<Ipv6>>::Code,
2852 },
2853 ParameterProblem {
2854 message: Icmpv6ParameterProblem,
2855 code: <Icmpv6ParameterProblem as IcmpMessage<Ipv6>>::Code,
2856 },
2857 DestUnreachable {
2858 message: IcmpDestUnreachable,
2859 code: <IcmpDestUnreachable as IcmpMessage<Ipv6>>::Code,
2860 },
2861}
2862
2863fn send_icmpv6_error_message<
2864 B: BufferMut,
2865 BC: IcmpBindingsContext,
2866 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2867>(
2868 core_ctx: &mut CC,
2869 bindings_ctx: &mut BC,
2870 device: Option<&CC::DeviceId>,
2871 frame_dst: Option<FrameDestination>,
2872 original_src_ip: SocketIpAddr<Ipv6Addr>,
2873 original_dst_ip: SocketIpAddr<Ipv6Addr>,
2874 message: Icmpv6ErrorMessage,
2875 original_packet: B,
2876 allow_dst_multicast: bool,
2877 marks: &Marks,
2878) {
2879 if !should_send_icmpv6_error(
2883 frame_dst,
2884 original_src_ip.into(),
2885 original_dst_ip.into(),
2886 allow_dst_multicast,
2887 ) {
2888 return;
2889 }
2890
2891 struct Icmpv6ErrorOptions<'a>(&'a Marks);
2892 impl<'a> OptionDelegationMarker for Icmpv6ErrorOptions<'a> {}
2893 impl<'a> DelegatedSendOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2894 fn mtu(&self) -> Mtu {
2895 Ipv6::MINIMUM_LINK_MTU
2896 }
2897 }
2898 impl<'a> DelegatedRouteResolutionOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2899 fn marks(&self) -> &Marks {
2900 let Self(marks) = self;
2901 marks
2902 }
2903 }
2904
2905 let tx_metadata: BC::TxMetadata = Default::default();
2906
2907 macro_rules! send {
2908 ($message:expr, $code:expr) => {{
2909 let _ = try_send_error!(
2912 core_ctx,
2913 bindings_ctx,
2914 core_ctx.send_oneshot_ip_packet(
2915 bindings_ctx,
2916 device.map(EitherDeviceId::Strong),
2917 None,
2918 original_src_ip,
2919 Ipv6Proto::Icmpv6,
2920 &Icmpv6ErrorOptions(marks),
2921 tx_metadata,
2922 |local_ip| {
2923 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
2924 local_ip.addr(),
2925 original_src_ip.addr(),
2926 $code,
2927 $message,
2928 );
2929
2930 TruncatingSerializer::new(original_packet, TruncateDirection::DiscardBack)
2933 .encapsulate(icmp_builder)
2934 },
2935 )
2936 );
2937 }};
2938 }
2939
2940 match message {
2941 Icmpv6ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2942 Icmpv6ErrorMessage::PacketTooBig { message, code } => send!(message, code),
2943 Icmpv6ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2944 Icmpv6ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2945 }
2946}
2947
2948fn should_send_icmpv4_error(
2966 frame_dst: Option<FrameDestination>,
2967 src_ip: SpecifiedAddr<Ipv4Addr>,
2968 dst_ip: SpecifiedAddr<Ipv4Addr>,
2969 fragment_type: Ipv4FragmentType,
2970) -> bool {
2971 fragment_type == Ipv4FragmentType::InitialFragment
2991 && !(dst_ip.is_multicast()
2992 || dst_ip.is_limited_broadcast()
2993 || frame_dst.is_some_and(|dst| dst.is_broadcast())
2994 || src_ip.is_loopback()
2995 || src_ip.is_limited_broadcast()
2996 || src_ip.is_multicast()
2997 || src_ip.is_class_e())
2998}
2999
3000fn should_send_icmpv6_error(
3027 frame_dst: Option<FrameDestination>,
3028 src_ip: SpecifiedAddr<Ipv6Addr>,
3029 dst_ip: SpecifiedAddr<Ipv6Addr>,
3030 allow_dst_multicast: bool,
3031) -> bool {
3032 let multicast_frame_dst = match frame_dst {
3035 Some(FrameDestination::Individual { local: _ }) | None => false,
3036 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
3037 };
3038 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
3039 return false;
3040 }
3041 if src_ip.is_loopback() || src_ip.is_multicast() {
3042 return false;
3043 }
3044 true
3045}
3046
3047fn is_icmp_error_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
3059 proto == I::ICMP_IP_PROTO
3060 && peek_message_type::<I::IcmpMessageType>(buf).map(IcmpMessageType::is_err).unwrap_or(true)
3061}
3062
3063#[cfg(any(test, feature = "testutils"))]
3065pub(crate) mod testutil {
3066 use alloc::vec::Vec;
3067 use net_types::ethernet::Mac;
3068 use net_types::ip::{Ipv6, Ipv6Addr};
3069 use packet::{Buf, InnerPacketBuilder as _, Serializer as _};
3070 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
3071 use packet_formats::icmp::ndp::{
3072 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
3073 };
3074 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
3075 use packet_formats::ip::Ipv6Proto;
3076 use packet_formats::ipv6::Ipv6PacketBuilder;
3077
3078 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
3079
3080 pub fn neighbor_advertisement_ip_packet(
3083 src_ip: Ipv6Addr,
3084 dst_ip: Ipv6Addr,
3085 router_flag: bool,
3086 solicited_flag: bool,
3087 override_flag: bool,
3088 mac: Mac,
3089 ) -> Buf<Vec<u8>> {
3090 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
3091 .into_serializer()
3092 .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
3093 src_ip,
3094 dst_ip,
3095 IcmpZeroCode,
3096 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
3097 ))
3098 .encapsulate(Ipv6PacketBuilder::new(
3099 src_ip,
3100 dst_ip,
3101 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
3102 Ipv6Proto::Icmpv6,
3103 ))
3104 .serialize_vec_outer()
3105 .unwrap()
3106 .unwrap_b()
3107 }
3108
3109 pub fn neighbor_solicitation_ip_packet(
3112 src_ip: Ipv6Addr,
3113 dst_ip: Ipv6Addr,
3114 target_addr: Ipv6Addr,
3115 mac: Mac,
3116 ) -> Buf<Vec<u8>> {
3117 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
3118 .into_serializer()
3119 .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
3120 src_ip,
3121 dst_ip,
3122 IcmpZeroCode,
3123 NeighborSolicitation::new(target_addr),
3124 ))
3125 .encapsulate(Ipv6PacketBuilder::new(
3126 src_ip,
3127 dst_ip,
3128 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
3129 Ipv6Proto::Icmpv6,
3130 ))
3131 .serialize_vec_outer()
3132 .unwrap()
3133 .unwrap_b()
3134 }
3135}
3136
3137#[cfg(test)]
3138mod tests {
3139 use alloc::vec;
3140 use alloc::vec::Vec;
3141 use packet_formats::icmp::ndp::options::NdpNonce;
3142
3143 use core::fmt::Debug;
3144 use core::time::Duration;
3145
3146 use net_types::ip::Subnet;
3147 use netstack3_base::testutil::{
3148 set_logger_for_test, FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant,
3149 FakeTxMetadata, FakeWeakDeviceId, TestIpExt, TEST_ADDRS_V4, TEST_ADDRS_V6,
3150 };
3151 use netstack3_base::{CtxPair, Uninstantiable};
3152 use packet::Buf;
3153 use packet_formats::icmp::mld::MldPacket;
3154 use packet_formats::ip::IpProto;
3155 use packet_formats::utils::NonZeroDuration;
3156
3157 use super::*;
3158 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
3159 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
3160 use crate::internal::socket::{
3161 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
3162 };
3163 use crate::socket::RouteResolutionOptions;
3164
3165 type InnerIpSocketCtx<I> = FakeCoreCtx<
3167 FakeIpSocketCtx<I, FakeDeviceId>,
3168 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
3169 FakeDeviceId,
3170 >;
3171
3172 pub(super) struct FakeIcmpCoreCtx<I: IpExt> {
3174 ip_socket_ctx: InnerIpSocketCtx<I>,
3175 icmp: FakeIcmpCoreCtxState<I>,
3176 }
3177
3178 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
3180 (),
3181 RouterAdvertisementEvent<FakeDeviceId>,
3182 FakeIcmpBindingsCtxState<I>,
3183 (),
3184 >;
3185
3186 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
3190
3191 pub(super) struct FakeIcmpCoreCtxState<I: IpExt> {
3192 error_send_bucket: TokenBucket<FakeInstant>,
3193 receive_icmp_error: Vec<I::ErrorCode>,
3194 rx_counters: IcmpRxCounters<I>,
3195 tx_counters: IcmpTxCounters<I>,
3196 ndp_counters: NdpCounters,
3197 }
3198
3199 impl<I: TestIpExt + IpExt> FakeIcmpCoreCtx<I> {
3200 fn with_errors_per_second(errors_per_second: u64) -> Self {
3201 Self {
3202 icmp: FakeIcmpCoreCtxState {
3203 error_send_bucket: TokenBucket::new(errors_per_second),
3204 receive_icmp_error: Default::default(),
3205 rx_counters: Default::default(),
3206 tx_counters: Default::default(),
3207 ndp_counters: Default::default(),
3208 },
3209 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
3210 core::iter::once(FakeDeviceConfig {
3211 device: FakeDeviceId,
3212 local_ips: vec![I::TEST_ADDRS.local_ip],
3213 remote_ips: vec![I::TEST_ADDRS.remote_ip],
3214 }),
3215 )),
3216 }
3217 }
3218 }
3219
3220 impl<I: TestIpExt + IpExt> Default for FakeIcmpCoreCtx<I> {
3221 fn default() -> Self {
3222 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
3223 }
3224 }
3225
3226 impl<I: IpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
3227 type DeviceId = FakeDeviceId;
3228 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
3229 }
3230
3231 impl<I: IpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
3232 impl<I: IpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
3233
3234 impl<I: IpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
3235 fn counters(&self) -> &IcmpRxCounters<I> {
3236 &self.icmp.rx_counters
3237 }
3238 }
3239
3240 impl<I: IpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
3241 fn counters(&self) -> &IcmpTxCounters<I> {
3242 &self.icmp.tx_counters
3243 }
3244 }
3245
3246 impl<I: IpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
3247 fn counters(&self) -> &NdpCounters {
3248 &self.icmp.ndp_counters
3249 }
3250 }
3251
3252 pub enum FakeEchoIpTransportContext {}
3253
3254 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
3255
3256 impl<I: IpExt> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
3257 for FakeEchoIpTransportContext
3258 {
3259 fn receive_icmp_error(
3260 core_ctx: &mut FakeIcmpCoreCtx<I>,
3261 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3262 _device: &FakeDeviceId,
3263 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3264 _original_dst_ip: SpecifiedAddr<I::Addr>,
3265 _original_body: &[u8],
3266 _err: I::ErrorCode,
3267 ) {
3268 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
3269 }
3270
3271 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
3272 _core_ctx: &mut FakeIcmpCoreCtx<I>,
3273 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3274 _device: &FakeDeviceId,
3275 _src_ip: I::RecvSrcAddr,
3276 _dst_ip: SpecifiedAddr<I::Addr>,
3277 _buffer: B,
3278 _info: &LocalDeliveryPacketInfo<I, H>,
3279 ) -> Result<(), (B, TransportReceiveError)> {
3280 unimplemented!()
3281 }
3282 }
3283
3284 impl<I: IpExt + FilterIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3285 type EchoTransportContext = FakeEchoIpTransportContext;
3286
3287 fn receive_icmp_error(
3288 &mut self,
3289 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3290 device: &Self::DeviceId,
3291 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3292 original_dst_ip: SpecifiedAddr<I::Addr>,
3293 original_proto: I::Proto,
3294 original_body: &[u8],
3295 err: I::ErrorCode,
3296 ) {
3297 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
3298 self.icmp.receive_icmp_error.push(err);
3299 if original_proto == I::ICMP_IP_PROTO {
3300 receive_ip_transport_icmp_error(
3301 self,
3302 bindings_ctx,
3303 device,
3304 original_src_ip,
3305 original_dst_ip,
3306 original_body,
3307 err,
3308 )
3309 }
3310 }
3311
3312 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
3313 &mut self,
3314 cb: F,
3315 ) -> O {
3316 cb(&mut self.icmp.error_send_bucket)
3317 }
3318 }
3319
3320 #[test]
3321 fn test_should_send_icmpv4_error() {
3322 let src_ip = TEST_ADDRS_V4.local_ip;
3323 let dst_ip = TEST_ADDRS_V4.remote_ip;
3324 let frame_dst = FrameDestination::Individual { local: true };
3325 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
3326 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
3327
3328 assert!(should_send_icmpv4_error(
3330 Some(frame_dst),
3331 src_ip,
3332 dst_ip,
3333 Ipv4FragmentType::InitialFragment
3334 ));
3335 assert!(should_send_icmpv4_error(None, src_ip, dst_ip, Ipv4FragmentType::InitialFragment));
3336 assert!(!should_send_icmpv4_error(
3337 Some(frame_dst),
3338 src_ip,
3339 dst_ip,
3340 Ipv4FragmentType::NonInitialFragment
3341 ));
3342
3343 assert!(!should_send_icmpv4_error(
3345 Some(frame_dst),
3346 src_ip,
3347 Ipv4::LIMITED_BROADCAST_ADDRESS,
3348 Ipv4FragmentType::InitialFragment
3349 ));
3350 assert!(!should_send_icmpv4_error(
3351 Some(frame_dst),
3352 src_ip,
3353 Ipv4::LIMITED_BROADCAST_ADDRESS,
3354 Ipv4FragmentType::NonInitialFragment
3355 ));
3356
3357 assert!(!should_send_icmpv4_error(
3359 Some(frame_dst),
3360 src_ip,
3361 multicast_ip_1,
3362 Ipv4FragmentType::InitialFragment
3363 ));
3364 assert!(!should_send_icmpv4_error(
3365 Some(frame_dst),
3366 src_ip,
3367 multicast_ip_1,
3368 Ipv4FragmentType::NonInitialFragment
3369 ));
3370
3371 assert!(!should_send_icmpv4_error(
3373 Some(FrameDestination::Broadcast),
3374 src_ip,
3375 dst_ip,
3376 Ipv4FragmentType::InitialFragment
3377 ));
3378 assert!(!should_send_icmpv4_error(
3379 Some(FrameDestination::Broadcast),
3380 src_ip,
3381 dst_ip,
3382 Ipv4FragmentType::NonInitialFragment
3383 ));
3384
3385 assert!(!should_send_icmpv4_error(
3387 Some(frame_dst),
3388 Ipv4::LOOPBACK_ADDRESS,
3389 dst_ip,
3390 Ipv4FragmentType::InitialFragment
3391 ));
3392 assert!(!should_send_icmpv4_error(
3393 Some(frame_dst),
3394 Ipv4::LOOPBACK_ADDRESS,
3395 dst_ip,
3396 Ipv4FragmentType::NonInitialFragment
3397 ));
3398
3399 assert!(!should_send_icmpv4_error(
3401 Some(frame_dst),
3402 Ipv4::LIMITED_BROADCAST_ADDRESS,
3403 dst_ip,
3404 Ipv4FragmentType::InitialFragment
3405 ));
3406 assert!(!should_send_icmpv4_error(
3407 Some(frame_dst),
3408 Ipv4::LIMITED_BROADCAST_ADDRESS,
3409 dst_ip,
3410 Ipv4FragmentType::NonInitialFragment
3411 ));
3412
3413 assert!(!should_send_icmpv4_error(
3415 Some(frame_dst),
3416 multicast_ip_2,
3417 dst_ip,
3418 Ipv4FragmentType::InitialFragment
3419 ));
3420 assert!(!should_send_icmpv4_error(
3421 Some(frame_dst),
3422 multicast_ip_2,
3423 dst_ip,
3424 Ipv4FragmentType::NonInitialFragment
3425 ));
3426
3427 assert!(!should_send_icmpv4_error(
3429 Some(frame_dst),
3430 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
3431 dst_ip,
3432 Ipv4FragmentType::InitialFragment
3433 ));
3434 assert!(!should_send_icmpv4_error(
3435 Some(frame_dst),
3436 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
3437 dst_ip,
3438 Ipv4FragmentType::NonInitialFragment
3439 ));
3440 }
3441
3442 #[test]
3443 fn test_should_send_icmpv6_error() {
3444 let src_ip = TEST_ADDRS_V6.local_ip;
3445 let dst_ip = TEST_ADDRS_V6.remote_ip;
3446 let frame_dst = FrameDestination::Individual { local: true };
3447 let multicast_ip_1 =
3448 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
3449 let multicast_ip_2 =
3450 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
3451
3452 assert!(should_send_icmpv6_error(
3454 Some(frame_dst),
3455 src_ip,
3456 dst_ip,
3457 false ));
3459 assert!(should_send_icmpv6_error(None, src_ip, dst_ip, false ));
3460 assert!(should_send_icmpv6_error(
3461 Some(frame_dst),
3462 src_ip,
3463 dst_ip,
3464 true ));
3466
3467 assert!(!should_send_icmpv6_error(
3470 Some(frame_dst),
3471 src_ip,
3472 multicast_ip_1,
3473 false ));
3475 assert!(should_send_icmpv6_error(
3476 Some(frame_dst),
3477 src_ip,
3478 multicast_ip_1,
3479 true ));
3481
3482 assert!(!should_send_icmpv6_error(
3485 Some(FrameDestination::Broadcast),
3486 src_ip,
3487 dst_ip,
3488 false ));
3490 assert!(should_send_icmpv6_error(
3491 Some(FrameDestination::Broadcast),
3492 src_ip,
3493 dst_ip,
3494 true ));
3496
3497 assert!(!should_send_icmpv6_error(
3499 Some(frame_dst),
3500 Ipv6::LOOPBACK_ADDRESS,
3501 dst_ip,
3502 false ));
3504 assert!(!should_send_icmpv6_error(
3505 Some(frame_dst),
3506 Ipv6::LOOPBACK_ADDRESS,
3507 dst_ip,
3508 true ));
3510
3511 assert!(!should_send_icmpv6_error(
3513 Some(frame_dst),
3514 multicast_ip_2,
3515 dst_ip,
3516 false ));
3518 assert!(!should_send_icmpv6_error(
3519 Some(frame_dst),
3520 multicast_ip_2,
3521 dst_ip,
3522 true ));
3524
3525 assert!(!should_send_icmpv6_error(
3528 Some(FrameDestination::Broadcast),
3529 multicast_ip_2,
3530 dst_ip,
3531 false ));
3533 assert!(!should_send_icmpv6_error(
3534 Some(FrameDestination::Broadcast),
3535 multicast_ip_2,
3536 dst_ip,
3537 true ));
3539 assert!(!should_send_icmpv6_error(
3540 Some(frame_dst),
3541 multicast_ip_2,
3542 multicast_ip_1,
3543 false ));
3545 assert!(!should_send_icmpv6_error(
3546 Some(frame_dst),
3547 multicast_ip_2,
3548 multicast_ip_1,
3549 true ));
3551 }
3552
3553 #[derive(Default)]
3560 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3561 _marker: core::marker::PhantomData<I>,
3562 }
3563
3564 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3565 fn should_send_timestamp_reply(&self) -> bool {
3566 false
3567 }
3568 }
3569 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3570 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3571
3572 impl<I: IpExt + FilterIpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3573 fn new_ip_socket<O>(
3574 &mut self,
3575 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3576 device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
3577 local_ip: Option<IpDeviceAddr<I::Addr>>,
3578 remote_ip: SocketIpAddr<I::Addr>,
3579 proto: I::Proto,
3580 options: &O,
3581 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3582 where
3583 O: RouteResolutionOptions<I>,
3584 {
3585 self.ip_socket_ctx.new_ip_socket(
3586 bindings_ctx,
3587 device,
3588 local_ip,
3589 remote_ip,
3590 proto,
3591 options,
3592 )
3593 }
3594
3595 fn send_ip_packet<S, O>(
3596 &mut self,
3597 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3598 socket: &IpSock<I, Self::WeakDeviceId>,
3599 body: S,
3600 options: &O,
3601 tx_meta: FakeTxMetadata,
3602 ) -> Result<(), IpSockSendError>
3603 where
3604 S: TransportPacketSerializer<I>,
3605 S::Buffer: BufferMut,
3606 O: SendOptions<I> + RouteResolutionOptions<I>,
3607 {
3608 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3609 }
3610
3611 fn confirm_reachable<O>(
3612 &mut self,
3613 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3614 socket: &IpSock<I, Self::WeakDeviceId>,
3615 options: &O,
3616 ) where
3617 O: RouteResolutionOptions<I>,
3618 {
3619 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3620 }
3621 }
3622
3623 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3624 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3625 unimplemented!()
3626 }
3627
3628 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3629 unreachable!()
3630 }
3631 }
3632
3633 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3634 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3635 cb(&())
3636 }
3637
3638 fn get_local_addr_for_remote(
3639 &mut self,
3640 _device_id: &Self::DeviceId,
3641 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3642 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3643 unimplemented!()
3644 }
3645
3646 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3647 unimplemented!()
3648 }
3649 }
3650
3651 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3652 fn address_status_for_device(
3653 &mut self,
3654 _addr: SpecifiedAddr<Ipv6Addr>,
3655 _device_id: &Self::DeviceId,
3656 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3657 unimplemented!()
3658 }
3659 }
3660
3661 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3662 type LinkLayerAddr = Uninstantiable;
3663
3664 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3665 unimplemented!()
3666 }
3667
3668 fn set_discovered_retrans_timer(
3669 &mut self,
3670 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3671 _device_id: &Self::DeviceId,
3672 _retrans_timer: NonZeroDuration,
3673 ) {
3674 unimplemented!()
3675 }
3676
3677 fn handle_received_dad_neighbor_solicitation(
3678 &mut self,
3679 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3680 _device_id: &Self::DeviceId,
3681 _addr: UnicastAddr<Ipv6Addr>,
3682 _nonce: Option<NdpNonce<&'_ [u8]>>,
3683 ) -> IpAddressState {
3684 unimplemented!()
3685 }
3686
3687 fn handle_received_neighbor_advertisement(
3688 &mut self,
3689 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3690 _device_id: &Self::DeviceId,
3691 _addr: UnicastAddr<Ipv6Addr>,
3692 ) -> IpAddressState {
3693 unimplemented!()
3694 }
3695
3696 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3697 unimplemented!()
3698 }
3699
3700 fn update_discovered_ipv6_route(
3701 &mut self,
3702 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3703 _device_id: &Self::DeviceId,
3704 _route: Ipv6DiscoveredRoute,
3705 _lifetime: Option<NonZeroNdpLifetime>,
3706 ) {
3707 unimplemented!()
3708 }
3709
3710 fn apply_slaac_update(
3711 &mut self,
3712 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3713 _device_id: &Self::DeviceId,
3714 _subnet: Subnet<Ipv6Addr>,
3715 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3716 _valid_lifetime: Option<NonZeroNdpLifetime>,
3717 ) {
3718 unimplemented!()
3719 }
3720
3721 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3722 &mut self,
3723 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3724 _device: &FakeDeviceId,
3725 _src_ip: Ipv6SourceAddr,
3726 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3727 _packet: MldPacket<B>,
3728 _header_info: &H,
3729 ) {
3730 unimplemented!()
3731 }
3732 }
3733
3734 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3735 fn send_ip_packet_from_device<S>(
3736 &mut self,
3737 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3738 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3739 _body: S,
3740 ) -> Result<(), IpSendFrameError<S>> {
3741 unimplemented!()
3742 }
3743
3744 fn send_ip_frame<S>(
3745 &mut self,
3746 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3747 _device: &Self::DeviceId,
3748 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3749 _body: S,
3750 ) -> Result<(), IpSendFrameError<S>>
3751 where
3752 S: Serializer,
3753 S::Buffer: BufferMut,
3754 {
3755 unimplemented!()
3756 }
3757 }
3758
3759 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3760 fn handle_neighbor_probe(
3761 &mut self,
3762 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3763 _device_id: &Self::DeviceId,
3764 _neighbor: SpecifiedAddr<Ipv6Addr>,
3765 _link_addr: &[u8],
3766 ) {
3767 unimplemented!()
3768 }
3769
3770 fn handle_neighbor_confirmation(
3771 &mut self,
3772 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3773 _device_id: &Self::DeviceId,
3774 _neighbor: SpecifiedAddr<Ipv6Addr>,
3775 _link_addr: &[u8],
3776 _flags: ConfirmationFlags,
3777 ) {
3778 unimplemented!()
3779 }
3780
3781 fn flush_neighbor_table(
3782 &mut self,
3783 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3784 _device_id: &Self::DeviceId,
3785 ) {
3786 unimplemented!()
3787 }
3788 }
3789
3790 #[test]
3791 fn test_receive_icmpv4_error() {
3792 const ICMP_ID: u16 = 0x0F;
3795 const SEQ_NUM: u16 = 0xF0;
3796
3797 fn test_receive_icmpv4_error_helper<
3812 C: Debug,
3813 M: IcmpMessage<Ipv4, Code = C> + Debug,
3814 F: Fn(&FakeIcmpCtx<Ipv4>),
3815 >(
3816 original_packet: &mut [u8],
3817 code: C,
3818 msg: M,
3819 f: F,
3820 ) {
3821 set_logger_for_test();
3822
3823 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3824
3825 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3826 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3827 core_ctx,
3828 bindings_ctx,
3829 &FakeDeviceId,
3830 Ipv4SourceAddr::new(*TEST_ADDRS_V4.remote_ip).unwrap(),
3831 TEST_ADDRS_V4.local_ip,
3832 Buf::new(original_packet, ..)
3833 .encapsulate(IcmpPacketBuilder::new(
3834 TEST_ADDRS_V4.remote_ip,
3835 TEST_ADDRS_V4.local_ip,
3836 code,
3837 msg,
3838 ))
3839 .serialize_vec_outer()
3840 .unwrap(),
3841 &LocalDeliveryPacketInfo::default(),
3842 )
3843 .unwrap();
3844 f(&ctx);
3845 }
3846 let mut buffer = Buf::new(&mut [], ..)
3859 .encapsulate(IcmpPacketBuilder::<Ipv4, _>::new(
3860 TEST_ADDRS_V4.local_ip,
3861 TEST_ADDRS_V4.remote_ip,
3862 IcmpZeroCode,
3863 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3864 ))
3865 .encapsulate(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3866 TEST_ADDRS_V4.local_ip,
3867 TEST_ADDRS_V4.remote_ip,
3868 64,
3869 Ipv4Proto::Icmp,
3870 ))
3871 .serialize_vec_outer()
3872 .unwrap();
3873
3874 test_receive_icmpv4_error_helper(
3875 buffer.as_mut(),
3876 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3877 IcmpDestUnreachable::default(),
3878 |CtxPair { core_ctx, bindings_ctx: _ }| {
3879 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3880 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3881 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3882 let err = Icmpv4ErrorCode::DestUnreachable(
3883 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3884 IcmpDestUnreachable::default(),
3885 );
3886 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3887 },
3888 );
3889
3890 test_receive_icmpv4_error_helper(
3891 buffer.as_mut(),
3892 Icmpv4TimeExceededCode::TtlExpired,
3893 IcmpTimeExceeded::default(),
3894 |CtxPair { core_ctx, bindings_ctx: _ }| {
3895 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3896 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3897 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3898 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3899 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3900 },
3901 );
3902
3903 test_receive_icmpv4_error_helper(
3904 buffer.as_mut(),
3905 Icmpv4ParameterProblemCode::PointerIndicatesError,
3906 Icmpv4ParameterProblem::new(0),
3907 |CtxPair { core_ctx, bindings_ctx: _ }| {
3908 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3909 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3910 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3911 let err = Icmpv4ErrorCode::ParameterProblem(
3912 Icmpv4ParameterProblemCode::PointerIndicatesError,
3913 );
3914 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3915 },
3916 );
3917
3918 let mut buffer = Buf::new(&mut [], ..)
3925 .encapsulate(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3926 TEST_ADDRS_V4.local_ip,
3927 TEST_ADDRS_V4.remote_ip,
3928 64,
3929 Ipv4Proto::Icmp,
3930 ))
3931 .serialize_vec_outer()
3932 .unwrap();
3933
3934 test_receive_icmpv4_error_helper(
3935 buffer.as_mut(),
3936 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3937 IcmpDestUnreachable::default(),
3938 |CtxPair { core_ctx, bindings_ctx: _ }| {
3939 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3940 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3941 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3942 let err = Icmpv4ErrorCode::DestUnreachable(
3943 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3944 IcmpDestUnreachable::default(),
3945 );
3946 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3947 },
3948 );
3949
3950 test_receive_icmpv4_error_helper(
3951 buffer.as_mut(),
3952 Icmpv4TimeExceededCode::TtlExpired,
3953 IcmpTimeExceeded::default(),
3954 |CtxPair { core_ctx, bindings_ctx: _ }| {
3955 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3956 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3957 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3958 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3959 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3960 },
3961 );
3962
3963 test_receive_icmpv4_error_helper(
3964 buffer.as_mut(),
3965 Icmpv4ParameterProblemCode::PointerIndicatesError,
3966 Icmpv4ParameterProblem::new(0),
3967 |CtxPair { core_ctx, bindings_ctx: _ }| {
3968 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3969 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3970 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3971 let err = Icmpv4ErrorCode::ParameterProblem(
3972 Icmpv4ParameterProblemCode::PointerIndicatesError,
3973 );
3974 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3975 },
3976 );
3977
3978 let mut buffer = Buf::new(&mut [], ..)
3984 .encapsulate(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3985 TEST_ADDRS_V4.local_ip,
3986 TEST_ADDRS_V4.remote_ip,
3987 64,
3988 IpProto::Udp.into(),
3989 ))
3990 .serialize_vec_outer()
3991 .unwrap();
3992
3993 test_receive_icmpv4_error_helper(
3994 buffer.as_mut(),
3995 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3996 IcmpDestUnreachable::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(), 0);
4000 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4001 let err = Icmpv4ErrorCode::DestUnreachable(
4002 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4003 IcmpDestUnreachable::default(),
4004 );
4005 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4006 },
4007 );
4008
4009 test_receive_icmpv4_error_helper(
4010 buffer.as_mut(),
4011 Icmpv4TimeExceededCode::TtlExpired,
4012 IcmpTimeExceeded::default(),
4013 |CtxPair { core_ctx, bindings_ctx: _ }| {
4014 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4015 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4016 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4017 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
4018 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4019 },
4020 );
4021
4022 test_receive_icmpv4_error_helper(
4023 buffer.as_mut(),
4024 Icmpv4ParameterProblemCode::PointerIndicatesError,
4025 Icmpv4ParameterProblem::new(0),
4026 |CtxPair { core_ctx, bindings_ctx: _ }| {
4027 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4028 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4029 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4030 let err = Icmpv4ErrorCode::ParameterProblem(
4031 Icmpv4ParameterProblemCode::PointerIndicatesError,
4032 );
4033 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4034 },
4035 );
4036 }
4037
4038 #[test]
4039 fn test_receive_icmpv6_error() {
4040 const ICMP_ID: u16 = 0x0F;
4043 const SEQ_NUM: u16 = 0xF0;
4044
4045 fn test_receive_icmpv6_error_helper<
4060 C: Debug,
4061 M: IcmpMessage<Ipv6, Code = C> + Debug,
4062 F: Fn(&FakeIcmpCtx<Ipv6>),
4063 >(
4064 original_packet: &mut [u8],
4065 code: C,
4066 msg: M,
4067 f: F,
4068 ) {
4069 set_logger_for_test();
4070
4071 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
4072 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
4073 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
4074 core_ctx,
4075 bindings_ctx,
4076 &FakeDeviceId,
4077 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
4078 TEST_ADDRS_V6.local_ip,
4079 Buf::new(original_packet, ..)
4080 .encapsulate(IcmpPacketBuilder::new(
4081 TEST_ADDRS_V6.remote_ip,
4082 TEST_ADDRS_V6.local_ip,
4083 code,
4084 msg,
4085 ))
4086 .serialize_vec_outer()
4087 .unwrap(),
4088 &LocalDeliveryPacketInfo::default(),
4089 )
4090 .unwrap();
4091 f(&ctx);
4092 }
4093 let mut buffer = Buf::new(&mut [], ..)
4106 .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
4107 TEST_ADDRS_V6.local_ip,
4108 TEST_ADDRS_V6.remote_ip,
4109 IcmpZeroCode,
4110 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
4111 ))
4112 .encapsulate(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4113 TEST_ADDRS_V6.local_ip,
4114 TEST_ADDRS_V6.remote_ip,
4115 64,
4116 Ipv6Proto::Icmpv6,
4117 ))
4118 .serialize_vec_outer()
4119 .unwrap();
4120
4121 test_receive_icmpv6_error_helper(
4122 buffer.as_mut(),
4123 Icmpv6DestUnreachableCode::NoRoute,
4124 IcmpDestUnreachable::default(),
4125 |CtxPair { core_ctx, bindings_ctx: _ }| {
4126 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4127 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4128 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4129 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4130 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4131 },
4132 );
4133
4134 test_receive_icmpv6_error_helper(
4135 buffer.as_mut(),
4136 Icmpv6TimeExceededCode::HopLimitExceeded,
4137 IcmpTimeExceeded::default(),
4138 |CtxPair { core_ctx, bindings_ctx: _ }| {
4139 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4140 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4141 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4142 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4143 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4144 },
4145 );
4146
4147 test_receive_icmpv6_error_helper(
4148 buffer.as_mut(),
4149 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4150 Icmpv6ParameterProblem::new(0),
4151 |CtxPair { core_ctx, bindings_ctx: _ }| {
4152 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4153 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4154 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4155 let err = Icmpv6ErrorCode::ParameterProblem(
4156 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4157 );
4158 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4159 },
4160 );
4161
4162 let mut buffer = Buf::new(&mut [], ..)
4169 .encapsulate(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4170 TEST_ADDRS_V6.local_ip,
4171 TEST_ADDRS_V6.remote_ip,
4172 64,
4173 Ipv6Proto::Icmpv6,
4174 ))
4175 .serialize_vec_outer()
4176 .unwrap();
4177
4178 test_receive_icmpv6_error_helper(
4179 buffer.as_mut(),
4180 Icmpv6DestUnreachableCode::NoRoute,
4181 IcmpDestUnreachable::default(),
4182 |CtxPair { core_ctx, bindings_ctx: _ }| {
4183 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4184 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4185 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4186 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4187 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4188 },
4189 );
4190
4191 test_receive_icmpv6_error_helper(
4192 buffer.as_mut(),
4193 Icmpv6TimeExceededCode::HopLimitExceeded,
4194 IcmpTimeExceeded::default(),
4195 |CtxPair { core_ctx, bindings_ctx: _ }| {
4196 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4197 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4198 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4199 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4200 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4201 },
4202 );
4203
4204 test_receive_icmpv6_error_helper(
4205 buffer.as_mut(),
4206 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4207 Icmpv6ParameterProblem::new(0),
4208 |CtxPair { core_ctx, bindings_ctx: _ }| {
4209 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4210 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4211 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4212 let err = Icmpv6ErrorCode::ParameterProblem(
4213 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4214 );
4215 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4216 },
4217 );
4218
4219 let mut buffer = Buf::new(&mut [], ..)
4225 .encapsulate(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4226 TEST_ADDRS_V6.local_ip,
4227 TEST_ADDRS_V6.remote_ip,
4228 64,
4229 IpProto::Udp.into(),
4230 ))
4231 .serialize_vec_outer()
4232 .unwrap();
4233
4234 test_receive_icmpv6_error_helper(
4235 buffer.as_mut(),
4236 Icmpv6DestUnreachableCode::NoRoute,
4237 IcmpDestUnreachable::default(),
4238 |CtxPair { core_ctx, bindings_ctx: _ }| {
4239 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4240 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4241 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4242 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4243 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4244 },
4245 );
4246
4247 test_receive_icmpv6_error_helper(
4248 buffer.as_mut(),
4249 Icmpv6TimeExceededCode::HopLimitExceeded,
4250 IcmpTimeExceeded::default(),
4251 |CtxPair { core_ctx, bindings_ctx: _ }| {
4252 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4253 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4254 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4255 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4256 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4257 },
4258 );
4259
4260 test_receive_icmpv6_error_helper(
4261 buffer.as_mut(),
4262 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4263 Icmpv6ParameterProblem::new(0),
4264 |CtxPair { core_ctx, bindings_ctx: _ }| {
4265 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4266 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4267 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4268 let err = Icmpv6ErrorCode::ParameterProblem(
4269 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4270 );
4271 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4272 },
4273 );
4274 }
4275
4276 #[test]
4277 fn test_error_rate_limit() {
4278 set_logger_for_test();
4279
4280 fn send_icmpv4_ttl_expired_helper(
4282 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4283 ) {
4284 send_icmpv4_ttl_expired(
4285 core_ctx,
4286 bindings_ctx,
4287 &FakeDeviceId,
4288 Some(FrameDestination::Individual { local: true }),
4289 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4290 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4291 IpProto::Udp.into(),
4292 Buf::new(&mut [], ..),
4293 0,
4294 Ipv4FragmentType::InitialFragment,
4295 &Default::default(),
4296 );
4297 }
4298
4299 fn send_icmpv4_parameter_problem_helper(
4301 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4302 ) {
4303 send_icmpv4_parameter_problem(
4304 core_ctx,
4305 bindings_ctx,
4306 &FakeDeviceId,
4307 Some(FrameDestination::Individual { local: true }),
4308 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4309 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4310 Icmpv4ParameterProblemCode::PointerIndicatesError,
4311 Icmpv4ParameterProblem::new(0),
4312 Buf::new(&mut [], ..),
4313 0,
4314 Ipv4FragmentType::InitialFragment,
4315 &Default::default(),
4316 );
4317 }
4318
4319 fn send_icmpv4_dest_unreachable_helper(
4321 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4322 ) {
4323 send_icmpv4_dest_unreachable(
4324 core_ctx,
4325 bindings_ctx,
4326 Some(&FakeDeviceId),
4327 Some(FrameDestination::Individual { local: true }),
4328 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4329 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4330 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4331 Buf::new(&mut [], ..),
4332 0,
4333 Ipv4FragmentType::InitialFragment,
4334 &Default::default(),
4335 );
4336 }
4337
4338 fn send_icmpv6_ttl_expired_helper(
4340 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4341 ) {
4342 send_icmpv6_ttl_expired(
4343 core_ctx,
4344 bindings_ctx,
4345 &FakeDeviceId,
4346 Some(FrameDestination::Individual { local: true }),
4347 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4348 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4349 IpProto::Udp.into(),
4350 Buf::new(&mut [], ..),
4351 0,
4352 &Default::default(),
4353 );
4354 }
4355
4356 fn send_icmpv6_packet_too_big_helper(
4358 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4359 ) {
4360 send_icmpv6_packet_too_big(
4361 core_ctx,
4362 bindings_ctx,
4363 &FakeDeviceId,
4364 Some(FrameDestination::Individual { local: true }),
4365 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4366 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4367 IpProto::Udp.into(),
4368 Mtu::new(0),
4369 Buf::new(&mut [], ..),
4370 0,
4371 &Default::default(),
4372 );
4373 }
4374
4375 fn send_icmpv6_parameter_problem_helper(
4377 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4378 ) {
4379 send_icmpv6_parameter_problem(
4380 core_ctx,
4381 bindings_ctx,
4382 &FakeDeviceId,
4383 Some(FrameDestination::Individual { local: true }),
4384 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4385 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4386 Icmpv6ParameterProblemCode::ErroneousHeaderField,
4387 Icmpv6ParameterProblem::new(0),
4388 Buf::new(&mut [], ..),
4389 false,
4390 &Default::default(),
4391 );
4392 }
4393
4394 fn send_icmpv6_dest_unreachable_helper(
4396 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4397 ) {
4398 send_icmpv6_dest_unreachable(
4399 core_ctx,
4400 bindings_ctx,
4401 Some(&FakeDeviceId),
4402 Some(FrameDestination::Individual { local: true }),
4403 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4404 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4405 Icmpv6DestUnreachableCode::NoRoute,
4406 Buf::new(&mut [], ..),
4407 &Default::default(),
4408 );
4409 }
4410
4411 fn run_test<I: IpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
4415 with_errors_per_second: W,
4416 send: S,
4417 ) {
4418 const ERRORS_PER_SECOND: u64 = 64;
4432
4433 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
4434
4435 for i in 0..ERRORS_PER_SECOND {
4436 send(&mut ctx);
4437 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
4438 }
4439
4440 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4441 send(&mut ctx);
4442 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4443
4444 let mut ctx = with_errors_per_second(0);
4448 send(&mut ctx);
4449 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4450 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4451 send(&mut ctx);
4452 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4453 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4454 send(&mut ctx);
4455 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4456 }
4457
4458 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
4459 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4460 }
4461 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
4462 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
4463 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
4464
4465 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
4466 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4467 }
4468
4469 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
4470 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
4471 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
4472 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
4473 }
4474}