1pub mod counters;
8
9use alloc::boxed::Box;
10use core::convert::{Infallible as Never, TryInto as _};
11use core::num::{NonZeroU8, NonZeroU16};
12
13use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
14use log::{debug, error, trace};
15use net_types::ip::{
16 GenericOverIp, Ip, IpAddress, IpMarked, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr,
17 Ipv6SourceAddr, Mtu, SubnetError,
18};
19use net_types::{
20 LinkLocalAddress, LinkLocalUnicastAddr, MulticastAddr, MulticastAddress, NonMulticastAddr,
21 SpecifiedAddr, UnicastAddr, Witness,
22};
23use netstack3_base::socket::{AddrIsMappedError, SocketIpAddr, SocketIpAddrExt as _};
24use netstack3_base::sync::Mutex;
25use netstack3_base::{
26 AnyDevice, Counter, CounterContext, DeviceIdContext, EitherDeviceId, FrameDestination,
27 IcmpIpExt, Icmpv4ErrorCode, Icmpv6ErrorCode, InstantBindingsTypes, InstantContext,
28 IpDeviceAddr, IpExt, Marks, RngContext, TokenBucket, TxMetadataBindingsTypes,
29};
30use netstack3_filter::{DynTransportSerializer, DynamicTransportSerializer, FilterIpExt};
31use packet::{
32 BufferMut, InnerPacketBuilder as _, PacketBuilder as _, ParsablePacket as _, ParseBuffer,
33 PartialSerializer, Serializer, TruncateDirection, TruncatingSerializer,
34};
35use packet_formats::icmp::ndp::options::{NdpOption, NdpOptionBuilder};
36use packet_formats::icmp::ndp::{
37 NdpPacket, NeighborAdvertisement, NeighborSolicitation, NonZeroNdpLifetime,
38 OptionSequenceBuilder, RouterSolicitation,
39};
40use packet_formats::icmp::{
41 IcmpDestUnreachable, IcmpEchoRequest, IcmpMessage, IcmpMessageType, IcmpPacket,
42 IcmpPacketBuilder, IcmpPacketRaw, IcmpParseArgs, IcmpTimeExceeded, IcmpZeroCode,
43 Icmpv4DestUnreachableCode, Icmpv4Packet, Icmpv4ParameterProblem, Icmpv4ParameterProblemCode,
44 Icmpv4TimeExceededCode, Icmpv6DestUnreachableCode, Icmpv6Packet, Icmpv6PacketTooBig,
45 Icmpv6ParameterProblem, Icmpv6ParameterProblemCode, Icmpv6TimeExceededCode, MessageBody,
46 OriginalPacket, peek_message_type,
47};
48use packet_formats::ip::{DscpAndEcn, IpPacket, Ipv4Proto, Ipv6Proto};
49use packet_formats::ipv4::{Ipv4FragmentType, Ipv4Header, Ipv4OnlyMeta};
50use packet_formats::ipv6::{ExtHdrParseError, Ipv6Header};
51use zerocopy::SplitByteSlice;
52
53use crate::internal::base::{
54 AddressStatus, IPV6_DEFAULT_SUBNET, IpDeviceIngressStateContext, IpLayerHandler,
55 IpPacketDestination, IpSendFrameError, IpTransportContext, Ipv6PresentAddressStatus,
56 NdpBindingsContext, RouterAdvertisementEvent, SendIpPacketMeta, TransportReceiveError,
57};
58use crate::internal::device::nud::{ConfirmationFlags, NudIpHandler};
59use crate::internal::device::route_discovery::Ipv6DiscoveredRoute;
60use crate::internal::device::{
61 IpAddressState, IpDeviceHandler, Ipv6DeviceHandler, Ipv6LinkLayerAddr,
62};
63use crate::internal::icmp::counters::{IcmpCountersIpExt, IcmpRxCounters, IcmpTxCounters};
64use crate::internal::local_delivery::{IpHeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta};
65use crate::internal::path_mtu::PmtuHandler;
66use crate::internal::socket::{
67 DelegatedRouteResolutionOptions, DelegatedSendOptions, IpSocketArgs, IpSocketHandler,
68 OptionDelegationMarker, RouteResolutionOptions, SendOptions,
69};
70
71pub const REQUIRED_NDP_IP_PACKET_HOP_LIMIT: u8 = 255;
83
84pub const DEFAULT_ERRORS_PER_SECOND: u64 = 1000;
92#[derive(GenericOverIp)]
94#[generic_over_ip(I, Ip)]
95pub struct IcmpState<I: IpExt + IcmpCountersIpExt, BT: IcmpBindingsTypes> {
96 error_send_bucket: Mutex<IpMarked<I, TokenBucket<BT::Instant>>>,
97 pub tx_counters: IcmpTxCounters<I>,
99 pub rx_counters: IcmpRxCounters<I>,
101}
102
103impl<I, BT> OrderedLockAccess<IpMarked<I, TokenBucket<BT::Instant>>> for IcmpState<I, BT>
104where
105 I: IpExt + IcmpCountersIpExt,
106 BT: IcmpBindingsTypes,
107{
108 type Lock = Mutex<IpMarked<I, TokenBucket<BT::Instant>>>;
109 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
110 OrderedLockRef::new(&self.error_send_bucket)
111 }
112}
113
114#[derive(Default)]
116pub struct NdpRxCounters {
117 pub neighbor_solicitation: Counter,
119 pub neighbor_advertisement: Counter,
121 pub router_advertisement: Counter,
123 pub router_solicitation: Counter,
125}
126
127#[derive(Default)]
129pub struct NdpTxCounters {
130 pub neighbor_advertisement: Counter,
132 pub neighbor_solicitation: Counter,
134}
135
136#[derive(Default)]
138pub struct NdpCounters {
139 pub rx: NdpRxCounters,
141 pub tx: NdpTxCounters,
143}
144
145#[derive(Copy, Clone)]
147pub struct Icmpv4StateBuilder {
148 send_timestamp_reply: bool,
149 errors_per_second: u64,
150}
151
152impl Default for Icmpv4StateBuilder {
153 fn default() -> Icmpv4StateBuilder {
154 Icmpv4StateBuilder {
155 send_timestamp_reply: false,
156 errors_per_second: DEFAULT_ERRORS_PER_SECOND,
157 }
158 }
159}
160
161impl Icmpv4StateBuilder {
162 pub fn send_timestamp_reply(&mut self, send_timestamp_reply: bool) -> &mut Self {
169 self.send_timestamp_reply = send_timestamp_reply;
170 self
171 }
172
173 pub fn build<BT: IcmpBindingsTypes>(self) -> Icmpv4State<BT> {
175 Icmpv4State {
176 inner: IcmpState {
177 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
178 self.errors_per_second,
179 ))),
180 tx_counters: Default::default(),
181 rx_counters: Default::default(),
182 },
183 send_timestamp_reply: self.send_timestamp_reply,
184 }
185 }
186}
187
188pub struct Icmpv4State<BT: IcmpBindingsTypes> {
190 pub inner: IcmpState<Ipv4, BT>,
192 pub send_timestamp_reply: bool,
194}
195
196impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
197 fn as_ref(&self) -> &IcmpState<Ipv4, BT> {
198 &self.inner
199 }
200}
201
202impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
203 fn as_mut(&mut self) -> &mut IcmpState<Ipv4, BT> {
204 &mut self.inner
205 }
206}
207
208#[derive(Copy, Clone)]
210pub(crate) struct Icmpv6StateBuilder {
211 errors_per_second: u64,
212}
213
214impl Default for Icmpv6StateBuilder {
215 fn default() -> Icmpv6StateBuilder {
216 Icmpv6StateBuilder { errors_per_second: DEFAULT_ERRORS_PER_SECOND }
217 }
218}
219
220impl Icmpv6StateBuilder {
221 pub(crate) fn build<BT: IcmpBindingsTypes>(self) -> Icmpv6State<BT> {
222 Icmpv6State {
223 inner: IcmpState {
224 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
225 self.errors_per_second,
226 ))),
227 tx_counters: Default::default(),
228 rx_counters: Default::default(),
229 },
230 ndp_counters: Default::default(),
231 }
232 }
233}
234
235pub struct Icmpv6State<BT: IcmpBindingsTypes> {
237 pub inner: IcmpState<Ipv6, BT>,
239 pub ndp_counters: NdpCounters,
241}
242
243impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
244 fn as_ref(&self) -> &IcmpState<Ipv6, BT> {
245 &self.inner
246 }
247}
248
249impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
250 fn as_mut(&mut self) -> &mut IcmpState<Ipv6, BT> {
251 &mut self.inner
252 }
253}
254
255pub trait IcmpHandlerIpExt: IpExt {
257 type SourceAddress: Witness<Self::Addr>;
258 type IcmpError;
259
260 fn received_source_as_icmp_source(src: Self::RecvSrcAddr) -> Option<Self::SourceAddress>;
262
263 fn new_ttl_expired<B: SplitByteSlice>(
265 proto: Self::Proto,
266 header_len: usize,
267 meta: <Self::Packet<B> as IpPacket<B, Self>>::VersionSpecificMeta,
268 ) -> Self::IcmpError;
269
270 fn new_mtu_exceeded(proto: Self::Proto, header_len: usize, mtu: Mtu)
272 -> Option<Self::IcmpError>;
273}
274
275impl IcmpHandlerIpExt for Ipv4 {
276 type SourceAddress = NonMulticastAddr<SpecifiedAddr<Ipv4Addr>>;
277 type IcmpError = Icmpv4Error;
278 fn received_source_as_icmp_source(
279 src: Ipv4SourceAddr,
280 ) -> Option<NonMulticastAddr<SpecifiedAddr<Ipv4Addr>>> {
281 match src {
282 Ipv4SourceAddr::Specified(src) => Some(src),
283 Ipv4SourceAddr::Unspecified => None,
284 }
285 }
286 fn new_ttl_expired<B: SplitByteSlice>(
287 proto: Ipv4Proto,
288 header_len: usize,
289 Ipv4OnlyMeta { id: _, fragment_type }: Ipv4OnlyMeta,
290 ) -> Icmpv4Error {
291 Icmpv4Error { kind: Icmpv4ErrorKind::TtlExpired { proto, fragment_type }, header_len }
292 }
293 fn new_mtu_exceeded(_proto: Ipv4Proto, _header_len: usize, _mtu: Mtu) -> Option<Icmpv4Error> {
294 None
296 }
297}
298
299impl IcmpHandlerIpExt for Ipv6 {
300 type SourceAddress = UnicastAddr<Ipv6Addr>;
301 type IcmpError = Icmpv6ErrorKind;
302 fn received_source_as_icmp_source(src: Ipv6SourceAddr) -> Option<UnicastAddr<Ipv6Addr>> {
303 match src {
304 Ipv6SourceAddr::Unicast(src) => Some(src.get()),
305 Ipv6SourceAddr::Unspecified => None,
306 }
307 }
308 fn new_ttl_expired<B: SplitByteSlice>(
309 proto: Ipv6Proto,
310 header_len: usize,
311 _meta: (),
312 ) -> Icmpv6ErrorKind {
313 Icmpv6ErrorKind::TtlExpired { proto, header_len }
314 }
315 fn new_mtu_exceeded(proto: Ipv6Proto, header_len: usize, mtu: Mtu) -> Option<Icmpv6ErrorKind> {
316 Some(Icmpv6ErrorKind::PacketTooBig { proto, header_len, mtu })
317 }
318}
319
320pub(crate) enum Icmpv4ErrorKind {
322 ParameterProblem {
323 code: Icmpv4ParameterProblemCode,
324 pointer: u8,
325 fragment_type: Ipv4FragmentType,
326 },
327 TtlExpired {
328 proto: Ipv4Proto,
329 fragment_type: Ipv4FragmentType,
330 },
331 NetUnreachable {
332 proto: Ipv4Proto,
333 fragment_type: Ipv4FragmentType,
334 },
335 ProtocolUnreachable,
336 PortUnreachable,
337}
338
339pub struct Icmpv4Error {
341 pub(super) kind: Icmpv4ErrorKind,
342 pub(super) header_len: usize,
343}
344
345pub enum Icmpv6ErrorKind {
347 ParameterProblem { code: Icmpv6ParameterProblemCode, pointer: u32, allow_dst_multicast: bool },
348 TtlExpired { proto: Ipv6Proto, header_len: usize },
349 NetUnreachable { proto: Ipv6Proto, header_len: usize },
350 PacketTooBig { proto: Ipv6Proto, header_len: usize, mtu: Mtu },
351 ProtocolUnreachable { header_len: usize },
352 PortUnreachable,
353}
354
355pub trait IcmpErrorHandler<I: IcmpHandlerIpExt, BC>: DeviceIdContext<AnyDevice> {
357 fn send_icmp_error_message<B: BufferMut>(
362 &mut self,
363 bindings_ctx: &mut BC,
364 device: &Self::DeviceId,
365 frame_dst: Option<FrameDestination>,
366 src_ip: I::SourceAddress,
367 dst_ip: SpecifiedAddr<I::Addr>,
368 original_packet: B,
369 error: I::IcmpError,
370 marks: &Marks,
371 );
372}
373
374impl<BC: IcmpBindingsContext, CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>>
375 IcmpErrorHandler<Ipv4, BC> for CC
376{
377 fn send_icmp_error_message<B: BufferMut>(
378 &mut self,
379 bindings_ctx: &mut BC,
380 device: &CC::DeviceId,
381 frame_dst: Option<FrameDestination>,
382 src_ip: NonMulticastAddr<SpecifiedAddr<Ipv4Addr>>,
383 dst_ip: SpecifiedAddr<Ipv4Addr>,
384 original_packet: B,
385 Icmpv4Error { kind, header_len }: Icmpv4Error,
386 marks: &Marks,
387 ) {
388 let src_ip = SocketIpAddr::new_ipv4_specified(src_ip.get());
389 let dst_ip = SocketIpAddr::new_ipv4_specified(dst_ip);
390 match kind {
391 Icmpv4ErrorKind::ParameterProblem { code, pointer, fragment_type } => {
392 send_icmpv4_parameter_problem(
393 self,
394 bindings_ctx,
395 device,
396 frame_dst,
397 src_ip,
398 dst_ip,
399 code,
400 Icmpv4ParameterProblem::new(pointer),
401 original_packet,
402 header_len,
403 fragment_type,
404 marks,
405 )
406 }
407 Icmpv4ErrorKind::TtlExpired { proto, fragment_type } => send_icmpv4_ttl_expired(
408 self,
409 bindings_ctx,
410 device,
411 frame_dst,
412 src_ip,
413 dst_ip,
414 proto,
415 original_packet,
416 header_len,
417 fragment_type,
418 marks,
419 ),
420 Icmpv4ErrorKind::NetUnreachable { proto, fragment_type } => {
421 send_icmpv4_net_unreachable(
422 self,
423 bindings_ctx,
424 device,
425 frame_dst,
426 src_ip,
427 dst_ip,
428 proto,
429 original_packet,
430 header_len,
431 fragment_type,
432 marks,
433 )
434 }
435 Icmpv4ErrorKind::ProtocolUnreachable => send_icmpv4_protocol_unreachable(
436 self,
437 bindings_ctx,
438 device,
439 frame_dst,
440 src_ip,
441 dst_ip,
442 original_packet,
443 header_len,
444 marks,
445 ),
446 Icmpv4ErrorKind::PortUnreachable => send_icmpv4_port_unreachable(
447 self,
448 bindings_ctx,
449 device,
450 frame_dst,
451 src_ip,
452 dst_ip,
453 original_packet,
454 header_len,
455 marks,
456 ),
457 }
458 }
459}
460
461impl<BC: IcmpBindingsContext, CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>>
462 IcmpErrorHandler<Ipv6, BC> for CC
463{
464 fn send_icmp_error_message<B: BufferMut>(
465 &mut self,
466 bindings_ctx: &mut BC,
467 device: &CC::DeviceId,
468 frame_dst: Option<FrameDestination>,
469 src_ip: UnicastAddr<Ipv6Addr>,
470 dst_ip: SpecifiedAddr<Ipv6Addr>,
471 original_packet: B,
472 error: Icmpv6ErrorKind,
473 marks: &Marks,
474 ) {
475 let src_ip: SocketIpAddr<Ipv6Addr> = match src_ip.into_specified().try_into() {
476 Ok(addr) => addr,
477 Err(AddrIsMappedError {}) => {
478 trace!("send_icmpv6_error_message: src_ip is mapped");
479 return;
480 }
481 };
482 let dst_ip: SocketIpAddr<Ipv6Addr> = match dst_ip.try_into() {
483 Ok(addr) => addr,
484 Err(AddrIsMappedError {}) => {
485 trace!("send_icmpv6_error_message: dst_ip is mapped");
486 return;
487 }
488 };
489
490 match error {
491 Icmpv6ErrorKind::ParameterProblem { code, pointer, allow_dst_multicast } => {
492 send_icmpv6_parameter_problem(
493 self,
494 bindings_ctx,
495 device,
496 frame_dst,
497 src_ip,
498 dst_ip,
499 code,
500 Icmpv6ParameterProblem::new(pointer),
501 original_packet,
502 allow_dst_multicast,
503 marks,
504 )
505 }
506 Icmpv6ErrorKind::TtlExpired { proto, header_len } => send_icmpv6_ttl_expired(
507 self,
508 bindings_ctx,
509 device,
510 frame_dst,
511 src_ip,
512 dst_ip,
513 proto,
514 original_packet,
515 header_len,
516 marks,
517 ),
518 Icmpv6ErrorKind::NetUnreachable { proto, header_len } => send_icmpv6_net_unreachable(
519 self,
520 bindings_ctx,
521 device,
522 frame_dst,
523 src_ip,
524 dst_ip,
525 proto,
526 original_packet,
527 header_len,
528 marks,
529 ),
530 Icmpv6ErrorKind::PacketTooBig { proto, header_len, mtu } => send_icmpv6_packet_too_big(
531 self,
532 bindings_ctx,
533 device,
534 frame_dst,
535 src_ip,
536 dst_ip,
537 proto,
538 mtu,
539 original_packet,
540 header_len,
541 marks,
542 ),
543 Icmpv6ErrorKind::ProtocolUnreachable { header_len } => {
544 send_icmpv6_protocol_unreachable(
545 self,
546 bindings_ctx,
547 device,
548 frame_dst,
549 src_ip,
550 dst_ip,
551 original_packet,
552 header_len,
553 marks,
554 )
555 }
556 Icmpv6ErrorKind::PortUnreachable => send_icmpv6_port_unreachable(
557 self,
558 bindings_ctx,
559 device,
560 frame_dst,
561 src_ip,
562 dst_ip,
563 original_packet,
564 marks,
565 ),
566 }
567 }
568}
569
570pub trait IcmpBindingsContext: InstantContext + RngContext + IcmpBindingsTypes {}
573impl<BC> IcmpBindingsContext for BC where
574 BC: InstantContext + RngContext + IcmpBindingsTypes + IcmpBindingsTypes
575{
576}
577
578pub trait IcmpBindingsTypes: InstantBindingsTypes + TxMetadataBindingsTypes {}
580impl<BT: InstantBindingsTypes + TxMetadataBindingsTypes> IcmpBindingsTypes for BT {}
581
582pub trait IcmpStateContext {}
590
591pub trait EchoTransportContextMarker {}
601
602pub trait InnerIcmpContext<I: IpExt + FilterIpExt, BC: IcmpBindingsTypes>:
605 IpSocketHandler<I, BC>
606{
607 type EchoTransportContext: IpTransportContext<I, BC, Self> + EchoTransportContextMarker;
610
611 fn receive_icmp_error(
641 &mut self,
642 bindings_ctx: &mut BC,
643 device: &Self::DeviceId,
644 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
645 original_dst_ip: SpecifiedAddr<I::Addr>,
646 original_proto: I::Proto,
647 original_body: &[u8],
648 err: I::ErrorCode,
649 );
650
651 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
654 &mut self,
655 cb: F,
656 ) -> O;
657}
658
659pub trait InnerIcmpv4Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv4, BC> {
663 fn should_send_timestamp_reply(&self) -> bool;
665}
666
667pub trait InnerIcmpv6Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv6, BC> {}
671impl<BC: IcmpBindingsTypes, CC: InnerIcmpContext<Ipv6, BC>> InnerIcmpv6Context<BC> for CC {}
672
673macro_rules! try_send_error {
687 ($core_ctx:expr, $bindings_ctx:expr, $e:expr) => {{
688 let send = $core_ctx.with_error_send_bucket_mut(|error_send_bucket| {
689 error_send_bucket.try_take($bindings_ctx)
690 });
691
692 if send {
693 $core_ctx.counters().error.increment();
694 $e
695 } else {
696 trace!("ip::icmp::try_send_error!: dropping rate-limited ICMP error message");
697 Ok(())
698 }
699 }};
700}
701
702pub enum IcmpIpTransportContext {}
704
705fn receive_ip_transport_icmp_error<
706 I: IpExt + FilterIpExt + IcmpCountersIpExt,
707 CC: InnerIcmpContext<I, BC> + CounterContext<IcmpRxCounters<I>>,
708 BC: IcmpBindingsContext,
709>(
710 core_ctx: &mut CC,
711 bindings_ctx: &mut BC,
712 device: &CC::DeviceId,
713 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
714 original_dst_ip: SpecifiedAddr<I::Addr>,
715 original_body: &[u8],
716 err: I::ErrorCode,
717) {
718 core_ctx.counters().error_delivered_to_transport_layer.increment();
719 trace!("IcmpIpTransportContext::receive_icmp_error({:?})", err);
720
721 let mut parse_body = original_body;
722 match parse_body.parse::<IcmpPacketRaw<I, _, IcmpEchoRequest>>() {
723 Ok(_echo_request) => (),
726 Err(_) => {
727 return;
731 }
732 }
733
734 <CC::EchoTransportContext as IpTransportContext<I, BC, CC>>::receive_icmp_error(
735 core_ctx,
736 bindings_ctx,
737 device,
738 original_src_ip,
739 original_dst_ip,
740 original_body,
741 err,
742 );
743}
744
745impl<
746 BC: IcmpBindingsContext,
747 CC: InnerIcmpv4Context<BC>
748 + PmtuHandler<Ipv4, BC>
749 + CounterContext<IcmpRxCounters<Ipv4>>
750 + CounterContext<IcmpTxCounters<Ipv4>>,
751> IpTransportContext<Ipv4, BC, CC> for IcmpIpTransportContext
752{
753 type EarlyDemuxSocket = Never;
754
755 fn early_demux<B: ParseBuffer>(
756 _core_ctx: &mut CC,
757 _device: &CC::DeviceId,
758 _src_ip: Ipv4Addr,
759 _dst_ip: Ipv4Addr,
760 _buffer: B,
761 ) -> Option<Self::EarlyDemuxSocket> {
762 None
763 }
764
765 fn receive_icmp_error(
766 core_ctx: &mut CC,
767 bindings_ctx: &mut BC,
768 device: &CC::DeviceId,
769 original_src_ip: Option<SpecifiedAddr<Ipv4Addr>>,
770 original_dst_ip: SpecifiedAddr<Ipv4Addr>,
771 original_body: &[u8],
772 err: Icmpv4ErrorCode,
773 ) {
774 receive_ip_transport_icmp_error(
775 core_ctx,
776 bindings_ctx,
777 device,
778 original_src_ip,
779 original_dst_ip,
780 original_body,
781 err,
782 )
783 }
784
785 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv4>>(
786 core_ctx: &mut CC,
787 bindings_ctx: &mut BC,
788 device: &CC::DeviceId,
789 src_ip: Ipv4SourceAddr,
790 dst_ip: SpecifiedAddr<Ipv4Addr>,
791 mut buffer: B,
792 info: &LocalDeliveryPacketInfo<Ipv4, H>,
793 _early_demux_socket: Option<Never>,
794 ) -> Result<(), (B, TransportReceiveError)> {
795 let LocalDeliveryPacketInfo { meta, header_info: _, marks } = info;
796 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
797 if let Some(delivery) = transparent_override {
798 unreachable!(
799 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
800 transparent proxy rules can only be configured for TCP and UDP packets"
801 );
802 }
803
804 trace!(
805 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet({}, {})",
806 src_ip, dst_ip
807 );
808 let packet =
809 match buffer.parse_with::<_, Icmpv4Packet<_>>(IcmpParseArgs::new(src_ip, dst_ip)) {
810 Ok(packet) => packet,
811 Err(_) => return Ok(()), };
813
814 match packet {
815 Icmpv4Packet::EchoRequest(echo_request) => {
816 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_request.increment();
817
818 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
819 let req = *echo_request.message();
820 let code = echo_request.code();
821 let (local_ip, remote_ip) = (dst_ip, src_ip);
822 debug!(
823 "replying to ICMP echo request from {remote_ip} to {local_ip}%{device:?}: \
824 id={}, seq={}",
825 req.id(),
826 req.seq()
827 );
828 send_icmp_reply(
829 core_ctx,
830 bindings_ctx,
831 device,
832 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
833 SocketIpAddr::new_ipv4_specified(local_ip),
834 |src_ip| {
835 IcmpPacketBuilder::<Ipv4, _>::new(src_ip, *remote_ip, code, req.reply())
836 .wrap_body(buffer)
837 },
838 &WithMarks(marks),
839 );
840 } else {
841 trace!(
842 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
843 Received echo request with an unspecified source address"
844 );
845 }
846 }
847 Icmpv4Packet::EchoReply(echo_reply) => {
848 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_reply.increment();
849 trace!(
850 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
851 Received an EchoReply message"
852 );
853 let parse_metadata = echo_reply.parse_metadata();
854 buffer.undo_parse(parse_metadata);
855 return <CC::EchoTransportContext
856 as IpTransportContext<Ipv4, BC, CC>>::receive_ip_packet(
857 core_ctx,
858 bindings_ctx,
859 device,
860 src_ip,
861 dst_ip,
862 buffer,
863 info,
864 None,
865 );
866 }
867 Icmpv4Packet::TimestampRequest(timestamp_request) => {
868 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
869 .timestamp_request
870 .increment();
871 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
872 if core_ctx.should_send_timestamp_reply() {
873 trace!(
874 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
875 receive_ip_packet: Responding to Timestamp Request message"
876 );
877 const NOW: u32 = 0x80000000;
896 let reply = timestamp_request.message().reply(NOW, NOW);
897 let (local_ip, remote_ip) = (dst_ip, src_ip);
898 buffer.shrink_front_to(0);
905 send_icmp_reply(
906 core_ctx,
907 bindings_ctx,
908 device,
909 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
910 SocketIpAddr::new_ipv4_specified(local_ip),
911 |src_ip| {
912 IcmpPacketBuilder::<Ipv4, _>::new(
913 src_ip,
914 *remote_ip,
915 IcmpZeroCode,
916 reply,
917 )
918 .wrap_body(buffer)
919 },
920 &WithMarks(marks),
921 );
922 } else {
923 trace!(
924 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
925 receive_ip_packet: Silently ignoring Timestamp Request message"
926 );
927 }
928 } else {
929 trace!(
930 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
931 receive_ip_packet: Received timestamp request with an unspecified source \
932 address"
933 );
934 }
935 }
936 Icmpv4Packet::TimestampReply(_) => {
937 debug!(
940 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
941 Received unsolicited Timestamp Reply message"
942 );
943 }
944 Icmpv4Packet::DestUnreachable(dest_unreachable) => {
945 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
946 .dest_unreachable
947 .increment_code(dest_unreachable.code());
948 trace!(
949 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
950 Received a Destination Unreachable message"
951 );
952
953 let error = if dest_unreachable.code()
954 == Icmpv4DestUnreachableCode::FragmentationRequired
955 {
956 let mtu = if let Some(next_hop_mtu) = dest_unreachable.message().next_hop_mtu()
957 {
958 core_ctx.update_pmtu_if_less(
968 bindings_ctx,
969 dst_ip.get(),
970 src_ip.get(),
971 Mtu::new(u32::from(next_hop_mtu.get())),
972 )
973 } else {
974 let (original_packet_buf, inner_body) = dest_unreachable.body().bytes();
996 debug_assert!(inner_body.is_none());
998 if original_packet_buf.len() >= 4 {
999 let total_len =
1003 u16::from_be_bytes(original_packet_buf[2..4].try_into().unwrap());
1004
1005 trace!(
1006 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1007 receive_ip_packet: Next-Hop MTU is 0 so using the next best PMTU \
1008 value from {total_len}"
1009 );
1010
1011 core_ctx.update_pmtu_next_lower(
1012 bindings_ctx,
1013 dst_ip.get(),
1014 src_ip.get(),
1015 Mtu::new(u32::from(total_len)),
1016 )
1017 } else {
1018 trace!(
1023 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1024 receive_ip_packet: Original packet buf is too small to get \
1025 original packet len so ignoring"
1026 );
1027 None
1028 }
1029 };
1030 mtu.and_then(|mtu| {
1031 let mtu = u16::try_from(mtu.get()).unwrap_or(u16::MAX);
1032 let mtu = NonZeroU16::new(mtu)?;
1033 Some(Icmpv4ErrorCode::DestUnreachable(
1034 dest_unreachable.code(),
1035 IcmpDestUnreachable::new_for_frag_req(mtu),
1036 ))
1037 })
1038 } else {
1039 Some(Icmpv4ErrorCode::DestUnreachable(
1040 dest_unreachable.code(),
1041 *dest_unreachable.message(),
1042 ))
1043 };
1044
1045 if let Some(error) = error {
1046 receive_icmpv4_error(core_ctx, bindings_ctx, device, &dest_unreachable, error);
1047 }
1048 }
1049 Icmpv4Packet::TimeExceeded(time_exceeded) => {
1050 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1051 .time_exceeded
1052 .increment_code(time_exceeded.code());
1053 trace!(
1054 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1055 Received a Time Exceeded message"
1056 );
1057
1058 receive_icmpv4_error(
1059 core_ctx,
1060 bindings_ctx,
1061 device,
1062 &time_exceeded,
1063 Icmpv4ErrorCode::TimeExceeded(time_exceeded.code()),
1064 );
1065 }
1066 Icmpv4Packet::Redirect(_) => {
1068 debug!(
1069 "Unimplemented: <IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1070 receive_ip_packet::redirect"
1071 )
1072 }
1073 Icmpv4Packet::ParameterProblem(parameter_problem) => {
1074 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1075 .parameter_problem
1076 .increment_code(parameter_problem.code());
1077 trace!(
1078 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1079 Received a Parameter Problem message"
1080 );
1081
1082 receive_icmpv4_error(
1083 core_ctx,
1084 bindings_ctx,
1085 device,
1086 ¶meter_problem,
1087 Icmpv4ErrorCode::ParameterProblem(parameter_problem.code()),
1088 );
1089 }
1090 }
1091
1092 Ok(())
1093 }
1094}
1095
1096#[allow(missing_docs)]
1099pub enum NdpMessage {
1100 NeighborSolicitation {
1101 message: NeighborSolicitation,
1102 code: <NeighborSolicitation as IcmpMessage<Ipv6>>::Code,
1103 },
1104
1105 RouterSolicitation {
1106 message: RouterSolicitation,
1107 code: <RouterSolicitation as IcmpMessage<Ipv6>>::Code,
1108 },
1109
1110 NeighborAdvertisement {
1111 message: NeighborAdvertisement,
1112 code: <NeighborAdvertisement as IcmpMessage<Ipv6>>::Code,
1113 },
1114}
1115
1116pub fn send_ndp_packet<BC, CC, S>(
1118 core_ctx: &mut CC,
1119 bindings_ctx: &mut BC,
1120 device_id: &CC::DeviceId,
1121 src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1122 dst_ip: SpecifiedAddr<Ipv6Addr>,
1123 body: S,
1124 message: NdpMessage,
1125) -> Result<(), IpSendFrameError<S>>
1126where
1127 CC: IpLayerHandler<Ipv6, BC>,
1128 S: Serializer + PartialSerializer,
1129 S::Buffer: BufferMut,
1130{
1131 macro_rules! send {
1132 ($message:expr, $code:expr) => {{
1133 let mut ser = IcmpPacketBuilder::<Ipv6, _>::new(
1135 src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
1136 dst_ip.get(),
1137 $code,
1138 $message,
1139 )
1140 .wrap_body(body);
1141 match IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
1142 core_ctx,
1143 bindings_ctx,
1144 SendIpPacketMeta {
1145 device: device_id,
1146 src_ip,
1147 dst_ip,
1148 destination: IpPacketDestination::from_addr(dst_ip),
1149 ttl: NonZeroU8::new(REQUIRED_NDP_IP_PACKET_HOP_LIMIT),
1150 proto: Ipv6Proto::Icmpv6,
1151 mtu: Mtu::no_limit(),
1152 dscp_and_ecn: DscpAndEcn::default(),
1153 },
1154 DynTransportSerializer::new(&mut ser),
1155 ) {
1156 Ok(()) => Ok(()),
1157 Err(e) => Err(e
1158 .map_serializer(|s| {
1159 let _: DynTransportSerializer<'_, _> = s;
1161 })
1162 .map_serializer(|()| ser.into_inner())),
1163 }
1164 }};
1165 }
1166
1167 match message {
1168 NdpMessage::NeighborSolicitation { message, code } => send!(message, code),
1169 NdpMessage::RouterSolicitation { message, code } => send!(message, code),
1170 NdpMessage::NeighborAdvertisement { message, code } => send!(message, code),
1171 }
1172}
1173
1174fn send_neighbor_advertisement<
1175 BC,
1176 CC: Ipv6DeviceHandler<BC>
1177 + IpDeviceHandler<Ipv6, BC>
1178 + IpLayerHandler<Ipv6, BC>
1179 + CounterContext<NdpCounters>,
1180>(
1181 core_ctx: &mut CC,
1182 bindings_ctx: &mut BC,
1183 device_id: &CC::DeviceId,
1184 solicited: bool,
1185 device_addr: UnicastAddr<Ipv6Addr>,
1186 dst_ip: SpecifiedAddr<Ipv6Addr>,
1187) {
1188 core_ctx.counters().tx.neighbor_advertisement.increment();
1189 debug!("send_neighbor_advertisement from {:?} to {:?}", device_addr, dst_ip);
1190 debug_assert!(dst_ip.is_valid_unicast() || (!solicited && dst_ip.is_multicast()));
1197
1198 let src_ll = core_ctx.get_link_layer_addr(&device_id);
1205
1206 let advertisement = NeighborAdvertisement::new(
1208 core_ctx.is_router_device(&device_id),
1209 solicited,
1210 true, device_addr.get(),
1223 );
1224 let _: Result<(), _> = send_ndp_packet(
1225 core_ctx,
1226 bindings_ctx,
1227 &device_id,
1228 Some(device_addr.into_specified()),
1229 dst_ip,
1230 OptionSequenceBuilder::new(
1231 src_ll
1232 .as_ref()
1233 .map(Ipv6LinkLayerAddr::as_bytes)
1234 .map(NdpOptionBuilder::TargetLinkLayerAddress)
1235 .iter(),
1236 )
1237 .into_serializer(),
1238 NdpMessage::NeighborAdvertisement { message: advertisement, code: IcmpZeroCode },
1239 );
1240}
1241
1242fn receive_ndp_packet<
1243 B: SplitByteSlice,
1244 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1245 CC: InnerIcmpv6Context<BC>
1246 + Ipv6DeviceHandler<BC>
1247 + IpDeviceHandler<Ipv6, BC>
1248 + IpDeviceIngressStateContext<Ipv6>
1249 + NudIpHandler<Ipv6, BC>
1250 + IpLayerHandler<Ipv6, BC>
1251 + CounterContext<NdpCounters>,
1252 H: IpHeaderInfo<Ipv6>,
1253>(
1254 core_ctx: &mut CC,
1255 bindings_ctx: &mut BC,
1256 device_id: &CC::DeviceId,
1257 src_ip: Ipv6SourceAddr,
1258 dst_ip: SpecifiedAddr<Ipv6Addr>,
1259 packet: NdpPacket<B>,
1260 header_info: &H,
1261) {
1262 if header_info.hop_limit() != REQUIRED_NDP_IP_PACKET_HOP_LIMIT {
1280 trace!("dropping NDP packet from {src_ip} with invalid hop limit");
1281 return;
1282 }
1283
1284 match packet {
1285 NdpPacket::RouterSolicitation(_) => {}
1286 NdpPacket::Redirect(_) => {}
1288 NdpPacket::NeighborSolicitation(ref p) => {
1289 let target_address = p.message().target_address();
1296 let target_address = match UnicastAddr::new(*target_address) {
1297 Some(a) => a,
1298 None => {
1299 trace!(
1300 "dropping NS from {} with non-unicast target={:?}",
1301 src_ip, target_address
1302 );
1303 return;
1304 }
1305 };
1306
1307 let (source_link_addr, nonce) = p.body().iter().fold(
1309 (None, None),
1310 |(found_source_link_addr, found_nonce), option| {
1311 match option {
1312 NdpOption::Nonce(nonce) => (found_source_link_addr, Some(nonce)),
1313 NdpOption::SourceLinkLayerAddress(source_link_addr) => {
1314 (Some(source_link_addr), found_nonce)
1315 }
1316 NdpOption::Mtu(_)
1324 | NdpOption::PrefixInformation(_)
1325 | NdpOption::RecursiveDnsServer(_)
1326 | NdpOption::RedirectedHeader { .. }
1327 | NdpOption::RouteInformation(_)
1328 | NdpOption::TargetLinkLayerAddress(_) => {
1329 (found_source_link_addr, found_nonce)
1330 }
1331 }
1332 },
1333 );
1334
1335 if src_ip == Ipv6SourceAddr::Unspecified {
1336 if target_address.get().to_solicited_node_address().get() != dst_ip.get() {
1345 debug!(
1346 "dropping NS from {} for {} with invalid IPv6 dst ({}).",
1347 src_ip, target_address, dst_ip
1348 );
1349 return;
1350 }
1351 if let Some(addr) = source_link_addr {
1356 debug!(
1357 "dropping NS from {} for {} with source link-layer addr option ({:?}).",
1358 src_ip, target_address, addr
1359 );
1360 return;
1361 }
1362 }
1363
1364 core_ctx.counters().rx.neighbor_solicitation.increment();
1365
1366 match src_ip {
1367 Ipv6SourceAddr::Unspecified => {
1368 match IpDeviceHandler::handle_received_dad_packet(
1378 core_ctx,
1379 bindings_ctx,
1380 &device_id,
1381 target_address.into_specified(),
1382 nonce,
1383 ) {
1384 Some(IpAddressState::Assigned) => {
1385 send_neighbor_advertisement(
1389 core_ctx,
1390 bindings_ctx,
1391 &device_id,
1392 false,
1393 target_address,
1394 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified(),
1395 );
1396 }
1397 Some(IpAddressState::Tentative) => {
1398 }
1401 Some(IpAddressState::Unavailable) | None => {
1402 }
1405 }
1406
1407 return;
1408 }
1409 Ipv6SourceAddr::Unicast(src_ip) => {
1410 match core_ctx
1412 .address_status_for_device(target_address.into_specified(), device_id)
1413 {
1414 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned) => {}
1415 AddressStatus::Present(
1416 Ipv6PresentAddressStatus::UnicastTentative
1417 | Ipv6PresentAddressStatus::Multicast,
1418 )
1419 | AddressStatus::Unassigned => {
1420 return;
1424 }
1425 }
1426
1427 if let Some(link_addr) = source_link_addr {
1428 NudIpHandler::handle_neighbor_probe(
1429 core_ctx,
1430 bindings_ctx,
1431 &device_id,
1432 src_ip.into_specified(),
1433 link_addr,
1434 );
1435 }
1436
1437 send_neighbor_advertisement(
1438 core_ctx,
1439 bindings_ctx,
1440 &device_id,
1441 true,
1442 target_address,
1443 src_ip.into_specified(),
1444 );
1445 }
1446 }
1447 }
1448 NdpPacket::NeighborAdvertisement(ref p) => {
1449 let target_address = p.message().target_address();
1453
1454 let target_address = match UnicastAddr::new(*target_address) {
1461 Some(a) => a,
1462 None => {
1463 debug!(
1464 "dropping NA from {} with non-unicast target={:?}",
1465 src_ip, target_address
1466 );
1467 return;
1468 }
1469 };
1470 if let Some(dst_ip) = MulticastAddr::new(dst_ip.get())
1474 && p.message().solicited_flag()
1475 {
1476 debug!(
1477 "dropping NA from {} with solicited flag and multicast dst {}",
1478 src_ip, dst_ip
1479 );
1480 return;
1481 }
1482
1483 core_ctx.counters().rx.neighbor_advertisement.increment();
1484
1485 let nonce = None;
1489 match IpDeviceHandler::handle_received_dad_packet(
1490 core_ctx,
1491 bindings_ctx,
1492 &device_id,
1493 target_address.into_specified(),
1494 nonce,
1495 ) {
1496 Some(IpAddressState::Assigned) => {
1497 error!(
1515 "NA from {src_ip} with target address {target_address} that is also \
1516 assigned on device {device_id:?}",
1517 );
1518 }
1519 Some(IpAddressState::Tentative) => {
1520 return;
1523 }
1524 Some(IpAddressState::Unavailable) | None => {
1525 }
1529 }
1530
1531 let link_addr = p.body().iter().find_map(|o| o.target_link_layer_address());
1532
1533 NudIpHandler::handle_neighbor_confirmation(
1534 core_ctx,
1535 bindings_ctx,
1536 &device_id,
1537 target_address.into_specified(),
1538 link_addr,
1539 ConfirmationFlags {
1540 solicited_flag: p.message().solicited_flag(),
1541 override_flag: p.message().override_flag(),
1542 },
1543 );
1544 }
1545 NdpPacket::RouterAdvertisement(ref p) => {
1546 let src_ip = match src_ip {
1559 Ipv6SourceAddr::Unicast(ip) => match LinkLocalUnicastAddr::new(*ip) {
1560 Some(ip) => ip,
1561 None => return,
1562 },
1563 Ipv6SourceAddr::Unspecified => return,
1564 };
1565
1566 let ra = p.message();
1567 debug!("received router advertisement from {:?}: {:?}", src_ip, ra);
1568 core_ctx.counters().rx.router_advertisement.increment();
1569
1570 if let Some(retransmit_timer) = ra.retransmit_timer() {
1577 Ipv6DeviceHandler::set_discovered_retrans_timer(
1578 core_ctx,
1579 bindings_ctx,
1580 &device_id,
1581 retransmit_timer,
1582 );
1583 }
1584
1585 if let Some(hop_limit) = ra.current_hop_limit() {
1592 trace!(
1593 "receive_ndp_packet: NDP RA: updating device's hop limit to {:?} for router: {:?}",
1594 ra.current_hop_limit(),
1595 src_ip
1596 );
1597 IpDeviceHandler::set_default_hop_limit(core_ctx, &device_id, hop_limit);
1598 }
1599
1600 Ipv6DeviceHandler::update_discovered_ipv6_route(
1602 core_ctx,
1603 bindings_ctx,
1604 &device_id,
1605 Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) },
1606 p.message().router_lifetime().map(NonZeroNdpLifetime::Finite),
1607 );
1608
1609 for option in p.body().iter() {
1610 match option {
1611 NdpOption::TargetLinkLayerAddress(_)
1612 | NdpOption::RedirectedHeader { .. }
1613 | NdpOption::RecursiveDnsServer(_)
1614 | NdpOption::Nonce(_) => {}
1615 NdpOption::SourceLinkLayerAddress(addr) => {
1616 debug!("processing SourceLinkLayerAddress option in RA: {:?}", addr);
1617 NudIpHandler::handle_neighbor_probe(
1643 core_ctx,
1644 bindings_ctx,
1645 &device_id,
1646 {
1647 let src_ip: UnicastAddr<_> = src_ip.into_addr();
1648 src_ip.into_specified()
1649 },
1650 addr,
1651 );
1652 }
1653 NdpOption::PrefixInformation(prefix_info) => {
1654 debug!("processing Prefix Information option in RA: {:?}", prefix_info);
1655 if prefix_info.prefix().is_link_local() {
1673 continue;
1674 }
1675
1676 let subnet = match prefix_info.subnet() {
1677 Ok(subnet) => subnet,
1678 Err(err) => match err {
1679 SubnetError::PrefixTooLong | SubnetError::HostBitsSet => continue,
1680 },
1681 };
1682
1683 match UnicastAddr::new(subnet.network()) {
1684 Some(UnicastAddr { .. }) => {}
1685 None => continue,
1686 }
1687
1688 let valid_lifetime = prefix_info.valid_lifetime();
1689
1690 if prefix_info.on_link_flag() {
1691 Ipv6DeviceHandler::update_discovered_ipv6_route(
1693 core_ctx,
1694 bindings_ctx,
1695 &device_id,
1696 Ipv6DiscoveredRoute { subnet, gateway: None },
1697 valid_lifetime,
1698 )
1699 }
1700
1701 if prefix_info.autonomous_address_configuration_flag() {
1702 Ipv6DeviceHandler::apply_slaac_update(
1703 core_ctx,
1704 bindings_ctx,
1705 &device_id,
1706 subnet,
1707 prefix_info.preferred_lifetime(),
1708 valid_lifetime,
1709 );
1710 }
1711 }
1712 NdpOption::RouteInformation(rio) => {
1713 debug!("processing Route Information option in RA: {:?}", rio);
1714 Ipv6DeviceHandler::update_discovered_ipv6_route(
1716 core_ctx,
1717 bindings_ctx,
1718 &device_id,
1719 Ipv6DiscoveredRoute {
1720 subnet: rio.prefix().clone(),
1721 gateway: Some(src_ip),
1722 },
1723 rio.route_lifetime(),
1724 )
1725 }
1726 NdpOption::Mtu(mtu) => {
1727 debug!("processing MTU option in RA: {:?}", mtu);
1728 Ipv6DeviceHandler::set_link_mtu(core_ctx, &device_id, Mtu::new(mtu));
1732 }
1733 }
1734 }
1735
1736 bindings_ctx.on_event(RouterAdvertisementEvent {
1737 options_bytes: Box::from(p.body().bytes()),
1738 source: **src_ip,
1739 device: device_id.clone(),
1740 });
1741 }
1742 }
1743}
1744
1745impl<
1746 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1747 CC: InnerIcmpv6Context<BC>
1748 + InnerIcmpContext<Ipv6, BC>
1749 + Ipv6DeviceHandler<BC>
1750 + IpDeviceHandler<Ipv6, BC>
1751 + IpDeviceIngressStateContext<Ipv6>
1752 + PmtuHandler<Ipv6, BC>
1753 + NudIpHandler<Ipv6, BC>
1754 + IpLayerHandler<Ipv6, BC>
1755 + CounterContext<IcmpRxCounters<Ipv6>>
1756 + CounterContext<IcmpTxCounters<Ipv6>>
1757 + CounterContext<NdpCounters>,
1758> IpTransportContext<Ipv6, BC, CC> for IcmpIpTransportContext
1759{
1760 type EarlyDemuxSocket = Never;
1761
1762 fn early_demux<B: ParseBuffer>(
1763 _core_ctx: &mut CC,
1764 _device: &CC::DeviceId,
1765 _src_ip: Ipv6Addr,
1766 _dst_ip: Ipv6Addr,
1767 _buffer: B,
1768 ) -> Option<Self::EarlyDemuxSocket> {
1769 None
1770 }
1771
1772 fn receive_icmp_error(
1773 core_ctx: &mut CC,
1774 bindings_ctx: &mut BC,
1775 device: &CC::DeviceId,
1776 original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1777 original_dst_ip: SpecifiedAddr<Ipv6Addr>,
1778 original_body: &[u8],
1779 err: Icmpv6ErrorCode,
1780 ) {
1781 receive_ip_transport_icmp_error(
1782 core_ctx,
1783 bindings_ctx,
1784 device,
1785 original_src_ip,
1786 original_dst_ip,
1787 original_body,
1788 err,
1789 )
1790 }
1791
1792 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
1793 core_ctx: &mut CC,
1794 bindings_ctx: &mut BC,
1795 device: &CC::DeviceId,
1796 src_ip: Ipv6SourceAddr,
1797 dst_ip: SpecifiedAddr<Ipv6Addr>,
1798 mut buffer: B,
1799 info: &LocalDeliveryPacketInfo<Ipv6, H>,
1800 _early_demux_socket: Option<Never>,
1801 ) -> Result<(), (B, TransportReceiveError)> {
1802 let LocalDeliveryPacketInfo { meta, header_info, marks } = info;
1803 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
1804 if let Some(delivery) = transparent_override {
1805 unreachable!(
1806 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
1807 transparent proxy rules can only be configured for TCP and UDP packets"
1808 );
1809 }
1810
1811 trace!(
1812 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet({:?}, {})",
1813 src_ip, dst_ip
1814 );
1815
1816 let packet = match buffer
1817 .parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(src_ip.get(), dst_ip))
1818 {
1819 Ok(packet) => packet,
1820 Err(_) => return Ok(()), };
1822
1823 match packet {
1824 Icmpv6Packet::EchoRequest(echo_request) => {
1825 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_request.increment();
1826
1827 if let Some(src_ip) = SocketIpAddr::new_from_ipv6_source(src_ip) {
1828 match SocketIpAddr::try_from(dst_ip) {
1829 Ok(dst_ip) => {
1830 let req = *echo_request.message();
1831 let code = echo_request.code();
1832 let (local_ip, remote_ip) = (dst_ip, src_ip);
1833 debug!(
1834 "replying to ICMP echo request from {remote_ip}: id={}, seq={}",
1835 req.id(),
1836 req.seq()
1837 );
1838 send_icmp_reply(
1839 core_ctx,
1840 bindings_ctx,
1841 device,
1842 remote_ip,
1843 local_ip,
1844 |src_ip| {
1845 IcmpPacketBuilder::<Ipv6, _>::new(
1846 src_ip,
1847 remote_ip.addr(),
1848 code,
1849 req.reply(),
1850 )
1851 .wrap_body(buffer)
1852 },
1853 &WithMarks(marks),
1854 );
1855 }
1856 Err(AddrIsMappedError {}) => {
1857 trace!(
1858 "IpTransportContext<Ipv6>::receive_ip_packet: Received echo request with an ipv4-mapped-ipv6 destination address"
1859 );
1860 }
1861 }
1862 } else {
1863 trace!(
1864 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received echo request with an unspecified source address"
1865 );
1866 }
1867 }
1868 Icmpv6Packet::EchoReply(echo_reply) => {
1869 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_reply.increment();
1870 trace!(
1871 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received an EchoReply message"
1872 );
1873 let parse_metadata = echo_reply.parse_metadata();
1874 buffer.undo_parse(parse_metadata);
1875 return <CC::EchoTransportContext
1876 as IpTransportContext<Ipv6, BC, CC>>::receive_ip_packet(
1877 core_ctx,
1878 bindings_ctx,
1879 device,
1880 src_ip,
1881 dst_ip,
1882 buffer,
1883 info,
1884 None
1885 );
1886 }
1887 Icmpv6Packet::Ndp(packet) => receive_ndp_packet(
1888 core_ctx,
1889 bindings_ctx,
1890 device,
1891 src_ip,
1892 dst_ip,
1893 packet,
1894 header_info,
1895 ),
1896 Icmpv6Packet::PacketTooBig(packet_too_big) => {
1897 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
1898 .packet_too_big
1899 .increment();
1900 trace!(
1901 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received a Packet Too Big message"
1902 );
1903 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
1904 let mtu = core_ctx.update_pmtu_if_less(
1914 bindings_ctx,
1915 dst_ip.get(),
1916 src_ip.get(),
1917 Mtu::new(packet_too_big.message().mtu()),
1918 );
1919 if let Some(mtu) = mtu {
1920 receive_icmpv6_error(
1921 core_ctx,
1922 bindings_ctx,
1923 device,
1924 &packet_too_big,
1925 Icmpv6ErrorCode::PacketTooBig(mtu),
1926 );
1927 }
1928 }
1929 }
1930 Icmpv6Packet::Mld(packet) => {
1931 core_ctx.receive_mld_packet(
1932 bindings_ctx,
1933 &device,
1934 src_ip,
1935 dst_ip,
1936 packet,
1937 header_info,
1938 );
1939 }
1940 Icmpv6Packet::DestUnreachable(dest_unreachable) => {
1941 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
1942 .dest_unreachable
1943 .increment_code(dest_unreachable.code());
1944 receive_icmpv6_error(
1945 core_ctx,
1946 bindings_ctx,
1947 device,
1948 &dest_unreachable,
1949 Icmpv6ErrorCode::DestUnreachable(dest_unreachable.code()),
1950 )
1951 }
1952 Icmpv6Packet::TimeExceeded(time_exceeded) => {
1953 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
1954 .time_exceeded
1955 .increment_code(time_exceeded.code());
1956 receive_icmpv6_error(
1957 core_ctx,
1958 bindings_ctx,
1959 device,
1960 &time_exceeded,
1961 Icmpv6ErrorCode::TimeExceeded(time_exceeded.code()),
1962 )
1963 }
1964 Icmpv6Packet::ParameterProblem(parameter_problem) => {
1965 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
1966 .parameter_problem
1967 .increment_code(parameter_problem.code());
1968 receive_icmpv6_error(
1969 core_ctx,
1970 bindings_ctx,
1971 device,
1972 ¶meter_problem,
1973 Icmpv6ErrorCode::ParameterProblem(parameter_problem.code()),
1974 )
1975 }
1976 }
1977
1978 Ok(())
1979 }
1980}
1981
1982#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1983struct WithMarks<'a>(&'a Marks);
1984
1985impl<'a> OptionDelegationMarker for WithMarks<'a> {}
1986
1987impl<'a, I: IpExt> DelegatedRouteResolutionOptions<I> for WithMarks<'a> {
1988 fn marks(&self) -> &Marks {
1989 let Self(marks) = self;
1990 marks
1991 }
1992}
1993
1994impl<'a, I: IpExt> DelegatedSendOptions<I> for WithMarks<'a> {}
1995
1996fn send_icmp_reply<I, BC, CC, S, F, O>(
2007 core_ctx: &mut CC,
2008 bindings_ctx: &mut BC,
2009 device: &CC::DeviceId,
2010 original_src_ip: SocketIpAddr<I::Addr>,
2011 original_dst_ip: SocketIpAddr<I::Addr>,
2012 get_body_from_src_ip: F,
2013 ip_options: &O,
2014) where
2015 I: IpExt + FilterIpExt + IcmpCountersIpExt,
2016 CC: IpSocketHandler<I, BC> + DeviceIdContext<AnyDevice> + CounterContext<IcmpTxCounters<I>>,
2017 BC: TxMetadataBindingsTypes,
2018 S: DynamicTransportSerializer<I>,
2019 F: FnOnce(SpecifiedAddr<I::Addr>) -> S,
2020 O: SendOptions<I> + RouteResolutionOptions<I>,
2021{
2022 trace!("send_icmp_reply({:?}, {}, {})", device, original_src_ip, original_dst_ip);
2023 core_ctx.counters().reply.increment();
2024 let tx_metadata: BC::TxMetadata = Default::default();
2025
2026 let egress_device = (original_dst_ip.as_ref().is_multicast()
2030 || original_dst_ip.as_ref().must_have_zone())
2031 .then_some(EitherDeviceId::Strong(device));
2032
2033 core_ctx
2034 .send_oneshot_ip_packet_with_dyn_serializer(
2035 bindings_ctx,
2036 IpSocketArgs {
2037 device: egress_device,
2038 local_ip: IpDeviceAddr::new_from_socket_ip_addr(original_dst_ip),
2039 remote_ip: original_src_ip,
2040 proto: I::ICMP_IP_PROTO,
2041 options: ip_options,
2042 },
2043 tx_metadata,
2044 |src_ip| get_body_from_src_ip(src_ip.into()),
2045 )
2046 .unwrap_or_else(|err| {
2047 debug!("failed to send ICMP reply: {}", err);
2048 })
2049}
2050
2051fn receive_icmpv4_error<
2056 BC: IcmpBindingsContext,
2057 CC: InnerIcmpv4Context<BC>,
2058 B: SplitByteSlice,
2059 M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>,
2060>(
2061 core_ctx: &mut CC,
2062 bindings_ctx: &mut BC,
2063 device: &CC::DeviceId,
2064 packet: &IcmpPacket<Ipv4, B, M>,
2065 err: Icmpv4ErrorCode,
2066) {
2067 packet.with_original_packet(|res| match res {
2068 Ok(original_packet) => {
2069 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2070 Some(ip) => ip,
2071 None => {
2072 trace!("receive_icmpv4_error: Got ICMP error message whose original IPv4 packet contains an unspecified destination address; discarding");
2073 return;
2074 },
2075 };
2076 InnerIcmpContext::receive_icmp_error(
2077 core_ctx,
2078 bindings_ctx,
2079 device,
2080 SpecifiedAddr::new(original_packet.src_ip()),
2081 dst_ip,
2082 original_packet.proto(),
2083 original_packet.body().into_inner(),
2084 err,
2085 );
2086 }
2087 Err(_) => debug!(
2088 "receive_icmpv4_error: Got ICMP error message with unparsable original IPv4 packet"
2089 ),
2090 })
2091}
2092
2093fn receive_icmpv6_error<
2098 BC: IcmpBindingsContext,
2099 CC: InnerIcmpv6Context<BC>,
2100 B: SplitByteSlice,
2101 M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>,
2102>(
2103 core_ctx: &mut CC,
2104 bindings_ctx: &mut BC,
2105 device: &CC::DeviceId,
2106 packet: &IcmpPacket<Ipv6, B, M>,
2107 err: Icmpv6ErrorCode,
2108) {
2109 packet.with_original_packet(|res| match res {
2110 Ok(original_packet) => {
2111 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2112 Some(ip)=>ip,
2113 None => {
2114 trace!("receive_icmpv6_error: Got ICMP error message whose original IPv6 packet contains an unspecified destination address; discarding");
2115 return;
2116 },
2117 };
2118 match original_packet.body_proto() {
2119 Ok((body, proto)) => {
2120 InnerIcmpContext::receive_icmp_error(
2121 core_ctx,
2122 bindings_ctx,
2123 device,
2124 SpecifiedAddr::new(original_packet.src_ip()),
2125 dst_ip,
2126 proto,
2127 body.into_inner(),
2128 err,
2129 );
2130 }
2131 Err(ExtHdrParseError) => {
2132 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");
2133 return;
2136 }
2137 }
2138 }
2139 Err(_body) => debug!(
2140 "receive_icmpv6_error: Got ICMPv6 error message with unparsable original IPv6 packet"
2141 ),
2142 })
2143}
2144
2145pub fn send_icmpv4_host_unreachable<
2163 B: BufferMut,
2164 BC: IcmpBindingsContext,
2165 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2166>(
2167 core_ctx: &mut CC,
2168 bindings_ctx: &mut BC,
2169 device: Option<&CC::DeviceId>,
2170 frame_dst: Option<FrameDestination>,
2171 src_ip: SocketIpAddr<Ipv4Addr>,
2172 dst_ip: SocketIpAddr<Ipv4Addr>,
2173 original_packet: B,
2174 header_len: usize,
2175 fragment_type: Ipv4FragmentType,
2176 marks: &Marks,
2177) {
2178 core_ctx.counters().address_unreachable.increment();
2179
2180 send_icmpv4_dest_unreachable(
2181 core_ctx,
2182 bindings_ctx,
2183 device,
2184 frame_dst,
2185 src_ip,
2186 dst_ip,
2187 Icmpv4DestUnreachableCode::DestHostUnreachable,
2188 original_packet,
2189 header_len,
2190 fragment_type,
2191 marks,
2192 );
2193}
2194
2195pub fn send_icmpv6_address_unreachable<
2206 B: BufferMut,
2207 BC: IcmpBindingsContext,
2208 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2209>(
2210 core_ctx: &mut CC,
2211 bindings_ctx: &mut BC,
2212 device: Option<&CC::DeviceId>,
2213 frame_dst: Option<FrameDestination>,
2214 src_ip: SocketIpAddr<Ipv6Addr>,
2215 dst_ip: SocketIpAddr<Ipv6Addr>,
2216 original_packet: B,
2217 marks: &Marks,
2218) {
2219 core_ctx.counters().address_unreachable.increment();
2220
2221 send_icmpv6_dest_unreachable(
2222 core_ctx,
2223 bindings_ctx,
2224 device,
2225 frame_dst,
2226 src_ip,
2227 dst_ip,
2228 Icmpv6DestUnreachableCode::AddrUnreachable,
2229 original_packet,
2230 marks,
2231 );
2232}
2233
2234pub(crate) fn send_icmpv4_protocol_unreachable<
2246 B: BufferMut,
2247 BC: IcmpBindingsContext,
2248 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2249>(
2250 core_ctx: &mut CC,
2251 bindings_ctx: &mut BC,
2252 device: &CC::DeviceId,
2253 frame_dst: Option<FrameDestination>,
2254 src_ip: SocketIpAddr<Ipv4Addr>,
2255 dst_ip: SocketIpAddr<Ipv4Addr>,
2256 original_packet: B,
2257 header_len: usize,
2258 marks: &Marks,
2259) {
2260 core_ctx.counters().protocol_unreachable.increment();
2261
2262 send_icmpv4_dest_unreachable(
2263 core_ctx,
2264 bindings_ctx,
2265 Some(device),
2266 frame_dst,
2267 src_ip,
2268 dst_ip,
2269 Icmpv4DestUnreachableCode::DestProtocolUnreachable,
2270 original_packet,
2271 header_len,
2272 Ipv4FragmentType::InitialFragment,
2278 marks,
2279 );
2280}
2281
2282pub(crate) fn send_icmpv6_protocol_unreachable<
2292 B: BufferMut,
2293 BC: IcmpBindingsContext,
2294 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2295>(
2296 core_ctx: &mut CC,
2297 bindings_ctx: &mut BC,
2298 device: &CC::DeviceId,
2299 frame_dst: Option<FrameDestination>,
2300 src_ip: SocketIpAddr<Ipv6Addr>,
2301 dst_ip: SocketIpAddr<Ipv6Addr>,
2302 original_packet: B,
2303 header_len: usize,
2304 marks: &Marks,
2305) {
2306 core_ctx.counters().protocol_unreachable.increment();
2307
2308 send_icmpv6_parameter_problem(
2309 core_ctx,
2310 bindings_ctx,
2311 device,
2312 frame_dst,
2313 src_ip,
2314 dst_ip,
2315 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2316 Icmpv6ParameterProblem::new(header_len as u32),
2330 original_packet,
2331 false,
2332 marks,
2333 );
2334}
2335
2336pub(crate) fn send_icmpv4_port_unreachable<
2348 B: BufferMut,
2349 BC: IcmpBindingsContext,
2350 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2351>(
2352 core_ctx: &mut CC,
2353 bindings_ctx: &mut BC,
2354 device: &CC::DeviceId,
2355 frame_dst: Option<FrameDestination>,
2356 src_ip: SocketIpAddr<Ipv4Addr>,
2357 dst_ip: SocketIpAddr<Ipv4Addr>,
2358 original_packet: B,
2359 header_len: usize,
2360 marks: &Marks,
2361) {
2362 core_ctx.counters().port_unreachable.increment();
2363
2364 send_icmpv4_dest_unreachable(
2365 core_ctx,
2366 bindings_ctx,
2367 Some(device),
2368 frame_dst,
2369 src_ip,
2370 dst_ip,
2371 Icmpv4DestUnreachableCode::DestPortUnreachable,
2372 original_packet,
2373 header_len,
2374 Ipv4FragmentType::InitialFragment,
2380 marks,
2381 );
2382}
2383
2384pub(crate) fn send_icmpv6_port_unreachable<
2393 B: BufferMut,
2394 BC: IcmpBindingsContext,
2395 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2396>(
2397 core_ctx: &mut CC,
2398 bindings_ctx: &mut BC,
2399 device: &CC::DeviceId,
2400 frame_dst: Option<FrameDestination>,
2401 src_ip: SocketIpAddr<Ipv6Addr>,
2402 dst_ip: SocketIpAddr<Ipv6Addr>,
2403 original_packet: B,
2404 marks: &Marks,
2405) {
2406 core_ctx.counters().port_unreachable.increment();
2407
2408 send_icmpv6_dest_unreachable(
2409 core_ctx,
2410 bindings_ctx,
2411 Some(device),
2412 frame_dst,
2413 src_ip,
2414 dst_ip,
2415 Icmpv6DestUnreachableCode::PortUnreachable,
2416 original_packet,
2417 marks,
2418 );
2419}
2420
2421pub(crate) fn send_icmpv4_net_unreachable<
2433 B: BufferMut,
2434 BC: IcmpBindingsContext,
2435 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2436>(
2437 core_ctx: &mut CC,
2438 bindings_ctx: &mut BC,
2439 device: &CC::DeviceId,
2440 frame_dst: Option<FrameDestination>,
2441 src_ip: SocketIpAddr<Ipv4Addr>,
2442 dst_ip: SocketIpAddr<Ipv4Addr>,
2443 proto: Ipv4Proto,
2444 original_packet: B,
2445 header_len: usize,
2446 fragment_type: Ipv4FragmentType,
2447 marks: &Marks,
2448) {
2449 core_ctx.counters().net_unreachable.increment();
2450
2451 if is_icmp_error_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..]) {
2454 return;
2455 }
2456
2457 send_icmpv4_dest_unreachable(
2458 core_ctx,
2459 bindings_ctx,
2460 Some(device),
2461 frame_dst,
2462 src_ip,
2463 dst_ip,
2464 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
2465 original_packet,
2466 header_len,
2467 fragment_type,
2468 marks,
2469 );
2470}
2471
2472pub(crate) fn send_icmpv6_net_unreachable<
2483 B: BufferMut,
2484 BC: IcmpBindingsContext,
2485 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2486>(
2487 core_ctx: &mut CC,
2488 bindings_ctx: &mut BC,
2489 device: &CC::DeviceId,
2490 frame_dst: Option<FrameDestination>,
2491 src_ip: SocketIpAddr<Ipv6Addr>,
2492 dst_ip: SocketIpAddr<Ipv6Addr>,
2493 proto: Ipv6Proto,
2494 original_packet: B,
2495 header_len: usize,
2496 marks: &Marks,
2497) {
2498 core_ctx.counters().net_unreachable.increment();
2499
2500 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2503 return;
2504 }
2505
2506 send_icmpv6_dest_unreachable(
2507 core_ctx,
2508 bindings_ctx,
2509 Some(device),
2510 frame_dst,
2511 src_ip,
2512 dst_ip,
2513 Icmpv6DestUnreachableCode::NoRoute,
2514 original_packet,
2515 marks,
2516 );
2517}
2518
2519pub(crate) fn send_icmpv4_ttl_expired<
2531 B: BufferMut,
2532 BC: IcmpBindingsContext,
2533 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2534>(
2535 core_ctx: &mut CC,
2536 bindings_ctx: &mut BC,
2537 device: &CC::DeviceId,
2538 frame_dst: Option<FrameDestination>,
2539 src_ip: SocketIpAddr<Ipv4Addr>,
2540 dst_ip: SocketIpAddr<Ipv4Addr>,
2541 proto: Ipv4Proto,
2542 original_packet: B,
2543 header_len: usize,
2544 fragment_type: Ipv4FragmentType,
2545 marks: &Marks,
2546) {
2547 let code = Icmpv4TimeExceededCode::TtlExpired;
2548 core_ctx.counters().time_exceeded.increment_code(code);
2549
2550 if is_icmp_error_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..]) {
2553 return;
2554 }
2555
2556 send_icmpv4_error_message(
2557 core_ctx,
2558 bindings_ctx,
2559 Some(device),
2560 frame_dst,
2561 src_ip,
2562 dst_ip,
2563 Icmpv4ErrorMessage::TimeExceeded { message: IcmpTimeExceeded::default(), code },
2564 original_packet,
2565 header_len,
2566 fragment_type,
2567 marks,
2568 )
2569}
2570
2571pub(crate) fn send_icmpv6_ttl_expired<
2582 B: BufferMut,
2583 BC: IcmpBindingsContext,
2584 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2585>(
2586 core_ctx: &mut CC,
2587 bindings_ctx: &mut BC,
2588 device: &CC::DeviceId,
2589 frame_dst: Option<FrameDestination>,
2590 src_ip: SocketIpAddr<Ipv6Addr>,
2591 dst_ip: SocketIpAddr<Ipv6Addr>,
2592 proto: Ipv6Proto,
2593 original_packet: B,
2594 header_len: usize,
2595 marks: &Marks,
2596) {
2597 let code = Icmpv6TimeExceededCode::HopLimitExceeded;
2598 core_ctx.counters().time_exceeded.increment_code(code);
2599
2600 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2603 return;
2604 }
2605
2606 send_icmpv6_error_message(
2607 core_ctx,
2608 bindings_ctx,
2609 Some(device),
2610 frame_dst,
2611 src_ip,
2612 dst_ip,
2613 Icmpv6ErrorMessage::TimeExceeded { message: IcmpTimeExceeded::default(), code },
2614 original_packet,
2615 false, marks,
2617 )
2618}
2619
2620pub(crate) fn send_icmpv6_packet_too_big<
2630 B: BufferMut,
2631 BC: IcmpBindingsContext,
2632 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2633>(
2634 core_ctx: &mut CC,
2635 bindings_ctx: &mut BC,
2636 device: &CC::DeviceId,
2637 frame_dst: Option<FrameDestination>,
2638 src_ip: SocketIpAddr<Ipv6Addr>,
2639 dst_ip: SocketIpAddr<Ipv6Addr>,
2640 proto: Ipv6Proto,
2641 mtu: Mtu,
2642 original_packet: B,
2643 header_len: usize,
2644 marks: &Marks,
2645) {
2646 core_ctx.counters().packet_too_big.increment();
2647 if is_icmp_error_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..]) {
2650 return;
2651 }
2652
2653 send_icmpv6_error_message(
2654 core_ctx,
2655 bindings_ctx,
2656 Some(device),
2657 frame_dst,
2658 src_ip,
2659 dst_ip,
2660 Icmpv6ErrorMessage::PacketTooBig {
2661 message: Icmpv6PacketTooBig::new(mtu.into()),
2662 code: IcmpZeroCode,
2663 },
2664 original_packet,
2665 true, marks,
2685 )
2686}
2687
2688pub(crate) fn send_icmpv4_parameter_problem<
2689 B: BufferMut,
2690 BC: IcmpBindingsContext,
2691 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2692>(
2693 core_ctx: &mut CC,
2694 bindings_ctx: &mut BC,
2695 device: &CC::DeviceId,
2696 frame_dst: Option<FrameDestination>,
2697 src_ip: SocketIpAddr<Ipv4Addr>,
2698 dst_ip: SocketIpAddr<Ipv4Addr>,
2699 code: Icmpv4ParameterProblemCode,
2700 parameter_problem: Icmpv4ParameterProblem,
2701 original_packet: B,
2702 header_len: usize,
2703 fragment_type: Ipv4FragmentType,
2704 marks: &Marks,
2705) {
2706 core_ctx.counters().parameter_problem.increment_code(code);
2707
2708 send_icmpv4_error_message(
2709 core_ctx,
2710 bindings_ctx,
2711 Some(device),
2712 frame_dst,
2713 src_ip,
2714 dst_ip,
2715 Icmpv4ErrorMessage::ParameterProblem { message: parameter_problem, code },
2716 original_packet,
2717 header_len,
2718 fragment_type,
2719 marks,
2720 )
2721}
2722
2723pub(crate) fn send_icmpv6_parameter_problem<
2734 B: BufferMut,
2735 BC: IcmpBindingsContext,
2736 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2737>(
2738 core_ctx: &mut CC,
2739 bindings_ctx: &mut BC,
2740 device: &CC::DeviceId,
2741 frame_dst: Option<FrameDestination>,
2742 src_ip: SocketIpAddr<Ipv6Addr>,
2743 dst_ip: SocketIpAddr<Ipv6Addr>,
2744 code: Icmpv6ParameterProblemCode,
2745 parameter_problem: Icmpv6ParameterProblem,
2746 original_packet: B,
2747 allow_dst_multicast: bool,
2748 marks: &Marks,
2749) {
2750 assert!(!allow_dst_multicast || code == Icmpv6ParameterProblemCode::UnrecognizedIpv6Option);
2755
2756 core_ctx.counters().parameter_problem.increment_code(code);
2757
2758 send_icmpv6_error_message(
2759 core_ctx,
2760 bindings_ctx,
2761 Some(device),
2762 frame_dst,
2763 src_ip,
2764 dst_ip,
2765 Icmpv6ErrorMessage::ParameterProblem { message: parameter_problem, code },
2766 original_packet,
2767 allow_dst_multicast,
2768 marks,
2769 )
2770}
2771
2772fn send_icmpv4_dest_unreachable<
2773 B: BufferMut,
2774 BC: IcmpBindingsContext,
2775 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2776>(
2777 core_ctx: &mut CC,
2778 bindings_ctx: &mut BC,
2779 device: Option<&CC::DeviceId>,
2780 frame_dst: Option<FrameDestination>,
2781 src_ip: SocketIpAddr<Ipv4Addr>,
2782 dst_ip: SocketIpAddr<Ipv4Addr>,
2783 code: Icmpv4DestUnreachableCode,
2784 original_packet: B,
2785 header_len: usize,
2786 fragment_type: Ipv4FragmentType,
2787 marks: &Marks,
2788) {
2789 core_ctx.counters().dest_unreachable.increment_code(code);
2790 send_icmpv4_error_message(
2791 core_ctx,
2792 bindings_ctx,
2793 device,
2794 frame_dst,
2795 src_ip,
2796 dst_ip,
2797 Icmpv4ErrorMessage::DestUnreachable { message: IcmpDestUnreachable::default(), code },
2798 original_packet,
2799 header_len,
2800 fragment_type,
2801 marks,
2802 )
2803}
2804
2805fn send_icmpv6_dest_unreachable<
2806 B: BufferMut,
2807 BC: IcmpBindingsContext,
2808 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2809>(
2810 core_ctx: &mut CC,
2811 bindings_ctx: &mut BC,
2812 device: Option<&CC::DeviceId>,
2813 frame_dst: Option<FrameDestination>,
2814 src_ip: SocketIpAddr<Ipv6Addr>,
2815 dst_ip: SocketIpAddr<Ipv6Addr>,
2816 code: Icmpv6DestUnreachableCode,
2817 original_packet: B,
2818 marks: &Marks,
2819) {
2820 core_ctx.counters().dest_unreachable.increment_code(code);
2821 send_icmpv6_error_message(
2822 core_ctx,
2823 bindings_ctx,
2824 device,
2825 frame_dst,
2826 src_ip,
2827 dst_ip,
2828 Icmpv6ErrorMessage::DestUnreachable { message: IcmpDestUnreachable::default(), code },
2829 original_packet,
2830 false, marks,
2832 )
2833}
2834
2835#[allow(missing_docs)]
2838enum Icmpv4ErrorMessage {
2839 TimeExceeded {
2840 message: IcmpTimeExceeded,
2841 code: <IcmpTimeExceeded as IcmpMessage<Ipv4>>::Code,
2842 },
2843 ParameterProblem {
2844 message: Icmpv4ParameterProblem,
2845 code: <Icmpv4ParameterProblem as IcmpMessage<Ipv4>>::Code,
2846 },
2847 DestUnreachable {
2848 message: IcmpDestUnreachable,
2849 code: <IcmpDestUnreachable as IcmpMessage<Ipv4>>::Code,
2850 },
2851}
2852
2853fn send_icmpv4_error_message<
2854 B: BufferMut,
2855 BC: IcmpBindingsContext,
2856 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2857>(
2858 core_ctx: &mut CC,
2859 bindings_ctx: &mut BC,
2860 device: Option<&CC::DeviceId>,
2861 frame_dst: Option<FrameDestination>,
2862 original_src_ip: SocketIpAddr<Ipv4Addr>,
2863 original_dst_ip: SocketIpAddr<Ipv4Addr>,
2864 message: Icmpv4ErrorMessage,
2865 mut original_packet: B,
2866 header_len: usize,
2867 fragment_type: Ipv4FragmentType,
2868 marks: &Marks,
2869) {
2870 if !should_send_icmpv4_error(
2874 frame_dst,
2875 original_src_ip.into(),
2876 original_dst_ip.into(),
2877 fragment_type,
2878 ) {
2879 return;
2880 }
2881
2882 original_packet.shrink_back_to(header_len + 64);
2885
2886 let tx_metadata: BC::TxMetadata = Default::default();
2887
2888 macro_rules! send {
2889 ($message:expr, $code:expr) => {{
2890 let _ = try_send_error!(
2893 core_ctx,
2894 bindings_ctx,
2895 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2896 bindings_ctx,
2897 IpSocketArgs {
2898 device: device.map(EitherDeviceId::Strong),
2899 local_ip: None,
2900 remote_ip: original_src_ip,
2901 proto: Ipv4Proto::Icmp,
2902 options: &WithMarks(marks),
2903 },
2904 tx_metadata,
2905 |local_ip| {
2906 IcmpPacketBuilder::<Ipv4, _>::new(
2907 local_ip.addr(),
2908 original_src_ip.addr(),
2909 $code,
2910 $message,
2911 )
2912 .wrap_body(original_packet)
2913 },
2914 )
2915 );
2916 }};
2917 }
2918
2919 match message {
2920 Icmpv4ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2921 Icmpv4ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2922 Icmpv4ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2923 }
2924}
2925
2926#[allow(missing_docs)]
2929enum Icmpv6ErrorMessage {
2930 TimeExceeded {
2931 message: IcmpTimeExceeded,
2932 code: <IcmpTimeExceeded as IcmpMessage<Ipv6>>::Code,
2933 },
2934 PacketTooBig {
2935 message: Icmpv6PacketTooBig,
2936 code: <Icmpv6PacketTooBig as IcmpMessage<Ipv6>>::Code,
2937 },
2938 ParameterProblem {
2939 message: Icmpv6ParameterProblem,
2940 code: <Icmpv6ParameterProblem as IcmpMessage<Ipv6>>::Code,
2941 },
2942 DestUnreachable {
2943 message: IcmpDestUnreachable,
2944 code: <IcmpDestUnreachable as IcmpMessage<Ipv6>>::Code,
2945 },
2946}
2947
2948fn send_icmpv6_error_message<
2949 B: BufferMut,
2950 BC: IcmpBindingsContext,
2951 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2952>(
2953 core_ctx: &mut CC,
2954 bindings_ctx: &mut BC,
2955 device: Option<&CC::DeviceId>,
2956 frame_dst: Option<FrameDestination>,
2957 original_src_ip: SocketIpAddr<Ipv6Addr>,
2958 original_dst_ip: SocketIpAddr<Ipv6Addr>,
2959 message: Icmpv6ErrorMessage,
2960 original_packet: B,
2961 allow_dst_multicast: bool,
2962 marks: &Marks,
2963) {
2964 if !should_send_icmpv6_error(
2968 frame_dst,
2969 original_src_ip.into(),
2970 original_dst_ip.into(),
2971 allow_dst_multicast,
2972 ) {
2973 return;
2974 }
2975
2976 struct Icmpv6ErrorOptions<'a>(&'a Marks);
2977 impl<'a> OptionDelegationMarker for Icmpv6ErrorOptions<'a> {}
2978 impl<'a> DelegatedSendOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2979 fn mtu(&self) -> Mtu {
2980 Ipv6::MINIMUM_LINK_MTU
2981 }
2982 }
2983 impl<'a> DelegatedRouteResolutionOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2984 fn marks(&self) -> &Marks {
2985 let Self(marks) = self;
2986 marks
2987 }
2988 }
2989
2990 let tx_metadata: BC::TxMetadata = Default::default();
2991
2992 macro_rules! send {
2993 ($message:expr, $code:expr) => {{
2994 let _ = try_send_error!(
2997 core_ctx,
2998 bindings_ctx,
2999 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
3000 bindings_ctx,
3001 IpSocketArgs {
3002 device: device.map(EitherDeviceId::Strong),
3003 local_ip: None,
3004 remote_ip: original_src_ip,
3005 proto: Ipv6Proto::Icmpv6,
3006 options: &Icmpv6ErrorOptions(marks),
3007 },
3008 tx_metadata,
3009 |local_ip| {
3010 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
3011 local_ip.addr(),
3012 original_src_ip.addr(),
3013 $code,
3014 $message,
3015 );
3016
3017 icmp_builder.wrap_body(TruncatingSerializer::new(
3020 original_packet,
3021 TruncateDirection::DiscardBack,
3022 ))
3023 },
3024 )
3025 );
3026 }};
3027 }
3028
3029 match message {
3030 Icmpv6ErrorMessage::TimeExceeded { message, code } => send!(message, code),
3031 Icmpv6ErrorMessage::PacketTooBig { message, code } => send!(message, code),
3032 Icmpv6ErrorMessage::ParameterProblem { message, code } => send!(message, code),
3033 Icmpv6ErrorMessage::DestUnreachable { message, code } => send!(message, code),
3034 }
3035}
3036
3037fn should_send_icmpv4_error(
3055 frame_dst: Option<FrameDestination>,
3056 src_ip: SpecifiedAddr<Ipv4Addr>,
3057 dst_ip: SpecifiedAddr<Ipv4Addr>,
3058 fragment_type: Ipv4FragmentType,
3059) -> bool {
3060 fragment_type == Ipv4FragmentType::InitialFragment
3080 && !(dst_ip.is_multicast()
3081 || dst_ip.is_limited_broadcast()
3082 || frame_dst.is_some_and(|dst| dst.is_broadcast())
3083 || src_ip.is_loopback()
3084 || src_ip.is_limited_broadcast()
3085 || src_ip.is_multicast()
3086 || src_ip.is_class_e())
3087}
3088
3089fn should_send_icmpv6_error(
3116 frame_dst: Option<FrameDestination>,
3117 src_ip: SpecifiedAddr<Ipv6Addr>,
3118 dst_ip: SpecifiedAddr<Ipv6Addr>,
3119 allow_dst_multicast: bool,
3120) -> bool {
3121 let multicast_frame_dst = match frame_dst {
3124 Some(FrameDestination::Individual { local: _ }) | None => false,
3125 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
3126 };
3127 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
3128 return false;
3129 }
3130 if src_ip.is_loopback() || src_ip.is_multicast() {
3131 return false;
3132 }
3133 true
3134}
3135
3136fn is_icmp_error_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
3148 proto == I::ICMP_IP_PROTO
3149 && peek_message_type::<I::IcmpMessageType>(buf).map(IcmpMessageType::is_err).unwrap_or(true)
3150}
3151
3152#[cfg(any(test, feature = "testutils"))]
3154pub(crate) mod testutil {
3155 use alloc::vec::Vec;
3156 use net_types::ethernet::Mac;
3157 use net_types::ip::{Ipv6, Ipv6Addr};
3158 use packet::{Buf, InnerPacketBuilder as _, Serializer as _};
3159 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
3160 use packet_formats::icmp::ndp::{
3161 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
3162 };
3163 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
3164 use packet_formats::ip::Ipv6Proto;
3165 use packet_formats::ipv6::Ipv6PacketBuilder;
3166
3167 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
3168
3169 pub fn neighbor_advertisement_ip_packet(
3172 src_ip: Ipv6Addr,
3173 dst_ip: Ipv6Addr,
3174 router_flag: bool,
3175 solicited_flag: bool,
3176 override_flag: bool,
3177 mac: Mac,
3178 ) -> Buf<Vec<u8>> {
3179 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
3180 .into_serializer()
3181 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3182 src_ip,
3183 dst_ip,
3184 IcmpZeroCode,
3185 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
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 pub fn neighbor_solicitation_ip_packet(
3201 src_ip: Ipv6Addr,
3202 dst_ip: Ipv6Addr,
3203 target_addr: Ipv6Addr,
3204 mac: Mac,
3205 ) -> Buf<Vec<u8>> {
3206 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
3207 .into_serializer()
3208 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3209 src_ip,
3210 dst_ip,
3211 IcmpZeroCode,
3212 NeighborSolicitation::new(target_addr),
3213 ))
3214 .wrap_in(Ipv6PacketBuilder::new(
3215 src_ip,
3216 dst_ip,
3217 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
3218 Ipv6Proto::Icmpv6,
3219 ))
3220 .serialize_vec_outer()
3221 .unwrap()
3222 .unwrap_b()
3223 }
3224}
3225
3226#[cfg(test)]
3227mod tests {
3228 use alloc::vec;
3229 use alloc::vec::Vec;
3230 use packet_formats::icmp::ndp::options::NdpNonce;
3231
3232 use core::fmt::Debug;
3233 use core::time::Duration;
3234
3235 use net_types::ip::Subnet;
3236 use netstack3_base::testutil::{
3237 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId,
3238 TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt, set_logger_for_test,
3239 };
3240 use netstack3_base::{CtxPair, Uninstantiable};
3241 use netstack3_filter::TransportPacketSerializer;
3242 use packet::{Buf, EmptyBuf};
3243 use packet_formats::icmp::mld::MldPacket;
3244 use packet_formats::ip::IpProto;
3245 use packet_formats::utils::NonZeroDuration;
3246
3247 use super::*;
3248 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
3249 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
3250 use crate::internal::socket::{
3251 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
3252 };
3253 use crate::socket::RouteResolutionOptions;
3254
3255 use test_util::assert_geq;
3256
3257 pub(super) trait IcmpTestIpExt:
3258 TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt
3259 {
3260 }
3261 impl<I: TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt> IcmpTestIpExt for I {}
3262
3263 type InnerIpSocketCtx<I> = FakeCoreCtx<
3265 FakeIpSocketCtx<I, FakeDeviceId>,
3266 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
3267 FakeDeviceId,
3268 >;
3269
3270 pub(super) struct FakeIcmpCoreCtx<I: IcmpTestIpExt> {
3272 ip_socket_ctx: InnerIpSocketCtx<I>,
3273 icmp: FakeIcmpCoreCtxState<I>,
3274 }
3275
3276 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
3278 (),
3279 RouterAdvertisementEvent<FakeDeviceId>,
3280 FakeIcmpBindingsCtxState<I>,
3281 (),
3282 >;
3283
3284 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
3288
3289 pub(super) struct FakeIcmpCoreCtxState<I: IcmpTestIpExt> {
3290 error_send_bucket: TokenBucket<FakeInstant>,
3291 receive_icmp_error: Vec<I::ErrorCode>,
3292 rx_counters: IcmpRxCounters<I>,
3293 tx_counters: IcmpTxCounters<I>,
3294 ndp_counters: NdpCounters,
3295 }
3296
3297 impl<I: IcmpTestIpExt> FakeIcmpCoreCtx<I> {
3298 fn with_errors_per_second(errors_per_second: u64) -> Self {
3299 Self {
3300 icmp: FakeIcmpCoreCtxState {
3301 error_send_bucket: TokenBucket::new(errors_per_second),
3302 receive_icmp_error: Default::default(),
3303 rx_counters: Default::default(),
3304 tx_counters: Default::default(),
3305 ndp_counters: Default::default(),
3306 },
3307 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
3308 core::iter::once(FakeDeviceConfig {
3309 device: FakeDeviceId,
3310 local_ips: vec![I::TEST_ADDRS.local_ip],
3311 remote_ips: vec![I::TEST_ADDRS.remote_ip],
3312 }),
3313 )),
3314 }
3315 }
3316 }
3317
3318 impl<I: IcmpTestIpExt> Default for FakeIcmpCoreCtx<I> {
3319 fn default() -> Self {
3320 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
3321 }
3322 }
3323
3324 impl<I: IcmpTestIpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
3325 type DeviceId = FakeDeviceId;
3326 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
3327 }
3328
3329 impl<I: IcmpTestIpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
3330 impl<I: IcmpTestIpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
3331
3332 impl<I: IcmpTestIpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
3333 fn counters(&self) -> &IcmpRxCounters<I> {
3334 &self.icmp.rx_counters
3335 }
3336 }
3337
3338 impl<I: IcmpTestIpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
3339 fn counters(&self) -> &IcmpTxCounters<I> {
3340 &self.icmp.tx_counters
3341 }
3342 }
3343
3344 impl<I: IcmpTestIpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
3345 fn counters(&self) -> &NdpCounters {
3346 &self.icmp.ndp_counters
3347 }
3348 }
3349
3350 pub enum FakeEchoIpTransportContext {}
3351
3352 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
3353
3354 impl<I: IcmpTestIpExt> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
3355 for FakeEchoIpTransportContext
3356 {
3357 type EarlyDemuxSocket = Never;
3358
3359 fn early_demux<B: ParseBuffer>(
3360 _core_ctx: &mut FakeIcmpCoreCtx<I>,
3361 _device: &FakeDeviceId,
3362 _src_ip: I::Addr,
3363 _dst_ip: I::Addr,
3364 _buffer: B,
3365 ) -> Option<Self::EarlyDemuxSocket> {
3366 None
3367 }
3368
3369 fn receive_icmp_error(
3370 core_ctx: &mut FakeIcmpCoreCtx<I>,
3371 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3372 _device: &FakeDeviceId,
3373 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3374 _original_dst_ip: SpecifiedAddr<I::Addr>,
3375 _original_body: &[u8],
3376 _err: I::ErrorCode,
3377 ) {
3378 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
3379 }
3380
3381 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
3382 _core_ctx: &mut FakeIcmpCoreCtx<I>,
3383 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3384 _device: &FakeDeviceId,
3385 _src_ip: I::RecvSrcAddr,
3386 _dst_ip: SpecifiedAddr<I::Addr>,
3387 _buffer: B,
3388 _info: &LocalDeliveryPacketInfo<I, H>,
3389 _early_demux_socket: Option<Never>,
3390 ) -> Result<(), (B, TransportReceiveError)> {
3391 unimplemented!()
3392 }
3393 }
3394
3395 impl<I: IcmpTestIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3396 type EchoTransportContext = FakeEchoIpTransportContext;
3397
3398 fn receive_icmp_error(
3399 &mut self,
3400 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3401 device: &Self::DeviceId,
3402 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
3403 original_dst_ip: SpecifiedAddr<I::Addr>,
3404 original_proto: I::Proto,
3405 original_body: &[u8],
3406 err: I::ErrorCode,
3407 ) {
3408 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
3409 self.icmp.receive_icmp_error.push(err);
3410 if original_proto == I::ICMP_IP_PROTO {
3411 receive_ip_transport_icmp_error(
3412 self,
3413 bindings_ctx,
3414 device,
3415 original_src_ip,
3416 original_dst_ip,
3417 original_body,
3418 err,
3419 )
3420 }
3421 }
3422
3423 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
3424 &mut self,
3425 cb: F,
3426 ) -> O {
3427 cb(&mut self.icmp.error_send_bucket)
3428 }
3429 }
3430
3431 #[test]
3432 fn test_should_send_icmpv4_error() {
3433 let src_ip = TEST_ADDRS_V4.local_ip;
3434 let dst_ip = TEST_ADDRS_V4.remote_ip;
3435 let frame_dst = FrameDestination::Individual { local: true };
3436 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
3437 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
3438
3439 assert!(should_send_icmpv4_error(
3441 Some(frame_dst),
3442 src_ip,
3443 dst_ip,
3444 Ipv4FragmentType::InitialFragment
3445 ));
3446 assert!(should_send_icmpv4_error(None, src_ip, dst_ip, Ipv4FragmentType::InitialFragment));
3447 assert!(!should_send_icmpv4_error(
3448 Some(frame_dst),
3449 src_ip,
3450 dst_ip,
3451 Ipv4FragmentType::NonInitialFragment
3452 ));
3453
3454 assert!(!should_send_icmpv4_error(
3456 Some(frame_dst),
3457 src_ip,
3458 Ipv4::LIMITED_BROADCAST_ADDRESS,
3459 Ipv4FragmentType::InitialFragment
3460 ));
3461 assert!(!should_send_icmpv4_error(
3462 Some(frame_dst),
3463 src_ip,
3464 Ipv4::LIMITED_BROADCAST_ADDRESS,
3465 Ipv4FragmentType::NonInitialFragment
3466 ));
3467
3468 assert!(!should_send_icmpv4_error(
3470 Some(frame_dst),
3471 src_ip,
3472 multicast_ip_1,
3473 Ipv4FragmentType::InitialFragment
3474 ));
3475 assert!(!should_send_icmpv4_error(
3476 Some(frame_dst),
3477 src_ip,
3478 multicast_ip_1,
3479 Ipv4FragmentType::NonInitialFragment
3480 ));
3481
3482 assert!(!should_send_icmpv4_error(
3484 Some(FrameDestination::Broadcast),
3485 src_ip,
3486 dst_ip,
3487 Ipv4FragmentType::InitialFragment
3488 ));
3489 assert!(!should_send_icmpv4_error(
3490 Some(FrameDestination::Broadcast),
3491 src_ip,
3492 dst_ip,
3493 Ipv4FragmentType::NonInitialFragment
3494 ));
3495
3496 assert!(!should_send_icmpv4_error(
3498 Some(frame_dst),
3499 Ipv4::LOOPBACK_ADDRESS,
3500 dst_ip,
3501 Ipv4FragmentType::InitialFragment
3502 ));
3503 assert!(!should_send_icmpv4_error(
3504 Some(frame_dst),
3505 Ipv4::LOOPBACK_ADDRESS,
3506 dst_ip,
3507 Ipv4FragmentType::NonInitialFragment
3508 ));
3509
3510 assert!(!should_send_icmpv4_error(
3512 Some(frame_dst),
3513 Ipv4::LIMITED_BROADCAST_ADDRESS,
3514 dst_ip,
3515 Ipv4FragmentType::InitialFragment
3516 ));
3517 assert!(!should_send_icmpv4_error(
3518 Some(frame_dst),
3519 Ipv4::LIMITED_BROADCAST_ADDRESS,
3520 dst_ip,
3521 Ipv4FragmentType::NonInitialFragment
3522 ));
3523
3524 assert!(!should_send_icmpv4_error(
3526 Some(frame_dst),
3527 multicast_ip_2,
3528 dst_ip,
3529 Ipv4FragmentType::InitialFragment
3530 ));
3531 assert!(!should_send_icmpv4_error(
3532 Some(frame_dst),
3533 multicast_ip_2,
3534 dst_ip,
3535 Ipv4FragmentType::NonInitialFragment
3536 ));
3537
3538 assert!(!should_send_icmpv4_error(
3540 Some(frame_dst),
3541 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
3542 dst_ip,
3543 Ipv4FragmentType::InitialFragment
3544 ));
3545 assert!(!should_send_icmpv4_error(
3546 Some(frame_dst),
3547 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
3548 dst_ip,
3549 Ipv4FragmentType::NonInitialFragment
3550 ));
3551 }
3552
3553 #[test]
3554 fn test_should_send_icmpv6_error() {
3555 let src_ip = TEST_ADDRS_V6.local_ip;
3556 let dst_ip = TEST_ADDRS_V6.remote_ip;
3557 let frame_dst = FrameDestination::Individual { local: true };
3558 let multicast_ip_1 =
3559 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
3560 let multicast_ip_2 =
3561 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
3562
3563 assert!(should_send_icmpv6_error(
3565 Some(frame_dst),
3566 src_ip,
3567 dst_ip,
3568 false ));
3570 assert!(should_send_icmpv6_error(
3571 None, src_ip, dst_ip, false ));
3573 assert!(should_send_icmpv6_error(
3574 Some(frame_dst),
3575 src_ip,
3576 dst_ip,
3577 true ));
3579
3580 assert!(!should_send_icmpv6_error(
3583 Some(frame_dst),
3584 src_ip,
3585 multicast_ip_1,
3586 false ));
3588 assert!(should_send_icmpv6_error(
3589 Some(frame_dst),
3590 src_ip,
3591 multicast_ip_1,
3592 true ));
3594
3595 assert!(!should_send_icmpv6_error(
3598 Some(FrameDestination::Broadcast),
3599 src_ip,
3600 dst_ip,
3601 false ));
3603 assert!(should_send_icmpv6_error(
3604 Some(FrameDestination::Broadcast),
3605 src_ip,
3606 dst_ip,
3607 true ));
3609
3610 assert!(!should_send_icmpv6_error(
3612 Some(frame_dst),
3613 Ipv6::LOOPBACK_ADDRESS,
3614 dst_ip,
3615 false ));
3617 assert!(!should_send_icmpv6_error(
3618 Some(frame_dst),
3619 Ipv6::LOOPBACK_ADDRESS,
3620 dst_ip,
3621 true ));
3623
3624 assert!(!should_send_icmpv6_error(
3626 Some(frame_dst),
3627 multicast_ip_2,
3628 dst_ip,
3629 false ));
3631 assert!(!should_send_icmpv6_error(
3632 Some(frame_dst),
3633 multicast_ip_2,
3634 dst_ip,
3635 true ));
3637
3638 assert!(!should_send_icmpv6_error(
3641 Some(FrameDestination::Broadcast),
3642 multicast_ip_2,
3643 dst_ip,
3644 false ));
3646 assert!(!should_send_icmpv6_error(
3647 Some(FrameDestination::Broadcast),
3648 multicast_ip_2,
3649 dst_ip,
3650 true ));
3652 assert!(!should_send_icmpv6_error(
3653 Some(frame_dst),
3654 multicast_ip_2,
3655 multicast_ip_1,
3656 false ));
3658 assert!(!should_send_icmpv6_error(
3659 Some(frame_dst),
3660 multicast_ip_2,
3661 multicast_ip_1,
3662 true ));
3664 }
3665
3666 #[derive(Default)]
3673 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3674 _marker: core::marker::PhantomData<I>,
3675 }
3676
3677 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3678 fn should_send_timestamp_reply(&self) -> bool {
3679 false
3680 }
3681 }
3682 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3683 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3684
3685 impl<I: IcmpTestIpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3686 fn new_ip_socket<O>(
3687 &mut self,
3688 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3689 args: IpSocketArgs<'_, Self::DeviceId, I, O>,
3690 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3691 where
3692 O: RouteResolutionOptions<I>,
3693 {
3694 self.ip_socket_ctx.new_ip_socket(bindings_ctx, args)
3695 }
3696
3697 fn send_ip_packet<S, O>(
3698 &mut self,
3699 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3700 socket: &IpSock<I, Self::WeakDeviceId>,
3701 body: S,
3702 options: &O,
3703 tx_meta: FakeTxMetadata,
3704 ) -> Result<(), IpSockSendError>
3705 where
3706 S: TransportPacketSerializer<I>,
3707 S::Buffer: BufferMut,
3708 O: SendOptions<I> + RouteResolutionOptions<I>,
3709 {
3710 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3711 }
3712
3713 fn confirm_reachable<O>(
3714 &mut self,
3715 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3716 socket: &IpSock<I, Self::WeakDeviceId>,
3717 options: &O,
3718 ) where
3719 O: RouteResolutionOptions<I>,
3720 {
3721 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3722 }
3723 }
3724
3725 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3726 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3727 unimplemented!()
3728 }
3729
3730 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3731 unreachable!()
3732 }
3733
3734 fn handle_received_dad_packet(
3735 &mut self,
3736 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3737 _device_id: &Self::DeviceId,
3738 _addr: SpecifiedAddr<Ipv6Addr>,
3739 _probe_data: Option<NdpNonce<&'_ [u8]>>,
3740 ) -> Option<IpAddressState> {
3741 unimplemented!()
3742 }
3743 }
3744
3745 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3746 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3747 cb(&())
3748 }
3749
3750 fn get_local_addr_for_remote(
3751 &mut self,
3752 _device_id: &Self::DeviceId,
3753 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3754 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3755 unimplemented!()
3756 }
3757
3758 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3759 unimplemented!()
3760 }
3761 }
3762
3763 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3764 fn address_status_for_device(
3765 &mut self,
3766 _addr: SpecifiedAddr<Ipv6Addr>,
3767 _device_id: &Self::DeviceId,
3768 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3769 unimplemented!()
3770 }
3771 }
3772
3773 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3774 type LinkLayerAddr = Uninstantiable;
3775
3776 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3777 unimplemented!()
3778 }
3779
3780 fn set_discovered_retrans_timer(
3781 &mut self,
3782 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3783 _device_id: &Self::DeviceId,
3784 _retrans_timer: NonZeroDuration,
3785 ) {
3786 unimplemented!()
3787 }
3788
3789 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3790 unimplemented!()
3791 }
3792
3793 fn update_discovered_ipv6_route(
3794 &mut self,
3795 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3796 _device_id: &Self::DeviceId,
3797 _route: Ipv6DiscoveredRoute,
3798 _lifetime: Option<NonZeroNdpLifetime>,
3799 ) {
3800 unimplemented!()
3801 }
3802
3803 fn apply_slaac_update(
3804 &mut self,
3805 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3806 _device_id: &Self::DeviceId,
3807 _subnet: Subnet<Ipv6Addr>,
3808 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3809 _valid_lifetime: Option<NonZeroNdpLifetime>,
3810 ) {
3811 unimplemented!()
3812 }
3813
3814 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3815 &mut self,
3816 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3817 _device: &FakeDeviceId,
3818 _src_ip: Ipv6SourceAddr,
3819 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3820 _packet: MldPacket<B>,
3821 _header_info: &H,
3822 ) {
3823 unimplemented!()
3824 }
3825 }
3826
3827 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3828 fn send_ip_packet_from_device<S>(
3829 &mut self,
3830 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3831 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3832 _body: S,
3833 ) -> Result<(), IpSendFrameError<S>> {
3834 unimplemented!()
3835 }
3836
3837 fn send_ip_frame<S>(
3838 &mut self,
3839 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3840 _device: &Self::DeviceId,
3841 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3842 _body: S,
3843 ) -> Result<(), IpSendFrameError<S>>
3844 where
3845 S: Serializer,
3846 S::Buffer: BufferMut,
3847 {
3848 unimplemented!()
3849 }
3850 }
3851
3852 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3853 fn handle_neighbor_probe(
3854 &mut self,
3855 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3856 _device_id: &Self::DeviceId,
3857 _neighbor: SpecifiedAddr<Ipv6Addr>,
3858 _link_addr: &[u8],
3859 ) {
3860 unimplemented!()
3861 }
3862
3863 fn handle_neighbor_confirmation(
3864 &mut self,
3865 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3866 _device_id: &Self::DeviceId,
3867 _neighbor: SpecifiedAddr<Ipv6Addr>,
3868 _link_addr: Option<&[u8]>,
3869 _flags: ConfirmationFlags,
3870 ) {
3871 unimplemented!()
3872 }
3873
3874 fn flush_neighbor_table(
3875 &mut self,
3876 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3877 _device_id: &Self::DeviceId,
3878 ) {
3879 unimplemented!()
3880 }
3881 }
3882
3883 #[test]
3884 fn test_receive_icmpv4_error() {
3885 const ICMP_ID: u16 = 0x0F;
3888 const SEQ_NUM: u16 = 0xF0;
3889
3890 fn test_receive_icmpv4_error_helper<
3905 C: Debug,
3906 M: IcmpMessage<Ipv4, Code = C> + Debug,
3907 F: Fn(&FakeIcmpCtx<Ipv4>),
3908 >(
3909 original_packet: &mut [u8],
3910 code: C,
3911 msg: M,
3912 f: F,
3913 ) {
3914 set_logger_for_test();
3915
3916 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3917
3918 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3919 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3920 core_ctx,
3921 bindings_ctx,
3922 &FakeDeviceId,
3923 Ipv4SourceAddr::new(*TEST_ADDRS_V4.remote_ip).unwrap(),
3924 TEST_ADDRS_V4.local_ip,
3925 IcmpPacketBuilder::new(TEST_ADDRS_V4.remote_ip, TEST_ADDRS_V4.local_ip, code, msg)
3926 .wrap_body(Buf::new(original_packet, ..))
3927 .serialize_vec_outer()
3928 .unwrap(),
3929 &LocalDeliveryPacketInfo::default(),
3930 None,
3931 )
3932 .unwrap();
3933 f(&ctx);
3934 }
3935 let mut buffer = EmptyBuf
3948 .wrap_in(IcmpPacketBuilder::<Ipv4, _>::new(
3949 TEST_ADDRS_V4.local_ip,
3950 TEST_ADDRS_V4.remote_ip,
3951 IcmpZeroCode,
3952 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3953 ))
3954 .wrap_in(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3955 TEST_ADDRS_V4.local_ip,
3956 TEST_ADDRS_V4.remote_ip,
3957 64,
3958 Ipv4Proto::Icmp,
3959 ))
3960 .serialize_vec_outer()
3961 .unwrap();
3962
3963 test_receive_icmpv4_error_helper(
3964 buffer.as_mut(),
3965 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3966 IcmpDestUnreachable::default(),
3967 |CtxPair { core_ctx, bindings_ctx: _ }| {
3968 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3969 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3970 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3971 assert_eq!(
3972 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3973 1
3974 );
3975 let err = Icmpv4ErrorCode::DestUnreachable(
3976 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3977 IcmpDestUnreachable::default(),
3978 );
3979 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3980 },
3981 );
3982
3983 test_receive_icmpv4_error_helper(
3984 buffer.as_mut(),
3985 Icmpv4TimeExceededCode::TtlExpired,
3986 IcmpTimeExceeded::default(),
3987 |CtxPair { core_ctx, bindings_ctx: _ }| {
3988 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3989 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3990 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3991 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3992 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3993 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3994 },
3995 );
3996
3997 test_receive_icmpv4_error_helper(
3998 buffer.as_mut(),
3999 Icmpv4ParameterProblemCode::PointerIndicatesError,
4000 Icmpv4ParameterProblem::new(0),
4001 |CtxPair { core_ctx, bindings_ctx: _ }| {
4002 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4003 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4004 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4005 assert_eq!(
4006 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
4007 1
4008 );
4009 let err = Icmpv4ErrorCode::ParameterProblem(
4010 Icmpv4ParameterProblemCode::PointerIndicatesError,
4011 );
4012 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4013 },
4014 );
4015
4016 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
4023 TEST_ADDRS_V4.local_ip,
4024 TEST_ADDRS_V4.remote_ip,
4025 64,
4026 Ipv4Proto::Icmp,
4027 )
4028 .wrap_body(EmptyBuf)
4029 .serialize_vec_outer()
4030 .unwrap();
4031
4032 test_receive_icmpv4_error_helper(
4033 buffer.as_mut(),
4034 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4035 IcmpDestUnreachable::default(),
4036 |CtxPair { core_ctx, bindings_ctx: _ }| {
4037 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4038 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4039 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4040 assert_eq!(
4041 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
4042 1
4043 );
4044 let err = Icmpv4ErrorCode::DestUnreachable(
4045 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4046 IcmpDestUnreachable::default(),
4047 );
4048 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4049 },
4050 );
4051
4052 test_receive_icmpv4_error_helper(
4053 buffer.as_mut(),
4054 Icmpv4TimeExceededCode::TtlExpired,
4055 IcmpTimeExceeded::default(),
4056 |CtxPair { core_ctx, bindings_ctx: _ }| {
4057 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4058 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4059 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4060 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
4061 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
4062 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4063 },
4064 );
4065
4066 test_receive_icmpv4_error_helper(
4067 buffer.as_mut(),
4068 Icmpv4ParameterProblemCode::PointerIndicatesError,
4069 Icmpv4ParameterProblem::new(0),
4070 |CtxPair { core_ctx, bindings_ctx: _ }| {
4071 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4072 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4073 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4074 assert_eq!(
4075 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
4076 1
4077 );
4078 let err = Icmpv4ErrorCode::ParameterProblem(
4079 Icmpv4ParameterProblemCode::PointerIndicatesError,
4080 );
4081 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4082 },
4083 );
4084
4085 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
4091 TEST_ADDRS_V4.local_ip,
4092 TEST_ADDRS_V4.remote_ip,
4093 64,
4094 IpProto::Udp.into(),
4095 )
4096 .wrap_body(EmptyBuf)
4097 .serialize_vec_outer()
4098 .unwrap();
4099
4100 test_receive_icmpv4_error_helper(
4101 buffer.as_mut(),
4102 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4103 IcmpDestUnreachable::default(),
4104 |CtxPair { core_ctx, bindings_ctx: _ }| {
4105 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4106 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4107 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4108 assert_eq!(
4109 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
4110 1
4111 );
4112 let err = Icmpv4ErrorCode::DestUnreachable(
4113 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4114 IcmpDestUnreachable::default(),
4115 );
4116 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4117 },
4118 );
4119
4120 test_receive_icmpv4_error_helper(
4121 buffer.as_mut(),
4122 Icmpv4TimeExceededCode::TtlExpired,
4123 IcmpTimeExceeded::default(),
4124 |CtxPair { core_ctx, bindings_ctx: _ }| {
4125 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4126 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4127 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4128 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
4129 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
4130 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4131 },
4132 );
4133
4134 test_receive_icmpv4_error_helper(
4135 buffer.as_mut(),
4136 Icmpv4ParameterProblemCode::PointerIndicatesError,
4137 Icmpv4ParameterProblem::new(0),
4138 |CtxPair { core_ctx, bindings_ctx: _ }| {
4139 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4140 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4141 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4142 assert_eq!(
4143 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
4144 1
4145 );
4146 let err = Icmpv4ErrorCode::ParameterProblem(
4147 Icmpv4ParameterProblemCode::PointerIndicatesError,
4148 );
4149 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4150 },
4151 );
4152 }
4153
4154 #[test]
4155 fn test_receive_icmpv6_error() {
4156 const ICMP_ID: u16 = 0x0F;
4159 const SEQ_NUM: u16 = 0xF0;
4160
4161 fn test_receive_icmpv6_error_helper<
4176 C: Debug,
4177 M: IcmpMessage<Ipv6, Code = C> + Debug,
4178 F: Fn(&FakeIcmpCtx<Ipv6>),
4179 >(
4180 original_packet: &mut [u8],
4181 code: C,
4182 msg: M,
4183 f: F,
4184 ) {
4185 set_logger_for_test();
4186
4187 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
4188 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
4189 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
4190 core_ctx,
4191 bindings_ctx,
4192 &FakeDeviceId,
4193 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
4194 TEST_ADDRS_V6.local_ip,
4195 IcmpPacketBuilder::new(TEST_ADDRS_V6.remote_ip, TEST_ADDRS_V6.local_ip, code, msg)
4196 .wrap_body(Buf::new(original_packet, ..))
4197 .serialize_vec_outer()
4198 .unwrap(),
4199 &LocalDeliveryPacketInfo::default(),
4200 None,
4201 )
4202 .unwrap();
4203 f(&ctx);
4204 }
4205 let mut buffer = EmptyBuf
4218 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
4219 TEST_ADDRS_V6.local_ip,
4220 TEST_ADDRS_V6.remote_ip,
4221 IcmpZeroCode,
4222 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
4223 ))
4224 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4225 TEST_ADDRS_V6.local_ip,
4226 TEST_ADDRS_V6.remote_ip,
4227 64,
4228 Ipv6Proto::Icmpv6,
4229 ))
4230 .serialize_vec_outer()
4231 .unwrap();
4232
4233 test_receive_icmpv6_error_helper(
4234 buffer.as_mut(),
4235 Icmpv6DestUnreachableCode::NoRoute,
4236 IcmpDestUnreachable::default(),
4237 |CtxPair { core_ctx, bindings_ctx: _ }| {
4238 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4239 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4240 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4241 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
4242 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4243 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4244 },
4245 );
4246
4247 test_receive_icmpv6_error_helper(
4248 buffer.as_mut(),
4249 Icmpv6TimeExceededCode::HopLimitExceeded,
4250 IcmpTimeExceeded::default(),
4251 |CtxPair { core_ctx, bindings_ctx: _ }| {
4252 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4253 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4254 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4255 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
4256 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4257 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4258 },
4259 );
4260
4261 test_receive_icmpv6_error_helper(
4262 buffer.as_mut(),
4263 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4264 Icmpv6ParameterProblem::new(0),
4265 |CtxPair { core_ctx, bindings_ctx: _ }| {
4266 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4267 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4268 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
4269 assert_eq!(
4270 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
4271 1
4272 );
4273 let err = Icmpv6ErrorCode::ParameterProblem(
4274 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4275 );
4276 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4277 },
4278 );
4279
4280 let mut buffer = EmptyBuf
4287 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4288 TEST_ADDRS_V6.local_ip,
4289 TEST_ADDRS_V6.remote_ip,
4290 64,
4291 Ipv6Proto::Icmpv6,
4292 ))
4293 .serialize_vec_outer()
4294 .unwrap();
4295
4296 test_receive_icmpv6_error_helper(
4297 buffer.as_mut(),
4298 Icmpv6DestUnreachableCode::NoRoute,
4299 IcmpDestUnreachable::default(),
4300 |CtxPair { core_ctx, bindings_ctx: _ }| {
4301 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4302 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4303 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4304 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
4305 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4306 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4307 },
4308 );
4309
4310 test_receive_icmpv6_error_helper(
4311 buffer.as_mut(),
4312 Icmpv6TimeExceededCode::HopLimitExceeded,
4313 IcmpTimeExceeded::default(),
4314 |CtxPair { core_ctx, bindings_ctx: _ }| {
4315 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4316 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4317 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4318 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
4319 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4320 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4321 },
4322 );
4323
4324 test_receive_icmpv6_error_helper(
4325 buffer.as_mut(),
4326 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4327 Icmpv6ParameterProblem::new(0),
4328 |CtxPair { core_ctx, bindings_ctx: _ }| {
4329 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4330 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
4331 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4332 assert_eq!(
4333 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
4334 1
4335 );
4336 let err = Icmpv6ErrorCode::ParameterProblem(
4337 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4338 );
4339 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4340 },
4341 );
4342
4343 let mut buffer = <Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
4349 TEST_ADDRS_V6.local_ip,
4350 TEST_ADDRS_V6.remote_ip,
4351 64,
4352 IpProto::Udp.into(),
4353 )
4354 .wrap_body(EmptyBuf)
4355 .serialize_vec_outer()
4356 .unwrap();
4357
4358 test_receive_icmpv6_error_helper(
4359 buffer.as_mut(),
4360 Icmpv6DestUnreachableCode::NoRoute,
4361 IcmpDestUnreachable::default(),
4362 |CtxPair { core_ctx, bindings_ctx: _ }| {
4363 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4364 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4365 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4366 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
4367 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
4368 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4369 },
4370 );
4371
4372 test_receive_icmpv6_error_helper(
4373 buffer.as_mut(),
4374 Icmpv6TimeExceededCode::HopLimitExceeded,
4375 IcmpTimeExceeded::default(),
4376 |CtxPair { core_ctx, bindings_ctx: _ }| {
4377 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4378 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4379 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4380 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
4381 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
4382 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4383 },
4384 );
4385
4386 test_receive_icmpv6_error_helper(
4387 buffer.as_mut(),
4388 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4389 Icmpv6ParameterProblem::new(0),
4390 |CtxPair { core_ctx, bindings_ctx: _ }| {
4391 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
4392 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
4393 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
4394 assert_eq!(
4395 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
4396 1
4397 );
4398 let err = Icmpv6ErrorCode::ParameterProblem(
4399 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
4400 );
4401 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
4402 },
4403 );
4404 }
4405
4406 #[test]
4407 fn test_error_rate_limit() {
4408 set_logger_for_test();
4409
4410 fn send_icmpv4_ttl_expired_helper(
4412 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4413 ) {
4414 send_icmpv4_ttl_expired(
4415 core_ctx,
4416 bindings_ctx,
4417 &FakeDeviceId,
4418 Some(FrameDestination::Individual { local: true }),
4419 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4420 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4421 IpProto::Udp.into(),
4422 EmptyBuf,
4423 0,
4424 Ipv4FragmentType::InitialFragment,
4425 &Default::default(),
4426 );
4427 assert_geq!(core_ctx.icmp.tx_counters.time_exceeded.ttl_expired.get(), 1);
4428 }
4429
4430 fn send_icmpv4_parameter_problem_helper(
4432 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4433 ) {
4434 send_icmpv4_parameter_problem(
4435 core_ctx,
4436 bindings_ctx,
4437 &FakeDeviceId,
4438 Some(FrameDestination::Individual { local: true }),
4439 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4440 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4441 Icmpv4ParameterProblemCode::PointerIndicatesError,
4442 Icmpv4ParameterProblem::new(0),
4443 EmptyBuf,
4444 0,
4445 Ipv4FragmentType::InitialFragment,
4446 &Default::default(),
4447 );
4448 assert_geq!(
4449 core_ctx.icmp.tx_counters.parameter_problem.pointer_indicates_error.get(),
4450 1
4451 );
4452 }
4453
4454 fn send_icmpv4_dest_unreachable_helper(
4456 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
4457 ) {
4458 send_icmpv4_dest_unreachable(
4459 core_ctx,
4460 bindings_ctx,
4461 Some(&FakeDeviceId),
4462 Some(FrameDestination::Individual { local: true }),
4463 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
4464 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
4465 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
4466 EmptyBuf,
4467 0,
4468 Ipv4FragmentType::InitialFragment,
4469 &Default::default(),
4470 );
4471 assert_geq!(
4472 core_ctx.icmp.tx_counters.dest_unreachable.dest_network_unreachable.get(),
4473 1
4474 );
4475 }
4476
4477 fn send_icmpv6_ttl_expired_helper(
4479 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4480 ) {
4481 send_icmpv6_ttl_expired(
4482 core_ctx,
4483 bindings_ctx,
4484 &FakeDeviceId,
4485 Some(FrameDestination::Individual { local: true }),
4486 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4487 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4488 IpProto::Udp.into(),
4489 EmptyBuf,
4490 0,
4491 &Default::default(),
4492 );
4493 assert_geq!(core_ctx.icmp.tx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
4494 }
4495
4496 fn send_icmpv6_packet_too_big_helper(
4498 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4499 ) {
4500 send_icmpv6_packet_too_big(
4501 core_ctx,
4502 bindings_ctx,
4503 &FakeDeviceId,
4504 Some(FrameDestination::Individual { local: true }),
4505 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4506 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4507 IpProto::Udp.into(),
4508 Mtu::new(0),
4509 EmptyBuf,
4510 0,
4511 &Default::default(),
4512 );
4513 assert_geq!(core_ctx.icmp.tx_counters.packet_too_big.get(), 1);
4514 }
4515
4516 fn send_icmpv6_parameter_problem_helper(
4518 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4519 ) {
4520 send_icmpv6_parameter_problem(
4521 core_ctx,
4522 bindings_ctx,
4523 &FakeDeviceId,
4524 Some(FrameDestination::Individual { local: true }),
4525 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4526 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4527 Icmpv6ParameterProblemCode::ErroneousHeaderField,
4528 Icmpv6ParameterProblem::new(0),
4529 EmptyBuf,
4530 false,
4531 &Default::default(),
4532 );
4533 assert_geq!(
4534 core_ctx.icmp.tx_counters.parameter_problem.erroneous_header_field.get(),
4535 1
4536 );
4537 }
4538
4539 fn send_icmpv6_dest_unreachable_helper(
4541 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
4542 ) {
4543 send_icmpv6_dest_unreachable(
4544 core_ctx,
4545 bindings_ctx,
4546 Some(&FakeDeviceId),
4547 Some(FrameDestination::Individual { local: true }),
4548 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
4549 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
4550 Icmpv6DestUnreachableCode::NoRoute,
4551 EmptyBuf,
4552 &Default::default(),
4553 );
4554 assert_geq!(core_ctx.icmp.tx_counters.dest_unreachable.no_route.get(), 1);
4555 }
4556
4557 fn run_test<I: IcmpTestIpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
4561 with_errors_per_second: W,
4562 send: S,
4563 ) {
4564 const ERRORS_PER_SECOND: u64 = 64;
4578
4579 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
4580
4581 for i in 0..ERRORS_PER_SECOND {
4582 send(&mut ctx);
4583 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
4584 }
4585
4586 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4587 send(&mut ctx);
4588 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4589
4590 let mut ctx = with_errors_per_second(0);
4594 send(&mut ctx);
4595 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4596 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4597 send(&mut ctx);
4598 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4599 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4600 send(&mut ctx);
4601 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4602 }
4603
4604 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
4605 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4606 }
4607 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
4608 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
4609 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
4610
4611 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
4612 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4613 }
4614
4615 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
4616 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
4617 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
4618 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
4619 }
4620}