1use alloc::boxed::Box;
8use core::convert::TryInto as _;
9use core::num::{NonZeroU8, NonZeroU16};
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::{DynTransportSerializer, DynamicTransportSerializer, FilterIpExt};
29use packet::{
30 BufferMut, InnerPacketBuilder as _, PacketBuilder as _, ParsablePacket as _, ParseBuffer,
31 PartialSerializer, Serializer, 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 IcmpDestUnreachable, IcmpEchoRequest, IcmpMessage, IcmpMessageType, IcmpPacket,
40 IcmpPacketBuilder, IcmpPacketRaw, IcmpParseArgs, IcmpTimeExceeded, IcmpZeroCode,
41 Icmpv4DestUnreachableCode, Icmpv4Packet, Icmpv4ParameterProblem, Icmpv4ParameterProblemCode,
42 Icmpv4TimeExceededCode, Icmpv6DestUnreachableCode, Icmpv6Packet, Icmpv6PacketTooBig,
43 Icmpv6ParameterProblem, Icmpv6ParameterProblemCode, Icmpv6TimeExceededCode, MessageBody,
44 OriginalPacket, peek_message_type,
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, IPV6_DEFAULT_SUBNET, IpDeviceIngressStateContext, IpLayerHandler,
53 IpPacketDestination, IpSendFrameError, IpTransportContext, Ipv6PresentAddressStatus,
54 NdpBindingsContext, RouterAdvertisementEvent, SendIpPacketMeta, TransportReceiveError,
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, IpSocketArgs, IpSocketHandler,
65 OptionDelegationMarker, 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 pub queue_full: Counter,
168}
169
170#[derive(Default)]
172pub struct NdpRxCounters {
173 pub neighbor_solicitation: Counter,
175 pub neighbor_advertisement: Counter,
177 pub router_advertisement: Counter,
179 pub router_solicitation: Counter,
181}
182
183#[derive(Default)]
185pub struct NdpTxCounters {
186 pub neighbor_advertisement: Counter,
188 pub neighbor_solicitation: Counter,
190}
191
192#[derive(Default)]
194pub struct NdpCounters {
195 pub rx: NdpRxCounters,
197 pub tx: NdpTxCounters,
199}
200
201#[derive(Copy, Clone)]
203pub struct Icmpv4StateBuilder {
204 send_timestamp_reply: bool,
205 errors_per_second: u64,
206}
207
208impl Default for Icmpv4StateBuilder {
209 fn default() -> Icmpv4StateBuilder {
210 Icmpv4StateBuilder {
211 send_timestamp_reply: false,
212 errors_per_second: DEFAULT_ERRORS_PER_SECOND,
213 }
214 }
215}
216
217impl Icmpv4StateBuilder {
218 pub fn send_timestamp_reply(&mut self, send_timestamp_reply: bool) -> &mut Self {
225 self.send_timestamp_reply = send_timestamp_reply;
226 self
227 }
228
229 pub fn build<BT: IcmpBindingsTypes>(self) -> Icmpv4State<BT> {
231 Icmpv4State {
232 inner: IcmpState {
233 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
234 self.errors_per_second,
235 ))),
236 tx_counters: Default::default(),
237 rx_counters: Default::default(),
238 },
239 send_timestamp_reply: self.send_timestamp_reply,
240 }
241 }
242}
243
244pub struct Icmpv4State<BT: IcmpBindingsTypes> {
246 pub inner: IcmpState<Ipv4, BT>,
248 pub send_timestamp_reply: bool,
250}
251
252impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
253 fn as_ref(&self) -> &IcmpState<Ipv4, BT> {
254 &self.inner
255 }
256}
257
258impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
259 fn as_mut(&mut self) -> &mut IcmpState<Ipv4, BT> {
260 &mut self.inner
261 }
262}
263
264#[derive(Copy, Clone)]
266pub(crate) struct Icmpv6StateBuilder {
267 errors_per_second: u64,
268}
269
270impl Default for Icmpv6StateBuilder {
271 fn default() -> Icmpv6StateBuilder {
272 Icmpv6StateBuilder { errors_per_second: DEFAULT_ERRORS_PER_SECOND }
273 }
274}
275
276impl Icmpv6StateBuilder {
277 pub(crate) fn build<BT: IcmpBindingsTypes>(self) -> Icmpv6State<BT> {
278 Icmpv6State {
279 inner: IcmpState {
280 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
281 self.errors_per_second,
282 ))),
283 tx_counters: Default::default(),
284 rx_counters: Default::default(),
285 },
286 ndp_counters: Default::default(),
287 }
288 }
289}
290
291pub struct Icmpv6State<BT: IcmpBindingsTypes> {
293 pub inner: IcmpState<Ipv6, BT>,
295 pub ndp_counters: NdpCounters,
297}
298
299impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
300 fn as_ref(&self) -> &IcmpState<Ipv6, BT> {
301 &self.inner
302 }
303}
304
305impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
306 fn as_mut(&mut self) -> &mut IcmpState<Ipv6, BT> {
307 &mut self.inner
308 }
309}
310
311pub trait IcmpHandlerIpExt: IpExt {
313 type SourceAddress: Witness<Self::Addr>;
314 type IcmpError;
315
316 fn received_source_as_icmp_source(src: Self::RecvSrcAddr) -> Option<Self::SourceAddress>;
318
319 fn new_ttl_expired<B: SplitByteSlice>(
321 proto: Self::Proto,
322 header_len: usize,
323 meta: <Self::Packet<B> as IpPacket<B, Self>>::VersionSpecificMeta,
324 ) -> Self::IcmpError;
325
326 fn new_mtu_exceeded(proto: Self::Proto, header_len: usize, mtu: Mtu)
328 -> Option<Self::IcmpError>;
329}
330
331impl IcmpHandlerIpExt for Ipv4 {
332 type SourceAddress = NonMulticastAddr<SpecifiedAddr<Ipv4Addr>>;
333 type IcmpError = Icmpv4Error;
334 fn received_source_as_icmp_source(
335 src: Ipv4SourceAddr,
336 ) -> Option<NonMulticastAddr<SpecifiedAddr<Ipv4Addr>>> {
337 match src {
338 Ipv4SourceAddr::Specified(src) => Some(src),
339 Ipv4SourceAddr::Unspecified => None,
340 }
341 }
342 fn new_ttl_expired<B: SplitByteSlice>(
343 proto: Ipv4Proto,
344 header_len: usize,
345 Ipv4OnlyMeta { id: _, fragment_type }: Ipv4OnlyMeta,
346 ) -> Icmpv4Error {
347 Icmpv4Error { kind: Icmpv4ErrorKind::TtlExpired { proto, fragment_type }, header_len }
348 }
349 fn new_mtu_exceeded(_proto: Ipv4Proto, _header_len: usize, _mtu: Mtu) -> Option<Icmpv4Error> {
350 None
352 }
353}
354
355impl IcmpHandlerIpExt for Ipv6 {
356 type SourceAddress = UnicastAddr<Ipv6Addr>;
357 type IcmpError = Icmpv6ErrorKind;
358 fn received_source_as_icmp_source(src: Ipv6SourceAddr) -> Option<UnicastAddr<Ipv6Addr>> {
359 match src {
360 Ipv6SourceAddr::Unicast(src) => Some(src.get()),
361 Ipv6SourceAddr::Unspecified => None,
362 }
363 }
364 fn new_ttl_expired<B: SplitByteSlice>(
365 proto: Ipv6Proto,
366 header_len: usize,
367 _meta: (),
368 ) -> Icmpv6ErrorKind {
369 Icmpv6ErrorKind::TtlExpired { proto, header_len }
370 }
371 fn new_mtu_exceeded(proto: Ipv6Proto, header_len: usize, mtu: Mtu) -> Option<Icmpv6ErrorKind> {
372 Some(Icmpv6ErrorKind::PacketTooBig { proto, header_len, mtu })
373 }
374}
375
376pub(crate) enum Icmpv4ErrorKind {
378 ParameterProblem {
379 code: Icmpv4ParameterProblemCode,
380 pointer: u8,
381 fragment_type: Ipv4FragmentType,
382 },
383 TtlExpired {
384 proto: Ipv4Proto,
385 fragment_type: Ipv4FragmentType,
386 },
387 NetUnreachable {
388 proto: Ipv4Proto,
389 fragment_type: Ipv4FragmentType,
390 },
391 ProtocolUnreachable,
392 PortUnreachable,
393}
394
395pub struct Icmpv4Error {
397 pub(super) kind: Icmpv4ErrorKind,
398 pub(super) header_len: usize,
399}
400
401pub enum Icmpv6ErrorKind {
403 ParameterProblem { code: Icmpv6ParameterProblemCode, pointer: u32, allow_dst_multicast: bool },
404 TtlExpired { proto: Ipv6Proto, header_len: usize },
405 NetUnreachable { proto: Ipv6Proto, header_len: usize },
406 PacketTooBig { proto: Ipv6Proto, header_len: usize, mtu: Mtu },
407 ProtocolUnreachable { header_len: usize },
408 PortUnreachable,
409}
410
411pub trait IcmpErrorHandler<I: IcmpHandlerIpExt, BC>: DeviceIdContext<AnyDevice> {
413 fn send_icmp_error_message<B: BufferMut>(
418 &mut self,
419 bindings_ctx: &mut BC,
420 device: &Self::DeviceId,
421 frame_dst: Option<FrameDestination>,
422 src_ip: I::SourceAddress,
423 dst_ip: SpecifiedAddr<I::Addr>,
424 original_packet: B,
425 error: I::IcmpError,
426 marks: &Marks,
427 );
428}
429
430impl<BC: IcmpBindingsContext, CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>>
431 IcmpErrorHandler<Ipv4, BC> for CC
432{
433 fn send_icmp_error_message<B: BufferMut>(
434 &mut self,
435 bindings_ctx: &mut BC,
436 device: &CC::DeviceId,
437 frame_dst: Option<FrameDestination>,
438 src_ip: NonMulticastAddr<SpecifiedAddr<Ipv4Addr>>,
439 dst_ip: SpecifiedAddr<Ipv4Addr>,
440 original_packet: B,
441 Icmpv4Error { kind, header_len }: Icmpv4Error,
442 marks: &Marks,
443 ) {
444 let src_ip = SocketIpAddr::new_ipv4_specified(src_ip.get());
445 let dst_ip = SocketIpAddr::new_ipv4_specified(dst_ip);
446 match kind {
447 Icmpv4ErrorKind::ParameterProblem { code, pointer, fragment_type } => {
448 send_icmpv4_parameter_problem(
449 self,
450 bindings_ctx,
451 device,
452 frame_dst,
453 src_ip,
454 dst_ip,
455 code,
456 Icmpv4ParameterProblem::new(pointer),
457 original_packet,
458 header_len,
459 fragment_type,
460 marks,
461 )
462 }
463 Icmpv4ErrorKind::TtlExpired { proto, fragment_type } => send_icmpv4_ttl_expired(
464 self,
465 bindings_ctx,
466 device,
467 frame_dst,
468 src_ip,
469 dst_ip,
470 proto,
471 original_packet,
472 header_len,
473 fragment_type,
474 marks,
475 ),
476 Icmpv4ErrorKind::NetUnreachable { proto, fragment_type } => {
477 send_icmpv4_net_unreachable(
478 self,
479 bindings_ctx,
480 device,
481 frame_dst,
482 src_ip,
483 dst_ip,
484 proto,
485 original_packet,
486 header_len,
487 fragment_type,
488 marks,
489 )
490 }
491 Icmpv4ErrorKind::ProtocolUnreachable => send_icmpv4_protocol_unreachable(
492 self,
493 bindings_ctx,
494 device,
495 frame_dst,
496 src_ip,
497 dst_ip,
498 original_packet,
499 header_len,
500 marks,
501 ),
502 Icmpv4ErrorKind::PortUnreachable => send_icmpv4_port_unreachable(
503 self,
504 bindings_ctx,
505 device,
506 frame_dst,
507 src_ip,
508 dst_ip,
509 original_packet,
510 header_len,
511 marks,
512 ),
513 }
514 }
515}
516
517impl<BC: IcmpBindingsContext, CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>>
518 IcmpErrorHandler<Ipv6, BC> for CC
519{
520 fn send_icmp_error_message<B: BufferMut>(
521 &mut self,
522 bindings_ctx: &mut BC,
523 device: &CC::DeviceId,
524 frame_dst: Option<FrameDestination>,
525 src_ip: UnicastAddr<Ipv6Addr>,
526 dst_ip: SpecifiedAddr<Ipv6Addr>,
527 original_packet: B,
528 error: Icmpv6ErrorKind,
529 marks: &Marks,
530 ) {
531 let src_ip: SocketIpAddr<Ipv6Addr> = match src_ip.into_specified().try_into() {
532 Ok(addr) => addr,
533 Err(AddrIsMappedError {}) => {
534 trace!("send_icmpv6_error_message: src_ip is mapped");
535 return;
536 }
537 };
538 let dst_ip: SocketIpAddr<Ipv6Addr> = match dst_ip.try_into() {
539 Ok(addr) => addr,
540 Err(AddrIsMappedError {}) => {
541 trace!("send_icmpv6_error_message: dst_ip is mapped");
542 return;
543 }
544 };
545
546 match error {
547 Icmpv6ErrorKind::ParameterProblem { code, pointer, allow_dst_multicast } => {
548 send_icmpv6_parameter_problem(
549 self,
550 bindings_ctx,
551 device,
552 frame_dst,
553 src_ip,
554 dst_ip,
555 code,
556 Icmpv6ParameterProblem::new(pointer),
557 original_packet,
558 allow_dst_multicast,
559 marks,
560 )
561 }
562 Icmpv6ErrorKind::TtlExpired { proto, header_len } => send_icmpv6_ttl_expired(
563 self,
564 bindings_ctx,
565 device,
566 frame_dst,
567 src_ip,
568 dst_ip,
569 proto,
570 original_packet,
571 header_len,
572 marks,
573 ),
574 Icmpv6ErrorKind::NetUnreachable { proto, header_len } => send_icmpv6_net_unreachable(
575 self,
576 bindings_ctx,
577 device,
578 frame_dst,
579 src_ip,
580 dst_ip,
581 proto,
582 original_packet,
583 header_len,
584 marks,
585 ),
586 Icmpv6ErrorKind::PacketTooBig { proto, header_len, mtu } => send_icmpv6_packet_too_big(
587 self,
588 bindings_ctx,
589 device,
590 frame_dst,
591 src_ip,
592 dst_ip,
593 proto,
594 mtu,
595 original_packet,
596 header_len,
597 marks,
598 ),
599 Icmpv6ErrorKind::ProtocolUnreachable { header_len } => {
600 send_icmpv6_protocol_unreachable(
601 self,
602 bindings_ctx,
603 device,
604 frame_dst,
605 src_ip,
606 dst_ip,
607 original_packet,
608 header_len,
609 marks,
610 )
611 }
612 Icmpv6ErrorKind::PortUnreachable => send_icmpv6_port_unreachable(
613 self,
614 bindings_ctx,
615 device,
616 frame_dst,
617 src_ip,
618 dst_ip,
619 original_packet,
620 marks,
621 ),
622 }
623 }
624}
625
626pub trait IcmpBindingsContext: InstantContext + RngContext + IcmpBindingsTypes {}
629impl<BC> IcmpBindingsContext for BC where
630 BC: InstantContext + RngContext + IcmpBindingsTypes + IcmpBindingsTypes
631{
632}
633
634pub trait IcmpBindingsTypes: InstantBindingsTypes + TxMetadataBindingsTypes {}
636impl<BT: InstantBindingsTypes + TxMetadataBindingsTypes> IcmpBindingsTypes for BT {}
637
638pub trait IcmpStateContext {}
646
647pub trait EchoTransportContextMarker {}
657
658pub trait InnerIcmpContext<I: IpExt + FilterIpExt, BC: IcmpBindingsTypes>:
661 IpSocketHandler<I, BC>
662{
663 type EchoTransportContext: IpTransportContext<I, BC, Self> + EchoTransportContextMarker;
666
667 fn receive_icmp_error(
697 &mut self,
698 bindings_ctx: &mut BC,
699 device: &Self::DeviceId,
700 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
701 original_dst_ip: SpecifiedAddr<I::Addr>,
702 original_proto: I::Proto,
703 original_body: &[u8],
704 err: I::ErrorCode,
705 );
706
707 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
710 &mut self,
711 cb: F,
712 ) -> O;
713}
714
715pub trait InnerIcmpv4Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv4, BC> {
719 fn should_send_timestamp_reply(&self) -> bool;
721}
722
723pub trait InnerIcmpv6Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv6, BC> {}
727impl<BC: IcmpBindingsTypes, CC: InnerIcmpContext<Ipv6, BC>> InnerIcmpv6Context<BC> for CC {}
728
729macro_rules! try_send_error {
743 ($core_ctx:expr, $bindings_ctx:expr, $e:expr) => {{
744 let send = $core_ctx.with_error_send_bucket_mut(|error_send_bucket| {
745 error_send_bucket.try_take($bindings_ctx)
746 });
747
748 if send {
749 $core_ctx.counters().error.increment();
750 $e
751 } else {
752 trace!("ip::icmp::try_send_error!: dropping rate-limited ICMP error message");
753 Ok(())
754 }
755 }};
756}
757
758pub enum IcmpIpTransportContext {}
760
761fn receive_ip_transport_icmp_error<
762 I: IpExt + FilterIpExt,
763 CC: InnerIcmpContext<I, BC> + CounterContext<IcmpRxCounters<I>>,
764 BC: IcmpBindingsContext,
765>(
766 core_ctx: &mut CC,
767 bindings_ctx: &mut BC,
768 device: &CC::DeviceId,
769 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
770 original_dst_ip: SpecifiedAddr<I::Addr>,
771 original_body: &[u8],
772 err: I::ErrorCode,
773) {
774 core_ctx.counters().error_delivered_to_transport_layer.increment();
775 trace!("IcmpIpTransportContext::receive_icmp_error({:?})", err);
776
777 let mut parse_body = original_body;
778 match parse_body.parse::<IcmpPacketRaw<I, _, IcmpEchoRequest>>() {
779 Ok(_echo_request) => (),
782 Err(_) => {
783 return;
787 }
788 }
789
790 <CC::EchoTransportContext as IpTransportContext<I, BC, CC>>::receive_icmp_error(
791 core_ctx,
792 bindings_ctx,
793 device,
794 original_src_ip,
795 original_dst_ip,
796 original_body,
797 err,
798 );
799}
800
801impl<
802 BC: IcmpBindingsContext,
803 CC: InnerIcmpv4Context<BC>
804 + PmtuHandler<Ipv4, BC>
805 + CounterContext<IcmpRxCounters<Ipv4>>
806 + CounterContext<IcmpTxCounters<Ipv4>>,
807> IpTransportContext<Ipv4, BC, CC> for IcmpIpTransportContext
808{
809 fn receive_icmp_error(
810 core_ctx: &mut CC,
811 bindings_ctx: &mut BC,
812 device: &CC::DeviceId,
813 original_src_ip: Option<SpecifiedAddr<Ipv4Addr>>,
814 original_dst_ip: SpecifiedAddr<Ipv4Addr>,
815 original_body: &[u8],
816 err: Icmpv4ErrorCode,
817 ) {
818 receive_ip_transport_icmp_error(
819 core_ctx,
820 bindings_ctx,
821 device,
822 original_src_ip,
823 original_dst_ip,
824 original_body,
825 err,
826 )
827 }
828
829 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv4>>(
830 core_ctx: &mut CC,
831 bindings_ctx: &mut BC,
832 device: &CC::DeviceId,
833 src_ip: Ipv4SourceAddr,
834 dst_ip: SpecifiedAddr<Ipv4Addr>,
835 mut buffer: B,
836 info: &LocalDeliveryPacketInfo<Ipv4, H>,
837 ) -> Result<(), (B, TransportReceiveError)> {
838 let LocalDeliveryPacketInfo { meta, header_info: _, marks } = info;
839 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
840 if let Some(delivery) = transparent_override {
841 unreachable!(
842 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
843 transparent proxy rules can only be configured for TCP and UDP packets"
844 );
845 }
846
847 trace!(
848 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet({}, {})",
849 src_ip, dst_ip
850 );
851 let packet =
852 match buffer.parse_with::<_, Icmpv4Packet<_>>(IcmpParseArgs::new(src_ip, dst_ip)) {
853 Ok(packet) => packet,
854 Err(_) => return Ok(()), };
856
857 match packet {
858 Icmpv4Packet::EchoRequest(echo_request) => {
859 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_request.increment();
860
861 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
862 let req = *echo_request.message();
863 let code = echo_request.code();
864 let (local_ip, remote_ip) = (dst_ip, src_ip);
865 debug!(
866 "replying to ICMP echo request from {remote_ip} to {local_ip}%{device:?}: \
867 id={}, seq={}",
868 req.id(),
869 req.seq()
870 );
871 send_icmp_reply(
872 core_ctx,
873 bindings_ctx,
874 device,
875 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
876 SocketIpAddr::new_ipv4_specified(local_ip),
877 |src_ip| {
878 IcmpPacketBuilder::<Ipv4, _>::new(src_ip, *remote_ip, code, req.reply())
879 .wrap_body(buffer)
880 },
881 &WithMarks(marks),
882 );
883 } else {
884 trace!(
885 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
886 Received echo request with an unspecified source address"
887 );
888 }
889 }
890 Icmpv4Packet::EchoReply(echo_reply) => {
891 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_reply.increment();
892 trace!(
893 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
894 Received an EchoReply message"
895 );
896 let parse_metadata = echo_reply.parse_metadata();
897 buffer.undo_parse(parse_metadata);
898 return <CC::EchoTransportContext
899 as IpTransportContext<Ipv4, BC, CC>>::receive_ip_packet(
900 core_ctx,
901 bindings_ctx,
902 device,
903 src_ip,
904 dst_ip,
905 buffer,
906 info,
907 );
908 }
909 Icmpv4Packet::TimestampRequest(timestamp_request) => {
910 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
911 .timestamp_request
912 .increment();
913 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
914 if core_ctx.should_send_timestamp_reply() {
915 trace!(
916 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
917 receive_ip_packet: Responding to Timestamp Request message"
918 );
919 const NOW: u32 = 0x80000000;
938 let reply = timestamp_request.message().reply(NOW, NOW);
939 let (local_ip, remote_ip) = (dst_ip, src_ip);
940 buffer.shrink_front_to(0);
947 send_icmp_reply(
948 core_ctx,
949 bindings_ctx,
950 device,
951 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
952 SocketIpAddr::new_ipv4_specified(local_ip),
953 |src_ip| {
954 IcmpPacketBuilder::<Ipv4, _>::new(
955 src_ip,
956 *remote_ip,
957 IcmpZeroCode,
958 reply,
959 )
960 .wrap_body(buffer)
961 },
962 &WithMarks(marks),
963 );
964 } else {
965 trace!(
966 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
967 receive_ip_packet: Silently ignoring Timestamp Request message"
968 );
969 }
970 } else {
971 trace!(
972 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
973 receive_ip_packet: Received timestamp request with an unspecified source \
974 address"
975 );
976 }
977 }
978 Icmpv4Packet::TimestampReply(_) => {
979 debug!(
982 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
983 Received unsolicited Timestamp Reply message"
984 );
985 }
986 Icmpv4Packet::DestUnreachable(dest_unreachable) => {
987 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
988 .dest_unreachable
989 .increment();
990 trace!(
991 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
992 Received a Destination Unreachable message"
993 );
994
995 let error = if dest_unreachable.code()
996 == Icmpv4DestUnreachableCode::FragmentationRequired
997 {
998 let mtu = if let Some(next_hop_mtu) = dest_unreachable.message().next_hop_mtu()
999 {
1000 core_ctx.update_pmtu_if_less(
1010 bindings_ctx,
1011 dst_ip.get(),
1012 src_ip.get(),
1013 Mtu::new(u32::from(next_hop_mtu.get())),
1014 )
1015 } else {
1016 let (original_packet_buf, inner_body) = dest_unreachable.body().bytes();
1038 debug_assert!(inner_body.is_none());
1040 if original_packet_buf.len() >= 4 {
1041 let total_len =
1045 u16::from_be_bytes(original_packet_buf[2..4].try_into().unwrap());
1046
1047 trace!(
1048 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1049 receive_ip_packet: Next-Hop MTU is 0 so using the next best PMTU \
1050 value from {total_len}"
1051 );
1052
1053 core_ctx.update_pmtu_next_lower(
1054 bindings_ctx,
1055 dst_ip.get(),
1056 src_ip.get(),
1057 Mtu::new(u32::from(total_len)),
1058 )
1059 } else {
1060 trace!(
1065 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1066 receive_ip_packet: Original packet buf is too small to get \
1067 original packet len so ignoring"
1068 );
1069 None
1070 }
1071 };
1072 mtu.and_then(|mtu| {
1073 let mtu = u16::try_from(mtu.get()).unwrap_or(u16::MAX);
1074 let mtu = NonZeroU16::new(mtu)?;
1075 Some(Icmpv4ErrorCode::DestUnreachable(
1076 dest_unreachable.code(),
1077 IcmpDestUnreachable::new_for_frag_req(mtu),
1078 ))
1079 })
1080 } else {
1081 Some(Icmpv4ErrorCode::DestUnreachable(
1082 dest_unreachable.code(),
1083 *dest_unreachable.message(),
1084 ))
1085 };
1086
1087 if let Some(error) = error {
1088 receive_icmpv4_error(core_ctx, bindings_ctx, device, &dest_unreachable, error);
1089 }
1090 }
1091 Icmpv4Packet::TimeExceeded(time_exceeded) => {
1092 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1093 .time_exceeded
1094 .increment();
1095 trace!(
1096 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1097 Received a Time Exceeded message"
1098 );
1099
1100 receive_icmpv4_error(
1101 core_ctx,
1102 bindings_ctx,
1103 device,
1104 &time_exceeded,
1105 Icmpv4ErrorCode::TimeExceeded(time_exceeded.code()),
1106 );
1107 }
1108 Icmpv4Packet::Redirect(_) => {
1110 debug!(
1111 "Unimplemented: <IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1112 receive_ip_packet::redirect"
1113 )
1114 }
1115 Icmpv4Packet::ParameterProblem(parameter_problem) => {
1116 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1117 .parameter_problem
1118 .increment();
1119 trace!(
1120 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1121 Received a Parameter Problem message"
1122 );
1123
1124 receive_icmpv4_error(
1125 core_ctx,
1126 bindings_ctx,
1127 device,
1128 ¶meter_problem,
1129 Icmpv4ErrorCode::ParameterProblem(parameter_problem.code()),
1130 );
1131 }
1132 }
1133
1134 Ok(())
1135 }
1136}
1137
1138#[allow(missing_docs)]
1141pub enum NdpMessage {
1142 NeighborSolicitation {
1143 message: NeighborSolicitation,
1144 code: <NeighborSolicitation as IcmpMessage<Ipv6>>::Code,
1145 },
1146
1147 RouterSolicitation {
1148 message: RouterSolicitation,
1149 code: <RouterSolicitation as IcmpMessage<Ipv6>>::Code,
1150 },
1151
1152 NeighborAdvertisement {
1153 message: NeighborAdvertisement,
1154 code: <NeighborAdvertisement as IcmpMessage<Ipv6>>::Code,
1155 },
1156}
1157
1158pub fn send_ndp_packet<BC, CC, S>(
1160 core_ctx: &mut CC,
1161 bindings_ctx: &mut BC,
1162 device_id: &CC::DeviceId,
1163 src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1164 dst_ip: SpecifiedAddr<Ipv6Addr>,
1165 body: S,
1166 message: NdpMessage,
1167) -> Result<(), IpSendFrameError<S>>
1168where
1169 CC: IpLayerHandler<Ipv6, BC>,
1170 S: Serializer + PartialSerializer,
1171 S::Buffer: BufferMut,
1172{
1173 macro_rules! send {
1174 ($message:expr, $code:expr) => {{
1175 let mut ser = IcmpPacketBuilder::<Ipv6, _>::new(
1177 src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
1178 dst_ip.get(),
1179 $code,
1180 $message,
1181 )
1182 .wrap_body(body);
1183 match IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
1184 core_ctx,
1185 bindings_ctx,
1186 SendIpPacketMeta {
1187 device: device_id,
1188 src_ip,
1189 dst_ip,
1190 destination: IpPacketDestination::from_addr(dst_ip),
1191 ttl: NonZeroU8::new(REQUIRED_NDP_IP_PACKET_HOP_LIMIT),
1192 proto: Ipv6Proto::Icmpv6,
1193 mtu: Mtu::no_limit(),
1194 dscp_and_ecn: DscpAndEcn::default(),
1195 },
1196 DynTransportSerializer::new(&mut ser),
1197 ) {
1198 Ok(()) => Ok(()),
1199 Err(e) => Err(e
1200 .map_serializer(|s| {
1201 let _: DynTransportSerializer<'_, _> = s;
1203 })
1204 .map_serializer(|()| ser.into_inner())),
1205 }
1206 }};
1207 }
1208
1209 match message {
1210 NdpMessage::NeighborSolicitation { message, code } => send!(message, code),
1211 NdpMessage::RouterSolicitation { message, code } => send!(message, code),
1212 NdpMessage::NeighborAdvertisement { message, code } => send!(message, code),
1213 }
1214}
1215
1216fn send_neighbor_advertisement<
1217 BC,
1218 CC: Ipv6DeviceHandler<BC>
1219 + IpDeviceHandler<Ipv6, BC>
1220 + IpLayerHandler<Ipv6, BC>
1221 + CounterContext<NdpCounters>,
1222>(
1223 core_ctx: &mut CC,
1224 bindings_ctx: &mut BC,
1225 device_id: &CC::DeviceId,
1226 solicited: bool,
1227 device_addr: UnicastAddr<Ipv6Addr>,
1228 dst_ip: SpecifiedAddr<Ipv6Addr>,
1229) {
1230 core_ctx.counters().tx.neighbor_advertisement.increment();
1231 debug!("send_neighbor_advertisement from {:?} to {:?}", device_addr, dst_ip);
1232 debug_assert!(dst_ip.is_valid_unicast() || (!solicited && dst_ip.is_multicast()));
1239
1240 let src_ll = core_ctx.get_link_layer_addr(&device_id);
1247
1248 let advertisement = NeighborAdvertisement::new(
1250 core_ctx.is_router_device(&device_id),
1251 solicited,
1252 true, device_addr.get(),
1265 );
1266 let _: Result<(), _> = send_ndp_packet(
1267 core_ctx,
1268 bindings_ctx,
1269 &device_id,
1270 Some(device_addr.into_specified()),
1271 dst_ip,
1272 OptionSequenceBuilder::new(
1273 src_ll
1274 .as_ref()
1275 .map(Ipv6LinkLayerAddr::as_bytes)
1276 .map(NdpOptionBuilder::TargetLinkLayerAddress)
1277 .iter(),
1278 )
1279 .into_serializer(),
1280 NdpMessage::NeighborAdvertisement { message: advertisement, code: IcmpZeroCode },
1281 );
1282}
1283
1284fn receive_ndp_packet<
1285 B: SplitByteSlice,
1286 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1287 CC: InnerIcmpv6Context<BC>
1288 + Ipv6DeviceHandler<BC>
1289 + IpDeviceHandler<Ipv6, BC>
1290 + IpDeviceIngressStateContext<Ipv6>
1291 + NudIpHandler<Ipv6, BC>
1292 + IpLayerHandler<Ipv6, BC>
1293 + CounterContext<NdpCounters>,
1294 H: IpHeaderInfo<Ipv6>,
1295>(
1296 core_ctx: &mut CC,
1297 bindings_ctx: &mut BC,
1298 device_id: &CC::DeviceId,
1299 src_ip: Ipv6SourceAddr,
1300 dst_ip: SpecifiedAddr<Ipv6Addr>,
1301 packet: NdpPacket<B>,
1302 header_info: &H,
1303) {
1304 if header_info.hop_limit() != REQUIRED_NDP_IP_PACKET_HOP_LIMIT {
1322 trace!("dropping NDP packet from {src_ip} with invalid hop limit");
1323 return;
1324 }
1325
1326 match packet {
1327 NdpPacket::RouterSolicitation(_) | NdpPacket::Redirect(_) => {}
1328 NdpPacket::NeighborSolicitation(ref p) => {
1329 let target_address = p.message().target_address();
1336 let target_address = match UnicastAddr::new(*target_address) {
1337 Some(a) => a,
1338 None => {
1339 trace!(
1340 "dropping NS from {} with non-unicast target={:?}",
1341 src_ip, target_address
1342 );
1343 return;
1344 }
1345 };
1346
1347 if src_ip == Ipv6SourceAddr::Unspecified {
1348 if target_address.get().to_solicited_node_address().get() != dst_ip.get() {
1357 debug!(
1358 "dropping NS from {} for {} with invalid IPv6 dst ({}).",
1359 src_ip, target_address, dst_ip
1360 );
1361 return;
1362 }
1363
1364 }
1370
1371 core_ctx.counters().rx.neighbor_solicitation.increment();
1372
1373 match src_ip {
1374 Ipv6SourceAddr::Unspecified => {
1375 match IpDeviceHandler::handle_received_dad_packet(
1385 core_ctx,
1386 bindings_ctx,
1387 &device_id,
1388 target_address.into_specified(),
1389 p.body().iter().find_map(|option| option.nonce()),
1390 ) {
1391 Some(IpAddressState::Assigned) => {
1392 send_neighbor_advertisement(
1396 core_ctx,
1397 bindings_ctx,
1398 &device_id,
1399 false,
1400 target_address,
1401 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified(),
1402 );
1403 }
1404 Some(IpAddressState::Tentative) => {
1405 }
1408 Some(IpAddressState::Unavailable) | None => {
1409 }
1412 }
1413
1414 return;
1415 }
1416 Ipv6SourceAddr::Unicast(src_ip) => {
1417 match core_ctx
1419 .address_status_for_device(target_address.into_specified(), device_id)
1420 {
1421 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned) => {}
1422 AddressStatus::Present(
1423 Ipv6PresentAddressStatus::UnicastTentative
1424 | Ipv6PresentAddressStatus::Multicast,
1425 )
1426 | AddressStatus::Unassigned => {
1427 return;
1431 }
1432 }
1433
1434 let link_addr = p.body().iter().find_map(|o| o.source_link_layer_address());
1435
1436 if let Some(link_addr) = link_addr {
1437 NudIpHandler::handle_neighbor_probe(
1438 core_ctx,
1439 bindings_ctx,
1440 &device_id,
1441 src_ip.into_specified(),
1442 link_addr,
1443 );
1444 }
1445
1446 send_neighbor_advertisement(
1447 core_ctx,
1448 bindings_ctx,
1449 &device_id,
1450 true,
1451 target_address,
1452 src_ip.into_specified(),
1453 );
1454 }
1455 }
1456 }
1457 NdpPacket::NeighborAdvertisement(ref p) => {
1458 let target_address = p.message().target_address();
1462
1463 let src_ip = match src_ip {
1464 Ipv6SourceAddr::Unicast(src_ip) => src_ip,
1465 Ipv6SourceAddr::Unspecified => {
1466 trace!("dropping NA with unspecified source and target = {:?}", target_address);
1467 return;
1468 }
1469 };
1470
1471 let target_address = match UnicastAddr::new(*target_address) {
1472 Some(a) => a,
1473 None => {
1474 trace!(
1475 "dropping NA from {} with non-unicast target={:?}",
1476 src_ip, target_address
1477 );
1478 return;
1479 }
1480 };
1481
1482 core_ctx.counters().rx.neighbor_advertisement.increment();
1483
1484 let nonce = None;
1488 match IpDeviceHandler::handle_received_dad_packet(
1489 core_ctx,
1490 bindings_ctx,
1491 &device_id,
1492 target_address.into_specified(),
1493 nonce,
1494 ) {
1495 Some(IpAddressState::Assigned) => {
1496 error!(
1514 "NA from {src_ip} with target address {target_address} that is also \
1515 assigned on device {device_id:?}",
1516 );
1517 }
1518 Some(IpAddressState::Tentative) => {
1519 return;
1522 }
1523 Some(IpAddressState::Unavailable) | None => {
1524 }
1528 }
1529
1530 let link_addr = p.body().iter().find_map(|o| o.target_link_layer_address());
1531
1532 NudIpHandler::handle_neighbor_confirmation(
1533 core_ctx,
1534 bindings_ctx,
1535 &device_id,
1536 target_address.into_specified(),
1537 link_addr,
1538 ConfirmationFlags {
1539 solicited_flag: p.message().solicited_flag(),
1540 override_flag: p.message().override_flag(),
1541 },
1542 );
1543 }
1544 NdpPacket::RouterAdvertisement(ref p) => {
1545 let src_ip = match src_ip {
1558 Ipv6SourceAddr::Unicast(ip) => match LinkLocalUnicastAddr::new(*ip) {
1559 Some(ip) => ip,
1560 None => return,
1561 },
1562 Ipv6SourceAddr::Unspecified => return,
1563 };
1564
1565 let ra = p.message();
1566 debug!("received router advertisement from {:?}: {:?}", src_ip, ra);
1567 core_ctx.counters().rx.router_advertisement.increment();
1568
1569 if let Some(retransmit_timer) = ra.retransmit_timer() {
1576 Ipv6DeviceHandler::set_discovered_retrans_timer(
1577 core_ctx,
1578 bindings_ctx,
1579 &device_id,
1580 retransmit_timer,
1581 );
1582 }
1583
1584 if let Some(hop_limit) = ra.current_hop_limit() {
1591 trace!(
1592 "receive_ndp_packet: NDP RA: updating device's hop limit to {:?} for router: {:?}",
1593 ra.current_hop_limit(),
1594 src_ip
1595 );
1596 IpDeviceHandler::set_default_hop_limit(core_ctx, &device_id, hop_limit);
1597 }
1598
1599 Ipv6DeviceHandler::update_discovered_ipv6_route(
1601 core_ctx,
1602 bindings_ctx,
1603 &device_id,
1604 Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) },
1605 p.message().router_lifetime().map(NonZeroNdpLifetime::Finite),
1606 );
1607
1608 for option in p.body().iter() {
1609 match option {
1610 NdpOption::TargetLinkLayerAddress(_)
1611 | NdpOption::RedirectedHeader { .. }
1612 | NdpOption::RecursiveDnsServer(_)
1613 | NdpOption::Nonce(_) => {}
1614 NdpOption::SourceLinkLayerAddress(addr) => {
1615 debug!("processing SourceLinkLayerAddress option in RA: {:?}", addr);
1616 NudIpHandler::handle_neighbor_probe(
1642 core_ctx,
1643 bindings_ctx,
1644 &device_id,
1645 {
1646 let src_ip: UnicastAddr<_> = src_ip.into_addr();
1647 src_ip.into_specified()
1648 },
1649 addr,
1650 );
1651 }
1652 NdpOption::PrefixInformation(prefix_info) => {
1653 debug!("processing Prefix Information option in RA: {:?}", prefix_info);
1654 if prefix_info.prefix().is_link_local() {
1672 continue;
1673 }
1674
1675 let subnet = match prefix_info.subnet() {
1676 Ok(subnet) => subnet,
1677 Err(err) => match err {
1678 SubnetError::PrefixTooLong | SubnetError::HostBitsSet => continue,
1679 },
1680 };
1681
1682 match UnicastAddr::new(subnet.network()) {
1683 Some(UnicastAddr { .. }) => {}
1684 None => continue,
1685 }
1686
1687 let valid_lifetime = prefix_info.valid_lifetime();
1688
1689 if prefix_info.on_link_flag() {
1690 Ipv6DeviceHandler::update_discovered_ipv6_route(
1692 core_ctx,
1693 bindings_ctx,
1694 &device_id,
1695 Ipv6DiscoveredRoute { subnet, gateway: None },
1696 valid_lifetime,
1697 )
1698 }
1699
1700 if prefix_info.autonomous_address_configuration_flag() {
1701 Ipv6DeviceHandler::apply_slaac_update(
1702 core_ctx,
1703 bindings_ctx,
1704 &device_id,
1705 subnet,
1706 prefix_info.preferred_lifetime(),
1707 valid_lifetime,
1708 );
1709 }
1710 }
1711 NdpOption::RouteInformation(rio) => {
1712 debug!("processing Route Information option in RA: {:?}", rio);
1713 Ipv6DeviceHandler::update_discovered_ipv6_route(
1715 core_ctx,
1716 bindings_ctx,
1717 &device_id,
1718 Ipv6DiscoveredRoute {
1719 subnet: rio.prefix().clone(),
1720 gateway: Some(src_ip),
1721 },
1722 rio.route_lifetime(),
1723 )
1724 }
1725 NdpOption::Mtu(mtu) => {
1726 debug!("processing MTU option in RA: {:?}", mtu);
1727 Ipv6DeviceHandler::set_link_mtu(core_ctx, &device_id, Mtu::new(mtu));
1731 }
1732 }
1733 }
1734
1735 bindings_ctx.on_event(RouterAdvertisementEvent {
1736 options_bytes: Box::from(p.body().bytes()),
1737 source: **src_ip,
1738 device: device_id.clone(),
1739 });
1740 }
1741 }
1742}
1743
1744impl<
1745 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1746 CC: InnerIcmpv6Context<BC>
1747 + InnerIcmpContext<Ipv6, BC>
1748 + Ipv6DeviceHandler<BC>
1749 + IpDeviceHandler<Ipv6, BC>
1750 + IpDeviceIngressStateContext<Ipv6>
1751 + PmtuHandler<Ipv6, BC>
1752 + NudIpHandler<Ipv6, BC>
1753 + IpLayerHandler<Ipv6, BC>
1754 + CounterContext<IcmpRxCounters<Ipv6>>
1755 + CounterContext<IcmpTxCounters<Ipv6>>
1756 + CounterContext<NdpCounters>,
1757> IpTransportContext<Ipv6, BC, CC> for IcmpIpTransportContext
1758{
1759 fn receive_icmp_error(
1760 core_ctx: &mut CC,
1761 bindings_ctx: &mut BC,
1762 device: &CC::DeviceId,
1763 original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1764 original_dst_ip: SpecifiedAddr<Ipv6Addr>,
1765 original_body: &[u8],
1766 err: Icmpv6ErrorCode,
1767 ) {
1768 receive_ip_transport_icmp_error(
1769 core_ctx,
1770 bindings_ctx,
1771 device,
1772 original_src_ip,
1773 original_dst_ip,
1774 original_body,
1775 err,
1776 )
1777 }
1778
1779 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
1780 core_ctx: &mut CC,
1781 bindings_ctx: &mut BC,
1782 device: &CC::DeviceId,
1783 src_ip: Ipv6SourceAddr,
1784 dst_ip: SpecifiedAddr<Ipv6Addr>,
1785 mut buffer: B,
1786 info: &LocalDeliveryPacketInfo<Ipv6, H>,
1787 ) -> Result<(), (B, TransportReceiveError)> {
1788 let LocalDeliveryPacketInfo { meta, header_info, marks } = info;
1789 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
1790 if let Some(delivery) = transparent_override {
1791 unreachable!(
1792 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
1793 transparent proxy rules can only be configured for TCP and UDP packets"
1794 );
1795 }
1796
1797 trace!(
1798 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet({:?}, {})",
1799 src_ip, dst_ip
1800 );
1801
1802 let packet = match buffer
1803 .parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(src_ip.get(), dst_ip))
1804 {
1805 Ok(packet) => packet,
1806 Err(_) => return Ok(()), };
1808
1809 match packet {
1810 Icmpv6Packet::EchoRequest(echo_request) => {
1811 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_request.increment();
1812
1813 if let Some(src_ip) = SocketIpAddr::new_from_ipv6_source(src_ip) {
1814 match SocketIpAddr::try_from(dst_ip) {
1815 Ok(dst_ip) => {
1816 let req = *echo_request.message();
1817 let code = echo_request.code();
1818 let (local_ip, remote_ip) = (dst_ip, src_ip);
1819 debug!(
1820 "replying to ICMP echo request from {remote_ip}: id={}, seq={}",
1821 req.id(),
1822 req.seq()
1823 );
1824 send_icmp_reply(
1825 core_ctx,
1826 bindings_ctx,
1827 device,
1828 remote_ip,
1829 local_ip,
1830 |src_ip| {
1831 IcmpPacketBuilder::<Ipv6, _>::new(
1832 src_ip,
1833 remote_ip.addr(),
1834 code,
1835 req.reply(),
1836 )
1837 .wrap_body(buffer)
1838 },
1839 &WithMarks(marks),
1840 );
1841 }
1842 Err(AddrIsMappedError {}) => {
1843 trace!(
1844 "IpTransportContext<Ipv6>::receive_ip_packet: Received echo request with an ipv4-mapped-ipv6 destination address"
1845 );
1846 }
1847 }
1848 } else {
1849 trace!(
1850 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received echo request with an unspecified source address"
1851 );
1852 }
1853 }
1854 Icmpv6Packet::EchoReply(echo_reply) => {
1855 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_reply.increment();
1856 trace!(
1857 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received an EchoReply message"
1858 );
1859 let parse_metadata = echo_reply.parse_metadata();
1860 buffer.undo_parse(parse_metadata);
1861 return <CC::EchoTransportContext
1862 as IpTransportContext<Ipv6, BC, CC>>::receive_ip_packet(
1863 core_ctx,
1864 bindings_ctx,
1865 device,
1866 src_ip,
1867 dst_ip,
1868 buffer,
1869 info
1870 );
1871 }
1872 Icmpv6Packet::Ndp(packet) => receive_ndp_packet(
1873 core_ctx,
1874 bindings_ctx,
1875 device,
1876 src_ip,
1877 dst_ip,
1878 packet,
1879 header_info,
1880 ),
1881 Icmpv6Packet::PacketTooBig(packet_too_big) => {
1882 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
1883 .packet_too_big
1884 .increment();
1885 trace!(
1886 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received a Packet Too Big message"
1887 );
1888 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
1889 let mtu = core_ctx.update_pmtu_if_less(
1899 bindings_ctx,
1900 dst_ip.get(),
1901 src_ip.get(),
1902 Mtu::new(packet_too_big.message().mtu()),
1903 );
1904 if let Some(mtu) = mtu {
1905 receive_icmpv6_error(
1906 core_ctx,
1907 bindings_ctx,
1908 device,
1909 &packet_too_big,
1910 Icmpv6ErrorCode::PacketTooBig(mtu),
1911 );
1912 }
1913 }
1914 }
1915 Icmpv6Packet::Mld(packet) => {
1916 core_ctx.receive_mld_packet(
1917 bindings_ctx,
1918 &device,
1919 src_ip,
1920 dst_ip,
1921 packet,
1922 header_info,
1923 );
1924 }
1925 Icmpv6Packet::DestUnreachable(dest_unreachable) => receive_icmpv6_error(
1926 core_ctx,
1927 bindings_ctx,
1928 device,
1929 &dest_unreachable,
1930 Icmpv6ErrorCode::DestUnreachable(dest_unreachable.code()),
1931 ),
1932 Icmpv6Packet::TimeExceeded(time_exceeded) => receive_icmpv6_error(
1933 core_ctx,
1934 bindings_ctx,
1935 device,
1936 &time_exceeded,
1937 Icmpv6ErrorCode::TimeExceeded(time_exceeded.code()),
1938 ),
1939 Icmpv6Packet::ParameterProblem(parameter_problem) => receive_icmpv6_error(
1940 core_ctx,
1941 bindings_ctx,
1942 device,
1943 ¶meter_problem,
1944 Icmpv6ErrorCode::ParameterProblem(parameter_problem.code()),
1945 ),
1946 }
1947
1948 Ok(())
1949 }
1950}
1951
1952#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1953struct WithMarks<'a>(&'a Marks);
1954
1955impl<'a> OptionDelegationMarker for WithMarks<'a> {}
1956
1957impl<'a, I: IpExt> DelegatedRouteResolutionOptions<I> for WithMarks<'a> {
1958 fn marks(&self) -> &Marks {
1959 let Self(marks) = self;
1960 marks
1961 }
1962}
1963
1964impl<'a, I: IpExt> DelegatedSendOptions<I> for WithMarks<'a> {}
1965
1966fn send_icmp_reply<I, BC, CC, S, F, O>(
1977 core_ctx: &mut CC,
1978 bindings_ctx: &mut BC,
1979 device: &CC::DeviceId,
1980 original_src_ip: SocketIpAddr<I::Addr>,
1981 original_dst_ip: SocketIpAddr<I::Addr>,
1982 get_body_from_src_ip: F,
1983 ip_options: &O,
1984) where
1985 I: IpExt + FilterIpExt,
1986 CC: IpSocketHandler<I, BC> + DeviceIdContext<AnyDevice> + CounterContext<IcmpTxCounters<I>>,
1987 BC: TxMetadataBindingsTypes,
1988 S: DynamicTransportSerializer<I>,
1989 F: FnOnce(SpecifiedAddr<I::Addr>) -> S,
1990 O: SendOptions<I> + RouteResolutionOptions<I>,
1991{
1992 trace!("send_icmp_reply({:?}, {}, {})", device, original_src_ip, original_dst_ip);
1993 core_ctx.counters().reply.increment();
1994 let tx_metadata: BC::TxMetadata = Default::default();
1995
1996 let egress_device = (original_dst_ip.as_ref().is_multicast()
2000 || original_dst_ip.as_ref().must_have_zone())
2001 .then_some(EitherDeviceId::Strong(device));
2002
2003 core_ctx
2004 .send_oneshot_ip_packet_with_dyn_serializer(
2005 bindings_ctx,
2006 IpSocketArgs {
2007 device: egress_device,
2008 local_ip: IpDeviceAddr::new_from_socket_ip_addr(original_dst_ip),
2009 remote_ip: original_src_ip,
2010 proto: I::ICMP_IP_PROTO,
2011 options: ip_options,
2012 },
2013 tx_metadata,
2014 |src_ip| get_body_from_src_ip(src_ip.into()),
2015 )
2016 .unwrap_or_else(|err| {
2017 debug!("failed to send ICMP reply: {}", err);
2018 })
2019}
2020
2021fn receive_icmpv4_error<
2026 BC: IcmpBindingsContext,
2027 CC: InnerIcmpv4Context<BC>,
2028 B: SplitByteSlice,
2029 M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>,
2030>(
2031 core_ctx: &mut CC,
2032 bindings_ctx: &mut BC,
2033 device: &CC::DeviceId,
2034 packet: &IcmpPacket<Ipv4, B, M>,
2035 err: Icmpv4ErrorCode,
2036) {
2037 packet.with_original_packet(|res| match res {
2038 Ok(original_packet) => {
2039 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2040 Some(ip) => ip,
2041 None => {
2042 trace!("receive_icmpv4_error: Got ICMP error message whose original IPv4 packet contains an unspecified destination address; discarding");
2043 return;
2044 },
2045 };
2046 InnerIcmpContext::receive_icmp_error(
2047 core_ctx,
2048 bindings_ctx,
2049 device,
2050 SpecifiedAddr::new(original_packet.src_ip()),
2051 dst_ip,
2052 original_packet.proto(),
2053 original_packet.body().into_inner(),
2054 err,
2055 );
2056 }
2057 Err(_) => debug!(
2058 "receive_icmpv4_error: Got ICMP error message with unparsable original IPv4 packet"
2059 ),
2060 })
2061}
2062
2063fn receive_icmpv6_error<
2068 BC: IcmpBindingsContext,
2069 CC: InnerIcmpv6Context<BC>,
2070 B: SplitByteSlice,
2071 M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>,
2072>(
2073 core_ctx: &mut CC,
2074 bindings_ctx: &mut BC,
2075 device: &CC::DeviceId,
2076 packet: &IcmpPacket<Ipv6, B, M>,
2077 err: Icmpv6ErrorCode,
2078) {
2079 packet.with_original_packet(|res| match res {
2080 Ok(original_packet) => {
2081 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2082 Some(ip)=>ip,
2083 None => {
2084 trace!("receive_icmpv6_error: Got ICMP error message whose original IPv6 packet contains an unspecified destination address; discarding");
2085 return;
2086 },
2087 };
2088 match original_packet.body_proto() {
2089 Ok((body, proto)) => {
2090 InnerIcmpContext::receive_icmp_error(
2091 core_ctx,
2092 bindings_ctx,
2093 device,
2094 SpecifiedAddr::new(original_packet.src_ip()),
2095 dst_ip,
2096 proto,
2097 body.into_inner(),
2098 err,
2099 );
2100 }
2101 Err(ExtHdrParseError) => {
2102 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");
2103 return;
2106 }
2107 }
2108 }
2109 Err(_body) => debug!(
2110 "receive_icmpv6_error: Got ICMPv6 error message with unparsable original IPv6 packet"
2111 ),
2112 })
2113}
2114
2115pub fn send_icmpv4_host_unreachable<
2133 B: BufferMut,
2134 BC: IcmpBindingsContext,
2135 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2136>(
2137 core_ctx: &mut CC,
2138 bindings_ctx: &mut BC,
2139 device: Option<&CC::DeviceId>,
2140 frame_dst: Option<FrameDestination>,
2141 src_ip: SocketIpAddr<Ipv4Addr>,
2142 dst_ip: SocketIpAddr<Ipv4Addr>,
2143 original_packet: B,
2144 header_len: usize,
2145 fragment_type: Ipv4FragmentType,
2146 marks: &Marks,
2147) {
2148 core_ctx.counters().address_unreachable.increment();
2149
2150 send_icmpv4_dest_unreachable(
2151 core_ctx,
2152 bindings_ctx,
2153 device,
2154 frame_dst,
2155 src_ip,
2156 dst_ip,
2157 Icmpv4DestUnreachableCode::DestHostUnreachable,
2158 original_packet,
2159 header_len,
2160 fragment_type,
2161 marks,
2162 );
2163}
2164
2165pub fn send_icmpv6_address_unreachable<
2176 B: BufferMut,
2177 BC: IcmpBindingsContext,
2178 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2179>(
2180 core_ctx: &mut CC,
2181 bindings_ctx: &mut BC,
2182 device: Option<&CC::DeviceId>,
2183 frame_dst: Option<FrameDestination>,
2184 src_ip: SocketIpAddr<Ipv6Addr>,
2185 dst_ip: SocketIpAddr<Ipv6Addr>,
2186 original_packet: B,
2187 marks: &Marks,
2188) {
2189 core_ctx.counters().address_unreachable.increment();
2190
2191 send_icmpv6_dest_unreachable(
2192 core_ctx,
2193 bindings_ctx,
2194 device,
2195 frame_dst,
2196 src_ip,
2197 dst_ip,
2198 Icmpv6DestUnreachableCode::AddrUnreachable,
2199 original_packet,
2200 marks,
2201 );
2202}
2203
2204pub(crate) fn send_icmpv4_protocol_unreachable<
2216 B: BufferMut,
2217 BC: IcmpBindingsContext,
2218 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2219>(
2220 core_ctx: &mut CC,
2221 bindings_ctx: &mut BC,
2222 device: &CC::DeviceId,
2223 frame_dst: Option<FrameDestination>,
2224 src_ip: SocketIpAddr<Ipv4Addr>,
2225 dst_ip: SocketIpAddr<Ipv4Addr>,
2226 original_packet: B,
2227 header_len: usize,
2228 marks: &Marks,
2229) {
2230 core_ctx.counters().protocol_unreachable.increment();
2231
2232 send_icmpv4_dest_unreachable(
2233 core_ctx,
2234 bindings_ctx,
2235 Some(device),
2236 frame_dst,
2237 src_ip,
2238 dst_ip,
2239 Icmpv4DestUnreachableCode::DestProtocolUnreachable,
2240 original_packet,
2241 header_len,
2242 Ipv4FragmentType::InitialFragment,
2248 marks,
2249 );
2250}
2251
2252pub(crate) fn send_icmpv6_protocol_unreachable<
2262 B: BufferMut,
2263 BC: IcmpBindingsContext,
2264 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2265>(
2266 core_ctx: &mut CC,
2267 bindings_ctx: &mut BC,
2268 device: &CC::DeviceId,
2269 frame_dst: Option<FrameDestination>,
2270 src_ip: SocketIpAddr<Ipv6Addr>,
2271 dst_ip: SocketIpAddr<Ipv6Addr>,
2272 original_packet: B,
2273 header_len: usize,
2274 marks: &Marks,
2275) {
2276 core_ctx.counters().protocol_unreachable.increment();
2277
2278 send_icmpv6_parameter_problem(
2279 core_ctx,
2280 bindings_ctx,
2281 device,
2282 frame_dst,
2283 src_ip,
2284 dst_ip,
2285 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2286 Icmpv6ParameterProblem::new(header_len as u32),
2300 original_packet,
2301 false,
2302 marks,
2303 );
2304}
2305
2306pub(crate) fn send_icmpv4_port_unreachable<
2318 B: BufferMut,
2319 BC: IcmpBindingsContext,
2320 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2321>(
2322 core_ctx: &mut CC,
2323 bindings_ctx: &mut BC,
2324 device: &CC::DeviceId,
2325 frame_dst: Option<FrameDestination>,
2326 src_ip: SocketIpAddr<Ipv4Addr>,
2327 dst_ip: SocketIpAddr<Ipv4Addr>,
2328 original_packet: B,
2329 header_len: usize,
2330 marks: &Marks,
2331) {
2332 core_ctx.counters().port_unreachable.increment();
2333
2334 send_icmpv4_dest_unreachable(
2335 core_ctx,
2336 bindings_ctx,
2337 Some(device),
2338 frame_dst,
2339 src_ip,
2340 dst_ip,
2341 Icmpv4DestUnreachableCode::DestPortUnreachable,
2342 original_packet,
2343 header_len,
2344 Ipv4FragmentType::InitialFragment,
2350 marks,
2351 );
2352}
2353
2354pub(crate) fn send_icmpv6_port_unreachable<
2363 B: BufferMut,
2364 BC: IcmpBindingsContext,
2365 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2366>(
2367 core_ctx: &mut CC,
2368 bindings_ctx: &mut BC,
2369 device: &CC::DeviceId,
2370 frame_dst: Option<FrameDestination>,
2371 src_ip: SocketIpAddr<Ipv6Addr>,
2372 dst_ip: SocketIpAddr<Ipv6Addr>,
2373 original_packet: B,
2374 marks: &Marks,
2375) {
2376 core_ctx.counters().port_unreachable.increment();
2377
2378 send_icmpv6_dest_unreachable(
2379 core_ctx,
2380 bindings_ctx,
2381 Some(device),
2382 frame_dst,
2383 src_ip,
2384 dst_ip,
2385 Icmpv6DestUnreachableCode::PortUnreachable,
2386 original_packet,
2387 marks,
2388 );
2389}
2390
2391pub(crate) fn send_icmpv4_net_unreachable<
2403 B: BufferMut,
2404 BC: IcmpBindingsContext,
2405 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2406>(
2407 core_ctx: &mut CC,
2408 bindings_ctx: &mut BC,
2409 device: &CC::DeviceId,
2410 frame_dst: Option<FrameDestination>,
2411 src_ip: SocketIpAddr<Ipv4Addr>,
2412 dst_ip: SocketIpAddr<Ipv4Addr>,
2413 proto: Ipv4Proto,
2414 original_packet: B,
2415 header_len: usize,
2416 fragment_type: Ipv4FragmentType,
2417 marks: &Marks,
2418) {
2419 core_ctx.counters().net_unreachable.increment();
2420
2421 if is_icmp_error_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..]) {
2424 return;
2425 }
2426
2427 send_icmpv4_dest_unreachable(
2428 core_ctx,
2429 bindings_ctx,
2430 Some(device),
2431 frame_dst,
2432 src_ip,
2433 dst_ip,
2434 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
2435 original_packet,
2436 header_len,
2437 fragment_type,
2438 marks,
2439 );
2440}
2441
2442pub(crate) fn send_icmpv6_net_unreachable<
2453 B: BufferMut,
2454 BC: IcmpBindingsContext,
2455 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2456>(
2457 core_ctx: &mut CC,
2458 bindings_ctx: &mut BC,
2459 device: &CC::DeviceId,
2460 frame_dst: Option<FrameDestination>,
2461 src_ip: SocketIpAddr<Ipv6Addr>,
2462 dst_ip: SocketIpAddr<Ipv6Addr>,
2463 proto: Ipv6Proto,
2464 original_packet: B,
2465 header_len: usize,
2466 marks: &Marks,
2467) {
2468 core_ctx.counters().net_unreachable.increment();
2469
2470 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2473 return;
2474 }
2475
2476 send_icmpv6_dest_unreachable(
2477 core_ctx,
2478 bindings_ctx,
2479 Some(device),
2480 frame_dst,
2481 src_ip,
2482 dst_ip,
2483 Icmpv6DestUnreachableCode::NoRoute,
2484 original_packet,
2485 marks,
2486 );
2487}
2488
2489pub(crate) fn send_icmpv4_ttl_expired<
2501 B: BufferMut,
2502 BC: IcmpBindingsContext,
2503 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2504>(
2505 core_ctx: &mut CC,
2506 bindings_ctx: &mut BC,
2507 device: &CC::DeviceId,
2508 frame_dst: Option<FrameDestination>,
2509 src_ip: SocketIpAddr<Ipv4Addr>,
2510 dst_ip: SocketIpAddr<Ipv4Addr>,
2511 proto: Ipv4Proto,
2512 original_packet: B,
2513 header_len: usize,
2514 fragment_type: Ipv4FragmentType,
2515 marks: &Marks,
2516) {
2517 core_ctx.counters().ttl_expired.increment();
2518
2519 if is_icmp_error_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..]) {
2522 return;
2523 }
2524
2525 send_icmpv4_error_message(
2526 core_ctx,
2527 bindings_ctx,
2528 Some(device),
2529 frame_dst,
2530 src_ip,
2531 dst_ip,
2532 Icmpv4ErrorMessage::TimeExceeded {
2533 message: IcmpTimeExceeded::default(),
2534 code: Icmpv4TimeExceededCode::TtlExpired,
2535 },
2536 original_packet,
2537 header_len,
2538 fragment_type,
2539 marks,
2540 )
2541}
2542
2543pub(crate) fn send_icmpv6_ttl_expired<
2554 B: BufferMut,
2555 BC: IcmpBindingsContext,
2556 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2557>(
2558 core_ctx: &mut CC,
2559 bindings_ctx: &mut BC,
2560 device: &CC::DeviceId,
2561 frame_dst: Option<FrameDestination>,
2562 src_ip: SocketIpAddr<Ipv6Addr>,
2563 dst_ip: SocketIpAddr<Ipv6Addr>,
2564 proto: Ipv6Proto,
2565 original_packet: B,
2566 header_len: usize,
2567 marks: &Marks,
2568) {
2569 core_ctx.counters().ttl_expired.increment();
2570
2571 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2574 return;
2575 }
2576
2577 send_icmpv6_error_message(
2578 core_ctx,
2579 bindings_ctx,
2580 Some(device),
2581 frame_dst,
2582 src_ip,
2583 dst_ip,
2584 Icmpv6ErrorMessage::TimeExceeded {
2585 message: IcmpTimeExceeded::default(),
2586 code: Icmpv6TimeExceededCode::HopLimitExceeded,
2587 },
2588 original_packet,
2589 false, marks,
2591 )
2592}
2593
2594pub(crate) fn send_icmpv6_packet_too_big<
2604 B: BufferMut,
2605 BC: IcmpBindingsContext,
2606 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2607>(
2608 core_ctx: &mut CC,
2609 bindings_ctx: &mut BC,
2610 device: &CC::DeviceId,
2611 frame_dst: Option<FrameDestination>,
2612 src_ip: SocketIpAddr<Ipv6Addr>,
2613 dst_ip: SocketIpAddr<Ipv6Addr>,
2614 proto: Ipv6Proto,
2615 mtu: Mtu,
2616 original_packet: B,
2617 header_len: usize,
2618 marks: &Marks,
2619) {
2620 core_ctx.counters().packet_too_big.increment();
2621 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2624 return;
2625 }
2626
2627 send_icmpv6_error_message(
2628 core_ctx,
2629 bindings_ctx,
2630 Some(device),
2631 frame_dst,
2632 src_ip,
2633 dst_ip,
2634 Icmpv6ErrorMessage::PacketTooBig {
2635 message: Icmpv6PacketTooBig::new(mtu.into()),
2636 code: IcmpZeroCode,
2637 },
2638 original_packet,
2639 true, marks,
2659 )
2660}
2661
2662pub(crate) fn send_icmpv4_parameter_problem<
2663 B: BufferMut,
2664 BC: IcmpBindingsContext,
2665 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2666>(
2667 core_ctx: &mut CC,
2668 bindings_ctx: &mut BC,
2669 device: &CC::DeviceId,
2670 frame_dst: Option<FrameDestination>,
2671 src_ip: SocketIpAddr<Ipv4Addr>,
2672 dst_ip: SocketIpAddr<Ipv4Addr>,
2673 code: Icmpv4ParameterProblemCode,
2674 parameter_problem: Icmpv4ParameterProblem,
2675 original_packet: B,
2676 header_len: usize,
2677 fragment_type: Ipv4FragmentType,
2678 marks: &Marks,
2679) {
2680 core_ctx.counters().parameter_problem.increment();
2681
2682 send_icmpv4_error_message(
2683 core_ctx,
2684 bindings_ctx,
2685 Some(device),
2686 frame_dst,
2687 src_ip,
2688 dst_ip,
2689 Icmpv4ErrorMessage::ParameterProblem { message: parameter_problem, code },
2690 original_packet,
2691 header_len,
2692 fragment_type,
2693 marks,
2694 )
2695}
2696
2697pub(crate) fn send_icmpv6_parameter_problem<
2708 B: BufferMut,
2709 BC: IcmpBindingsContext,
2710 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2711>(
2712 core_ctx: &mut CC,
2713 bindings_ctx: &mut BC,
2714 device: &CC::DeviceId,
2715 frame_dst: Option<FrameDestination>,
2716 src_ip: SocketIpAddr<Ipv6Addr>,
2717 dst_ip: SocketIpAddr<Ipv6Addr>,
2718 code: Icmpv6ParameterProblemCode,
2719 parameter_problem: Icmpv6ParameterProblem,
2720 original_packet: B,
2721 allow_dst_multicast: bool,
2722 marks: &Marks,
2723) {
2724 assert!(!allow_dst_multicast || code == Icmpv6ParameterProblemCode::UnrecognizedIpv6Option);
2729
2730 core_ctx.counters().parameter_problem.increment();
2731
2732 send_icmpv6_error_message(
2733 core_ctx,
2734 bindings_ctx,
2735 Some(device),
2736 frame_dst,
2737 src_ip,
2738 dst_ip,
2739 Icmpv6ErrorMessage::ParameterProblem { message: parameter_problem, code },
2740 original_packet,
2741 allow_dst_multicast,
2742 marks,
2743 )
2744}
2745
2746fn send_icmpv4_dest_unreachable<
2747 B: BufferMut,
2748 BC: IcmpBindingsContext,
2749 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2750>(
2751 core_ctx: &mut CC,
2752 bindings_ctx: &mut BC,
2753 device: Option<&CC::DeviceId>,
2754 frame_dst: Option<FrameDestination>,
2755 src_ip: SocketIpAddr<Ipv4Addr>,
2756 dst_ip: SocketIpAddr<Ipv4Addr>,
2757 code: Icmpv4DestUnreachableCode,
2758 original_packet: B,
2759 header_len: usize,
2760 fragment_type: Ipv4FragmentType,
2761 marks: &Marks,
2762) {
2763 core_ctx.counters().dest_unreachable.increment();
2764 send_icmpv4_error_message(
2765 core_ctx,
2766 bindings_ctx,
2767 device,
2768 frame_dst,
2769 src_ip,
2770 dst_ip,
2771 Icmpv4ErrorMessage::DestUnreachable { message: IcmpDestUnreachable::default(), code },
2772 original_packet,
2773 header_len,
2774 fragment_type,
2775 marks,
2776 )
2777}
2778
2779fn send_icmpv6_dest_unreachable<
2780 B: BufferMut,
2781 BC: IcmpBindingsContext,
2782 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2783>(
2784 core_ctx: &mut CC,
2785 bindings_ctx: &mut BC,
2786 device: Option<&CC::DeviceId>,
2787 frame_dst: Option<FrameDestination>,
2788 src_ip: SocketIpAddr<Ipv6Addr>,
2789 dst_ip: SocketIpAddr<Ipv6Addr>,
2790 code: Icmpv6DestUnreachableCode,
2791 original_packet: B,
2792 marks: &Marks,
2793) {
2794 send_icmpv6_error_message(
2795 core_ctx,
2796 bindings_ctx,
2797 device,
2798 frame_dst,
2799 src_ip,
2800 dst_ip,
2801 Icmpv6ErrorMessage::DestUnreachable { message: IcmpDestUnreachable::default(), code },
2802 original_packet,
2803 false, marks,
2805 )
2806}
2807
2808#[allow(missing_docs)]
2811enum Icmpv4ErrorMessage {
2812 TimeExceeded {
2813 message: IcmpTimeExceeded,
2814 code: <IcmpTimeExceeded as IcmpMessage<Ipv4>>::Code,
2815 },
2816 ParameterProblem {
2817 message: Icmpv4ParameterProblem,
2818 code: <Icmpv4ParameterProblem as IcmpMessage<Ipv4>>::Code,
2819 },
2820 DestUnreachable {
2821 message: IcmpDestUnreachable,
2822 code: <IcmpDestUnreachable as IcmpMessage<Ipv4>>::Code,
2823 },
2824}
2825
2826fn send_icmpv4_error_message<
2827 B: BufferMut,
2828 BC: IcmpBindingsContext,
2829 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2830>(
2831 core_ctx: &mut CC,
2832 bindings_ctx: &mut BC,
2833 device: Option<&CC::DeviceId>,
2834 frame_dst: Option<FrameDestination>,
2835 original_src_ip: SocketIpAddr<Ipv4Addr>,
2836 original_dst_ip: SocketIpAddr<Ipv4Addr>,
2837 message: Icmpv4ErrorMessage,
2838 mut original_packet: B,
2839 header_len: usize,
2840 fragment_type: Ipv4FragmentType,
2841 marks: &Marks,
2842) {
2843 if !should_send_icmpv4_error(
2847 frame_dst,
2848 original_src_ip.into(),
2849 original_dst_ip.into(),
2850 fragment_type,
2851 ) {
2852 return;
2853 }
2854
2855 original_packet.shrink_back_to(header_len + 64);
2858
2859 let tx_metadata: BC::TxMetadata = Default::default();
2860
2861 macro_rules! send {
2862 ($message:expr, $code:expr) => {{
2863 let _ = try_send_error!(
2866 core_ctx,
2867 bindings_ctx,
2868 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2869 bindings_ctx,
2870 IpSocketArgs {
2871 device: device.map(EitherDeviceId::Strong),
2872 local_ip: None,
2873 remote_ip: original_src_ip,
2874 proto: Ipv4Proto::Icmp,
2875 options: &WithMarks(marks),
2876 },
2877 tx_metadata,
2878 |local_ip| {
2879 IcmpPacketBuilder::<Ipv4, _>::new(
2880 local_ip.addr(),
2881 original_src_ip.addr(),
2882 $code,
2883 $message,
2884 )
2885 .wrap_body(original_packet)
2886 },
2887 )
2888 );
2889 }};
2890 }
2891
2892 match message {
2893 Icmpv4ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2894 Icmpv4ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2895 Icmpv4ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2896 }
2897}
2898
2899#[allow(missing_docs)]
2902enum Icmpv6ErrorMessage {
2903 TimeExceeded {
2904 message: IcmpTimeExceeded,
2905 code: <IcmpTimeExceeded as IcmpMessage<Ipv6>>::Code,
2906 },
2907 PacketTooBig {
2908 message: Icmpv6PacketTooBig,
2909 code: <Icmpv6PacketTooBig as IcmpMessage<Ipv6>>::Code,
2910 },
2911 ParameterProblem {
2912 message: Icmpv6ParameterProblem,
2913 code: <Icmpv6ParameterProblem as IcmpMessage<Ipv6>>::Code,
2914 },
2915 DestUnreachable {
2916 message: IcmpDestUnreachable,
2917 code: <IcmpDestUnreachable as IcmpMessage<Ipv6>>::Code,
2918 },
2919}
2920
2921fn send_icmpv6_error_message<
2922 B: BufferMut,
2923 BC: IcmpBindingsContext,
2924 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2925>(
2926 core_ctx: &mut CC,
2927 bindings_ctx: &mut BC,
2928 device: Option<&CC::DeviceId>,
2929 frame_dst: Option<FrameDestination>,
2930 original_src_ip: SocketIpAddr<Ipv6Addr>,
2931 original_dst_ip: SocketIpAddr<Ipv6Addr>,
2932 message: Icmpv6ErrorMessage,
2933 original_packet: B,
2934 allow_dst_multicast: bool,
2935 marks: &Marks,
2936) {
2937 if !should_send_icmpv6_error(
2941 frame_dst,
2942 original_src_ip.into(),
2943 original_dst_ip.into(),
2944 allow_dst_multicast,
2945 ) {
2946 return;
2947 }
2948
2949 struct Icmpv6ErrorOptions<'a>(&'a Marks);
2950 impl<'a> OptionDelegationMarker for Icmpv6ErrorOptions<'a> {}
2951 impl<'a> DelegatedSendOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2952 fn mtu(&self) -> Mtu {
2953 Ipv6::MINIMUM_LINK_MTU
2954 }
2955 }
2956 impl<'a> DelegatedRouteResolutionOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2957 fn marks(&self) -> &Marks {
2958 let Self(marks) = self;
2959 marks
2960 }
2961 }
2962
2963 let tx_metadata: BC::TxMetadata = Default::default();
2964
2965 macro_rules! send {
2966 ($message:expr, $code:expr) => {{
2967 let _ = try_send_error!(
2970 core_ctx,
2971 bindings_ctx,
2972 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2973 bindings_ctx,
2974 IpSocketArgs {
2975 device: device.map(EitherDeviceId::Strong),
2976 local_ip: None,
2977 remote_ip: original_src_ip,
2978 proto: Ipv6Proto::Icmpv6,
2979 options: &Icmpv6ErrorOptions(marks),
2980 },
2981 tx_metadata,
2982 |local_ip| {
2983 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
2984 local_ip.addr(),
2985 original_src_ip.addr(),
2986 $code,
2987 $message,
2988 );
2989
2990 icmp_builder.wrap_body(TruncatingSerializer::new(
2993 original_packet,
2994 TruncateDirection::DiscardBack,
2995 ))
2996 },
2997 )
2998 );
2999 }};
3000 }
3001
3002 match message {
3003 Icmpv6ErrorMessage::TimeExceeded { message, code } => send!(message, code),
3004 Icmpv6ErrorMessage::PacketTooBig { message, code } => send!(message, code),
3005 Icmpv6ErrorMessage::ParameterProblem { message, code } => send!(message, code),
3006 Icmpv6ErrorMessage::DestUnreachable { message, code } => send!(message, code),
3007 }
3008}
3009
3010fn should_send_icmpv4_error(
3028 frame_dst: Option<FrameDestination>,
3029 src_ip: SpecifiedAddr<Ipv4Addr>,
3030 dst_ip: SpecifiedAddr<Ipv4Addr>,
3031 fragment_type: Ipv4FragmentType,
3032) -> bool {
3033 fragment_type == Ipv4FragmentType::InitialFragment
3053 && !(dst_ip.is_multicast()
3054 || dst_ip.is_limited_broadcast()
3055 || frame_dst.is_some_and(|dst| dst.is_broadcast())
3056 || src_ip.is_loopback()
3057 || src_ip.is_limited_broadcast()
3058 || src_ip.is_multicast()
3059 || src_ip.is_class_e())
3060}
3061
3062fn should_send_icmpv6_error(
3089 frame_dst: Option<FrameDestination>,
3090 src_ip: SpecifiedAddr<Ipv6Addr>,
3091 dst_ip: SpecifiedAddr<Ipv6Addr>,
3092 allow_dst_multicast: bool,
3093) -> bool {
3094 let multicast_frame_dst = match frame_dst {
3097 Some(FrameDestination::Individual { local: _ }) | None => false,
3098 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
3099 };
3100 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
3101 return false;
3102 }
3103 if src_ip.is_loopback() || src_ip.is_multicast() {
3104 return false;
3105 }
3106 true
3107}
3108
3109fn is_icmp_error_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
3121 proto == I::ICMP_IP_PROTO
3122 && peek_message_type::<I::IcmpMessageType>(buf).map(IcmpMessageType::is_err).unwrap_or(true)
3123}
3124
3125#[cfg(any(test, feature = "testutils"))]
3127pub(crate) mod testutil {
3128 use alloc::vec::Vec;
3129 use net_types::ethernet::Mac;
3130 use net_types::ip::{Ipv6, Ipv6Addr};
3131 use packet::{Buf, InnerPacketBuilder as _, Serializer as _};
3132 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
3133 use packet_formats::icmp::ndp::{
3134 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
3135 };
3136 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
3137 use packet_formats::ip::Ipv6Proto;
3138 use packet_formats::ipv6::Ipv6PacketBuilder;
3139
3140 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
3141
3142 pub fn neighbor_advertisement_ip_packet(
3145 src_ip: Ipv6Addr,
3146 dst_ip: Ipv6Addr,
3147 router_flag: bool,
3148 solicited_flag: bool,
3149 override_flag: bool,
3150 mac: Mac,
3151 ) -> Buf<Vec<u8>> {
3152 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
3153 .into_serializer()
3154 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3155 src_ip,
3156 dst_ip,
3157 IcmpZeroCode,
3158 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
3159 ))
3160 .wrap_in(Ipv6PacketBuilder::new(
3161 src_ip,
3162 dst_ip,
3163 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
3164 Ipv6Proto::Icmpv6,
3165 ))
3166 .serialize_vec_outer()
3167 .unwrap()
3168 .unwrap_b()
3169 }
3170
3171 pub fn neighbor_solicitation_ip_packet(
3174 src_ip: Ipv6Addr,
3175 dst_ip: Ipv6Addr,
3176 target_addr: Ipv6Addr,
3177 mac: Mac,
3178 ) -> Buf<Vec<u8>> {
3179 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
3180 .into_serializer()
3181 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3182 src_ip,
3183 dst_ip,
3184 IcmpZeroCode,
3185 NeighborSolicitation::new(target_addr),
3186 ))
3187 .wrap_in(Ipv6PacketBuilder::new(
3188 src_ip,
3189 dst_ip,
3190 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
3191 Ipv6Proto::Icmpv6,
3192 ))
3193 .serialize_vec_outer()
3194 .unwrap()
3195 .unwrap_b()
3196 }
3197}
3198
3199#[cfg(test)]
3200mod tests {
3201 use alloc::vec;
3202 use alloc::vec::Vec;
3203 use packet_formats::icmp::ndp::options::NdpNonce;
3204
3205 use core::fmt::Debug;
3206 use core::time::Duration;
3207
3208 use net_types::ip::Subnet;
3209 use netstack3_base::testutil::{
3210 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId,
3211 TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt, set_logger_for_test,
3212 };
3213 use netstack3_base::{CtxPair, Uninstantiable};
3214 use netstack3_filter::TransportPacketSerializer;
3215 use packet::{Buf, EmptyBuf};
3216 use packet_formats::icmp::mld::MldPacket;
3217 use packet_formats::ip::IpProto;
3218 use packet_formats::utils::NonZeroDuration;
3219
3220 use super::*;
3221 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
3222 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
3223 use crate::internal::socket::{
3224 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
3225 };
3226 use crate::socket::RouteResolutionOptions;
3227
3228 type InnerIpSocketCtx<I> = FakeCoreCtx<
3230 FakeIpSocketCtx<I, FakeDeviceId>,
3231 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
3232 FakeDeviceId,
3233 >;
3234
3235 pub(super) struct FakeIcmpCoreCtx<I: IpExt> {
3237 ip_socket_ctx: InnerIpSocketCtx<I>,
3238 icmp: FakeIcmpCoreCtxState<I>,
3239 }
3240
3241 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
3243 (),
3244 RouterAdvertisementEvent<FakeDeviceId>,
3245 FakeIcmpBindingsCtxState<I>,
3246 (),
3247 >;
3248
3249 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
3253
3254 pub(super) struct FakeIcmpCoreCtxState<I: IpExt> {
3255 error_send_bucket: TokenBucket<FakeInstant>,
3256 receive_icmp_error: Vec<I::ErrorCode>,
3257 rx_counters: IcmpRxCounters<I>,
3258 tx_counters: IcmpTxCounters<I>,
3259 ndp_counters: NdpCounters,
3260 }
3261
3262 impl<I: TestIpExt + IpExt> FakeIcmpCoreCtx<I> {
3263 fn with_errors_per_second(errors_per_second: u64) -> Self {
3264 Self {
3265 icmp: FakeIcmpCoreCtxState {
3266 error_send_bucket: TokenBucket::new(errors_per_second),
3267 receive_icmp_error: Default::default(),
3268 rx_counters: Default::default(),
3269 tx_counters: Default::default(),
3270 ndp_counters: Default::default(),
3271 },
3272 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
3273 core::iter::once(FakeDeviceConfig {
3274 device: FakeDeviceId,
3275 local_ips: vec![I::TEST_ADDRS.local_ip],
3276 remote_ips: vec![I::TEST_ADDRS.remote_ip],
3277 }),
3278 )),
3279 }
3280 }
3281 }
3282
3283 impl<I: TestIpExt + IpExt> Default for FakeIcmpCoreCtx<I> {
3284 fn default() -> Self {
3285 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
3286 }
3287 }
3288
3289 impl<I: IpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
3290 type DeviceId = FakeDeviceId;
3291 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
3292 }
3293
3294 impl<I: IpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
3295 impl<I: IpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
3296
3297 impl<I: IpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
3298 fn counters(&self) -> &IcmpRxCounters<I> {
3299 &self.icmp.rx_counters
3300 }
3301 }
3302
3303 impl<I: IpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
3304 fn counters(&self) -> &IcmpTxCounters<I> {
3305 &self.icmp.tx_counters
3306 }
3307 }
3308
3309 impl<I: IpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
3310 fn counters(&self) -> &NdpCounters {
3311 &self.icmp.ndp_counters
3312 }
3313 }
3314
3315 pub enum FakeEchoIpTransportContext {}
3316
3317 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
3318
3319 impl<I: IpExt> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
3320 for FakeEchoIpTransportContext
3321 {
3322 fn receive_icmp_error(
3323 core_ctx: &mut FakeIcmpCoreCtx<I>,
3324 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3325 _device: &FakeDeviceId,
3326 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3327 _original_dst_ip: SpecifiedAddr<I::Addr>,
3328 _original_body: &[u8],
3329 _err: I::ErrorCode,
3330 ) {
3331 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
3332 }
3333
3334 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
3335 _core_ctx: &mut FakeIcmpCoreCtx<I>,
3336 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3337 _device: &FakeDeviceId,
3338 _src_ip: I::RecvSrcAddr,
3339 _dst_ip: SpecifiedAddr<I::Addr>,
3340 _buffer: B,
3341 _info: &LocalDeliveryPacketInfo<I, H>,
3342 ) -> Result<(), (B, TransportReceiveError)> {
3343 unimplemented!()
3344 }
3345 }
3346
3347 impl<I: IpExt + FilterIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3348 type EchoTransportContext = FakeEchoIpTransportContext;
3349
3350 fn receive_icmp_error(
3351 &mut self,
3352 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3353 device: &Self::DeviceId,
3354 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3355 original_dst_ip: SpecifiedAddr<I::Addr>,
3356 original_proto: I::Proto,
3357 original_body: &[u8],
3358 err: I::ErrorCode,
3359 ) {
3360 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
3361 self.icmp.receive_icmp_error.push(err);
3362 if original_proto == I::ICMP_IP_PROTO {
3363 receive_ip_transport_icmp_error(
3364 self,
3365 bindings_ctx,
3366 device,
3367 original_src_ip,
3368 original_dst_ip,
3369 original_body,
3370 err,
3371 )
3372 }
3373 }
3374
3375 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
3376 &mut self,
3377 cb: F,
3378 ) -> O {
3379 cb(&mut self.icmp.error_send_bucket)
3380 }
3381 }
3382
3383 #[test]
3384 fn test_should_send_icmpv4_error() {
3385 let src_ip = TEST_ADDRS_V4.local_ip;
3386 let dst_ip = TEST_ADDRS_V4.remote_ip;
3387 let frame_dst = FrameDestination::Individual { local: true };
3388 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
3389 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
3390
3391 assert!(should_send_icmpv4_error(
3393 Some(frame_dst),
3394 src_ip,
3395 dst_ip,
3396 Ipv4FragmentType::InitialFragment
3397 ));
3398 assert!(should_send_icmpv4_error(None, src_ip, dst_ip, Ipv4FragmentType::InitialFragment));
3399 assert!(!should_send_icmpv4_error(
3400 Some(frame_dst),
3401 src_ip,
3402 dst_ip,
3403 Ipv4FragmentType::NonInitialFragment
3404 ));
3405
3406 assert!(!should_send_icmpv4_error(
3408 Some(frame_dst),
3409 src_ip,
3410 Ipv4::LIMITED_BROADCAST_ADDRESS,
3411 Ipv4FragmentType::InitialFragment
3412 ));
3413 assert!(!should_send_icmpv4_error(
3414 Some(frame_dst),
3415 src_ip,
3416 Ipv4::LIMITED_BROADCAST_ADDRESS,
3417 Ipv4FragmentType::NonInitialFragment
3418 ));
3419
3420 assert!(!should_send_icmpv4_error(
3422 Some(frame_dst),
3423 src_ip,
3424 multicast_ip_1,
3425 Ipv4FragmentType::InitialFragment
3426 ));
3427 assert!(!should_send_icmpv4_error(
3428 Some(frame_dst),
3429 src_ip,
3430 multicast_ip_1,
3431 Ipv4FragmentType::NonInitialFragment
3432 ));
3433
3434 assert!(!should_send_icmpv4_error(
3436 Some(FrameDestination::Broadcast),
3437 src_ip,
3438 dst_ip,
3439 Ipv4FragmentType::InitialFragment
3440 ));
3441 assert!(!should_send_icmpv4_error(
3442 Some(FrameDestination::Broadcast),
3443 src_ip,
3444 dst_ip,
3445 Ipv4FragmentType::NonInitialFragment
3446 ));
3447
3448 assert!(!should_send_icmpv4_error(
3450 Some(frame_dst),
3451 Ipv4::LOOPBACK_ADDRESS,
3452 dst_ip,
3453 Ipv4FragmentType::InitialFragment
3454 ));
3455 assert!(!should_send_icmpv4_error(
3456 Some(frame_dst),
3457 Ipv4::LOOPBACK_ADDRESS,
3458 dst_ip,
3459 Ipv4FragmentType::NonInitialFragment
3460 ));
3461
3462 assert!(!should_send_icmpv4_error(
3464 Some(frame_dst),
3465 Ipv4::LIMITED_BROADCAST_ADDRESS,
3466 dst_ip,
3467 Ipv4FragmentType::InitialFragment
3468 ));
3469 assert!(!should_send_icmpv4_error(
3470 Some(frame_dst),
3471 Ipv4::LIMITED_BROADCAST_ADDRESS,
3472 dst_ip,
3473 Ipv4FragmentType::NonInitialFragment
3474 ));
3475
3476 assert!(!should_send_icmpv4_error(
3478 Some(frame_dst),
3479 multicast_ip_2,
3480 dst_ip,
3481 Ipv4FragmentType::InitialFragment
3482 ));
3483 assert!(!should_send_icmpv4_error(
3484 Some(frame_dst),
3485 multicast_ip_2,
3486 dst_ip,
3487 Ipv4FragmentType::NonInitialFragment
3488 ));
3489
3490 assert!(!should_send_icmpv4_error(
3492 Some(frame_dst),
3493 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
3494 dst_ip,
3495 Ipv4FragmentType::InitialFragment
3496 ));
3497 assert!(!should_send_icmpv4_error(
3498 Some(frame_dst),
3499 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
3500 dst_ip,
3501 Ipv4FragmentType::NonInitialFragment
3502 ));
3503 }
3504
3505 #[test]
3506 fn test_should_send_icmpv6_error() {
3507 let src_ip = TEST_ADDRS_V6.local_ip;
3508 let dst_ip = TEST_ADDRS_V6.remote_ip;
3509 let frame_dst = FrameDestination::Individual { local: true };
3510 let multicast_ip_1 =
3511 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
3512 let multicast_ip_2 =
3513 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
3514
3515 assert!(should_send_icmpv6_error(
3517 Some(frame_dst),
3518 src_ip,
3519 dst_ip,
3520 false ));
3522 assert!(should_send_icmpv6_error(
3523 None, src_ip, dst_ip, false ));
3525 assert!(should_send_icmpv6_error(
3526 Some(frame_dst),
3527 src_ip,
3528 dst_ip,
3529 true ));
3531
3532 assert!(!should_send_icmpv6_error(
3535 Some(frame_dst),
3536 src_ip,
3537 multicast_ip_1,
3538 false ));
3540 assert!(should_send_icmpv6_error(
3541 Some(frame_dst),
3542 src_ip,
3543 multicast_ip_1,
3544 true ));
3546
3547 assert!(!should_send_icmpv6_error(
3550 Some(FrameDestination::Broadcast),
3551 src_ip,
3552 dst_ip,
3553 false ));
3555 assert!(should_send_icmpv6_error(
3556 Some(FrameDestination::Broadcast),
3557 src_ip,
3558 dst_ip,
3559 true ));
3561
3562 assert!(!should_send_icmpv6_error(
3564 Some(frame_dst),
3565 Ipv6::LOOPBACK_ADDRESS,
3566 dst_ip,
3567 false ));
3569 assert!(!should_send_icmpv6_error(
3570 Some(frame_dst),
3571 Ipv6::LOOPBACK_ADDRESS,
3572 dst_ip,
3573 true ));
3575
3576 assert!(!should_send_icmpv6_error(
3578 Some(frame_dst),
3579 multicast_ip_2,
3580 dst_ip,
3581 false ));
3583 assert!(!should_send_icmpv6_error(
3584 Some(frame_dst),
3585 multicast_ip_2,
3586 dst_ip,
3587 true ));
3589
3590 assert!(!should_send_icmpv6_error(
3593 Some(FrameDestination::Broadcast),
3594 multicast_ip_2,
3595 dst_ip,
3596 false ));
3598 assert!(!should_send_icmpv6_error(
3599 Some(FrameDestination::Broadcast),
3600 multicast_ip_2,
3601 dst_ip,
3602 true ));
3604 assert!(!should_send_icmpv6_error(
3605 Some(frame_dst),
3606 multicast_ip_2,
3607 multicast_ip_1,
3608 false ));
3610 assert!(!should_send_icmpv6_error(
3611 Some(frame_dst),
3612 multicast_ip_2,
3613 multicast_ip_1,
3614 true ));
3616 }
3617
3618 #[derive(Default)]
3625 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3626 _marker: core::marker::PhantomData<I>,
3627 }
3628
3629 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3630 fn should_send_timestamp_reply(&self) -> bool {
3631 false
3632 }
3633 }
3634 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3635 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3636
3637 impl<I: IpExt + FilterIpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3638 fn new_ip_socket<O>(
3639 &mut self,
3640 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3641 args: IpSocketArgs<'_, Self::DeviceId, I, O>,
3642 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3643 where
3644 O: RouteResolutionOptions<I>,
3645 {
3646 self.ip_socket_ctx.new_ip_socket(bindings_ctx, args)
3647 }
3648
3649 fn send_ip_packet<S, O>(
3650 &mut self,
3651 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3652 socket: &IpSock<I, Self::WeakDeviceId>,
3653 body: S,
3654 options: &O,
3655 tx_meta: FakeTxMetadata,
3656 ) -> Result<(), IpSockSendError>
3657 where
3658 S: TransportPacketSerializer<I>,
3659 S::Buffer: BufferMut,
3660 O: SendOptions<I> + RouteResolutionOptions<I>,
3661 {
3662 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3663 }
3664
3665 fn confirm_reachable<O>(
3666 &mut self,
3667 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3668 socket: &IpSock<I, Self::WeakDeviceId>,
3669 options: &O,
3670 ) where
3671 O: RouteResolutionOptions<I>,
3672 {
3673 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3674 }
3675 }
3676
3677 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3678 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3679 unimplemented!()
3680 }
3681
3682 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3683 unreachable!()
3684 }
3685
3686 fn handle_received_dad_packet(
3687 &mut self,
3688 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3689 _device_id: &Self::DeviceId,
3690 _addr: SpecifiedAddr<Ipv6Addr>,
3691 _probe_data: Option<NdpNonce<&'_ [u8]>>,
3692 ) -> Option<IpAddressState> {
3693 unimplemented!()
3694 }
3695 }
3696
3697 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3698 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3699 cb(&())
3700 }
3701
3702 fn get_local_addr_for_remote(
3703 &mut self,
3704 _device_id: &Self::DeviceId,
3705 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3706 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3707 unimplemented!()
3708 }
3709
3710 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3711 unimplemented!()
3712 }
3713 }
3714
3715 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3716 fn address_status_for_device(
3717 &mut self,
3718 _addr: SpecifiedAddr<Ipv6Addr>,
3719 _device_id: &Self::DeviceId,
3720 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3721 unimplemented!()
3722 }
3723 }
3724
3725 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3726 type LinkLayerAddr = Uninstantiable;
3727
3728 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3729 unimplemented!()
3730 }
3731
3732 fn set_discovered_retrans_timer(
3733 &mut self,
3734 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3735 _device_id: &Self::DeviceId,
3736 _retrans_timer: NonZeroDuration,
3737 ) {
3738 unimplemented!()
3739 }
3740
3741 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3742 unimplemented!()
3743 }
3744
3745 fn update_discovered_ipv6_route(
3746 &mut self,
3747 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3748 _device_id: &Self::DeviceId,
3749 _route: Ipv6DiscoveredRoute,
3750 _lifetime: Option<NonZeroNdpLifetime>,
3751 ) {
3752 unimplemented!()
3753 }
3754
3755 fn apply_slaac_update(
3756 &mut self,
3757 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3758 _device_id: &Self::DeviceId,
3759 _subnet: Subnet<Ipv6Addr>,
3760 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3761 _valid_lifetime: Option<NonZeroNdpLifetime>,
3762 ) {
3763 unimplemented!()
3764 }
3765
3766 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3767 &mut self,
3768 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3769 _device: &FakeDeviceId,
3770 _src_ip: Ipv6SourceAddr,
3771 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3772 _packet: MldPacket<B>,
3773 _header_info: &H,
3774 ) {
3775 unimplemented!()
3776 }
3777 }
3778
3779 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3780 fn send_ip_packet_from_device<S>(
3781 &mut self,
3782 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3783 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3784 _body: S,
3785 ) -> Result<(), IpSendFrameError<S>> {
3786 unimplemented!()
3787 }
3788
3789 fn send_ip_frame<S>(
3790 &mut self,
3791 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3792 _device: &Self::DeviceId,
3793 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3794 _body: S,
3795 ) -> Result<(), IpSendFrameError<S>>
3796 where
3797 S: Serializer,
3798 S::Buffer: BufferMut,
3799 {
3800 unimplemented!()
3801 }
3802 }
3803
3804 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3805 fn handle_neighbor_probe(
3806 &mut self,
3807 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3808 _device_id: &Self::DeviceId,
3809 _neighbor: SpecifiedAddr<Ipv6Addr>,
3810 _link_addr: &[u8],
3811 ) {
3812 unimplemented!()
3813 }
3814
3815 fn handle_neighbor_confirmation(
3816 &mut self,
3817 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3818 _device_id: &Self::DeviceId,
3819 _neighbor: SpecifiedAddr<Ipv6Addr>,
3820 _link_addr: Option<&[u8]>,
3821 _flags: ConfirmationFlags,
3822 ) {
3823 unimplemented!()
3824 }
3825
3826 fn flush_neighbor_table(
3827 &mut self,
3828 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3829 _device_id: &Self::DeviceId,
3830 ) {
3831 unimplemented!()
3832 }
3833 }
3834
3835 #[test]
3836 fn test_receive_icmpv4_error() {
3837 const ICMP_ID: u16 = 0x0F;
3840 const SEQ_NUM: u16 = 0xF0;
3841
3842 fn test_receive_icmpv4_error_helper<
3857 C: Debug,
3858 M: IcmpMessage<Ipv4, Code = C> + Debug,
3859 F: Fn(&FakeIcmpCtx<Ipv4>),
3860 >(
3861 original_packet: &mut [u8],
3862 code: C,
3863 msg: M,
3864 f: F,
3865 ) {
3866 set_logger_for_test();
3867
3868 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3869
3870 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3871 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3872 core_ctx,
3873 bindings_ctx,
3874 &FakeDeviceId,
3875 Ipv4SourceAddr::new(*TEST_ADDRS_V4.remote_ip).unwrap(),
3876 TEST_ADDRS_V4.local_ip,
3877 IcmpPacketBuilder::new(TEST_ADDRS_V4.remote_ip, TEST_ADDRS_V4.local_ip, code, msg)
3878 .wrap_body(Buf::new(original_packet, ..))
3879 .serialize_vec_outer()
3880 .unwrap(),
3881 &LocalDeliveryPacketInfo::default(),
3882 )
3883 .unwrap();
3884 f(&ctx);
3885 }
3886 let mut buffer = EmptyBuf
3899 .wrap_in(IcmpPacketBuilder::<Ipv4, _>::new(
3900 TEST_ADDRS_V4.local_ip,
3901 TEST_ADDRS_V4.remote_ip,
3902 IcmpZeroCode,
3903 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3904 ))
3905 .wrap_in(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3906 TEST_ADDRS_V4.local_ip,
3907 TEST_ADDRS_V4.remote_ip,
3908 64,
3909 Ipv4Proto::Icmp,
3910 ))
3911 .serialize_vec_outer()
3912 .unwrap();
3913
3914 test_receive_icmpv4_error_helper(
3915 buffer.as_mut(),
3916 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3917 IcmpDestUnreachable::default(),
3918 |CtxPair { core_ctx, bindings_ctx: _ }| {
3919 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3920 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3921 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3922 let err = Icmpv4ErrorCode::DestUnreachable(
3923 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3924 IcmpDestUnreachable::default(),
3925 );
3926 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3927 },
3928 );
3929
3930 test_receive_icmpv4_error_helper(
3931 buffer.as_mut(),
3932 Icmpv4TimeExceededCode::TtlExpired,
3933 IcmpTimeExceeded::default(),
3934 |CtxPair { core_ctx, bindings_ctx: _ }| {
3935 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3936 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3937 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3938 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3939 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3940 },
3941 );
3942
3943 test_receive_icmpv4_error_helper(
3944 buffer.as_mut(),
3945 Icmpv4ParameterProblemCode::PointerIndicatesError,
3946 Icmpv4ParameterProblem::new(0),
3947 |CtxPair { core_ctx, bindings_ctx: _ }| {
3948 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3949 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3950 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3951 let err = Icmpv4ErrorCode::ParameterProblem(
3952 Icmpv4ParameterProblemCode::PointerIndicatesError,
3953 );
3954 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3955 },
3956 );
3957
3958 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3965 TEST_ADDRS_V4.local_ip,
3966 TEST_ADDRS_V4.remote_ip,
3967 64,
3968 Ipv4Proto::Icmp,
3969 )
3970 .wrap_body(EmptyBuf)
3971 .serialize_vec_outer()
3972 .unwrap();
3973
3974 test_receive_icmpv4_error_helper(
3975 buffer.as_mut(),
3976 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3977 IcmpDestUnreachable::default(),
3978 |CtxPair { core_ctx, bindings_ctx: _ }| {
3979 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3980 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3981 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3982 let err = Icmpv4ErrorCode::DestUnreachable(
3983 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3984 IcmpDestUnreachable::default(),
3985 );
3986 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3987 },
3988 );
3989
3990 test_receive_icmpv4_error_helper(
3991 buffer.as_mut(),
3992 Icmpv4TimeExceededCode::TtlExpired,
3993 IcmpTimeExceeded::default(),
3994 |CtxPair { core_ctx, bindings_ctx: _ }| {
3995 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3996 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3997 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3998 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3999 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4000 },
4001 );
4002
4003 test_receive_icmpv4_error_helper(
4004 buffer.as_mut(),
4005 Icmpv4ParameterProblemCode::PointerIndicatesError,
4006 Icmpv4ParameterProblem::new(0),
4007 |CtxPair { core_ctx, bindings_ctx: _ }| {
4008 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4009 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4010 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4011 let err = Icmpv4ErrorCode::ParameterProblem(
4012 Icmpv4ParameterProblemCode::PointerIndicatesError,
4013 );
4014 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4015 },
4016 );
4017
4018 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
4024 TEST_ADDRS_V4.local_ip,
4025 TEST_ADDRS_V4.remote_ip,
4026 64,
4027 IpProto::Udp.into(),
4028 )
4029 .wrap_body(EmptyBuf)
4030 .serialize_vec_outer()
4031 .unwrap();
4032
4033 test_receive_icmpv4_error_helper(
4034 buffer.as_mut(),
4035 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4036 IcmpDestUnreachable::default(),
4037 |CtxPair { core_ctx, bindings_ctx: _ }| {
4038 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4039 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4040 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4041 let err = Icmpv4ErrorCode::DestUnreachable(
4042 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4043 IcmpDestUnreachable::default(),
4044 );
4045 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4046 },
4047 );
4048
4049 test_receive_icmpv4_error_helper(
4050 buffer.as_mut(),
4051 Icmpv4TimeExceededCode::TtlExpired,
4052 IcmpTimeExceeded::default(),
4053 |CtxPair { core_ctx, bindings_ctx: _ }| {
4054 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4055 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4056 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4057 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
4058 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4059 },
4060 );
4061
4062 test_receive_icmpv4_error_helper(
4063 buffer.as_mut(),
4064 Icmpv4ParameterProblemCode::PointerIndicatesError,
4065 Icmpv4ParameterProblem::new(0),
4066 |CtxPair { core_ctx, bindings_ctx: _ }| {
4067 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4068 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4069 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4070 let err = Icmpv4ErrorCode::ParameterProblem(
4071 Icmpv4ParameterProblemCode::PointerIndicatesError,
4072 );
4073 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4074 },
4075 );
4076 }
4077
4078 #[test]
4079 fn test_receive_icmpv6_error() {
4080 const ICMP_ID: u16 = 0x0F;
4083 const SEQ_NUM: u16 = 0xF0;
4084
4085 fn test_receive_icmpv6_error_helper<
4100 C: Debug,
4101 M: IcmpMessage<Ipv6, Code = C> + Debug,
4102 F: Fn(&FakeIcmpCtx<Ipv6>),
4103 >(
4104 original_packet: &mut [u8],
4105 code: C,
4106 msg: M,
4107 f: F,
4108 ) {
4109 set_logger_for_test();
4110
4111 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
4112 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
4113 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
4114 core_ctx,
4115 bindings_ctx,
4116 &FakeDeviceId,
4117 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
4118 TEST_ADDRS_V6.local_ip,
4119 IcmpPacketBuilder::new(TEST_ADDRS_V6.remote_ip, TEST_ADDRS_V6.local_ip, code, msg)
4120 .wrap_body(Buf::new(original_packet, ..))
4121 .serialize_vec_outer()
4122 .unwrap(),
4123 &LocalDeliveryPacketInfo::default(),
4124 )
4125 .unwrap();
4126 f(&ctx);
4127 }
4128 let mut buffer = EmptyBuf
4141 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
4142 TEST_ADDRS_V6.local_ip,
4143 TEST_ADDRS_V6.remote_ip,
4144 IcmpZeroCode,
4145 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
4146 ))
4147 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4148 TEST_ADDRS_V6.local_ip,
4149 TEST_ADDRS_V6.remote_ip,
4150 64,
4151 Ipv6Proto::Icmpv6,
4152 ))
4153 .serialize_vec_outer()
4154 .unwrap();
4155
4156 test_receive_icmpv6_error_helper(
4157 buffer.as_mut(),
4158 Icmpv6DestUnreachableCode::NoRoute,
4159 IcmpDestUnreachable::default(),
4160 |CtxPair { core_ctx, bindings_ctx: _ }| {
4161 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4162 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4163 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4164 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4165 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4166 },
4167 );
4168
4169 test_receive_icmpv6_error_helper(
4170 buffer.as_mut(),
4171 Icmpv6TimeExceededCode::HopLimitExceeded,
4172 IcmpTimeExceeded::default(),
4173 |CtxPair { core_ctx, bindings_ctx: _ }| {
4174 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4175 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4176 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4177 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4178 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4179 },
4180 );
4181
4182 test_receive_icmpv6_error_helper(
4183 buffer.as_mut(),
4184 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4185 Icmpv6ParameterProblem::new(0),
4186 |CtxPair { core_ctx, bindings_ctx: _ }| {
4187 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4188 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4189 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4190 let err = Icmpv6ErrorCode::ParameterProblem(
4191 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4192 );
4193 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4194 },
4195 );
4196
4197 let mut buffer = EmptyBuf
4204 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4205 TEST_ADDRS_V6.local_ip,
4206 TEST_ADDRS_V6.remote_ip,
4207 64,
4208 Ipv6Proto::Icmpv6,
4209 ))
4210 .serialize_vec_outer()
4211 .unwrap();
4212
4213 test_receive_icmpv6_error_helper(
4214 buffer.as_mut(),
4215 Icmpv6DestUnreachableCode::NoRoute,
4216 IcmpDestUnreachable::default(),
4217 |CtxPair { core_ctx, bindings_ctx: _ }| {
4218 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4219 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4220 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4221 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4222 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4223 },
4224 );
4225
4226 test_receive_icmpv6_error_helper(
4227 buffer.as_mut(),
4228 Icmpv6TimeExceededCode::HopLimitExceeded,
4229 IcmpTimeExceeded::default(),
4230 |CtxPair { core_ctx, bindings_ctx: _ }| {
4231 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4232 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4233 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4234 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4235 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4236 },
4237 );
4238
4239 test_receive_icmpv6_error_helper(
4240 buffer.as_mut(),
4241 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4242 Icmpv6ParameterProblem::new(0),
4243 |CtxPair { core_ctx, bindings_ctx: _ }| {
4244 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4245 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4246 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4247 let err = Icmpv6ErrorCode::ParameterProblem(
4248 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4249 );
4250 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4251 },
4252 );
4253
4254 let mut buffer = <Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4260 TEST_ADDRS_V6.local_ip,
4261 TEST_ADDRS_V6.remote_ip,
4262 64,
4263 IpProto::Udp.into(),
4264 )
4265 .wrap_body(EmptyBuf)
4266 .serialize_vec_outer()
4267 .unwrap();
4268
4269 test_receive_icmpv6_error_helper(
4270 buffer.as_mut(),
4271 Icmpv6DestUnreachableCode::NoRoute,
4272 IcmpDestUnreachable::default(),
4273 |CtxPair { core_ctx, bindings_ctx: _ }| {
4274 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4275 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4276 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4277 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4278 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4279 },
4280 );
4281
4282 test_receive_icmpv6_error_helper(
4283 buffer.as_mut(),
4284 Icmpv6TimeExceededCode::HopLimitExceeded,
4285 IcmpTimeExceeded::default(),
4286 |CtxPair { core_ctx, bindings_ctx: _ }| {
4287 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4288 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4289 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4290 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4291 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4292 },
4293 );
4294
4295 test_receive_icmpv6_error_helper(
4296 buffer.as_mut(),
4297 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4298 Icmpv6ParameterProblem::new(0),
4299 |CtxPair { core_ctx, bindings_ctx: _ }| {
4300 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4301 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4302 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4303 let err = Icmpv6ErrorCode::ParameterProblem(
4304 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4305 );
4306 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4307 },
4308 );
4309 }
4310
4311 #[test]
4312 fn test_error_rate_limit() {
4313 set_logger_for_test();
4314
4315 fn send_icmpv4_ttl_expired_helper(
4317 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4318 ) {
4319 send_icmpv4_ttl_expired(
4320 core_ctx,
4321 bindings_ctx,
4322 &FakeDeviceId,
4323 Some(FrameDestination::Individual { local: true }),
4324 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4325 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4326 IpProto::Udp.into(),
4327 EmptyBuf,
4328 0,
4329 Ipv4FragmentType::InitialFragment,
4330 &Default::default(),
4331 );
4332 }
4333
4334 fn send_icmpv4_parameter_problem_helper(
4336 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4337 ) {
4338 send_icmpv4_parameter_problem(
4339 core_ctx,
4340 bindings_ctx,
4341 &FakeDeviceId,
4342 Some(FrameDestination::Individual { local: true }),
4343 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4344 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4345 Icmpv4ParameterProblemCode::PointerIndicatesError,
4346 Icmpv4ParameterProblem::new(0),
4347 EmptyBuf,
4348 0,
4349 Ipv4FragmentType::InitialFragment,
4350 &Default::default(),
4351 );
4352 }
4353
4354 fn send_icmpv4_dest_unreachable_helper(
4356 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4357 ) {
4358 send_icmpv4_dest_unreachable(
4359 core_ctx,
4360 bindings_ctx,
4361 Some(&FakeDeviceId),
4362 Some(FrameDestination::Individual { local: true }),
4363 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4364 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4365 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4366 EmptyBuf,
4367 0,
4368 Ipv4FragmentType::InitialFragment,
4369 &Default::default(),
4370 );
4371 }
4372
4373 fn send_icmpv6_ttl_expired_helper(
4375 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4376 ) {
4377 send_icmpv6_ttl_expired(
4378 core_ctx,
4379 bindings_ctx,
4380 &FakeDeviceId,
4381 Some(FrameDestination::Individual { local: true }),
4382 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4383 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4384 IpProto::Udp.into(),
4385 EmptyBuf,
4386 0,
4387 &Default::default(),
4388 );
4389 }
4390
4391 fn send_icmpv6_packet_too_big_helper(
4393 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4394 ) {
4395 send_icmpv6_packet_too_big(
4396 core_ctx,
4397 bindings_ctx,
4398 &FakeDeviceId,
4399 Some(FrameDestination::Individual { local: true }),
4400 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4401 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4402 IpProto::Udp.into(),
4403 Mtu::new(0),
4404 EmptyBuf,
4405 0,
4406 &Default::default(),
4407 );
4408 }
4409
4410 fn send_icmpv6_parameter_problem_helper(
4412 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4413 ) {
4414 send_icmpv6_parameter_problem(
4415 core_ctx,
4416 bindings_ctx,
4417 &FakeDeviceId,
4418 Some(FrameDestination::Individual { local: true }),
4419 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4420 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4421 Icmpv6ParameterProblemCode::ErroneousHeaderField,
4422 Icmpv6ParameterProblem::new(0),
4423 EmptyBuf,
4424 false,
4425 &Default::default(),
4426 );
4427 }
4428
4429 fn send_icmpv6_dest_unreachable_helper(
4431 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4432 ) {
4433 send_icmpv6_dest_unreachable(
4434 core_ctx,
4435 bindings_ctx,
4436 Some(&FakeDeviceId),
4437 Some(FrameDestination::Individual { local: true }),
4438 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4439 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4440 Icmpv6DestUnreachableCode::NoRoute,
4441 EmptyBuf,
4442 &Default::default(),
4443 );
4444 }
4445
4446 fn run_test<I: IpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
4450 with_errors_per_second: W,
4451 send: S,
4452 ) {
4453 const ERRORS_PER_SECOND: u64 = 64;
4467
4468 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
4469
4470 for i in 0..ERRORS_PER_SECOND {
4471 send(&mut ctx);
4472 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
4473 }
4474
4475 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4476 send(&mut ctx);
4477 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4478
4479 let mut ctx = with_errors_per_second(0);
4483 send(&mut ctx);
4484 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4485 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4486 send(&mut ctx);
4487 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4488 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4489 send(&mut ctx);
4490 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4491 }
4492
4493 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
4494 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4495 }
4496 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
4497 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
4498 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
4499
4500 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
4501 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4502 }
4503
4504 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
4505 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
4506 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
4507 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
4508 }
4509}