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::{
62 Ipv6DiscoveredRoute, Ipv6DiscoveredRouteProperties,
63};
64use crate::internal::device::{
65 IpAddressState, IpDeviceHandler, Ipv6DeviceHandler, Ipv6LinkLayerAddr,
66};
67use crate::internal::icmp::counters::{IcmpCountersIpExt, IcmpRxCounters, IcmpTxCounters};
68use crate::internal::local_delivery::{IpHeaderInfo, LocalDeliveryPacketInfo, ReceiveIpPacketMeta};
69use crate::internal::path_mtu::PmtuHandler;
70use crate::internal::socket::{
71 DelegatedRouteResolutionOptions, DelegatedSendOptions, IpSocketArgs, IpSocketHandler,
72 OptionDelegationMarker, RouteResolutionOptions, SendOptions,
73};
74use crate::internal::types::RoutePreference;
75
76pub const REQUIRED_NDP_IP_PACKET_HOP_LIMIT: u8 = 255;
88
89pub const DEFAULT_ERRORS_PER_SECOND: u64 = 1000;
97#[derive(GenericOverIp)]
99#[generic_over_ip(I, Ip)]
100pub struct IcmpState<I: IpExt + IcmpCountersIpExt, BT: IcmpBindingsTypes> {
101 error_send_bucket: Mutex<IpMarked<I, TokenBucket<BT::Instant>>>,
102 pub tx_counters: IcmpTxCounters<I>,
104 pub rx_counters: IcmpRxCounters<I>,
106}
107
108impl<I, BT> OrderedLockAccess<IpMarked<I, TokenBucket<BT::Instant>>> for IcmpState<I, BT>
109where
110 I: IpExt + IcmpCountersIpExt,
111 BT: IcmpBindingsTypes,
112{
113 type Lock = Mutex<IpMarked<I, TokenBucket<BT::Instant>>>;
114 fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
115 OrderedLockRef::new(&self.error_send_bucket)
116 }
117}
118
119#[derive(Default)]
121pub struct NdpRxCounters {
122 pub neighbor_solicitation: Counter,
124 pub neighbor_advertisement: Counter,
126 pub router_advertisement: Counter,
128 pub router_solicitation: Counter,
130}
131
132#[derive(Default)]
134pub struct NdpTxCounters {
135 pub neighbor_advertisement: Counter,
137 pub neighbor_solicitation: Counter,
139}
140
141#[derive(Default)]
143pub struct NdpCounters {
144 pub rx: NdpRxCounters,
146 pub tx: NdpTxCounters,
148}
149
150#[derive(Copy, Clone)]
152pub struct Icmpv4StateBuilder {
153 send_timestamp_reply: bool,
154 errors_per_second: u64,
155}
156
157impl Default for Icmpv4StateBuilder {
158 fn default() -> Icmpv4StateBuilder {
159 Icmpv4StateBuilder {
160 send_timestamp_reply: false,
161 errors_per_second: DEFAULT_ERRORS_PER_SECOND,
162 }
163 }
164}
165
166impl Icmpv4StateBuilder {
167 pub fn send_timestamp_reply(&mut self, send_timestamp_reply: bool) -> &mut Self {
174 self.send_timestamp_reply = send_timestamp_reply;
175 self
176 }
177
178 pub fn build<BT: IcmpBindingsTypes>(self) -> Icmpv4State<BT> {
180 Icmpv4State {
181 inner: IcmpState {
182 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
183 self.errors_per_second,
184 ))),
185 tx_counters: Default::default(),
186 rx_counters: Default::default(),
187 },
188 send_timestamp_reply: self.send_timestamp_reply,
189 }
190 }
191}
192
193pub struct Icmpv4State<BT: IcmpBindingsTypes> {
195 pub inner: IcmpState<Ipv4, BT>,
197 pub send_timestamp_reply: bool,
199}
200
201impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
202 fn as_ref(&self) -> &IcmpState<Ipv4, BT> {
203 &self.inner
204 }
205}
206
207impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv4, BT>> for Icmpv4State<BT> {
208 fn as_mut(&mut self) -> &mut IcmpState<Ipv4, BT> {
209 &mut self.inner
210 }
211}
212
213#[derive(Copy, Clone)]
215pub(crate) struct Icmpv6StateBuilder {
216 errors_per_second: u64,
217}
218
219impl Default for Icmpv6StateBuilder {
220 fn default() -> Icmpv6StateBuilder {
221 Icmpv6StateBuilder { errors_per_second: DEFAULT_ERRORS_PER_SECOND }
222 }
223}
224
225impl Icmpv6StateBuilder {
226 pub(crate) fn build<BT: IcmpBindingsTypes>(self) -> Icmpv6State<BT> {
227 Icmpv6State {
228 inner: IcmpState {
229 error_send_bucket: Mutex::new(IpMarked::new(TokenBucket::new(
230 self.errors_per_second,
231 ))),
232 tx_counters: Default::default(),
233 rx_counters: Default::default(),
234 },
235 ndp_counters: Default::default(),
236 }
237 }
238}
239
240pub struct Icmpv6State<BT: IcmpBindingsTypes> {
242 pub inner: IcmpState<Ipv6, BT>,
244 pub ndp_counters: NdpCounters,
246}
247
248impl<BT: IcmpBindingsTypes> AsRef<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
249 fn as_ref(&self) -> &IcmpState<Ipv6, BT> {
250 &self.inner
251 }
252}
253
254impl<BT: IcmpBindingsTypes> AsMut<IcmpState<Ipv6, BT>> for Icmpv6State<BT> {
255 fn as_mut(&mut self) -> &mut IcmpState<Ipv6, BT> {
256 &mut self.inner
257 }
258}
259
260pub trait IcmpHandlerIpExt: IpExt {
262 type IcmpError: IcmpError
264 + GenericOverIp<Self, Type = Self::IcmpError>
265 + GenericOverIp<Ipv4, Type = Icmpv4Error>
266 + GenericOverIp<Ipv6, Type = Icmpv6Error>;
267
268 fn received_source_as_icmp_source(src: Self::RecvSrcAddr) -> Option<SocketIpAddr<Self::Addr>>;
270
271 fn nud_failure_icmp_error() -> Self::IcmpError;
273}
274
275impl IcmpHandlerIpExt for Ipv4 {
276 type IcmpError = Icmpv4Error;
277
278 fn received_source_as_icmp_source(src: Ipv4SourceAddr) -> Option<SocketIpAddr<Ipv4Addr>> {
279 SocketIpAddr::new_from_ipv4_source(src)
280 }
281
282 fn nud_failure_icmp_error() -> Icmpv4Error {
283 Icmpv4Error::HostUnreachable
284 }
285}
286
287impl IcmpHandlerIpExt for Ipv6 {
288 type IcmpError = Icmpv6Error;
289
290 fn received_source_as_icmp_source(src: Ipv6SourceAddr) -> Option<SocketIpAddr<Ipv6Addr>> {
291 SocketIpAddr::new_from_ipv6_source(src)
292 }
293
294 fn nud_failure_icmp_error() -> Icmpv6Error {
295 Icmpv6Error::AddressUnreachable
296 }
297}
298
299pub trait IcmpError: Sized + Debug + PartialEq {
301 fn port_unreachable() -> Self;
303 fn ttl_expired() -> Self;
305 fn mtu_exceeded(mtu: Mtu) -> Option<Self>;
308}
309
310#[derive(Debug, PartialEq)]
312pub enum Icmpv4Error {
313 ParameterProblem {
315 code: Icmpv4ParameterProblemCode,
317 pointer: u8,
319 },
320 TtlExpired,
322 NetUnreachable,
324 ProtocolUnreachable,
326 PortUnreachable,
328 HostUnreachable,
330 NetworkProhibited,
332 HostProhibited,
334 AdminProhibited,
336}
337
338impl IcmpError for Icmpv4Error {
339 fn port_unreachable() -> Self {
340 Icmpv4Error::PortUnreachable
341 }
342 fn ttl_expired() -> Self {
343 Icmpv4Error::TtlExpired
344 }
345 fn mtu_exceeded(_mtu: Mtu) -> Option<Self> {
346 None
347 }
348}
349
350impl<I: IcmpHandlerIpExt> GenericOverIp<I> for Icmpv4Error {
351 type Type = I::IcmpError;
352}
353
354enum Icmpv4ErrorMessage {
357 TimeExceeded {
358 message: IcmpTimeExceeded,
359 code: <IcmpTimeExceeded as IcmpMessage<Ipv4>>::Code,
360 },
361 ParameterProblem {
362 message: Icmpv4ParameterProblem,
363 code: <Icmpv4ParameterProblem as IcmpMessage<Ipv4>>::Code,
364 },
365 DestUnreachable {
366 message: IcmpDestUnreachable,
367 code: <IcmpDestUnreachable as IcmpMessage<Ipv4>>::Code,
368 },
369}
370
371impl Icmpv4Error {
372 fn update_counters(&self, counters: &IcmpTxCounters<Ipv4>) {
373 match self {
374 Icmpv4Error::ParameterProblem { code, pointer: _ } => {
375 counters.parameter_problem.increment_code(*code);
376 }
377 Icmpv4Error::TtlExpired => {
378 counters.time_exceeded.increment_code(Icmpv4TimeExceededCode::TtlExpired);
379 }
380 Icmpv4Error::NetUnreachable => {
381 counters.net_unreachable.increment();
382 counters
383 .dest_unreachable
384 .increment_code(Icmpv4DestUnreachableCode::DestNetworkUnreachable);
385 }
386 Icmpv4Error::ProtocolUnreachable => {
387 counters.protocol_unreachable.increment();
388 counters
389 .dest_unreachable
390 .increment_code(Icmpv4DestUnreachableCode::DestProtocolUnreachable);
391 }
392 Icmpv4Error::PortUnreachable => {
393 counters.port_unreachable.increment();
394 counters
395 .dest_unreachable
396 .increment_code(Icmpv4DestUnreachableCode::DestPortUnreachable);
397 }
398 Icmpv4Error::HostUnreachable => {
399 counters.address_unreachable.increment();
400 counters
401 .dest_unreachable
402 .increment_code(Icmpv4DestUnreachableCode::DestHostUnreachable);
403 }
404 Icmpv4Error::NetworkProhibited => {
405 counters
406 .dest_unreachable
407 .increment_code(Icmpv4DestUnreachableCode::NetworkAdministrativelyProhibited);
408 }
409 Icmpv4Error::HostProhibited => {
410 counters
411 .dest_unreachable
412 .increment_code(Icmpv4DestUnreachableCode::HostAdministrativelyProhibited);
413 }
414 Icmpv4Error::AdminProhibited => {
415 counters
416 .dest_unreachable
417 .increment_code(Icmpv4DestUnreachableCode::CommAdministrativelyProhibited);
418 }
419 }
420 }
421
422 fn create_message(&self) -> Icmpv4ErrorMessage {
423 match self {
424 Icmpv4Error::ParameterProblem { code, pointer } => {
425 Icmpv4ErrorMessage::ParameterProblem {
426 message: Icmpv4ParameterProblem::new(*pointer),
427 code: *code,
428 }
429 }
430 Icmpv4Error::TtlExpired => Icmpv4ErrorMessage::TimeExceeded {
431 message: IcmpTimeExceeded::default(),
432 code: Icmpv4TimeExceededCode::TtlExpired,
433 },
434 Icmpv4Error::NetUnreachable => Icmpv4ErrorMessage::DestUnreachable {
435 message: IcmpDestUnreachable::default(),
436 code: Icmpv4DestUnreachableCode::DestNetworkUnreachable,
437 },
438 Icmpv4Error::ProtocolUnreachable => Icmpv4ErrorMessage::DestUnreachable {
439 message: IcmpDestUnreachable::default(),
440 code: Icmpv4DestUnreachableCode::DestProtocolUnreachable,
441 },
442 Icmpv4Error::PortUnreachable => Icmpv4ErrorMessage::DestUnreachable {
443 message: IcmpDestUnreachable::default(),
444 code: Icmpv4DestUnreachableCode::DestPortUnreachable,
445 },
446 Icmpv4Error::HostUnreachable => Icmpv4ErrorMessage::DestUnreachable {
447 message: IcmpDestUnreachable::default(),
448 code: Icmpv4DestUnreachableCode::DestHostUnreachable,
449 },
450 Icmpv4Error::NetworkProhibited => Icmpv4ErrorMessage::DestUnreachable {
451 message: IcmpDestUnreachable::default(),
452 code: Icmpv4DestUnreachableCode::NetworkAdministrativelyProhibited,
453 },
454 Icmpv4Error::HostProhibited => Icmpv4ErrorMessage::DestUnreachable {
455 message: IcmpDestUnreachable::default(),
456 code: Icmpv4DestUnreachableCode::HostAdministrativelyProhibited,
457 },
458 Icmpv4Error::AdminProhibited => Icmpv4ErrorMessage::DestUnreachable {
459 message: IcmpDestUnreachable::default(),
460 code: Icmpv4DestUnreachableCode::CommAdministrativelyProhibited,
461 },
462 }
463 }
464}
465
466impl<I: IcmpHandlerIpExt> GenericOverIp<I> for Icmpv6Error {
467 type Type = I::IcmpError;
468}
469
470#[derive(Debug, PartialEq, Eq)]
472pub enum Icmpv6Error {
473 ParameterProblem {
475 code: Icmpv6ParameterProblemCode,
477 pointer: u32,
479 allow_dst_multicast: bool,
481 },
482 TtlExpired,
484 NetUnreachable,
486 PacketTooBig {
488 mtu: Mtu,
490 },
491 PortUnreachable,
493 AddressUnreachable,
495 RejectRoute,
497 SourceAddressPolicyFailed,
499 AdminProhibited,
501}
502
503impl IcmpError for Icmpv6Error {
504 fn port_unreachable() -> Self {
505 Icmpv6Error::PortUnreachable
506 }
507 fn ttl_expired() -> Self {
508 Icmpv6Error::TtlExpired
509 }
510 fn mtu_exceeded(mtu: Mtu) -> Option<Self> {
511 Some(Icmpv6Error::PacketTooBig { mtu })
512 }
513}
514
515enum Icmpv6ErrorMessage {
518 TimeExceeded {
519 message: IcmpTimeExceeded,
520 code: <IcmpTimeExceeded as IcmpMessage<Ipv6>>::Code,
521 },
522 PacketTooBig {
523 message: Icmpv6PacketTooBig,
524 code: <Icmpv6PacketTooBig as IcmpMessage<Ipv6>>::Code,
525 },
526 ParameterProblem {
527 message: Icmpv6ParameterProblem,
528 code: <Icmpv6ParameterProblem as IcmpMessage<Ipv6>>::Code,
529 },
530 DestUnreachable {
531 message: IcmpDestUnreachable,
532 code: <IcmpDestUnreachable as IcmpMessage<Ipv6>>::Code,
533 },
534}
535
536impl Icmpv6Error {
537 fn update_counters(&self, counters: &IcmpTxCounters<Ipv6>) {
538 match self {
539 Icmpv6Error::ParameterProblem { code, pointer: _, allow_dst_multicast: _ } => {
540 counters.parameter_problem.increment_code(*code);
541 }
542 Icmpv6Error::TtlExpired => {
543 counters.time_exceeded.increment_code(Icmpv6TimeExceededCode::HopLimitExceeded);
544 }
545 Icmpv6Error::NetUnreachable => {
546 counters.net_unreachable.increment();
547 counters.dest_unreachable.increment_code(Icmpv6DestUnreachableCode::NoRoute);
548 }
549 Icmpv6Error::PacketTooBig { mtu: _ } => {
550 counters.packet_too_big.increment();
551 }
552 Icmpv6Error::PortUnreachable => {
553 counters.port_unreachable.increment();
554 counters
555 .dest_unreachable
556 .increment_code(Icmpv6DestUnreachableCode::PortUnreachable);
557 }
558 Icmpv6Error::AddressUnreachable => {
559 counters.address_unreachable.increment();
560 counters
561 .dest_unreachable
562 .increment_code(Icmpv6DestUnreachableCode::AddrUnreachable);
563 }
564 Icmpv6Error::RejectRoute => {
565 counters.dest_unreachable.increment_code(Icmpv6DestUnreachableCode::RejectRoute);
566 }
567 Icmpv6Error::SourceAddressPolicyFailed => {
568 counters
569 .dest_unreachable
570 .increment_code(Icmpv6DestUnreachableCode::SrcAddrFailedPolicy);
571 }
572 Icmpv6Error::AdminProhibited => {
573 counters
574 .dest_unreachable
575 .increment_code(Icmpv6DestUnreachableCode::CommAdministrativelyProhibited);
576 }
577 }
578 }
579
580 fn create_message(&self) -> Icmpv6ErrorMessage {
581 match self {
582 Icmpv6Error::ParameterProblem { code, pointer, allow_dst_multicast: _ } => {
583 Icmpv6ErrorMessage::ParameterProblem {
584 message: Icmpv6ParameterProblem::new(*pointer),
585 code: *code,
586 }
587 }
588 Icmpv6Error::TtlExpired => Icmpv6ErrorMessage::TimeExceeded {
589 message: IcmpTimeExceeded::default(),
590 code: Icmpv6TimeExceededCode::HopLimitExceeded,
591 },
592 Icmpv6Error::NetUnreachable => Icmpv6ErrorMessage::DestUnreachable {
593 message: IcmpDestUnreachable::default(),
594 code: Icmpv6DestUnreachableCode::NoRoute,
595 },
596 Icmpv6Error::PacketTooBig { mtu } => Icmpv6ErrorMessage::PacketTooBig {
597 message: Icmpv6PacketTooBig::new((*mtu).into()),
598 code: IcmpZeroCode,
599 },
600 Icmpv6Error::PortUnreachable => Icmpv6ErrorMessage::DestUnreachable {
601 message: IcmpDestUnreachable::default(),
602 code: Icmpv6DestUnreachableCode::PortUnreachable,
603 },
604 Icmpv6Error::AddressUnreachable => Icmpv6ErrorMessage::DestUnreachable {
605 message: IcmpDestUnreachable::default(),
606 code: Icmpv6DestUnreachableCode::AddrUnreachable,
607 },
608 Icmpv6Error::RejectRoute => Icmpv6ErrorMessage::DestUnreachable {
609 message: IcmpDestUnreachable::default(),
610 code: Icmpv6DestUnreachableCode::RejectRoute,
611 },
612 Icmpv6Error::SourceAddressPolicyFailed => Icmpv6ErrorMessage::DestUnreachable {
613 message: IcmpDestUnreachable::default(),
614 code: Icmpv6DestUnreachableCode::SrcAddrFailedPolicy,
615 },
616 Icmpv6Error::AdminProhibited => Icmpv6ErrorMessage::DestUnreachable {
617 message: IcmpDestUnreachable::default(),
618 code: Icmpv6DestUnreachableCode::CommAdministrativelyProhibited,
619 },
620 }
621 }
622
623 fn allow_dst_multicast(&self) -> bool {
624 match self {
637 Icmpv6Error::ParameterProblem { allow_dst_multicast, code, pointer: _ } => {
638 assert!(
639 !allow_dst_multicast
640 || *code == Icmpv6ParameterProblemCode::UnrecognizedIpv6Option
641 );
642 *allow_dst_multicast
643 }
644 Icmpv6Error::PacketTooBig { .. } => true,
645 _ => false,
646 }
647 }
648}
649
650pub trait IcmpErrorHandler<I: IcmpHandlerIpExt, BC>: DeviceIdContext<AnyDevice> {
652 fn send_icmp_error_message<B: BufferMut>(
659 &mut self,
660 bindings_ctx: &mut BC,
661 device: Option<&Self::DeviceId>,
662 frame_dst: Option<FrameDestination>,
663 src_ip: SocketIpAddr<I::Addr>,
664 dst_ip: SocketIpAddr<I::Addr>,
665 original_packet: B,
666 error: I::IcmpError,
667 header_len: usize,
668 proto: I::Proto,
669 marks: &Marks,
670 );
671}
672
673impl<BC: IcmpBindingsContext, CC: IcmpSendContext<Ipv4, BC> + CounterContext<IcmpTxCounters<Ipv4>>>
674 IcmpErrorHandler<Ipv4, BC> for CC
675{
676 fn send_icmp_error_message<B: BufferMut>(
677 &mut self,
678 bindings_ctx: &mut BC,
679 device: Option<&CC::DeviceId>,
680 frame_dst: Option<FrameDestination>,
681 src_ip: SocketIpAddr<Ipv4Addr>,
682 dst_ip: SocketIpAddr<Ipv4Addr>,
683 original_packet: B,
684 icmp_error: Icmpv4Error,
685 header_len: usize,
686 proto: Ipv4Proto,
687 marks: &Marks,
688 ) {
689 if is_icmp_error_or_redirect_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..])
692 {
693 return;
694 }
695
696 icmp_error.update_counters(&self.counters());
697 send_icmpv4_error_message(
698 self,
699 bindings_ctx,
700 device,
701 frame_dst,
702 src_ip,
703 dst_ip,
704 icmp_error.create_message(),
705 original_packet,
706 header_len,
707 marks,
708 );
709 }
710}
711
712impl<BC: IcmpBindingsContext, CC: IcmpSendContext<Ipv6, BC> + CounterContext<IcmpTxCounters<Ipv6>>>
713 IcmpErrorHandler<Ipv6, BC> for CC
714{
715 fn send_icmp_error_message<B: BufferMut>(
716 &mut self,
717 bindings_ctx: &mut BC,
718 device: Option<&CC::DeviceId>,
719 frame_dst: Option<FrameDestination>,
720 src_ip: SocketIpAddr<Ipv6Addr>,
721 dst_ip: SocketIpAddr<Ipv6Addr>,
722 original_packet: B,
723 error: Icmpv6Error,
724 header_len: usize,
725 proto: Ipv6Proto,
726 marks: &Marks,
727 ) {
728 if is_icmp_error_or_redirect_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..])
731 {
732 return;
733 }
734
735 error.update_counters(&self.counters());
736 send_icmpv6_error_message(
737 self,
738 bindings_ctx,
739 device,
740 frame_dst,
741 src_ip,
742 dst_ip,
743 error.create_message(),
744 original_packet,
745 error.allow_dst_multicast(),
746 marks,
747 )
748 }
749}
750
751pub trait IcmpBindingsContext: InstantContext + RngContext + IcmpBindingsTypes {}
754impl<BC> IcmpBindingsContext for BC where
755 BC: InstantContext + RngContext + IcmpBindingsTypes + IcmpBindingsTypes
756{
757}
758
759pub trait IcmpBindingsTypes: InstantBindingsTypes + TxMetadataBindingsTypes {}
761impl<BT: InstantBindingsTypes + TxMetadataBindingsTypes> IcmpBindingsTypes for BT {}
762
763pub trait IcmpStateContext {}
771
772pub trait EchoTransportContextMarker {}
782
783pub trait InnerIcmpContext<I, BC>: IpSocketHandler<I, BC>
786where
787 I: IpLayerIpExt,
788 BC: IcmpBindingsTypes,
789{
790 type EchoTransportContext: IpTransportContext<I, BC, Self> + EchoTransportContextMarker;
793
794 fn receive_icmp_error(
824 &mut self,
825 bindings_ctx: &mut BC,
826 device: &Self::DeviceId,
827 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
828 original_dst_ip: SpecifiedAddr<I::Addr>,
829 original_proto: I::Proto,
830 original_body: &[u8],
831 err: I::ErrorCode,
832 );
833}
834
835pub trait InnerIcmpv4Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv4, BC> {
839 fn should_send_timestamp_reply(&self) -> bool;
841}
842
843pub trait IcmpSendContext<I, BC>: IpSocketHandler<I, BC>
845where
846 I: IpLayerIpExt,
847 BC: IcmpBindingsTypes,
848{
849 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
852 &mut self,
853 cb: F,
854 ) -> O;
855}
856
857macro_rules! try_send_error {
871 ($core_ctx:expr, $bindings_ctx:expr, $e:expr) => {{
872 let send = $core_ctx.with_error_send_bucket_mut(|error_send_bucket| {
873 error_send_bucket.try_take($bindings_ctx)
874 });
875
876 if send {
877 $core_ctx.counters().error.increment();
878 $e
879 } else {
880 trace!("ip::icmp::try_send_error!: dropping rate-limited ICMP error message");
881 Ok(())
882 }
883 }};
884}
885
886pub enum IcmpIpTransportContext {}
888
889fn receive_ip_transport_icmp_error<
890 I: IpLayerIpExt,
891 CC: InnerIcmpContext<I, BC> + CounterContext<IcmpRxCounters<I>>,
892 BC: IcmpBindingsContext,
893>(
894 core_ctx: &mut CC,
895 bindings_ctx: &mut BC,
896 device: &CC::DeviceId,
897 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
898 original_dst_ip: SpecifiedAddr<I::Addr>,
899 original_body: &[u8],
900 err: I::ErrorCode,
901) {
902 core_ctx.counters().error_delivered_to_transport_layer.increment();
903 trace!("IcmpIpTransportContext::receive_icmp_error({:?})", err);
904
905 let mut parse_body = original_body;
906 match parse_body.parse::<IcmpPacketRaw<I, _, IcmpEchoRequest>>() {
907 Ok(_echo_request) => (),
910 Err(_) => {
911 return;
915 }
916 }
917
918 <CC::EchoTransportContext as IpTransportContext<I, BC, CC>>::receive_icmp_error(
919 core_ctx,
920 bindings_ctx,
921 device,
922 original_src_ip,
923 original_dst_ip,
924 original_body,
925 err,
926 );
927}
928
929impl<
930 BC: IcmpBindingsContext,
931 CC: InnerIcmpv4Context<BC>
932 + PmtuHandler<Ipv4, BC>
933 + CounterContext<IcmpRxCounters<Ipv4>>
934 + CounterContext<IcmpTxCounters<Ipv4>>,
935> IpTransportContext<Ipv4, BC, CC> for IcmpIpTransportContext
936{
937 type EarlyDemuxSocket = Never;
938
939 fn early_demux<B: ParseBuffer>(
940 _core_ctx: &mut CC,
941 _device: &CC::DeviceId,
942 _src_ip: Ipv4Addr,
943 _dst_ip: Ipv4Addr,
944 _buffer: B,
945 ) -> Option<Self::EarlyDemuxSocket> {
946 None
947 }
948
949 fn receive_icmp_error(
950 core_ctx: &mut CC,
951 bindings_ctx: &mut BC,
952 device: &CC::DeviceId,
953 original_src_ip: Option<SpecifiedAddr<Ipv4Addr>>,
954 original_dst_ip: SpecifiedAddr<Ipv4Addr>,
955 original_body: &[u8],
956 err: Icmpv4ErrorCode,
957 ) {
958 receive_ip_transport_icmp_error(
959 core_ctx,
960 bindings_ctx,
961 device,
962 original_src_ip,
963 original_dst_ip,
964 original_body,
965 err,
966 )
967 }
968
969 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv4>>(
970 core_ctx: &mut CC,
971 bindings_ctx: &mut BC,
972 device: &CC::DeviceId,
973 src_ip: Ipv4SourceAddr,
974 dst_ip: SpecifiedAddr<Ipv4Addr>,
975 mut buffer: B,
976 info: &LocalDeliveryPacketInfo<Ipv4, H>,
977 _early_demux_socket: Option<Never>,
978 ) -> Result<(), (B, Icmpv4Error)> {
979 let LocalDeliveryPacketInfo { meta, header_info: _, marks } = info;
980 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
981 if let Some(delivery) = transparent_override {
982 unreachable!(
983 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
984 transparent proxy rules can only be configured for TCP and UDP packets"
985 );
986 }
987
988 trace!(
989 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet({}, {})",
990 src_ip, dst_ip
991 );
992 let packet =
993 match buffer.parse_with::<_, Icmpv4Packet<_>>(IcmpParseArgs::new(src_ip, dst_ip)) {
994 Ok(packet) => packet,
995 Err(_) => return Ok(()), };
997
998 match packet {
999 Icmpv4Packet::EchoRequest(echo_request) => {
1000 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_request.increment();
1001
1002 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
1003 let req = *echo_request.message();
1004 let code = echo_request.code();
1005 let (local_ip, remote_ip) = (dst_ip, src_ip);
1006 debug!(
1007 "replying to ICMP echo request from {remote_ip} to {local_ip}%{device:?}: \
1008 id={}, seq={}",
1009 req.id(),
1010 req.seq()
1011 );
1012 send_icmp_reply(
1013 core_ctx,
1014 bindings_ctx,
1015 device,
1016 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1017 SocketIpAddr::new_ipv4_specified(local_ip),
1018 |src_ip| {
1019 IcmpPacketBuilder::<Ipv4, _>::new(src_ip, *remote_ip, code, req.reply())
1020 .wrap_body(buffer)
1021 },
1022 &WithMarks(marks),
1023 );
1024 } else {
1025 trace!(
1026 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1027 Received echo request with an unspecified source address"
1028 );
1029 }
1030 }
1031 Icmpv4Packet::EchoReply(echo_reply) => {
1032 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_reply.increment();
1033 trace!(
1034 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1035 Received an EchoReply message"
1036 );
1037 let parse_metadata = echo_reply.parse_metadata();
1038 buffer.undo_parse(parse_metadata);
1039 return <CC::EchoTransportContext
1040 as IpTransportContext<Ipv4, BC, CC>>::receive_ip_packet(
1041 core_ctx,
1042 bindings_ctx,
1043 device,
1044 src_ip,
1045 dst_ip,
1046 buffer,
1047 info,
1048 None,
1049 );
1050 }
1051 Icmpv4Packet::TimestampRequest(timestamp_request) => {
1052 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1053 .timestamp_request
1054 .increment();
1055 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
1056 if core_ctx.should_send_timestamp_reply() {
1057 trace!(
1058 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1059 receive_ip_packet: Responding to Timestamp Request message"
1060 );
1061 const NOW: u32 = 0x80000000;
1080 let reply = timestamp_request.message().reply(NOW, NOW);
1081 let (local_ip, remote_ip) = (dst_ip, src_ip);
1082 buffer.shrink_front_to(0);
1089 send_icmp_reply(
1090 core_ctx,
1091 bindings_ctx,
1092 device,
1093 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1094 SocketIpAddr::new_ipv4_specified(local_ip),
1095 |src_ip| {
1096 IcmpPacketBuilder::<Ipv4, _>::new(
1097 src_ip,
1098 *remote_ip,
1099 IcmpZeroCode,
1100 reply,
1101 )
1102 .wrap_body(buffer)
1103 },
1104 &WithMarks(marks),
1105 );
1106 } else {
1107 trace!(
1108 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1109 receive_ip_packet: Silently ignoring Timestamp Request message"
1110 );
1111 }
1112 } else {
1113 trace!(
1114 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1115 receive_ip_packet: Received timestamp request with an unspecified source \
1116 address"
1117 );
1118 }
1119 }
1120 Icmpv4Packet::TimestampReply(_) => {
1121 debug!(
1124 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1125 Received unsolicited Timestamp Reply message"
1126 );
1127 }
1128 Icmpv4Packet::DestUnreachable(dest_unreachable) => {
1129 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1130 .dest_unreachable
1131 .increment_code(dest_unreachable.code());
1132 trace!(
1133 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1134 Received a Destination Unreachable message"
1135 );
1136
1137 let error = if dest_unreachable.code()
1138 == Icmpv4DestUnreachableCode::FragmentationRequired
1139 {
1140 let mtu = if let Some(next_hop_mtu) = dest_unreachable.message().next_hop_mtu()
1141 {
1142 core_ctx.update_pmtu_if_less(
1152 bindings_ctx,
1153 dst_ip.get(),
1154 src_ip.get(),
1155 Mtu::new(u32::from(next_hop_mtu.get())),
1156 )
1157 } else {
1158 let (original_packet_buf, inner_body) = dest_unreachable.body().bytes();
1180 debug_assert!(inner_body.is_none());
1182 if original_packet_buf.len() >= 4 {
1183 let total_len =
1187 u16::from_be_bytes(original_packet_buf[2..4].try_into().unwrap());
1188
1189 trace!(
1190 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1191 receive_ip_packet: Next-Hop MTU is 0 so using the next best PMTU \
1192 value from {total_len}"
1193 );
1194
1195 core_ctx.update_pmtu_next_lower(
1196 bindings_ctx,
1197 dst_ip.get(),
1198 src_ip.get(),
1199 Mtu::new(u32::from(total_len)),
1200 )
1201 } else {
1202 trace!(
1207 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1208 receive_ip_packet: Original packet buf is too small to get \
1209 original packet len so ignoring"
1210 );
1211 None
1212 }
1213 };
1214 mtu.and_then(|mtu| {
1215 let mtu = u16::try_from(mtu.get()).unwrap_or(u16::MAX);
1216 let mtu = NonZeroU16::new(mtu)?;
1217 Some(Icmpv4ErrorCode::DestUnreachable(
1218 dest_unreachable.code(),
1219 IcmpDestUnreachable::new_for_frag_req(mtu),
1220 ))
1221 })
1222 } else {
1223 Some(Icmpv4ErrorCode::DestUnreachable(
1224 dest_unreachable.code(),
1225 *dest_unreachable.message(),
1226 ))
1227 };
1228
1229 if let Some(error) = error {
1230 receive_icmpv4_error(core_ctx, bindings_ctx, device, &dest_unreachable, error);
1231 }
1232 }
1233 Icmpv4Packet::TimeExceeded(time_exceeded) => {
1234 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1235 .time_exceeded
1236 .increment_code(time_exceeded.code());
1237 trace!(
1238 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1239 Received a Time Exceeded message"
1240 );
1241
1242 receive_icmpv4_error(
1243 core_ctx,
1244 bindings_ctx,
1245 device,
1246 &time_exceeded,
1247 Icmpv4ErrorCode::TimeExceeded(time_exceeded.code()),
1248 );
1249 }
1250 Icmpv4Packet::Redirect(_) => {
1252 debug!(
1253 "Unimplemented: <IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1254 receive_ip_packet::redirect"
1255 )
1256 }
1257 Icmpv4Packet::ParameterProblem(parameter_problem) => {
1258 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1259 .parameter_problem
1260 .increment_code(parameter_problem.code());
1261 trace!(
1262 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1263 Received a Parameter Problem message"
1264 );
1265
1266 receive_icmpv4_error(
1267 core_ctx,
1268 bindings_ctx,
1269 device,
1270 ¶meter_problem,
1271 Icmpv4ErrorCode::ParameterProblem(parameter_problem.code()),
1272 );
1273 }
1274 }
1275
1276 Ok(())
1277 }
1278}
1279
1280#[allow(missing_docs)]
1283pub enum NdpMessage {
1284 NeighborSolicitation {
1285 message: NeighborSolicitation,
1286 code: <NeighborSolicitation as IcmpMessage<Ipv6>>::Code,
1287 },
1288
1289 RouterSolicitation {
1290 message: RouterSolicitation,
1291 code: <RouterSolicitation as IcmpMessage<Ipv6>>::Code,
1292 },
1293
1294 NeighborAdvertisement {
1295 message: NeighborAdvertisement,
1296 code: <NeighborAdvertisement as IcmpMessage<Ipv6>>::Code,
1297 },
1298}
1299
1300pub fn send_ndp_packet<BC, CC, S>(
1302 core_ctx: &mut CC,
1303 bindings_ctx: &mut BC,
1304 device_id: &CC::DeviceId,
1305 src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1306 dst_ip: SpecifiedAddr<Ipv6Addr>,
1307 body: S,
1308 message: NdpMessage,
1309) -> Result<(), IpSendFrameError<S>>
1310where
1311 CC: IpLayerHandler<Ipv6, BC>,
1312 S: Serializer + PartialSerializer,
1313 S::Buffer: BufferMut,
1314{
1315 macro_rules! send {
1316 ($message:expr, $code:expr) => {{
1317 let mut ser = IcmpPacketBuilder::<Ipv6, _>::new(
1319 src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
1320 dst_ip.get(),
1321 $code,
1322 $message,
1323 )
1324 .wrap_body(body);
1325 match IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
1326 core_ctx,
1327 bindings_ctx,
1328 SendIpPacketMeta {
1329 device: device_id,
1330 src_ip,
1331 dst_ip,
1332 destination: IpPacketDestination::from_addr(dst_ip),
1333 ttl: NonZeroU8::new(REQUIRED_NDP_IP_PACKET_HOP_LIMIT),
1334 proto: Ipv6Proto::Icmpv6,
1335 mtu: Mtu::no_limit(),
1336 dscp_and_ecn: DscpAndEcn::default(),
1337 },
1338 DynTransportSerializer::new(&mut ser),
1339 ) {
1340 Ok(()) => Ok(()),
1341 Err(e) => Err(e
1342 .map_serializer(|s| {
1343 let _: DynTransportSerializer<'_, _> = s;
1345 })
1346 .map_serializer(|()| ser.into_inner())),
1347 }
1348 }};
1349 }
1350
1351 match message {
1352 NdpMessage::NeighborSolicitation { message, code } => send!(message, code),
1353 NdpMessage::RouterSolicitation { message, code } => send!(message, code),
1354 NdpMessage::NeighborAdvertisement { message, code } => send!(message, code),
1355 }
1356}
1357
1358fn send_neighbor_advertisement<
1359 BC,
1360 CC: Ipv6DeviceHandler<BC>
1361 + IpDeviceHandler<Ipv6, BC>
1362 + IpLayerHandler<Ipv6, BC>
1363 + CounterContext<NdpCounters>,
1364>(
1365 core_ctx: &mut CC,
1366 bindings_ctx: &mut BC,
1367 device_id: &CC::DeviceId,
1368 solicited: bool,
1369 device_addr: UnicastAddr<Ipv6Addr>,
1370 dst_ip: SpecifiedAddr<Ipv6Addr>,
1371) {
1372 core_ctx.counters().tx.neighbor_advertisement.increment();
1373 debug!("send_neighbor_advertisement from {:?} to {:?}", device_addr, dst_ip);
1374 debug_assert!(dst_ip.is_valid_unicast() || (!solicited && dst_ip.is_multicast()));
1381
1382 let src_ll = core_ctx.get_link_layer_addr(&device_id);
1389
1390 let advertisement = NeighborAdvertisement::new(
1392 core_ctx.is_router_device(&device_id),
1393 solicited,
1394 true, device_addr.get(),
1407 );
1408 let _: Result<(), _> = send_ndp_packet(
1409 core_ctx,
1410 bindings_ctx,
1411 &device_id,
1412 Some(device_addr.into_specified()),
1413 dst_ip,
1414 OptionSequenceBuilder::new(
1415 src_ll
1416 .as_ref()
1417 .map(Ipv6LinkLayerAddr::as_bytes)
1418 .map(NdpOptionBuilder::TargetLinkLayerAddress)
1419 .iter(),
1420 )
1421 .into_serializer(),
1422 NdpMessage::NeighborAdvertisement { message: advertisement, code: IcmpZeroCode },
1423 );
1424}
1425
1426fn receive_ndp_packet<
1427 B: SplitByteSlice,
1428 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1429 CC: InnerIcmpContext<Ipv6, BC>
1430 + Ipv6DeviceHandler<BC>
1431 + IpDeviceHandler<Ipv6, BC>
1432 + IpDeviceIngressStateContext<Ipv6>
1433 + NudIpHandler<Ipv6, BC>
1434 + IpLayerHandler<Ipv6, BC>
1435 + CounterContext<NdpCounters>,
1436 H: IpHeaderInfo<Ipv6>,
1437>(
1438 core_ctx: &mut CC,
1439 bindings_ctx: &mut BC,
1440 device_id: &CC::DeviceId,
1441 src_ip: Ipv6SourceAddr,
1442 dst_ip: SpecifiedAddr<Ipv6Addr>,
1443 packet: NdpPacket<B>,
1444 header_info: &H,
1445) {
1446 if header_info.hop_limit() != REQUIRED_NDP_IP_PACKET_HOP_LIMIT {
1464 trace!("dropping NDP packet from {src_ip} with invalid hop limit");
1465 return;
1466 }
1467
1468 match packet {
1469 NdpPacket::RouterSolicitation(_) => {}
1470 NdpPacket::Redirect(_) => {}
1472 NdpPacket::NeighborSolicitation(ref p) => {
1473 let target_address = p.message().target_address();
1480 let target_address = match UnicastAddr::new(*target_address) {
1481 Some(a) => a,
1482 None => {
1483 trace!(
1484 "dropping NS from {} with non-unicast target={:?}",
1485 src_ip, target_address
1486 );
1487 return;
1488 }
1489 };
1490
1491 let (source_link_addr, nonce) = p.body().iter().fold(
1493 (None, None),
1494 |(found_source_link_addr, found_nonce), option| {
1495 match option {
1496 NdpOption::Nonce(nonce) => (found_source_link_addr, Some(nonce)),
1497 NdpOption::SourceLinkLayerAddress(source_link_addr) => {
1498 (Some(source_link_addr), found_nonce)
1499 }
1500 NdpOption::Mtu(_)
1508 | NdpOption::PrefixInformation(_)
1509 | NdpOption::RecursiveDnsServer(_)
1510 | NdpOption::RedirectedHeader { .. }
1511 | NdpOption::RouteInformation(_)
1512 | NdpOption::TargetLinkLayerAddress(_) => {
1513 (found_source_link_addr, found_nonce)
1514 }
1515 }
1516 },
1517 );
1518
1519 if src_ip == Ipv6SourceAddr::Unspecified {
1520 if target_address.get().to_solicited_node_address().get() != dst_ip.get() {
1529 debug!(
1530 "dropping NS from {} for {} with invalid IPv6 dst ({}).",
1531 src_ip, target_address, dst_ip
1532 );
1533 return;
1534 }
1535 if let Some(addr) = source_link_addr {
1540 debug!(
1541 "dropping NS from {} for {} with source link-layer addr option ({:?}).",
1542 src_ip, target_address, addr
1543 );
1544 return;
1545 }
1546 }
1547
1548 core_ctx.counters().rx.neighbor_solicitation.increment();
1549
1550 match src_ip {
1551 Ipv6SourceAddr::Unspecified => {
1552 match IpDeviceHandler::handle_received_dad_packet(
1562 core_ctx,
1563 bindings_ctx,
1564 &device_id,
1565 target_address.into_specified(),
1566 nonce,
1567 ) {
1568 Some(IpAddressState::Assigned) => {
1569 send_neighbor_advertisement(
1573 core_ctx,
1574 bindings_ctx,
1575 &device_id,
1576 false,
1577 target_address,
1578 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified(),
1579 );
1580 }
1581 Some(IpAddressState::Tentative) => {
1582 }
1585 Some(IpAddressState::Unavailable) | None => {
1586 }
1589 }
1590
1591 return;
1592 }
1593 Ipv6SourceAddr::Unicast(src_ip) => {
1594 match core_ctx
1596 .address_status_for_device(target_address.into_specified(), device_id)
1597 {
1598 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned) => {}
1599 AddressStatus::Present(
1600 Ipv6PresentAddressStatus::UnicastTentative
1601 | Ipv6PresentAddressStatus::Multicast,
1602 )
1603 | AddressStatus::Unassigned => {
1604 return;
1608 }
1609 }
1610
1611 if let Some(link_addr) = source_link_addr {
1612 NudIpHandler::handle_neighbor_probe(
1613 core_ctx,
1614 bindings_ctx,
1615 &device_id,
1616 src_ip.into_specified(),
1617 link_addr,
1618 );
1619 }
1620
1621 send_neighbor_advertisement(
1622 core_ctx,
1623 bindings_ctx,
1624 &device_id,
1625 true,
1626 target_address,
1627 src_ip.into_specified(),
1628 );
1629 }
1630 }
1631 }
1632 NdpPacket::NeighborAdvertisement(ref p) => {
1633 let target_address = p.message().target_address();
1637
1638 let target_address = match UnicastAddr::new(*target_address) {
1645 Some(a) => a,
1646 None => {
1647 debug!(
1648 "dropping NA from {} with non-unicast target={:?}",
1649 src_ip, target_address
1650 );
1651 return;
1652 }
1653 };
1654 if let Some(dst_ip) = MulticastAddr::new(dst_ip.get())
1658 && p.message().solicited_flag()
1659 {
1660 debug!(
1661 "dropping NA from {} with solicited flag and multicast dst {}",
1662 src_ip, dst_ip
1663 );
1664 return;
1665 }
1666
1667 core_ctx.counters().rx.neighbor_advertisement.increment();
1668
1669 let nonce = None;
1673 match IpDeviceHandler::handle_received_dad_packet(
1674 core_ctx,
1675 bindings_ctx,
1676 &device_id,
1677 target_address.into_specified(),
1678 nonce,
1679 ) {
1680 Some(IpAddressState::Assigned) => {
1681 error!(
1699 "NA from {src_ip} with target address {target_address} that is also \
1700 assigned on device {device_id:?}",
1701 );
1702 }
1703 Some(IpAddressState::Tentative) => {
1704 return;
1707 }
1708 Some(IpAddressState::Unavailable) | None => {
1709 }
1713 }
1714
1715 let link_addr = p.body().iter().find_map(|o| o.target_link_layer_address());
1716
1717 NudIpHandler::handle_neighbor_confirmation(
1718 core_ctx,
1719 bindings_ctx,
1720 &device_id,
1721 target_address.into_specified(),
1722 link_addr,
1723 ConfirmationFlags {
1724 solicited_flag: p.message().solicited_flag(),
1725 override_flag: p.message().override_flag(),
1726 },
1727 );
1728 }
1729 NdpPacket::RouterAdvertisement(ref p) => {
1730 let src_ip = match src_ip {
1743 Ipv6SourceAddr::Unicast(ip) => match LinkLocalUnicastAddr::new(*ip) {
1744 Some(ip) => ip,
1745 None => return,
1746 },
1747 Ipv6SourceAddr::Unspecified => return,
1748 };
1749
1750 let ra = p.message();
1751 debug!("received router advertisement from {:?}: {:?}", src_ip, ra);
1752 core_ctx.counters().rx.router_advertisement.increment();
1753
1754 if let Some(retransmit_timer) = ra.retransmit_timer() {
1761 Ipv6DeviceHandler::set_discovered_retrans_timer(
1762 core_ctx,
1763 bindings_ctx,
1764 &device_id,
1765 retransmit_timer,
1766 );
1767 }
1768
1769 if let Some(hop_limit) = ra.current_hop_limit() {
1776 trace!(
1777 "receive_ndp_packet: NDP RA: updating device's hop limit to {:?} for router: {:?}",
1778 ra.current_hop_limit(),
1779 src_ip
1780 );
1781 IpDeviceHandler::set_default_hop_limit(core_ctx, &device_id, hop_limit);
1782 }
1783
1784 Ipv6DeviceHandler::update_discovered_ipv6_route(
1785 core_ctx,
1786 bindings_ctx,
1787 &device_id,
1788 Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) },
1789 Ipv6DiscoveredRouteProperties { route_preference: p.message().preference().into() },
1790 p.message().router_lifetime().map(NonZeroNdpLifetime::Finite),
1791 );
1792
1793 for option in p.body().iter() {
1794 match option {
1795 NdpOption::TargetLinkLayerAddress(_)
1796 | NdpOption::RedirectedHeader { .. }
1797 | NdpOption::RecursiveDnsServer(_)
1798 | NdpOption::Nonce(_) => {}
1799 NdpOption::SourceLinkLayerAddress(addr) => {
1800 debug!("processing SourceLinkLayerAddress option in RA: {:?}", addr);
1801 NudIpHandler::handle_neighbor_probe(
1827 core_ctx,
1828 bindings_ctx,
1829 &device_id,
1830 {
1831 let src_ip: UnicastAddr<_> = src_ip.into_addr();
1832 src_ip.into_specified()
1833 },
1834 addr,
1835 );
1836 }
1837 NdpOption::PrefixInformation(prefix_info) => {
1838 debug!("processing Prefix Information option in RA: {:?}", prefix_info);
1839 if prefix_info.prefix().is_link_local() {
1857 continue;
1858 }
1859
1860 let subnet = match prefix_info.subnet() {
1861 Ok(subnet) => subnet,
1862 Err(err) => match err {
1863 SubnetError::PrefixTooLong | SubnetError::HostBitsSet => continue,
1864 },
1865 };
1866
1867 match UnicastAddr::new(subnet.network()) {
1868 Some(UnicastAddr { .. }) => {}
1869 None => continue,
1870 }
1871
1872 let valid_lifetime = prefix_info.valid_lifetime();
1873
1874 if prefix_info.on_link_flag() {
1875 Ipv6DeviceHandler::update_discovered_ipv6_route(
1876 core_ctx,
1877 bindings_ctx,
1878 &device_id,
1879 Ipv6DiscoveredRoute { subnet, gateway: None },
1880 Ipv6DiscoveredRouteProperties {
1881 route_preference: RoutePreference::Medium,
1882 },
1883 valid_lifetime,
1884 )
1885 }
1886
1887 if prefix_info.autonomous_address_configuration_flag() {
1888 Ipv6DeviceHandler::apply_slaac_update(
1889 core_ctx,
1890 bindings_ctx,
1891 &device_id,
1892 subnet,
1893 prefix_info.preferred_lifetime(),
1894 valid_lifetime,
1895 );
1896 }
1897 }
1898 NdpOption::RouteInformation(rio) => {
1899 debug!("processing Route Information option in RA: {:?}", rio);
1900 Ipv6DeviceHandler::update_discovered_ipv6_route(
1901 core_ctx,
1902 bindings_ctx,
1903 &device_id,
1904 Ipv6DiscoveredRoute {
1905 subnet: rio.prefix().clone(),
1906 gateway: Some(src_ip),
1907 },
1908 Ipv6DiscoveredRouteProperties {
1909 route_preference: rio.preference().into(),
1910 },
1911 rio.route_lifetime(),
1912 )
1913 }
1914 NdpOption::Mtu(mtu) => {
1915 debug!("processing MTU option in RA: {:?}", mtu);
1916 Ipv6DeviceHandler::set_link_mtu(core_ctx, &device_id, Mtu::new(mtu));
1920 }
1921 }
1922 }
1923
1924 bindings_ctx.on_event(RouterAdvertisementEvent {
1925 options_bytes: Box::from(p.body().bytes()),
1926 source: **src_ip,
1927 device: device_id.clone(),
1928 });
1929 }
1930 }
1931}
1932
1933impl<
1934 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1935 CC: InnerIcmpContext<Ipv6, BC>
1936 + InnerIcmpContext<Ipv6, BC>
1937 + Ipv6DeviceHandler<BC>
1938 + IpDeviceHandler<Ipv6, BC>
1939 + IpDeviceIngressStateContext<Ipv6>
1940 + PmtuHandler<Ipv6, BC>
1941 + NudIpHandler<Ipv6, BC>
1942 + IpLayerHandler<Ipv6, BC>
1943 + CounterContext<IcmpRxCounters<Ipv6>>
1944 + CounterContext<IcmpTxCounters<Ipv6>>
1945 + CounterContext<NdpCounters>,
1946> IpTransportContext<Ipv6, BC, CC> for IcmpIpTransportContext
1947{
1948 type EarlyDemuxSocket = Never;
1949
1950 fn early_demux<B: ParseBuffer>(
1951 _core_ctx: &mut CC,
1952 _device: &CC::DeviceId,
1953 _src_ip: Ipv6Addr,
1954 _dst_ip: Ipv6Addr,
1955 _buffer: B,
1956 ) -> Option<Self::EarlyDemuxSocket> {
1957 None
1958 }
1959
1960 fn receive_icmp_error(
1961 core_ctx: &mut CC,
1962 bindings_ctx: &mut BC,
1963 device: &CC::DeviceId,
1964 original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1965 original_dst_ip: SpecifiedAddr<Ipv6Addr>,
1966 original_body: &[u8],
1967 err: Icmpv6ErrorCode,
1968 ) {
1969 receive_ip_transport_icmp_error(
1970 core_ctx,
1971 bindings_ctx,
1972 device,
1973 original_src_ip,
1974 original_dst_ip,
1975 original_body,
1976 err,
1977 )
1978 }
1979
1980 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
1981 core_ctx: &mut CC,
1982 bindings_ctx: &mut BC,
1983 device: &CC::DeviceId,
1984 src_ip: Ipv6SourceAddr,
1985 dst_ip: SpecifiedAddr<Ipv6Addr>,
1986 mut buffer: B,
1987 info: &LocalDeliveryPacketInfo<Ipv6, H>,
1988 _early_demux_socket: Option<Never>,
1989 ) -> Result<(), (B, Icmpv6Error)> {
1990 let LocalDeliveryPacketInfo { meta, header_info, marks } = info;
1991 let ReceiveIpPacketMeta { broadcast: _, transparent_override } = meta;
1992 if let Some(delivery) = transparent_override {
1993 unreachable!(
1994 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
1995 transparent proxy rules can only be configured for TCP and UDP packets"
1996 );
1997 }
1998
1999 trace!(
2000 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet({:?}, {})",
2001 src_ip, dst_ip
2002 );
2003
2004 let packet = match buffer
2005 .parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(src_ip.get(), dst_ip))
2006 {
2007 Ok(packet) => packet,
2008 Err(_) => return Ok(()), };
2010
2011 match packet {
2012 Icmpv6Packet::EchoRequest(echo_request) => {
2013 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_request.increment();
2014
2015 if let Some(src_ip) = SocketIpAddr::new_from_ipv6_source(src_ip) {
2016 match SocketIpAddr::try_from(dst_ip) {
2017 Ok(dst_ip) => {
2018 let req = *echo_request.message();
2019 let code = echo_request.code();
2020 let (local_ip, remote_ip) = (dst_ip, src_ip);
2021 debug!(
2022 "replying to ICMP echo request from {remote_ip}: id={}, seq={}",
2023 req.id(),
2024 req.seq()
2025 );
2026 send_icmp_reply(
2027 core_ctx,
2028 bindings_ctx,
2029 device,
2030 remote_ip,
2031 local_ip,
2032 |src_ip| {
2033 IcmpPacketBuilder::<Ipv6, _>::new(
2034 src_ip,
2035 remote_ip.addr(),
2036 code,
2037 req.reply(),
2038 )
2039 .wrap_body(buffer)
2040 },
2041 &WithMarks(marks),
2042 );
2043 }
2044 Err(AddrIsMappedError {}) => {
2045 trace!(
2046 "IpTransportContext<Ipv6>::receive_ip_packet: Received echo request with an ipv4-mapped-ipv6 destination address"
2047 );
2048 }
2049 }
2050 } else {
2051 trace!(
2052 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received echo request with an unspecified source address"
2053 );
2054 }
2055 }
2056 Icmpv6Packet::EchoReply(echo_reply) => {
2057 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_reply.increment();
2058 trace!(
2059 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received an EchoReply message"
2060 );
2061 let parse_metadata = echo_reply.parse_metadata();
2062 buffer.undo_parse(parse_metadata);
2063 return <CC::EchoTransportContext
2064 as IpTransportContext<Ipv6, BC, CC>>::receive_ip_packet(
2065 core_ctx,
2066 bindings_ctx,
2067 device,
2068 src_ip,
2069 dst_ip,
2070 buffer,
2071 info,
2072 None
2073 );
2074 }
2075 Icmpv6Packet::Ndp(packet) => receive_ndp_packet(
2076 core_ctx,
2077 bindings_ctx,
2078 device,
2079 src_ip,
2080 dst_ip,
2081 packet,
2082 header_info,
2083 ),
2084 Icmpv6Packet::PacketTooBig(packet_too_big) => {
2085 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2086 .packet_too_big
2087 .increment();
2088 trace!(
2089 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received a Packet Too Big message"
2090 );
2091 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2092 let mtu = core_ctx.update_pmtu_if_less(
2102 bindings_ctx,
2103 dst_ip.get(),
2104 src_ip.get(),
2105 Mtu::new(packet_too_big.message().mtu()),
2106 );
2107 if let Some(mtu) = mtu {
2108 receive_icmpv6_error(
2109 core_ctx,
2110 bindings_ctx,
2111 device,
2112 &packet_too_big,
2113 Icmpv6ErrorCode::PacketTooBig(mtu),
2114 );
2115 }
2116 }
2117 }
2118 Icmpv6Packet::Mld(packet) => {
2119 core_ctx.receive_mld_packet(
2120 bindings_ctx,
2121 &device,
2122 src_ip,
2123 dst_ip,
2124 packet,
2125 header_info,
2126 );
2127 }
2128 Icmpv6Packet::DestUnreachable(dest_unreachable) => {
2129 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2130 .dest_unreachable
2131 .increment_code(dest_unreachable.code());
2132 receive_icmpv6_error(
2133 core_ctx,
2134 bindings_ctx,
2135 device,
2136 &dest_unreachable,
2137 Icmpv6ErrorCode::DestUnreachable(dest_unreachable.code()),
2138 )
2139 }
2140 Icmpv6Packet::TimeExceeded(time_exceeded) => {
2141 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2142 .time_exceeded
2143 .increment_code(time_exceeded.code());
2144 receive_icmpv6_error(
2145 core_ctx,
2146 bindings_ctx,
2147 device,
2148 &time_exceeded,
2149 Icmpv6ErrorCode::TimeExceeded(time_exceeded.code()),
2150 )
2151 }
2152 Icmpv6Packet::ParameterProblem(parameter_problem) => {
2153 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2154 .parameter_problem
2155 .increment_code(parameter_problem.code());
2156 receive_icmpv6_error(
2157 core_ctx,
2158 bindings_ctx,
2159 device,
2160 ¶meter_problem,
2161 Icmpv6ErrorCode::ParameterProblem(parameter_problem.code()),
2162 )
2163 }
2164 }
2165
2166 Ok(())
2167 }
2168}
2169
2170#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2171struct WithMarks<'a>(&'a Marks);
2172
2173impl<'a> OptionDelegationMarker for WithMarks<'a> {}
2174
2175impl<'a, I: IpExt> DelegatedRouteResolutionOptions<I> for WithMarks<'a> {
2176 fn marks(&self) -> &Marks {
2177 let Self(marks) = self;
2178 marks
2179 }
2180}
2181
2182impl<'a, I: IpExt> DelegatedSendOptions<I> for WithMarks<'a> {}
2183
2184fn send_icmp_reply<I, BC, CC, S, F, O>(
2195 core_ctx: &mut CC,
2196 bindings_ctx: &mut BC,
2197 device: &CC::DeviceId,
2198 original_src_ip: SocketIpAddr<I::Addr>,
2199 original_dst_ip: SocketIpAddr<I::Addr>,
2200 get_body_from_src_ip: F,
2201 ip_options: &O,
2202) where
2203 I: IpExt + FilterIpExt + IcmpCountersIpExt,
2204 CC: IpSocketHandler<I, BC> + DeviceIdContext<AnyDevice> + CounterContext<IcmpTxCounters<I>>,
2205 BC: TxMetadataBindingsTypes,
2206 S: DynamicTransportSerializer<I>,
2207 F: FnOnce(SpecifiedAddr<I::Addr>) -> S,
2208 O: SendOptions<I> + RouteResolutionOptions<I>,
2209{
2210 trace!("send_icmp_reply({:?}, {}, {})", device, original_src_ip, original_dst_ip);
2211 core_ctx.counters().reply.increment();
2212 let tx_metadata: BC::TxMetadata = Default::default();
2213
2214 let egress_device = (original_dst_ip.as_ref().is_multicast()
2218 || original_dst_ip.as_ref().must_have_zone())
2219 .then_some(EitherDeviceId::Strong(device));
2220
2221 core_ctx
2222 .send_oneshot_ip_packet_with_dyn_serializer(
2223 bindings_ctx,
2224 IpSocketArgs {
2225 device: egress_device,
2226 local_ip: IpDeviceAddr::new_from_socket_ip_addr(original_dst_ip),
2227 remote_ip: original_src_ip,
2228 proto: I::ICMP_IP_PROTO,
2229 options: ip_options,
2230 },
2231 tx_metadata,
2232 |src_ip| get_body_from_src_ip(src_ip.into()),
2233 )
2234 .unwrap_or_else(|err| {
2235 debug!("failed to send ICMP reply: {}", err);
2236 })
2237}
2238
2239fn receive_icmpv4_error<
2244 BC: IcmpBindingsContext,
2245 CC: InnerIcmpContext<Ipv4, BC>,
2246 B: SplitByteSlice,
2247 M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>,
2248>(
2249 core_ctx: &mut CC,
2250 bindings_ctx: &mut BC,
2251 device: &CC::DeviceId,
2252 packet: &IcmpPacket<Ipv4, B, M>,
2253 err: Icmpv4ErrorCode,
2254) {
2255 packet.with_original_packet(|res| match res {
2256 Ok(original_packet) => {
2257 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2258 Some(ip) => ip,
2259 None => {
2260 trace!("receive_icmpv4_error: Got ICMP error message whose original IPv4 packet contains an unspecified destination address; discarding");
2261 return;
2262 },
2263 };
2264 InnerIcmpContext::receive_icmp_error(
2265 core_ctx,
2266 bindings_ctx,
2267 device,
2268 SpecifiedAddr::new(original_packet.src_ip()),
2269 dst_ip,
2270 original_packet.proto(),
2271 original_packet.body().into_inner(),
2272 err,
2273 );
2274 }
2275 Err(_) => debug!(
2276 "receive_icmpv4_error: Got ICMP error message with unparsable original IPv4 packet"
2277 ),
2278 })
2279}
2280
2281fn receive_icmpv6_error<
2286 BC: IcmpBindingsContext,
2287 CC: InnerIcmpContext<Ipv6, BC>,
2288 B: SplitByteSlice,
2289 M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>,
2290>(
2291 core_ctx: &mut CC,
2292 bindings_ctx: &mut BC,
2293 device: &CC::DeviceId,
2294 packet: &IcmpPacket<Ipv6, B, M>,
2295 err: Icmpv6ErrorCode,
2296) {
2297 packet.with_original_packet(|res| match res {
2298 Ok(original_packet) => {
2299 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2300 Some(ip)=>ip,
2301 None => {
2302 trace!("receive_icmpv6_error: Got ICMP error message whose original IPv6 packet contains an unspecified destination address; discarding");
2303 return;
2304 },
2305 };
2306 match original_packet.body_proto() {
2307 Ok((body, proto)) => {
2308 InnerIcmpContext::receive_icmp_error(
2309 core_ctx,
2310 bindings_ctx,
2311 device,
2312 SpecifiedAddr::new(original_packet.src_ip()),
2313 dst_ip,
2314 proto,
2315 body.into_inner(),
2316 err,
2317 );
2318 }
2319 Err(ExtHdrParseError) => {
2320 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");
2321 return;
2324 }
2325 }
2326 }
2327 Err(_body) => debug!(
2328 "receive_icmpv6_error: Got ICMPv6 error message with unparsable original IPv6 packet"
2329 ),
2330 })
2331}
2332
2333fn send_icmpv4_error_message<B, BC, CC>(
2334 core_ctx: &mut CC,
2335 bindings_ctx: &mut BC,
2336 device: Option<&CC::DeviceId>,
2337 frame_dst: Option<FrameDestination>,
2338 original_src_ip: SocketIpAddr<Ipv4Addr>,
2339 original_dst_ip: SocketIpAddr<Ipv4Addr>,
2340 message: Icmpv4ErrorMessage,
2341 mut original_packet: B,
2342 header_len: usize,
2343 marks: &Marks,
2344) where
2345 B: BufferMut,
2346 BC: IcmpBindingsContext,
2347 CC: IcmpSendContext<Ipv4, BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2348{
2349 if !should_send_icmpv4_error(frame_dst, original_src_ip.into(), original_dst_ip.into()) {
2353 return;
2354 }
2355
2356 original_packet.shrink_back_to(header_len + 64);
2359
2360 let tx_metadata: BC::TxMetadata = Default::default();
2361
2362 macro_rules! send {
2363 ($message:expr, $code:expr) => {{
2364 let _ = try_send_error!(
2367 core_ctx,
2368 bindings_ctx,
2369 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2370 bindings_ctx,
2371 IpSocketArgs {
2372 device: device.map(EitherDeviceId::Strong),
2373 local_ip: None,
2374 remote_ip: original_src_ip,
2375 proto: Ipv4Proto::Icmp,
2376 options: &WithMarks(marks),
2377 },
2378 tx_metadata,
2379 |local_ip| {
2380 IcmpPacketBuilder::<Ipv4, _>::new(
2381 local_ip.addr(),
2382 original_src_ip.addr(),
2383 $code,
2384 $message,
2385 )
2386 .wrap_body(original_packet)
2387 },
2388 )
2389 );
2390 }};
2391 }
2392
2393 match message {
2394 Icmpv4ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2395 Icmpv4ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2396 Icmpv4ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2397 }
2398}
2399
2400fn send_icmpv6_error_message<B, BC, CC>(
2401 core_ctx: &mut CC,
2402 bindings_ctx: &mut BC,
2403 device: Option<&CC::DeviceId>,
2404 frame_dst: Option<FrameDestination>,
2405 original_src_ip: SocketIpAddr<Ipv6Addr>,
2406 original_dst_ip: SocketIpAddr<Ipv6Addr>,
2407 message: Icmpv6ErrorMessage,
2408 original_packet: B,
2409 allow_dst_multicast: bool,
2410 marks: &Marks,
2411) where
2412 B: BufferMut,
2413 BC: IcmpBindingsContext,
2414 CC: IcmpSendContext<Ipv6, BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2415{
2416 if !should_send_icmpv6_error(
2420 frame_dst,
2421 original_src_ip.into(),
2422 original_dst_ip.into(),
2423 allow_dst_multicast,
2424 ) {
2425 return;
2426 }
2427
2428 struct Icmpv6ErrorOptions<'a>(&'a Marks);
2429 impl<'a> OptionDelegationMarker for Icmpv6ErrorOptions<'a> {}
2430 impl<'a> DelegatedSendOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2431 fn mtu(&self) -> Mtu {
2432 Ipv6::MINIMUM_LINK_MTU
2433 }
2434 }
2435 impl<'a> DelegatedRouteResolutionOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2436 fn marks(&self) -> &Marks {
2437 let Self(marks) = self;
2438 marks
2439 }
2440 }
2441
2442 let tx_metadata: BC::TxMetadata = Default::default();
2443
2444 macro_rules! send {
2445 ($message:expr, $code:expr) => {{
2446 let _ = try_send_error!(
2449 core_ctx,
2450 bindings_ctx,
2451 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2452 bindings_ctx,
2453 IpSocketArgs {
2454 device: device.map(EitherDeviceId::Strong),
2455 local_ip: None,
2456 remote_ip: original_src_ip,
2457 proto: Ipv6Proto::Icmpv6,
2458 options: &Icmpv6ErrorOptions(marks),
2459 },
2460 tx_metadata,
2461 |local_ip| {
2462 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
2463 local_ip.addr(),
2464 original_src_ip.addr(),
2465 $code,
2466 $message,
2467 );
2468
2469 icmp_builder.wrap_body(TruncatingSerializer::new(
2472 original_packet,
2473 TruncateDirection::DiscardBack,
2474 ))
2475 },
2476 )
2477 );
2478 }};
2479 }
2480
2481 match message {
2482 Icmpv6ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2483 Icmpv6ErrorMessage::PacketTooBig { message, code } => send!(message, code),
2484 Icmpv6ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2485 Icmpv6ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2486 }
2487}
2488
2489fn should_send_icmpv4_error(
2507 frame_dst: Option<FrameDestination>,
2508 src_ip: SpecifiedAddr<Ipv4Addr>,
2509 dst_ip: SpecifiedAddr<Ipv4Addr>,
2510) -> bool {
2511 !(dst_ip.is_multicast()
2531 || dst_ip.is_limited_broadcast()
2532 || frame_dst.is_some_and(|dst| dst.is_broadcast())
2533 || src_ip.is_loopback()
2534 || src_ip.is_limited_broadcast()
2535 || src_ip.is_multicast()
2536 || src_ip.is_class_e())
2537}
2538
2539fn should_send_icmpv6_error(
2566 frame_dst: Option<FrameDestination>,
2567 src_ip: SpecifiedAddr<Ipv6Addr>,
2568 dst_ip: SpecifiedAddr<Ipv6Addr>,
2569 allow_dst_multicast: bool,
2570) -> bool {
2571 let multicast_frame_dst = match frame_dst {
2574 Some(FrameDestination::Individual { local: _ }) | None => false,
2575 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
2576 };
2577 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
2578 return false;
2579 }
2580 if src_ip.is_loopback() || src_ip.is_multicast() {
2581 return false;
2582 }
2583 true
2584}
2585
2586fn is_icmp_error_or_redirect_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
2598 proto == I::ICMP_IP_PROTO
2599 && peek_message_type::<I::IcmpMessageType>(buf)
2600 .map(IcmpMessageType::is_error_or_redirect)
2601 .unwrap_or(true)
2602}
2603
2604#[cfg(any(test, feature = "testutils"))]
2606pub(crate) mod testutil {
2607 use alloc::vec::Vec;
2608 use net_types::ethernet::Mac;
2609 use net_types::ip::{Ipv6, Ipv6Addr};
2610 use packet::{Buf, InnerPacketBuilder as _, Serializer as _};
2611 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
2612 use packet_formats::icmp::ndp::{
2613 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
2614 };
2615 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
2616 use packet_formats::ip::Ipv6Proto;
2617 use packet_formats::ipv6::Ipv6PacketBuilder;
2618
2619 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
2620
2621 pub fn neighbor_advertisement_ip_packet(
2624 src_ip: Ipv6Addr,
2625 dst_ip: Ipv6Addr,
2626 router_flag: bool,
2627 solicited_flag: bool,
2628 override_flag: bool,
2629 mac: Mac,
2630 ) -> Buf<Vec<u8>> {
2631 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
2632 .into_serializer()
2633 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2634 src_ip,
2635 dst_ip,
2636 IcmpZeroCode,
2637 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
2638 ))
2639 .wrap_in(Ipv6PacketBuilder::new(
2640 src_ip,
2641 dst_ip,
2642 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2643 Ipv6Proto::Icmpv6,
2644 ))
2645 .serialize_vec_outer()
2646 .unwrap()
2647 .unwrap_b()
2648 }
2649
2650 pub fn neighbor_solicitation_ip_packet(
2653 src_ip: Ipv6Addr,
2654 dst_ip: Ipv6Addr,
2655 target_addr: Ipv6Addr,
2656 mac: Mac,
2657 ) -> Buf<Vec<u8>> {
2658 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
2659 .into_serializer()
2660 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2661 src_ip,
2662 dst_ip,
2663 IcmpZeroCode,
2664 NeighborSolicitation::new(target_addr),
2665 ))
2666 .wrap_in(Ipv6PacketBuilder::new(
2667 src_ip,
2668 dst_ip,
2669 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2670 Ipv6Proto::Icmpv6,
2671 ))
2672 .serialize_vec_outer()
2673 .unwrap()
2674 .unwrap_b()
2675 }
2676}
2677
2678#[cfg(test)]
2679mod tests {
2680 use alloc::vec;
2681 use alloc::vec::Vec;
2682 use packet_formats::icmp::ndp::options::NdpNonce;
2683
2684 use core::fmt::Debug;
2685 use core::time::Duration;
2686
2687 use net_types::ip::Subnet;
2688 use netstack3_base::testutil::{
2689 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId,
2690 TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt, set_logger_for_test,
2691 };
2692 use netstack3_base::{CtxPair, Uninstantiable};
2693 use netstack3_filter::TransportPacketSerializer;
2694 use packet::{Buf, EmptyBuf};
2695 use packet_formats::icmp::mld::MldPacket;
2696 use packet_formats::ip::IpProto;
2697 use packet_formats::utils::NonZeroDuration;
2698
2699 use super::*;
2700 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
2701 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
2702 use crate::internal::socket::{
2703 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
2704 };
2705 use crate::socket::RouteResolutionOptions;
2706
2707 use test_util::assert_geq;
2708
2709 pub(super) trait IcmpTestIpExt:
2710 TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt
2711 {
2712 }
2713 impl<I: TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt> IcmpTestIpExt for I {}
2714
2715 type InnerIpSocketCtx<I> = FakeCoreCtx<
2717 FakeIpSocketCtx<I, FakeDeviceId>,
2718 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
2719 FakeDeviceId,
2720 >;
2721
2722 pub(super) struct FakeIcmpCoreCtx<I: IcmpTestIpExt> {
2724 ip_socket_ctx: InnerIpSocketCtx<I>,
2725 icmp: FakeIcmpCoreCtxState<I>,
2726 }
2727
2728 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
2730 (),
2731 RouterAdvertisementEvent<FakeDeviceId>,
2732 FakeIcmpBindingsCtxState<I>,
2733 (),
2734 >;
2735
2736 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
2740
2741 pub(super) struct FakeIcmpCoreCtxState<I: IcmpTestIpExt> {
2742 error_send_bucket: TokenBucket<FakeInstant>,
2743 receive_icmp_error: Vec<I::ErrorCode>,
2744 rx_counters: IcmpRxCounters<I>,
2745 tx_counters: IcmpTxCounters<I>,
2746 ndp_counters: NdpCounters,
2747 }
2748
2749 impl<I: IcmpTestIpExt> FakeIcmpCoreCtx<I> {
2750 fn with_errors_per_second(errors_per_second: u64) -> Self {
2751 Self {
2752 icmp: FakeIcmpCoreCtxState {
2753 error_send_bucket: TokenBucket::new(errors_per_second),
2754 receive_icmp_error: Default::default(),
2755 rx_counters: Default::default(),
2756 tx_counters: Default::default(),
2757 ndp_counters: Default::default(),
2758 },
2759 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
2760 core::iter::once(FakeDeviceConfig {
2761 device: FakeDeviceId,
2762 local_ips: vec![I::TEST_ADDRS.local_ip],
2763 remote_ips: vec![I::TEST_ADDRS.remote_ip],
2764 }),
2765 )),
2766 }
2767 }
2768 }
2769
2770 impl<I: IcmpTestIpExt> Default for FakeIcmpCoreCtx<I> {
2771 fn default() -> Self {
2772 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
2773 }
2774 }
2775
2776 impl<I: IcmpTestIpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
2777 type DeviceId = FakeDeviceId;
2778 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
2779 }
2780
2781 impl<I: IcmpTestIpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
2782 impl<I: IcmpTestIpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
2783
2784 impl<I: IcmpTestIpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
2785 fn counters(&self) -> &IcmpRxCounters<I> {
2786 &self.icmp.rx_counters
2787 }
2788 }
2789
2790 impl<I: IcmpTestIpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
2791 fn counters(&self) -> &IcmpTxCounters<I> {
2792 &self.icmp.tx_counters
2793 }
2794 }
2795
2796 impl<I: IcmpTestIpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
2797 fn counters(&self) -> &NdpCounters {
2798 &self.icmp.ndp_counters
2799 }
2800 }
2801
2802 pub enum FakeEchoIpTransportContext {}
2803
2804 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
2805
2806 impl<I> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
2807 for FakeEchoIpTransportContext
2808 where
2809 I: IcmpTestIpExt + IpLayerIpExt,
2810 {
2811 type EarlyDemuxSocket = Never;
2812
2813 fn early_demux<B: ParseBuffer>(
2814 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2815 _device: &FakeDeviceId,
2816 _src_ip: I::Addr,
2817 _dst_ip: I::Addr,
2818 _buffer: B,
2819 ) -> Option<Self::EarlyDemuxSocket> {
2820 None
2821 }
2822
2823 fn receive_icmp_error(
2824 core_ctx: &mut FakeIcmpCoreCtx<I>,
2825 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2826 _device: &FakeDeviceId,
2827 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2828 _original_dst_ip: SpecifiedAddr<I::Addr>,
2829 _original_body: &[u8],
2830 _err: I::ErrorCode,
2831 ) {
2832 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
2833 }
2834
2835 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
2836 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2837 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2838 _device: &FakeDeviceId,
2839 _src_ip: I::RecvSrcAddr,
2840 _dst_ip: SpecifiedAddr<I::Addr>,
2841 _buffer: B,
2842 _info: &LocalDeliveryPacketInfo<I, H>,
2843 _early_demux_socket: Option<Never>,
2844 ) -> Result<(), (B, I::IcmpError)> {
2845 unimplemented!()
2846 }
2847 }
2848
2849 impl<I: IpLayerIpExt + IcmpTestIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>>
2850 for FakeIcmpCoreCtx<I>
2851 {
2852 type EchoTransportContext = FakeEchoIpTransportContext;
2853
2854 fn receive_icmp_error(
2855 &mut self,
2856 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2857 device: &Self::DeviceId,
2858 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2859 original_dst_ip: SpecifiedAddr<I::Addr>,
2860 original_proto: I::Proto,
2861 original_body: &[u8],
2862 err: I::ErrorCode,
2863 ) {
2864 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
2865 self.icmp.receive_icmp_error.push(err);
2866 if original_proto == I::ICMP_IP_PROTO {
2867 receive_ip_transport_icmp_error(
2868 self,
2869 bindings_ctx,
2870 device,
2871 original_src_ip,
2872 original_dst_ip,
2873 original_body,
2874 err,
2875 )
2876 }
2877 }
2878 }
2879
2880 impl<I: IpLayerIpExt + IcmpTestIpExt> IcmpSendContext<I, FakeIcmpBindingsCtx<I>>
2881 for FakeIcmpCoreCtx<I>
2882 {
2883 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
2884 &mut self,
2885 cb: F,
2886 ) -> O {
2887 cb(&mut self.icmp.error_send_bucket)
2888 }
2889 }
2890
2891 #[test]
2892 fn test_should_send_icmpv4_error() {
2893 let src_ip = TEST_ADDRS_V4.local_ip;
2894 let dst_ip = TEST_ADDRS_V4.remote_ip;
2895 let frame_dst = FrameDestination::Individual { local: true };
2896 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
2897 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
2898
2899 assert!(should_send_icmpv4_error(Some(frame_dst), src_ip, dst_ip));
2901 assert!(should_send_icmpv4_error(None, src_ip, dst_ip));
2902
2903 assert!(!should_send_icmpv4_error(
2905 Some(frame_dst),
2906 src_ip,
2907 Ipv4::LIMITED_BROADCAST_ADDRESS,
2908 ));
2909
2910 assert!(!should_send_icmpv4_error(Some(frame_dst), src_ip, multicast_ip_1,));
2912
2913 assert!(!should_send_icmpv4_error(Some(FrameDestination::Broadcast), src_ip, dst_ip,));
2915
2916 assert!(!should_send_icmpv4_error(Some(frame_dst), Ipv4::LOOPBACK_ADDRESS, dst_ip,));
2918
2919 assert!(!should_send_icmpv4_error(
2921 Some(frame_dst),
2922 Ipv4::LIMITED_BROADCAST_ADDRESS,
2923 dst_ip,
2924 ));
2925
2926 assert!(!should_send_icmpv4_error(Some(frame_dst), multicast_ip_2, dst_ip));
2928
2929 assert!(!should_send_icmpv4_error(
2931 Some(frame_dst),
2932 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
2933 dst_ip,
2934 ));
2935 }
2936
2937 #[test]
2938 fn test_should_send_icmpv6_error() {
2939 let src_ip = TEST_ADDRS_V6.local_ip;
2940 let dst_ip = TEST_ADDRS_V6.remote_ip;
2941 let frame_dst = FrameDestination::Individual { local: true };
2942 let multicast_ip_1 =
2943 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
2944 let multicast_ip_2 =
2945 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
2946
2947 assert!(should_send_icmpv6_error(
2949 Some(frame_dst),
2950 src_ip,
2951 dst_ip,
2952 false ));
2954 assert!(should_send_icmpv6_error(
2955 None, src_ip, dst_ip, false ));
2957 assert!(should_send_icmpv6_error(
2958 Some(frame_dst),
2959 src_ip,
2960 dst_ip,
2961 true ));
2963
2964 assert!(!should_send_icmpv6_error(
2967 Some(frame_dst),
2968 src_ip,
2969 multicast_ip_1,
2970 false ));
2972 assert!(should_send_icmpv6_error(
2973 Some(frame_dst),
2974 src_ip,
2975 multicast_ip_1,
2976 true ));
2978
2979 assert!(!should_send_icmpv6_error(
2982 Some(FrameDestination::Broadcast),
2983 src_ip,
2984 dst_ip,
2985 false ));
2987 assert!(should_send_icmpv6_error(
2988 Some(FrameDestination::Broadcast),
2989 src_ip,
2990 dst_ip,
2991 true ));
2993
2994 assert!(!should_send_icmpv6_error(
2996 Some(frame_dst),
2997 Ipv6::LOOPBACK_ADDRESS,
2998 dst_ip,
2999 false ));
3001 assert!(!should_send_icmpv6_error(
3002 Some(frame_dst),
3003 Ipv6::LOOPBACK_ADDRESS,
3004 dst_ip,
3005 true ));
3007
3008 assert!(!should_send_icmpv6_error(
3010 Some(frame_dst),
3011 multicast_ip_2,
3012 dst_ip,
3013 false ));
3015 assert!(!should_send_icmpv6_error(
3016 Some(frame_dst),
3017 multicast_ip_2,
3018 dst_ip,
3019 true ));
3021
3022 assert!(!should_send_icmpv6_error(
3025 Some(FrameDestination::Broadcast),
3026 multicast_ip_2,
3027 dst_ip,
3028 false ));
3030 assert!(!should_send_icmpv6_error(
3031 Some(FrameDestination::Broadcast),
3032 multicast_ip_2,
3033 dst_ip,
3034 true ));
3036 assert!(!should_send_icmpv6_error(
3037 Some(frame_dst),
3038 multicast_ip_2,
3039 multicast_ip_1,
3040 false ));
3042 assert!(!should_send_icmpv6_error(
3043 Some(frame_dst),
3044 multicast_ip_2,
3045 multicast_ip_1,
3046 true ));
3048 }
3049
3050 #[derive(Default)]
3057 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3058 _marker: core::marker::PhantomData<I>,
3059 }
3060
3061 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3062 fn should_send_timestamp_reply(&self) -> bool {
3063 false
3064 }
3065 }
3066 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3067 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3068
3069 impl<I: IcmpTestIpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3070 fn new_ip_socket<O>(
3071 &mut self,
3072 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3073 args: IpSocketArgs<'_, Self::DeviceId, I, O>,
3074 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3075 where
3076 O: RouteResolutionOptions<I>,
3077 {
3078 self.ip_socket_ctx.new_ip_socket(bindings_ctx, args)
3079 }
3080
3081 fn send_ip_packet<S, O>(
3082 &mut self,
3083 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3084 socket: &IpSock<I, Self::WeakDeviceId>,
3085 body: S,
3086 options: &O,
3087 tx_meta: FakeTxMetadata,
3088 ) -> Result<(), IpSockSendError>
3089 where
3090 S: TransportPacketSerializer<I>,
3091 S::Buffer: BufferMut,
3092 O: SendOptions<I> + RouteResolutionOptions<I>,
3093 {
3094 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3095 }
3096
3097 fn confirm_reachable<O>(
3098 &mut self,
3099 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3100 socket: &IpSock<I, Self::WeakDeviceId>,
3101 options: &O,
3102 ) where
3103 O: RouteResolutionOptions<I>,
3104 {
3105 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3106 }
3107 }
3108
3109 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3110 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3111 unimplemented!()
3112 }
3113
3114 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3115 unreachable!()
3116 }
3117
3118 fn handle_received_dad_packet(
3119 &mut self,
3120 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3121 _device_id: &Self::DeviceId,
3122 _addr: SpecifiedAddr<Ipv6Addr>,
3123 _probe_data: Option<NdpNonce<&'_ [u8]>>,
3124 ) -> Option<IpAddressState> {
3125 unimplemented!()
3126 }
3127 }
3128
3129 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3130 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3131 cb(&())
3132 }
3133
3134 fn get_local_addr_for_remote(
3135 &mut self,
3136 _device_id: &Self::DeviceId,
3137 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3138 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3139 unimplemented!()
3140 }
3141
3142 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3143 unimplemented!()
3144 }
3145 }
3146
3147 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3148 fn address_status_for_device(
3149 &mut self,
3150 _addr: SpecifiedAddr<Ipv6Addr>,
3151 _device_id: &Self::DeviceId,
3152 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3153 unimplemented!()
3154 }
3155 }
3156
3157 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3158 type LinkLayerAddr = Uninstantiable;
3159
3160 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3161 unimplemented!()
3162 }
3163
3164 fn set_discovered_retrans_timer(
3165 &mut self,
3166 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3167 _device_id: &Self::DeviceId,
3168 _retrans_timer: NonZeroDuration,
3169 ) {
3170 unimplemented!()
3171 }
3172
3173 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3174 unimplemented!()
3175 }
3176
3177 fn update_discovered_ipv6_route(
3178 &mut self,
3179 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3180 _device_id: &Self::DeviceId,
3181 _route: Ipv6DiscoveredRoute,
3182 _properties: Ipv6DiscoveredRouteProperties,
3183 _lifetime: Option<NonZeroNdpLifetime>,
3184 ) {
3185 unimplemented!()
3186 }
3187
3188 fn apply_slaac_update(
3189 &mut self,
3190 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3191 _device_id: &Self::DeviceId,
3192 _subnet: Subnet<Ipv6Addr>,
3193 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3194 _valid_lifetime: Option<NonZeroNdpLifetime>,
3195 ) {
3196 unimplemented!()
3197 }
3198
3199 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3200 &mut self,
3201 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3202 _device: &FakeDeviceId,
3203 _src_ip: Ipv6SourceAddr,
3204 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3205 _packet: MldPacket<B>,
3206 _header_info: &H,
3207 ) {
3208 unimplemented!()
3209 }
3210 }
3211
3212 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3213 fn send_ip_packet_from_device<S>(
3214 &mut self,
3215 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3216 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3217 _body: S,
3218 ) -> Result<(), IpSendFrameError<S>> {
3219 unimplemented!()
3220 }
3221
3222 fn send_ip_frame<S>(
3223 &mut self,
3224 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3225 _device: &Self::DeviceId,
3226 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3227 _body: S,
3228 ) -> Result<(), IpSendFrameError<S>>
3229 where
3230 S: Serializer,
3231 S::Buffer: BufferMut,
3232 {
3233 unimplemented!()
3234 }
3235 }
3236
3237 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3238 fn handle_neighbor_probe(
3239 &mut self,
3240 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3241 _device_id: &Self::DeviceId,
3242 _neighbor: SpecifiedAddr<Ipv6Addr>,
3243 _link_addr: &[u8],
3244 ) {
3245 unimplemented!()
3246 }
3247
3248 fn handle_neighbor_confirmation(
3249 &mut self,
3250 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3251 _device_id: &Self::DeviceId,
3252 _neighbor: SpecifiedAddr<Ipv6Addr>,
3253 _link_addr: Option<&[u8]>,
3254 _flags: ConfirmationFlags,
3255 ) {
3256 unimplemented!()
3257 }
3258
3259 fn flush_neighbor_table(
3260 &mut self,
3261 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3262 _device_id: &Self::DeviceId,
3263 ) {
3264 unimplemented!()
3265 }
3266 }
3267
3268 #[test]
3269 fn test_receive_icmpv4_error() {
3270 const ICMP_ID: u16 = 0x0F;
3273 const SEQ_NUM: u16 = 0xF0;
3274
3275 fn test_receive_icmpv4_error_helper<
3290 C: Debug,
3291 M: IcmpMessage<Ipv4, Code = C> + Debug,
3292 F: Fn(&FakeIcmpCtx<Ipv4>),
3293 >(
3294 original_packet: &mut [u8],
3295 code: C,
3296 msg: M,
3297 f: F,
3298 ) {
3299 set_logger_for_test();
3300
3301 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3302
3303 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3304 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3305 core_ctx,
3306 bindings_ctx,
3307 &FakeDeviceId,
3308 Ipv4SourceAddr::new(*TEST_ADDRS_V4.remote_ip).unwrap(),
3309 TEST_ADDRS_V4.local_ip,
3310 IcmpPacketBuilder::new(TEST_ADDRS_V4.remote_ip, TEST_ADDRS_V4.local_ip, code, msg)
3311 .wrap_body(Buf::new(original_packet, ..))
3312 .serialize_vec_outer()
3313 .unwrap(),
3314 &LocalDeliveryPacketInfo::default(),
3315 None,
3316 )
3317 .unwrap();
3318 f(&ctx);
3319 }
3320 let mut buffer = EmptyBuf
3333 .wrap_in(IcmpPacketBuilder::<Ipv4, _>::new(
3334 TEST_ADDRS_V4.local_ip,
3335 TEST_ADDRS_V4.remote_ip,
3336 IcmpZeroCode,
3337 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3338 ))
3339 .wrap_in(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3340 TEST_ADDRS_V4.local_ip,
3341 TEST_ADDRS_V4.remote_ip,
3342 64,
3343 Ipv4Proto::Icmp,
3344 ))
3345 .serialize_vec_outer()
3346 .unwrap();
3347
3348 test_receive_icmpv4_error_helper(
3349 buffer.as_mut(),
3350 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3351 IcmpDestUnreachable::default(),
3352 |CtxPair { core_ctx, bindings_ctx: _ }| {
3353 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3354 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3355 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3356 assert_eq!(
3357 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3358 1
3359 );
3360 let err = Icmpv4ErrorCode::DestUnreachable(
3361 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3362 IcmpDestUnreachable::default(),
3363 );
3364 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3365 },
3366 );
3367
3368 test_receive_icmpv4_error_helper(
3369 buffer.as_mut(),
3370 Icmpv4TimeExceededCode::TtlExpired,
3371 IcmpTimeExceeded::default(),
3372 |CtxPair { core_ctx, bindings_ctx: _ }| {
3373 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3374 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3375 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3376 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3377 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3378 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3379 },
3380 );
3381
3382 test_receive_icmpv4_error_helper(
3383 buffer.as_mut(),
3384 Icmpv4ParameterProblemCode::PointerIndicatesError,
3385 Icmpv4ParameterProblem::new(0),
3386 |CtxPair { core_ctx, bindings_ctx: _ }| {
3387 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3388 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3389 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3390 assert_eq!(
3391 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3392 1
3393 );
3394 let err = Icmpv4ErrorCode::ParameterProblem(
3395 Icmpv4ParameterProblemCode::PointerIndicatesError,
3396 );
3397 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3398 },
3399 );
3400
3401 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3408 TEST_ADDRS_V4.local_ip,
3409 TEST_ADDRS_V4.remote_ip,
3410 64,
3411 Ipv4Proto::Icmp,
3412 )
3413 .wrap_body(EmptyBuf)
3414 .serialize_vec_outer()
3415 .unwrap();
3416
3417 test_receive_icmpv4_error_helper(
3418 buffer.as_mut(),
3419 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3420 IcmpDestUnreachable::default(),
3421 |CtxPair { core_ctx, bindings_ctx: _ }| {
3422 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3423 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3424 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3425 assert_eq!(
3426 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3427 1
3428 );
3429 let err = Icmpv4ErrorCode::DestUnreachable(
3430 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3431 IcmpDestUnreachable::default(),
3432 );
3433 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3434 },
3435 );
3436
3437 test_receive_icmpv4_error_helper(
3438 buffer.as_mut(),
3439 Icmpv4TimeExceededCode::TtlExpired,
3440 IcmpTimeExceeded::default(),
3441 |CtxPair { core_ctx, bindings_ctx: _ }| {
3442 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3443 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3444 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3445 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3446 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3447 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3448 },
3449 );
3450
3451 test_receive_icmpv4_error_helper(
3452 buffer.as_mut(),
3453 Icmpv4ParameterProblemCode::PointerIndicatesError,
3454 Icmpv4ParameterProblem::new(0),
3455 |CtxPair { core_ctx, bindings_ctx: _ }| {
3456 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3457 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3458 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3459 assert_eq!(
3460 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3461 1
3462 );
3463 let err = Icmpv4ErrorCode::ParameterProblem(
3464 Icmpv4ParameterProblemCode::PointerIndicatesError,
3465 );
3466 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3467 },
3468 );
3469
3470 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3476 TEST_ADDRS_V4.local_ip,
3477 TEST_ADDRS_V4.remote_ip,
3478 64,
3479 IpProto::Udp.into(),
3480 )
3481 .wrap_body(EmptyBuf)
3482 .serialize_vec_outer()
3483 .unwrap();
3484
3485 test_receive_icmpv4_error_helper(
3486 buffer.as_mut(),
3487 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3488 IcmpDestUnreachable::default(),
3489 |CtxPair { core_ctx, bindings_ctx: _ }| {
3490 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3491 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3492 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3493 assert_eq!(
3494 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3495 1
3496 );
3497 let err = Icmpv4ErrorCode::DestUnreachable(
3498 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3499 IcmpDestUnreachable::default(),
3500 );
3501 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3502 },
3503 );
3504
3505 test_receive_icmpv4_error_helper(
3506 buffer.as_mut(),
3507 Icmpv4TimeExceededCode::TtlExpired,
3508 IcmpTimeExceeded::default(),
3509 |CtxPair { core_ctx, bindings_ctx: _ }| {
3510 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3511 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3512 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3513 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3514 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3515 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3516 },
3517 );
3518
3519 test_receive_icmpv4_error_helper(
3520 buffer.as_mut(),
3521 Icmpv4ParameterProblemCode::PointerIndicatesError,
3522 Icmpv4ParameterProblem::new(0),
3523 |CtxPair { core_ctx, bindings_ctx: _ }| {
3524 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3525 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3526 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3527 assert_eq!(
3528 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3529 1
3530 );
3531 let err = Icmpv4ErrorCode::ParameterProblem(
3532 Icmpv4ParameterProblemCode::PointerIndicatesError,
3533 );
3534 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3535 },
3536 );
3537 }
3538
3539 #[test]
3540 fn test_receive_icmpv6_error() {
3541 const ICMP_ID: u16 = 0x0F;
3544 const SEQ_NUM: u16 = 0xF0;
3545
3546 fn test_receive_icmpv6_error_helper<
3561 C: Debug,
3562 M: IcmpMessage<Ipv6, Code = C> + Debug,
3563 F: Fn(&FakeIcmpCtx<Ipv6>),
3564 >(
3565 original_packet: &mut [u8],
3566 code: C,
3567 msg: M,
3568 f: F,
3569 ) {
3570 set_logger_for_test();
3571
3572 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
3573 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3574 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
3575 core_ctx,
3576 bindings_ctx,
3577 &FakeDeviceId,
3578 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
3579 TEST_ADDRS_V6.local_ip,
3580 IcmpPacketBuilder::new(TEST_ADDRS_V6.remote_ip, TEST_ADDRS_V6.local_ip, code, msg)
3581 .wrap_body(Buf::new(original_packet, ..))
3582 .serialize_vec_outer()
3583 .unwrap(),
3584 &LocalDeliveryPacketInfo::default(),
3585 None,
3586 )
3587 .unwrap();
3588 f(&ctx);
3589 }
3590 let mut buffer = EmptyBuf
3603 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3604 TEST_ADDRS_V6.local_ip,
3605 TEST_ADDRS_V6.remote_ip,
3606 IcmpZeroCode,
3607 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3608 ))
3609 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3610 TEST_ADDRS_V6.local_ip,
3611 TEST_ADDRS_V6.remote_ip,
3612 64,
3613 Ipv6Proto::Icmpv6,
3614 ))
3615 .serialize_vec_outer()
3616 .unwrap();
3617
3618 test_receive_icmpv6_error_helper(
3619 buffer.as_mut(),
3620 Icmpv6DestUnreachableCode::NoRoute,
3621 IcmpDestUnreachable::default(),
3622 |CtxPair { core_ctx, bindings_ctx: _ }| {
3623 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3624 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3625 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3626 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3627 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3628 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3629 },
3630 );
3631
3632 test_receive_icmpv6_error_helper(
3633 buffer.as_mut(),
3634 Icmpv6TimeExceededCode::HopLimitExceeded,
3635 IcmpTimeExceeded::default(),
3636 |CtxPair { core_ctx, bindings_ctx: _ }| {
3637 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3638 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3639 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3640 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3641 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3642 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3643 },
3644 );
3645
3646 test_receive_icmpv6_error_helper(
3647 buffer.as_mut(),
3648 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3649 Icmpv6ParameterProblem::new(0),
3650 |CtxPair { core_ctx, bindings_ctx: _ }| {
3651 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3652 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3653 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3654 assert_eq!(
3655 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3656 1
3657 );
3658 let err = Icmpv6ErrorCode::ParameterProblem(
3659 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3660 );
3661 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3662 },
3663 );
3664
3665 let mut buffer = EmptyBuf
3672 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3673 TEST_ADDRS_V6.local_ip,
3674 TEST_ADDRS_V6.remote_ip,
3675 64,
3676 Ipv6Proto::Icmpv6,
3677 ))
3678 .serialize_vec_outer()
3679 .unwrap();
3680
3681 test_receive_icmpv6_error_helper(
3682 buffer.as_mut(),
3683 Icmpv6DestUnreachableCode::NoRoute,
3684 IcmpDestUnreachable::default(),
3685 |CtxPair { core_ctx, bindings_ctx: _ }| {
3686 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3687 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3688 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3689 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3690 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3691 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3692 },
3693 );
3694
3695 test_receive_icmpv6_error_helper(
3696 buffer.as_mut(),
3697 Icmpv6TimeExceededCode::HopLimitExceeded,
3698 IcmpTimeExceeded::default(),
3699 |CtxPair { core_ctx, bindings_ctx: _ }| {
3700 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3701 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3702 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3703 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3704 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3705 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3706 },
3707 );
3708
3709 test_receive_icmpv6_error_helper(
3710 buffer.as_mut(),
3711 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3712 Icmpv6ParameterProblem::new(0),
3713 |CtxPair { core_ctx, bindings_ctx: _ }| {
3714 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3715 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3716 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3717 assert_eq!(
3718 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3719 1
3720 );
3721 let err = Icmpv6ErrorCode::ParameterProblem(
3722 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3723 );
3724 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3725 },
3726 );
3727
3728 let mut buffer = <Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3734 TEST_ADDRS_V6.local_ip,
3735 TEST_ADDRS_V6.remote_ip,
3736 64,
3737 IpProto::Udp.into(),
3738 )
3739 .wrap_body(EmptyBuf)
3740 .serialize_vec_outer()
3741 .unwrap();
3742
3743 test_receive_icmpv6_error_helper(
3744 buffer.as_mut(),
3745 Icmpv6DestUnreachableCode::NoRoute,
3746 IcmpDestUnreachable::default(),
3747 |CtxPair { core_ctx, bindings_ctx: _ }| {
3748 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3749 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3750 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3751 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3752 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3753 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3754 },
3755 );
3756
3757 test_receive_icmpv6_error_helper(
3758 buffer.as_mut(),
3759 Icmpv6TimeExceededCode::HopLimitExceeded,
3760 IcmpTimeExceeded::default(),
3761 |CtxPair { core_ctx, bindings_ctx: _ }| {
3762 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3763 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3764 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3765 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3766 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3767 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3768 },
3769 );
3770
3771 test_receive_icmpv6_error_helper(
3772 buffer.as_mut(),
3773 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3774 Icmpv6ParameterProblem::new(0),
3775 |CtxPair { core_ctx, bindings_ctx: _ }| {
3776 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3777 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3778 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3779 assert_eq!(
3780 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3781 1
3782 );
3783 let err = Icmpv6ErrorCode::ParameterProblem(
3784 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3785 );
3786 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3787 },
3788 );
3789 }
3790
3791 #[test]
3792 fn test_error_rate_limit() {
3793 set_logger_for_test();
3794
3795 fn send_icmpv4_ttl_expired_helper(
3797 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3798 ) {
3799 let error = Icmpv4Error::TtlExpired;
3800 core_ctx.send_icmp_error_message(
3801 bindings_ctx,
3802 Some(&FakeDeviceId),
3803 Some(FrameDestination::Individual { local: true }),
3804 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3805 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3806 EmptyBuf,
3807 error,
3808 0,
3809 packet_formats::ip::IpProto::Udp.into(),
3810 &Default::default(),
3811 );
3812 assert_geq!(core_ctx.icmp.tx_counters.time_exceeded.ttl_expired.get(), 1);
3813 }
3814
3815 fn send_icmpv4_parameter_problem_helper(
3817 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3818 ) {
3819 let error = Icmpv4Error::ParameterProblem {
3820 code: Icmpv4ParameterProblemCode::PointerIndicatesError,
3821 pointer: 0,
3822 };
3823 core_ctx.send_icmp_error_message(
3824 bindings_ctx,
3825 Some(&FakeDeviceId),
3826 Some(FrameDestination::Individual { local: true }),
3827 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3828 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3829 EmptyBuf,
3830 error,
3831 0,
3832 packet_formats::ip::IpProto::Udp.into(),
3833 &Default::default(),
3834 );
3835 assert_geq!(
3836 core_ctx.icmp.tx_counters.parameter_problem.pointer_indicates_error.get(),
3837 1
3838 );
3839 }
3840
3841 fn send_icmpv4_dest_unreachable_helper(
3843 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3844 ) {
3845 core_ctx.send_icmp_error_message(
3846 bindings_ctx,
3847 Some(&FakeDeviceId),
3848 Some(FrameDestination::Individual { local: true }),
3849 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3850 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3851 EmptyBuf,
3852 Icmpv4Error::NetUnreachable,
3853 0,
3854 packet_formats::ip::IpProto::Udp.into(),
3855 &Default::default(),
3856 );
3857 assert_geq!(
3858 core_ctx.icmp.tx_counters.dest_unreachable.dest_network_unreachable.get(),
3859 1
3860 );
3861 }
3862
3863 fn send_icmpv6_ttl_expired_helper(
3865 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3866 ) {
3867 core_ctx.send_icmp_error_message(
3868 bindings_ctx,
3869 Some(&FakeDeviceId),
3870 Some(FrameDestination::Individual { local: true }),
3871 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3872 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3873 EmptyBuf,
3874 Icmpv6Error::TtlExpired,
3875 0,
3876 Ipv6Proto::NoNextHeader,
3877 &Default::default(),
3878 );
3879 assert_geq!(core_ctx.icmp.tx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3880 }
3881
3882 fn send_icmpv6_packet_too_big_helper(
3884 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
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 Icmpv6Error::PacketTooBig { mtu: Mtu::new(1280) },
3894 0,
3895 Ipv6Proto::NoNextHeader,
3896 &Default::default(),
3897 );
3898 assert_geq!(core_ctx.icmp.tx_counters.packet_too_big.get(), 1);
3899 }
3900
3901 fn send_icmpv6_parameter_problem_helper(
3903 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3904 ) {
3905 let error = Icmpv6Error::ParameterProblem {
3906 code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
3907 pointer: 0,
3908 allow_dst_multicast: false,
3909 };
3910 core_ctx.send_icmp_error_message(
3911 bindings_ctx,
3912 Some(&FakeDeviceId),
3913 Some(FrameDestination::Individual { local: true }),
3914 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3915 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3916 EmptyBuf,
3917 error,
3918 0,
3919 Ipv6Proto::NoNextHeader,
3920 &Default::default(),
3921 );
3922 assert_geq!(
3923 core_ctx.icmp.tx_counters.parameter_problem.erroneous_header_field.get(),
3924 1
3925 );
3926 }
3927
3928 fn send_icmpv6_dest_unreachable_helper(
3930 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3931 ) {
3932 core_ctx.send_icmp_error_message(
3933 bindings_ctx,
3934 Some(&FakeDeviceId),
3935 Some(FrameDestination::Individual { local: true }),
3936 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3937 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3938 EmptyBuf,
3939 Icmpv6Error::NetUnreachable,
3940 0,
3941 Ipv6Proto::NoNextHeader,
3942 &Default::default(),
3943 );
3944 assert_geq!(core_ctx.icmp.tx_counters.dest_unreachable.no_route.get(), 1);
3945 }
3946
3947 fn run_test<I: IcmpTestIpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
3951 with_errors_per_second: W,
3952 send: S,
3953 ) {
3954 const ERRORS_PER_SECOND: u64 = 64;
3968
3969 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
3970
3971 for i in 0..ERRORS_PER_SECOND {
3972 send(&mut ctx);
3973 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
3974 }
3975
3976 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3977 send(&mut ctx);
3978 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3979
3980 let mut ctx = with_errors_per_second(0);
3984 send(&mut ctx);
3985 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3986 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
3987 send(&mut ctx);
3988 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3989 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
3990 send(&mut ctx);
3991 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3992 }
3993
3994 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
3995 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
3996 }
3997 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
3998 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
3999 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
4000
4001 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
4002 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4003 }
4004
4005 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
4006 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
4007 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
4008 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
4009 }
4010}