1pub mod counters;
8
9use alloc::boxed::Box;
10use core::fmt::Debug;
11use core::num::{NonZeroU8, NonZeroU16};
12
13use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
14use log::{debug, error, trace};
15use net_types::ip::{
16 GenericOverIp, Ip, IpMarked, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6, Ipv6Addr, Ipv6SourceAddr,
17 Mtu, SubnetError,
18};
19use net_types::{
20 LinkLocalAddress, LinkLocalUnicastAddr, MulticastAddr, MulticastAddress, SpecifiedAddr,
21 UnicastAddr, Witness,
22};
23use netstack3_base::socket::{AddrIsMappedError, SocketIpAddr, SocketIpAddrExt as _};
24use netstack3_base::sync::Mutex;
25use netstack3_base::{
26 AnyDevice, Counter, CounterContext, DeviceIdContext, EitherDeviceId, FrameDestination,
27 IcmpIpExt, Icmpv4ErrorCode, Icmpv6ErrorCode, InstantBindingsTypes, InstantContext,
28 IpDeviceAddr, IpExt, LocalFrameDestination, Marks, NetworkPartialSerializer, NetworkSerializer,
29 RngContext, TokenBucket, TxMetadataBindingsTypes,
30};
31use netstack3_filter::{DynTransportSerializer, DynamicTransportSerializer, FilterIpExt};
32use packet::{
33 BufferMut, InnerPacketBuilder as _, NestablePacketBuilder as _, ParsablePacket as _,
34 ParseBuffer, 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
349 }
350}
351
352impl<I: IcmpHandlerIpExt> GenericOverIp<I> for Icmpv4Error {
353 type Type = I::IcmpError;
354}
355
356enum Icmpv4ErrorMessage {
359 TimeExceeded {
360 message: IcmpTimeExceeded,
361 code: <IcmpTimeExceeded as IcmpMessage<Ipv4>>::Code,
362 },
363 ParameterProblem {
364 message: Icmpv4ParameterProblem,
365 code: <Icmpv4ParameterProblem as IcmpMessage<Ipv4>>::Code,
366 },
367 DestUnreachable {
368 message: IcmpDestUnreachable,
369 code: <IcmpDestUnreachable as IcmpMessage<Ipv4>>::Code,
370 },
371}
372
373impl Icmpv4Error {
374 fn update_counters(&self, counters: &IcmpTxCounters<Ipv4>) {
375 match self {
376 Icmpv4Error::ParameterProblem { code, pointer: _ } => {
377 counters.parameter_problem.increment_code(*code);
378 }
379 Icmpv4Error::TtlExpired => {
380 counters.time_exceeded.increment_code(Icmpv4TimeExceededCode::TtlExpired);
381 }
382 Icmpv4Error::NetUnreachable => {
383 counters
384 .dest_unreachable
385 .increment_code(Icmpv4DestUnreachableCode::DestNetworkUnreachable);
386 }
387 Icmpv4Error::ProtocolUnreachable => {
388 counters
389 .dest_unreachable
390 .increment_code(Icmpv4DestUnreachableCode::DestProtocolUnreachable);
391 }
392 Icmpv4Error::PortUnreachable => {
393 counters
394 .dest_unreachable
395 .increment_code(Icmpv4DestUnreachableCode::DestPortUnreachable);
396 }
397 Icmpv4Error::HostUnreachable => {
398 counters
399 .dest_unreachable
400 .increment_code(Icmpv4DestUnreachableCode::DestHostUnreachable);
401 }
402 Icmpv4Error::NetworkProhibited => {
403 counters
404 .dest_unreachable
405 .increment_code(Icmpv4DestUnreachableCode::NetworkAdministrativelyProhibited);
406 }
407 Icmpv4Error::HostProhibited => {
408 counters
409 .dest_unreachable
410 .increment_code(Icmpv4DestUnreachableCode::HostAdministrativelyProhibited);
411 }
412 Icmpv4Error::AdminProhibited => {
413 counters
414 .dest_unreachable
415 .increment_code(Icmpv4DestUnreachableCode::CommAdministrativelyProhibited);
416 }
417 }
418 }
419
420 fn create_message(&self) -> Icmpv4ErrorMessage {
421 match self {
422 Icmpv4Error::ParameterProblem { code, pointer } => {
423 Icmpv4ErrorMessage::ParameterProblem {
424 message: Icmpv4ParameterProblem::new(*pointer),
425 code: *code,
426 }
427 }
428 Icmpv4Error::TtlExpired => Icmpv4ErrorMessage::TimeExceeded {
429 message: IcmpTimeExceeded::default(),
430 code: Icmpv4TimeExceededCode::TtlExpired,
431 },
432 Icmpv4Error::NetUnreachable => Icmpv4ErrorMessage::DestUnreachable {
433 message: IcmpDestUnreachable::default(),
434 code: Icmpv4DestUnreachableCode::DestNetworkUnreachable,
435 },
436 Icmpv4Error::ProtocolUnreachable => Icmpv4ErrorMessage::DestUnreachable {
437 message: IcmpDestUnreachable::default(),
438 code: Icmpv4DestUnreachableCode::DestProtocolUnreachable,
439 },
440 Icmpv4Error::PortUnreachable => Icmpv4ErrorMessage::DestUnreachable {
441 message: IcmpDestUnreachable::default(),
442 code: Icmpv4DestUnreachableCode::DestPortUnreachable,
443 },
444 Icmpv4Error::HostUnreachable => Icmpv4ErrorMessage::DestUnreachable {
445 message: IcmpDestUnreachable::default(),
446 code: Icmpv4DestUnreachableCode::DestHostUnreachable,
447 },
448 Icmpv4Error::NetworkProhibited => Icmpv4ErrorMessage::DestUnreachable {
449 message: IcmpDestUnreachable::default(),
450 code: Icmpv4DestUnreachableCode::NetworkAdministrativelyProhibited,
451 },
452 Icmpv4Error::HostProhibited => Icmpv4ErrorMessage::DestUnreachable {
453 message: IcmpDestUnreachable::default(),
454 code: Icmpv4DestUnreachableCode::HostAdministrativelyProhibited,
455 },
456 Icmpv4Error::AdminProhibited => Icmpv4ErrorMessage::DestUnreachable {
457 message: IcmpDestUnreachable::default(),
458 code: Icmpv4DestUnreachableCode::CommAdministrativelyProhibited,
459 },
460 }
461 }
462}
463
464impl<I: IcmpHandlerIpExt> GenericOverIp<I> for Icmpv6Error {
465 type Type = I::IcmpError;
466}
467
468#[derive(Debug, PartialEq, Eq)]
470pub enum Icmpv6Error {
471 ParameterProblem {
473 code: Icmpv6ParameterProblemCode,
475 pointer: u32,
477 allow_dst_multicast: bool,
479 },
480 TtlExpired,
482 NetUnreachable,
484 PacketTooBig {
486 mtu: Mtu,
488 },
489 PortUnreachable,
491 AddressUnreachable,
493 RejectRoute,
495 SourceAddressPolicyFailed,
497 AdminProhibited,
499}
500
501impl IcmpError for Icmpv6Error {
502 fn port_unreachable() -> Self {
503 Icmpv6Error::PortUnreachable
504 }
505 fn ttl_expired() -> Self {
506 Icmpv6Error::TtlExpired
507 }
508 fn mtu_exceeded(mtu: Mtu) -> Option<Self> {
509 Some(Icmpv6Error::PacketTooBig { mtu })
510 }
511}
512
513enum Icmpv6ErrorMessage {
516 TimeExceeded {
517 message: IcmpTimeExceeded,
518 code: <IcmpTimeExceeded as IcmpMessage<Ipv6>>::Code,
519 },
520 PacketTooBig {
521 message: Icmpv6PacketTooBig,
522 code: <Icmpv6PacketTooBig as IcmpMessage<Ipv6>>::Code,
523 },
524 ParameterProblem {
525 message: Icmpv6ParameterProblem,
526 code: <Icmpv6ParameterProblem as IcmpMessage<Ipv6>>::Code,
527 },
528 DestUnreachable {
529 message: IcmpDestUnreachable,
530 code: <IcmpDestUnreachable as IcmpMessage<Ipv6>>::Code,
531 },
532}
533
534impl Icmpv6Error {
535 fn update_counters(&self, counters: &IcmpTxCounters<Ipv6>) {
536 match self {
537 Icmpv6Error::ParameterProblem { code, pointer: _, allow_dst_multicast: _ } => {
538 counters.parameter_problem.increment_code(*code);
539 }
540 Icmpv6Error::TtlExpired => {
541 counters.time_exceeded.increment_code(Icmpv6TimeExceededCode::HopLimitExceeded);
542 }
543 Icmpv6Error::NetUnreachable => {
544 counters.dest_unreachable.increment_code(Icmpv6DestUnreachableCode::NoRoute);
545 }
546 Icmpv6Error::PacketTooBig { mtu: _ } => {
547 counters.packet_too_big.increment();
548 }
549 Icmpv6Error::PortUnreachable => {
550 counters
551 .dest_unreachable
552 .increment_code(Icmpv6DestUnreachableCode::PortUnreachable);
553 }
554 Icmpv6Error::AddressUnreachable => {
555 counters
556 .dest_unreachable
557 .increment_code(Icmpv6DestUnreachableCode::AddrUnreachable);
558 }
559 Icmpv6Error::RejectRoute => {
560 counters.dest_unreachable.increment_code(Icmpv6DestUnreachableCode::RejectRoute);
561 }
562 Icmpv6Error::SourceAddressPolicyFailed => {
563 counters
564 .dest_unreachable
565 .increment_code(Icmpv6DestUnreachableCode::SrcAddrFailedPolicy);
566 }
567 Icmpv6Error::AdminProhibited => {
568 counters
569 .dest_unreachable
570 .increment_code(Icmpv6DestUnreachableCode::CommAdministrativelyProhibited);
571 }
572 }
573 }
574
575 fn create_message(&self) -> Icmpv6ErrorMessage {
576 match self {
577 Icmpv6Error::ParameterProblem { code, pointer, allow_dst_multicast: _ } => {
578 Icmpv6ErrorMessage::ParameterProblem {
579 message: Icmpv6ParameterProblem::new(*pointer),
580 code: *code,
581 }
582 }
583 Icmpv6Error::TtlExpired => Icmpv6ErrorMessage::TimeExceeded {
584 message: IcmpTimeExceeded::default(),
585 code: Icmpv6TimeExceededCode::HopLimitExceeded,
586 },
587 Icmpv6Error::NetUnreachable => Icmpv6ErrorMessage::DestUnreachable {
588 message: IcmpDestUnreachable::default(),
589 code: Icmpv6DestUnreachableCode::NoRoute,
590 },
591 Icmpv6Error::PacketTooBig { mtu } => Icmpv6ErrorMessage::PacketTooBig {
592 message: Icmpv6PacketTooBig::new((*mtu).into()),
593 code: IcmpZeroCode,
594 },
595 Icmpv6Error::PortUnreachable => Icmpv6ErrorMessage::DestUnreachable {
596 message: IcmpDestUnreachable::default(),
597 code: Icmpv6DestUnreachableCode::PortUnreachable,
598 },
599 Icmpv6Error::AddressUnreachable => Icmpv6ErrorMessage::DestUnreachable {
600 message: IcmpDestUnreachable::default(),
601 code: Icmpv6DestUnreachableCode::AddrUnreachable,
602 },
603 Icmpv6Error::RejectRoute => Icmpv6ErrorMessage::DestUnreachable {
604 message: IcmpDestUnreachable::default(),
605 code: Icmpv6DestUnreachableCode::RejectRoute,
606 },
607 Icmpv6Error::SourceAddressPolicyFailed => Icmpv6ErrorMessage::DestUnreachable {
608 message: IcmpDestUnreachable::default(),
609 code: Icmpv6DestUnreachableCode::SrcAddrFailedPolicy,
610 },
611 Icmpv6Error::AdminProhibited => Icmpv6ErrorMessage::DestUnreachable {
612 message: IcmpDestUnreachable::default(),
613 code: Icmpv6DestUnreachableCode::CommAdministrativelyProhibited,
614 },
615 }
616 }
617
618 fn allow_dst_multicast(&self) -> bool {
619 match self {
632 Icmpv6Error::ParameterProblem { allow_dst_multicast, code, pointer: _ } => {
633 assert!(
634 !allow_dst_multicast
635 || *code == Icmpv6ParameterProblemCode::UnrecognizedIpv6Option
636 );
637 *allow_dst_multicast
638 }
639 Icmpv6Error::PacketTooBig { .. } => true,
640 _ => false,
641 }
642 }
643}
644
645pub trait IcmpErrorHandler<I: IcmpHandlerIpExt, BC>: DeviceIdContext<AnyDevice> {
647 fn send_icmp_error_message<B: BufferMut>(
654 &mut self,
655 bindings_ctx: &mut BC,
656 device: Option<&Self::DeviceId>,
657 frame_dst: Option<LocalFrameDestination>,
658 src_ip: SocketIpAddr<I::Addr>,
659 dst_ip: SocketIpAddr<I::Addr>,
660 original_packet: B,
661 error: I::IcmpError,
662 header_len: usize,
663 proto: I::Proto,
664 marks: &Marks,
665 );
666}
667
668impl<BC: IcmpBindingsContext, CC: IcmpSendContext<Ipv4, BC> + CounterContext<IcmpTxCounters<Ipv4>>>
669 IcmpErrorHandler<Ipv4, BC> for CC
670{
671 fn send_icmp_error_message<B: BufferMut>(
672 &mut self,
673 bindings_ctx: &mut BC,
674 device: Option<&CC::DeviceId>,
675 frame_dst: Option<LocalFrameDestination>,
676 src_ip: SocketIpAddr<Ipv4Addr>,
677 dst_ip: SocketIpAddr<Ipv4Addr>,
678 original_packet: B,
679 icmp_error: Icmpv4Error,
680 header_len: usize,
681 proto: Ipv4Proto,
682 marks: &Marks,
683 ) {
684 if is_icmp_error_or_redirect_message::<Ipv4>(proto, &original_packet.as_ref()[header_len..])
687 {
688 return;
689 }
690
691 icmp_error.update_counters(&self.counters());
692 send_icmpv4_error_message(
693 self,
694 bindings_ctx,
695 device,
696 frame_dst,
697 src_ip,
698 dst_ip,
699 icmp_error.create_message(),
700 original_packet,
701 header_len,
702 marks,
703 );
704 }
705}
706
707impl<BC: IcmpBindingsContext, CC: IcmpSendContext<Ipv6, BC> + CounterContext<IcmpTxCounters<Ipv6>>>
708 IcmpErrorHandler<Ipv6, BC> for CC
709{
710 fn send_icmp_error_message<B: BufferMut>(
711 &mut self,
712 bindings_ctx: &mut BC,
713 device: Option<&CC::DeviceId>,
714 frame_dst: Option<LocalFrameDestination>,
715 src_ip: SocketIpAddr<Ipv6Addr>,
716 dst_ip: SocketIpAddr<Ipv6Addr>,
717 original_packet: B,
718 error: Icmpv6Error,
719 header_len: usize,
720 proto: Ipv6Proto,
721 marks: &Marks,
722 ) {
723 if is_icmp_error_or_redirect_message::<Ipv6>(proto, &original_packet.as_ref()[header_len..])
726 {
727 return;
728 }
729
730 error.update_counters(&self.counters());
731 send_icmpv6_error_message(
732 self,
733 bindings_ctx,
734 device,
735 frame_dst,
736 src_ip,
737 dst_ip,
738 error.create_message(),
739 original_packet,
740 error.allow_dst_multicast(),
741 marks,
742 )
743 }
744}
745
746pub trait IcmpBindingsContext: InstantContext + RngContext + IcmpBindingsTypes {}
749impl<BC> IcmpBindingsContext for BC where
750 BC: InstantContext + RngContext + IcmpBindingsTypes + IcmpBindingsTypes
751{
752}
753
754pub trait IcmpBindingsTypes: InstantBindingsTypes + TxMetadataBindingsTypes {}
756impl<BT: InstantBindingsTypes + TxMetadataBindingsTypes> IcmpBindingsTypes for BT {}
757
758pub trait IcmpStateContext {}
766
767pub trait EchoTransportContextMarker {}
777
778pub trait InnerIcmpContext<I, BC>: IpSocketHandler<I, BC>
781where
782 I: IpLayerIpExt,
783 BC: IcmpBindingsTypes,
784{
785 type EchoTransportContext: IpTransportContext<I, BC, Self> + EchoTransportContextMarker;
788
789 fn receive_icmp_error(
819 &mut self,
820 bindings_ctx: &mut BC,
821 device: &Self::DeviceId,
822 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
823 original_dst_ip: SpecifiedAddr<I::Addr>,
824 original_proto: I::Proto,
825 original_body: &[u8],
826 err: I::ErrorCode,
827 );
828}
829
830pub trait InnerIcmpv4Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv4, BC> {
834 fn should_send_timestamp_reply(&self) -> bool;
836}
837
838pub trait IcmpSendContext<I, BC>: IpSocketHandler<I, BC>
840where
841 I: IpLayerIpExt,
842 BC: IcmpBindingsTypes,
843{
844 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
847 &mut self,
848 cb: F,
849 ) -> O;
850}
851
852macro_rules! try_send_error {
866 ($core_ctx:expr, $bindings_ctx:expr, $e:expr) => {{
867 let send = $core_ctx.with_error_send_bucket_mut(|error_send_bucket| {
868 error_send_bucket.try_take($bindings_ctx)
869 });
870
871 if send {
872 $core_ctx.counters().error.increment();
873 $e
874 } else {
875 trace!("ip::icmp::try_send_error!: dropping rate-limited ICMP error message");
876 Ok(())
877 }
878 }};
879}
880
881pub enum IcmpIpTransportContext {}
883
884fn receive_ip_transport_icmp_error<
885 I: IpLayerIpExt,
886 CC: InnerIcmpContext<I, BC> + CounterContext<IcmpRxCounters<I>>,
887 BC: IcmpBindingsContext,
888>(
889 core_ctx: &mut CC,
890 bindings_ctx: &mut BC,
891 device: &CC::DeviceId,
892 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
893 original_dst_ip: SpecifiedAddr<I::Addr>,
894 original_body: &[u8],
895 err: I::ErrorCode,
896) {
897 core_ctx.counters().error_delivered_to_transport_layer.increment();
898 trace!("IcmpIpTransportContext::receive_icmp_error({:?})", err);
899
900 let mut parse_body = original_body;
901 match parse_body.parse::<IcmpPacketRaw<I, _, IcmpEchoRequest>>() {
902 Ok(_echo_request) => (),
905 Err(_) => {
906 return;
910 }
911 }
912
913 <CC::EchoTransportContext as IpTransportContext<I, BC, CC>>::receive_icmp_error(
914 core_ctx,
915 bindings_ctx,
916 device,
917 original_src_ip,
918 original_dst_ip,
919 original_body,
920 err,
921 );
922}
923
924impl<
925 BC: IcmpBindingsContext,
926 CC: InnerIcmpv4Context<BC>
927 + PmtuHandler<Ipv4, BC>
928 + CounterContext<IcmpRxCounters<Ipv4>>
929 + CounterContext<IcmpTxCounters<Ipv4>>,
930> IpTransportContext<Ipv4, BC, CC> for IcmpIpTransportContext
931{
932 type EarlyDemuxSocket = !;
933
934 fn early_demux<B: ParseBuffer>(
935 _core_ctx: &mut CC,
936 _device: &CC::DeviceId,
937 _src_ip: Ipv4Addr,
938 _dst_ip: Ipv4Addr,
939 _buffer: B,
940 ) -> Option<Self::EarlyDemuxSocket> {
941 None
942 }
943
944 fn receive_icmp_error(
945 core_ctx: &mut CC,
946 bindings_ctx: &mut BC,
947 device: &CC::DeviceId,
948 original_src_ip: Option<SpecifiedAddr<Ipv4Addr>>,
949 original_dst_ip: SpecifiedAddr<Ipv4Addr>,
950 original_body: &[u8],
951 err: Icmpv4ErrorCode,
952 ) {
953 receive_ip_transport_icmp_error(
954 core_ctx,
955 bindings_ctx,
956 device,
957 original_src_ip,
958 original_dst_ip,
959 original_body,
960 err,
961 )
962 }
963
964 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv4>>(
965 core_ctx: &mut CC,
966 bindings_ctx: &mut BC,
967 device: &CC::DeviceId,
968 src_ip: Ipv4SourceAddr,
969 dst_ip: SpecifiedAddr<Ipv4Addr>,
970 mut buffer: B,
971 info: &mut LocalDeliveryPacketInfo<Ipv4, H>,
972 _early_demux_socket: Option<!>,
973 ) -> Result<(), (B, Icmpv4Error)> {
974 let LocalDeliveryPacketInfo { meta, header_info: _, marks, packet_type: _, gso_info: _ } =
975 info;
976 let ReceiveIpPacketMeta { broadcast: _, transparent_override, parsing_context: _ } = meta;
977 if let Some(delivery) = transparent_override {
978 unreachable!(
979 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
980 transparent proxy rules can only be configured for TCP and UDP packets"
981 );
982 }
983
984 trace!(
985 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet({}, {})",
986 src_ip, dst_ip
987 );
988 let packet =
989 match buffer.parse_with::<_, Icmpv4Packet<_>>(IcmpParseArgs::new(src_ip, dst_ip)) {
990 Ok(packet) => packet,
991 Err(_) => return Ok(()), };
993
994 match packet {
995 Icmpv4Packet::EchoRequest(echo_request) => {
996 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_request.increment();
997
998 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
999 let req = *echo_request.message();
1000 let code = echo_request.code();
1001 let (local_ip, remote_ip) = (dst_ip, src_ip);
1002 debug!(
1003 "replying to ICMP echo request from {remote_ip} to {local_ip}%{device:?}: \
1004 id={}, seq={}",
1005 req.id(),
1006 req.seq()
1007 );
1008 send_icmp_reply(
1009 core_ctx,
1010 bindings_ctx,
1011 device,
1012 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1013 SocketIpAddr::new_ipv4_specified(local_ip),
1014 |src_ip| {
1015 IcmpPacketBuilder::<Ipv4, _>::new(src_ip, *remote_ip, code, req.reply())
1016 .wrap_body(buffer)
1017 },
1018 &WithMarks(marks),
1019 );
1020 } else {
1021 trace!(
1022 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1023 Received echo request with an unspecified source address"
1024 );
1025 }
1026 }
1027 Icmpv4Packet::EchoReply(echo_reply) => {
1028 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_reply.increment();
1029 trace!(
1030 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1031 Received an EchoReply message"
1032 );
1033 let parse_metadata = echo_reply.parse_metadata();
1034 buffer.undo_parse(parse_metadata);
1035 return <CC::EchoTransportContext
1036 as IpTransportContext<Ipv4, BC, CC>>::receive_ip_packet(
1037 core_ctx,
1038 bindings_ctx,
1039 device,
1040 src_ip,
1041 dst_ip,
1042 buffer,
1043 info,
1044 None,
1045 );
1046 }
1047 Icmpv4Packet::TimestampRequest(timestamp_request) => {
1048 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1049 .timestamp_request
1050 .increment();
1051 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
1052 if core_ctx.should_send_timestamp_reply() {
1053 trace!(
1054 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1055 receive_ip_packet: Responding to Timestamp Request message"
1056 );
1057 const NOW: u32 = 0x80000000;
1076 let reply = timestamp_request.message().reply(NOW, NOW);
1077 let (local_ip, remote_ip) = (dst_ip, src_ip);
1078 buffer.shrink_front_to(0);
1085 send_icmp_reply(
1086 core_ctx,
1087 bindings_ctx,
1088 device,
1089 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1090 SocketIpAddr::new_ipv4_specified(local_ip),
1091 |src_ip| {
1092 IcmpPacketBuilder::<Ipv4, _>::new(
1093 src_ip,
1094 *remote_ip,
1095 IcmpZeroCode,
1096 reply,
1097 )
1098 .wrap_body(buffer)
1099 },
1100 &WithMarks(marks),
1101 );
1102 } else {
1103 trace!(
1104 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1105 receive_ip_packet: Silently ignoring Timestamp Request message"
1106 );
1107 }
1108 } else {
1109 trace!(
1110 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1111 receive_ip_packet: Received timestamp request with an unspecified source \
1112 address"
1113 );
1114 }
1115 }
1116 Icmpv4Packet::TimestampReply(_) => {
1117 debug!(
1120 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1121 Received unsolicited Timestamp Reply message"
1122 );
1123 }
1124 Icmpv4Packet::DestUnreachable(dest_unreachable) => {
1125 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1126 .dest_unreachable
1127 .increment_code(dest_unreachable.code());
1128 trace!(
1129 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1130 Received a Destination Unreachable message"
1131 );
1132
1133 let error = if dest_unreachable.code()
1134 == Icmpv4DestUnreachableCode::FragmentationRequired
1135 {
1136 let mtu = if let Some(next_hop_mtu) = dest_unreachable.message().next_hop_mtu()
1137 {
1138 core_ctx.update_pmtu_if_less(
1148 bindings_ctx,
1149 dst_ip.get(),
1150 src_ip.get(),
1151 Mtu::new(u32::from(next_hop_mtu.get())),
1152 )
1153 } else {
1154 let (original_packet_buf, inner_body) = dest_unreachable.body().bytes();
1176 debug_assert!(inner_body.is_none());
1178 if original_packet_buf.len() >= 4 {
1179 let total_len =
1183 u16::from_be_bytes(original_packet_buf[2..4].try_into().unwrap());
1184
1185 trace!(
1186 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1187 receive_ip_packet: Next-Hop MTU is 0 so using the next best PMTU \
1188 value from {total_len}"
1189 );
1190
1191 core_ctx.update_pmtu_next_lower(
1192 bindings_ctx,
1193 dst_ip.get(),
1194 src_ip.get(),
1195 Mtu::new(u32::from(total_len)),
1196 )
1197 } else {
1198 trace!(
1203 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1204 receive_ip_packet: Original packet buf is too small to get \
1205 original packet len so ignoring"
1206 );
1207 None
1208 }
1209 };
1210 mtu.and_then(|mtu| {
1211 let mtu = u16::try_from(mtu.get()).unwrap_or(u16::MAX);
1212 let mtu = NonZeroU16::new(mtu)?;
1213 Some(Icmpv4ErrorCode::DestUnreachable(
1214 dest_unreachable.code(),
1215 IcmpDestUnreachable::new_for_frag_req(mtu),
1216 ))
1217 })
1218 } else {
1219 Some(Icmpv4ErrorCode::DestUnreachable(
1220 dest_unreachable.code(),
1221 *dest_unreachable.message(),
1222 ))
1223 };
1224
1225 if let Some(error) = error {
1226 receive_icmpv4_error(core_ctx, bindings_ctx, device, &dest_unreachable, error);
1227 }
1228 }
1229 Icmpv4Packet::TimeExceeded(time_exceeded) => {
1230 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1231 .time_exceeded
1232 .increment_code(time_exceeded.code());
1233 trace!(
1234 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1235 Received a Time Exceeded message"
1236 );
1237
1238 receive_icmpv4_error(
1239 core_ctx,
1240 bindings_ctx,
1241 device,
1242 &time_exceeded,
1243 Icmpv4ErrorCode::TimeExceeded(time_exceeded.code()),
1244 );
1245 }
1246 Icmpv4Packet::Redirect(_) => {
1248 debug!(
1249 "Unimplemented: <IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1250 receive_ip_packet::redirect"
1251 )
1252 }
1253 Icmpv4Packet::ParameterProblem(parameter_problem) => {
1254 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1255 .parameter_problem
1256 .increment_code(parameter_problem.code());
1257 trace!(
1258 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1259 Received a Parameter Problem message"
1260 );
1261
1262 receive_icmpv4_error(
1263 core_ctx,
1264 bindings_ctx,
1265 device,
1266 ¶meter_problem,
1267 Icmpv4ErrorCode::ParameterProblem(parameter_problem.code()),
1268 );
1269 }
1270 }
1271
1272 Ok(())
1273 }
1274}
1275
1276#[allow(missing_docs)]
1279pub enum NdpMessage {
1280 NeighborSolicitation {
1281 message: NeighborSolicitation,
1282 code: <NeighborSolicitation as IcmpMessage<Ipv6>>::Code,
1283 },
1284
1285 RouterSolicitation {
1286 message: RouterSolicitation,
1287 code: <RouterSolicitation as IcmpMessage<Ipv6>>::Code,
1288 },
1289
1290 NeighborAdvertisement {
1291 message: NeighborAdvertisement,
1292 code: <NeighborAdvertisement as IcmpMessage<Ipv6>>::Code,
1293 },
1294}
1295
1296pub fn send_ndp_packet<BC, CC, S>(
1298 core_ctx: &mut CC,
1299 bindings_ctx: &mut BC,
1300 device_id: &CC::DeviceId,
1301 src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1302 dst_ip: SpecifiedAddr<Ipv6Addr>,
1303 body: S,
1304 message: NdpMessage,
1305) -> Result<(), IpSendFrameError<S>>
1306where
1307 CC: IpLayerHandler<Ipv6, BC>,
1308 S: NetworkSerializer + NetworkPartialSerializer,
1309 S::Buffer: BufferMut,
1310{
1311 macro_rules! send {
1312 ($message:expr, $code:expr) => {{
1313 let mut ser = IcmpPacketBuilder::<Ipv6, _>::new(
1315 src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
1316 dst_ip.get(),
1317 $code,
1318 $message,
1319 )
1320 .wrap_body(body);
1321 match IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
1322 core_ctx,
1323 bindings_ctx,
1324 SendIpPacketMeta {
1325 device: device_id,
1326 src_ip,
1327 dst_ip,
1328 destination: IpPacketDestination::from_addr(dst_ip),
1329 ttl: NonZeroU8::new(REQUIRED_NDP_IP_PACKET_HOP_LIMIT),
1330 proto: Ipv6Proto::Icmpv6,
1331 mtu: Mtu::no_limit(),
1332 dscp_and_ecn: DscpAndEcn::default(),
1333 },
1334 DynTransportSerializer::new(&mut ser),
1335 ) {
1336 Ok(()) => Ok(()),
1337 Err(e) => Err(e
1338 .map_serializer(|s| {
1339 let _: DynTransportSerializer<'_, _> = s;
1341 })
1342 .map_serializer(|()| ser.into_inner())),
1343 }
1344 }};
1345 }
1346
1347 match message {
1348 NdpMessage::NeighborSolicitation { message, code } => send!(message, code),
1349 NdpMessage::RouterSolicitation { message, code } => send!(message, code),
1350 NdpMessage::NeighborAdvertisement { message, code } => send!(message, code),
1351 }
1352}
1353
1354fn send_neighbor_advertisement<
1355 BC,
1356 CC: Ipv6DeviceHandler<BC>
1357 + IpDeviceHandler<Ipv6, BC>
1358 + IpLayerHandler<Ipv6, BC>
1359 + CounterContext<NdpCounters>,
1360>(
1361 core_ctx: &mut CC,
1362 bindings_ctx: &mut BC,
1363 device_id: &CC::DeviceId,
1364 solicited: bool,
1365 device_addr: UnicastAddr<Ipv6Addr>,
1366 dst_ip: SpecifiedAddr<Ipv6Addr>,
1367) {
1368 core_ctx.counters().tx.neighbor_advertisement.increment();
1369 debug!("send_neighbor_advertisement from {:?} to {:?}", device_addr, dst_ip);
1370 debug_assert!(dst_ip.is_valid_unicast() || (!solicited && dst_ip.is_multicast()));
1377
1378 let src_ll = core_ctx.get_link_layer_addr(&device_id);
1385
1386 let advertisement = NeighborAdvertisement::new(
1388 core_ctx.is_router_device(&device_id),
1389 solicited,
1390 true, device_addr.get(),
1403 );
1404 let _: Result<(), _> = send_ndp_packet(
1405 core_ctx,
1406 bindings_ctx,
1407 &device_id,
1408 Some(device_addr.into_specified()),
1409 dst_ip,
1410 OptionSequenceBuilder::new(
1411 src_ll
1412 .as_ref()
1413 .map(Ipv6LinkLayerAddr::as_bytes)
1414 .map(NdpOptionBuilder::TargetLinkLayerAddress)
1415 .iter(),
1416 )
1417 .into_serializer(),
1418 NdpMessage::NeighborAdvertisement { message: advertisement, code: IcmpZeroCode },
1419 );
1420}
1421
1422fn receive_ndp_packet<
1423 B: SplitByteSlice,
1424 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1425 CC: InnerIcmpContext<Ipv6, BC>
1426 + Ipv6DeviceHandler<BC>
1427 + IpDeviceHandler<Ipv6, BC>
1428 + IpDeviceIngressStateContext<Ipv6>
1429 + NudIpHandler<Ipv6, BC>
1430 + IpLayerHandler<Ipv6, BC>
1431 + CounterContext<NdpCounters>,
1432 H: IpHeaderInfo<Ipv6>,
1433>(
1434 core_ctx: &mut CC,
1435 bindings_ctx: &mut BC,
1436 device_id: &CC::DeviceId,
1437 src_ip: Ipv6SourceAddr,
1438 dst_ip: SpecifiedAddr<Ipv6Addr>,
1439 packet: NdpPacket<B>,
1440 header_info: &H,
1441) {
1442 if header_info.hop_limit() != REQUIRED_NDP_IP_PACKET_HOP_LIMIT {
1460 trace!("dropping NDP packet from {src_ip} with invalid hop limit");
1461 return;
1462 }
1463
1464 match packet {
1465 NdpPacket::RouterSolicitation(_) => {}
1466 NdpPacket::Redirect(_) => {}
1468 NdpPacket::NeighborSolicitation(ref p) => {
1469 let target_address = p.message().target_address();
1476 let target_address = match UnicastAddr::new(*target_address) {
1477 Some(a) => a,
1478 None => {
1479 trace!(
1480 "dropping NS from {} with non-unicast target={:?}",
1481 src_ip, target_address
1482 );
1483 return;
1484 }
1485 };
1486
1487 let (source_link_addr, nonce) = p.body().iter().fold(
1489 (None, None),
1490 |(found_source_link_addr, found_nonce), option| {
1491 match option {
1492 NdpOption::Nonce(nonce) => (found_source_link_addr, Some(nonce)),
1493 NdpOption::SourceLinkLayerAddress(source_link_addr) => {
1494 (Some(source_link_addr), found_nonce)
1495 }
1496 NdpOption::Mtu(_)
1504 | NdpOption::PrefixInformation(_)
1505 | NdpOption::RecursiveDnsServer(_)
1506 | NdpOption::RedirectedHeader { .. }
1507 | NdpOption::RouteInformation(_)
1508 | NdpOption::TargetLinkLayerAddress(_) => {
1509 (found_source_link_addr, found_nonce)
1510 }
1511 }
1512 },
1513 );
1514
1515 if src_ip == Ipv6SourceAddr::Unspecified {
1516 if target_address.get().to_solicited_node_address().get() != dst_ip.get() {
1525 debug!(
1526 "dropping NS from {} for {} with invalid IPv6 dst ({}).",
1527 src_ip, target_address, dst_ip
1528 );
1529 return;
1530 }
1531 if let Some(addr) = source_link_addr {
1536 debug!(
1537 "dropping NS from {} for {} with source link-layer addr option ({:?}).",
1538 src_ip, target_address, addr
1539 );
1540 return;
1541 }
1542 }
1543
1544 core_ctx.counters().rx.neighbor_solicitation.increment();
1545
1546 match src_ip {
1547 Ipv6SourceAddr::Unspecified => {
1548 match IpDeviceHandler::handle_received_dad_packet(
1558 core_ctx,
1559 bindings_ctx,
1560 &device_id,
1561 target_address.into_specified(),
1562 nonce,
1563 ) {
1564 Some(IpAddressState::Assigned) => {
1565 send_neighbor_advertisement(
1569 core_ctx,
1570 bindings_ctx,
1571 &device_id,
1572 false,
1573 target_address,
1574 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified(),
1575 );
1576 }
1577 Some(IpAddressState::Tentative) => {
1578 }
1581 Some(IpAddressState::Unavailable) | None => {
1582 }
1585 }
1586
1587 return;
1588 }
1589 Ipv6SourceAddr::Unicast(src_ip) => {
1590 match core_ctx
1592 .address_status_for_device(target_address.into_specified(), device_id)
1593 {
1594 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned) => {}
1595 AddressStatus::Present(
1596 Ipv6PresentAddressStatus::UnicastTentative
1597 | Ipv6PresentAddressStatus::Multicast,
1598 )
1599 | AddressStatus::Unassigned => {
1600 return;
1604 }
1605 }
1606
1607 if let Some(link_addr) = source_link_addr {
1608 NudIpHandler::handle_neighbor_probe(
1609 core_ctx,
1610 bindings_ctx,
1611 &device_id,
1612 src_ip.into_specified(),
1613 link_addr,
1614 );
1615 }
1616
1617 send_neighbor_advertisement(
1618 core_ctx,
1619 bindings_ctx,
1620 &device_id,
1621 true,
1622 target_address,
1623 src_ip.into_specified(),
1624 );
1625 }
1626 }
1627 }
1628 NdpPacket::NeighborAdvertisement(ref p) => {
1629 let target_address = p.message().target_address();
1633
1634 let target_address = match UnicastAddr::new(*target_address) {
1641 Some(a) => a,
1642 None => {
1643 debug!(
1644 "dropping NA from {} with non-unicast target={:?}",
1645 src_ip, target_address
1646 );
1647 return;
1648 }
1649 };
1650 if let Some(dst_ip) = MulticastAddr::new(dst_ip.get())
1654 && p.message().solicited_flag()
1655 {
1656 debug!(
1657 "dropping NA from {} with solicited flag and multicast dst {}",
1658 src_ip, dst_ip
1659 );
1660 return;
1661 }
1662
1663 core_ctx.counters().rx.neighbor_advertisement.increment();
1664
1665 let nonce = None;
1669 match IpDeviceHandler::handle_received_dad_packet(
1670 core_ctx,
1671 bindings_ctx,
1672 &device_id,
1673 target_address.into_specified(),
1674 nonce,
1675 ) {
1676 Some(IpAddressState::Assigned) => {
1677 error!(
1695 "NA from {src_ip} with target address {target_address} that is also \
1696 assigned on device {device_id:?}",
1697 );
1698 }
1699 Some(IpAddressState::Tentative) => {
1700 return;
1703 }
1704 Some(IpAddressState::Unavailable) | None => {
1705 }
1709 }
1710
1711 let link_addr = p.body().iter().find_map(|o| o.target_link_layer_address());
1712
1713 NudIpHandler::handle_neighbor_confirmation(
1714 core_ctx,
1715 bindings_ctx,
1716 &device_id,
1717 target_address.into_specified(),
1718 link_addr,
1719 ConfirmationFlags {
1720 solicited_flag: p.message().solicited_flag(),
1721 override_flag: p.message().override_flag(),
1722 },
1723 );
1724 }
1725 NdpPacket::RouterAdvertisement(ref p) => {
1726 let src_ip = match src_ip {
1739 Ipv6SourceAddr::Unicast(ip) => match LinkLocalUnicastAddr::new(*ip) {
1740 Some(ip) => ip,
1741 None => return,
1742 },
1743 Ipv6SourceAddr::Unspecified => return,
1744 };
1745
1746 let ra = p.message();
1747 debug!("received router advertisement from {:?}: {:?}", src_ip, ra);
1748 core_ctx.counters().rx.router_advertisement.increment();
1749
1750 if let Some(retransmit_timer) = ra.retransmit_timer() {
1757 Ipv6DeviceHandler::set_discovered_retrans_timer(
1758 core_ctx,
1759 bindings_ctx,
1760 &device_id,
1761 retransmit_timer,
1762 );
1763 }
1764
1765 if let Some(hop_limit) = ra.current_hop_limit() {
1772 trace!(
1773 "receive_ndp_packet: NDP RA: updating device's hop limit to {:?} for router: {:?}",
1774 ra.current_hop_limit(),
1775 src_ip
1776 );
1777 IpDeviceHandler::set_default_hop_limit(core_ctx, &device_id, hop_limit);
1778 }
1779
1780 Ipv6DeviceHandler::update_discovered_ipv6_route(
1781 core_ctx,
1782 bindings_ctx,
1783 &device_id,
1784 Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) },
1785 Ipv6DiscoveredRouteProperties { route_preference: p.message().preference().into() },
1786 p.message().router_lifetime().map(NonZeroNdpLifetime::Finite),
1787 );
1788
1789 for option in p.body().iter() {
1790 match option {
1791 NdpOption::TargetLinkLayerAddress(_)
1792 | NdpOption::RedirectedHeader { .. }
1793 | NdpOption::RecursiveDnsServer(_)
1794 | NdpOption::Nonce(_) => {}
1795 NdpOption::SourceLinkLayerAddress(addr) => {
1796 debug!("processing SourceLinkLayerAddress option in RA: {:?}", addr);
1797 NudIpHandler::handle_neighbor_probe(
1823 core_ctx,
1824 bindings_ctx,
1825 &device_id,
1826 {
1827 let src_ip: UnicastAddr<_> = src_ip.into_addr();
1828 src_ip.into_specified()
1829 },
1830 addr,
1831 );
1832 }
1833 NdpOption::PrefixInformation(prefix_info) => {
1834 debug!("processing Prefix Information option in RA: {:?}", prefix_info);
1835 if prefix_info.prefix().is_link_local() {
1853 continue;
1854 }
1855
1856 let subnet = match prefix_info.subnet() {
1857 Ok(subnet) => subnet,
1858 Err(err) => match err {
1859 SubnetError::PrefixTooLong | SubnetError::HostBitsSet => continue,
1860 },
1861 };
1862
1863 match UnicastAddr::new(subnet.network()) {
1864 Some(UnicastAddr { .. }) => {}
1865 None => continue,
1866 }
1867
1868 let valid_lifetime = prefix_info.valid_lifetime();
1869
1870 if prefix_info.on_link_flag() {
1871 Ipv6DeviceHandler::update_discovered_ipv6_route(
1872 core_ctx,
1873 bindings_ctx,
1874 &device_id,
1875 Ipv6DiscoveredRoute { subnet, gateway: None },
1876 Ipv6DiscoveredRouteProperties {
1877 route_preference: RoutePreference::Medium,
1878 },
1879 valid_lifetime,
1880 )
1881 }
1882
1883 if prefix_info.autonomous_address_configuration_flag() {
1884 Ipv6DeviceHandler::apply_slaac_update(
1885 core_ctx,
1886 bindings_ctx,
1887 &device_id,
1888 subnet,
1889 prefix_info.preferred_lifetime(),
1890 valid_lifetime,
1891 );
1892 }
1893 }
1894 NdpOption::RouteInformation(rio) => {
1895 debug!("processing Route Information option in RA: {:?}", rio);
1896 Ipv6DeviceHandler::update_discovered_ipv6_route(
1897 core_ctx,
1898 bindings_ctx,
1899 &device_id,
1900 Ipv6DiscoveredRoute {
1901 subnet: rio.prefix().clone(),
1902 gateway: Some(src_ip),
1903 },
1904 Ipv6DiscoveredRouteProperties {
1905 route_preference: rio.preference().into(),
1906 },
1907 rio.route_lifetime(),
1908 )
1909 }
1910 NdpOption::Mtu(mtu) => {
1911 debug!("processing MTU option in RA: {:?}", mtu);
1912 Ipv6DeviceHandler::set_link_mtu(core_ctx, &device_id, Mtu::new(mtu));
1916 }
1917 }
1918 }
1919
1920 bindings_ctx.on_event(RouterAdvertisementEvent {
1921 options_bytes: Box::from(p.body().bytes()),
1922 source: **src_ip,
1923 device: device_id.clone(),
1924 });
1925 }
1926 }
1927}
1928
1929impl<
1930 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1931 CC: InnerIcmpContext<Ipv6, BC>
1932 + InnerIcmpContext<Ipv6, BC>
1933 + Ipv6DeviceHandler<BC>
1934 + IpDeviceHandler<Ipv6, BC>
1935 + IpDeviceIngressStateContext<Ipv6>
1936 + PmtuHandler<Ipv6, BC>
1937 + NudIpHandler<Ipv6, BC>
1938 + IpLayerHandler<Ipv6, BC>
1939 + CounterContext<IcmpRxCounters<Ipv6>>
1940 + CounterContext<IcmpTxCounters<Ipv6>>
1941 + CounterContext<NdpCounters>,
1942> IpTransportContext<Ipv6, BC, CC> for IcmpIpTransportContext
1943{
1944 type EarlyDemuxSocket = !;
1945
1946 fn early_demux<B: ParseBuffer>(
1947 _core_ctx: &mut CC,
1948 _device: &CC::DeviceId,
1949 _src_ip: Ipv6Addr,
1950 _dst_ip: Ipv6Addr,
1951 _buffer: B,
1952 ) -> Option<Self::EarlyDemuxSocket> {
1953 None
1954 }
1955
1956 fn receive_icmp_error(
1957 core_ctx: &mut CC,
1958 bindings_ctx: &mut BC,
1959 device: &CC::DeviceId,
1960 original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1961 original_dst_ip: SpecifiedAddr<Ipv6Addr>,
1962 original_body: &[u8],
1963 err: Icmpv6ErrorCode,
1964 ) {
1965 receive_ip_transport_icmp_error(
1966 core_ctx,
1967 bindings_ctx,
1968 device,
1969 original_src_ip,
1970 original_dst_ip,
1971 original_body,
1972 err,
1973 )
1974 }
1975
1976 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
1977 core_ctx: &mut CC,
1978 bindings_ctx: &mut BC,
1979 device: &CC::DeviceId,
1980 src_ip: Ipv6SourceAddr,
1981 dst_ip: SpecifiedAddr<Ipv6Addr>,
1982 mut buffer: B,
1983 info: &mut LocalDeliveryPacketInfo<Ipv6, H>,
1984 _early_demux_socket: Option<!>,
1985 ) -> Result<(), (B, Icmpv6Error)> {
1986 let LocalDeliveryPacketInfo { meta, header_info, marks, packet_type: _, gso_info: _ } =
1987 info;
1988 let ReceiveIpPacketMeta { broadcast: _, transparent_override, parsing_context: _ } = meta;
1989 if let Some(delivery) = transparent_override {
1990 unreachable!(
1991 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
1992 transparent proxy rules can only be configured for TCP and UDP packets"
1993 );
1994 }
1995
1996 trace!(
1997 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet({:?}, {})",
1998 src_ip, dst_ip
1999 );
2000
2001 let packet = match buffer
2002 .parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(src_ip.get(), dst_ip))
2003 {
2004 Ok(packet) => packet,
2005 Err(_) => return Ok(()), };
2007
2008 match packet {
2009 Icmpv6Packet::EchoRequest(echo_request) => {
2010 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_request.increment();
2011
2012 if let Some(src_ip) = SocketIpAddr::new_from_ipv6_source(src_ip) {
2013 match SocketIpAddr::try_from(dst_ip) {
2014 Ok(dst_ip) => {
2015 let req = *echo_request.message();
2016 let code = echo_request.code();
2017 let (local_ip, remote_ip) = (dst_ip, src_ip);
2018 debug!(
2019 "replying to ICMP echo request from {remote_ip}: id={}, seq={}",
2020 req.id(),
2021 req.seq()
2022 );
2023 send_icmp_reply(
2024 core_ctx,
2025 bindings_ctx,
2026 device,
2027 remote_ip,
2028 local_ip,
2029 |src_ip| {
2030 IcmpPacketBuilder::<Ipv6, _>::new(
2031 src_ip,
2032 remote_ip.addr(),
2033 code,
2034 req.reply(),
2035 )
2036 .wrap_body(buffer)
2037 },
2038 &WithMarks(marks),
2039 );
2040 }
2041 Err(AddrIsMappedError {}) => {
2042 trace!(
2043 "IpTransportContext<Ipv6>::receive_ip_packet: Received echo request with an ipv4-mapped-ipv6 destination address"
2044 );
2045 }
2046 }
2047 } else {
2048 trace!(
2049 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received echo request with an unspecified source address"
2050 );
2051 }
2052 }
2053 Icmpv6Packet::EchoReply(echo_reply) => {
2054 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_reply.increment();
2055 trace!(
2056 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received an EchoReply message"
2057 );
2058 let parse_metadata = echo_reply.parse_metadata();
2059 buffer.undo_parse(parse_metadata);
2060 return <CC::EchoTransportContext
2061 as IpTransportContext<Ipv6, BC, CC>>::receive_ip_packet(
2062 core_ctx,
2063 bindings_ctx,
2064 device,
2065 src_ip,
2066 dst_ip,
2067 buffer,
2068 info,
2069 None
2070 );
2071 }
2072 Icmpv6Packet::Ndp(packet) => receive_ndp_packet(
2073 core_ctx,
2074 bindings_ctx,
2075 device,
2076 src_ip,
2077 dst_ip,
2078 packet,
2079 header_info,
2080 ),
2081 Icmpv6Packet::PacketTooBig(packet_too_big) => {
2082 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2083 .packet_too_big
2084 .increment();
2085 trace!(
2086 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received a Packet Too Big message"
2087 );
2088 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2089 let mtu = core_ctx.update_pmtu_if_less(
2099 bindings_ctx,
2100 dst_ip.get(),
2101 src_ip.get(),
2102 Mtu::new(packet_too_big.message().mtu()),
2103 );
2104 if let Some(mtu) = mtu {
2105 receive_icmpv6_error(
2106 core_ctx,
2107 bindings_ctx,
2108 device,
2109 &packet_too_big,
2110 Icmpv6ErrorCode::PacketTooBig(mtu),
2111 );
2112 }
2113 }
2114 }
2115 Icmpv6Packet::Mld(packet) => {
2116 core_ctx.receive_mld_packet(
2117 bindings_ctx,
2118 &device,
2119 src_ip,
2120 dst_ip,
2121 packet,
2122 header_info,
2123 );
2124 }
2125 Icmpv6Packet::DestUnreachable(dest_unreachable) => {
2126 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2127 .dest_unreachable
2128 .increment_code(dest_unreachable.code());
2129 receive_icmpv6_error(
2130 core_ctx,
2131 bindings_ctx,
2132 device,
2133 &dest_unreachable,
2134 Icmpv6ErrorCode::DestUnreachable(dest_unreachable.code()),
2135 )
2136 }
2137 Icmpv6Packet::TimeExceeded(time_exceeded) => {
2138 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2139 .time_exceeded
2140 .increment_code(time_exceeded.code());
2141 receive_icmpv6_error(
2142 core_ctx,
2143 bindings_ctx,
2144 device,
2145 &time_exceeded,
2146 Icmpv6ErrorCode::TimeExceeded(time_exceeded.code()),
2147 )
2148 }
2149 Icmpv6Packet::ParameterProblem(parameter_problem) => {
2150 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2151 .parameter_problem
2152 .increment_code(parameter_problem.code());
2153 receive_icmpv6_error(
2154 core_ctx,
2155 bindings_ctx,
2156 device,
2157 ¶meter_problem,
2158 Icmpv6ErrorCode::ParameterProblem(parameter_problem.code()),
2159 )
2160 }
2161 }
2162
2163 Ok(())
2164 }
2165}
2166
2167#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2168struct WithMarks<'a>(&'a Marks);
2169
2170impl<'a> OptionDelegationMarker for WithMarks<'a> {}
2171
2172impl<'a, I: IpExt> DelegatedRouteResolutionOptions<I> for WithMarks<'a> {
2173 fn marks(&self) -> &Marks {
2174 let Self(marks) = self;
2175 marks
2176 }
2177}
2178
2179impl<'a, I: IpExt> DelegatedSendOptions<I> for WithMarks<'a> {}
2180
2181fn send_icmp_reply<I, BC, CC, S, F, O>(
2192 core_ctx: &mut CC,
2193 bindings_ctx: &mut BC,
2194 device: &CC::DeviceId,
2195 original_src_ip: SocketIpAddr<I::Addr>,
2196 original_dst_ip: SocketIpAddr<I::Addr>,
2197 get_body_from_src_ip: F,
2198 ip_options: &O,
2199) where
2200 I: IpExt + FilterIpExt + IcmpCountersIpExt,
2201 CC: IpSocketHandler<I, BC> + DeviceIdContext<AnyDevice> + CounterContext<IcmpTxCounters<I>>,
2202 BC: TxMetadataBindingsTypes,
2203 S: DynamicTransportSerializer<I>,
2204 F: FnOnce(SpecifiedAddr<I::Addr>) -> S,
2205 O: SendOptions<I> + RouteResolutionOptions<I>,
2206{
2207 trace!("send_icmp_reply({:?}, {}, {})", device, original_src_ip, original_dst_ip);
2208 core_ctx.counters().reply.increment();
2209 let tx_metadata: BC::TxMetadata = Default::default();
2210
2211 let egress_device = (original_dst_ip.as_ref().is_multicast()
2215 || original_dst_ip.as_ref().must_have_zone())
2216 .then_some(EitherDeviceId::Strong(device));
2217
2218 core_ctx
2219 .send_oneshot_ip_packet_with_dyn_serializer(
2220 bindings_ctx,
2221 IpSocketArgs {
2222 device: egress_device,
2223 local_ip: IpDeviceAddr::new_from_socket_ip_addr(original_dst_ip),
2224 remote_ip: original_src_ip,
2225 proto: I::ICMP_IP_PROTO,
2226 options: ip_options,
2227 },
2228 tx_metadata,
2229 |src_ip| get_body_from_src_ip(src_ip.into()),
2230 )
2231 .unwrap_or_else(|err| {
2232 debug!("failed to send ICMP reply: {}", err);
2233 })
2234}
2235
2236fn receive_icmpv4_error<
2241 BC: IcmpBindingsContext,
2242 CC: InnerIcmpContext<Ipv4, BC>,
2243 B: SplitByteSlice,
2244 M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>,
2245>(
2246 core_ctx: &mut CC,
2247 bindings_ctx: &mut BC,
2248 device: &CC::DeviceId,
2249 packet: &IcmpPacket<Ipv4, B, M>,
2250 err: Icmpv4ErrorCode,
2251) {
2252 packet.with_original_packet(|res| match res {
2253 Ok(original_packet) => {
2254 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2255 Some(ip) => ip,
2256 None => {
2257 trace!("receive_icmpv4_error: Got ICMP error message whose original IPv4 packet contains an unspecified destination address; discarding");
2258 return;
2259 },
2260 };
2261 InnerIcmpContext::receive_icmp_error(
2262 core_ctx,
2263 bindings_ctx,
2264 device,
2265 SpecifiedAddr::new(original_packet.src_ip()),
2266 dst_ip,
2267 original_packet.proto(),
2268 original_packet.body().into_inner(),
2269 err,
2270 );
2271 }
2272 Err(_) => debug!(
2273 "receive_icmpv4_error: Got ICMP error message with unparsable original IPv4 packet"
2274 ),
2275 })
2276}
2277
2278fn receive_icmpv6_error<
2283 BC: IcmpBindingsContext,
2284 CC: InnerIcmpContext<Ipv6, BC>,
2285 B: SplitByteSlice,
2286 M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>,
2287>(
2288 core_ctx: &mut CC,
2289 bindings_ctx: &mut BC,
2290 device: &CC::DeviceId,
2291 packet: &IcmpPacket<Ipv6, B, M>,
2292 err: Icmpv6ErrorCode,
2293) {
2294 packet.with_original_packet(|res| match res {
2295 Ok(original_packet) => {
2296 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2297 Some(ip)=>ip,
2298 None => {
2299 trace!("receive_icmpv6_error: Got ICMP error message whose original IPv6 packet contains an unspecified destination address; discarding");
2300 return;
2301 },
2302 };
2303 match original_packet.body_proto() {
2304 Ok((body, proto)) => {
2305 InnerIcmpContext::receive_icmp_error(
2306 core_ctx,
2307 bindings_ctx,
2308 device,
2309 SpecifiedAddr::new(original_packet.src_ip()),
2310 dst_ip,
2311 proto,
2312 body.into_inner(),
2313 err,
2314 );
2315 }
2316 Err(ExtHdrParseError) => {
2317 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");
2318 return;
2321 }
2322 }
2323 }
2324 Err(_body) => debug!(
2325 "receive_icmpv6_error: Got ICMPv6 error message with unparsable original IPv6 packet"
2326 ),
2327 })
2328}
2329
2330fn send_icmpv4_error_message<B, BC, CC>(
2331 core_ctx: &mut CC,
2332 bindings_ctx: &mut BC,
2333 device: Option<&CC::DeviceId>,
2334 frame_dst: Option<LocalFrameDestination>,
2335 original_src_ip: SocketIpAddr<Ipv4Addr>,
2336 original_dst_ip: SocketIpAddr<Ipv4Addr>,
2337 message: Icmpv4ErrorMessage,
2338 mut original_packet: B,
2339 header_len: usize,
2340 marks: &Marks,
2341) where
2342 B: BufferMut,
2343 BC: IcmpBindingsContext,
2344 CC: IcmpSendContext<Ipv4, BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2345{
2346 if !should_send_icmpv4_error(frame_dst, original_src_ip.into(), original_dst_ip.into()) {
2350 return;
2351 }
2352
2353 original_packet.shrink_back_to(header_len + 64);
2356
2357 let tx_metadata: BC::TxMetadata = Default::default();
2358
2359 macro_rules! send {
2360 ($message:expr, $code:expr) => {{
2361 let _ = try_send_error!(
2364 core_ctx,
2365 bindings_ctx,
2366 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2367 bindings_ctx,
2368 IpSocketArgs {
2369 device: device.map(EitherDeviceId::Strong),
2370 local_ip: None,
2371 remote_ip: original_src_ip,
2372 proto: Ipv4Proto::Icmp,
2373 options: &WithMarks(marks),
2374 },
2375 tx_metadata,
2376 |local_ip| {
2377 IcmpPacketBuilder::<Ipv4, _>::new(
2378 local_ip.addr(),
2379 original_src_ip.addr(),
2380 $code,
2381 $message,
2382 )
2383 .wrap_body(original_packet)
2384 },
2385 )
2386 );
2387 }};
2388 }
2389
2390 match message {
2391 Icmpv4ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2392 Icmpv4ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2393 Icmpv4ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2394 }
2395}
2396
2397fn send_icmpv6_error_message<B, BC, CC>(
2398 core_ctx: &mut CC,
2399 bindings_ctx: &mut BC,
2400 device: Option<&CC::DeviceId>,
2401 frame_dst: Option<LocalFrameDestination>,
2402 original_src_ip: SocketIpAddr<Ipv6Addr>,
2403 original_dst_ip: SocketIpAddr<Ipv6Addr>,
2404 message: Icmpv6ErrorMessage,
2405 original_packet: B,
2406 allow_dst_multicast: bool,
2407 marks: &Marks,
2408) where
2409 B: BufferMut,
2410 BC: IcmpBindingsContext,
2411 CC: IcmpSendContext<Ipv6, BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2412{
2413 if !should_send_icmpv6_error(
2417 frame_dst,
2418 original_src_ip.into(),
2419 original_dst_ip.into(),
2420 allow_dst_multicast,
2421 ) {
2422 return;
2423 }
2424
2425 struct Icmpv6ErrorOptions<'a>(&'a Marks);
2426 impl<'a> OptionDelegationMarker for Icmpv6ErrorOptions<'a> {}
2427 impl<'a> DelegatedSendOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2428 fn mtu(&self) -> Mtu {
2429 Ipv6::MINIMUM_LINK_MTU
2430 }
2431 }
2432 impl<'a> DelegatedRouteResolutionOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2433 fn marks(&self) -> &Marks {
2434 let Self(marks) = self;
2435 marks
2436 }
2437 }
2438
2439 let tx_metadata: BC::TxMetadata = Default::default();
2440
2441 macro_rules! send {
2442 ($message:expr, $code:expr) => {{
2443 let _ = try_send_error!(
2446 core_ctx,
2447 bindings_ctx,
2448 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2449 bindings_ctx,
2450 IpSocketArgs {
2451 device: device.map(EitherDeviceId::Strong),
2452 local_ip: None,
2453 remote_ip: original_src_ip,
2454 proto: Ipv6Proto::Icmpv6,
2455 options: &Icmpv6ErrorOptions(marks),
2456 },
2457 tx_metadata,
2458 |local_ip| {
2459 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
2460 local_ip.addr(),
2461 original_src_ip.addr(),
2462 $code,
2463 $message,
2464 );
2465
2466 icmp_builder.wrap_body(TruncatingSerializer::new(
2469 original_packet,
2470 TruncateDirection::DiscardBack,
2471 ))
2472 },
2473 )
2474 );
2475 }};
2476 }
2477
2478 match message {
2479 Icmpv6ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2480 Icmpv6ErrorMessage::PacketTooBig { message, code } => send!(message, code),
2481 Icmpv6ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2482 Icmpv6ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2483 }
2484}
2485
2486fn should_send_icmpv4_error(
2509 frame_dst: Option<LocalFrameDestination>,
2510 src_ip: SpecifiedAddr<Ipv4Addr>,
2511 dst_ip: SpecifiedAddr<Ipv4Addr>,
2512) -> bool {
2513 !(dst_ip.is_multicast()
2533 || dst_ip.is_limited_broadcast()
2534 || frame_dst.is_some_and(|dst| dst.is_broadcast())
2535 || src_ip.is_limited_broadcast()
2536 || src_ip.is_multicast()
2537 || src_ip.is_class_e())
2538}
2539
2540fn should_send_icmpv6_error(
2570 frame_dst: Option<LocalFrameDestination>,
2571 src_ip: SpecifiedAddr<Ipv6Addr>,
2572 dst_ip: SpecifiedAddr<Ipv6Addr>,
2573 allow_dst_multicast: bool,
2574) -> bool {
2575 let multicast_frame_dst = match frame_dst {
2578 Some(FrameDestination::Individual { local: () }) | None => false,
2579 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
2580 };
2581 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
2582 return false;
2583 }
2584 if src_ip.is_multicast() {
2585 return false;
2586 }
2587 true
2588}
2589
2590fn is_icmp_error_or_redirect_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
2602 proto == I::ICMP_IP_PROTO
2603 && peek_message_type::<I::IcmpMessageType>(buf)
2604 .map(IcmpMessageType::is_error_or_redirect)
2605 .unwrap_or(true)
2606}
2607
2608#[cfg(any(test, feature = "testutils"))]
2610pub(crate) mod testutil {
2611 use alloc::vec::Vec;
2612 use net_types::ethernet::Mac;
2613 use net_types::ip::{Ipv6, Ipv6Addr};
2614 use netstack3_base::NetworkSerializationContext;
2615 use packet::{Buf, InnerPacketBuilder as _, NestableSerializer as _, Serializer as _};
2616 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
2617 use packet_formats::icmp::ndp::{
2618 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
2619 };
2620 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
2621 use packet_formats::ip::Ipv6Proto;
2622 use packet_formats::ipv6::Ipv6PacketBuilder;
2623
2624 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
2625
2626 pub fn neighbor_advertisement_ip_packet(
2629 src_ip: Ipv6Addr,
2630 dst_ip: Ipv6Addr,
2631 router_flag: bool,
2632 solicited_flag: bool,
2633 override_flag: bool,
2634 mac: Mac,
2635 ) -> Buf<Vec<u8>> {
2636 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
2637 .into_serializer()
2638 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2639 src_ip,
2640 dst_ip,
2641 IcmpZeroCode,
2642 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
2643 ))
2644 .wrap_in(Ipv6PacketBuilder::new(
2645 src_ip,
2646 dst_ip,
2647 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2648 Ipv6Proto::Icmpv6,
2649 ))
2650 .serialize_vec_outer(&mut NetworkSerializationContext::default())
2651 .unwrap()
2652 .unwrap_b()
2653 }
2654
2655 pub fn neighbor_solicitation_ip_packet(
2658 src_ip: Ipv6Addr,
2659 dst_ip: Ipv6Addr,
2660 target_addr: Ipv6Addr,
2661 mac: Mac,
2662 ) -> Buf<Vec<u8>> {
2663 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
2664 .into_serializer()
2665 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2666 src_ip,
2667 dst_ip,
2668 IcmpZeroCode,
2669 NeighborSolicitation::new(target_addr),
2670 ))
2671 .wrap_in(Ipv6PacketBuilder::new(
2672 src_ip,
2673 dst_ip,
2674 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2675 Ipv6Proto::Icmpv6,
2676 ))
2677 .serialize_vec_outer(&mut NetworkSerializationContext::default())
2678 .unwrap()
2679 .unwrap_b()
2680 }
2681}
2682
2683#[cfg(test)]
2684mod tests {
2685 use alloc::vec;
2686 use alloc::vec::Vec;
2687 use packet_formats::icmp::ndp::options::NdpNonce;
2688
2689 use core::fmt::Debug;
2690 use core::time::Duration;
2691
2692 use net_types::ip::Subnet;
2693 use netstack3_base::testutil::{
2694 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId,
2695 TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt, set_logger_for_test,
2696 };
2697 use netstack3_base::{CtxPair, NetworkSerializationContext, Uninstantiable};
2698 use netstack3_filter::TransportPacketSerializer;
2699 use packet::{Buf, EmptyBuf, NestableSerializer as _, Serializer as _};
2700 use packet_formats::icmp::mld::MldPacket;
2701 use packet_formats::ip::IpProto;
2702 use packet_formats::utils::NonZeroDuration;
2703
2704 use super::*;
2705 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
2706 use crate::internal::gso::MaybeSegmentableTransportSerializer;
2707 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
2708 use crate::internal::socket::{
2709 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
2710 };
2711 use crate::socket::RouteResolutionOptions;
2712
2713 pub(super) trait IcmpTestIpExt:
2714 TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt
2715 {
2716 }
2717 impl<I: TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt> IcmpTestIpExt for I {}
2718
2719 type InnerIpSocketCtx<I> = FakeCoreCtx<
2721 FakeIpSocketCtx<I, FakeDeviceId>,
2722 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
2723 FakeDeviceId,
2724 >;
2725
2726 pub(super) struct FakeIcmpCoreCtx<I: IcmpTestIpExt> {
2728 ip_socket_ctx: InnerIpSocketCtx<I>,
2729 icmp: FakeIcmpCoreCtxState<I>,
2730 }
2731
2732 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
2734 (),
2735 RouterAdvertisementEvent<FakeDeviceId>,
2736 FakeIcmpBindingsCtxState<I>,
2737 (),
2738 >;
2739
2740 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
2744
2745 pub(super) struct FakeIcmpCoreCtxState<I: IcmpTestIpExt> {
2746 error_send_bucket: TokenBucket<FakeInstant>,
2747 receive_icmp_error: Vec<I::ErrorCode>,
2748 rx_counters: IcmpRxCounters<I>,
2749 tx_counters: IcmpTxCounters<I>,
2750 ndp_counters: NdpCounters,
2751 }
2752
2753 impl<I: IcmpTestIpExt> FakeIcmpCoreCtx<I> {
2754 fn with_errors_per_second(errors_per_second: u64) -> Self {
2755 Self {
2756 icmp: FakeIcmpCoreCtxState {
2757 error_send_bucket: TokenBucket::new(errors_per_second),
2758 receive_icmp_error: Default::default(),
2759 rx_counters: Default::default(),
2760 tx_counters: Default::default(),
2761 ndp_counters: Default::default(),
2762 },
2763 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
2764 core::iter::once(FakeDeviceConfig {
2765 device: FakeDeviceId,
2766 local_ips: vec![I::TEST_ADDRS.local_ip],
2767 remote_ips: vec![I::TEST_ADDRS.remote_ip],
2768 }),
2769 )),
2770 }
2771 }
2772 }
2773
2774 impl<I: IcmpTestIpExt> Default for FakeIcmpCoreCtx<I> {
2775 fn default() -> Self {
2776 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
2777 }
2778 }
2779
2780 impl<I: IcmpTestIpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
2781 type DeviceId = FakeDeviceId;
2782 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
2783 }
2784
2785 impl<I: IcmpTestIpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
2786 impl<I: IcmpTestIpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
2787
2788 impl<I: IcmpTestIpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
2789 fn counters(&self) -> &IcmpRxCounters<I> {
2790 &self.icmp.rx_counters
2791 }
2792 }
2793
2794 impl<I: IcmpTestIpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
2795 fn counters(&self) -> &IcmpTxCounters<I> {
2796 &self.icmp.tx_counters
2797 }
2798 }
2799
2800 impl<I: IcmpTestIpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
2801 fn counters(&self) -> &NdpCounters {
2802 &self.icmp.ndp_counters
2803 }
2804 }
2805
2806 pub enum FakeEchoIpTransportContext {}
2807
2808 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
2809
2810 impl<I> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
2811 for FakeEchoIpTransportContext
2812 where
2813 I: IcmpTestIpExt + IpLayerIpExt,
2814 {
2815 type EarlyDemuxSocket = !;
2816
2817 fn early_demux<B: ParseBuffer>(
2818 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2819 _device: &FakeDeviceId,
2820 _src_ip: I::Addr,
2821 _dst_ip: I::Addr,
2822 _buffer: B,
2823 ) -> Option<Self::EarlyDemuxSocket> {
2824 None
2825 }
2826
2827 fn receive_icmp_error(
2828 core_ctx: &mut FakeIcmpCoreCtx<I>,
2829 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2830 _device: &FakeDeviceId,
2831 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2832 _original_dst_ip: SpecifiedAddr<I::Addr>,
2833 _original_body: &[u8],
2834 _err: I::ErrorCode,
2835 ) {
2836 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
2837 }
2838
2839 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
2840 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2841 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2842 _device: &FakeDeviceId,
2843 _src_ip: I::RecvSrcAddr,
2844 _dst_ip: SpecifiedAddr<I::Addr>,
2845 _buffer: B,
2846 _info: &mut LocalDeliveryPacketInfo<I, H>,
2847 _early_demux_socket: Option<!>,
2848 ) -> Result<(), (B, I::IcmpError)> {
2849 unimplemented!()
2850 }
2851 }
2852
2853 impl<I: IpLayerIpExt + IcmpTestIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>>
2854 for FakeIcmpCoreCtx<I>
2855 {
2856 type EchoTransportContext = FakeEchoIpTransportContext;
2857
2858 fn receive_icmp_error(
2859 &mut self,
2860 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2861 device: &Self::DeviceId,
2862 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2863 original_dst_ip: SpecifiedAddr<I::Addr>,
2864 original_proto: I::Proto,
2865 original_body: &[u8],
2866 err: I::ErrorCode,
2867 ) {
2868 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
2869 self.icmp.receive_icmp_error.push(err);
2870 if original_proto == I::ICMP_IP_PROTO {
2871 receive_ip_transport_icmp_error(
2872 self,
2873 bindings_ctx,
2874 device,
2875 original_src_ip,
2876 original_dst_ip,
2877 original_body,
2878 err,
2879 )
2880 }
2881 }
2882 }
2883
2884 impl<I: IpLayerIpExt + IcmpTestIpExt> IcmpSendContext<I, FakeIcmpBindingsCtx<I>>
2885 for FakeIcmpCoreCtx<I>
2886 {
2887 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
2888 &mut self,
2889 cb: F,
2890 ) -> O {
2891 cb(&mut self.icmp.error_send_bucket)
2892 }
2893 }
2894
2895 #[test]
2896 fn test_should_send_icmpv4_error() {
2897 let src_ip = TEST_ADDRS_V4.local_ip;
2898 let dst_ip = TEST_ADDRS_V4.remote_ip;
2899 let frame_dst = FrameDestination::Individual { local: () };
2900 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
2901 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
2902
2903 assert!(should_send_icmpv4_error(Some(frame_dst), src_ip, dst_ip));
2905 assert!(should_send_icmpv4_error(None, src_ip, dst_ip));
2906
2907 assert!(should_send_icmpv4_error(
2909 Some(frame_dst),
2910 Ipv4::LOOPBACK_ADDRESS,
2911 Ipv4::LOOPBACK_ADDRESS,
2912 ));
2913
2914 assert!(!should_send_icmpv4_error(
2916 Some(frame_dst),
2917 src_ip,
2918 Ipv4::LIMITED_BROADCAST_ADDRESS,
2919 ));
2920
2921 assert!(!should_send_icmpv4_error(Some(frame_dst), src_ip, multicast_ip_1,));
2923
2924 assert!(!should_send_icmpv4_error(Some(FrameDestination::Broadcast), src_ip, dst_ip,));
2926
2927 assert!(!should_send_icmpv4_error(
2929 Some(frame_dst),
2930 Ipv4::LIMITED_BROADCAST_ADDRESS,
2931 dst_ip,
2932 ));
2933
2934 assert!(!should_send_icmpv4_error(Some(frame_dst), multicast_ip_2, dst_ip));
2936
2937 assert!(!should_send_icmpv4_error(
2939 Some(frame_dst),
2940 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
2941 dst_ip,
2942 ));
2943 }
2944
2945 #[test]
2946 fn test_should_send_icmpv6_error() {
2947 let src_ip = TEST_ADDRS_V6.local_ip;
2948 let dst_ip = TEST_ADDRS_V6.remote_ip;
2949 let frame_dst = FrameDestination::Individual { local: () };
2950 let multicast_ip_1 =
2951 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
2952 let multicast_ip_2 =
2953 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
2954
2955 assert!(should_send_icmpv6_error(
2957 Some(frame_dst),
2958 src_ip,
2959 dst_ip,
2960 false ));
2962 assert!(should_send_icmpv6_error(
2963 None, src_ip, dst_ip, false ));
2965 assert!(should_send_icmpv6_error(
2966 Some(frame_dst),
2967 src_ip,
2968 dst_ip,
2969 true ));
2971
2972 assert!(should_send_icmpv6_error(
2974 Some(frame_dst),
2975 Ipv6::LOOPBACK_ADDRESS,
2976 Ipv6::LOOPBACK_ADDRESS,
2977 false ));
2979 assert!(should_send_icmpv6_error(
2980 Some(frame_dst),
2981 Ipv6::LOOPBACK_ADDRESS,
2982 Ipv6::LOOPBACK_ADDRESS,
2983 true ));
2985
2986 assert!(!should_send_icmpv6_error(
2989 Some(frame_dst),
2990 src_ip,
2991 multicast_ip_1,
2992 false ));
2994 assert!(should_send_icmpv6_error(
2995 Some(frame_dst),
2996 src_ip,
2997 multicast_ip_1,
2998 true ));
3000
3001 assert!(!should_send_icmpv6_error(
3004 Some(FrameDestination::Broadcast),
3005 src_ip,
3006 dst_ip,
3007 false ));
3009 assert!(should_send_icmpv6_error(
3010 Some(FrameDestination::Broadcast),
3011 src_ip,
3012 dst_ip,
3013 true ));
3015
3016 assert!(!should_send_icmpv6_error(
3018 Some(frame_dst),
3019 multicast_ip_2,
3020 dst_ip,
3021 false ));
3023 assert!(!should_send_icmpv6_error(
3024 Some(frame_dst),
3025 multicast_ip_2,
3026 dst_ip,
3027 true ));
3029
3030 assert!(!should_send_icmpv6_error(
3033 Some(FrameDestination::Broadcast),
3034 multicast_ip_2,
3035 dst_ip,
3036 false ));
3038 assert!(!should_send_icmpv6_error(
3039 Some(FrameDestination::Broadcast),
3040 multicast_ip_2,
3041 dst_ip,
3042 true ));
3044 assert!(!should_send_icmpv6_error(
3045 Some(frame_dst),
3046 multicast_ip_2,
3047 multicast_ip_1,
3048 false ));
3050 assert!(!should_send_icmpv6_error(
3051 Some(frame_dst),
3052 multicast_ip_2,
3053 multicast_ip_1,
3054 true ));
3056 }
3057
3058 #[derive(Default)]
3065 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3066 _marker: core::marker::PhantomData<I>,
3067 }
3068
3069 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3070 fn should_send_timestamp_reply(&self) -> bool {
3071 false
3072 }
3073 }
3074 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3075 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3076
3077 impl<I: IcmpTestIpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3078 fn new_ip_socket<O>(
3079 &mut self,
3080 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3081 args: IpSocketArgs<'_, Self::DeviceId, I, O>,
3082 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3083 where
3084 O: RouteResolutionOptions<I>,
3085 {
3086 self.ip_socket_ctx.new_ip_socket(bindings_ctx, args)
3087 }
3088
3089 fn send_ip_packet<S, O>(
3090 &mut self,
3091 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3092 socket: &IpSock<I, Self::WeakDeviceId>,
3093 body: S,
3094 options: &O,
3095 tx_meta: FakeTxMetadata,
3096 ) -> Result<(), IpSockSendError>
3097 where
3098 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
3099 S::Buffer: BufferMut,
3100 O: SendOptions<I> + RouteResolutionOptions<I>,
3101 {
3102 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3103 }
3104
3105 fn confirm_reachable<O>(
3106 &mut self,
3107 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3108 socket: &IpSock<I, Self::WeakDeviceId>,
3109 options: &O,
3110 ) where
3111 O: RouteResolutionOptions<I>,
3112 {
3113 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3114 }
3115 }
3116
3117 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3118 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3119 unimplemented!()
3120 }
3121
3122 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3123 unreachable!()
3124 }
3125
3126 fn handle_received_dad_packet(
3127 &mut self,
3128 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3129 _device_id: &Self::DeviceId,
3130 _addr: SpecifiedAddr<Ipv6Addr>,
3131 _probe_data: Option<NdpNonce<&'_ [u8]>>,
3132 ) -> Option<IpAddressState> {
3133 unimplemented!()
3134 }
3135 }
3136
3137 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3138 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3139 cb(&())
3140 }
3141
3142 fn get_local_addr_for_remote(
3143 &mut self,
3144 _device_id: &Self::DeviceId,
3145 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3146 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3147 unimplemented!()
3148 }
3149
3150 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3151 unimplemented!()
3152 }
3153 }
3154
3155 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3156 fn address_status_for_device(
3157 &mut self,
3158 _addr: SpecifiedAddr<Ipv6Addr>,
3159 _device_id: &Self::DeviceId,
3160 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3161 unimplemented!()
3162 }
3163 }
3164
3165 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3166 type LinkLayerAddr = Uninstantiable;
3167
3168 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3169 unimplemented!()
3170 }
3171
3172 fn set_discovered_retrans_timer(
3173 &mut self,
3174 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3175 _device_id: &Self::DeviceId,
3176 _retrans_timer: NonZeroDuration,
3177 ) {
3178 unimplemented!()
3179 }
3180
3181 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3182 unimplemented!()
3183 }
3184
3185 fn update_discovered_ipv6_route(
3186 &mut self,
3187 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3188 _device_id: &Self::DeviceId,
3189 _route: Ipv6DiscoveredRoute,
3190 _properties: Ipv6DiscoveredRouteProperties,
3191 _lifetime: Option<NonZeroNdpLifetime>,
3192 ) {
3193 unimplemented!()
3194 }
3195
3196 fn apply_slaac_update(
3197 &mut self,
3198 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3199 _device_id: &Self::DeviceId,
3200 _subnet: Subnet<Ipv6Addr>,
3201 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3202 _valid_lifetime: Option<NonZeroNdpLifetime>,
3203 ) {
3204 unimplemented!()
3205 }
3206
3207 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3208 &mut self,
3209 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3210 _device: &FakeDeviceId,
3211 _src_ip: Ipv6SourceAddr,
3212 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3213 _packet: MldPacket<B>,
3214 _header_info: &H,
3215 ) {
3216 unimplemented!()
3217 }
3218 }
3219
3220 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3221 fn send_ip_packet_from_device<S>(
3222 &mut self,
3223 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3224 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3225 _body: S,
3226 ) -> Result<(), IpSendFrameError<S>> {
3227 unimplemented!()
3228 }
3229
3230 fn send_ip_frame<S>(
3231 &mut self,
3232 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3233 _device: &Self::DeviceId,
3234 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3235 _body: S,
3236 ) -> Result<(), IpSendFrameError<S>>
3237 where
3238 S: NetworkSerializer,
3239 S::Buffer: BufferMut,
3240 {
3241 unimplemented!()
3242 }
3243 }
3244
3245 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3246 fn handle_neighbor_probe(
3247 &mut self,
3248 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3249 _device_id: &Self::DeviceId,
3250 _neighbor: SpecifiedAddr<Ipv6Addr>,
3251 _link_addr: &[u8],
3252 ) {
3253 unimplemented!()
3254 }
3255
3256 fn handle_neighbor_confirmation(
3257 &mut self,
3258 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3259 _device_id: &Self::DeviceId,
3260 _neighbor: SpecifiedAddr<Ipv6Addr>,
3261 _link_addr: Option<&[u8]>,
3262 _flags: ConfirmationFlags,
3263 ) {
3264 unimplemented!()
3265 }
3266
3267 fn flush_neighbor_table(
3268 &mut self,
3269 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3270 _device_id: &Self::DeviceId,
3271 ) {
3272 unimplemented!()
3273 }
3274 }
3275
3276 #[test]
3277 fn test_receive_icmpv4_error() {
3278 const ICMP_ID: u16 = 0x0F;
3281 const SEQ_NUM: u16 = 0xF0;
3282
3283 fn test_receive_icmpv4_error_helper<
3298 C: Debug,
3299 M: IcmpMessage<Ipv4, Code = C> + Debug,
3300 F: Fn(&FakeIcmpCtx<Ipv4>),
3301 >(
3302 original_packet: &mut [u8],
3303 code: C,
3304 msg: M,
3305 f: F,
3306 ) {
3307 set_logger_for_test();
3308
3309 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3310
3311 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3312 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3313 core_ctx,
3314 bindings_ctx,
3315 &FakeDeviceId,
3316 Ipv4SourceAddr::new(*TEST_ADDRS_V4.remote_ip).unwrap(),
3317 TEST_ADDRS_V4.local_ip,
3318 IcmpPacketBuilder::new(TEST_ADDRS_V4.remote_ip, TEST_ADDRS_V4.local_ip, code, msg)
3319 .wrap_body(Buf::new(original_packet, ..))
3320 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3321 .unwrap(),
3322 &mut LocalDeliveryPacketInfo::default(),
3323 None,
3324 )
3325 .unwrap();
3326 f(&ctx);
3327 }
3328 let mut buffer = EmptyBuf
3341 .wrap_in(IcmpPacketBuilder::<Ipv4, _>::new(
3342 TEST_ADDRS_V4.local_ip,
3343 TEST_ADDRS_V4.remote_ip,
3344 IcmpZeroCode,
3345 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3346 ))
3347 .wrap_in(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::<
3348 NetworkSerializationContext,
3349 >::new(
3350 TEST_ADDRS_V4.local_ip, TEST_ADDRS_V4.remote_ip, 64, Ipv4Proto::Icmp
3351 ))
3352 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3353 .unwrap();
3354
3355 test_receive_icmpv4_error_helper(
3356 buffer.as_mut(),
3357 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3358 IcmpDestUnreachable::default(),
3359 |CtxPair { core_ctx, bindings_ctx: _ }| {
3360 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3361 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3362 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3363 assert_eq!(
3364 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3365 1
3366 );
3367 let err = Icmpv4ErrorCode::DestUnreachable(
3368 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3369 IcmpDestUnreachable::default(),
3370 );
3371 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3372 },
3373 );
3374
3375 test_receive_icmpv4_error_helper(
3376 buffer.as_mut(),
3377 Icmpv4TimeExceededCode::TtlExpired,
3378 IcmpTimeExceeded::default(),
3379 |CtxPair { core_ctx, bindings_ctx: _ }| {
3380 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3381 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3382 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3383 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3384 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3385 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3386 },
3387 );
3388
3389 test_receive_icmpv4_error_helper(
3390 buffer.as_mut(),
3391 Icmpv4ParameterProblemCode::PointerIndicatesError,
3392 Icmpv4ParameterProblem::new(0),
3393 |CtxPair { core_ctx, bindings_ctx: _ }| {
3394 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3395 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3396 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3397 assert_eq!(
3398 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3399 1
3400 );
3401 let err = Icmpv4ErrorCode::ParameterProblem(
3402 Icmpv4ParameterProblemCode::PointerIndicatesError,
3403 );
3404 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3405 },
3406 );
3407
3408 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::<
3415 NetworkSerializationContext,
3416 >::new(
3417 TEST_ADDRS_V4.local_ip, TEST_ADDRS_V4.remote_ip, 64, Ipv4Proto::Icmp
3418 )
3419 .wrap_body(EmptyBuf)
3420 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3421 .unwrap();
3422
3423 test_receive_icmpv4_error_helper(
3424 buffer.as_mut(),
3425 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3426 IcmpDestUnreachable::default(),
3427 |CtxPair { core_ctx, bindings_ctx: _ }| {
3428 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3429 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3430 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3431 assert_eq!(
3432 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3433 1
3434 );
3435 let err = Icmpv4ErrorCode::DestUnreachable(
3436 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3437 IcmpDestUnreachable::default(),
3438 );
3439 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3440 },
3441 );
3442
3443 test_receive_icmpv4_error_helper(
3444 buffer.as_mut(),
3445 Icmpv4TimeExceededCode::TtlExpired,
3446 IcmpTimeExceeded::default(),
3447 |CtxPair { core_ctx, bindings_ctx: _ }| {
3448 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3449 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3450 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3451 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3452 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3453 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3454 },
3455 );
3456
3457 test_receive_icmpv4_error_helper(
3458 buffer.as_mut(),
3459 Icmpv4ParameterProblemCode::PointerIndicatesError,
3460 Icmpv4ParameterProblem::new(0),
3461 |CtxPair { core_ctx, bindings_ctx: _ }| {
3462 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3463 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3464 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3465 assert_eq!(
3466 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3467 1
3468 );
3469 let err = Icmpv4ErrorCode::ParameterProblem(
3470 Icmpv4ParameterProblemCode::PointerIndicatesError,
3471 );
3472 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3473 },
3474 );
3475
3476 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::<
3482 NetworkSerializationContext,
3483 >::new(
3484 TEST_ADDRS_V4.local_ip, TEST_ADDRS_V4.remote_ip, 64, IpProto::Udp.into()
3485 )
3486 .wrap_body(EmptyBuf)
3487 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3488 .unwrap();
3489
3490 test_receive_icmpv4_error_helper(
3491 buffer.as_mut(),
3492 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3493 IcmpDestUnreachable::default(),
3494 |CtxPair { core_ctx, bindings_ctx: _ }| {
3495 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3496 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3497 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3498 assert_eq!(
3499 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3500 1
3501 );
3502 let err = Icmpv4ErrorCode::DestUnreachable(
3503 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3504 IcmpDestUnreachable::default(),
3505 );
3506 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3507 },
3508 );
3509
3510 test_receive_icmpv4_error_helper(
3511 buffer.as_mut(),
3512 Icmpv4TimeExceededCode::TtlExpired,
3513 IcmpTimeExceeded::default(),
3514 |CtxPair { core_ctx, bindings_ctx: _ }| {
3515 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3516 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3517 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3518 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3519 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3520 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3521 },
3522 );
3523
3524 test_receive_icmpv4_error_helper(
3525 buffer.as_mut(),
3526 Icmpv4ParameterProblemCode::PointerIndicatesError,
3527 Icmpv4ParameterProblem::new(0),
3528 |CtxPair { core_ctx, bindings_ctx: _ }| {
3529 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3530 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3531 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3532 assert_eq!(
3533 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3534 1
3535 );
3536 let err = Icmpv4ErrorCode::ParameterProblem(
3537 Icmpv4ParameterProblemCode::PointerIndicatesError,
3538 );
3539 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3540 },
3541 );
3542 }
3543
3544 #[test]
3545 fn test_receive_icmpv6_error() {
3546 const ICMP_ID: u16 = 0x0F;
3549 const SEQ_NUM: u16 = 0xF0;
3550
3551 fn test_receive_icmpv6_error_helper<
3566 C: Debug,
3567 M: IcmpMessage<Ipv6, Code = C> + Debug,
3568 F: Fn(&FakeIcmpCtx<Ipv6>),
3569 >(
3570 original_packet: &mut [u8],
3571 code: C,
3572 msg: M,
3573 f: F,
3574 ) {
3575 set_logger_for_test();
3576
3577 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
3578 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3579 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
3580 core_ctx,
3581 bindings_ctx,
3582 &FakeDeviceId,
3583 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
3584 TEST_ADDRS_V6.local_ip,
3585 IcmpPacketBuilder::new(TEST_ADDRS_V6.remote_ip, TEST_ADDRS_V6.local_ip, code, msg)
3586 .wrap_body(Buf::new(original_packet, ..))
3587 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3588 .unwrap(),
3589 &mut LocalDeliveryPacketInfo::default(),
3590 None,
3591 )
3592 .unwrap();
3593 f(&ctx);
3594 }
3595 let mut buffer = EmptyBuf
3608 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3609 TEST_ADDRS_V6.local_ip,
3610 TEST_ADDRS_V6.remote_ip,
3611 IcmpZeroCode,
3612 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3613 ))
3614 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::<
3615 NetworkSerializationContext,
3616 >::new(
3617 TEST_ADDRS_V6.local_ip, TEST_ADDRS_V6.remote_ip, 64, Ipv6Proto::Icmpv6
3618 ))
3619 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3620 .unwrap();
3621
3622 test_receive_icmpv6_error_helper(
3623 buffer.as_mut(),
3624 Icmpv6DestUnreachableCode::NoRoute,
3625 IcmpDestUnreachable::default(),
3626 |CtxPair { core_ctx, bindings_ctx: _ }| {
3627 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3628 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3629 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3630 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3631 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3632 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3633 },
3634 );
3635
3636 test_receive_icmpv6_error_helper(
3637 buffer.as_mut(),
3638 Icmpv6TimeExceededCode::HopLimitExceeded,
3639 IcmpTimeExceeded::default(),
3640 |CtxPair { core_ctx, bindings_ctx: _ }| {
3641 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3642 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3643 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3644 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3645 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3646 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3647 },
3648 );
3649
3650 test_receive_icmpv6_error_helper(
3651 buffer.as_mut(),
3652 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3653 Icmpv6ParameterProblem::new(0),
3654 |CtxPair { core_ctx, bindings_ctx: _ }| {
3655 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3656 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3657 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3658 assert_eq!(
3659 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3660 1
3661 );
3662 let err = Icmpv6ErrorCode::ParameterProblem(
3663 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3664 );
3665 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3666 },
3667 );
3668
3669 let mut buffer = EmptyBuf
3676 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::<
3677 NetworkSerializationContext,
3678 >::new(
3679 TEST_ADDRS_V6.local_ip, TEST_ADDRS_V6.remote_ip, 64, Ipv6Proto::Icmpv6
3680 ))
3681 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3682 .unwrap();
3683
3684 test_receive_icmpv6_error_helper(
3685 buffer.as_mut(),
3686 Icmpv6DestUnreachableCode::NoRoute,
3687 IcmpDestUnreachable::default(),
3688 |CtxPair { core_ctx, bindings_ctx: _ }| {
3689 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3690 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3691 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3692 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3693 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3694 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3695 },
3696 );
3697
3698 test_receive_icmpv6_error_helper(
3699 buffer.as_mut(),
3700 Icmpv6TimeExceededCode::HopLimitExceeded,
3701 IcmpTimeExceeded::default(),
3702 |CtxPair { core_ctx, bindings_ctx: _ }| {
3703 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3704 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3705 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3706 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3707 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3708 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3709 },
3710 );
3711
3712 test_receive_icmpv6_error_helper(
3713 buffer.as_mut(),
3714 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3715 Icmpv6ParameterProblem::new(0),
3716 |CtxPair { core_ctx, bindings_ctx: _ }| {
3717 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3718 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3719 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3720 assert_eq!(
3721 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3722 1
3723 );
3724 let err = Icmpv6ErrorCode::ParameterProblem(
3725 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3726 );
3727 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3728 },
3729 );
3730
3731 let mut buffer = <Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::<
3737 NetworkSerializationContext,
3738 >::new(
3739 TEST_ADDRS_V6.local_ip, TEST_ADDRS_V6.remote_ip, 64, IpProto::Udp.into()
3740 )
3741 .wrap_body(EmptyBuf)
3742 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3743 .unwrap();
3744
3745 test_receive_icmpv6_error_helper(
3746 buffer.as_mut(),
3747 Icmpv6DestUnreachableCode::NoRoute,
3748 IcmpDestUnreachable::default(),
3749 |CtxPair { core_ctx, bindings_ctx: _ }| {
3750 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3751 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3752 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3753 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3754 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3755 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3756 },
3757 );
3758
3759 test_receive_icmpv6_error_helper(
3760 buffer.as_mut(),
3761 Icmpv6TimeExceededCode::HopLimitExceeded,
3762 IcmpTimeExceeded::default(),
3763 |CtxPair { core_ctx, bindings_ctx: _ }| {
3764 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3765 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3766 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3767 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3768 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3769 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3770 },
3771 );
3772
3773 test_receive_icmpv6_error_helper(
3774 buffer.as_mut(),
3775 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3776 Icmpv6ParameterProblem::new(0),
3777 |CtxPair { core_ctx, bindings_ctx: _ }| {
3778 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3779 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3780 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3781 assert_eq!(
3782 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3783 1
3784 );
3785 let err = Icmpv6ErrorCode::ParameterProblem(
3786 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3787 );
3788 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3789 },
3790 );
3791 }
3792
3793 #[test]
3794 fn test_error_rate_limit() {
3795 set_logger_for_test();
3796
3797 fn send_icmpv4_ttl_expired_helper(
3799 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3800 ) {
3801 let error = Icmpv4Error::TtlExpired;
3802 core_ctx.send_icmp_error_message(
3803 bindings_ctx,
3804 Some(&FakeDeviceId),
3805 Some(FrameDestination::Individual { local: () }),
3806 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3807 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3808 EmptyBuf,
3809 error,
3810 0,
3811 packet_formats::ip::IpProto::Udp.into(),
3812 &Default::default(),
3813 );
3814 let count = core_ctx.icmp.tx_counters.time_exceeded.ttl_expired.get();
3815 assert!(count >= 1, "{count} >= 1");
3816 }
3817
3818 fn send_icmpv4_parameter_problem_helper(
3820 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3821 ) {
3822 let error = Icmpv4Error::ParameterProblem {
3823 code: Icmpv4ParameterProblemCode::PointerIndicatesError,
3824 pointer: 0,
3825 };
3826 core_ctx.send_icmp_error_message(
3827 bindings_ctx,
3828 Some(&FakeDeviceId),
3829 Some(FrameDestination::Individual { local: () }),
3830 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3831 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3832 EmptyBuf,
3833 error,
3834 0,
3835 packet_formats::ip::IpProto::Udp.into(),
3836 &Default::default(),
3837 );
3838 let count = core_ctx.icmp.tx_counters.parameter_problem.pointer_indicates_error.get();
3839 assert!(count >= 1, "{count} >= 1");
3840 }
3841
3842 fn send_icmpv4_dest_unreachable_helper(
3844 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3845 ) {
3846 core_ctx.send_icmp_error_message(
3847 bindings_ctx,
3848 Some(&FakeDeviceId),
3849 Some(FrameDestination::Individual { local: () }),
3850 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3851 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3852 EmptyBuf,
3853 Icmpv4Error::NetUnreachable,
3854 0,
3855 packet_formats::ip::IpProto::Udp.into(),
3856 &Default::default(),
3857 );
3858 let count = core_ctx.icmp.tx_counters.dest_unreachable.dest_network_unreachable.get();
3859 assert!(count >= 1, "{count} >= 1");
3860 }
3861
3862 fn send_icmpv6_ttl_expired_helper(
3864 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3865 ) {
3866 core_ctx.send_icmp_error_message(
3867 bindings_ctx,
3868 Some(&FakeDeviceId),
3869 Some(FrameDestination::Individual { local: () }),
3870 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3871 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3872 EmptyBuf,
3873 Icmpv6Error::TtlExpired,
3874 0,
3875 Ipv6Proto::NoNextHeader,
3876 &Default::default(),
3877 );
3878 let count = core_ctx.icmp.tx_counters.time_exceeded.hop_limit_exceeded.get();
3879 assert!(count >= 1, "{count} >= 1");
3880 }
3881
3882 fn send_icmpv6_packet_too_big_helper(
3884 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3885 ) {
3886 core_ctx.send_icmp_error_message(
3887 bindings_ctx,
3888 Some(&FakeDeviceId),
3889 Some(FrameDestination::Individual { local: () }),
3890 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3891 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3892 EmptyBuf,
3893 Icmpv6Error::PacketTooBig { mtu: Mtu::new(1280) },
3894 0,
3895 Ipv6Proto::NoNextHeader,
3896 &Default::default(),
3897 );
3898 let count = core_ctx.icmp.tx_counters.packet_too_big.get();
3899 assert!(count >= 1, "{count} >= 1");
3900 }
3901
3902 fn send_icmpv6_parameter_problem_helper(
3904 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3905 ) {
3906 let error = Icmpv6Error::ParameterProblem {
3907 code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
3908 pointer: 0,
3909 allow_dst_multicast: false,
3910 };
3911 core_ctx.send_icmp_error_message(
3912 bindings_ctx,
3913 Some(&FakeDeviceId),
3914 Some(FrameDestination::Individual { local: () }),
3915 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3916 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3917 EmptyBuf,
3918 error,
3919 0,
3920 Ipv6Proto::NoNextHeader,
3921 &Default::default(),
3922 );
3923 let count = core_ctx.icmp.tx_counters.parameter_problem.erroneous_header_field.get();
3924 assert!(count >= 1, "{count} >= 1");
3925 }
3926
3927 fn send_icmpv6_dest_unreachable_helper(
3929 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3930 ) {
3931 core_ctx.send_icmp_error_message(
3932 bindings_ctx,
3933 Some(&FakeDeviceId),
3934 Some(FrameDestination::Individual { local: () }),
3935 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3936 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3937 EmptyBuf,
3938 Icmpv6Error::NetUnreachable,
3939 0,
3940 Ipv6Proto::NoNextHeader,
3941 &Default::default(),
3942 );
3943 let count = core_ctx.icmp.tx_counters.dest_unreachable.no_route.get();
3944 assert!(count >= 1, "{count} >= 1");
3945 }
3946
3947 fn run_test<I: IcmpTestIpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
3951 with_errors_per_second: W,
3952 send: S,
3953 ) {
3954 const ERRORS_PER_SECOND: u64 = 64;
3968
3969 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
3970
3971 for i in 0..ERRORS_PER_SECOND {
3972 send(&mut ctx);
3973 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
3974 }
3975
3976 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3977 send(&mut ctx);
3978 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3979
3980 let mut ctx = with_errors_per_second(0);
3984 send(&mut ctx);
3985 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3986 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
3987 send(&mut ctx);
3988 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3989 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
3990 send(&mut ctx);
3991 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3992 }
3993
3994 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
3995 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
3996 }
3997 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
3998 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
3999 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
4000
4001 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
4002 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4003 }
4004
4005 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
4006 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
4007 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
4008 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
4009 }
4010}