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 } = info;
975 let ReceiveIpPacketMeta { broadcast: _, transparent_override, parsing_context: _ } = meta;
976 if let Some(delivery) = transparent_override {
977 unreachable!(
978 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
979 transparent proxy rules can only be configured for TCP and UDP packets"
980 );
981 }
982
983 trace!(
984 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet({}, {})",
985 src_ip, dst_ip
986 );
987 let packet =
988 match buffer.parse_with::<_, Icmpv4Packet<_>>(IcmpParseArgs::new(src_ip, dst_ip)) {
989 Ok(packet) => packet,
990 Err(_) => return Ok(()), };
992
993 match packet {
994 Icmpv4Packet::EchoRequest(echo_request) => {
995 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_request.increment();
996
997 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
998 let req = *echo_request.message();
999 let code = echo_request.code();
1000 let (local_ip, remote_ip) = (dst_ip, src_ip);
1001 debug!(
1002 "replying to ICMP echo request from {remote_ip} to {local_ip}%{device:?}: \
1003 id={}, seq={}",
1004 req.id(),
1005 req.seq()
1006 );
1007 send_icmp_reply(
1008 core_ctx,
1009 bindings_ctx,
1010 device,
1011 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1012 SocketIpAddr::new_ipv4_specified(local_ip),
1013 |src_ip| {
1014 IcmpPacketBuilder::<Ipv4, _>::new(src_ip, *remote_ip, code, req.reply())
1015 .wrap_body(buffer)
1016 },
1017 &WithMarks(marks),
1018 );
1019 } else {
1020 trace!(
1021 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1022 Received echo request with an unspecified source address"
1023 );
1024 }
1025 }
1026 Icmpv4Packet::EchoReply(echo_reply) => {
1027 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_reply.increment();
1028 trace!(
1029 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1030 Received an EchoReply message"
1031 );
1032 let parse_metadata = echo_reply.parse_metadata();
1033 buffer.undo_parse(parse_metadata);
1034 return <CC::EchoTransportContext
1035 as IpTransportContext<Ipv4, BC, CC>>::receive_ip_packet(
1036 core_ctx,
1037 bindings_ctx,
1038 device,
1039 src_ip,
1040 dst_ip,
1041 buffer,
1042 info,
1043 None,
1044 );
1045 }
1046 Icmpv4Packet::TimestampRequest(timestamp_request) => {
1047 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1048 .timestamp_request
1049 .increment();
1050 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
1051 if core_ctx.should_send_timestamp_reply() {
1052 trace!(
1053 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1054 receive_ip_packet: Responding to Timestamp Request message"
1055 );
1056 const NOW: u32 = 0x80000000;
1075 let reply = timestamp_request.message().reply(NOW, NOW);
1076 let (local_ip, remote_ip) = (dst_ip, src_ip);
1077 buffer.shrink_front_to(0);
1084 send_icmp_reply(
1085 core_ctx,
1086 bindings_ctx,
1087 device,
1088 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1089 SocketIpAddr::new_ipv4_specified(local_ip),
1090 |src_ip| {
1091 IcmpPacketBuilder::<Ipv4, _>::new(
1092 src_ip,
1093 *remote_ip,
1094 IcmpZeroCode,
1095 reply,
1096 )
1097 .wrap_body(buffer)
1098 },
1099 &WithMarks(marks),
1100 );
1101 } else {
1102 trace!(
1103 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1104 receive_ip_packet: Silently ignoring Timestamp Request message"
1105 );
1106 }
1107 } else {
1108 trace!(
1109 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1110 receive_ip_packet: Received timestamp request with an unspecified source \
1111 address"
1112 );
1113 }
1114 }
1115 Icmpv4Packet::TimestampReply(_) => {
1116 debug!(
1119 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1120 Received unsolicited Timestamp Reply message"
1121 );
1122 }
1123 Icmpv4Packet::DestUnreachable(dest_unreachable) => {
1124 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1125 .dest_unreachable
1126 .increment_code(dest_unreachable.code());
1127 trace!(
1128 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1129 Received a Destination Unreachable message"
1130 );
1131
1132 let error = if dest_unreachable.code()
1133 == Icmpv4DestUnreachableCode::FragmentationRequired
1134 {
1135 let mtu = if let Some(next_hop_mtu) = dest_unreachable.message().next_hop_mtu()
1136 {
1137 core_ctx.update_pmtu_if_less(
1147 bindings_ctx,
1148 dst_ip.get(),
1149 src_ip.get(),
1150 Mtu::new(u32::from(next_hop_mtu.get())),
1151 )
1152 } else {
1153 let (original_packet_buf, inner_body) = dest_unreachable.body().bytes();
1175 debug_assert!(inner_body.is_none());
1177 if original_packet_buf.len() >= 4 {
1178 let total_len =
1182 u16::from_be_bytes(original_packet_buf[2..4].try_into().unwrap());
1183
1184 trace!(
1185 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1186 receive_ip_packet: Next-Hop MTU is 0 so using the next best PMTU \
1187 value from {total_len}"
1188 );
1189
1190 core_ctx.update_pmtu_next_lower(
1191 bindings_ctx,
1192 dst_ip.get(),
1193 src_ip.get(),
1194 Mtu::new(u32::from(total_len)),
1195 )
1196 } else {
1197 trace!(
1202 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1203 receive_ip_packet: Original packet buf is too small to get \
1204 original packet len so ignoring"
1205 );
1206 None
1207 }
1208 };
1209 mtu.and_then(|mtu| {
1210 let mtu = u16::try_from(mtu.get()).unwrap_or(u16::MAX);
1211 let mtu = NonZeroU16::new(mtu)?;
1212 Some(Icmpv4ErrorCode::DestUnreachable(
1213 dest_unreachable.code(),
1214 IcmpDestUnreachable::new_for_frag_req(mtu),
1215 ))
1216 })
1217 } else {
1218 Some(Icmpv4ErrorCode::DestUnreachable(
1219 dest_unreachable.code(),
1220 *dest_unreachable.message(),
1221 ))
1222 };
1223
1224 if let Some(error) = error {
1225 receive_icmpv4_error(core_ctx, bindings_ctx, device, &dest_unreachable, error);
1226 }
1227 }
1228 Icmpv4Packet::TimeExceeded(time_exceeded) => {
1229 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1230 .time_exceeded
1231 .increment_code(time_exceeded.code());
1232 trace!(
1233 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1234 Received a Time Exceeded message"
1235 );
1236
1237 receive_icmpv4_error(
1238 core_ctx,
1239 bindings_ctx,
1240 device,
1241 &time_exceeded,
1242 Icmpv4ErrorCode::TimeExceeded(time_exceeded.code()),
1243 );
1244 }
1245 Icmpv4Packet::Redirect(_) => {
1247 debug!(
1248 "Unimplemented: <IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1249 receive_ip_packet::redirect"
1250 )
1251 }
1252 Icmpv4Packet::ParameterProblem(parameter_problem) => {
1253 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1254 .parameter_problem
1255 .increment_code(parameter_problem.code());
1256 trace!(
1257 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1258 Received a Parameter Problem message"
1259 );
1260
1261 receive_icmpv4_error(
1262 core_ctx,
1263 bindings_ctx,
1264 device,
1265 ¶meter_problem,
1266 Icmpv4ErrorCode::ParameterProblem(parameter_problem.code()),
1267 );
1268 }
1269 }
1270
1271 Ok(())
1272 }
1273}
1274
1275#[allow(missing_docs)]
1278pub enum NdpMessage {
1279 NeighborSolicitation {
1280 message: NeighborSolicitation,
1281 code: <NeighborSolicitation as IcmpMessage<Ipv6>>::Code,
1282 },
1283
1284 RouterSolicitation {
1285 message: RouterSolicitation,
1286 code: <RouterSolicitation as IcmpMessage<Ipv6>>::Code,
1287 },
1288
1289 NeighborAdvertisement {
1290 message: NeighborAdvertisement,
1291 code: <NeighborAdvertisement as IcmpMessage<Ipv6>>::Code,
1292 },
1293}
1294
1295pub fn send_ndp_packet<BC, CC, S>(
1297 core_ctx: &mut CC,
1298 bindings_ctx: &mut BC,
1299 device_id: &CC::DeviceId,
1300 src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1301 dst_ip: SpecifiedAddr<Ipv6Addr>,
1302 body: S,
1303 message: NdpMessage,
1304) -> Result<(), IpSendFrameError<S>>
1305where
1306 CC: IpLayerHandler<Ipv6, BC>,
1307 S: NetworkSerializer + NetworkPartialSerializer,
1308 S::Buffer: BufferMut,
1309{
1310 macro_rules! send {
1311 ($message:expr, $code:expr) => {{
1312 let mut ser = IcmpPacketBuilder::<Ipv6, _>::new(
1314 src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
1315 dst_ip.get(),
1316 $code,
1317 $message,
1318 )
1319 .wrap_body(body);
1320 match IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
1321 core_ctx,
1322 bindings_ctx,
1323 SendIpPacketMeta {
1324 device: device_id,
1325 src_ip,
1326 dst_ip,
1327 destination: IpPacketDestination::from_addr(dst_ip),
1328 ttl: NonZeroU8::new(REQUIRED_NDP_IP_PACKET_HOP_LIMIT),
1329 proto: Ipv6Proto::Icmpv6,
1330 mtu: Mtu::no_limit(),
1331 dscp_and_ecn: DscpAndEcn::default(),
1332 },
1333 DynTransportSerializer::new(&mut ser),
1334 ) {
1335 Ok(()) => Ok(()),
1336 Err(e) => Err(e
1337 .map_serializer(|s| {
1338 let _: DynTransportSerializer<'_, _> = s;
1340 })
1341 .map_serializer(|()| ser.into_inner())),
1342 }
1343 }};
1344 }
1345
1346 match message {
1347 NdpMessage::NeighborSolicitation { message, code } => send!(message, code),
1348 NdpMessage::RouterSolicitation { message, code } => send!(message, code),
1349 NdpMessage::NeighborAdvertisement { message, code } => send!(message, code),
1350 }
1351}
1352
1353fn send_neighbor_advertisement<
1354 BC,
1355 CC: Ipv6DeviceHandler<BC>
1356 + IpDeviceHandler<Ipv6, BC>
1357 + IpLayerHandler<Ipv6, BC>
1358 + CounterContext<NdpCounters>,
1359>(
1360 core_ctx: &mut CC,
1361 bindings_ctx: &mut BC,
1362 device_id: &CC::DeviceId,
1363 solicited: bool,
1364 device_addr: UnicastAddr<Ipv6Addr>,
1365 dst_ip: SpecifiedAddr<Ipv6Addr>,
1366) {
1367 core_ctx.counters().tx.neighbor_advertisement.increment();
1368 debug!("send_neighbor_advertisement from {:?} to {:?}", device_addr, dst_ip);
1369 debug_assert!(dst_ip.is_valid_unicast() || (!solicited && dst_ip.is_multicast()));
1376
1377 let src_ll = core_ctx.get_link_layer_addr(&device_id);
1384
1385 let advertisement = NeighborAdvertisement::new(
1387 core_ctx.is_router_device(&device_id),
1388 solicited,
1389 true, device_addr.get(),
1402 );
1403 let _: Result<(), _> = send_ndp_packet(
1404 core_ctx,
1405 bindings_ctx,
1406 &device_id,
1407 Some(device_addr.into_specified()),
1408 dst_ip,
1409 OptionSequenceBuilder::new(
1410 src_ll
1411 .as_ref()
1412 .map(Ipv6LinkLayerAddr::as_bytes)
1413 .map(NdpOptionBuilder::TargetLinkLayerAddress)
1414 .iter(),
1415 )
1416 .into_serializer(),
1417 NdpMessage::NeighborAdvertisement { message: advertisement, code: IcmpZeroCode },
1418 );
1419}
1420
1421fn receive_ndp_packet<
1422 B: SplitByteSlice,
1423 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1424 CC: InnerIcmpContext<Ipv6, BC>
1425 + Ipv6DeviceHandler<BC>
1426 + IpDeviceHandler<Ipv6, BC>
1427 + IpDeviceIngressStateContext<Ipv6>
1428 + NudIpHandler<Ipv6, BC>
1429 + IpLayerHandler<Ipv6, BC>
1430 + CounterContext<NdpCounters>,
1431 H: IpHeaderInfo<Ipv6>,
1432>(
1433 core_ctx: &mut CC,
1434 bindings_ctx: &mut BC,
1435 device_id: &CC::DeviceId,
1436 src_ip: Ipv6SourceAddr,
1437 dst_ip: SpecifiedAddr<Ipv6Addr>,
1438 packet: NdpPacket<B>,
1439 header_info: &H,
1440) {
1441 if header_info.hop_limit() != REQUIRED_NDP_IP_PACKET_HOP_LIMIT {
1459 trace!("dropping NDP packet from {src_ip} with invalid hop limit");
1460 return;
1461 }
1462
1463 match packet {
1464 NdpPacket::RouterSolicitation(_) => {}
1465 NdpPacket::Redirect(_) => {}
1467 NdpPacket::NeighborSolicitation(ref p) => {
1468 let target_address = p.message().target_address();
1475 let target_address = match UnicastAddr::new(*target_address) {
1476 Some(a) => a,
1477 None => {
1478 trace!(
1479 "dropping NS from {} with non-unicast target={:?}",
1480 src_ip, target_address
1481 );
1482 return;
1483 }
1484 };
1485
1486 let (source_link_addr, nonce) = p.body().iter().fold(
1488 (None, None),
1489 |(found_source_link_addr, found_nonce), option| {
1490 match option {
1491 NdpOption::Nonce(nonce) => (found_source_link_addr, Some(nonce)),
1492 NdpOption::SourceLinkLayerAddress(source_link_addr) => {
1493 (Some(source_link_addr), found_nonce)
1494 }
1495 NdpOption::Mtu(_)
1503 | NdpOption::PrefixInformation(_)
1504 | NdpOption::RecursiveDnsServer(_)
1505 | NdpOption::RedirectedHeader { .. }
1506 | NdpOption::RouteInformation(_)
1507 | NdpOption::TargetLinkLayerAddress(_) => {
1508 (found_source_link_addr, found_nonce)
1509 }
1510 }
1511 },
1512 );
1513
1514 if src_ip == Ipv6SourceAddr::Unspecified {
1515 if target_address.get().to_solicited_node_address().get() != dst_ip.get() {
1524 debug!(
1525 "dropping NS from {} for {} with invalid IPv6 dst ({}).",
1526 src_ip, target_address, dst_ip
1527 );
1528 return;
1529 }
1530 if let Some(addr) = source_link_addr {
1535 debug!(
1536 "dropping NS from {} for {} with source link-layer addr option ({:?}).",
1537 src_ip, target_address, addr
1538 );
1539 return;
1540 }
1541 }
1542
1543 core_ctx.counters().rx.neighbor_solicitation.increment();
1544
1545 match src_ip {
1546 Ipv6SourceAddr::Unspecified => {
1547 match IpDeviceHandler::handle_received_dad_packet(
1557 core_ctx,
1558 bindings_ctx,
1559 &device_id,
1560 target_address.into_specified(),
1561 nonce,
1562 ) {
1563 Some(IpAddressState::Assigned) => {
1564 send_neighbor_advertisement(
1568 core_ctx,
1569 bindings_ctx,
1570 &device_id,
1571 false,
1572 target_address,
1573 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified(),
1574 );
1575 }
1576 Some(IpAddressState::Tentative) => {
1577 }
1580 Some(IpAddressState::Unavailable) | None => {
1581 }
1584 }
1585
1586 return;
1587 }
1588 Ipv6SourceAddr::Unicast(src_ip) => {
1589 match core_ctx
1591 .address_status_for_device(target_address.into_specified(), device_id)
1592 {
1593 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned) => {}
1594 AddressStatus::Present(
1595 Ipv6PresentAddressStatus::UnicastTentative
1596 | Ipv6PresentAddressStatus::Multicast,
1597 )
1598 | AddressStatus::Unassigned => {
1599 return;
1603 }
1604 }
1605
1606 if let Some(link_addr) = source_link_addr {
1607 NudIpHandler::handle_neighbor_probe(
1608 core_ctx,
1609 bindings_ctx,
1610 &device_id,
1611 src_ip.into_specified(),
1612 link_addr,
1613 );
1614 }
1615
1616 send_neighbor_advertisement(
1617 core_ctx,
1618 bindings_ctx,
1619 &device_id,
1620 true,
1621 target_address,
1622 src_ip.into_specified(),
1623 );
1624 }
1625 }
1626 }
1627 NdpPacket::NeighborAdvertisement(ref p) => {
1628 let target_address = p.message().target_address();
1632
1633 let target_address = match UnicastAddr::new(*target_address) {
1640 Some(a) => a,
1641 None => {
1642 debug!(
1643 "dropping NA from {} with non-unicast target={:?}",
1644 src_ip, target_address
1645 );
1646 return;
1647 }
1648 };
1649 if let Some(dst_ip) = MulticastAddr::new(dst_ip.get())
1653 && p.message().solicited_flag()
1654 {
1655 debug!(
1656 "dropping NA from {} with solicited flag and multicast dst {}",
1657 src_ip, dst_ip
1658 );
1659 return;
1660 }
1661
1662 core_ctx.counters().rx.neighbor_advertisement.increment();
1663
1664 let nonce = None;
1668 match IpDeviceHandler::handle_received_dad_packet(
1669 core_ctx,
1670 bindings_ctx,
1671 &device_id,
1672 target_address.into_specified(),
1673 nonce,
1674 ) {
1675 Some(IpAddressState::Assigned) => {
1676 error!(
1694 "NA from {src_ip} with target address {target_address} that is also \
1695 assigned on device {device_id:?}",
1696 );
1697 }
1698 Some(IpAddressState::Tentative) => {
1699 return;
1702 }
1703 Some(IpAddressState::Unavailable) | None => {
1704 }
1708 }
1709
1710 let link_addr = p.body().iter().find_map(|o| o.target_link_layer_address());
1711
1712 NudIpHandler::handle_neighbor_confirmation(
1713 core_ctx,
1714 bindings_ctx,
1715 &device_id,
1716 target_address.into_specified(),
1717 link_addr,
1718 ConfirmationFlags {
1719 solicited_flag: p.message().solicited_flag(),
1720 override_flag: p.message().override_flag(),
1721 },
1722 );
1723 }
1724 NdpPacket::RouterAdvertisement(ref p) => {
1725 let src_ip = match src_ip {
1738 Ipv6SourceAddr::Unicast(ip) => match LinkLocalUnicastAddr::new(*ip) {
1739 Some(ip) => ip,
1740 None => return,
1741 },
1742 Ipv6SourceAddr::Unspecified => return,
1743 };
1744
1745 let ra = p.message();
1746 debug!("received router advertisement from {:?}: {:?}", src_ip, ra);
1747 core_ctx.counters().rx.router_advertisement.increment();
1748
1749 if let Some(retransmit_timer) = ra.retransmit_timer() {
1756 Ipv6DeviceHandler::set_discovered_retrans_timer(
1757 core_ctx,
1758 bindings_ctx,
1759 &device_id,
1760 retransmit_timer,
1761 );
1762 }
1763
1764 if let Some(hop_limit) = ra.current_hop_limit() {
1771 trace!(
1772 "receive_ndp_packet: NDP RA: updating device's hop limit to {:?} for router: {:?}",
1773 ra.current_hop_limit(),
1774 src_ip
1775 );
1776 IpDeviceHandler::set_default_hop_limit(core_ctx, &device_id, hop_limit);
1777 }
1778
1779 Ipv6DeviceHandler::update_discovered_ipv6_route(
1780 core_ctx,
1781 bindings_ctx,
1782 &device_id,
1783 Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) },
1784 Ipv6DiscoveredRouteProperties { route_preference: p.message().preference().into() },
1785 p.message().router_lifetime().map(NonZeroNdpLifetime::Finite),
1786 );
1787
1788 for option in p.body().iter() {
1789 match option {
1790 NdpOption::TargetLinkLayerAddress(_)
1791 | NdpOption::RedirectedHeader { .. }
1792 | NdpOption::RecursiveDnsServer(_)
1793 | NdpOption::Nonce(_) => {}
1794 NdpOption::SourceLinkLayerAddress(addr) => {
1795 debug!("processing SourceLinkLayerAddress option in RA: {:?}", addr);
1796 NudIpHandler::handle_neighbor_probe(
1822 core_ctx,
1823 bindings_ctx,
1824 &device_id,
1825 {
1826 let src_ip: UnicastAddr<_> = src_ip.into_addr();
1827 src_ip.into_specified()
1828 },
1829 addr,
1830 );
1831 }
1832 NdpOption::PrefixInformation(prefix_info) => {
1833 debug!("processing Prefix Information option in RA: {:?}", prefix_info);
1834 if prefix_info.prefix().is_link_local() {
1852 continue;
1853 }
1854
1855 let subnet = match prefix_info.subnet() {
1856 Ok(subnet) => subnet,
1857 Err(err) => match err {
1858 SubnetError::PrefixTooLong | SubnetError::HostBitsSet => continue,
1859 },
1860 };
1861
1862 match UnicastAddr::new(subnet.network()) {
1863 Some(UnicastAddr { .. }) => {}
1864 None => continue,
1865 }
1866
1867 let valid_lifetime = prefix_info.valid_lifetime();
1868
1869 if prefix_info.on_link_flag() {
1870 Ipv6DeviceHandler::update_discovered_ipv6_route(
1871 core_ctx,
1872 bindings_ctx,
1873 &device_id,
1874 Ipv6DiscoveredRoute { subnet, gateway: None },
1875 Ipv6DiscoveredRouteProperties {
1876 route_preference: RoutePreference::Medium,
1877 },
1878 valid_lifetime,
1879 )
1880 }
1881
1882 if prefix_info.autonomous_address_configuration_flag() {
1883 Ipv6DeviceHandler::apply_slaac_update(
1884 core_ctx,
1885 bindings_ctx,
1886 &device_id,
1887 subnet,
1888 prefix_info.preferred_lifetime(),
1889 valid_lifetime,
1890 );
1891 }
1892 }
1893 NdpOption::RouteInformation(rio) => {
1894 debug!("processing Route Information option in RA: {:?}", rio);
1895 Ipv6DeviceHandler::update_discovered_ipv6_route(
1896 core_ctx,
1897 bindings_ctx,
1898 &device_id,
1899 Ipv6DiscoveredRoute {
1900 subnet: rio.prefix().clone(),
1901 gateway: Some(src_ip),
1902 },
1903 Ipv6DiscoveredRouteProperties {
1904 route_preference: rio.preference().into(),
1905 },
1906 rio.route_lifetime(),
1907 )
1908 }
1909 NdpOption::Mtu(mtu) => {
1910 debug!("processing MTU option in RA: {:?}", mtu);
1911 Ipv6DeviceHandler::set_link_mtu(core_ctx, &device_id, Mtu::new(mtu));
1915 }
1916 }
1917 }
1918
1919 bindings_ctx.on_event(RouterAdvertisementEvent {
1920 options_bytes: Box::from(p.body().bytes()),
1921 source: **src_ip,
1922 device: device_id.clone(),
1923 });
1924 }
1925 }
1926}
1927
1928impl<
1929 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1930 CC: InnerIcmpContext<Ipv6, BC>
1931 + InnerIcmpContext<Ipv6, BC>
1932 + Ipv6DeviceHandler<BC>
1933 + IpDeviceHandler<Ipv6, BC>
1934 + IpDeviceIngressStateContext<Ipv6>
1935 + PmtuHandler<Ipv6, BC>
1936 + NudIpHandler<Ipv6, BC>
1937 + IpLayerHandler<Ipv6, BC>
1938 + CounterContext<IcmpRxCounters<Ipv6>>
1939 + CounterContext<IcmpTxCounters<Ipv6>>
1940 + CounterContext<NdpCounters>,
1941> IpTransportContext<Ipv6, BC, CC> for IcmpIpTransportContext
1942{
1943 type EarlyDemuxSocket = !;
1944
1945 fn early_demux<B: ParseBuffer>(
1946 _core_ctx: &mut CC,
1947 _device: &CC::DeviceId,
1948 _src_ip: Ipv6Addr,
1949 _dst_ip: Ipv6Addr,
1950 _buffer: B,
1951 ) -> Option<Self::EarlyDemuxSocket> {
1952 None
1953 }
1954
1955 fn receive_icmp_error(
1956 core_ctx: &mut CC,
1957 bindings_ctx: &mut BC,
1958 device: &CC::DeviceId,
1959 original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1960 original_dst_ip: SpecifiedAddr<Ipv6Addr>,
1961 original_body: &[u8],
1962 err: Icmpv6ErrorCode,
1963 ) {
1964 receive_ip_transport_icmp_error(
1965 core_ctx,
1966 bindings_ctx,
1967 device,
1968 original_src_ip,
1969 original_dst_ip,
1970 original_body,
1971 err,
1972 )
1973 }
1974
1975 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
1976 core_ctx: &mut CC,
1977 bindings_ctx: &mut BC,
1978 device: &CC::DeviceId,
1979 src_ip: Ipv6SourceAddr,
1980 dst_ip: SpecifiedAddr<Ipv6Addr>,
1981 mut buffer: B,
1982 info: &mut LocalDeliveryPacketInfo<Ipv6, H>,
1983 _early_demux_socket: Option<!>,
1984 ) -> Result<(), (B, Icmpv6Error)> {
1985 let LocalDeliveryPacketInfo { meta, header_info, marks } = info;
1986 let ReceiveIpPacketMeta { broadcast: _, transparent_override, parsing_context: _ } = meta;
1987 if let Some(delivery) = transparent_override {
1988 unreachable!(
1989 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
1990 transparent proxy rules can only be configured for TCP and UDP packets"
1991 );
1992 }
1993
1994 trace!(
1995 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet({:?}, {})",
1996 src_ip, dst_ip
1997 );
1998
1999 let packet = match buffer
2000 .parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(src_ip.get(), dst_ip))
2001 {
2002 Ok(packet) => packet,
2003 Err(_) => return Ok(()), };
2005
2006 match packet {
2007 Icmpv6Packet::EchoRequest(echo_request) => {
2008 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_request.increment();
2009
2010 if let Some(src_ip) = SocketIpAddr::new_from_ipv6_source(src_ip) {
2011 match SocketIpAddr::try_from(dst_ip) {
2012 Ok(dst_ip) => {
2013 let req = *echo_request.message();
2014 let code = echo_request.code();
2015 let (local_ip, remote_ip) = (dst_ip, src_ip);
2016 debug!(
2017 "replying to ICMP echo request from {remote_ip}: id={}, seq={}",
2018 req.id(),
2019 req.seq()
2020 );
2021 send_icmp_reply(
2022 core_ctx,
2023 bindings_ctx,
2024 device,
2025 remote_ip,
2026 local_ip,
2027 |src_ip| {
2028 IcmpPacketBuilder::<Ipv6, _>::new(
2029 src_ip,
2030 remote_ip.addr(),
2031 code,
2032 req.reply(),
2033 )
2034 .wrap_body(buffer)
2035 },
2036 &WithMarks(marks),
2037 );
2038 }
2039 Err(AddrIsMappedError {}) => {
2040 trace!(
2041 "IpTransportContext<Ipv6>::receive_ip_packet: Received echo request with an ipv4-mapped-ipv6 destination address"
2042 );
2043 }
2044 }
2045 } else {
2046 trace!(
2047 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received echo request with an unspecified source address"
2048 );
2049 }
2050 }
2051 Icmpv6Packet::EchoReply(echo_reply) => {
2052 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_reply.increment();
2053 trace!(
2054 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received an EchoReply message"
2055 );
2056 let parse_metadata = echo_reply.parse_metadata();
2057 buffer.undo_parse(parse_metadata);
2058 return <CC::EchoTransportContext
2059 as IpTransportContext<Ipv6, BC, CC>>::receive_ip_packet(
2060 core_ctx,
2061 bindings_ctx,
2062 device,
2063 src_ip,
2064 dst_ip,
2065 buffer,
2066 info,
2067 None
2068 );
2069 }
2070 Icmpv6Packet::Ndp(packet) => receive_ndp_packet(
2071 core_ctx,
2072 bindings_ctx,
2073 device,
2074 src_ip,
2075 dst_ip,
2076 packet,
2077 header_info,
2078 ),
2079 Icmpv6Packet::PacketTooBig(packet_too_big) => {
2080 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2081 .packet_too_big
2082 .increment();
2083 trace!(
2084 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received a Packet Too Big message"
2085 );
2086 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2087 let mtu = core_ctx.update_pmtu_if_less(
2097 bindings_ctx,
2098 dst_ip.get(),
2099 src_ip.get(),
2100 Mtu::new(packet_too_big.message().mtu()),
2101 );
2102 if let Some(mtu) = mtu {
2103 receive_icmpv6_error(
2104 core_ctx,
2105 bindings_ctx,
2106 device,
2107 &packet_too_big,
2108 Icmpv6ErrorCode::PacketTooBig(mtu),
2109 );
2110 }
2111 }
2112 }
2113 Icmpv6Packet::Mld(packet) => {
2114 core_ctx.receive_mld_packet(
2115 bindings_ctx,
2116 &device,
2117 src_ip,
2118 dst_ip,
2119 packet,
2120 header_info,
2121 );
2122 }
2123 Icmpv6Packet::DestUnreachable(dest_unreachable) => {
2124 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2125 .dest_unreachable
2126 .increment_code(dest_unreachable.code());
2127 receive_icmpv6_error(
2128 core_ctx,
2129 bindings_ctx,
2130 device,
2131 &dest_unreachable,
2132 Icmpv6ErrorCode::DestUnreachable(dest_unreachable.code()),
2133 )
2134 }
2135 Icmpv6Packet::TimeExceeded(time_exceeded) => {
2136 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2137 .time_exceeded
2138 .increment_code(time_exceeded.code());
2139 receive_icmpv6_error(
2140 core_ctx,
2141 bindings_ctx,
2142 device,
2143 &time_exceeded,
2144 Icmpv6ErrorCode::TimeExceeded(time_exceeded.code()),
2145 )
2146 }
2147 Icmpv6Packet::ParameterProblem(parameter_problem) => {
2148 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2149 .parameter_problem
2150 .increment_code(parameter_problem.code());
2151 receive_icmpv6_error(
2152 core_ctx,
2153 bindings_ctx,
2154 device,
2155 ¶meter_problem,
2156 Icmpv6ErrorCode::ParameterProblem(parameter_problem.code()),
2157 )
2158 }
2159 }
2160
2161 Ok(())
2162 }
2163}
2164
2165#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2166struct WithMarks<'a>(&'a Marks);
2167
2168impl<'a> OptionDelegationMarker for WithMarks<'a> {}
2169
2170impl<'a, I: IpExt> DelegatedRouteResolutionOptions<I> for WithMarks<'a> {
2171 fn marks(&self) -> &Marks {
2172 let Self(marks) = self;
2173 marks
2174 }
2175}
2176
2177impl<'a, I: IpExt> DelegatedSendOptions<I> for WithMarks<'a> {}
2178
2179fn send_icmp_reply<I, BC, CC, S, F, O>(
2190 core_ctx: &mut CC,
2191 bindings_ctx: &mut BC,
2192 device: &CC::DeviceId,
2193 original_src_ip: SocketIpAddr<I::Addr>,
2194 original_dst_ip: SocketIpAddr<I::Addr>,
2195 get_body_from_src_ip: F,
2196 ip_options: &O,
2197) where
2198 I: IpExt + FilterIpExt + IcmpCountersIpExt,
2199 CC: IpSocketHandler<I, BC> + DeviceIdContext<AnyDevice> + CounterContext<IcmpTxCounters<I>>,
2200 BC: TxMetadataBindingsTypes,
2201 S: DynamicTransportSerializer<I>,
2202 F: FnOnce(SpecifiedAddr<I::Addr>) -> S,
2203 O: SendOptions<I> + RouteResolutionOptions<I>,
2204{
2205 trace!("send_icmp_reply({:?}, {}, {})", device, original_src_ip, original_dst_ip);
2206 core_ctx.counters().reply.increment();
2207 let tx_metadata: BC::TxMetadata = Default::default();
2208
2209 let egress_device = (original_dst_ip.as_ref().is_multicast()
2213 || original_dst_ip.as_ref().must_have_zone())
2214 .then_some(EitherDeviceId::Strong(device));
2215
2216 core_ctx
2217 .send_oneshot_ip_packet_with_dyn_serializer(
2218 bindings_ctx,
2219 IpSocketArgs {
2220 device: egress_device,
2221 local_ip: IpDeviceAddr::new_from_socket_ip_addr(original_dst_ip),
2222 remote_ip: original_src_ip,
2223 proto: I::ICMP_IP_PROTO,
2224 options: ip_options,
2225 },
2226 tx_metadata,
2227 |src_ip| get_body_from_src_ip(src_ip.into()),
2228 )
2229 .unwrap_or_else(|err| {
2230 debug!("failed to send ICMP reply: {}", err);
2231 })
2232}
2233
2234fn receive_icmpv4_error<
2239 BC: IcmpBindingsContext,
2240 CC: InnerIcmpContext<Ipv4, BC>,
2241 B: SplitByteSlice,
2242 M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>,
2243>(
2244 core_ctx: &mut CC,
2245 bindings_ctx: &mut BC,
2246 device: &CC::DeviceId,
2247 packet: &IcmpPacket<Ipv4, B, M>,
2248 err: Icmpv4ErrorCode,
2249) {
2250 packet.with_original_packet(|res| match res {
2251 Ok(original_packet) => {
2252 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2253 Some(ip) => ip,
2254 None => {
2255 trace!("receive_icmpv4_error: Got ICMP error message whose original IPv4 packet contains an unspecified destination address; discarding");
2256 return;
2257 },
2258 };
2259 InnerIcmpContext::receive_icmp_error(
2260 core_ctx,
2261 bindings_ctx,
2262 device,
2263 SpecifiedAddr::new(original_packet.src_ip()),
2264 dst_ip,
2265 original_packet.proto(),
2266 original_packet.body().into_inner(),
2267 err,
2268 );
2269 }
2270 Err(_) => debug!(
2271 "receive_icmpv4_error: Got ICMP error message with unparsable original IPv4 packet"
2272 ),
2273 })
2274}
2275
2276fn receive_icmpv6_error<
2281 BC: IcmpBindingsContext,
2282 CC: InnerIcmpContext<Ipv6, BC>,
2283 B: SplitByteSlice,
2284 M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>,
2285>(
2286 core_ctx: &mut CC,
2287 bindings_ctx: &mut BC,
2288 device: &CC::DeviceId,
2289 packet: &IcmpPacket<Ipv6, B, M>,
2290 err: Icmpv6ErrorCode,
2291) {
2292 packet.with_original_packet(|res| match res {
2293 Ok(original_packet) => {
2294 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2295 Some(ip)=>ip,
2296 None => {
2297 trace!("receive_icmpv6_error: Got ICMP error message whose original IPv6 packet contains an unspecified destination address; discarding");
2298 return;
2299 },
2300 };
2301 match original_packet.body_proto() {
2302 Ok((body, proto)) => {
2303 InnerIcmpContext::receive_icmp_error(
2304 core_ctx,
2305 bindings_ctx,
2306 device,
2307 SpecifiedAddr::new(original_packet.src_ip()),
2308 dst_ip,
2309 proto,
2310 body.into_inner(),
2311 err,
2312 );
2313 }
2314 Err(ExtHdrParseError) => {
2315 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");
2316 return;
2319 }
2320 }
2321 }
2322 Err(_body) => debug!(
2323 "receive_icmpv6_error: Got ICMPv6 error message with unparsable original IPv6 packet"
2324 ),
2325 })
2326}
2327
2328fn send_icmpv4_error_message<B, BC, CC>(
2329 core_ctx: &mut CC,
2330 bindings_ctx: &mut BC,
2331 device: Option<&CC::DeviceId>,
2332 frame_dst: Option<LocalFrameDestination>,
2333 original_src_ip: SocketIpAddr<Ipv4Addr>,
2334 original_dst_ip: SocketIpAddr<Ipv4Addr>,
2335 message: Icmpv4ErrorMessage,
2336 mut original_packet: B,
2337 header_len: usize,
2338 marks: &Marks,
2339) where
2340 B: BufferMut,
2341 BC: IcmpBindingsContext,
2342 CC: IcmpSendContext<Ipv4, BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2343{
2344 if !should_send_icmpv4_error(frame_dst, original_src_ip.into(), original_dst_ip.into()) {
2348 return;
2349 }
2350
2351 original_packet.shrink_back_to(header_len + 64);
2354
2355 let tx_metadata: BC::TxMetadata = Default::default();
2356
2357 macro_rules! send {
2358 ($message:expr, $code:expr) => {{
2359 let _ = try_send_error!(
2362 core_ctx,
2363 bindings_ctx,
2364 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2365 bindings_ctx,
2366 IpSocketArgs {
2367 device: device.map(EitherDeviceId::Strong),
2368 local_ip: None,
2369 remote_ip: original_src_ip,
2370 proto: Ipv4Proto::Icmp,
2371 options: &WithMarks(marks),
2372 },
2373 tx_metadata,
2374 |local_ip| {
2375 IcmpPacketBuilder::<Ipv4, _>::new(
2376 local_ip.addr(),
2377 original_src_ip.addr(),
2378 $code,
2379 $message,
2380 )
2381 .wrap_body(original_packet)
2382 },
2383 )
2384 );
2385 }};
2386 }
2387
2388 match message {
2389 Icmpv4ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2390 Icmpv4ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2391 Icmpv4ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2392 }
2393}
2394
2395fn send_icmpv6_error_message<B, BC, CC>(
2396 core_ctx: &mut CC,
2397 bindings_ctx: &mut BC,
2398 device: Option<&CC::DeviceId>,
2399 frame_dst: Option<LocalFrameDestination>,
2400 original_src_ip: SocketIpAddr<Ipv6Addr>,
2401 original_dst_ip: SocketIpAddr<Ipv6Addr>,
2402 message: Icmpv6ErrorMessage,
2403 original_packet: B,
2404 allow_dst_multicast: bool,
2405 marks: &Marks,
2406) where
2407 B: BufferMut,
2408 BC: IcmpBindingsContext,
2409 CC: IcmpSendContext<Ipv6, BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2410{
2411 if !should_send_icmpv6_error(
2415 frame_dst,
2416 original_src_ip.into(),
2417 original_dst_ip.into(),
2418 allow_dst_multicast,
2419 ) {
2420 return;
2421 }
2422
2423 struct Icmpv6ErrorOptions<'a>(&'a Marks);
2424 impl<'a> OptionDelegationMarker for Icmpv6ErrorOptions<'a> {}
2425 impl<'a> DelegatedSendOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2426 fn mtu(&self) -> Mtu {
2427 Ipv6::MINIMUM_LINK_MTU
2428 }
2429 }
2430 impl<'a> DelegatedRouteResolutionOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2431 fn marks(&self) -> &Marks {
2432 let Self(marks) = self;
2433 marks
2434 }
2435 }
2436
2437 let tx_metadata: BC::TxMetadata = Default::default();
2438
2439 macro_rules! send {
2440 ($message:expr, $code:expr) => {{
2441 let _ = try_send_error!(
2444 core_ctx,
2445 bindings_ctx,
2446 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2447 bindings_ctx,
2448 IpSocketArgs {
2449 device: device.map(EitherDeviceId::Strong),
2450 local_ip: None,
2451 remote_ip: original_src_ip,
2452 proto: Ipv6Proto::Icmpv6,
2453 options: &Icmpv6ErrorOptions(marks),
2454 },
2455 tx_metadata,
2456 |local_ip| {
2457 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
2458 local_ip.addr(),
2459 original_src_ip.addr(),
2460 $code,
2461 $message,
2462 );
2463
2464 icmp_builder.wrap_body(TruncatingSerializer::new(
2467 original_packet,
2468 TruncateDirection::DiscardBack,
2469 ))
2470 },
2471 )
2472 );
2473 }};
2474 }
2475
2476 match message {
2477 Icmpv6ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2478 Icmpv6ErrorMessage::PacketTooBig { message, code } => send!(message, code),
2479 Icmpv6ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2480 Icmpv6ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2481 }
2482}
2483
2484fn should_send_icmpv4_error(
2507 frame_dst: Option<LocalFrameDestination>,
2508 src_ip: SpecifiedAddr<Ipv4Addr>,
2509 dst_ip: SpecifiedAddr<Ipv4Addr>,
2510) -> bool {
2511 !(dst_ip.is_multicast()
2531 || dst_ip.is_limited_broadcast()
2532 || frame_dst.is_some_and(|dst| dst.is_broadcast())
2533 || src_ip.is_limited_broadcast()
2534 || src_ip.is_multicast()
2535 || src_ip.is_class_e())
2536}
2537
2538fn should_send_icmpv6_error(
2568 frame_dst: Option<LocalFrameDestination>,
2569 src_ip: SpecifiedAddr<Ipv6Addr>,
2570 dst_ip: SpecifiedAddr<Ipv6Addr>,
2571 allow_dst_multicast: bool,
2572) -> bool {
2573 let multicast_frame_dst = match frame_dst {
2576 Some(FrameDestination::Individual { local: () }) | None => false,
2577 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
2578 };
2579 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
2580 return false;
2581 }
2582 if src_ip.is_multicast() {
2583 return false;
2584 }
2585 true
2586}
2587
2588fn is_icmp_error_or_redirect_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
2600 proto == I::ICMP_IP_PROTO
2601 && peek_message_type::<I::IcmpMessageType>(buf)
2602 .map(IcmpMessageType::is_error_or_redirect)
2603 .unwrap_or(true)
2604}
2605
2606#[cfg(any(test, feature = "testutils"))]
2608pub(crate) mod testutil {
2609 use alloc::vec::Vec;
2610 use net_types::ethernet::Mac;
2611 use net_types::ip::{Ipv6, Ipv6Addr};
2612 use netstack3_base::NetworkSerializationContext;
2613 use packet::{Buf, InnerPacketBuilder as _, NestableSerializer as _, Serializer as _};
2614 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
2615 use packet_formats::icmp::ndp::{
2616 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
2617 };
2618 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
2619 use packet_formats::ip::Ipv6Proto;
2620 use packet_formats::ipv6::Ipv6PacketBuilder;
2621
2622 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
2623
2624 pub fn neighbor_advertisement_ip_packet(
2627 src_ip: Ipv6Addr,
2628 dst_ip: Ipv6Addr,
2629 router_flag: bool,
2630 solicited_flag: bool,
2631 override_flag: bool,
2632 mac: Mac,
2633 ) -> Buf<Vec<u8>> {
2634 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
2635 .into_serializer()
2636 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2637 src_ip,
2638 dst_ip,
2639 IcmpZeroCode,
2640 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
2641 ))
2642 .wrap_in(Ipv6PacketBuilder::new(
2643 src_ip,
2644 dst_ip,
2645 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2646 Ipv6Proto::Icmpv6,
2647 ))
2648 .serialize_vec_outer(&mut NetworkSerializationContext::default())
2649 .unwrap()
2650 .unwrap_b()
2651 }
2652
2653 pub fn neighbor_solicitation_ip_packet(
2656 src_ip: Ipv6Addr,
2657 dst_ip: Ipv6Addr,
2658 target_addr: Ipv6Addr,
2659 mac: Mac,
2660 ) -> Buf<Vec<u8>> {
2661 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
2662 .into_serializer()
2663 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2664 src_ip,
2665 dst_ip,
2666 IcmpZeroCode,
2667 NeighborSolicitation::new(target_addr),
2668 ))
2669 .wrap_in(Ipv6PacketBuilder::new(
2670 src_ip,
2671 dst_ip,
2672 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2673 Ipv6Proto::Icmpv6,
2674 ))
2675 .serialize_vec_outer(&mut NetworkSerializationContext::default())
2676 .unwrap()
2677 .unwrap_b()
2678 }
2679}
2680
2681#[cfg(test)]
2682mod tests {
2683 use alloc::vec;
2684 use alloc::vec::Vec;
2685 use packet_formats::icmp::ndp::options::NdpNonce;
2686
2687 use core::fmt::Debug;
2688 use core::time::Duration;
2689
2690 use net_types::ip::Subnet;
2691 use netstack3_base::testutil::{
2692 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId,
2693 TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt, set_logger_for_test,
2694 };
2695 use netstack3_base::{CtxPair, NetworkSerializationContext, Uninstantiable};
2696 use netstack3_filter::TransportPacketSerializer;
2697 use packet::{Buf, EmptyBuf, NestableSerializer as _, Serializer as _};
2698 use packet_formats::icmp::mld::MldPacket;
2699 use packet_formats::ip::IpProto;
2700 use packet_formats::utils::NonZeroDuration;
2701
2702 use super::*;
2703 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
2704 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
2705 use crate::internal::socket::{
2706 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
2707 };
2708 use crate::socket::RouteResolutionOptions;
2709
2710 pub(super) trait IcmpTestIpExt:
2711 TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt
2712 {
2713 }
2714 impl<I: TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt> IcmpTestIpExt for I {}
2715
2716 type InnerIpSocketCtx<I> = FakeCoreCtx<
2718 FakeIpSocketCtx<I, FakeDeviceId>,
2719 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
2720 FakeDeviceId,
2721 >;
2722
2723 pub(super) struct FakeIcmpCoreCtx<I: IcmpTestIpExt> {
2725 ip_socket_ctx: InnerIpSocketCtx<I>,
2726 icmp: FakeIcmpCoreCtxState<I>,
2727 }
2728
2729 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
2731 (),
2732 RouterAdvertisementEvent<FakeDeviceId>,
2733 FakeIcmpBindingsCtxState<I>,
2734 (),
2735 >;
2736
2737 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
2741
2742 pub(super) struct FakeIcmpCoreCtxState<I: IcmpTestIpExt> {
2743 error_send_bucket: TokenBucket<FakeInstant>,
2744 receive_icmp_error: Vec<I::ErrorCode>,
2745 rx_counters: IcmpRxCounters<I>,
2746 tx_counters: IcmpTxCounters<I>,
2747 ndp_counters: NdpCounters,
2748 }
2749
2750 impl<I: IcmpTestIpExt> FakeIcmpCoreCtx<I> {
2751 fn with_errors_per_second(errors_per_second: u64) -> Self {
2752 Self {
2753 icmp: FakeIcmpCoreCtxState {
2754 error_send_bucket: TokenBucket::new(errors_per_second),
2755 receive_icmp_error: Default::default(),
2756 rx_counters: Default::default(),
2757 tx_counters: Default::default(),
2758 ndp_counters: Default::default(),
2759 },
2760 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
2761 core::iter::once(FakeDeviceConfig {
2762 device: FakeDeviceId,
2763 local_ips: vec![I::TEST_ADDRS.local_ip],
2764 remote_ips: vec![I::TEST_ADDRS.remote_ip],
2765 }),
2766 )),
2767 }
2768 }
2769 }
2770
2771 impl<I: IcmpTestIpExt> Default for FakeIcmpCoreCtx<I> {
2772 fn default() -> Self {
2773 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
2774 }
2775 }
2776
2777 impl<I: IcmpTestIpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
2778 type DeviceId = FakeDeviceId;
2779 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
2780 }
2781
2782 impl<I: IcmpTestIpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
2783 impl<I: IcmpTestIpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
2784
2785 impl<I: IcmpTestIpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
2786 fn counters(&self) -> &IcmpRxCounters<I> {
2787 &self.icmp.rx_counters
2788 }
2789 }
2790
2791 impl<I: IcmpTestIpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
2792 fn counters(&self) -> &IcmpTxCounters<I> {
2793 &self.icmp.tx_counters
2794 }
2795 }
2796
2797 impl<I: IcmpTestIpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
2798 fn counters(&self) -> &NdpCounters {
2799 &self.icmp.ndp_counters
2800 }
2801 }
2802
2803 pub enum FakeEchoIpTransportContext {}
2804
2805 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
2806
2807 impl<I> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
2808 for FakeEchoIpTransportContext
2809 where
2810 I: IcmpTestIpExt + IpLayerIpExt,
2811 {
2812 type EarlyDemuxSocket = !;
2813
2814 fn early_demux<B: ParseBuffer>(
2815 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2816 _device: &FakeDeviceId,
2817 _src_ip: I::Addr,
2818 _dst_ip: I::Addr,
2819 _buffer: B,
2820 ) -> Option<Self::EarlyDemuxSocket> {
2821 None
2822 }
2823
2824 fn receive_icmp_error(
2825 core_ctx: &mut FakeIcmpCoreCtx<I>,
2826 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2827 _device: &FakeDeviceId,
2828 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2829 _original_dst_ip: SpecifiedAddr<I::Addr>,
2830 _original_body: &[u8],
2831 _err: I::ErrorCode,
2832 ) {
2833 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
2834 }
2835
2836 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
2837 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2838 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2839 _device: &FakeDeviceId,
2840 _src_ip: I::RecvSrcAddr,
2841 _dst_ip: SpecifiedAddr<I::Addr>,
2842 _buffer: B,
2843 _info: &mut LocalDeliveryPacketInfo<I, H>,
2844 _early_demux_socket: Option<!>,
2845 ) -> Result<(), (B, I::IcmpError)> {
2846 unimplemented!()
2847 }
2848 }
2849
2850 impl<I: IpLayerIpExt + IcmpTestIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>>
2851 for FakeIcmpCoreCtx<I>
2852 {
2853 type EchoTransportContext = FakeEchoIpTransportContext;
2854
2855 fn receive_icmp_error(
2856 &mut self,
2857 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2858 device: &Self::DeviceId,
2859 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2860 original_dst_ip: SpecifiedAddr<I::Addr>,
2861 original_proto: I::Proto,
2862 original_body: &[u8],
2863 err: I::ErrorCode,
2864 ) {
2865 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
2866 self.icmp.receive_icmp_error.push(err);
2867 if original_proto == I::ICMP_IP_PROTO {
2868 receive_ip_transport_icmp_error(
2869 self,
2870 bindings_ctx,
2871 device,
2872 original_src_ip,
2873 original_dst_ip,
2874 original_body,
2875 err,
2876 )
2877 }
2878 }
2879 }
2880
2881 impl<I: IpLayerIpExt + IcmpTestIpExt> IcmpSendContext<I, FakeIcmpBindingsCtx<I>>
2882 for FakeIcmpCoreCtx<I>
2883 {
2884 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
2885 &mut self,
2886 cb: F,
2887 ) -> O {
2888 cb(&mut self.icmp.error_send_bucket)
2889 }
2890 }
2891
2892 #[test]
2893 fn test_should_send_icmpv4_error() {
2894 let src_ip = TEST_ADDRS_V4.local_ip;
2895 let dst_ip = TEST_ADDRS_V4.remote_ip;
2896 let frame_dst = FrameDestination::Individual { local: () };
2897 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
2898 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
2899
2900 assert!(should_send_icmpv4_error(Some(frame_dst), src_ip, dst_ip));
2902 assert!(should_send_icmpv4_error(None, src_ip, dst_ip));
2903
2904 assert!(should_send_icmpv4_error(
2906 Some(frame_dst),
2907 Ipv4::LOOPBACK_ADDRESS,
2908 Ipv4::LOOPBACK_ADDRESS,
2909 ));
2910
2911 assert!(!should_send_icmpv4_error(
2913 Some(frame_dst),
2914 src_ip,
2915 Ipv4::LIMITED_BROADCAST_ADDRESS,
2916 ));
2917
2918 assert!(!should_send_icmpv4_error(Some(frame_dst), src_ip, multicast_ip_1,));
2920
2921 assert!(!should_send_icmpv4_error(Some(FrameDestination::Broadcast), src_ip, dst_ip,));
2923
2924 assert!(!should_send_icmpv4_error(
2926 Some(frame_dst),
2927 Ipv4::LIMITED_BROADCAST_ADDRESS,
2928 dst_ip,
2929 ));
2930
2931 assert!(!should_send_icmpv4_error(Some(frame_dst), multicast_ip_2, dst_ip));
2933
2934 assert!(!should_send_icmpv4_error(
2936 Some(frame_dst),
2937 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
2938 dst_ip,
2939 ));
2940 }
2941
2942 #[test]
2943 fn test_should_send_icmpv6_error() {
2944 let src_ip = TEST_ADDRS_V6.local_ip;
2945 let dst_ip = TEST_ADDRS_V6.remote_ip;
2946 let frame_dst = FrameDestination::Individual { local: () };
2947 let multicast_ip_1 =
2948 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
2949 let multicast_ip_2 =
2950 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
2951
2952 assert!(should_send_icmpv6_error(
2954 Some(frame_dst),
2955 src_ip,
2956 dst_ip,
2957 false ));
2959 assert!(should_send_icmpv6_error(
2960 None, src_ip, dst_ip, false ));
2962 assert!(should_send_icmpv6_error(
2963 Some(frame_dst),
2964 src_ip,
2965 dst_ip,
2966 true ));
2968
2969 assert!(should_send_icmpv6_error(
2971 Some(frame_dst),
2972 Ipv6::LOOPBACK_ADDRESS,
2973 Ipv6::LOOPBACK_ADDRESS,
2974 false ));
2976 assert!(should_send_icmpv6_error(
2977 Some(frame_dst),
2978 Ipv6::LOOPBACK_ADDRESS,
2979 Ipv6::LOOPBACK_ADDRESS,
2980 true ));
2982
2983 assert!(!should_send_icmpv6_error(
2986 Some(frame_dst),
2987 src_ip,
2988 multicast_ip_1,
2989 false ));
2991 assert!(should_send_icmpv6_error(
2992 Some(frame_dst),
2993 src_ip,
2994 multicast_ip_1,
2995 true ));
2997
2998 assert!(!should_send_icmpv6_error(
3001 Some(FrameDestination::Broadcast),
3002 src_ip,
3003 dst_ip,
3004 false ));
3006 assert!(should_send_icmpv6_error(
3007 Some(FrameDestination::Broadcast),
3008 src_ip,
3009 dst_ip,
3010 true ));
3012
3013 assert!(!should_send_icmpv6_error(
3015 Some(frame_dst),
3016 multicast_ip_2,
3017 dst_ip,
3018 false ));
3020 assert!(!should_send_icmpv6_error(
3021 Some(frame_dst),
3022 multicast_ip_2,
3023 dst_ip,
3024 true ));
3026
3027 assert!(!should_send_icmpv6_error(
3030 Some(FrameDestination::Broadcast),
3031 multicast_ip_2,
3032 dst_ip,
3033 false ));
3035 assert!(!should_send_icmpv6_error(
3036 Some(FrameDestination::Broadcast),
3037 multicast_ip_2,
3038 dst_ip,
3039 true ));
3041 assert!(!should_send_icmpv6_error(
3042 Some(frame_dst),
3043 multicast_ip_2,
3044 multicast_ip_1,
3045 false ));
3047 assert!(!should_send_icmpv6_error(
3048 Some(frame_dst),
3049 multicast_ip_2,
3050 multicast_ip_1,
3051 true ));
3053 }
3054
3055 #[derive(Default)]
3062 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3063 _marker: core::marker::PhantomData<I>,
3064 }
3065
3066 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3067 fn should_send_timestamp_reply(&self) -> bool {
3068 false
3069 }
3070 }
3071 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3072 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3073
3074 impl<I: IcmpTestIpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3075 fn new_ip_socket<O>(
3076 &mut self,
3077 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3078 args: IpSocketArgs<'_, Self::DeviceId, I, O>,
3079 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3080 where
3081 O: RouteResolutionOptions<I>,
3082 {
3083 self.ip_socket_ctx.new_ip_socket(bindings_ctx, args)
3084 }
3085
3086 fn send_ip_packet<S, O>(
3087 &mut self,
3088 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3089 socket: &IpSock<I, Self::WeakDeviceId>,
3090 body: S,
3091 options: &O,
3092 tx_meta: FakeTxMetadata,
3093 ) -> Result<(), IpSockSendError>
3094 where
3095 S: TransportPacketSerializer<I>,
3096 S::Buffer: BufferMut,
3097 O: SendOptions<I> + RouteResolutionOptions<I>,
3098 {
3099 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3100 }
3101
3102 fn confirm_reachable<O>(
3103 &mut self,
3104 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3105 socket: &IpSock<I, Self::WeakDeviceId>,
3106 options: &O,
3107 ) where
3108 O: RouteResolutionOptions<I>,
3109 {
3110 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3111 }
3112 }
3113
3114 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3115 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3116 unimplemented!()
3117 }
3118
3119 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3120 unreachable!()
3121 }
3122
3123 fn handle_received_dad_packet(
3124 &mut self,
3125 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3126 _device_id: &Self::DeviceId,
3127 _addr: SpecifiedAddr<Ipv6Addr>,
3128 _probe_data: Option<NdpNonce<&'_ [u8]>>,
3129 ) -> Option<IpAddressState> {
3130 unimplemented!()
3131 }
3132 }
3133
3134 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3135 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3136 cb(&())
3137 }
3138
3139 fn get_local_addr_for_remote(
3140 &mut self,
3141 _device_id: &Self::DeviceId,
3142 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3143 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3144 unimplemented!()
3145 }
3146
3147 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3148 unimplemented!()
3149 }
3150 }
3151
3152 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3153 fn address_status_for_device(
3154 &mut self,
3155 _addr: SpecifiedAddr<Ipv6Addr>,
3156 _device_id: &Self::DeviceId,
3157 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3158 unimplemented!()
3159 }
3160 }
3161
3162 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3163 type LinkLayerAddr = Uninstantiable;
3164
3165 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3166 unimplemented!()
3167 }
3168
3169 fn set_discovered_retrans_timer(
3170 &mut self,
3171 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3172 _device_id: &Self::DeviceId,
3173 _retrans_timer: NonZeroDuration,
3174 ) {
3175 unimplemented!()
3176 }
3177
3178 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3179 unimplemented!()
3180 }
3181
3182 fn update_discovered_ipv6_route(
3183 &mut self,
3184 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3185 _device_id: &Self::DeviceId,
3186 _route: Ipv6DiscoveredRoute,
3187 _properties: Ipv6DiscoveredRouteProperties,
3188 _lifetime: Option<NonZeroNdpLifetime>,
3189 ) {
3190 unimplemented!()
3191 }
3192
3193 fn apply_slaac_update(
3194 &mut self,
3195 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3196 _device_id: &Self::DeviceId,
3197 _subnet: Subnet<Ipv6Addr>,
3198 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3199 _valid_lifetime: Option<NonZeroNdpLifetime>,
3200 ) {
3201 unimplemented!()
3202 }
3203
3204 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3205 &mut self,
3206 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3207 _device: &FakeDeviceId,
3208 _src_ip: Ipv6SourceAddr,
3209 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3210 _packet: MldPacket<B>,
3211 _header_info: &H,
3212 ) {
3213 unimplemented!()
3214 }
3215 }
3216
3217 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3218 fn send_ip_packet_from_device<S>(
3219 &mut self,
3220 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3221 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3222 _body: S,
3223 ) -> Result<(), IpSendFrameError<S>> {
3224 unimplemented!()
3225 }
3226
3227 fn send_ip_frame<S>(
3228 &mut self,
3229 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3230 _device: &Self::DeviceId,
3231 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3232 _body: S,
3233 ) -> Result<(), IpSendFrameError<S>>
3234 where
3235 S: NetworkSerializer,
3236 S::Buffer: BufferMut,
3237 {
3238 unimplemented!()
3239 }
3240 }
3241
3242 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3243 fn handle_neighbor_probe(
3244 &mut self,
3245 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3246 _device_id: &Self::DeviceId,
3247 _neighbor: SpecifiedAddr<Ipv6Addr>,
3248 _link_addr: &[u8],
3249 ) {
3250 unimplemented!()
3251 }
3252
3253 fn handle_neighbor_confirmation(
3254 &mut self,
3255 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3256 _device_id: &Self::DeviceId,
3257 _neighbor: SpecifiedAddr<Ipv6Addr>,
3258 _link_addr: Option<&[u8]>,
3259 _flags: ConfirmationFlags,
3260 ) {
3261 unimplemented!()
3262 }
3263
3264 fn flush_neighbor_table(
3265 &mut self,
3266 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3267 _device_id: &Self::DeviceId,
3268 ) {
3269 unimplemented!()
3270 }
3271 }
3272
3273 #[test]
3274 fn test_receive_icmpv4_error() {
3275 const ICMP_ID: u16 = 0x0F;
3278 const SEQ_NUM: u16 = 0xF0;
3279
3280 fn test_receive_icmpv4_error_helper<
3295 C: Debug,
3296 M: IcmpMessage<Ipv4, Code = C> + Debug,
3297 F: Fn(&FakeIcmpCtx<Ipv4>),
3298 >(
3299 original_packet: &mut [u8],
3300 code: C,
3301 msg: M,
3302 f: F,
3303 ) {
3304 set_logger_for_test();
3305
3306 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3307
3308 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3309 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3310 core_ctx,
3311 bindings_ctx,
3312 &FakeDeviceId,
3313 Ipv4SourceAddr::new(*TEST_ADDRS_V4.remote_ip).unwrap(),
3314 TEST_ADDRS_V4.local_ip,
3315 IcmpPacketBuilder::new(TEST_ADDRS_V4.remote_ip, TEST_ADDRS_V4.local_ip, code, msg)
3316 .wrap_body(Buf::new(original_packet, ..))
3317 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3318 .unwrap(),
3319 &mut LocalDeliveryPacketInfo::default(),
3320 None,
3321 )
3322 .unwrap();
3323 f(&ctx);
3324 }
3325 let mut buffer = EmptyBuf
3338 .wrap_in(IcmpPacketBuilder::<Ipv4, _>::new(
3339 TEST_ADDRS_V4.local_ip,
3340 TEST_ADDRS_V4.remote_ip,
3341 IcmpZeroCode,
3342 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3343 ))
3344 .wrap_in(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::<
3345 NetworkSerializationContext,
3346 >::new(
3347 TEST_ADDRS_V4.local_ip, TEST_ADDRS_V4.remote_ip, 64, Ipv4Proto::Icmp
3348 ))
3349 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3350 .unwrap();
3351
3352 test_receive_icmpv4_error_helper(
3353 buffer.as_mut(),
3354 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3355 IcmpDestUnreachable::default(),
3356 |CtxPair { core_ctx, bindings_ctx: _ }| {
3357 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3358 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3359 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3360 assert_eq!(
3361 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3362 1
3363 );
3364 let err = Icmpv4ErrorCode::DestUnreachable(
3365 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3366 IcmpDestUnreachable::default(),
3367 );
3368 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3369 },
3370 );
3371
3372 test_receive_icmpv4_error_helper(
3373 buffer.as_mut(),
3374 Icmpv4TimeExceededCode::TtlExpired,
3375 IcmpTimeExceeded::default(),
3376 |CtxPair { core_ctx, bindings_ctx: _ }| {
3377 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3378 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3379 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3380 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3381 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3382 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3383 },
3384 );
3385
3386 test_receive_icmpv4_error_helper(
3387 buffer.as_mut(),
3388 Icmpv4ParameterProblemCode::PointerIndicatesError,
3389 Icmpv4ParameterProblem::new(0),
3390 |CtxPair { core_ctx, bindings_ctx: _ }| {
3391 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3392 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3393 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3394 assert_eq!(
3395 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3396 1
3397 );
3398 let err = Icmpv4ErrorCode::ParameterProblem(
3399 Icmpv4ParameterProblemCode::PointerIndicatesError,
3400 );
3401 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3402 },
3403 );
3404
3405 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::<
3412 NetworkSerializationContext,
3413 >::new(
3414 TEST_ADDRS_V4.local_ip, TEST_ADDRS_V4.remote_ip, 64, Ipv4Proto::Icmp
3415 )
3416 .wrap_body(EmptyBuf)
3417 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3418 .unwrap();
3419
3420 test_receive_icmpv4_error_helper(
3421 buffer.as_mut(),
3422 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3423 IcmpDestUnreachable::default(),
3424 |CtxPair { core_ctx, bindings_ctx: _ }| {
3425 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3426 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3427 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3428 assert_eq!(
3429 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3430 1
3431 );
3432 let err = Icmpv4ErrorCode::DestUnreachable(
3433 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3434 IcmpDestUnreachable::default(),
3435 );
3436 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3437 },
3438 );
3439
3440 test_receive_icmpv4_error_helper(
3441 buffer.as_mut(),
3442 Icmpv4TimeExceededCode::TtlExpired,
3443 IcmpTimeExceeded::default(),
3444 |CtxPair { core_ctx, bindings_ctx: _ }| {
3445 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3446 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3447 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3448 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3449 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3450 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3451 },
3452 );
3453
3454 test_receive_icmpv4_error_helper(
3455 buffer.as_mut(),
3456 Icmpv4ParameterProblemCode::PointerIndicatesError,
3457 Icmpv4ParameterProblem::new(0),
3458 |CtxPair { core_ctx, bindings_ctx: _ }| {
3459 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3460 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3461 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3462 assert_eq!(
3463 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3464 1
3465 );
3466 let err = Icmpv4ErrorCode::ParameterProblem(
3467 Icmpv4ParameterProblemCode::PointerIndicatesError,
3468 );
3469 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3470 },
3471 );
3472
3473 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::<
3479 NetworkSerializationContext,
3480 >::new(
3481 TEST_ADDRS_V4.local_ip, TEST_ADDRS_V4.remote_ip, 64, IpProto::Udp.into()
3482 )
3483 .wrap_body(EmptyBuf)
3484 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3485 .unwrap();
3486
3487 test_receive_icmpv4_error_helper(
3488 buffer.as_mut(),
3489 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3490 IcmpDestUnreachable::default(),
3491 |CtxPair { core_ctx, bindings_ctx: _ }| {
3492 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3493 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3494 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3495 assert_eq!(
3496 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3497 1
3498 );
3499 let err = Icmpv4ErrorCode::DestUnreachable(
3500 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3501 IcmpDestUnreachable::default(),
3502 );
3503 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3504 },
3505 );
3506
3507 test_receive_icmpv4_error_helper(
3508 buffer.as_mut(),
3509 Icmpv4TimeExceededCode::TtlExpired,
3510 IcmpTimeExceeded::default(),
3511 |CtxPair { core_ctx, bindings_ctx: _ }| {
3512 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3513 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3514 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3515 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3516 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3517 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3518 },
3519 );
3520
3521 test_receive_icmpv4_error_helper(
3522 buffer.as_mut(),
3523 Icmpv4ParameterProblemCode::PointerIndicatesError,
3524 Icmpv4ParameterProblem::new(0),
3525 |CtxPair { core_ctx, bindings_ctx: _ }| {
3526 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3527 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3528 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3529 assert_eq!(
3530 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3531 1
3532 );
3533 let err = Icmpv4ErrorCode::ParameterProblem(
3534 Icmpv4ParameterProblemCode::PointerIndicatesError,
3535 );
3536 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3537 },
3538 );
3539 }
3540
3541 #[test]
3542 fn test_receive_icmpv6_error() {
3543 const ICMP_ID: u16 = 0x0F;
3546 const SEQ_NUM: u16 = 0xF0;
3547
3548 fn test_receive_icmpv6_error_helper<
3563 C: Debug,
3564 M: IcmpMessage<Ipv6, Code = C> + Debug,
3565 F: Fn(&FakeIcmpCtx<Ipv6>),
3566 >(
3567 original_packet: &mut [u8],
3568 code: C,
3569 msg: M,
3570 f: F,
3571 ) {
3572 set_logger_for_test();
3573
3574 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
3575 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3576 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
3577 core_ctx,
3578 bindings_ctx,
3579 &FakeDeviceId,
3580 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
3581 TEST_ADDRS_V6.local_ip,
3582 IcmpPacketBuilder::new(TEST_ADDRS_V6.remote_ip, TEST_ADDRS_V6.local_ip, code, msg)
3583 .wrap_body(Buf::new(original_packet, ..))
3584 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3585 .unwrap(),
3586 &mut LocalDeliveryPacketInfo::default(),
3587 None,
3588 )
3589 .unwrap();
3590 f(&ctx);
3591 }
3592 let mut buffer = EmptyBuf
3605 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3606 TEST_ADDRS_V6.local_ip,
3607 TEST_ADDRS_V6.remote_ip,
3608 IcmpZeroCode,
3609 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3610 ))
3611 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::<
3612 NetworkSerializationContext,
3613 >::new(
3614 TEST_ADDRS_V6.local_ip, TEST_ADDRS_V6.remote_ip, 64, Ipv6Proto::Icmpv6
3615 ))
3616 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3617 .unwrap();
3618
3619 test_receive_icmpv6_error_helper(
3620 buffer.as_mut(),
3621 Icmpv6DestUnreachableCode::NoRoute,
3622 IcmpDestUnreachable::default(),
3623 |CtxPair { core_ctx, bindings_ctx: _ }| {
3624 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3625 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3626 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3627 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3628 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3629 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3630 },
3631 );
3632
3633 test_receive_icmpv6_error_helper(
3634 buffer.as_mut(),
3635 Icmpv6TimeExceededCode::HopLimitExceeded,
3636 IcmpTimeExceeded::default(),
3637 |CtxPair { core_ctx, bindings_ctx: _ }| {
3638 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3639 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3640 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3641 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3642 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3643 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3644 },
3645 );
3646
3647 test_receive_icmpv6_error_helper(
3648 buffer.as_mut(),
3649 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3650 Icmpv6ParameterProblem::new(0),
3651 |CtxPair { core_ctx, bindings_ctx: _ }| {
3652 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3653 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3654 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3655 assert_eq!(
3656 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3657 1
3658 );
3659 let err = Icmpv6ErrorCode::ParameterProblem(
3660 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3661 );
3662 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3663 },
3664 );
3665
3666 let mut buffer = EmptyBuf
3673 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::<
3674 NetworkSerializationContext,
3675 >::new(
3676 TEST_ADDRS_V6.local_ip, TEST_ADDRS_V6.remote_ip, 64, Ipv6Proto::Icmpv6
3677 ))
3678 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3679 .unwrap();
3680
3681 test_receive_icmpv6_error_helper(
3682 buffer.as_mut(),
3683 Icmpv6DestUnreachableCode::NoRoute,
3684 IcmpDestUnreachable::default(),
3685 |CtxPair { core_ctx, bindings_ctx: _ }| {
3686 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3687 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3688 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3689 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3690 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3691 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3692 },
3693 );
3694
3695 test_receive_icmpv6_error_helper(
3696 buffer.as_mut(),
3697 Icmpv6TimeExceededCode::HopLimitExceeded,
3698 IcmpTimeExceeded::default(),
3699 |CtxPair { core_ctx, bindings_ctx: _ }| {
3700 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3701 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3702 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3703 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3704 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3705 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3706 },
3707 );
3708
3709 test_receive_icmpv6_error_helper(
3710 buffer.as_mut(),
3711 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3712 Icmpv6ParameterProblem::new(0),
3713 |CtxPair { core_ctx, bindings_ctx: _ }| {
3714 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3715 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3716 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3717 assert_eq!(
3718 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3719 1
3720 );
3721 let err = Icmpv6ErrorCode::ParameterProblem(
3722 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3723 );
3724 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3725 },
3726 );
3727
3728 let mut buffer = <Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::<
3734 NetworkSerializationContext,
3735 >::new(
3736 TEST_ADDRS_V6.local_ip, TEST_ADDRS_V6.remote_ip, 64, IpProto::Udp.into()
3737 )
3738 .wrap_body(EmptyBuf)
3739 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3740 .unwrap();
3741
3742 test_receive_icmpv6_error_helper(
3743 buffer.as_mut(),
3744 Icmpv6DestUnreachableCode::NoRoute,
3745 IcmpDestUnreachable::default(),
3746 |CtxPair { core_ctx, bindings_ctx: _ }| {
3747 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3748 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3749 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3750 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3751 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3752 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3753 },
3754 );
3755
3756 test_receive_icmpv6_error_helper(
3757 buffer.as_mut(),
3758 Icmpv6TimeExceededCode::HopLimitExceeded,
3759 IcmpTimeExceeded::default(),
3760 |CtxPair { core_ctx, bindings_ctx: _ }| {
3761 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3762 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3763 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3764 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3765 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3766 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3767 },
3768 );
3769
3770 test_receive_icmpv6_error_helper(
3771 buffer.as_mut(),
3772 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3773 Icmpv6ParameterProblem::new(0),
3774 |CtxPair { core_ctx, bindings_ctx: _ }| {
3775 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3776 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3777 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3778 assert_eq!(
3779 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3780 1
3781 );
3782 let err = Icmpv6ErrorCode::ParameterProblem(
3783 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3784 );
3785 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3786 },
3787 );
3788 }
3789
3790 #[test]
3791 fn test_error_rate_limit() {
3792 set_logger_for_test();
3793
3794 fn send_icmpv4_ttl_expired_helper(
3796 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3797 ) {
3798 let error = Icmpv4Error::TtlExpired;
3799 core_ctx.send_icmp_error_message(
3800 bindings_ctx,
3801 Some(&FakeDeviceId),
3802 Some(FrameDestination::Individual { local: () }),
3803 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3804 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3805 EmptyBuf,
3806 error,
3807 0,
3808 packet_formats::ip::IpProto::Udp.into(),
3809 &Default::default(),
3810 );
3811 let count = core_ctx.icmp.tx_counters.time_exceeded.ttl_expired.get();
3812 assert!(count >= 1, "{count} >= 1");
3813 }
3814
3815 fn send_icmpv4_parameter_problem_helper(
3817 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3818 ) {
3819 let error = Icmpv4Error::ParameterProblem {
3820 code: Icmpv4ParameterProblemCode::PointerIndicatesError,
3821 pointer: 0,
3822 };
3823 core_ctx.send_icmp_error_message(
3824 bindings_ctx,
3825 Some(&FakeDeviceId),
3826 Some(FrameDestination::Individual { local: () }),
3827 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3828 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3829 EmptyBuf,
3830 error,
3831 0,
3832 packet_formats::ip::IpProto::Udp.into(),
3833 &Default::default(),
3834 );
3835 let count = core_ctx.icmp.tx_counters.parameter_problem.pointer_indicates_error.get();
3836 assert!(count >= 1, "{count} >= 1");
3837 }
3838
3839 fn send_icmpv4_dest_unreachable_helper(
3841 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3842 ) {
3843 core_ctx.send_icmp_error_message(
3844 bindings_ctx,
3845 Some(&FakeDeviceId),
3846 Some(FrameDestination::Individual { local: () }),
3847 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3848 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3849 EmptyBuf,
3850 Icmpv4Error::NetUnreachable,
3851 0,
3852 packet_formats::ip::IpProto::Udp.into(),
3853 &Default::default(),
3854 );
3855 let count = core_ctx.icmp.tx_counters.dest_unreachable.dest_network_unreachable.get();
3856 assert!(count >= 1, "{count} >= 1");
3857 }
3858
3859 fn send_icmpv6_ttl_expired_helper(
3861 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3862 ) {
3863 core_ctx.send_icmp_error_message(
3864 bindings_ctx,
3865 Some(&FakeDeviceId),
3866 Some(FrameDestination::Individual { local: () }),
3867 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3868 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3869 EmptyBuf,
3870 Icmpv6Error::TtlExpired,
3871 0,
3872 Ipv6Proto::NoNextHeader,
3873 &Default::default(),
3874 );
3875 let count = core_ctx.icmp.tx_counters.time_exceeded.hop_limit_exceeded.get();
3876 assert!(count >= 1, "{count} >= 1");
3877 }
3878
3879 fn send_icmpv6_packet_too_big_helper(
3881 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3882 ) {
3883 core_ctx.send_icmp_error_message(
3884 bindings_ctx,
3885 Some(&FakeDeviceId),
3886 Some(FrameDestination::Individual { local: () }),
3887 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3888 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3889 EmptyBuf,
3890 Icmpv6Error::PacketTooBig { mtu: Mtu::new(1280) },
3891 0,
3892 Ipv6Proto::NoNextHeader,
3893 &Default::default(),
3894 );
3895 let count = core_ctx.icmp.tx_counters.packet_too_big.get();
3896 assert!(count >= 1, "{count} >= 1");
3897 }
3898
3899 fn send_icmpv6_parameter_problem_helper(
3901 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3902 ) {
3903 let error = Icmpv6Error::ParameterProblem {
3904 code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
3905 pointer: 0,
3906 allow_dst_multicast: false,
3907 };
3908 core_ctx.send_icmp_error_message(
3909 bindings_ctx,
3910 Some(&FakeDeviceId),
3911 Some(FrameDestination::Individual { local: () }),
3912 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3913 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3914 EmptyBuf,
3915 error,
3916 0,
3917 Ipv6Proto::NoNextHeader,
3918 &Default::default(),
3919 );
3920 let count = core_ctx.icmp.tx_counters.parameter_problem.erroneous_header_field.get();
3921 assert!(count >= 1, "{count} >= 1");
3922 }
3923
3924 fn send_icmpv6_dest_unreachable_helper(
3926 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3927 ) {
3928 core_ctx.send_icmp_error_message(
3929 bindings_ctx,
3930 Some(&FakeDeviceId),
3931 Some(FrameDestination::Individual { local: () }),
3932 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3933 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3934 EmptyBuf,
3935 Icmpv6Error::NetUnreachable,
3936 0,
3937 Ipv6Proto::NoNextHeader,
3938 &Default::default(),
3939 );
3940 let count = core_ctx.icmp.tx_counters.dest_unreachable.no_route.get();
3941 assert!(count >= 1, "{count} >= 1");
3942 }
3943
3944 fn run_test<I: IcmpTestIpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
3948 with_errors_per_second: W,
3949 send: S,
3950 ) {
3951 const ERRORS_PER_SECOND: u64 = 64;
3965
3966 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
3967
3968 for i in 0..ERRORS_PER_SECOND {
3969 send(&mut ctx);
3970 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
3971 }
3972
3973 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3974 send(&mut ctx);
3975 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
3976
3977 let mut ctx = with_errors_per_second(0);
3981 send(&mut ctx);
3982 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
3983 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
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 }
3990
3991 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
3992 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
3993 }
3994 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
3995 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
3996 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
3997
3998 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
3999 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4000 }
4001
4002 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
4003 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
4004 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
4005 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
4006 }
4007}