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