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, IpMarked, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr, Ipv6SourceAddr,
18 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(
2512 frame_dst: Option<FrameDestination>,
2513 src_ip: SpecifiedAddr<Ipv4Addr>,
2514 dst_ip: SpecifiedAddr<Ipv4Addr>,
2515) -> bool {
2516 !(dst_ip.is_multicast()
2536 || dst_ip.is_limited_broadcast()
2537 || frame_dst.is_some_and(|dst| dst.is_broadcast())
2538 || src_ip.is_limited_broadcast()
2539 || src_ip.is_multicast()
2540 || src_ip.is_class_e())
2541}
2542
2543fn should_send_icmpv6_error(
2573 frame_dst: Option<FrameDestination>,
2574 src_ip: SpecifiedAddr<Ipv6Addr>,
2575 dst_ip: SpecifiedAddr<Ipv6Addr>,
2576 allow_dst_multicast: bool,
2577) -> bool {
2578 let multicast_frame_dst = match frame_dst {
2581 Some(FrameDestination::Individual { local: _ }) | None => false,
2582 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
2583 };
2584 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
2585 return false;
2586 }
2587 if src_ip.is_multicast() {
2588 return false;
2589 }
2590 true
2591}
2592
2593fn is_icmp_error_or_redirect_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
2605 proto == I::ICMP_IP_PROTO
2606 && peek_message_type::<I::IcmpMessageType>(buf)
2607 .map(IcmpMessageType::is_error_or_redirect)
2608 .unwrap_or(true)
2609}
2610
2611#[cfg(any(test, feature = "testutils"))]
2613pub(crate) mod testutil {
2614 use alloc::vec::Vec;
2615 use net_types::ethernet::Mac;
2616 use net_types::ip::{Ipv6, Ipv6Addr};
2617 use packet::{Buf, InnerPacketBuilder as _, Serializer as _};
2618 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
2619 use packet_formats::icmp::ndp::{
2620 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
2621 };
2622 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
2623 use packet_formats::ip::Ipv6Proto;
2624 use packet_formats::ipv6::Ipv6PacketBuilder;
2625
2626 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
2627
2628 pub fn neighbor_advertisement_ip_packet(
2631 src_ip: Ipv6Addr,
2632 dst_ip: Ipv6Addr,
2633 router_flag: bool,
2634 solicited_flag: bool,
2635 override_flag: bool,
2636 mac: Mac,
2637 ) -> Buf<Vec<u8>> {
2638 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
2639 .into_serializer()
2640 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2641 src_ip,
2642 dst_ip,
2643 IcmpZeroCode,
2644 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
2645 ))
2646 .wrap_in(Ipv6PacketBuilder::new(
2647 src_ip,
2648 dst_ip,
2649 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2650 Ipv6Proto::Icmpv6,
2651 ))
2652 .serialize_vec_outer()
2653 .unwrap()
2654 .unwrap_b()
2655 }
2656
2657 pub fn neighbor_solicitation_ip_packet(
2660 src_ip: Ipv6Addr,
2661 dst_ip: Ipv6Addr,
2662 target_addr: Ipv6Addr,
2663 mac: Mac,
2664 ) -> Buf<Vec<u8>> {
2665 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
2666 .into_serializer()
2667 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2668 src_ip,
2669 dst_ip,
2670 IcmpZeroCode,
2671 NeighborSolicitation::new(target_addr),
2672 ))
2673 .wrap_in(Ipv6PacketBuilder::new(
2674 src_ip,
2675 dst_ip,
2676 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2677 Ipv6Proto::Icmpv6,
2678 ))
2679 .serialize_vec_outer()
2680 .unwrap()
2681 .unwrap_b()
2682 }
2683}
2684
2685#[cfg(test)]
2686mod tests {
2687 use alloc::vec;
2688 use alloc::vec::Vec;
2689 use packet_formats::icmp::ndp::options::NdpNonce;
2690
2691 use core::fmt::Debug;
2692 use core::time::Duration;
2693
2694 use net_types::ip::Subnet;
2695 use netstack3_base::testutil::{
2696 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId,
2697 TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt, set_logger_for_test,
2698 };
2699 use netstack3_base::{CtxPair, Uninstantiable};
2700 use netstack3_filter::TransportPacketSerializer;
2701 use packet::{Buf, EmptyBuf};
2702 use packet_formats::icmp::mld::MldPacket;
2703 use packet_formats::ip::IpProto;
2704 use packet_formats::utils::NonZeroDuration;
2705
2706 use super::*;
2707 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
2708 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
2709 use crate::internal::socket::{
2710 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
2711 };
2712 use crate::socket::RouteResolutionOptions;
2713
2714 use test_util::assert_geq;
2715
2716 pub(super) trait IcmpTestIpExt:
2717 TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt
2718 {
2719 }
2720 impl<I: TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt> IcmpTestIpExt for I {}
2721
2722 type InnerIpSocketCtx<I> = FakeCoreCtx<
2724 FakeIpSocketCtx<I, FakeDeviceId>,
2725 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
2726 FakeDeviceId,
2727 >;
2728
2729 pub(super) struct FakeIcmpCoreCtx<I: IcmpTestIpExt> {
2731 ip_socket_ctx: InnerIpSocketCtx<I>,
2732 icmp: FakeIcmpCoreCtxState<I>,
2733 }
2734
2735 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
2737 (),
2738 RouterAdvertisementEvent<FakeDeviceId>,
2739 FakeIcmpBindingsCtxState<I>,
2740 (),
2741 >;
2742
2743 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
2747
2748 pub(super) struct FakeIcmpCoreCtxState<I: IcmpTestIpExt> {
2749 error_send_bucket: TokenBucket<FakeInstant>,
2750 receive_icmp_error: Vec<I::ErrorCode>,
2751 rx_counters: IcmpRxCounters<I>,
2752 tx_counters: IcmpTxCounters<I>,
2753 ndp_counters: NdpCounters,
2754 }
2755
2756 impl<I: IcmpTestIpExt> FakeIcmpCoreCtx<I> {
2757 fn with_errors_per_second(errors_per_second: u64) -> Self {
2758 Self {
2759 icmp: FakeIcmpCoreCtxState {
2760 error_send_bucket: TokenBucket::new(errors_per_second),
2761 receive_icmp_error: Default::default(),
2762 rx_counters: Default::default(),
2763 tx_counters: Default::default(),
2764 ndp_counters: Default::default(),
2765 },
2766 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
2767 core::iter::once(FakeDeviceConfig {
2768 device: FakeDeviceId,
2769 local_ips: vec![I::TEST_ADDRS.local_ip],
2770 remote_ips: vec![I::TEST_ADDRS.remote_ip],
2771 }),
2772 )),
2773 }
2774 }
2775 }
2776
2777 impl<I: IcmpTestIpExt> Default for FakeIcmpCoreCtx<I> {
2778 fn default() -> Self {
2779 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
2780 }
2781 }
2782
2783 impl<I: IcmpTestIpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
2784 type DeviceId = FakeDeviceId;
2785 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
2786 }
2787
2788 impl<I: IcmpTestIpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
2789 impl<I: IcmpTestIpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
2790
2791 impl<I: IcmpTestIpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
2792 fn counters(&self) -> &IcmpRxCounters<I> {
2793 &self.icmp.rx_counters
2794 }
2795 }
2796
2797 impl<I: IcmpTestIpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
2798 fn counters(&self) -> &IcmpTxCounters<I> {
2799 &self.icmp.tx_counters
2800 }
2801 }
2802
2803 impl<I: IcmpTestIpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
2804 fn counters(&self) -> &NdpCounters {
2805 &self.icmp.ndp_counters
2806 }
2807 }
2808
2809 pub enum FakeEchoIpTransportContext {}
2810
2811 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
2812
2813 impl<I> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
2814 for FakeEchoIpTransportContext
2815 where
2816 I: IcmpTestIpExt + IpLayerIpExt,
2817 {
2818 type EarlyDemuxSocket = Never;
2819
2820 fn early_demux<B: ParseBuffer>(
2821 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2822 _device: &FakeDeviceId,
2823 _src_ip: I::Addr,
2824 _dst_ip: I::Addr,
2825 _buffer: B,
2826 ) -> Option<Self::EarlyDemuxSocket> {
2827 None
2828 }
2829
2830 fn receive_icmp_error(
2831 core_ctx: &mut FakeIcmpCoreCtx<I>,
2832 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2833 _device: &FakeDeviceId,
2834 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2835 _original_dst_ip: SpecifiedAddr<I::Addr>,
2836 _original_body: &[u8],
2837 _err: I::ErrorCode,
2838 ) {
2839 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
2840 }
2841
2842 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
2843 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2844 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2845 _device: &FakeDeviceId,
2846 _src_ip: I::RecvSrcAddr,
2847 _dst_ip: SpecifiedAddr<I::Addr>,
2848 _buffer: B,
2849 _info: &LocalDeliveryPacketInfo<I, H>,
2850 _early_demux_socket: Option<Never>,
2851 ) -> Result<(), (B, I::IcmpError)> {
2852 unimplemented!()
2853 }
2854 }
2855
2856 impl<I: IpLayerIpExt + IcmpTestIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>>
2857 for FakeIcmpCoreCtx<I>
2858 {
2859 type EchoTransportContext = FakeEchoIpTransportContext;
2860
2861 fn receive_icmp_error(
2862 &mut self,
2863 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2864 device: &Self::DeviceId,
2865 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2866 original_dst_ip: SpecifiedAddr<I::Addr>,
2867 original_proto: I::Proto,
2868 original_body: &[u8],
2869 err: I::ErrorCode,
2870 ) {
2871 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
2872 self.icmp.receive_icmp_error.push(err);
2873 if original_proto == I::ICMP_IP_PROTO {
2874 receive_ip_transport_icmp_error(
2875 self,
2876 bindings_ctx,
2877 device,
2878 original_src_ip,
2879 original_dst_ip,
2880 original_body,
2881 err,
2882 )
2883 }
2884 }
2885 }
2886
2887 impl<I: IpLayerIpExt + IcmpTestIpExt> IcmpSendContext<I, FakeIcmpBindingsCtx<I>>
2888 for FakeIcmpCoreCtx<I>
2889 {
2890 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
2891 &mut self,
2892 cb: F,
2893 ) -> O {
2894 cb(&mut self.icmp.error_send_bucket)
2895 }
2896 }
2897
2898 #[test]
2899 fn test_should_send_icmpv4_error() {
2900 let src_ip = TEST_ADDRS_V4.local_ip;
2901 let dst_ip = TEST_ADDRS_V4.remote_ip;
2902 let frame_dst = FrameDestination::Individual { local: true };
2903 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
2904 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
2905
2906 assert!(should_send_icmpv4_error(Some(frame_dst), src_ip, dst_ip));
2908 assert!(should_send_icmpv4_error(None, src_ip, dst_ip));
2909
2910 assert!(should_send_icmpv4_error(
2912 Some(frame_dst),
2913 Ipv4::LOOPBACK_ADDRESS,
2914 Ipv4::LOOPBACK_ADDRESS,
2915 ));
2916
2917 assert!(!should_send_icmpv4_error(
2919 Some(frame_dst),
2920 src_ip,
2921 Ipv4::LIMITED_BROADCAST_ADDRESS,
2922 ));
2923
2924 assert!(!should_send_icmpv4_error(Some(frame_dst), src_ip, multicast_ip_1,));
2926
2927 assert!(!should_send_icmpv4_error(Some(FrameDestination::Broadcast), src_ip, dst_ip,));
2929
2930 assert!(!should_send_icmpv4_error(
2932 Some(frame_dst),
2933 Ipv4::LIMITED_BROADCAST_ADDRESS,
2934 dst_ip,
2935 ));
2936
2937 assert!(!should_send_icmpv4_error(Some(frame_dst), multicast_ip_2, dst_ip));
2939
2940 assert!(!should_send_icmpv4_error(
2942 Some(frame_dst),
2943 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
2944 dst_ip,
2945 ));
2946 }
2947
2948 #[test]
2949 fn test_should_send_icmpv6_error() {
2950 let src_ip = TEST_ADDRS_V6.local_ip;
2951 let dst_ip = TEST_ADDRS_V6.remote_ip;
2952 let frame_dst = FrameDestination::Individual { local: true };
2953 let multicast_ip_1 =
2954 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
2955 let multicast_ip_2 =
2956 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
2957
2958 assert!(should_send_icmpv6_error(
2960 Some(frame_dst),
2961 src_ip,
2962 dst_ip,
2963 false ));
2965 assert!(should_send_icmpv6_error(
2966 None, src_ip, dst_ip, false ));
2968 assert!(should_send_icmpv6_error(
2969 Some(frame_dst),
2970 src_ip,
2971 dst_ip,
2972 true ));
2974
2975 assert!(should_send_icmpv6_error(
2977 Some(frame_dst),
2978 Ipv6::LOOPBACK_ADDRESS,
2979 Ipv6::LOOPBACK_ADDRESS,
2980 false ));
2982 assert!(should_send_icmpv6_error(
2983 Some(frame_dst),
2984 Ipv6::LOOPBACK_ADDRESS,
2985 Ipv6::LOOPBACK_ADDRESS,
2986 true ));
2988
2989 assert!(!should_send_icmpv6_error(
2992 Some(frame_dst),
2993 src_ip,
2994 multicast_ip_1,
2995 false ));
2997 assert!(should_send_icmpv6_error(
2998 Some(frame_dst),
2999 src_ip,
3000 multicast_ip_1,
3001 true ));
3003
3004 assert!(!should_send_icmpv6_error(
3007 Some(FrameDestination::Broadcast),
3008 src_ip,
3009 dst_ip,
3010 false ));
3012 assert!(should_send_icmpv6_error(
3013 Some(FrameDestination::Broadcast),
3014 src_ip,
3015 dst_ip,
3016 true ));
3018
3019 assert!(!should_send_icmpv6_error(
3021 Some(frame_dst),
3022 multicast_ip_2,
3023 dst_ip,
3024 false ));
3026 assert!(!should_send_icmpv6_error(
3027 Some(frame_dst),
3028 multicast_ip_2,
3029 dst_ip,
3030 true ));
3032
3033 assert!(!should_send_icmpv6_error(
3036 Some(FrameDestination::Broadcast),
3037 multicast_ip_2,
3038 dst_ip,
3039 false ));
3041 assert!(!should_send_icmpv6_error(
3042 Some(FrameDestination::Broadcast),
3043 multicast_ip_2,
3044 dst_ip,
3045 true ));
3047 assert!(!should_send_icmpv6_error(
3048 Some(frame_dst),
3049 multicast_ip_2,
3050 multicast_ip_1,
3051 false ));
3053 assert!(!should_send_icmpv6_error(
3054 Some(frame_dst),
3055 multicast_ip_2,
3056 multicast_ip_1,
3057 true ));
3059 }
3060
3061 #[derive(Default)]
3068 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3069 _marker: core::marker::PhantomData<I>,
3070 }
3071
3072 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3073 fn should_send_timestamp_reply(&self) -> bool {
3074 false
3075 }
3076 }
3077 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3078 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3079
3080 impl<I: IcmpTestIpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3081 fn new_ip_socket<O>(
3082 &mut self,
3083 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3084 args: IpSocketArgs<'_, Self::DeviceId, I, O>,
3085 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3086 where
3087 O: RouteResolutionOptions<I>,
3088 {
3089 self.ip_socket_ctx.new_ip_socket(bindings_ctx, args)
3090 }
3091
3092 fn send_ip_packet<S, O>(
3093 &mut self,
3094 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3095 socket: &IpSock<I, Self::WeakDeviceId>,
3096 body: S,
3097 options: &O,
3098 tx_meta: FakeTxMetadata,
3099 ) -> Result<(), IpSockSendError>
3100 where
3101 S: TransportPacketSerializer<I>,
3102 S::Buffer: BufferMut,
3103 O: SendOptions<I> + RouteResolutionOptions<I>,
3104 {
3105 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3106 }
3107
3108 fn confirm_reachable<O>(
3109 &mut self,
3110 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3111 socket: &IpSock<I, Self::WeakDeviceId>,
3112 options: &O,
3113 ) where
3114 O: RouteResolutionOptions<I>,
3115 {
3116 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3117 }
3118 }
3119
3120 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3121 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3122 unimplemented!()
3123 }
3124
3125 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3126 unreachable!()
3127 }
3128
3129 fn handle_received_dad_packet(
3130 &mut self,
3131 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3132 _device_id: &Self::DeviceId,
3133 _addr: SpecifiedAddr<Ipv6Addr>,
3134 _probe_data: Option<NdpNonce<&'_ [u8]>>,
3135 ) -> Option<IpAddressState> {
3136 unimplemented!()
3137 }
3138 }
3139
3140 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3141 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3142 cb(&())
3143 }
3144
3145 fn get_local_addr_for_remote(
3146 &mut self,
3147 _device_id: &Self::DeviceId,
3148 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3149 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3150 unimplemented!()
3151 }
3152
3153 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3154 unimplemented!()
3155 }
3156 }
3157
3158 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3159 fn address_status_for_device(
3160 &mut self,
3161 _addr: SpecifiedAddr<Ipv6Addr>,
3162 _device_id: &Self::DeviceId,
3163 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3164 unimplemented!()
3165 }
3166 }
3167
3168 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3169 type LinkLayerAddr = Uninstantiable;
3170
3171 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3172 unimplemented!()
3173 }
3174
3175 fn set_discovered_retrans_timer(
3176 &mut self,
3177 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3178 _device_id: &Self::DeviceId,
3179 _retrans_timer: NonZeroDuration,
3180 ) {
3181 unimplemented!()
3182 }
3183
3184 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3185 unimplemented!()
3186 }
3187
3188 fn update_discovered_ipv6_route(
3189 &mut self,
3190 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3191 _device_id: &Self::DeviceId,
3192 _route: Ipv6DiscoveredRoute,
3193 _properties: Ipv6DiscoveredRouteProperties,
3194 _lifetime: Option<NonZeroNdpLifetime>,
3195 ) {
3196 unimplemented!()
3197 }
3198
3199 fn apply_slaac_update(
3200 &mut self,
3201 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3202 _device_id: &Self::DeviceId,
3203 _subnet: Subnet<Ipv6Addr>,
3204 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3205 _valid_lifetime: Option<NonZeroNdpLifetime>,
3206 ) {
3207 unimplemented!()
3208 }
3209
3210 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3211 &mut self,
3212 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3213 _device: &FakeDeviceId,
3214 _src_ip: Ipv6SourceAddr,
3215 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3216 _packet: MldPacket<B>,
3217 _header_info: &H,
3218 ) {
3219 unimplemented!()
3220 }
3221 }
3222
3223 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3224 fn send_ip_packet_from_device<S>(
3225 &mut self,
3226 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3227 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3228 _body: S,
3229 ) -> Result<(), IpSendFrameError<S>> {
3230 unimplemented!()
3231 }
3232
3233 fn send_ip_frame<S>(
3234 &mut self,
3235 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3236 _device: &Self::DeviceId,
3237 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3238 _body: S,
3239 ) -> Result<(), IpSendFrameError<S>>
3240 where
3241 S: Serializer,
3242 S::Buffer: BufferMut,
3243 {
3244 unimplemented!()
3245 }
3246 }
3247
3248 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3249 fn handle_neighbor_probe(
3250 &mut self,
3251 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3252 _device_id: &Self::DeviceId,
3253 _neighbor: SpecifiedAddr<Ipv6Addr>,
3254 _link_addr: &[u8],
3255 ) {
3256 unimplemented!()
3257 }
3258
3259 fn handle_neighbor_confirmation(
3260 &mut self,
3261 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3262 _device_id: &Self::DeviceId,
3263 _neighbor: SpecifiedAddr<Ipv6Addr>,
3264 _link_addr: Option<&[u8]>,
3265 _flags: ConfirmationFlags,
3266 ) {
3267 unimplemented!()
3268 }
3269
3270 fn flush_neighbor_table(
3271 &mut self,
3272 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3273 _device_id: &Self::DeviceId,
3274 ) {
3275 unimplemented!()
3276 }
3277 }
3278
3279 #[test]
3280 fn test_receive_icmpv4_error() {
3281 const ICMP_ID: u16 = 0x0F;
3284 const SEQ_NUM: u16 = 0xF0;
3285
3286 fn test_receive_icmpv4_error_helper<
3301 C: Debug,
3302 M: IcmpMessage<Ipv4, Code = C> + Debug,
3303 F: Fn(&FakeIcmpCtx<Ipv4>),
3304 >(
3305 original_packet: &mut [u8],
3306 code: C,
3307 msg: M,
3308 f: F,
3309 ) {
3310 set_logger_for_test();
3311
3312 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3313
3314 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3315 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3316 core_ctx,
3317 bindings_ctx,
3318 &FakeDeviceId,
3319 Ipv4SourceAddr::new(*TEST_ADDRS_V4.remote_ip).unwrap(),
3320 TEST_ADDRS_V4.local_ip,
3321 IcmpPacketBuilder::new(TEST_ADDRS_V4.remote_ip, TEST_ADDRS_V4.local_ip, code, msg)
3322 .wrap_body(Buf::new(original_packet, ..))
3323 .serialize_vec_outer()
3324 .unwrap(),
3325 &LocalDeliveryPacketInfo::default(),
3326 None,
3327 )
3328 .unwrap();
3329 f(&ctx);
3330 }
3331 let mut buffer = EmptyBuf
3344 .wrap_in(IcmpPacketBuilder::<Ipv4, _>::new(
3345 TEST_ADDRS_V4.local_ip,
3346 TEST_ADDRS_V4.remote_ip,
3347 IcmpZeroCode,
3348 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3349 ))
3350 .wrap_in(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3351 TEST_ADDRS_V4.local_ip,
3352 TEST_ADDRS_V4.remote_ip,
3353 64,
3354 Ipv4Proto::Icmp,
3355 ))
3356 .serialize_vec_outer()
3357 .unwrap();
3358
3359 test_receive_icmpv4_error_helper(
3360 buffer.as_mut(),
3361 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3362 IcmpDestUnreachable::default(),
3363 |CtxPair { core_ctx, bindings_ctx: _ }| {
3364 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3365 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3366 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3367 assert_eq!(
3368 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3369 1
3370 );
3371 let err = Icmpv4ErrorCode::DestUnreachable(
3372 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3373 IcmpDestUnreachable::default(),
3374 );
3375 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3376 },
3377 );
3378
3379 test_receive_icmpv4_error_helper(
3380 buffer.as_mut(),
3381 Icmpv4TimeExceededCode::TtlExpired,
3382 IcmpTimeExceeded::default(),
3383 |CtxPair { core_ctx, bindings_ctx: _ }| {
3384 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3385 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3386 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3387 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3388 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3389 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3390 },
3391 );
3392
3393 test_receive_icmpv4_error_helper(
3394 buffer.as_mut(),
3395 Icmpv4ParameterProblemCode::PointerIndicatesError,
3396 Icmpv4ParameterProblem::new(0),
3397 |CtxPair { core_ctx, bindings_ctx: _ }| {
3398 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3399 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3400 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3401 assert_eq!(
3402 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3403 1
3404 );
3405 let err = Icmpv4ErrorCode::ParameterProblem(
3406 Icmpv4ParameterProblemCode::PointerIndicatesError,
3407 );
3408 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3409 },
3410 );
3411
3412 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3419 TEST_ADDRS_V4.local_ip,
3420 TEST_ADDRS_V4.remote_ip,
3421 64,
3422 Ipv4Proto::Icmp,
3423 )
3424 .wrap_body(EmptyBuf)
3425 .serialize_vec_outer()
3426 .unwrap();
3427
3428 test_receive_icmpv4_error_helper(
3429 buffer.as_mut(),
3430 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3431 IcmpDestUnreachable::default(),
3432 |CtxPair { core_ctx, bindings_ctx: _ }| {
3433 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3434 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3435 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3436 assert_eq!(
3437 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3438 1
3439 );
3440 let err = Icmpv4ErrorCode::DestUnreachable(
3441 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3442 IcmpDestUnreachable::default(),
3443 );
3444 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3445 },
3446 );
3447
3448 test_receive_icmpv4_error_helper(
3449 buffer.as_mut(),
3450 Icmpv4TimeExceededCode::TtlExpired,
3451 IcmpTimeExceeded::default(),
3452 |CtxPair { core_ctx, bindings_ctx: _ }| {
3453 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3454 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3455 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3456 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3457 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3458 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3459 },
3460 );
3461
3462 test_receive_icmpv4_error_helper(
3463 buffer.as_mut(),
3464 Icmpv4ParameterProblemCode::PointerIndicatesError,
3465 Icmpv4ParameterProblem::new(0),
3466 |CtxPair { core_ctx, bindings_ctx: _ }| {
3467 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3468 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3469 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3470 assert_eq!(
3471 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3472 1
3473 );
3474 let err = Icmpv4ErrorCode::ParameterProblem(
3475 Icmpv4ParameterProblemCode::PointerIndicatesError,
3476 );
3477 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3478 },
3479 );
3480
3481 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::new(
3487 TEST_ADDRS_V4.local_ip,
3488 TEST_ADDRS_V4.remote_ip,
3489 64,
3490 IpProto::Udp.into(),
3491 )
3492 .wrap_body(EmptyBuf)
3493 .serialize_vec_outer()
3494 .unwrap();
3495
3496 test_receive_icmpv4_error_helper(
3497 buffer.as_mut(),
3498 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3499 IcmpDestUnreachable::default(),
3500 |CtxPair { core_ctx, bindings_ctx: _ }| {
3501 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3502 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3503 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3504 assert_eq!(
3505 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3506 1
3507 );
3508 let err = Icmpv4ErrorCode::DestUnreachable(
3509 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3510 IcmpDestUnreachable::default(),
3511 );
3512 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3513 },
3514 );
3515
3516 test_receive_icmpv4_error_helper(
3517 buffer.as_mut(),
3518 Icmpv4TimeExceededCode::TtlExpired,
3519 IcmpTimeExceeded::default(),
3520 |CtxPair { core_ctx, bindings_ctx: _ }| {
3521 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3522 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3523 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3524 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3525 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3526 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3527 },
3528 );
3529
3530 test_receive_icmpv4_error_helper(
3531 buffer.as_mut(),
3532 Icmpv4ParameterProblemCode::PointerIndicatesError,
3533 Icmpv4ParameterProblem::new(0),
3534 |CtxPair { core_ctx, bindings_ctx: _ }| {
3535 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3536 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3537 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3538 assert_eq!(
3539 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3540 1
3541 );
3542 let err = Icmpv4ErrorCode::ParameterProblem(
3543 Icmpv4ParameterProblemCode::PointerIndicatesError,
3544 );
3545 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3546 },
3547 );
3548 }
3549
3550 #[test]
3551 fn test_receive_icmpv6_error() {
3552 const ICMP_ID: u16 = 0x0F;
3555 const SEQ_NUM: u16 = 0xF0;
3556
3557 fn test_receive_icmpv6_error_helper<
3572 C: Debug,
3573 M: IcmpMessage<Ipv6, Code = C> + Debug,
3574 F: Fn(&FakeIcmpCtx<Ipv6>),
3575 >(
3576 original_packet: &mut [u8],
3577 code: C,
3578 msg: M,
3579 f: F,
3580 ) {
3581 set_logger_for_test();
3582
3583 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
3584 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3585 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
3586 core_ctx,
3587 bindings_ctx,
3588 &FakeDeviceId,
3589 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
3590 TEST_ADDRS_V6.local_ip,
3591 IcmpPacketBuilder::new(TEST_ADDRS_V6.remote_ip, TEST_ADDRS_V6.local_ip, code, msg)
3592 .wrap_body(Buf::new(original_packet, ..))
3593 .serialize_vec_outer()
3594 .unwrap(),
3595 &LocalDeliveryPacketInfo::default(),
3596 None,
3597 )
3598 .unwrap();
3599 f(&ctx);
3600 }
3601 let mut buffer = EmptyBuf
3614 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3615 TEST_ADDRS_V6.local_ip,
3616 TEST_ADDRS_V6.remote_ip,
3617 IcmpZeroCode,
3618 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3619 ))
3620 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3621 TEST_ADDRS_V6.local_ip,
3622 TEST_ADDRS_V6.remote_ip,
3623 64,
3624 Ipv6Proto::Icmpv6,
3625 ))
3626 .serialize_vec_outer()
3627 .unwrap();
3628
3629 test_receive_icmpv6_error_helper(
3630 buffer.as_mut(),
3631 Icmpv6DestUnreachableCode::NoRoute,
3632 IcmpDestUnreachable::default(),
3633 |CtxPair { core_ctx, bindings_ctx: _ }| {
3634 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3635 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3636 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3637 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3638 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3639 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3640 },
3641 );
3642
3643 test_receive_icmpv6_error_helper(
3644 buffer.as_mut(),
3645 Icmpv6TimeExceededCode::HopLimitExceeded,
3646 IcmpTimeExceeded::default(),
3647 |CtxPair { core_ctx, bindings_ctx: _ }| {
3648 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3649 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3650 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3651 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3652 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3653 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3654 },
3655 );
3656
3657 test_receive_icmpv6_error_helper(
3658 buffer.as_mut(),
3659 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3660 Icmpv6ParameterProblem::new(0),
3661 |CtxPair { core_ctx, bindings_ctx: _ }| {
3662 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3663 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3664 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3665 assert_eq!(
3666 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3667 1
3668 );
3669 let err = Icmpv6ErrorCode::ParameterProblem(
3670 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3671 );
3672 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3673 },
3674 );
3675
3676 let mut buffer = EmptyBuf
3683 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3684 TEST_ADDRS_V6.local_ip,
3685 TEST_ADDRS_V6.remote_ip,
3686 64,
3687 Ipv6Proto::Icmpv6,
3688 ))
3689 .serialize_vec_outer()
3690 .unwrap();
3691
3692 test_receive_icmpv6_error_helper(
3693 buffer.as_mut(),
3694 Icmpv6DestUnreachableCode::NoRoute,
3695 IcmpDestUnreachable::default(),
3696 |CtxPair { core_ctx, bindings_ctx: _ }| {
3697 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3698 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3699 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3700 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3701 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3702 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3703 },
3704 );
3705
3706 test_receive_icmpv6_error_helper(
3707 buffer.as_mut(),
3708 Icmpv6TimeExceededCode::HopLimitExceeded,
3709 IcmpTimeExceeded::default(),
3710 |CtxPair { core_ctx, bindings_ctx: _ }| {
3711 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3712 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3713 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3714 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3715 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3716 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3717 },
3718 );
3719
3720 test_receive_icmpv6_error_helper(
3721 buffer.as_mut(),
3722 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3723 Icmpv6ParameterProblem::new(0),
3724 |CtxPair { core_ctx, bindings_ctx: _ }| {
3725 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3726 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3727 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3728 assert_eq!(
3729 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3730 1
3731 );
3732 let err = Icmpv6ErrorCode::ParameterProblem(
3733 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3734 );
3735 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3736 },
3737 );
3738
3739 let mut buffer = <Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::new(
3745 TEST_ADDRS_V6.local_ip,
3746 TEST_ADDRS_V6.remote_ip,
3747 64,
3748 IpProto::Udp.into(),
3749 )
3750 .wrap_body(EmptyBuf)
3751 .serialize_vec_outer()
3752 .unwrap();
3753
3754 test_receive_icmpv6_error_helper(
3755 buffer.as_mut(),
3756 Icmpv6DestUnreachableCode::NoRoute,
3757 IcmpDestUnreachable::default(),
3758 |CtxPair { core_ctx, bindings_ctx: _ }| {
3759 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3760 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3761 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3762 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3763 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3764 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3765 },
3766 );
3767
3768 test_receive_icmpv6_error_helper(
3769 buffer.as_mut(),
3770 Icmpv6TimeExceededCode::HopLimitExceeded,
3771 IcmpTimeExceeded::default(),
3772 |CtxPair { core_ctx, bindings_ctx: _ }| {
3773 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3774 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3775 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3776 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3777 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3778 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3779 },
3780 );
3781
3782 test_receive_icmpv6_error_helper(
3783 buffer.as_mut(),
3784 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3785 Icmpv6ParameterProblem::new(0),
3786 |CtxPair { core_ctx, bindings_ctx: _ }| {
3787 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3788 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3789 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3790 assert_eq!(
3791 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3792 1
3793 );
3794 let err = Icmpv6ErrorCode::ParameterProblem(
3795 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3796 );
3797 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3798 },
3799 );
3800 }
3801
3802 #[test]
3803 fn test_error_rate_limit() {
3804 set_logger_for_test();
3805
3806 fn send_icmpv4_ttl_expired_helper(
3808 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3809 ) {
3810 let error = Icmpv4Error::TtlExpired;
3811 core_ctx.send_icmp_error_message(
3812 bindings_ctx,
3813 Some(&FakeDeviceId),
3814 Some(FrameDestination::Individual { local: true }),
3815 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3816 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3817 EmptyBuf,
3818 error,
3819 0,
3820 packet_formats::ip::IpProto::Udp.into(),
3821 &Default::default(),
3822 );
3823 assert_geq!(core_ctx.icmp.tx_counters.time_exceeded.ttl_expired.get(), 1);
3824 }
3825
3826 fn send_icmpv4_parameter_problem_helper(
3828 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3829 ) {
3830 let error = Icmpv4Error::ParameterProblem {
3831 code: Icmpv4ParameterProblemCode::PointerIndicatesError,
3832 pointer: 0,
3833 };
3834 core_ctx.send_icmp_error_message(
3835 bindings_ctx,
3836 Some(&FakeDeviceId),
3837 Some(FrameDestination::Individual { local: true }),
3838 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3839 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3840 EmptyBuf,
3841 error,
3842 0,
3843 packet_formats::ip::IpProto::Udp.into(),
3844 &Default::default(),
3845 );
3846 assert_geq!(
3847 core_ctx.icmp.tx_counters.parameter_problem.pointer_indicates_error.get(),
3848 1
3849 );
3850 }
3851
3852 fn send_icmpv4_dest_unreachable_helper(
3854 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3855 ) {
3856 core_ctx.send_icmp_error_message(
3857 bindings_ctx,
3858 Some(&FakeDeviceId),
3859 Some(FrameDestination::Individual { local: true }),
3860 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3861 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3862 EmptyBuf,
3863 Icmpv4Error::NetUnreachable,
3864 0,
3865 packet_formats::ip::IpProto::Udp.into(),
3866 &Default::default(),
3867 );
3868 assert_geq!(
3869 core_ctx.icmp.tx_counters.dest_unreachable.dest_network_unreachable.get(),
3870 1
3871 );
3872 }
3873
3874 fn send_icmpv6_ttl_expired_helper(
3876 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3877 ) {
3878 core_ctx.send_icmp_error_message(
3879 bindings_ctx,
3880 Some(&FakeDeviceId),
3881 Some(FrameDestination::Individual { local: true }),
3882 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3883 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3884 EmptyBuf,
3885 Icmpv6Error::TtlExpired,
3886 0,
3887 Ipv6Proto::NoNextHeader,
3888 &Default::default(),
3889 );
3890 assert_geq!(core_ctx.icmp.tx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3891 }
3892
3893 fn send_icmpv6_packet_too_big_helper(
3895 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3896 ) {
3897 core_ctx.send_icmp_error_message(
3898 bindings_ctx,
3899 Some(&FakeDeviceId),
3900 Some(FrameDestination::Individual { local: true }),
3901 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3902 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3903 EmptyBuf,
3904 Icmpv6Error::PacketTooBig { mtu: Mtu::new(1280) },
3905 0,
3906 Ipv6Proto::NoNextHeader,
3907 &Default::default(),
3908 );
3909 assert_geq!(core_ctx.icmp.tx_counters.packet_too_big.get(), 1);
3910 }
3911
3912 fn send_icmpv6_parameter_problem_helper(
3914 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3915 ) {
3916 let error = Icmpv6Error::ParameterProblem {
3917 code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
3918 pointer: 0,
3919 allow_dst_multicast: false,
3920 };
3921 core_ctx.send_icmp_error_message(
3922 bindings_ctx,
3923 Some(&FakeDeviceId),
3924 Some(FrameDestination::Individual { local: true }),
3925 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3926 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3927 EmptyBuf,
3928 error,
3929 0,
3930 Ipv6Proto::NoNextHeader,
3931 &Default::default(),
3932 );
3933 assert_geq!(
3934 core_ctx.icmp.tx_counters.parameter_problem.erroneous_header_field.get(),
3935 1
3936 );
3937 }
3938
3939 fn send_icmpv6_dest_unreachable_helper(
3941 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3942 ) {
3943 core_ctx.send_icmp_error_message(
3944 bindings_ctx,
3945 Some(&FakeDeviceId),
3946 Some(FrameDestination::Individual { local: true }),
3947 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3948 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3949 EmptyBuf,
3950 Icmpv6Error::NetUnreachable,
3951 0,
3952 Ipv6Proto::NoNextHeader,
3953 &Default::default(),
3954 );
3955 assert_geq!(core_ctx.icmp.tx_counters.dest_unreachable.no_route.get(), 1);
3956 }
3957
3958 fn run_test<I: IcmpTestIpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
3962 with_errors_per_second: W,
3963 send: S,
3964 ) {
3965 const ERRORS_PER_SECOND: u64 = 64;
3979
3980 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
3981
3982 for i in 0..ERRORS_PER_SECOND {
3983 send(&mut ctx);
3984 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
3985 }
3986
3987 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3988 send(&mut ctx);
3989 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3990
3991 let mut ctx = with_errors_per_second(0);
3995 send(&mut ctx);
3996 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3997 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
3998 send(&mut ctx);
3999 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4000 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4001 send(&mut ctx);
4002 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4003 }
4004
4005 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
4006 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4007 }
4008 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
4009 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
4010 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
4011
4012 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
4013 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4014 }
4015
4016 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
4017 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
4018 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
4019 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
4020 }
4021}