1pub mod counters;
8
9use alloc::boxed::Box;
10use core::convert::{Infallible as Never, TryInto as _};
11use core::fmt::Debug;
12use core::num::{NonZeroU8, NonZeroU16};
13
14use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
15use log::{debug, error, trace};
16use net_types::ip::{
17 GenericOverIp, Ip, IpAddress, IpMarked, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr,
18 Ipv6SourceAddr, Mtu, SubnetError,
19};
20use net_types::{
21 LinkLocalAddress, LinkLocalUnicastAddr, MulticastAddr, MulticastAddress, SpecifiedAddr,
22 UnicastAddr, Witness,
23};
24use netstack3_base::socket::{AddrIsMappedError, SocketIpAddr, SocketIpAddrExt as _};
25use netstack3_base::sync::Mutex;
26use netstack3_base::{
27 AnyDevice, Counter, CounterContext, DeviceIdContext, EitherDeviceId, FrameDestination,
28 IcmpIpExt, Icmpv4ErrorCode, Icmpv6ErrorCode, InstantBindingsTypes, InstantContext,
29 IpDeviceAddr, IpExt, Marks, RngContext, TokenBucket, TxMetadataBindingsTypes,
30};
31use netstack3_filter::{DynTransportSerializer, DynamicTransportSerializer, FilterIpExt};
32use packet::{
33 BufferMut, InnerPacketBuilder as _, PacketBuilder as _, ParsablePacket as _, ParseBuffer,
34 PartialSerializer, Serializer, TruncateDirection, TruncatingSerializer,
35};
36use packet_formats::icmp::ndp::options::{NdpOption, NdpOptionBuilder};
37use packet_formats::icmp::ndp::{
38 NdpPacket, NeighborAdvertisement, NeighborSolicitation, NonZeroNdpLifetime,
39 OptionSequenceBuilder, RouterSolicitation,
40};
41use packet_formats::icmp::{
42 IcmpDestUnreachable, IcmpEchoRequest, IcmpMessage, IcmpMessageType, IcmpPacket,
43 IcmpPacketBuilder, IcmpPacketRaw, IcmpParseArgs, IcmpTimeExceeded, IcmpZeroCode,
44 Icmpv4DestUnreachableCode, Icmpv4Packet, Icmpv4ParameterProblem, Icmpv4ParameterProblemCode,
45 Icmpv4TimeExceededCode, Icmpv6DestUnreachableCode, Icmpv6Packet, Icmpv6PacketTooBig,
46 Icmpv6ParameterProblem, Icmpv6ParameterProblemCode, Icmpv6TimeExceededCode, MessageBody,
47 OriginalPacket, peek_message_type,
48};
49use packet_formats::ip::{DscpAndEcn, Ipv4Proto, Ipv6Proto};
50use packet_formats::ipv4::Ipv4Header;
51use packet_formats::ipv6::{ExtHdrParseError, Ipv6Header};
52use zerocopy::SplitByteSlice;
53
54use crate::IpLayerIpExt;
55use crate::internal::base::{
56 AddressStatus, IPV6_DEFAULT_SUBNET, IpDeviceIngressStateContext, IpLayerHandler,
57 IpPacketDestination, IpSendFrameError, IpTransportContext, Ipv6PresentAddressStatus,
58 NdpBindingsContext, RouterAdvertisementEvent, SendIpPacketMeta,
59};
60use crate::internal::device::nud::{ConfirmationFlags, NudIpHandler};
61use crate::internal::device::route_discovery::Ipv6DiscoveredRoute;
62use crate::internal::device::{
63 IpAddressState, IpDeviceHandler, Ipv6DeviceHandler, Ipv6LinkLayerAddr,
64};
65use crate::internal::icmp::counters::{IcmpCountersIpExt, IcmpRxCounters, IcmpTxCounters};
66use crate::internal::local_delivery::{IpHeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta};
67use crate::internal::path_mtu::PmtuHandler;
68use crate::internal::socket::{
69 DelegatedRouteResolutionOptions, DelegatedSendOptions, IpSocketArgs, IpSocketHandler,
70 OptionDelegationMarker, RouteResolutionOptions, SendOptions,
71};
72
73pub const REQUIRED_NDP_IP_PACKET_HOP_LIMIT: u8 = 255;
85
86pub const DEFAULT_ERRORS_PER_SECOND: u64 = 1000;
94#[derive(GenericOverIp)]
96#[generic_over_ip(I, Ip)]
97pub struct IcmpState<I: IpExt + IcmpCountersIpExt, BT: IcmpBindingsTypes> {
98 error_send_bucket: Mutex<IpMarked<I, TokenBucket<BT::Instant>>>,
99 pub tx_counters: IcmpTxCounters<I>,
101 pub rx_counters: IcmpRxCounters<I>,
103}
104
105impl<I, BT> OrderedLockAccess<IpMarked<I, TokenBucket<BT::Instant>>> for IcmpState<I, BT>
106where
107 I: IpExt + IcmpCountersIpExt,
108 BT: IcmpBindingsTypes,
109{
110 type Lock = Mutex<IpMarked<I, TokenBucket<BT::Instant>>>;
111 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
112 OrderedLockRef::new(&self.error_send_bucket)
113 }
114}
115
116#[derive(Default)]
118pub struct NdpRxCounters {
119 pub neighbor_solicitation: Counter,
121 pub neighbor_advertisement: Counter,
123 pub router_advertisement: Counter,
125 pub router_solicitation: Counter,
127}
128
129#[derive(Default)]
131pub struct NdpTxCounters {
132 pub neighbor_advertisement: Counter,
134 pub neighbor_solicitation: Counter,
136}
137
138#[derive(Default)]
140pub struct NdpCounters {
141 pub rx: NdpRxCounters,
143 pub tx: NdpTxCounters,
145}
146
147#[derive(Copy, Clone)]
149pub struct Icmpv4StateBuilder {
150 send_timestamp_reply: bool,
151 errors_per_second: u64,
152}
153
154impl Default for Icmpv4StateBuilder {
155 fn default() -> Icmpv4StateBuilder {
156 Icmpv4StateBuilder {
157 send_timestamp_reply: false,
158 errors_per_second: DEFAULT_ERRORS_PER_SECOND,
159 }
160 }
161}
162
163impl Icmpv4StateBuilder {
164 pub fn send_timestamp_reply(&mut self, send_timestamp_reply: bool) -> &mut Self {
171 self.send_timestamp_reply = send_timestamp_reply;
172 self
173 }
174
175 pub fn build<BT: IcmpBindingsTypes>(self) -> Icmpv4State<BT> {
177 Icmpv4State {
178 inner: IcmpState {
179 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
180 self.errors_per_second,
181 ))),
182 tx_counters: Default::default(),
183 rx_counters: Default::default(),
184 },
185 send_timestamp_reply: self.send_timestamp_reply,
186 }
187 }
188}
189
190pub struct Icmpv4State<BT: IcmpBindingsTypes> {
192 pub inner: IcmpState<Ipv4, BT>,
194 pub send_timestamp_reply: bool,
196}
197
198impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
199 fn as_ref(&self) -> &IcmpState<Ipv4, BT> {
200 &self.inner
201 }
202}
203
204impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
205 fn as_mut(&mut self) -> &mut IcmpState<Ipv4, BT> {
206 &mut self.inner
207 }
208}
209
210#[derive(Copy, Clone)]
212pub(crate) struct Icmpv6StateBuilder {
213 errors_per_second: u64,
214}
215
216impl Default for Icmpv6StateBuilder {
217 fn default() -> Icmpv6StateBuilder {
218 Icmpv6StateBuilder { errors_per_second: DEFAULT_ERRORS_PER_SECOND }
219 }
220}
221
222impl Icmpv6StateBuilder {
223 pub(crate) fn build<BT: IcmpBindingsTypes>(self) -> Icmpv6State<BT> {
224 Icmpv6State {
225 inner: IcmpState {
226 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
227 self.errors_per_second,
228 ))),
229 tx_counters: Default::default(),
230 rx_counters: Default::default(),
231 },
232 ndp_counters: Default::default(),
233 }
234 }
235}
236
237pub struct Icmpv6State<BT: IcmpBindingsTypes> {
239 pub inner: IcmpState<Ipv6, BT>,
241 pub ndp_counters: NdpCounters,
243}
244
245impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
246 fn as_ref(&self) -> &IcmpState<Ipv6, BT> {
247 &self.inner
248 }
249}
250
251impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
252 fn as_mut(&mut self) -> &mut IcmpState<Ipv6, BT> {
253 &mut self.inner
254 }
255}
256
257pub trait IcmpHandlerIpExt: IpExt {
259 type IcmpError: IcmpError;
261
262 fn received_source_as_icmp_source(src: Self::RecvSrcAddr) -> Option<SocketIpAddr<Self::Addr>>;
264
265 fn nud_failure_icmp_error() -> Self::IcmpError;
267}
268
269impl IcmpHandlerIpExt for Ipv4 {
270 type IcmpError = Icmpv4Error;
271
272 fn received_source_as_icmp_source(src: Ipv4SourceAddr) -> Option<SocketIpAddr<Ipv4Addr>> {
273 SocketIpAddr::new_from_ipv4_source(src)
274 }
275
276 fn nud_failure_icmp_error() -> Icmpv4Error {
277 Icmpv4Error::HostUnreachable
278 }
279}
280
281impl IcmpHandlerIpExt for Ipv6 {
282 type IcmpError = Icmpv6Error;
283
284 fn received_source_as_icmp_source(src: Ipv6SourceAddr) -> Option<SocketIpAddr<Ipv6Addr>> {
285 SocketIpAddr::new_from_ipv6_source(src)
286 }
287
288 fn nud_failure_icmp_error() -> Icmpv6Error {
289 Icmpv6Error::AddressUnreachable
290 }
291}
292
293pub trait IcmpError: Sized + Debug + PartialEq {
295 fn port_unreachable() -> Self;
297 fn ttl_expired() -> Self;
299 fn mtu_exceeded(mtu: Mtu) -> Option<Self>;
302}
303
304#[derive(Debug, PartialEq)]
306pub enum Icmpv4Error {
307 ParameterProblem {
309 code: Icmpv4ParameterProblemCode,
311 pointer: u8,
313 },
314 TtlExpired,
316 NetUnreachable,
318 ProtocolUnreachable,
320 PortUnreachable,
322 HostUnreachable,
324 NetworkProhibited,
326 HostProhibited,
328 AdminProhibited,
330}
331
332impl IcmpError for Icmpv4Error {
333 fn port_unreachable() -> Self {
334 Icmpv4Error::PortUnreachable
335 }
336 fn ttl_expired() -> Self {
337 Icmpv4Error::TtlExpired
338 }
339 fn mtu_exceeded(_mtu: Mtu) -> Option<Self> {
340 None
341 }
342}
343
344enum Icmpv4ErrorMessage {
347 TimeExceeded {
348 message: IcmpTimeExceeded,
349 code: <IcmpTimeExceeded as IcmpMessage<Ipv4>>::Code,
350 },
351 ParameterProblem {
352 message: Icmpv4ParameterProblem,
353 code: <Icmpv4ParameterProblem as IcmpMessage<Ipv4>>::Code,
354 },
355 DestUnreachable {
356 message: IcmpDestUnreachable,
357 code: <IcmpDestUnreachable as IcmpMessage<Ipv4>>::Code,
358 },
359}
360
361impl Icmpv4Error {
362 fn update_counters(&self, counters: &IcmpTxCounters<Ipv4>) {
363 match self {
364 Icmpv4Error::ParameterProblem { code, pointer: _ } => {
365 counters.parameter_problem.increment_code(*code);
366 }
367 Icmpv4Error::TtlExpired => {
368 counters.time_exceeded.increment_code(Icmpv4TimeExceededCode::TtlExpired);
369 }
370 Icmpv4Error::NetUnreachable => {
371 counters.net_unreachable.increment();
372 counters
373 .dest_unreachable
374 .increment_code(Icmpv4DestUnreachableCode::DestNetworkUnreachable);
375 }
376 Icmpv4Error::ProtocolUnreachable => {
377 counters.protocol_unreachable.increment();
378 counters
379 .dest_unreachable
380 .increment_code(Icmpv4DestUnreachableCode::DestProtocolUnreachable);
381 }
382 Icmpv4Error::PortUnreachable => {
383 counters.port_unreachable.increment();
384 counters
385 .dest_unreachable
386 .increment_code(Icmpv4DestUnreachableCode::DestPortUnreachable);
387 }
388 Icmpv4Error::HostUnreachable => {
389 counters.address_unreachable.increment();
390 counters
391 .dest_unreachable
392 .increment_code(Icmpv4DestUnreachableCode::DestHostUnreachable);
393 }
394 Icmpv4Error::NetworkProhibited => {
395 counters
396 .dest_unreachable
397 .increment_code(Icmpv4DestUnreachableCode::NetworkAdministrativelyProhibited);
398 }
399 Icmpv4Error::HostProhibited => {
400 counters
401 .dest_unreachable
402 .increment_code(Icmpv4DestUnreachableCode::HostAdministrativelyProhibited);
403 }
404 Icmpv4Error::AdminProhibited => {
405 counters
406 .dest_unreachable
407 .increment_code(Icmpv4DestUnreachableCode::CommAdministrativelyProhibited);
408 }
409 }
410 }
411
412 fn create_message(&self) -> Icmpv4ErrorMessage {
413 match self {
414 Icmpv4Error::ParameterProblem { code, pointer } => {
415 Icmpv4ErrorMessage::ParameterProblem {
416 message: Icmpv4ParameterProblem::new(*pointer),
417 code: *code,
418 }
419 }
420 Icmpv4Error::TtlExpired => Icmpv4ErrorMessage::TimeExceeded {
421 message: IcmpTimeExceeded::default(),
422 code: Icmpv4TimeExceededCode::TtlExpired,
423 },
424 Icmpv4Error::NetUnreachable => Icmpv4ErrorMessage::DestUnreachable {
425 message: IcmpDestUnreachable::default(),
426 code: Icmpv4DestUnreachableCode::DestNetworkUnreachable,
427 },
428 Icmpv4Error::ProtocolUnreachable => Icmpv4ErrorMessage::DestUnreachable {
429 message: IcmpDestUnreachable::default(),
430 code: Icmpv4DestUnreachableCode::DestProtocolUnreachable,
431 },
432 Icmpv4Error::PortUnreachable => Icmpv4ErrorMessage::DestUnreachable {
433 message: IcmpDestUnreachable::default(),
434 code: Icmpv4DestUnreachableCode::DestPortUnreachable,
435 },
436 Icmpv4Error::HostUnreachable => Icmpv4ErrorMessage::DestUnreachable {
437 message: IcmpDestUnreachable::default(),
438 code: Icmpv4DestUnreachableCode::DestHostUnreachable,
439 },
440 Icmpv4Error::NetworkProhibited => Icmpv4ErrorMessage::DestUnreachable {
441 message: IcmpDestUnreachable::default(),
442 code: Icmpv4DestUnreachableCode::NetworkAdministrativelyProhibited,
443 },
444 Icmpv4Error::HostProhibited => Icmpv4ErrorMessage::DestUnreachable {
445 message: IcmpDestUnreachable::default(),
446 code: Icmpv4DestUnreachableCode::HostAdministrativelyProhibited,
447 },
448 Icmpv4Error::AdminProhibited => Icmpv4ErrorMessage::DestUnreachable {
449 message: IcmpDestUnreachable::default(),
450 code: Icmpv4DestUnreachableCode::CommAdministrativelyProhibited,
451 },
452 }
453 }
454}
455
456#[derive(Debug, PartialEq, Eq)]
458pub enum Icmpv6Error {
459 ParameterProblem {
461 code: Icmpv6ParameterProblemCode,
463 pointer: u32,
465 allow_dst_multicast: bool,
467 },
468 TtlExpired,
470 NetUnreachable,
472 PacketTooBig {
474 mtu: Mtu,
476 },
477 PortUnreachable,
479 AddressUnreachable,
481 RejectRoute,
483 SourceAddressPolicyFailed,
485 AdminProhibited,
487}
488
489impl IcmpError for Icmpv6Error {
490 fn port_unreachable() -> Self {
491 Icmpv6Error::PortUnreachable
492 }
493 fn ttl_expired() -> Self {
494 Icmpv6Error::TtlExpired
495 }
496 fn mtu_exceeded(mtu: Mtu) -> Option<Self> {
497 Some(Icmpv6Error::PacketTooBig { mtu })
498 }
499}
500
501enum Icmpv6ErrorMessage {
504 TimeExceeded {
505 message: IcmpTimeExceeded,
506 code: <IcmpTimeExceeded as IcmpMessage<Ipv6>>::Code,
507 },
508 PacketTooBig {
509 message: Icmpv6PacketTooBig,
510 code: <Icmpv6PacketTooBig as IcmpMessage<Ipv6>>::Code,
511 },
512 ParameterProblem {
513 message: Icmpv6ParameterProblem,
514 code: <Icmpv6ParameterProblem as IcmpMessage<Ipv6>>::Code,
515 },
516 DestUnreachable {
517 message: IcmpDestUnreachable,
518 code: <IcmpDestUnreachable as IcmpMessage<Ipv6>>::Code,
519 },
520}
521
522impl Icmpv6Error {
523 fn update_counters(&self, counters: &IcmpTxCounters<Ipv6>) {
524 match self {
525 Icmpv6Error::ParameterProblem { code, pointer: _, allow_dst_multicast: _ } => {
526 counters.parameter_problem.increment_code(*code);
527 }
528 Icmpv6Error::TtlExpired => {
529 counters.time_exceeded.increment_code(Icmpv6TimeExceededCode::HopLimitExceeded);
530 }
531 Icmpv6Error::NetUnreachable => {
532 counters.net_unreachable.increment();
533 counters.dest_unreachable.increment_code(Icmpv6DestUnreachableCode::NoRoute);
534 }
535 Icmpv6Error::PacketTooBig { mtu: _ } => {
536 counters.packet_too_big.increment();
537 }
538 Icmpv6Error::PortUnreachable => {
539 counters.port_unreachable.increment();
540 counters
541 .dest_unreachable
542 .increment_code(Icmpv6DestUnreachableCode::PortUnreachable);
543 }
544 Icmpv6Error::AddressUnreachable => {
545 counters.address_unreachable.increment();
546 counters
547 .dest_unreachable
548 .increment_code(Icmpv6DestUnreachableCode::AddrUnreachable);
549 }
550 Icmpv6Error::RejectRoute => {
551 counters.dest_unreachable.increment_code(Icmpv6DestUnreachableCode::RejectRoute);
552 }
553 Icmpv6Error::SourceAddressPolicyFailed => {
554 counters
555 .dest_unreachable
556 .increment_code(Icmpv6DestUnreachableCode::SrcAddrFailedPolicy);
557 }
558 Icmpv6Error::AdminProhibited => {
559 counters
560 .dest_unreachable
561 .increment_code(Icmpv6DestUnreachableCode::CommAdministrativelyProhibited);
562 }
563 }
564 }
565
566 fn create_message(&self) -> Icmpv6ErrorMessage {
567 match self {
568 Icmpv6Error::ParameterProblem { code, pointer, allow_dst_multicast: _ } => {
569 Icmpv6ErrorMessage::ParameterProblem {
570 message: Icmpv6ParameterProblem::new(*pointer),
571 code: *code,
572 }
573 }
574 Icmpv6Error::TtlExpired => Icmpv6ErrorMessage::TimeExceeded {
575 message: IcmpTimeExceeded::default(),
576 code: Icmpv6TimeExceededCode::HopLimitExceeded,
577 },
578 Icmpv6Error::NetUnreachable => Icmpv6ErrorMessage::DestUnreachable {
579 message: IcmpDestUnreachable::default(),
580 code: Icmpv6DestUnreachableCode::NoRoute,
581 },
582 Icmpv6Error::PacketTooBig { mtu } => Icmpv6ErrorMessage::PacketTooBig {
583 message: Icmpv6PacketTooBig::new((*mtu).into()),
584 code: IcmpZeroCode,
585 },
586 Icmpv6Error::PortUnreachable => Icmpv6ErrorMessage::DestUnreachable {
587 message: IcmpDestUnreachable::default(),
588 code: Icmpv6DestUnreachableCode::PortUnreachable,
589 },
590 Icmpv6Error::AddressUnreachable => Icmpv6ErrorMessage::DestUnreachable {
591 message: IcmpDestUnreachable::default(),
592 code: Icmpv6DestUnreachableCode::AddrUnreachable,
593 },
594 Icmpv6Error::RejectRoute => Icmpv6ErrorMessage::DestUnreachable {
595 message: IcmpDestUnreachable::default(),
596 code: Icmpv6DestUnreachableCode::RejectRoute,
597 },
598 Icmpv6Error::SourceAddressPolicyFailed => Icmpv6ErrorMessage::DestUnreachable {
599 message: IcmpDestUnreachable::default(),
600 code: Icmpv6DestUnreachableCode::SrcAddrFailedPolicy,
601 },
602 Icmpv6Error::AdminProhibited => Icmpv6ErrorMessage::DestUnreachable {
603 message: IcmpDestUnreachable::default(),
604 code: Icmpv6DestUnreachableCode::CommAdministrativelyProhibited,
605 },
606 }
607 }
608
609 fn allow_dst_multicast(&self) -> bool {
610 match self {
623 Icmpv6Error::ParameterProblem { allow_dst_multicast, code, pointer: _ } => {
624 assert!(
625 !allow_dst_multicast
626 || *code == Icmpv6ParameterProblemCode::UnrecognizedIpv6Option
627 );
628 *allow_dst_multicast
629 }
630 Icmpv6Error::PacketTooBig { .. } => true,
631 _ => false,
632 }
633 }
634}
635
636pub trait IcmpErrorHandler<I: IcmpHandlerIpExt, BC>: DeviceIdContext<AnyDevice> {
638 fn send_icmp_error_message<B: BufferMut>(
645 &mut self,
646 bindings_ctx: &mut BC,
647 device: Option<&Self::DeviceId>,
648 frame_dst: Option<FrameDestination>,
649 src_ip: SocketIpAddr<I::Addr>,
650 dst_ip: SocketIpAddr<I::Addr>,
651 original_packet: B,
652 error: I::IcmpError,
653 header_len: usize,
654 proto: I::Proto,
655 marks: &Marks,
656 );
657}
658
659impl<BC: IcmpBindingsContext, CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>>
660 IcmpErrorHandler<Ipv4, BC> for CC
661{
662 fn send_icmp_error_message<B: BufferMut>(
663 &mut self,
664 bindings_ctx: &mut BC,
665 device: Option<&CC::DeviceId>,
666 frame_dst: Option<FrameDestination>,
667 src_ip: SocketIpAddr<Ipv4Addr>,
668 dst_ip: SocketIpAddr<Ipv4Addr>,
669 original_packet: B,
670 icmp_error: Icmpv4Error,
671 header_len: usize,
672 proto: Ipv4Proto,
673 marks: &Marks,
674 ) {
675 if is_icmp_error_or_redirect_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..])
678 {
679 return;
680 }
681
682 icmp_error.update_counters(&self.counters());
683 send_icmpv4_error_message(
684 self,
685 bindings_ctx,
686 device,
687 frame_dst,
688 src_ip,
689 dst_ip,
690 icmp_error.create_message(),
691 original_packet,
692 header_len,
693 marks,
694 );
695 }
696}
697
698impl<BC: IcmpBindingsContext, CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>>
699 IcmpErrorHandler<Ipv6, BC> for CC
700{
701 fn send_icmp_error_message<B: BufferMut>(
702 &mut self,
703 bindings_ctx: &mut BC,
704 device: Option<&CC::DeviceId>,
705 frame_dst: Option<FrameDestination>,
706 src_ip: SocketIpAddr<Ipv6Addr>,
707 dst_ip: SocketIpAddr<Ipv6Addr>,
708 original_packet: B,
709 error: Icmpv6Error,
710 header_len: usize,
711 proto: Ipv6Proto,
712 marks: &Marks,
713 ) {
714 if is_icmp_error_or_redirect_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..])
717 {
718 return;
719 }
720
721 error.update_counters(&self.counters());
722 send_icmpv6_error_message(
723 self,
724 bindings_ctx,
725 device,
726 frame_dst,
727 src_ip,
728 dst_ip,
729 error.create_message(),
730 original_packet,
731 error.allow_dst_multicast(),
732 marks,
733 )
734 }
735}
736
737pub trait IcmpBindingsContext: InstantContext + RngContext + IcmpBindingsTypes {}
740impl<BC> IcmpBindingsContext for BC where
741 BC: InstantContext + RngContext + IcmpBindingsTypes + IcmpBindingsTypes
742{
743}
744
745pub trait IcmpBindingsTypes: InstantBindingsTypes + TxMetadataBindingsTypes {}
747impl<BT: InstantBindingsTypes + TxMetadataBindingsTypes> IcmpBindingsTypes for BT {}
748
749pub trait IcmpStateContext {}
757
758pub trait EchoTransportContextMarker {}
768
769pub trait InnerIcmpContext<I, BC>: IpSocketHandler<I, BC>
772where
773 I: IpLayerIpExt,
774 BC: IcmpBindingsTypes,
775{
776 type EchoTransportContext: IpTransportContext<I, BC, Self> + EchoTransportContextMarker;
779
780 fn receive_icmp_error(
810 &mut self,
811 bindings_ctx: &mut BC,
812 device: &Self::DeviceId,
813 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
814 original_dst_ip: SpecifiedAddr<I::Addr>,
815 original_proto: I::Proto,
816 original_body: &[u8],
817 err: I::ErrorCode,
818 );
819
820 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
823 &mut self,
824 cb: F,
825 ) -> O;
826}
827
828pub trait InnerIcmpv4Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv4, BC> {
832 fn should_send_timestamp_reply(&self) -> bool;
834}
835
836pub trait InnerIcmpv6Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv6, BC> {}
840impl<BC: IcmpBindingsTypes, CC: InnerIcmpContext<Ipv6, BC>> InnerIcmpv6Context<BC> for CC {}
841
842macro_rules! try_send_error {
856 ($core_ctx:expr, $bindings_ctx:expr, $e:expr) => {{
857 let send = $core_ctx.with_error_send_bucket_mut(|error_send_bucket| {
858 error_send_bucket.try_take($bindings_ctx)
859 });
860
861 if send {
862 $core_ctx.counters().error.increment();
863 $e
864 } else {
865 trace!("ip::icmp::try_send_error!: dropping rate-limited ICMP error message");
866 Ok(())
867 }
868 }};
869}
870
871pub enum IcmpIpTransportContext {}
873
874fn receive_ip_transport_icmp_error<
875 I: IpLayerIpExt,
876 CC: InnerIcmpContext<I, BC> + CounterContext<IcmpRxCounters<I>>,
877 BC: IcmpBindingsContext,
878>(
879 core_ctx: &mut CC,
880 bindings_ctx: &mut BC,
881 device: &CC::DeviceId,
882 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
883 original_dst_ip: SpecifiedAddr<I::Addr>,
884 original_body: &[u8],
885 err: I::ErrorCode,
886) {
887 core_ctx.counters().error_delivered_to_transport_layer.increment();
888 trace!("IcmpIpTransportContext::receive_icmp_error({:?})", err);
889
890 let mut parse_body = original_body;
891 match parse_body.parse::<IcmpPacketRaw<I, _, IcmpEchoRequest>>() {
892 Ok(_echo_request) => (),
895 Err(_) => {
896 return;
900 }
901 }
902
903 <CC::EchoTransportContext as IpTransportContext<I, BC, CC>>::receive_icmp_error(
904 core_ctx,
905 bindings_ctx,
906 device,
907 original_src_ip,
908 original_dst_ip,
909 original_body,
910 err,
911 );
912}
913
914impl<
915 BC: IcmpBindingsContext,
916 CC: InnerIcmpv4Context<BC>
917 + PmtuHandler<Ipv4, BC>
918 + CounterContext<IcmpRxCounters<Ipv4>>
919 + CounterContext<IcmpTxCounters<Ipv4>>,
920> IpTransportContext<Ipv4, BC, CC> for IcmpIpTransportContext
921{
922 type EarlyDemuxSocket = Never;
923
924 fn early_demux<B: ParseBuffer>(
925 _core_ctx: &mut CC,
926 _device: &CC::DeviceId,
927 _src_ip: Ipv4Addr,
928 _dst_ip: Ipv4Addr,
929 _buffer: B,
930 ) -> Option<Self::EarlyDemuxSocket> {
931 None
932 }
933
934 fn receive_icmp_error(
935 core_ctx: &mut CC,
936 bindings_ctx: &mut BC,
937 device: &CC::DeviceId,
938 original_src_ip: Option<SpecifiedAddr<Ipv4Addr>>,
939 original_dst_ip: SpecifiedAddr<Ipv4Addr>,
940 original_body: &[u8],
941 err: Icmpv4ErrorCode,
942 ) {
943 receive_ip_transport_icmp_error(
944 core_ctx,
945 bindings_ctx,
946 device,
947 original_src_ip,
948 original_dst_ip,
949 original_body,
950 err,
951 )
952 }
953
954 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv4>>(
955 core_ctx: &mut CC,
956 bindings_ctx: &mut BC,
957 device: &CC::DeviceId,
958 src_ip: Ipv4SourceAddr,
959 dst_ip: SpecifiedAddr<Ipv4Addr>,
960 mut buffer: B,
961 info: &LocalDeliveryPacketInfo<Ipv4, H>,
962 _early_demux_socket: Option<Never>,
963 ) -> Result<(), (B, Icmpv4Error)> {
964 let LocalDeliveryPacketInfo { meta, header_info: _, marks } = info;
965 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
966 if let Some(delivery) = transparent_override {
967 unreachable!(
968 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
969 transparent proxy rules can only be configured for TCP and UDP packets"
970 );
971 }
972
973 trace!(
974 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet({}, {})",
975 src_ip, dst_ip
976 );
977 let packet =
978 match buffer.parse_with::<_, Icmpv4Packet<_>>(IcmpParseArgs::new(src_ip, dst_ip)) {
979 Ok(packet) => packet,
980 Err(_) => return Ok(()), };
982
983 match packet {
984 Icmpv4Packet::EchoRequest(echo_request) => {
985 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_request.increment();
986
987 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
988 let req = *echo_request.message();
989 let code = echo_request.code();
990 let (local_ip, remote_ip) = (dst_ip, src_ip);
991 debug!(
992 "replying to ICMP echo request from {remote_ip} to {local_ip}%{device:?}: \
993 id={}, seq={}",
994 req.id(),
995 req.seq()
996 );
997 send_icmp_reply(
998 core_ctx,
999 bindings_ctx,
1000 device,
1001 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1002 SocketIpAddr::new_ipv4_specified(local_ip),
1003 |src_ip| {
1004 IcmpPacketBuilder::<Ipv4, _>::new(src_ip, *remote_ip, code, req.reply())
1005 .wrap_body(buffer)
1006 },
1007 &WithMarks(marks),
1008 );
1009 } else {
1010 trace!(
1011 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1012 Received echo request with an unspecified source address"
1013 );
1014 }
1015 }
1016 Icmpv4Packet::EchoReply(echo_reply) => {
1017 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_reply.increment();
1018 trace!(
1019 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1020 Received an EchoReply message"
1021 );
1022 let parse_metadata = echo_reply.parse_metadata();
1023 buffer.undo_parse(parse_metadata);
1024 return <CC::EchoTransportContext
1025 as IpTransportContext<Ipv4, BC, CC>>::receive_ip_packet(
1026 core_ctx,
1027 bindings_ctx,
1028 device,
1029 src_ip,
1030 dst_ip,
1031 buffer,
1032 info,
1033 None,
1034 );
1035 }
1036 Icmpv4Packet::TimestampRequest(timestamp_request) => {
1037 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1038 .timestamp_request
1039 .increment();
1040 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
1041 if core_ctx.should_send_timestamp_reply() {
1042 trace!(
1043 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1044 receive_ip_packet: Responding to Timestamp Request message"
1045 );
1046 const NOW: u32 = 0x80000000;
1065 let reply = timestamp_request.message().reply(NOW, NOW);
1066 let (local_ip, remote_ip) = (dst_ip, src_ip);
1067 buffer.shrink_front_to(0);
1074 send_icmp_reply(
1075 core_ctx,
1076 bindings_ctx,
1077 device,
1078 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1079 SocketIpAddr::new_ipv4_specified(local_ip),
1080 |src_ip| {
1081 IcmpPacketBuilder::<Ipv4, _>::new(
1082 src_ip,
1083 *remote_ip,
1084 IcmpZeroCode,
1085 reply,
1086 )
1087 .wrap_body(buffer)
1088 },
1089 &WithMarks(marks),
1090 );
1091 } else {
1092 trace!(
1093 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1094 receive_ip_packet: Silently ignoring Timestamp Request message"
1095 );
1096 }
1097 } else {
1098 trace!(
1099 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1100 receive_ip_packet: Received timestamp request with an unspecified source \
1101 address"
1102 );
1103 }
1104 }
1105 Icmpv4Packet::TimestampReply(_) => {
1106 debug!(
1109 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1110 Received unsolicited Timestamp Reply message"
1111 );
1112 }
1113 Icmpv4Packet::DestUnreachable(dest_unreachable) => {
1114 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1115 .dest_unreachable
1116 .increment_code(dest_unreachable.code());
1117 trace!(
1118 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1119 Received a Destination Unreachable message"
1120 );
1121
1122 let error = if dest_unreachable.code()
1123 == Icmpv4DestUnreachableCode::FragmentationRequired
1124 {
1125 let mtu = if let Some(next_hop_mtu) = dest_unreachable.message().next_hop_mtu()
1126 {
1127 core_ctx.update_pmtu_if_less(
1137 bindings_ctx,
1138 dst_ip.get(),
1139 src_ip.get(),
1140 Mtu::new(u32::from(next_hop_mtu.get())),
1141 )
1142 } else {
1143 let (original_packet_buf, inner_body) = dest_unreachable.body().bytes();
1165 debug_assert!(inner_body.is_none());
1167 if original_packet_buf.len() >= 4 {
1168 let total_len =
1172 u16::from_be_bytes(original_packet_buf[2..4].try_into().unwrap());
1173
1174 trace!(
1175 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1176 receive_ip_packet: Next-Hop MTU is 0 so using the next best PMTU \
1177 value from {total_len}"
1178 );
1179
1180 core_ctx.update_pmtu_next_lower(
1181 bindings_ctx,
1182 dst_ip.get(),
1183 src_ip.get(),
1184 Mtu::new(u32::from(total_len)),
1185 )
1186 } else {
1187 trace!(
1192 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1193 receive_ip_packet: Original packet buf is too small to get \
1194 original packet len so ignoring"
1195 );
1196 None
1197 }
1198 };
1199 mtu.and_then(|mtu| {
1200 let mtu = u16::try_from(mtu.get()).unwrap_or(u16::MAX);
1201 let mtu = NonZeroU16::new(mtu)?;
1202 Some(Icmpv4ErrorCode::DestUnreachable(
1203 dest_unreachable.code(),
1204 IcmpDestUnreachable::new_for_frag_req(mtu),
1205 ))
1206 })
1207 } else {
1208 Some(Icmpv4ErrorCode::DestUnreachable(
1209 dest_unreachable.code(),
1210 *dest_unreachable.message(),
1211 ))
1212 };
1213
1214 if let Some(error) = error {
1215 receive_icmpv4_error(core_ctx, bindings_ctx, device, &dest_unreachable, error);
1216 }
1217 }
1218 Icmpv4Packet::TimeExceeded(time_exceeded) => {
1219 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1220 .time_exceeded
1221 .increment_code(time_exceeded.code());
1222 trace!(
1223 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1224 Received a Time Exceeded message"
1225 );
1226
1227 receive_icmpv4_error(
1228 core_ctx,
1229 bindings_ctx,
1230 device,
1231 &time_exceeded,
1232 Icmpv4ErrorCode::TimeExceeded(time_exceeded.code()),
1233 );
1234 }
1235 Icmpv4Packet::Redirect(_) => {
1237 debug!(
1238 "Unimplemented: <IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1239 receive_ip_packet::redirect"
1240 )
1241 }
1242 Icmpv4Packet::ParameterProblem(parameter_problem) => {
1243 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1244 .parameter_problem
1245 .increment_code(parameter_problem.code());
1246 trace!(
1247 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1248 Received a Parameter Problem message"
1249 );
1250
1251 receive_icmpv4_error(
1252 core_ctx,
1253 bindings_ctx,
1254 device,
1255 ¶meter_problem,
1256 Icmpv4ErrorCode::ParameterProblem(parameter_problem.code()),
1257 );
1258 }
1259 }
1260
1261 Ok(())
1262 }
1263}
1264
1265#[allow(missing_docs)]
1268pub enum NdpMessage {
1269 NeighborSolicitation {
1270 message: NeighborSolicitation,
1271 code: <NeighborSolicitation as IcmpMessage<Ipv6>>::Code,
1272 },
1273
1274 RouterSolicitation {
1275 message: RouterSolicitation,
1276 code: <RouterSolicitation as IcmpMessage<Ipv6>>::Code,
1277 },
1278
1279 NeighborAdvertisement {
1280 message: NeighborAdvertisement,
1281 code: <NeighborAdvertisement as IcmpMessage<Ipv6>>::Code,
1282 },
1283}
1284
1285pub fn send_ndp_packet<BC, CC, S>(
1287 core_ctx: &mut CC,
1288 bindings_ctx: &mut BC,
1289 device_id: &CC::DeviceId,
1290 src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1291 dst_ip: SpecifiedAddr<Ipv6Addr>,
1292 body: S,
1293 message: NdpMessage,
1294) -> Result<(), IpSendFrameError<S>>
1295where
1296 CC: IpLayerHandler<Ipv6, BC>,
1297 S: Serializer + PartialSerializer,
1298 S::Buffer: BufferMut,
1299{
1300 macro_rules! send {
1301 ($message:expr, $code:expr) => {{
1302 let mut ser = IcmpPacketBuilder::<Ipv6, _>::new(
1304 src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
1305 dst_ip.get(),
1306 $code,
1307 $message,
1308 )
1309 .wrap_body(body);
1310 match IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
1311 core_ctx,
1312 bindings_ctx,
1313 SendIpPacketMeta {
1314 device: device_id,
1315 src_ip,
1316 dst_ip,
1317 destination: IpPacketDestination::from_addr(dst_ip),
1318 ttl: NonZeroU8::new(REQUIRED_NDP_IP_PACKET_HOP_LIMIT),
1319 proto: Ipv6Proto::Icmpv6,
1320 mtu: Mtu::no_limit(),
1321 dscp_and_ecn: DscpAndEcn::default(),
1322 },
1323 DynTransportSerializer::new(&mut ser),
1324 ) {
1325 Ok(()) => Ok(()),
1326 Err(e) => Err(e
1327 .map_serializer(|s| {
1328 let _: DynTransportSerializer<'_, _> = s;
1330 })
1331 .map_serializer(|()| ser.into_inner())),
1332 }
1333 }};
1334 }
1335
1336 match message {
1337 NdpMessage::NeighborSolicitation { message, code } => send!(message, code),
1338 NdpMessage::RouterSolicitation { message, code } => send!(message, code),
1339 NdpMessage::NeighborAdvertisement { message, code } => send!(message, code),
1340 }
1341}
1342
1343fn send_neighbor_advertisement<
1344 BC,
1345 CC: Ipv6DeviceHandler<BC>
1346 + IpDeviceHandler<Ipv6, BC>
1347 + IpLayerHandler<Ipv6, BC>
1348 + CounterContext<NdpCounters>,
1349>(
1350 core_ctx: &mut CC,
1351 bindings_ctx: &mut BC,
1352 device_id: &CC::DeviceId,
1353 solicited: bool,
1354 device_addr: UnicastAddr<Ipv6Addr>,
1355 dst_ip: SpecifiedAddr<Ipv6Addr>,
1356) {
1357 core_ctx.counters().tx.neighbor_advertisement.increment();
1358 debug!("send_neighbor_advertisement from {:?} to {:?}", device_addr, dst_ip);
1359 debug_assert!(dst_ip.is_valid_unicast() || (!solicited && dst_ip.is_multicast()));
1366
1367 let src_ll = core_ctx.get_link_layer_addr(&device_id);
1374
1375 let advertisement = NeighborAdvertisement::new(
1377 core_ctx.is_router_device(&device_id),
1378 solicited,
1379 true, device_addr.get(),
1392 );
1393 let _: Result<(), _> = send_ndp_packet(
1394 core_ctx,
1395 bindings_ctx,
1396 &device_id,
1397 Some(device_addr.into_specified()),
1398 dst_ip,
1399 OptionSequenceBuilder::new(
1400 src_ll
1401 .as_ref()
1402 .map(Ipv6LinkLayerAddr::as_bytes)
1403 .map(NdpOptionBuilder::TargetLinkLayerAddress)
1404 .iter(),
1405 )
1406 .into_serializer(),
1407 NdpMessage::NeighborAdvertisement { message: advertisement, code: IcmpZeroCode },
1408 );
1409}
1410
1411fn receive_ndp_packet<
1412 B: SplitByteSlice,
1413 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1414 CC: InnerIcmpv6Context<BC>
1415 + Ipv6DeviceHandler<BC>
1416 + IpDeviceHandler<Ipv6, BC>
1417 + IpDeviceIngressStateContext<Ipv6>
1418 + NudIpHandler<Ipv6, BC>
1419 + IpLayerHandler<Ipv6, BC>
1420 + CounterContext<NdpCounters>,
1421 H: IpHeaderInfo<Ipv6>,
1422>(
1423 core_ctx: &mut CC,
1424 bindings_ctx: &mut BC,
1425 device_id: &CC::DeviceId,
1426 src_ip: Ipv6SourceAddr,
1427 dst_ip: SpecifiedAddr<Ipv6Addr>,
1428 packet: NdpPacket<B>,
1429 header_info: &H,
1430) {
1431 if header_info.hop_limit() != REQUIRED_NDP_IP_PACKET_HOP_LIMIT {
1449 trace!("dropping NDP packet from {src_ip} with invalid hop limit");
1450 return;
1451 }
1452
1453 match packet {
1454 NdpPacket::RouterSolicitation(_) => {}
1455 NdpPacket::Redirect(_) => {}
1457 NdpPacket::NeighborSolicitation(ref p) => {
1458 let target_address = p.message().target_address();
1465 let target_address = match UnicastAddr::new(*target_address) {
1466 Some(a) => a,
1467 None => {
1468 trace!(
1469 "dropping NS from {} with non-unicast target={:?}",
1470 src_ip, target_address
1471 );
1472 return;
1473 }
1474 };
1475
1476 let (source_link_addr, nonce) = p.body().iter().fold(
1478 (None, None),
1479 |(found_source_link_addr, found_nonce), option| {
1480 match option {
1481 NdpOption::Nonce(nonce) => (found_source_link_addr, Some(nonce)),
1482 NdpOption::SourceLinkLayerAddress(source_link_addr) => {
1483 (Some(source_link_addr), found_nonce)
1484 }
1485 NdpOption::Mtu(_)
1493 | NdpOption::PrefixInformation(_)
1494 | NdpOption::RecursiveDnsServer(_)
1495 | NdpOption::RedirectedHeader { .. }
1496 | NdpOption::RouteInformation(_)
1497 | NdpOption::TargetLinkLayerAddress(_) => {
1498 (found_source_link_addr, found_nonce)
1499 }
1500 }
1501 },
1502 );
1503
1504 if src_ip == Ipv6SourceAddr::Unspecified {
1505 if target_address.get().to_solicited_node_address().get() != dst_ip.get() {
1514 debug!(
1515 "dropping NS from {} for {} with invalid IPv6 dst ({}).",
1516 src_ip, target_address, dst_ip
1517 );
1518 return;
1519 }
1520 if let Some(addr) = source_link_addr {
1525 debug!(
1526 "dropping NS from {} for {} with source link-layer addr option ({:?}).",
1527 src_ip, target_address, addr
1528 );
1529 return;
1530 }
1531 }
1532
1533 core_ctx.counters().rx.neighbor_solicitation.increment();
1534
1535 match src_ip {
1536 Ipv6SourceAddr::Unspecified => {
1537 match IpDeviceHandler::handle_received_dad_packet(
1547 core_ctx,
1548 bindings_ctx,
1549 &device_id,
1550 target_address.into_specified(),
1551 nonce,
1552 ) {
1553 Some(IpAddressState::Assigned) => {
1554 send_neighbor_advertisement(
1558 core_ctx,
1559 bindings_ctx,
1560 &device_id,
1561 false,
1562 target_address,
1563 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified(),
1564 );
1565 }
1566 Some(IpAddressState::Tentative) => {
1567 }
1570 Some(IpAddressState::Unavailable) | None => {
1571 }
1574 }
1575
1576 return;
1577 }
1578 Ipv6SourceAddr::Unicast(src_ip) => {
1579 match core_ctx
1581 .address_status_for_device(target_address.into_specified(), device_id)
1582 {
1583 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned) => {}
1584 AddressStatus::Present(
1585 Ipv6PresentAddressStatus::UnicastTentative
1586 | Ipv6PresentAddressStatus::Multicast,
1587 )
1588 | AddressStatus::Unassigned => {
1589 return;
1593 }
1594 }
1595
1596 if let Some(link_addr) = source_link_addr {
1597 NudIpHandler::handle_neighbor_probe(
1598 core_ctx,
1599 bindings_ctx,
1600 &device_id,
1601 src_ip.into_specified(),
1602 link_addr,
1603 );
1604 }
1605
1606 send_neighbor_advertisement(
1607 core_ctx,
1608 bindings_ctx,
1609 &device_id,
1610 true,
1611 target_address,
1612 src_ip.into_specified(),
1613 );
1614 }
1615 }
1616 }
1617 NdpPacket::NeighborAdvertisement(ref p) => {
1618 let target_address = p.message().target_address();
1622
1623 let target_address = match UnicastAddr::new(*target_address) {
1630 Some(a) => a,
1631 None => {
1632 debug!(
1633 "dropping NA from {} with non-unicast target={:?}",
1634 src_ip, target_address
1635 );
1636 return;
1637 }
1638 };
1639 if let Some(dst_ip) = MulticastAddr::new(dst_ip.get())
1643 && p.message().solicited_flag()
1644 {
1645 debug!(
1646 "dropping NA from {} with solicited flag and multicast dst {}",
1647 src_ip, dst_ip
1648 );
1649 return;
1650 }
1651
1652 core_ctx.counters().rx.neighbor_advertisement.increment();
1653
1654 let nonce = None;
1658 match IpDeviceHandler::handle_received_dad_packet(
1659 core_ctx,
1660 bindings_ctx,
1661 &device_id,
1662 target_address.into_specified(),
1663 nonce,
1664 ) {
1665 Some(IpAddressState::Assigned) => {
1666 error!(
1684 "NA from {src_ip} with target address {target_address} that is also \
1685 assigned on device {device_id:?}",
1686 );
1687 }
1688 Some(IpAddressState::Tentative) => {
1689 return;
1692 }
1693 Some(IpAddressState::Unavailable) | None => {
1694 }
1698 }
1699
1700 let link_addr = p.body().iter().find_map(|o| o.target_link_layer_address());
1701
1702 NudIpHandler::handle_neighbor_confirmation(
1703 core_ctx,
1704 bindings_ctx,
1705 &device_id,
1706 target_address.into_specified(),
1707 link_addr,
1708 ConfirmationFlags {
1709 solicited_flag: p.message().solicited_flag(),
1710 override_flag: p.message().override_flag(),
1711 },
1712 );
1713 }
1714 NdpPacket::RouterAdvertisement(ref p) => {
1715 let src_ip = match src_ip {
1728 Ipv6SourceAddr::Unicast(ip) => match LinkLocalUnicastAddr::new(*ip) {
1729 Some(ip) => ip,
1730 None => return,
1731 },
1732 Ipv6SourceAddr::Unspecified => return,
1733 };
1734
1735 let ra = p.message();
1736 debug!("received router advertisement from {:?}: {:?}", src_ip, ra);
1737 core_ctx.counters().rx.router_advertisement.increment();
1738
1739 if let Some(retransmit_timer) = ra.retransmit_timer() {
1746 Ipv6DeviceHandler::set_discovered_retrans_timer(
1747 core_ctx,
1748 bindings_ctx,
1749 &device_id,
1750 retransmit_timer,
1751 );
1752 }
1753
1754 if let Some(hop_limit) = ra.current_hop_limit() {
1761 trace!(
1762 "receive_ndp_packet: NDP RA: updating device's hop limit to {:?} for router: {:?}",
1763 ra.current_hop_limit(),
1764 src_ip
1765 );
1766 IpDeviceHandler::set_default_hop_limit(core_ctx, &device_id, hop_limit);
1767 }
1768
1769 Ipv6DeviceHandler::update_discovered_ipv6_route(
1771 core_ctx,
1772 bindings_ctx,
1773 &device_id,
1774 Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) },
1775 p.message().router_lifetime().map(NonZeroNdpLifetime::Finite),
1776 );
1777
1778 for option in p.body().iter() {
1779 match option {
1780 NdpOption::TargetLinkLayerAddress(_)
1781 | NdpOption::RedirectedHeader { .. }
1782 | NdpOption::RecursiveDnsServer(_)
1783 | NdpOption::Nonce(_) => {}
1784 NdpOption::SourceLinkLayerAddress(addr) => {
1785 debug!("processing SourceLinkLayerAddress option in RA: {:?}", addr);
1786 NudIpHandler::handle_neighbor_probe(
1812 core_ctx,
1813 bindings_ctx,
1814 &device_id,
1815 {
1816 let src_ip: UnicastAddr<_> = src_ip.into_addr();
1817 src_ip.into_specified()
1818 },
1819 addr,
1820 );
1821 }
1822 NdpOption::PrefixInformation(prefix_info) => {
1823 debug!("processing Prefix Information option in RA: {:?}", prefix_info);
1824 if prefix_info.prefix().is_link_local() {
1842 continue;
1843 }
1844
1845 let subnet = match prefix_info.subnet() {
1846 Ok(subnet) => subnet,
1847 Err(err) => match err {
1848 SubnetError::PrefixTooLong | SubnetError::HostBitsSet => continue,
1849 },
1850 };
1851
1852 match UnicastAddr::new(subnet.network()) {
1853 Some(UnicastAddr { .. }) => {}
1854 None => continue,
1855 }
1856
1857 let valid_lifetime = prefix_info.valid_lifetime();
1858
1859 if prefix_info.on_link_flag() {
1860 Ipv6DeviceHandler::update_discovered_ipv6_route(
1862 core_ctx,
1863 bindings_ctx,
1864 &device_id,
1865 Ipv6DiscoveredRoute { subnet, gateway: None },
1866 valid_lifetime,
1867 )
1868 }
1869
1870 if prefix_info.autonomous_address_configuration_flag() {
1871 Ipv6DeviceHandler::apply_slaac_update(
1872 core_ctx,
1873 bindings_ctx,
1874 &device_id,
1875 subnet,
1876 prefix_info.preferred_lifetime(),
1877 valid_lifetime,
1878 );
1879 }
1880 }
1881 NdpOption::RouteInformation(rio) => {
1882 debug!("processing Route Information option in RA: {:?}", rio);
1883 Ipv6DeviceHandler::update_discovered_ipv6_route(
1885 core_ctx,
1886 bindings_ctx,
1887 &device_id,
1888 Ipv6DiscoveredRoute {
1889 subnet: rio.prefix().clone(),
1890 gateway: Some(src_ip),
1891 },
1892 rio.route_lifetime(),
1893 )
1894 }
1895 NdpOption::Mtu(mtu) => {
1896 debug!("processing MTU option in RA: {:?}", mtu);
1897 Ipv6DeviceHandler::set_link_mtu(core_ctx, &device_id, Mtu::new(mtu));
1901 }
1902 }
1903 }
1904
1905 bindings_ctx.on_event(RouterAdvertisementEvent {
1906 options_bytes: Box::from(p.body().bytes()),
1907 source: **src_ip,
1908 device: device_id.clone(),
1909 });
1910 }
1911 }
1912}
1913
1914impl<
1915 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1916 CC: InnerIcmpv6Context<BC>
1917 + InnerIcmpContext<Ipv6, BC>
1918 + Ipv6DeviceHandler<BC>
1919 + IpDeviceHandler<Ipv6, BC>
1920 + IpDeviceIngressStateContext<Ipv6>
1921 + PmtuHandler<Ipv6, BC>
1922 + NudIpHandler<Ipv6, BC>
1923 + IpLayerHandler<Ipv6, BC>
1924 + CounterContext<IcmpRxCounters<Ipv6>>
1925 + CounterContext<IcmpTxCounters<Ipv6>>
1926 + CounterContext<NdpCounters>,
1927> IpTransportContext<Ipv6, BC, CC> for IcmpIpTransportContext
1928{
1929 type EarlyDemuxSocket = Never;
1930
1931 fn early_demux<B: ParseBuffer>(
1932 _core_ctx: &mut CC,
1933 _device: &CC::DeviceId,
1934 _src_ip: Ipv6Addr,
1935 _dst_ip: Ipv6Addr,
1936 _buffer: B,
1937 ) -> Option<Self::EarlyDemuxSocket> {
1938 None
1939 }
1940
1941 fn receive_icmp_error(
1942 core_ctx: &mut CC,
1943 bindings_ctx: &mut BC,
1944 device: &CC::DeviceId,
1945 original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1946 original_dst_ip: SpecifiedAddr<Ipv6Addr>,
1947 original_body: &[u8],
1948 err: Icmpv6ErrorCode,
1949 ) {
1950 receive_ip_transport_icmp_error(
1951 core_ctx,
1952 bindings_ctx,
1953 device,
1954 original_src_ip,
1955 original_dst_ip,
1956 original_body,
1957 err,
1958 )
1959 }
1960
1961 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
1962 core_ctx: &mut CC,
1963 bindings_ctx: &mut BC,
1964 device: &CC::DeviceId,
1965 src_ip: Ipv6SourceAddr,
1966 dst_ip: SpecifiedAddr<Ipv6Addr>,
1967 mut buffer: B,
1968 info: &LocalDeliveryPacketInfo<Ipv6, H>,
1969 _early_demux_socket: Option<Never>,
1970 ) -> Result<(), (B, Icmpv6Error)> {
1971 let LocalDeliveryPacketInfo { meta, header_info, marks } = info;
1972 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
1973 if let Some(delivery) = transparent_override {
1974 unreachable!(
1975 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
1976 transparent proxy rules can only be configured for TCP and UDP packets"
1977 );
1978 }
1979
1980 trace!(
1981 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet({:?}, {})",
1982 src_ip, dst_ip
1983 );
1984
1985 let packet = match buffer
1986 .parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(src_ip.get(), dst_ip))
1987 {
1988 Ok(packet) => packet,
1989 Err(_) => return Ok(()), };
1991
1992 match packet {
1993 Icmpv6Packet::EchoRequest(echo_request) => {
1994 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_request.increment();
1995
1996 if let Some(src_ip) = SocketIpAddr::new_from_ipv6_source(src_ip) {
1997 match SocketIpAddr::try_from(dst_ip) {
1998 Ok(dst_ip) => {
1999 let req = *echo_request.message();
2000 let code = echo_request.code();
2001 let (local_ip, remote_ip) = (dst_ip, src_ip);
2002 debug!(
2003 "replying to ICMP echo request from {remote_ip}: id={}, seq={}",
2004 req.id(),
2005 req.seq()
2006 );
2007 send_icmp_reply(
2008 core_ctx,
2009 bindings_ctx,
2010 device,
2011 remote_ip,
2012 local_ip,
2013 |src_ip| {
2014 IcmpPacketBuilder::<Ipv6, _>::new(
2015 src_ip,
2016 remote_ip.addr(),
2017 code,
2018 req.reply(),
2019 )
2020 .wrap_body(buffer)
2021 },
2022 &WithMarks(marks),
2023 );
2024 }
2025 Err(AddrIsMappedError {}) => {
2026 trace!(
2027 "IpTransportContext<Ipv6>::receive_ip_packet: Received echo request with an ipv4-mapped-ipv6 destination address"
2028 );
2029 }
2030 }
2031 } else {
2032 trace!(
2033 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received echo request with an unspecified source address"
2034 );
2035 }
2036 }
2037 Icmpv6Packet::EchoReply(echo_reply) => {
2038 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_reply.increment();
2039 trace!(
2040 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received an EchoReply message"
2041 );
2042 let parse_metadata = echo_reply.parse_metadata();
2043 buffer.undo_parse(parse_metadata);
2044 return <CC::EchoTransportContext
2045 as IpTransportContext<Ipv6, BC, CC>>::receive_ip_packet(
2046 core_ctx,
2047 bindings_ctx,
2048 device,
2049 src_ip,
2050 dst_ip,
2051 buffer,
2052 info,
2053 None
2054 );
2055 }
2056 Icmpv6Packet::Ndp(packet) => receive_ndp_packet(
2057 core_ctx,
2058 bindings_ctx,
2059 device,
2060 src_ip,
2061 dst_ip,
2062 packet,
2063 header_info,
2064 ),
2065 Icmpv6Packet::PacketTooBig(packet_too_big) => {
2066 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2067 .packet_too_big
2068 .increment();
2069 trace!(
2070 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received a Packet Too Big message"
2071 );
2072 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2073 let mtu = core_ctx.update_pmtu_if_less(
2083 bindings_ctx,
2084 dst_ip.get(),
2085 src_ip.get(),
2086 Mtu::new(packet_too_big.message().mtu()),
2087 );
2088 if let Some(mtu) = mtu {
2089 receive_icmpv6_error(
2090 core_ctx,
2091 bindings_ctx,
2092 device,
2093 &packet_too_big,
2094 Icmpv6ErrorCode::PacketTooBig(mtu),
2095 );
2096 }
2097 }
2098 }
2099 Icmpv6Packet::Mld(packet) => {
2100 core_ctx.receive_mld_packet(
2101 bindings_ctx,
2102 &device,
2103 src_ip,
2104 dst_ip,
2105 packet,
2106 header_info,
2107 );
2108 }
2109 Icmpv6Packet::DestUnreachable(dest_unreachable) => {
2110 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2111 .dest_unreachable
2112 .increment_code(dest_unreachable.code());
2113 receive_icmpv6_error(
2114 core_ctx,
2115 bindings_ctx,
2116 device,
2117 &dest_unreachable,
2118 Icmpv6ErrorCode::DestUnreachable(dest_unreachable.code()),
2119 )
2120 }
2121 Icmpv6Packet::TimeExceeded(time_exceeded) => {
2122 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2123 .time_exceeded
2124 .increment_code(time_exceeded.code());
2125 receive_icmpv6_error(
2126 core_ctx,
2127 bindings_ctx,
2128 device,
2129 &time_exceeded,
2130 Icmpv6ErrorCode::TimeExceeded(time_exceeded.code()),
2131 )
2132 }
2133 Icmpv6Packet::ParameterProblem(parameter_problem) => {
2134 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2135 .parameter_problem
2136 .increment_code(parameter_problem.code());
2137 receive_icmpv6_error(
2138 core_ctx,
2139 bindings_ctx,
2140 device,
2141 ¶meter_problem,
2142 Icmpv6ErrorCode::ParameterProblem(parameter_problem.code()),
2143 )
2144 }
2145 }
2146
2147 Ok(())
2148 }
2149}
2150
2151#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2152struct WithMarks<'a>(&'a Marks);
2153
2154impl<'a> OptionDelegationMarker for WithMarks<'a> {}
2155
2156impl<'a, I: IpExt> DelegatedRouteResolutionOptions<I> for WithMarks<'a> {
2157 fn marks(&self) -> &Marks {
2158 let Self(marks) = self;
2159 marks
2160 }
2161}
2162
2163impl<'a, I: IpExt> DelegatedSendOptions<I> for WithMarks<'a> {}
2164
2165fn send_icmp_reply<I, BC, CC, S, F, O>(
2176 core_ctx: &mut CC,
2177 bindings_ctx: &mut BC,
2178 device: &CC::DeviceId,
2179 original_src_ip: SocketIpAddr<I::Addr>,
2180 original_dst_ip: SocketIpAddr<I::Addr>,
2181 get_body_from_src_ip: F,
2182 ip_options: &O,
2183) where
2184 I: IpExt + FilterIpExt + IcmpCountersIpExt,
2185 CC: IpSocketHandler<I, BC> + DeviceIdContext<AnyDevice> + CounterContext<IcmpTxCounters<I>>,
2186 BC: TxMetadataBindingsTypes,
2187 S: DynamicTransportSerializer<I>,
2188 F: FnOnce(SpecifiedAddr<I::Addr>) -> S,
2189 O: SendOptions<I> + RouteResolutionOptions<I>,
2190{
2191 trace!("send_icmp_reply({:?}, {}, {})", device, original_src_ip, original_dst_ip);
2192 core_ctx.counters().reply.increment();
2193 let tx_metadata: BC::TxMetadata = Default::default();
2194
2195 let egress_device = (original_dst_ip.as_ref().is_multicast()
2199 || original_dst_ip.as_ref().must_have_zone())
2200 .then_some(EitherDeviceId::Strong(device));
2201
2202 core_ctx
2203 .send_oneshot_ip_packet_with_dyn_serializer(
2204 bindings_ctx,
2205 IpSocketArgs {
2206 device: egress_device,
2207 local_ip: IpDeviceAddr::new_from_socket_ip_addr(original_dst_ip),
2208 remote_ip: original_src_ip,
2209 proto: I::ICMP_IP_PROTO,
2210 options: ip_options,
2211 },
2212 tx_metadata,
2213 |src_ip| get_body_from_src_ip(src_ip.into()),
2214 )
2215 .unwrap_or_else(|err| {
2216 debug!("failed to send ICMP reply: {}", err);
2217 })
2218}
2219
2220fn receive_icmpv4_error<
2225 BC: IcmpBindingsContext,
2226 CC: InnerIcmpv4Context<BC>,
2227 B: SplitByteSlice,
2228 M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>,
2229>(
2230 core_ctx: &mut CC,
2231 bindings_ctx: &mut BC,
2232 device: &CC::DeviceId,
2233 packet: &IcmpPacket<Ipv4, B, M>,
2234 err: Icmpv4ErrorCode,
2235) {
2236 packet.with_original_packet(|res| match res {
2237 Ok(original_packet) => {
2238 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2239 Some(ip) => ip,
2240 None => {
2241 trace!("receive_icmpv4_error: Got ICMP error message whose original IPv4 packet contains an unspecified destination address; discarding");
2242 return;
2243 },
2244 };
2245 InnerIcmpContext::receive_icmp_error(
2246 core_ctx,
2247 bindings_ctx,
2248 device,
2249 SpecifiedAddr::new(original_packet.src_ip()),
2250 dst_ip,
2251 original_packet.proto(),
2252 original_packet.body().into_inner(),
2253 err,
2254 );
2255 }
2256 Err(_) => debug!(
2257 "receive_icmpv4_error: Got ICMP error message with unparsable original IPv4 packet"
2258 ),
2259 })
2260}
2261
2262fn receive_icmpv6_error<
2267 BC: IcmpBindingsContext,
2268 CC: InnerIcmpv6Context<BC>,
2269 B: SplitByteSlice,
2270 M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>,
2271>(
2272 core_ctx: &mut CC,
2273 bindings_ctx: &mut BC,
2274 device: &CC::DeviceId,
2275 packet: &IcmpPacket<Ipv6, B, M>,
2276 err: Icmpv6ErrorCode,
2277) {
2278 packet.with_original_packet(|res| match res {
2279 Ok(original_packet) => {
2280 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2281 Some(ip)=>ip,
2282 None => {
2283 trace!("receive_icmpv6_error: Got ICMP error message whose original IPv6 packet contains an unspecified destination address; discarding");
2284 return;
2285 },
2286 };
2287 match original_packet.body_proto() {
2288 Ok((body, proto)) => {
2289 InnerIcmpContext::receive_icmp_error(
2290 core_ctx,
2291 bindings_ctx,
2292 device,
2293 SpecifiedAddr::new(original_packet.src_ip()),
2294 dst_ip,
2295 proto,
2296 body.into_inner(),
2297 err,
2298 );
2299 }
2300 Err(ExtHdrParseError) => {
2301 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");
2302 return;
2305 }
2306 }
2307 }
2308 Err(_body) => debug!(
2309 "receive_icmpv6_error: Got ICMPv6 error message with unparsable original IPv6 packet"
2310 ),
2311 })
2312}
2313
2314fn send_icmpv4_error_message<
2315 B: BufferMut,
2316 BC: IcmpBindingsContext,
2317 CC: InnerIcmpv4Context<BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2318>(
2319 core_ctx: &mut CC,
2320 bindings_ctx: &mut BC,
2321 device: Option<&CC::DeviceId>,
2322 frame_dst: Option<FrameDestination>,
2323 original_src_ip: SocketIpAddr<Ipv4Addr>,
2324 original_dst_ip: SocketIpAddr<Ipv4Addr>,
2325 message: Icmpv4ErrorMessage,
2326 mut original_packet: B,
2327 header_len: usize,
2328 marks: &Marks,
2329) {
2330 if !should_send_icmpv4_error(frame_dst, original_src_ip.into(), original_dst_ip.into()) {
2334 return;
2335 }
2336
2337 original_packet.shrink_back_to(header_len + 64);
2340
2341 let tx_metadata: BC::TxMetadata = Default::default();
2342
2343 macro_rules! send {
2344 ($message:expr, $code:expr) => {{
2345 let _ = try_send_error!(
2348 core_ctx,
2349 bindings_ctx,
2350 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2351 bindings_ctx,
2352 IpSocketArgs {
2353 device: device.map(EitherDeviceId::Strong),
2354 local_ip: None,
2355 remote_ip: original_src_ip,
2356 proto: Ipv4Proto::Icmp,
2357 options: &WithMarks(marks),
2358 },
2359 tx_metadata,
2360 |local_ip| {
2361 IcmpPacketBuilder::<Ipv4, _>::new(
2362 local_ip.addr(),
2363 original_src_ip.addr(),
2364 $code,
2365 $message,
2366 )
2367 .wrap_body(original_packet)
2368 },
2369 )
2370 );
2371 }};
2372 }
2373
2374 match message {
2375 Icmpv4ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2376 Icmpv4ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2377 Icmpv4ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2378 }
2379}
2380
2381fn send_icmpv6_error_message<
2382 B: BufferMut,
2383 BC: IcmpBindingsContext,
2384 CC: InnerIcmpv6Context<BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2385>(
2386 core_ctx: &mut CC,
2387 bindings_ctx: &mut BC,
2388 device: Option<&CC::DeviceId>,
2389 frame_dst: Option<FrameDestination>,
2390 original_src_ip: SocketIpAddr<Ipv6Addr>,
2391 original_dst_ip: SocketIpAddr<Ipv6Addr>,
2392 message: Icmpv6ErrorMessage,
2393 original_packet: B,
2394 allow_dst_multicast: bool,
2395 marks: &Marks,
2396) {
2397 if !should_send_icmpv6_error(
2401 frame_dst,
2402 original_src_ip.into(),
2403 original_dst_ip.into(),
2404 allow_dst_multicast,
2405 ) {
2406 return;
2407 }
2408
2409 struct Icmpv6ErrorOptions<'a>(&'a Marks);
2410 impl<'a> OptionDelegationMarker for Icmpv6ErrorOptions<'a> {}
2411 impl<'a> DelegatedSendOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2412 fn mtu(&self) -> Mtu {
2413 Ipv6::MINIMUM_LINK_MTU
2414 }
2415 }
2416 impl<'a> DelegatedRouteResolutionOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2417 fn marks(&self) -> &Marks {
2418 let Self(marks) = self;
2419 marks
2420 }
2421 }
2422
2423 let tx_metadata: BC::TxMetadata = Default::default();
2424
2425 macro_rules! send {
2426 ($message:expr, $code:expr) => {{
2427 let _ = try_send_error!(
2430 core_ctx,
2431 bindings_ctx,
2432 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2433 bindings_ctx,
2434 IpSocketArgs {
2435 device: device.map(EitherDeviceId::Strong),
2436 local_ip: None,
2437 remote_ip: original_src_ip,
2438 proto: Ipv6Proto::Icmpv6,
2439 options: &Icmpv6ErrorOptions(marks),
2440 },
2441 tx_metadata,
2442 |local_ip| {
2443 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
2444 local_ip.addr(),
2445 original_src_ip.addr(),
2446 $code,
2447 $message,
2448 );
2449
2450 icmp_builder.wrap_body(TruncatingSerializer::new(
2453 original_packet,
2454 TruncateDirection::DiscardBack,
2455 ))
2456 },
2457 )
2458 );
2459 }};
2460 }
2461
2462 match message {
2463 Icmpv6ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2464 Icmpv6ErrorMessage::PacketTooBig { message, code } => send!(message, code),
2465 Icmpv6ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2466 Icmpv6ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2467 }
2468}
2469
2470fn should_send_icmpv4_error(
2488 frame_dst: Option<FrameDestination>,
2489 src_ip: SpecifiedAddr<Ipv4Addr>,
2490 dst_ip: SpecifiedAddr<Ipv4Addr>,
2491) -> bool {
2492 !(dst_ip.is_multicast()
2512 || dst_ip.is_limited_broadcast()
2513 || frame_dst.is_some_and(|dst| dst.is_broadcast())
2514 || src_ip.is_loopback()
2515 || src_ip.is_limited_broadcast()
2516 || src_ip.is_multicast()
2517 || src_ip.is_class_e())
2518}
2519
2520fn should_send_icmpv6_error(
2547 frame_dst: Option<FrameDestination>,
2548 src_ip: SpecifiedAddr<Ipv6Addr>,
2549 dst_ip: SpecifiedAddr<Ipv6Addr>,
2550 allow_dst_multicast: bool,
2551) -> bool {
2552 let multicast_frame_dst = match frame_dst {
2555 Some(FrameDestination::Individual { local: _ }) | None => false,
2556 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
2557 };
2558 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
2559 return false;
2560 }
2561 if src_ip.is_loopback() || src_ip.is_multicast() {
2562 return false;
2563 }
2564 true
2565}
2566
2567fn is_icmp_error_or_redirect_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
2579 proto == I::ICMP_IP_PROTO
2580 && peek_message_type::<I::IcmpMessageType>(buf)
2581 .map(IcmpMessageType::is_error_or_redirect)
2582 .unwrap_or(true)
2583}
2584
2585#[cfg(any(test, feature = "testutils"))]
2587pub(crate) mod testutil {
2588 use alloc::vec::Vec;
2589 use net_types::ethernet::Mac;
2590 use net_types::ip::{Ipv6, Ipv6Addr};
2591 use packet::{Buf, InnerPacketBuilder as _, Serializer as _};
2592 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
2593 use packet_formats::icmp::ndp::{
2594 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
2595 };
2596 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
2597 use packet_formats::ip::Ipv6Proto;
2598 use packet_formats::ipv6::Ipv6PacketBuilder;
2599
2600 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
2601
2602 pub fn neighbor_advertisement_ip_packet(
2605 src_ip: Ipv6Addr,
2606 dst_ip: Ipv6Addr,
2607 router_flag: bool,
2608 solicited_flag: bool,
2609 override_flag: bool,
2610 mac: Mac,
2611 ) -> Buf<Vec<u8>> {
2612 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
2613 .into_serializer()
2614 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2615 src_ip,
2616 dst_ip,
2617 IcmpZeroCode,
2618 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
2619 ))
2620 .wrap_in(Ipv6PacketBuilder::new(
2621 src_ip,
2622 dst_ip,
2623 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2624 Ipv6Proto::Icmpv6,
2625 ))
2626 .serialize_vec_outer()
2627 .unwrap()
2628 .unwrap_b()
2629 }
2630
2631 pub fn neighbor_solicitation_ip_packet(
2634 src_ip: Ipv6Addr,
2635 dst_ip: Ipv6Addr,
2636 target_addr: Ipv6Addr,
2637 mac: Mac,
2638 ) -> Buf<Vec<u8>> {
2639 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
2640 .into_serializer()
2641 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2642 src_ip,
2643 dst_ip,
2644 IcmpZeroCode,
2645 NeighborSolicitation::new(target_addr),
2646 ))
2647 .wrap_in(Ipv6PacketBuilder::new(
2648 src_ip,
2649 dst_ip,
2650 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2651 Ipv6Proto::Icmpv6,
2652 ))
2653 .serialize_vec_outer()
2654 .unwrap()
2655 .unwrap_b()
2656 }
2657}
2658
2659#[cfg(test)]
2660mod tests {
2661 use alloc::vec;
2662 use alloc::vec::Vec;
2663 use packet_formats::icmp::ndp::options::NdpNonce;
2664
2665 use core::fmt::Debug;
2666 use core::time::Duration;
2667
2668 use net_types::ip::Subnet;
2669 use netstack3_base::testutil::{
2670 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId,
2671 TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt, set_logger_for_test,
2672 };
2673 use netstack3_base::{CtxPair, Uninstantiable};
2674 use netstack3_filter::TransportPacketSerializer;
2675 use packet::{Buf, EmptyBuf};
2676 use packet_formats::icmp::mld::MldPacket;
2677 use packet_formats::ip::IpProto;
2678 use packet_formats::utils::NonZeroDuration;
2679
2680 use super::*;
2681 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
2682 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
2683 use crate::internal::socket::{
2684 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
2685 };
2686 use crate::socket::RouteResolutionOptions;
2687
2688 use test_util::assert_geq;
2689
2690 pub(super) trait IcmpTestIpExt:
2691 TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt
2692 {
2693 }
2694 impl<I: TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt> IcmpTestIpExt for I {}
2695
2696 type InnerIpSocketCtx<I> = FakeCoreCtx<
2698 FakeIpSocketCtx<I, FakeDeviceId>,
2699 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
2700 FakeDeviceId,
2701 >;
2702
2703 pub(super) struct FakeIcmpCoreCtx<I: IcmpTestIpExt> {
2705 ip_socket_ctx: InnerIpSocketCtx<I>,
2706 icmp: FakeIcmpCoreCtxState<I>,
2707 }
2708
2709 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
2711 (),
2712 RouterAdvertisementEvent<FakeDeviceId>,
2713 FakeIcmpBindingsCtxState<I>,
2714 (),
2715 >;
2716
2717 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
2721
2722 pub(super) struct FakeIcmpCoreCtxState<I: IcmpTestIpExt> {
2723 error_send_bucket: TokenBucket<FakeInstant>,
2724 receive_icmp_error: Vec<I::ErrorCode>,
2725 rx_counters: IcmpRxCounters<I>,
2726 tx_counters: IcmpTxCounters<I>,
2727 ndp_counters: NdpCounters,
2728 }
2729
2730 impl<I: IcmpTestIpExt> FakeIcmpCoreCtx<I> {
2731 fn with_errors_per_second(errors_per_second: u64) -> Self {
2732 Self {
2733 icmp: FakeIcmpCoreCtxState {
2734 error_send_bucket: TokenBucket::new(errors_per_second),
2735 receive_icmp_error: Default::default(),
2736 rx_counters: Default::default(),
2737 tx_counters: Default::default(),
2738 ndp_counters: Default::default(),
2739 },
2740 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
2741 core::iter::once(FakeDeviceConfig {
2742 device: FakeDeviceId,
2743 local_ips: vec![I::TEST_ADDRS.local_ip],
2744 remote_ips: vec![I::TEST_ADDRS.remote_ip],
2745 }),
2746 )),
2747 }
2748 }
2749 }
2750
2751 impl<I: IcmpTestIpExt> Default for FakeIcmpCoreCtx<I> {
2752 fn default() -> Self {
2753 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
2754 }
2755 }
2756
2757 impl<I: IcmpTestIpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
2758 type DeviceId = FakeDeviceId;
2759 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
2760 }
2761
2762 impl<I: IcmpTestIpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
2763 impl<I: IcmpTestIpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
2764
2765 impl<I: IcmpTestIpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
2766 fn counters(&self) -> &IcmpRxCounters<I> {
2767 &self.icmp.rx_counters
2768 }
2769 }
2770
2771 impl<I: IcmpTestIpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
2772 fn counters(&self) -> &IcmpTxCounters<I> {
2773 &self.icmp.tx_counters
2774 }
2775 }
2776
2777 impl<I: IcmpTestIpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
2778 fn counters(&self) -> &NdpCounters {
2779 &self.icmp.ndp_counters
2780 }
2781 }
2782
2783 pub enum FakeEchoIpTransportContext {}
2784
2785 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
2786
2787 impl<I> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
2788 for FakeEchoIpTransportContext
2789 where
2790 I: IcmpTestIpExt + IpLayerIpExt,
2791 {
2792 type EarlyDemuxSocket = Never;
2793
2794 fn early_demux<B: ParseBuffer>(
2795 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2796 _device: &FakeDeviceId,
2797 _src_ip: I::Addr,
2798 _dst_ip: I::Addr,
2799 _buffer: B,
2800 ) -> Option<Self::EarlyDemuxSocket> {
2801 None
2802 }
2803
2804 fn receive_icmp_error(
2805 core_ctx: &mut FakeIcmpCoreCtx<I>,
2806 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2807 _device: &FakeDeviceId,
2808 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2809 _original_dst_ip: SpecifiedAddr<I::Addr>,
2810 _original_body: &[u8],
2811 _err: I::ErrorCode,
2812 ) {
2813 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
2814 }
2815
2816 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
2817 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2818 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2819 _device: &FakeDeviceId,
2820 _src_ip: I::RecvSrcAddr,
2821 _dst_ip: SpecifiedAddr<I::Addr>,
2822 _buffer: B,
2823 _info: &LocalDeliveryPacketInfo<I, H>,
2824 _early_demux_socket: Option<Never>,
2825 ) -> Result<(), (B, I::IcmpError)> {
2826 unimplemented!()
2827 }
2828 }
2829
2830 impl<I: IpLayerIpExt + IcmpTestIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>>
2831 for FakeIcmpCoreCtx<I>
2832 {
2833 type EchoTransportContext = FakeEchoIpTransportContext;
2834
2835 fn receive_icmp_error(
2836 &mut self,
2837 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2838 device: &Self::DeviceId,
2839 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2840 original_dst_ip: SpecifiedAddr<I::Addr>,
2841 original_proto: I::Proto,
2842 original_body: &[u8],
2843 err: I::ErrorCode,
2844 ) {
2845 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
2846 self.icmp.receive_icmp_error.push(err);
2847 if original_proto == I::ICMP_IP_PROTO {
2848 receive_ip_transport_icmp_error(
2849 self,
2850 bindings_ctx,
2851 device,
2852 original_src_ip,
2853 original_dst_ip,
2854 original_body,
2855 err,
2856 )
2857 }
2858 }
2859
2860 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
2861 &mut self,
2862 cb: F,
2863 ) -> O {
2864 cb(&mut self.icmp.error_send_bucket)
2865 }
2866 }
2867
2868 #[test]
2869 fn test_should_send_icmpv4_error() {
2870 let src_ip = TEST_ADDRS_V4.local_ip;
2871 let dst_ip = TEST_ADDRS_V4.remote_ip;
2872 let frame_dst = FrameDestination::Individual { local: true };
2873 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
2874 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
2875
2876 assert!(should_send_icmpv4_error(Some(frame_dst), src_ip, dst_ip));
2878 assert!(should_send_icmpv4_error(None, src_ip, dst_ip));
2879
2880 assert!(!should_send_icmpv4_error(
2882 Some(frame_dst),
2883 src_ip,
2884 Ipv4::LIMITED_BROADCAST_ADDRESS,
2885 ));
2886
2887 assert!(!should_send_icmpv4_error(Some(frame_dst), src_ip, multicast_ip_1,));
2889
2890 assert!(!should_send_icmpv4_error(Some(FrameDestination::Broadcast), src_ip, dst_ip,));
2892
2893 assert!(!should_send_icmpv4_error(Some(frame_dst), Ipv4::LOOPBACK_ADDRESS, dst_ip,));
2895
2896 assert!(!should_send_icmpv4_error(
2898 Some(frame_dst),
2899 Ipv4::LIMITED_BROADCAST_ADDRESS,
2900 dst_ip,
2901 ));
2902
2903 assert!(!should_send_icmpv4_error(Some(frame_dst), multicast_ip_2, dst_ip));
2905
2906 assert!(!should_send_icmpv4_error(
2908 Some(frame_dst),
2909 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
2910 dst_ip,
2911 ));
2912 }
2913
2914 #[test]
2915 fn test_should_send_icmpv6_error() {
2916 let src_ip = TEST_ADDRS_V6.local_ip;
2917 let dst_ip = TEST_ADDRS_V6.remote_ip;
2918 let frame_dst = FrameDestination::Individual { local: true };
2919 let multicast_ip_1 =
2920 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
2921 let multicast_ip_2 =
2922 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
2923
2924 assert!(should_send_icmpv6_error(
2926 Some(frame_dst),
2927 src_ip,
2928 dst_ip,
2929 false ));
2931 assert!(should_send_icmpv6_error(
2932 None, src_ip, dst_ip, false ));
2934 assert!(should_send_icmpv6_error(
2935 Some(frame_dst),
2936 src_ip,
2937 dst_ip,
2938 true ));
2940
2941 assert!(!should_send_icmpv6_error(
2944 Some(frame_dst),
2945 src_ip,
2946 multicast_ip_1,
2947 false ));
2949 assert!(should_send_icmpv6_error(
2950 Some(frame_dst),
2951 src_ip,
2952 multicast_ip_1,
2953 true ));
2955
2956 assert!(!should_send_icmpv6_error(
2959 Some(FrameDestination::Broadcast),
2960 src_ip,
2961 dst_ip,
2962 false ));
2964 assert!(should_send_icmpv6_error(
2965 Some(FrameDestination::Broadcast),
2966 src_ip,
2967 dst_ip,
2968 true ));
2970
2971 assert!(!should_send_icmpv6_error(
2973 Some(frame_dst),
2974 Ipv6::LOOPBACK_ADDRESS,
2975 dst_ip,
2976 false ));
2978 assert!(!should_send_icmpv6_error(
2979 Some(frame_dst),
2980 Ipv6::LOOPBACK_ADDRESS,
2981 dst_ip,
2982 true ));
2984
2985 assert!(!should_send_icmpv6_error(
2987 Some(frame_dst),
2988 multicast_ip_2,
2989 dst_ip,
2990 false ));
2992 assert!(!should_send_icmpv6_error(
2993 Some(frame_dst),
2994 multicast_ip_2,
2995 dst_ip,
2996 true ));
2998
2999 assert!(!should_send_icmpv6_error(
3002 Some(FrameDestination::Broadcast),
3003 multicast_ip_2,
3004 dst_ip,
3005 false ));
3007 assert!(!should_send_icmpv6_error(
3008 Some(FrameDestination::Broadcast),
3009 multicast_ip_2,
3010 dst_ip,
3011 true ));
3013 assert!(!should_send_icmpv6_error(
3014 Some(frame_dst),
3015 multicast_ip_2,
3016 multicast_ip_1,
3017 false ));
3019 assert!(!should_send_icmpv6_error(
3020 Some(frame_dst),
3021 multicast_ip_2,
3022 multicast_ip_1,
3023 true ));
3025 }
3026
3027 #[derive(Default)]
3034 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3035 _marker: core::marker::PhantomData<I>,
3036 }
3037
3038 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3039 fn should_send_timestamp_reply(&self) -> bool {
3040 false
3041 }
3042 }
3043 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3044 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3045
3046 impl<I: IcmpTestIpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3047 fn new_ip_socket<O>(
3048 &mut self,
3049 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3050 args: IpSocketArgs<'_, Self::DeviceId, I, O>,
3051 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3052 where
3053 O: RouteResolutionOptions<I>,
3054 {
3055 self.ip_socket_ctx.new_ip_socket(bindings_ctx, args)
3056 }
3057
3058 fn send_ip_packet<S, O>(
3059 &mut self,
3060 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3061 socket: &IpSock<I, Self::WeakDeviceId>,
3062 body: S,
3063 options: &O,
3064 tx_meta: FakeTxMetadata,
3065 ) -> Result<(), IpSockSendError>
3066 where
3067 S: TransportPacketSerializer<I>,
3068 S::Buffer: BufferMut,
3069 O: SendOptions<I> + RouteResolutionOptions<I>,
3070 {
3071 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3072 }
3073
3074 fn confirm_reachable<O>(
3075 &mut self,
3076 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3077 socket: &IpSock<I, Self::WeakDeviceId>,
3078 options: &O,
3079 ) where
3080 O: RouteResolutionOptions<I>,
3081 {
3082 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3083 }
3084 }
3085
3086 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3087 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3088 unimplemented!()
3089 }
3090
3091 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3092 unreachable!()
3093 }
3094
3095 fn handle_received_dad_packet(
3096 &mut self,
3097 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3098 _device_id: &Self::DeviceId,
3099 _addr: SpecifiedAddr<Ipv6Addr>,
3100 _probe_data: Option<NdpNonce<&'_ [u8]>>,
3101 ) -> Option<IpAddressState> {
3102 unimplemented!()
3103 }
3104 }
3105
3106 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3107 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3108 cb(&())
3109 }
3110
3111 fn get_local_addr_for_remote(
3112 &mut self,
3113 _device_id: &Self::DeviceId,
3114 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3115 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3116 unimplemented!()
3117 }
3118
3119 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3120 unimplemented!()
3121 }
3122 }
3123
3124 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3125 fn address_status_for_device(
3126 &mut self,
3127 _addr: SpecifiedAddr<Ipv6Addr>,
3128 _device_id: &Self::DeviceId,
3129 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3130 unimplemented!()
3131 }
3132 }
3133
3134 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3135 type LinkLayerAddr = Uninstantiable;
3136
3137 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3138 unimplemented!()
3139 }
3140
3141 fn set_discovered_retrans_timer(
3142 &mut self,
3143 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3144 _device_id: &Self::DeviceId,
3145 _retrans_timer: NonZeroDuration,
3146 ) {
3147 unimplemented!()
3148 }
3149
3150 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3151 unimplemented!()
3152 }
3153
3154 fn update_discovered_ipv6_route(
3155 &mut self,
3156 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3157 _device_id: &Self::DeviceId,
3158 _route: Ipv6DiscoveredRoute,
3159 _lifetime: Option<NonZeroNdpLifetime>,
3160 ) {
3161 unimplemented!()
3162 }
3163
3164 fn apply_slaac_update(
3165 &mut self,
3166 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3167 _device_id: &Self::DeviceId,
3168 _subnet: Subnet<Ipv6Addr>,
3169 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3170 _valid_lifetime: Option<NonZeroNdpLifetime>,
3171 ) {
3172 unimplemented!()
3173 }
3174
3175 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3176 &mut self,
3177 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3178 _device: &FakeDeviceId,
3179 _src_ip: Ipv6SourceAddr,
3180 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3181 _packet: MldPacket<B>,
3182 _header_info: &H,
3183 ) {
3184 unimplemented!()
3185 }
3186 }
3187
3188 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3189 fn send_ip_packet_from_device<S>(
3190 &mut self,
3191 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3192 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3193 _body: S,
3194 ) -> Result<(), IpSendFrameError<S>> {
3195 unimplemented!()
3196 }
3197
3198 fn send_ip_frame<S>(
3199 &mut self,
3200 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3201 _device: &Self::DeviceId,
3202 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3203 _body: S,
3204 ) -> Result<(), IpSendFrameError<S>>
3205 where
3206 S: Serializer,
3207 S::Buffer: BufferMut,
3208 {
3209 unimplemented!()
3210 }
3211 }
3212
3213 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3214 fn handle_neighbor_probe(
3215 &mut self,
3216 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3217 _device_id: &Self::DeviceId,
3218 _neighbor: SpecifiedAddr<Ipv6Addr>,
3219 _link_addr: &[u8],
3220 ) {
3221 unimplemented!()
3222 }
3223
3224 fn handle_neighbor_confirmation(
3225 &mut self,
3226 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3227 _device_id: &Self::DeviceId,
3228 _neighbor: SpecifiedAddr<Ipv6Addr>,
3229 _link_addr: Option<&[u8]>,
3230 _flags: ConfirmationFlags,
3231 ) {
3232 unimplemented!()
3233 }
3234
3235 fn flush_neighbor_table(
3236 &mut self,
3237 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3238 _device_id: &Self::DeviceId,
3239 ) {
3240 unimplemented!()
3241 }
3242 }
3243
3244 #[test]
3245 fn test_receive_icmpv4_error() {
3246 const ICMP_ID: u16 = 0x0F;
3249 const SEQ_NUM: u16 = 0xF0;
3250
3251 fn test_receive_icmpv4_error_helper<
3266 C: Debug,
3267 M: IcmpMessage<Ipv4, Code = C> + Debug,
3268 F: Fn(&FakeIcmpCtx<Ipv4>),
3269 >(
3270 original_packet: &mut [u8],
3271 code: C,
3272 msg: M,
3273 f: F,
3274 ) {
3275 set_logger_for_test();
3276
3277 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3278
3279 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3280 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3281 core_ctx,
3282 bindings_ctx,
3283 &FakeDeviceId,
3284 Ipv4SourceAddr::new(*TEST_ADDRS_V4.remote_ip).unwrap(),
3285 TEST_ADDRS_V4.local_ip,
3286 IcmpPacketBuilder::new(TEST_ADDRS_V4.remote_ip, TEST_ADDRS_V4.local_ip, code, msg)
3287 .wrap_body(Buf::new(original_packet, ..))
3288 .serialize_vec_outer()
3289 .unwrap(),
3290 &LocalDeliveryPacketInfo::default(),
3291 None,
3292 )
3293 .unwrap();
3294 f(&ctx);
3295 }
3296 let mut buffer = EmptyBuf
3309 .wrap_in(IcmpPacketBuilder::<Ipv4, _>::new(
3310 TEST_ADDRS_V4.local_ip,
3311 TEST_ADDRS_V4.remote_ip,
3312 IcmpZeroCode,
3313 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3314 ))
3315 .wrap_in(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3316 TEST_ADDRS_V4.local_ip,
3317 TEST_ADDRS_V4.remote_ip,
3318 64,
3319 Ipv4Proto::Icmp,
3320 ))
3321 .serialize_vec_outer()
3322 .unwrap();
3323
3324 test_receive_icmpv4_error_helper(
3325 buffer.as_mut(),
3326 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3327 IcmpDestUnreachable::default(),
3328 |CtxPair { core_ctx, bindings_ctx: _ }| {
3329 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3330 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3331 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3332 assert_eq!(
3333 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3334 1
3335 );
3336 let err = Icmpv4ErrorCode::DestUnreachable(
3337 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3338 IcmpDestUnreachable::default(),
3339 );
3340 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3341 },
3342 );
3343
3344 test_receive_icmpv4_error_helper(
3345 buffer.as_mut(),
3346 Icmpv4TimeExceededCode::TtlExpired,
3347 IcmpTimeExceeded::default(),
3348 |CtxPair { core_ctx, bindings_ctx: _ }| {
3349 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3350 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3351 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3352 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3353 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3354 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3355 },
3356 );
3357
3358 test_receive_icmpv4_error_helper(
3359 buffer.as_mut(),
3360 Icmpv4ParameterProblemCode::PointerIndicatesError,
3361 Icmpv4ParameterProblem::new(0),
3362 |CtxPair { core_ctx, bindings_ctx: _ }| {
3363 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3364 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3365 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3366 assert_eq!(
3367 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3368 1
3369 );
3370 let err = Icmpv4ErrorCode::ParameterProblem(
3371 Icmpv4ParameterProblemCode::PointerIndicatesError,
3372 );
3373 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3374 },
3375 );
3376
3377 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3384 TEST_ADDRS_V4.local_ip,
3385 TEST_ADDRS_V4.remote_ip,
3386 64,
3387 Ipv4Proto::Icmp,
3388 )
3389 .wrap_body(EmptyBuf)
3390 .serialize_vec_outer()
3391 .unwrap();
3392
3393 test_receive_icmpv4_error_helper(
3394 buffer.as_mut(),
3395 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3396 IcmpDestUnreachable::default(),
3397 |CtxPair { core_ctx, bindings_ctx: _ }| {
3398 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3399 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3400 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3401 assert_eq!(
3402 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3403 1
3404 );
3405 let err = Icmpv4ErrorCode::DestUnreachable(
3406 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3407 IcmpDestUnreachable::default(),
3408 );
3409 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3410 },
3411 );
3412
3413 test_receive_icmpv4_error_helper(
3414 buffer.as_mut(),
3415 Icmpv4TimeExceededCode::TtlExpired,
3416 IcmpTimeExceeded::default(),
3417 |CtxPair { core_ctx, bindings_ctx: _ }| {
3418 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3419 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3420 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3421 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3422 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3423 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3424 },
3425 );
3426
3427 test_receive_icmpv4_error_helper(
3428 buffer.as_mut(),
3429 Icmpv4ParameterProblemCode::PointerIndicatesError,
3430 Icmpv4ParameterProblem::new(0),
3431 |CtxPair { core_ctx, bindings_ctx: _ }| {
3432 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3433 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3434 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3435 assert_eq!(
3436 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3437 1
3438 );
3439 let err = Icmpv4ErrorCode::ParameterProblem(
3440 Icmpv4ParameterProblemCode::PointerIndicatesError,
3441 );
3442 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3443 },
3444 );
3445
3446 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3452 TEST_ADDRS_V4.local_ip,
3453 TEST_ADDRS_V4.remote_ip,
3454 64,
3455 IpProto::Udp.into(),
3456 )
3457 .wrap_body(EmptyBuf)
3458 .serialize_vec_outer()
3459 .unwrap();
3460
3461 test_receive_icmpv4_error_helper(
3462 buffer.as_mut(),
3463 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3464 IcmpDestUnreachable::default(),
3465 |CtxPair { core_ctx, bindings_ctx: _ }| {
3466 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3467 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3468 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3469 assert_eq!(
3470 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3471 1
3472 );
3473 let err = Icmpv4ErrorCode::DestUnreachable(
3474 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3475 IcmpDestUnreachable::default(),
3476 );
3477 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3478 },
3479 );
3480
3481 test_receive_icmpv4_error_helper(
3482 buffer.as_mut(),
3483 Icmpv4TimeExceededCode::TtlExpired,
3484 IcmpTimeExceeded::default(),
3485 |CtxPair { core_ctx, bindings_ctx: _ }| {
3486 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3487 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3488 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3489 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3490 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3491 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3492 },
3493 );
3494
3495 test_receive_icmpv4_error_helper(
3496 buffer.as_mut(),
3497 Icmpv4ParameterProblemCode::PointerIndicatesError,
3498 Icmpv4ParameterProblem::new(0),
3499 |CtxPair { core_ctx, bindings_ctx: _ }| {
3500 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3501 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3502 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3503 assert_eq!(
3504 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3505 1
3506 );
3507 let err = Icmpv4ErrorCode::ParameterProblem(
3508 Icmpv4ParameterProblemCode::PointerIndicatesError,
3509 );
3510 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3511 },
3512 );
3513 }
3514
3515 #[test]
3516 fn test_receive_icmpv6_error() {
3517 const ICMP_ID: u16 = 0x0F;
3520 const SEQ_NUM: u16 = 0xF0;
3521
3522 fn test_receive_icmpv6_error_helper<
3537 C: Debug,
3538 M: IcmpMessage<Ipv6, Code = C> + Debug,
3539 F: Fn(&FakeIcmpCtx<Ipv6>),
3540 >(
3541 original_packet: &mut [u8],
3542 code: C,
3543 msg: M,
3544 f: F,
3545 ) {
3546 set_logger_for_test();
3547
3548 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
3549 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3550 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
3551 core_ctx,
3552 bindings_ctx,
3553 &FakeDeviceId,
3554 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
3555 TEST_ADDRS_V6.local_ip,
3556 IcmpPacketBuilder::new(TEST_ADDRS_V6.remote_ip, TEST_ADDRS_V6.local_ip, code, msg)
3557 .wrap_body(Buf::new(original_packet, ..))
3558 .serialize_vec_outer()
3559 .unwrap(),
3560 &LocalDeliveryPacketInfo::default(),
3561 None,
3562 )
3563 .unwrap();
3564 f(&ctx);
3565 }
3566 let mut buffer = EmptyBuf
3579 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3580 TEST_ADDRS_V6.local_ip,
3581 TEST_ADDRS_V6.remote_ip,
3582 IcmpZeroCode,
3583 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3584 ))
3585 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3586 TEST_ADDRS_V6.local_ip,
3587 TEST_ADDRS_V6.remote_ip,
3588 64,
3589 Ipv6Proto::Icmpv6,
3590 ))
3591 .serialize_vec_outer()
3592 .unwrap();
3593
3594 test_receive_icmpv6_error_helper(
3595 buffer.as_mut(),
3596 Icmpv6DestUnreachableCode::NoRoute,
3597 IcmpDestUnreachable::default(),
3598 |CtxPair { core_ctx, bindings_ctx: _ }| {
3599 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3600 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3601 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3602 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3603 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3604 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3605 },
3606 );
3607
3608 test_receive_icmpv6_error_helper(
3609 buffer.as_mut(),
3610 Icmpv6TimeExceededCode::HopLimitExceeded,
3611 IcmpTimeExceeded::default(),
3612 |CtxPair { core_ctx, bindings_ctx: _ }| {
3613 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3614 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3615 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3616 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3617 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3618 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3619 },
3620 );
3621
3622 test_receive_icmpv6_error_helper(
3623 buffer.as_mut(),
3624 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3625 Icmpv6ParameterProblem::new(0),
3626 |CtxPair { core_ctx, bindings_ctx: _ }| {
3627 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3628 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3629 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3630 assert_eq!(
3631 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3632 1
3633 );
3634 let err = Icmpv6ErrorCode::ParameterProblem(
3635 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3636 );
3637 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3638 },
3639 );
3640
3641 let mut buffer = EmptyBuf
3648 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3649 TEST_ADDRS_V6.local_ip,
3650 TEST_ADDRS_V6.remote_ip,
3651 64,
3652 Ipv6Proto::Icmpv6,
3653 ))
3654 .serialize_vec_outer()
3655 .unwrap();
3656
3657 test_receive_icmpv6_error_helper(
3658 buffer.as_mut(),
3659 Icmpv6DestUnreachableCode::NoRoute,
3660 IcmpDestUnreachable::default(),
3661 |CtxPair { core_ctx, bindings_ctx: _ }| {
3662 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3663 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3664 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3665 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3666 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3667 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3668 },
3669 );
3670
3671 test_receive_icmpv6_error_helper(
3672 buffer.as_mut(),
3673 Icmpv6TimeExceededCode::HopLimitExceeded,
3674 IcmpTimeExceeded::default(),
3675 |CtxPair { core_ctx, bindings_ctx: _ }| {
3676 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3677 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3678 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3679 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3680 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3681 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3682 },
3683 );
3684
3685 test_receive_icmpv6_error_helper(
3686 buffer.as_mut(),
3687 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3688 Icmpv6ParameterProblem::new(0),
3689 |CtxPair { core_ctx, bindings_ctx: _ }| {
3690 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3691 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3692 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3693 assert_eq!(
3694 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3695 1
3696 );
3697 let err = Icmpv6ErrorCode::ParameterProblem(
3698 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3699 );
3700 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3701 },
3702 );
3703
3704 let mut buffer = <Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3710 TEST_ADDRS_V6.local_ip,
3711 TEST_ADDRS_V6.remote_ip,
3712 64,
3713 IpProto::Udp.into(),
3714 )
3715 .wrap_body(EmptyBuf)
3716 .serialize_vec_outer()
3717 .unwrap();
3718
3719 test_receive_icmpv6_error_helper(
3720 buffer.as_mut(),
3721 Icmpv6DestUnreachableCode::NoRoute,
3722 IcmpDestUnreachable::default(),
3723 |CtxPair { core_ctx, bindings_ctx: _ }| {
3724 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3725 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3726 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3727 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3728 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3729 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3730 },
3731 );
3732
3733 test_receive_icmpv6_error_helper(
3734 buffer.as_mut(),
3735 Icmpv6TimeExceededCode::HopLimitExceeded,
3736 IcmpTimeExceeded::default(),
3737 |CtxPair { core_ctx, bindings_ctx: _ }| {
3738 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3739 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3740 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3741 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3742 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3743 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3744 },
3745 );
3746
3747 test_receive_icmpv6_error_helper(
3748 buffer.as_mut(),
3749 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3750 Icmpv6ParameterProblem::new(0),
3751 |CtxPair { core_ctx, bindings_ctx: _ }| {
3752 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3753 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3754 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3755 assert_eq!(
3756 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3757 1
3758 );
3759 let err = Icmpv6ErrorCode::ParameterProblem(
3760 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3761 );
3762 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3763 },
3764 );
3765 }
3766
3767 #[test]
3768 fn test_error_rate_limit() {
3769 set_logger_for_test();
3770
3771 fn send_icmpv4_ttl_expired_helper(
3773 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3774 ) {
3775 let error = Icmpv4Error::TtlExpired;
3776 core_ctx.send_icmp_error_message(
3777 bindings_ctx,
3778 Some(&FakeDeviceId),
3779 Some(FrameDestination::Individual { local: true }),
3780 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3781 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3782 EmptyBuf,
3783 error,
3784 0,
3785 packet_formats::ip::IpProto::Udp.into(),
3786 &Default::default(),
3787 );
3788 assert_geq!(core_ctx.icmp.tx_counters.time_exceeded.ttl_expired.get(), 1);
3789 }
3790
3791 fn send_icmpv4_parameter_problem_helper(
3793 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3794 ) {
3795 let error = Icmpv4Error::ParameterProblem {
3796 code: Icmpv4ParameterProblemCode::PointerIndicatesError,
3797 pointer: 0,
3798 };
3799 core_ctx.send_icmp_error_message(
3800 bindings_ctx,
3801 Some(&FakeDeviceId),
3802 Some(FrameDestination::Individual { local: true }),
3803 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3804 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3805 EmptyBuf,
3806 error,
3807 0,
3808 packet_formats::ip::IpProto::Udp.into(),
3809 &Default::default(),
3810 );
3811 assert_geq!(
3812 core_ctx.icmp.tx_counters.parameter_problem.pointer_indicates_error.get(),
3813 1
3814 );
3815 }
3816
3817 fn send_icmpv4_dest_unreachable_helper(
3819 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3820 ) {
3821 core_ctx.send_icmp_error_message(
3822 bindings_ctx,
3823 Some(&FakeDeviceId),
3824 Some(FrameDestination::Individual { local: true }),
3825 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3826 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3827 EmptyBuf,
3828 Icmpv4Error::NetUnreachable,
3829 0,
3830 packet_formats::ip::IpProto::Udp.into(),
3831 &Default::default(),
3832 );
3833 assert_geq!(
3834 core_ctx.icmp.tx_counters.dest_unreachable.dest_network_unreachable.get(),
3835 1
3836 );
3837 }
3838
3839 fn send_icmpv6_ttl_expired_helper(
3841 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3842 ) {
3843 core_ctx.send_icmp_error_message(
3844 bindings_ctx,
3845 Some(&FakeDeviceId),
3846 Some(FrameDestination::Individual { local: true }),
3847 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3848 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3849 EmptyBuf,
3850 Icmpv6Error::TtlExpired,
3851 0,
3852 Ipv6Proto::NoNextHeader,
3853 &Default::default(),
3854 );
3855 assert_geq!(core_ctx.icmp.tx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3856 }
3857
3858 fn send_icmpv6_packet_too_big_helper(
3860 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3861 ) {
3862 core_ctx.send_icmp_error_message(
3863 bindings_ctx,
3864 Some(&FakeDeviceId),
3865 Some(FrameDestination::Individual { local: true }),
3866 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3867 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3868 EmptyBuf,
3869 Icmpv6Error::PacketTooBig { mtu: Mtu::new(1280) },
3870 0,
3871 Ipv6Proto::NoNextHeader,
3872 &Default::default(),
3873 );
3874 assert_geq!(core_ctx.icmp.tx_counters.packet_too_big.get(), 1);
3875 }
3876
3877 fn send_icmpv6_parameter_problem_helper(
3879 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3880 ) {
3881 let error = Icmpv6Error::ParameterProblem {
3882 code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
3883 pointer: 0,
3884 allow_dst_multicast: false,
3885 };
3886 core_ctx.send_icmp_error_message(
3887 bindings_ctx,
3888 Some(&FakeDeviceId),
3889 Some(FrameDestination::Individual { local: true }),
3890 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3891 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3892 EmptyBuf,
3893 error,
3894 0,
3895 Ipv6Proto::NoNextHeader,
3896 &Default::default(),
3897 );
3898 assert_geq!(
3899 core_ctx.icmp.tx_counters.parameter_problem.erroneous_header_field.get(),
3900 1
3901 );
3902 }
3903
3904 fn send_icmpv6_dest_unreachable_helper(
3906 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3907 ) {
3908 core_ctx.send_icmp_error_message(
3909 bindings_ctx,
3910 Some(&FakeDeviceId),
3911 Some(FrameDestination::Individual { local: true }),
3912 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3913 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3914 EmptyBuf,
3915 Icmpv6Error::NetUnreachable,
3916 0,
3917 Ipv6Proto::NoNextHeader,
3918 &Default::default(),
3919 );
3920 assert_geq!(core_ctx.icmp.tx_counters.dest_unreachable.no_route.get(), 1);
3921 }
3922
3923 fn run_test<I: IcmpTestIpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
3927 with_errors_per_second: W,
3928 send: S,
3929 ) {
3930 const ERRORS_PER_SECOND: u64 = 64;
3944
3945 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
3946
3947 for i in 0..ERRORS_PER_SECOND {
3948 send(&mut ctx);
3949 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
3950 }
3951
3952 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3953 send(&mut ctx);
3954 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3955
3956 let mut ctx = with_errors_per_second(0);
3960 send(&mut ctx);
3961 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3962 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
3963 send(&mut ctx);
3964 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3965 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
3966 send(&mut ctx);
3967 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3968 }
3969
3970 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
3971 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
3972 }
3973 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
3974 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
3975 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
3976
3977 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
3978 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
3979 }
3980
3981 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
3982 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
3983 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
3984 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
3985 }
3986}