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, BindingsSyncTypes, Counter, CounterContext, DeviceIdContext, EitherDeviceId,
27 FrameDestination, IcmpIpExt, Icmpv4ErrorCode, Icmpv6ErrorCode, InstantBindingsTypes,
28 InstantContext, IpDeviceAddr, IpExt, LocalFrameDestination, Marks, NetworkPartialSerializer,
29 NetworkSerializer, 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>>, BT::Mutex>,
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>>, BT::Mutex>;
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:
756 InstantBindingsTypes + TxMetadataBindingsTypes + BindingsSyncTypes
757{
758}
759impl<BT: InstantBindingsTypes + TxMetadataBindingsTypes + BindingsSyncTypes> IcmpBindingsTypes
760 for BT
761{
762}
763
764pub trait IcmpStateContext {}
772
773pub trait EchoTransportContextMarker {}
783
784pub trait InnerIcmpContext<I, BC>: IpSocketHandler<I, BC>
787where
788 I: IpLayerIpExt,
789 BC: IcmpBindingsTypes,
790{
791 type EchoTransportContext: IpTransportContext<I, BC, Self> + EchoTransportContextMarker;
794
795 fn receive_icmp_error(
825 &mut self,
826 bindings_ctx: &mut BC,
827 device: &Self::DeviceId,
828 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
829 original_dst_ip: SpecifiedAddr<I::Addr>,
830 original_proto: I::Proto,
831 original_body: &[u8],
832 err: I::ErrorCode,
833 );
834}
835
836pub trait InnerIcmpv4Context<BC: IcmpBindingsTypes>: InnerIcmpContext<Ipv4, BC> {
840 fn should_send_timestamp_reply(&self) -> bool;
842}
843
844pub trait IcmpSendContext<I, BC>: IpSocketHandler<I, BC>
846where
847 I: IpLayerIpExt,
848 BC: IcmpBindingsTypes,
849{
850 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<BC::Instant>) -> O>(
853 &mut self,
854 cb: F,
855 ) -> O;
856}
857
858macro_rules! try_send_error {
872 ($core_ctx:expr, $bindings_ctx:expr, $e:expr) => {{
873 let send = $core_ctx.with_error_send_bucket_mut(|error_send_bucket| {
874 error_send_bucket.try_take($bindings_ctx)
875 });
876
877 if send {
878 $core_ctx.counters().error.increment();
879 $e
880 } else {
881 trace!("ip::icmp::try_send_error!: dropping rate-limited ICMP error message");
882 Ok(())
883 }
884 }};
885}
886
887pub enum IcmpIpTransportContext {}
889
890fn receive_ip_transport_icmp_error<
891 I: IpLayerIpExt,
892 CC: InnerIcmpContext<I, BC> + CounterContext<IcmpRxCounters<I>>,
893 BC: IcmpBindingsContext,
894>(
895 core_ctx: &mut CC,
896 bindings_ctx: &mut BC,
897 device: &CC::DeviceId,
898 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
899 original_dst_ip: SpecifiedAddr<I::Addr>,
900 original_body: &[u8],
901 err: I::ErrorCode,
902) {
903 core_ctx.counters().error_delivered_to_transport_layer.increment();
904 trace!("IcmpIpTransportContext::receive_icmp_error({:?})", err);
905
906 let mut parse_body = original_body;
907 match parse_body.parse::<IcmpPacketRaw<I, _, IcmpEchoRequest>>() {
908 Ok(_echo_request) => (),
911 Err(_) => {
912 return;
916 }
917 }
918
919 <CC::EchoTransportContext as IpTransportContext<I, BC, CC>>::receive_icmp_error(
920 core_ctx,
921 bindings_ctx,
922 device,
923 original_src_ip,
924 original_dst_ip,
925 original_body,
926 err,
927 );
928}
929
930impl<
931 BC: IcmpBindingsContext,
932 CC: InnerIcmpv4Context<BC>
933 + PmtuHandler<Ipv4, BC>
934 + CounterContext<IcmpRxCounters<Ipv4>>
935 + CounterContext<IcmpTxCounters<Ipv4>>,
936> IpTransportContext<Ipv4, BC, CC> for IcmpIpTransportContext
937{
938 type EarlyDemuxSocket = !;
939
940 fn early_demux<B: ParseBuffer>(
941 _core_ctx: &mut CC,
942 _device: &CC::DeviceId,
943 _src_ip: Ipv4Addr,
944 _dst_ip: Ipv4Addr,
945 _buffer: B,
946 ) -> Option<Self::EarlyDemuxSocket> {
947 None
948 }
949
950 fn receive_icmp_error(
951 core_ctx: &mut CC,
952 bindings_ctx: &mut BC,
953 device: &CC::DeviceId,
954 original_src_ip: Option<SpecifiedAddr<Ipv4Addr>>,
955 original_dst_ip: SpecifiedAddr<Ipv4Addr>,
956 original_body: &[u8],
957 err: Icmpv4ErrorCode,
958 ) {
959 receive_ip_transport_icmp_error(
960 core_ctx,
961 bindings_ctx,
962 device,
963 original_src_ip,
964 original_dst_ip,
965 original_body,
966 err,
967 )
968 }
969
970 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv4>>(
971 core_ctx: &mut CC,
972 bindings_ctx: &mut BC,
973 device: &CC::DeviceId,
974 src_ip: Ipv4SourceAddr,
975 dst_ip: SpecifiedAddr<Ipv4Addr>,
976 mut buffer: B,
977 info: &mut LocalDeliveryPacketInfo<Ipv4, H>,
978 _early_demux_socket: Option<!>,
979 ) -> Result<(), (B, Icmpv4Error)> {
980 let LocalDeliveryPacketInfo { meta, header_info: _, marks, packet_type: _, gso_info: _ } =
981 info;
982 let ReceiveIpPacketMeta { broadcast: _, transparent_override, parsing_context: _ } = meta;
983 if let Some(delivery) = transparent_override {
984 unreachable!(
985 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
986 transparent proxy rules can only be configured for TCP and UDP packets"
987 );
988 }
989
990 trace!(
991 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet({}, {})",
992 src_ip, dst_ip
993 );
994 let packet =
995 match buffer.parse_with::<_, Icmpv4Packet<_>>(IcmpParseArgs::new(src_ip, dst_ip)) {
996 Ok(packet) => packet,
997 Err(_) => return Ok(()), };
999
1000 match packet {
1001 Icmpv4Packet::EchoRequest(echo_request) => {
1002 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_request.increment();
1003
1004 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
1005 let req = *echo_request.message();
1006 let code = echo_request.code();
1007 let (local_ip, remote_ip) = (dst_ip, src_ip);
1008 debug!(
1009 "replying to ICMP echo request from {remote_ip} to {local_ip}%{device:?}: \
1010 id={}, seq={}",
1011 req.id(),
1012 req.seq()
1013 );
1014 send_icmp_reply(
1015 core_ctx,
1016 bindings_ctx,
1017 device,
1018 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1019 SocketIpAddr::new_ipv4_specified(local_ip),
1020 |src_ip| {
1021 IcmpPacketBuilder::<Ipv4, _>::new(src_ip, *remote_ip, code, req.reply())
1022 .wrap_body(buffer)
1023 },
1024 &WithMarks(marks),
1025 );
1026 } else {
1027 trace!(
1028 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1029 Received echo request with an unspecified source address"
1030 );
1031 }
1032 }
1033 Icmpv4Packet::EchoReply(echo_reply) => {
1034 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx).echo_reply.increment();
1035 trace!(
1036 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1037 Received an EchoReply message"
1038 );
1039 let parse_metadata = echo_reply.parse_metadata();
1040 buffer.undo_parse(parse_metadata);
1041 return <CC::EchoTransportContext
1042 as IpTransportContext<Ipv4, BC, CC>>::receive_ip_packet(
1043 core_ctx,
1044 bindings_ctx,
1045 device,
1046 src_ip,
1047 dst_ip,
1048 buffer,
1049 info,
1050 None,
1051 );
1052 }
1053 Icmpv4Packet::TimestampRequest(timestamp_request) => {
1054 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1055 .timestamp_request
1056 .increment();
1057 if let Ipv4SourceAddr::Specified(src_ip) = src_ip {
1058 if core_ctx.should_send_timestamp_reply() {
1059 trace!(
1060 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1061 receive_ip_packet: Responding to Timestamp Request message"
1062 );
1063 const NOW: u32 = 0x80000000;
1082 let reply = timestamp_request.message().reply(NOW, NOW);
1083 let (local_ip, remote_ip) = (dst_ip, src_ip);
1084 buffer.shrink_front_to(0);
1091 send_icmp_reply(
1092 core_ctx,
1093 bindings_ctx,
1094 device,
1095 SocketIpAddr::new_ipv4_specified(remote_ip.get()),
1096 SocketIpAddr::new_ipv4_specified(local_ip),
1097 |src_ip| {
1098 IcmpPacketBuilder::<Ipv4, _>::new(
1099 src_ip,
1100 *remote_ip,
1101 IcmpZeroCode,
1102 reply,
1103 )
1104 .wrap_body(buffer)
1105 },
1106 &WithMarks(marks),
1107 );
1108 } else {
1109 trace!(
1110 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1111 receive_ip_packet: Silently ignoring Timestamp Request message"
1112 );
1113 }
1114 } else {
1115 trace!(
1116 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1117 receive_ip_packet: Received timestamp request with an unspecified source \
1118 address"
1119 );
1120 }
1121 }
1122 Icmpv4Packet::TimestampReply(_) => {
1123 debug!(
1126 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1127 Received unsolicited Timestamp Reply message"
1128 );
1129 }
1130 Icmpv4Packet::DestUnreachable(dest_unreachable) => {
1131 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1132 .dest_unreachable
1133 .increment_code(dest_unreachable.code());
1134 trace!(
1135 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1136 Received a Destination Unreachable message"
1137 );
1138
1139 let error = if dest_unreachable.code()
1140 == Icmpv4DestUnreachableCode::FragmentationRequired
1141 {
1142 let mtu = if let Some(next_hop_mtu) = dest_unreachable.message().next_hop_mtu()
1143 {
1144 core_ctx.update_pmtu_if_less(
1154 bindings_ctx,
1155 dst_ip.get(),
1156 src_ip.get(),
1157 Mtu::new(u32::from(next_hop_mtu.get())),
1158 )
1159 } else {
1160 let (original_packet_buf, inner_body) = dest_unreachable.body().bytes();
1182 debug_assert!(inner_body.is_none());
1184 if original_packet_buf.len() >= 4 {
1185 let total_len =
1189 u16::from_be_bytes(original_packet_buf[2..4].try_into().unwrap());
1190
1191 trace!(
1192 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1193 receive_ip_packet: Next-Hop MTU is 0 so using the next best PMTU \
1194 value from {total_len}"
1195 );
1196
1197 core_ctx.update_pmtu_next_lower(
1198 bindings_ctx,
1199 dst_ip.get(),
1200 src_ip.get(),
1201 Mtu::new(u32::from(total_len)),
1202 )
1203 } else {
1204 trace!(
1209 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1210 receive_ip_packet: Original packet buf is too small to get \
1211 original packet len so ignoring"
1212 );
1213 None
1214 }
1215 };
1216 mtu.and_then(|mtu| {
1217 let mtu = u16::try_from(mtu.get()).unwrap_or(u16::MAX);
1218 let mtu = NonZeroU16::new(mtu)?;
1219 Some(Icmpv4ErrorCode::DestUnreachable(
1220 dest_unreachable.code(),
1221 IcmpDestUnreachable::new_for_frag_req(mtu),
1222 ))
1223 })
1224 } else {
1225 Some(Icmpv4ErrorCode::DestUnreachable(
1226 dest_unreachable.code(),
1227 *dest_unreachable.message(),
1228 ))
1229 };
1230
1231 if let Some(error) = error {
1232 receive_icmpv4_error(core_ctx, bindings_ctx, device, &dest_unreachable, error);
1233 }
1234 }
1235 Icmpv4Packet::TimeExceeded(time_exceeded) => {
1236 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1237 .time_exceeded
1238 .increment_code(time_exceeded.code());
1239 trace!(
1240 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1241 Received a Time Exceeded message"
1242 );
1243
1244 receive_icmpv4_error(
1245 core_ctx,
1246 bindings_ctx,
1247 device,
1248 &time_exceeded,
1249 Icmpv4ErrorCode::TimeExceeded(time_exceeded.code()),
1250 );
1251 }
1252 Icmpv4Packet::Redirect(_) => {
1254 debug!(
1255 "Unimplemented: <IcmpIpTransportContext as IpTransportContext<Ipv4>>::\
1256 receive_ip_packet::redirect"
1257 )
1258 }
1259 Icmpv4Packet::ParameterProblem(parameter_problem) => {
1260 CounterContext::<IcmpRxCounters<Ipv4>>::counters(core_ctx)
1261 .parameter_problem
1262 .increment_code(parameter_problem.code());
1263 trace!(
1264 "<IcmpIpTransportContext as IpTransportContext<Ipv4>>::receive_ip_packet: \
1265 Received a Parameter Problem message"
1266 );
1267
1268 receive_icmpv4_error(
1269 core_ctx,
1270 bindings_ctx,
1271 device,
1272 ¶meter_problem,
1273 Icmpv4ErrorCode::ParameterProblem(parameter_problem.code()),
1274 );
1275 }
1276 }
1277
1278 Ok(())
1279 }
1280}
1281
1282#[allow(missing_docs)]
1285pub enum NdpMessage {
1286 NeighborSolicitation {
1287 message: NeighborSolicitation,
1288 code: <NeighborSolicitation as IcmpMessage<Ipv6>>::Code,
1289 },
1290
1291 RouterSolicitation {
1292 message: RouterSolicitation,
1293 code: <RouterSolicitation as IcmpMessage<Ipv6>>::Code,
1294 },
1295
1296 NeighborAdvertisement {
1297 message: NeighborAdvertisement,
1298 code: <NeighborAdvertisement as IcmpMessage<Ipv6>>::Code,
1299 },
1300}
1301
1302pub fn send_ndp_packet<BC, CC, S>(
1304 core_ctx: &mut CC,
1305 bindings_ctx: &mut BC,
1306 device_id: &CC::DeviceId,
1307 src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1308 dst_ip: SpecifiedAddr<Ipv6Addr>,
1309 body: S,
1310 message: NdpMessage,
1311) -> Result<(), IpSendFrameError<S>>
1312where
1313 CC: IpLayerHandler<Ipv6, BC>,
1314 S: NetworkSerializer + NetworkPartialSerializer,
1315 S::Buffer: BufferMut,
1316{
1317 macro_rules! send {
1318 ($message:expr, $code:expr) => {{
1319 let mut ser = IcmpPacketBuilder::<Ipv6, _>::new(
1321 src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
1322 dst_ip.get(),
1323 $code,
1324 $message,
1325 )
1326 .wrap_body(body);
1327 match IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
1328 core_ctx,
1329 bindings_ctx,
1330 SendIpPacketMeta {
1331 device: device_id,
1332 src_ip,
1333 dst_ip,
1334 destination: IpPacketDestination::from_addr(dst_ip),
1335 ttl: NonZeroU8::new(REQUIRED_NDP_IP_PACKET_HOP_LIMIT),
1336 proto: Ipv6Proto::Icmpv6,
1337 mtu: Mtu::no_limit(),
1338 dscp_and_ecn: DscpAndEcn::default(),
1339 },
1340 DynTransportSerializer::new(&mut ser),
1341 ) {
1342 Ok(()) => Ok(()),
1343 Err(e) => Err(e
1344 .map_serializer(|s| {
1345 let _: DynTransportSerializer<'_, _> = s;
1347 })
1348 .map_serializer(|()| ser.into_inner())),
1349 }
1350 }};
1351 }
1352
1353 match message {
1354 NdpMessage::NeighborSolicitation { message, code } => send!(message, code),
1355 NdpMessage::RouterSolicitation { message, code } => send!(message, code),
1356 NdpMessage::NeighborAdvertisement { message, code } => send!(message, code),
1357 }
1358}
1359
1360fn send_neighbor_advertisement<
1361 BC,
1362 CC: Ipv6DeviceHandler<BC>
1363 + IpDeviceHandler<Ipv6, BC>
1364 + IpLayerHandler<Ipv6, BC>
1365 + CounterContext<NdpCounters>,
1366>(
1367 core_ctx: &mut CC,
1368 bindings_ctx: &mut BC,
1369 device_id: &CC::DeviceId,
1370 solicited: bool,
1371 device_addr: UnicastAddr<Ipv6Addr>,
1372 dst_ip: SpecifiedAddr<Ipv6Addr>,
1373) {
1374 core_ctx.counters().tx.neighbor_advertisement.increment();
1375 debug!("send_neighbor_advertisement from {:?} to {:?}", device_addr, dst_ip);
1376 debug_assert!(dst_ip.is_valid_unicast() || (!solicited && dst_ip.is_multicast()));
1383
1384 let src_ll = core_ctx.get_link_layer_addr(&device_id);
1391
1392 let advertisement = NeighborAdvertisement::new(
1394 core_ctx.is_router_device(&device_id),
1395 solicited,
1396 true, device_addr.get(),
1409 );
1410 let _: Result<(), _> = send_ndp_packet(
1411 core_ctx,
1412 bindings_ctx,
1413 &device_id,
1414 Some(device_addr.into_specified()),
1415 dst_ip,
1416 OptionSequenceBuilder::new(
1417 src_ll
1418 .as_ref()
1419 .map(Ipv6LinkLayerAddr::as_bytes)
1420 .map(NdpOptionBuilder::TargetLinkLayerAddress)
1421 .iter(),
1422 )
1423 .into_serializer(),
1424 NdpMessage::NeighborAdvertisement { message: advertisement, code: IcmpZeroCode },
1425 );
1426}
1427
1428fn receive_ndp_packet<
1429 B: SplitByteSlice,
1430 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1431 CC: InnerIcmpContext<Ipv6, BC>
1432 + Ipv6DeviceHandler<BC>
1433 + IpDeviceHandler<Ipv6, BC>
1434 + IpDeviceIngressStateContext<Ipv6>
1435 + NudIpHandler<Ipv6, BC>
1436 + IpLayerHandler<Ipv6, BC>
1437 + CounterContext<NdpCounters>,
1438 H: IpHeaderInfo<Ipv6>,
1439>(
1440 core_ctx: &mut CC,
1441 bindings_ctx: &mut BC,
1442 device_id: &CC::DeviceId,
1443 src_ip: Ipv6SourceAddr,
1444 dst_ip: SpecifiedAddr<Ipv6Addr>,
1445 packet: NdpPacket<B>,
1446 header_info: &H,
1447) {
1448 if header_info.hop_limit() != REQUIRED_NDP_IP_PACKET_HOP_LIMIT {
1466 trace!("dropping NDP packet from {src_ip} with invalid hop limit");
1467 return;
1468 }
1469
1470 match packet {
1471 NdpPacket::RouterSolicitation(_) => {}
1472 NdpPacket::Redirect(_) => {}
1474 NdpPacket::NeighborSolicitation(ref p) => {
1475 let target_address = p.message().target_address();
1482 let target_address = match UnicastAddr::new(*target_address) {
1483 Some(a) => a,
1484 None => {
1485 trace!(
1486 "dropping NS from {} with non-unicast target={:?}",
1487 src_ip, target_address
1488 );
1489 return;
1490 }
1491 };
1492
1493 let (source_link_addr, nonce) = p.body().iter().fold(
1495 (None, None),
1496 |(found_source_link_addr, found_nonce), option| {
1497 match option {
1498 NdpOption::Nonce(nonce) => (found_source_link_addr, Some(nonce)),
1499 NdpOption::SourceLinkLayerAddress(source_link_addr) => {
1500 (Some(source_link_addr), found_nonce)
1501 }
1502 NdpOption::Mtu(_)
1510 | NdpOption::PrefixInformation(_)
1511 | NdpOption::RecursiveDnsServer(_)
1512 | NdpOption::RedirectedHeader { .. }
1513 | NdpOption::RouteInformation(_)
1514 | NdpOption::TargetLinkLayerAddress(_) => {
1515 (found_source_link_addr, found_nonce)
1516 }
1517 }
1518 },
1519 );
1520
1521 if src_ip == Ipv6SourceAddr::Unspecified {
1522 if target_address.get().to_solicited_node_address().get() != dst_ip.get() {
1531 debug!(
1532 "dropping NS from {} for {} with invalid IPv6 dst ({}).",
1533 src_ip, target_address, dst_ip
1534 );
1535 return;
1536 }
1537 if let Some(addr) = source_link_addr {
1542 debug!(
1543 "dropping NS from {} for {} with source link-layer addr option ({:?}).",
1544 src_ip, target_address, addr
1545 );
1546 return;
1547 }
1548 }
1549
1550 core_ctx.counters().rx.neighbor_solicitation.increment();
1551
1552 match src_ip {
1553 Ipv6SourceAddr::Unspecified => {
1554 match IpDeviceHandler::handle_received_dad_packet(
1564 core_ctx,
1565 bindings_ctx,
1566 &device_id,
1567 target_address.into_specified(),
1568 nonce,
1569 ) {
1570 Some(IpAddressState::Assigned) => {
1571 send_neighbor_advertisement(
1575 core_ctx,
1576 bindings_ctx,
1577 &device_id,
1578 false,
1579 target_address,
1580 Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.into_specified(),
1581 );
1582 }
1583 Some(IpAddressState::Tentative) => {
1584 }
1587 Some(IpAddressState::Unavailable) | None => {
1588 }
1591 }
1592
1593 return;
1594 }
1595 Ipv6SourceAddr::Unicast(src_ip) => {
1596 match core_ctx
1598 .address_status_for_device(target_address.into_specified(), device_id)
1599 {
1600 AddressStatus::Present(Ipv6PresentAddressStatus::UnicastAssigned) => {}
1601 AddressStatus::Present(
1602 Ipv6PresentAddressStatus::UnicastTentative
1603 | Ipv6PresentAddressStatus::Multicast,
1604 )
1605 | AddressStatus::Unassigned => {
1606 return;
1610 }
1611 }
1612
1613 if let Some(link_addr) = source_link_addr {
1614 NudIpHandler::handle_neighbor_probe(
1615 core_ctx,
1616 bindings_ctx,
1617 &device_id,
1618 src_ip.into_specified(),
1619 link_addr,
1620 );
1621 }
1622
1623 send_neighbor_advertisement(
1624 core_ctx,
1625 bindings_ctx,
1626 &device_id,
1627 true,
1628 target_address,
1629 src_ip.into_specified(),
1630 );
1631 }
1632 }
1633 }
1634 NdpPacket::NeighborAdvertisement(ref p) => {
1635 let target_address = p.message().target_address();
1639
1640 let target_address = match UnicastAddr::new(*target_address) {
1647 Some(a) => a,
1648 None => {
1649 debug!(
1650 "dropping NA from {} with non-unicast target={:?}",
1651 src_ip, target_address
1652 );
1653 return;
1654 }
1655 };
1656 if let Some(dst_ip) = MulticastAddr::new(dst_ip.get())
1660 && p.message().solicited_flag()
1661 {
1662 debug!(
1663 "dropping NA from {} with solicited flag and multicast dst {}",
1664 src_ip, dst_ip
1665 );
1666 return;
1667 }
1668
1669 core_ctx.counters().rx.neighbor_advertisement.increment();
1670
1671 let nonce = None;
1675 match IpDeviceHandler::handle_received_dad_packet(
1676 core_ctx,
1677 bindings_ctx,
1678 &device_id,
1679 target_address.into_specified(),
1680 nonce,
1681 ) {
1682 Some(IpAddressState::Assigned) => {
1683 error!(
1701 "NA from {src_ip} with target address {target_address} that is also \
1702 assigned on device {device_id:?}",
1703 );
1704 }
1705 Some(IpAddressState::Tentative) => {
1706 return;
1709 }
1710 Some(IpAddressState::Unavailable) | None => {
1711 }
1715 }
1716
1717 let link_addr = p.body().iter().find_map(|o| o.target_link_layer_address());
1718
1719 NudIpHandler::handle_neighbor_confirmation(
1720 core_ctx,
1721 bindings_ctx,
1722 &device_id,
1723 target_address.into_specified(),
1724 link_addr,
1725 ConfirmationFlags {
1726 solicited_flag: p.message().solicited_flag(),
1727 override_flag: p.message().override_flag(),
1728 },
1729 );
1730 }
1731 NdpPacket::RouterAdvertisement(ref p) => {
1732 let src_ip = match src_ip {
1745 Ipv6SourceAddr::Unicast(ip) => match LinkLocalUnicastAddr::new(*ip) {
1746 Some(ip) => ip,
1747 None => return,
1748 },
1749 Ipv6SourceAddr::Unspecified => return,
1750 };
1751
1752 let ra = p.message();
1753 debug!("received router advertisement from {:?}: {:?}", src_ip, ra);
1754 core_ctx.counters().rx.router_advertisement.increment();
1755
1756 if let Some(retransmit_timer) = ra.retransmit_timer() {
1763 Ipv6DeviceHandler::set_discovered_retrans_timer(
1764 core_ctx,
1765 bindings_ctx,
1766 &device_id,
1767 retransmit_timer,
1768 );
1769 }
1770
1771 if let Some(hop_limit) = ra.current_hop_limit() {
1778 trace!(
1779 "receive_ndp_packet: NDP RA: updating device's hop limit to {:?} for router: {:?}",
1780 ra.current_hop_limit(),
1781 src_ip
1782 );
1783 IpDeviceHandler::set_default_hop_limit(core_ctx, &device_id, hop_limit);
1784 }
1785
1786 Ipv6DeviceHandler::update_discovered_ipv6_route(
1787 core_ctx,
1788 bindings_ctx,
1789 &device_id,
1790 Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) },
1791 Ipv6DiscoveredRouteProperties { route_preference: p.message().preference().into() },
1792 p.message().router_lifetime().map(NonZeroNdpLifetime::Finite),
1793 );
1794
1795 for option in p.body().iter() {
1796 match option {
1797 NdpOption::TargetLinkLayerAddress(_)
1798 | NdpOption::RedirectedHeader { .. }
1799 | NdpOption::RecursiveDnsServer(_)
1800 | NdpOption::Nonce(_) => {}
1801 NdpOption::SourceLinkLayerAddress(addr) => {
1802 debug!("processing SourceLinkLayerAddress option in RA: {:?}", addr);
1803 NudIpHandler::handle_neighbor_probe(
1829 core_ctx,
1830 bindings_ctx,
1831 &device_id,
1832 {
1833 let src_ip: UnicastAddr<_> = src_ip.into_addr();
1834 src_ip.into_specified()
1835 },
1836 addr,
1837 );
1838 }
1839 NdpOption::PrefixInformation(prefix_info) => {
1840 debug!("processing Prefix Information option in RA: {:?}", prefix_info);
1841 if prefix_info.prefix().is_link_local() {
1859 continue;
1860 }
1861
1862 let subnet = match prefix_info.subnet() {
1863 Ok(subnet) => subnet,
1864 Err(err) => match err {
1865 SubnetError::PrefixTooLong | SubnetError::HostBitsSet => continue,
1866 },
1867 };
1868
1869 match UnicastAddr::new(subnet.network()) {
1870 Some(UnicastAddr { .. }) => {}
1871 None => continue,
1872 }
1873
1874 let valid_lifetime = prefix_info.valid_lifetime();
1875
1876 if prefix_info.on_link_flag() {
1877 Ipv6DeviceHandler::update_discovered_ipv6_route(
1878 core_ctx,
1879 bindings_ctx,
1880 &device_id,
1881 Ipv6DiscoveredRoute { subnet, gateway: None },
1882 Ipv6DiscoveredRouteProperties {
1883 route_preference: RoutePreference::Medium,
1884 },
1885 valid_lifetime,
1886 )
1887 }
1888
1889 if prefix_info.autonomous_address_configuration_flag() {
1890 Ipv6DeviceHandler::apply_slaac_update(
1891 core_ctx,
1892 bindings_ctx,
1893 &device_id,
1894 subnet,
1895 prefix_info.preferred_lifetime(),
1896 valid_lifetime,
1897 );
1898 }
1899 }
1900 NdpOption::RouteInformation(rio) => {
1901 debug!("processing Route Information option in RA: {:?}", rio);
1902 Ipv6DeviceHandler::update_discovered_ipv6_route(
1903 core_ctx,
1904 bindings_ctx,
1905 &device_id,
1906 Ipv6DiscoveredRoute {
1907 subnet: rio.prefix().clone(),
1908 gateway: Some(src_ip),
1909 },
1910 Ipv6DiscoveredRouteProperties {
1911 route_preference: rio.preference().into(),
1912 },
1913 rio.route_lifetime(),
1914 )
1915 }
1916 NdpOption::Mtu(mtu) => {
1917 debug!("processing MTU option in RA: {:?}", mtu);
1918 Ipv6DeviceHandler::set_link_mtu(core_ctx, &device_id, Mtu::new(mtu));
1922 }
1923 }
1924 }
1925
1926 bindings_ctx.on_event(RouterAdvertisementEvent {
1927 options_bytes: Box::from(p.body().bytes()),
1928 source: **src_ip,
1929 device: device_id.clone(),
1930 });
1931 }
1932 }
1933}
1934
1935impl<
1936 BC: IcmpBindingsContext + NdpBindingsContext<CC::DeviceId>,
1937 CC: InnerIcmpContext<Ipv6, BC>
1938 + InnerIcmpContext<Ipv6, BC>
1939 + Ipv6DeviceHandler<BC>
1940 + IpDeviceHandler<Ipv6, BC>
1941 + IpDeviceIngressStateContext<Ipv6>
1942 + PmtuHandler<Ipv6, BC>
1943 + NudIpHandler<Ipv6, BC>
1944 + IpLayerHandler<Ipv6, BC>
1945 + CounterContext<IcmpRxCounters<Ipv6>>
1946 + CounterContext<IcmpTxCounters<Ipv6>>
1947 + CounterContext<NdpCounters>,
1948> IpTransportContext<Ipv6, BC, CC> for IcmpIpTransportContext
1949{
1950 type EarlyDemuxSocket = !;
1951
1952 fn early_demux<B: ParseBuffer>(
1953 _core_ctx: &mut CC,
1954 _device: &CC::DeviceId,
1955 _src_ip: Ipv6Addr,
1956 _dst_ip: Ipv6Addr,
1957 _buffer: B,
1958 ) -> Option<Self::EarlyDemuxSocket> {
1959 None
1960 }
1961
1962 fn receive_icmp_error(
1963 core_ctx: &mut CC,
1964 bindings_ctx: &mut BC,
1965 device: &CC::DeviceId,
1966 original_src_ip: Option<SpecifiedAddr<Ipv6Addr>>,
1967 original_dst_ip: SpecifiedAddr<Ipv6Addr>,
1968 original_body: &[u8],
1969 err: Icmpv6ErrorCode,
1970 ) {
1971 receive_ip_transport_icmp_error(
1972 core_ctx,
1973 bindings_ctx,
1974 device,
1975 original_src_ip,
1976 original_dst_ip,
1977 original_body,
1978 err,
1979 )
1980 }
1981
1982 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<Ipv6>>(
1983 core_ctx: &mut CC,
1984 bindings_ctx: &mut BC,
1985 device: &CC::DeviceId,
1986 src_ip: Ipv6SourceAddr,
1987 dst_ip: SpecifiedAddr<Ipv6Addr>,
1988 mut buffer: B,
1989 info: &mut LocalDeliveryPacketInfo<Ipv6, H>,
1990 _early_demux_socket: Option<!>,
1991 ) -> Result<(), (B, Icmpv6Error)> {
1992 let LocalDeliveryPacketInfo { meta, header_info, marks, packet_type: _, gso_info: _ } =
1993 info;
1994 let ReceiveIpPacketMeta { broadcast: _, transparent_override, parsing_context: _ } = meta;
1995 if let Some(delivery) = transparent_override {
1996 unreachable!(
1997 "cannot perform transparent local delivery {delivery:?} to an ICMP socket; \
1998 transparent proxy rules can only be configured for TCP and UDP packets"
1999 );
2000 }
2001
2002 trace!(
2003 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet({:?}, {})",
2004 src_ip, dst_ip
2005 );
2006
2007 let packet = match buffer
2008 .parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(src_ip.get(), dst_ip))
2009 {
2010 Ok(packet) => packet,
2011 Err(_) => return Ok(()), };
2013
2014 match packet {
2015 Icmpv6Packet::EchoRequest(echo_request) => {
2016 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_request.increment();
2017
2018 if let Some(src_ip) = SocketIpAddr::new_from_ipv6_source(src_ip) {
2019 match SocketIpAddr::try_from(dst_ip) {
2020 Ok(dst_ip) => {
2021 let req = *echo_request.message();
2022 let code = echo_request.code();
2023 let (local_ip, remote_ip) = (dst_ip, src_ip);
2024 debug!(
2025 "replying to ICMP echo request from {remote_ip}: id={}, seq={}",
2026 req.id(),
2027 req.seq()
2028 );
2029 send_icmp_reply(
2030 core_ctx,
2031 bindings_ctx,
2032 device,
2033 remote_ip,
2034 local_ip,
2035 |src_ip| {
2036 IcmpPacketBuilder::<Ipv6, _>::new(
2037 src_ip,
2038 remote_ip.addr(),
2039 code,
2040 req.reply(),
2041 )
2042 .wrap_body(buffer)
2043 },
2044 &WithMarks(marks),
2045 );
2046 }
2047 Err(AddrIsMappedError {}) => {
2048 trace!(
2049 "IpTransportContext<Ipv6>::receive_ip_packet: Received echo request with an ipv4-mapped-ipv6 destination address"
2050 );
2051 }
2052 }
2053 } else {
2054 trace!(
2055 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received echo request with an unspecified source address"
2056 );
2057 }
2058 }
2059 Icmpv6Packet::EchoReply(echo_reply) => {
2060 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx).echo_reply.increment();
2061 trace!(
2062 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received an EchoReply message"
2063 );
2064 let parse_metadata = echo_reply.parse_metadata();
2065 buffer.undo_parse(parse_metadata);
2066 return <CC::EchoTransportContext
2067 as IpTransportContext<Ipv6, BC, CC>>::receive_ip_packet(
2068 core_ctx,
2069 bindings_ctx,
2070 device,
2071 src_ip,
2072 dst_ip,
2073 buffer,
2074 info,
2075 None
2076 );
2077 }
2078 Icmpv6Packet::Ndp(packet) => receive_ndp_packet(
2079 core_ctx,
2080 bindings_ctx,
2081 device,
2082 src_ip,
2083 dst_ip,
2084 packet,
2085 header_info,
2086 ),
2087 Icmpv6Packet::PacketTooBig(packet_too_big) => {
2088 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2089 .packet_too_big
2090 .increment();
2091 trace!(
2092 "<IcmpIpTransportContext as IpTransportContext<Ipv6>>::receive_ip_packet: Received a Packet Too Big message"
2093 );
2094 if let Ipv6SourceAddr::Unicast(src_ip) = src_ip {
2095 let mtu = core_ctx.update_pmtu_if_less(
2105 bindings_ctx,
2106 dst_ip.get(),
2107 src_ip.get(),
2108 Mtu::new(packet_too_big.message().mtu()),
2109 );
2110 if let Some(mtu) = mtu {
2111 receive_icmpv6_error(
2112 core_ctx,
2113 bindings_ctx,
2114 device,
2115 &packet_too_big,
2116 Icmpv6ErrorCode::PacketTooBig(mtu),
2117 );
2118 }
2119 }
2120 }
2121 Icmpv6Packet::Mld(packet) => {
2122 core_ctx.receive_mld_packet(
2123 bindings_ctx,
2124 &device,
2125 src_ip,
2126 dst_ip,
2127 packet,
2128 header_info,
2129 );
2130 }
2131 Icmpv6Packet::DestUnreachable(dest_unreachable) => {
2132 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2133 .dest_unreachable
2134 .increment_code(dest_unreachable.code());
2135 receive_icmpv6_error(
2136 core_ctx,
2137 bindings_ctx,
2138 device,
2139 &dest_unreachable,
2140 Icmpv6ErrorCode::DestUnreachable(dest_unreachable.code()),
2141 )
2142 }
2143 Icmpv6Packet::TimeExceeded(time_exceeded) => {
2144 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2145 .time_exceeded
2146 .increment_code(time_exceeded.code());
2147 receive_icmpv6_error(
2148 core_ctx,
2149 bindings_ctx,
2150 device,
2151 &time_exceeded,
2152 Icmpv6ErrorCode::TimeExceeded(time_exceeded.code()),
2153 )
2154 }
2155 Icmpv6Packet::ParameterProblem(parameter_problem) => {
2156 CounterContext::<IcmpRxCounters<Ipv6>>::counters(core_ctx)
2157 .parameter_problem
2158 .increment_code(parameter_problem.code());
2159 receive_icmpv6_error(
2160 core_ctx,
2161 bindings_ctx,
2162 device,
2163 ¶meter_problem,
2164 Icmpv6ErrorCode::ParameterProblem(parameter_problem.code()),
2165 )
2166 }
2167 }
2168
2169 Ok(())
2170 }
2171}
2172
2173#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2174struct WithMarks<'a>(&'a Marks);
2175
2176impl<'a> OptionDelegationMarker for WithMarks<'a> {}
2177
2178impl<'a, I: IpExt> DelegatedRouteResolutionOptions<I> for WithMarks<'a> {
2179 fn marks(&self) -> &Marks {
2180 let Self(marks) = self;
2181 marks
2182 }
2183}
2184
2185impl<'a, I: IpExt> DelegatedSendOptions<I> for WithMarks<'a> {}
2186
2187fn send_icmp_reply<I, BC, CC, S, F, O>(
2198 core_ctx: &mut CC,
2199 bindings_ctx: &mut BC,
2200 device: &CC::DeviceId,
2201 original_src_ip: SocketIpAddr<I::Addr>,
2202 original_dst_ip: SocketIpAddr<I::Addr>,
2203 get_body_from_src_ip: F,
2204 ip_options: &O,
2205) where
2206 I: IpExt + FilterIpExt + IcmpCountersIpExt,
2207 CC: IpSocketHandler<I, BC> + DeviceIdContext<AnyDevice> + CounterContext<IcmpTxCounters<I>>,
2208 BC: TxMetadataBindingsTypes,
2209 S: DynamicTransportSerializer<I>,
2210 F: FnOnce(SpecifiedAddr<I::Addr>) -> S,
2211 O: SendOptions<I> + RouteResolutionOptions<I>,
2212{
2213 trace!("send_icmp_reply({:?}, {}, {})", device, original_src_ip, original_dst_ip);
2214 core_ctx.counters().reply.increment();
2215 let tx_metadata: BC::TxMetadata = Default::default();
2216
2217 let egress_device = (original_dst_ip.as_ref().is_multicast()
2221 || original_dst_ip.as_ref().must_have_zone())
2222 .then_some(EitherDeviceId::Strong(device));
2223
2224 core_ctx
2225 .send_oneshot_ip_packet_with_dyn_serializer(
2226 bindings_ctx,
2227 IpSocketArgs {
2228 device: egress_device,
2229 local_ip: IpDeviceAddr::new_from_socket_ip_addr(original_dst_ip),
2230 remote_ip: original_src_ip,
2231 proto: I::ICMP_IP_PROTO,
2232 options: ip_options,
2233 },
2234 tx_metadata,
2235 |src_ip| get_body_from_src_ip(src_ip.into()),
2236 )
2237 .unwrap_or_else(|err| {
2238 debug!("failed to send ICMP reply: {}", err);
2239 })
2240}
2241
2242fn receive_icmpv4_error<
2247 BC: IcmpBindingsContext,
2248 CC: InnerIcmpContext<Ipv4, BC>,
2249 B: SplitByteSlice,
2250 M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>,
2251>(
2252 core_ctx: &mut CC,
2253 bindings_ctx: &mut BC,
2254 device: &CC::DeviceId,
2255 packet: &IcmpPacket<Ipv4, B, M>,
2256 err: Icmpv4ErrorCode,
2257) {
2258 packet.with_original_packet(|res| match res {
2259 Ok(original_packet) => {
2260 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2261 Some(ip) => ip,
2262 None => {
2263 trace!("receive_icmpv4_error: Got ICMP error message whose original IPv4 packet contains an unspecified destination address; discarding");
2264 return;
2265 },
2266 };
2267 InnerIcmpContext::receive_icmp_error(
2268 core_ctx,
2269 bindings_ctx,
2270 device,
2271 SpecifiedAddr::new(original_packet.src_ip()),
2272 dst_ip,
2273 original_packet.proto(),
2274 original_packet.body().into_inner(),
2275 err,
2276 );
2277 }
2278 Err(_) => debug!(
2279 "receive_icmpv4_error: Got ICMP error message with unparsable original IPv4 packet"
2280 ),
2281 })
2282}
2283
2284fn receive_icmpv6_error<
2289 BC: IcmpBindingsContext,
2290 CC: InnerIcmpContext<Ipv6, BC>,
2291 B: SplitByteSlice,
2292 M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>,
2293>(
2294 core_ctx: &mut CC,
2295 bindings_ctx: &mut BC,
2296 device: &CC::DeviceId,
2297 packet: &IcmpPacket<Ipv6, B, M>,
2298 err: Icmpv6ErrorCode,
2299) {
2300 packet.with_original_packet(|res| match res {
2301 Ok(original_packet) => {
2302 let dst_ip = match SpecifiedAddr::new(original_packet.dst_ip()) {
2303 Some(ip)=>ip,
2304 None => {
2305 trace!("receive_icmpv6_error: Got ICMP error message whose original IPv6 packet contains an unspecified destination address; discarding");
2306 return;
2307 },
2308 };
2309 match original_packet.body_proto() {
2310 Ok((body, proto)) => {
2311 InnerIcmpContext::receive_icmp_error(
2312 core_ctx,
2313 bindings_ctx,
2314 device,
2315 SpecifiedAddr::new(original_packet.src_ip()),
2316 dst_ip,
2317 proto,
2318 body.into_inner(),
2319 err,
2320 );
2321 }
2322 Err(ExtHdrParseError) => {
2323 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");
2324 return;
2327 }
2328 }
2329 }
2330 Err(_body) => debug!(
2331 "receive_icmpv6_error: Got ICMPv6 error message with unparsable original IPv6 packet"
2332 ),
2333 })
2334}
2335
2336fn send_icmpv4_error_message<B, BC, CC>(
2337 core_ctx: &mut CC,
2338 bindings_ctx: &mut BC,
2339 device: Option<&CC::DeviceId>,
2340 frame_dst: Option<LocalFrameDestination>,
2341 original_src_ip: SocketIpAddr<Ipv4Addr>,
2342 original_dst_ip: SocketIpAddr<Ipv4Addr>,
2343 message: Icmpv4ErrorMessage,
2344 mut original_packet: B,
2345 header_len: usize,
2346 marks: &Marks,
2347) where
2348 B: BufferMut,
2349 BC: IcmpBindingsContext,
2350 CC: IcmpSendContext<Ipv4, BC> + CounterContext<IcmpTxCounters<Ipv4>>,
2351{
2352 if !should_send_icmpv4_error(frame_dst, original_src_ip.into(), original_dst_ip.into()) {
2356 return;
2357 }
2358
2359 original_packet.shrink_back_to(header_len + 64);
2362
2363 let tx_metadata: BC::TxMetadata = Default::default();
2364
2365 macro_rules! send {
2366 ($message:expr, $code:expr) => {{
2367 let _ = try_send_error!(
2370 core_ctx,
2371 bindings_ctx,
2372 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2373 bindings_ctx,
2374 IpSocketArgs {
2375 device: device.map(EitherDeviceId::Strong),
2376 local_ip: None,
2377 remote_ip: original_src_ip,
2378 proto: Ipv4Proto::Icmp,
2379 options: &WithMarks(marks),
2380 },
2381 tx_metadata,
2382 |local_ip| {
2383 IcmpPacketBuilder::<Ipv4, _>::new(
2384 local_ip.addr(),
2385 original_src_ip.addr(),
2386 $code,
2387 $message,
2388 )
2389 .wrap_body(original_packet)
2390 },
2391 )
2392 );
2393 }};
2394 }
2395
2396 match message {
2397 Icmpv4ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2398 Icmpv4ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2399 Icmpv4ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2400 }
2401}
2402
2403fn send_icmpv6_error_message<B, BC, CC>(
2404 core_ctx: &mut CC,
2405 bindings_ctx: &mut BC,
2406 device: Option<&CC::DeviceId>,
2407 frame_dst: Option<LocalFrameDestination>,
2408 original_src_ip: SocketIpAddr<Ipv6Addr>,
2409 original_dst_ip: SocketIpAddr<Ipv6Addr>,
2410 message: Icmpv6ErrorMessage,
2411 original_packet: B,
2412 allow_dst_multicast: bool,
2413 marks: &Marks,
2414) where
2415 B: BufferMut,
2416 BC: IcmpBindingsContext,
2417 CC: IcmpSendContext<Ipv6, BC> + CounterContext<IcmpTxCounters<Ipv6>>,
2418{
2419 if !should_send_icmpv6_error(
2423 frame_dst,
2424 original_src_ip.into(),
2425 original_dst_ip.into(),
2426 allow_dst_multicast,
2427 ) {
2428 return;
2429 }
2430
2431 struct Icmpv6ErrorOptions<'a>(&'a Marks);
2432 impl<'a> OptionDelegationMarker for Icmpv6ErrorOptions<'a> {}
2433 impl<'a> DelegatedSendOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2434 fn mtu(&self) -> Mtu {
2435 Ipv6::MINIMUM_LINK_MTU
2436 }
2437 }
2438 impl<'a> DelegatedRouteResolutionOptions<Ipv6> for Icmpv6ErrorOptions<'a> {
2439 fn marks(&self) -> &Marks {
2440 let Self(marks) = self;
2441 marks
2442 }
2443 }
2444
2445 let tx_metadata: BC::TxMetadata = Default::default();
2446
2447 macro_rules! send {
2448 ($message:expr, $code:expr) => {{
2449 let _ = try_send_error!(
2452 core_ctx,
2453 bindings_ctx,
2454 core_ctx.send_oneshot_ip_packet_with_dyn_serializer(
2455 bindings_ctx,
2456 IpSocketArgs {
2457 device: device.map(EitherDeviceId::Strong),
2458 local_ip: None,
2459 remote_ip: original_src_ip,
2460 proto: Ipv6Proto::Icmpv6,
2461 options: &Icmpv6ErrorOptions(marks),
2462 },
2463 tx_metadata,
2464 |local_ip| {
2465 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
2466 local_ip.addr(),
2467 original_src_ip.addr(),
2468 $code,
2469 $message,
2470 );
2471
2472 icmp_builder.wrap_body(TruncatingSerializer::new(
2475 original_packet,
2476 TruncateDirection::DiscardBack,
2477 ))
2478 },
2479 )
2480 );
2481 }};
2482 }
2483
2484 match message {
2485 Icmpv6ErrorMessage::TimeExceeded { message, code } => send!(message, code),
2486 Icmpv6ErrorMessage::PacketTooBig { message, code } => send!(message, code),
2487 Icmpv6ErrorMessage::ParameterProblem { message, code } => send!(message, code),
2488 Icmpv6ErrorMessage::DestUnreachable { message, code } => send!(message, code),
2489 }
2490}
2491
2492fn should_send_icmpv4_error(
2519 frame_dst: Option<LocalFrameDestination>,
2520 src_ip: SpecifiedAddr<Ipv4Addr>,
2521 dst_ip: SpecifiedAddr<Ipv4Addr>,
2522) -> bool {
2523 let broadcast_or_multicast_frame_dst = match frame_dst {
2540 Some(FrameDestination::Individual { local: () }) | None => false,
2541 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
2542 };
2543 !(dst_ip.is_multicast()
2544 || dst_ip.is_limited_broadcast()
2545 || broadcast_or_multicast_frame_dst
2546 || src_ip.is_limited_broadcast()
2547 || src_ip.is_multicast()
2548 || src_ip.is_class_e())
2549}
2550
2551fn should_send_icmpv6_error(
2581 frame_dst: Option<LocalFrameDestination>,
2582 src_ip: SpecifiedAddr<Ipv6Addr>,
2583 dst_ip: SpecifiedAddr<Ipv6Addr>,
2584 allow_dst_multicast: bool,
2585) -> bool {
2586 let multicast_frame_dst = match frame_dst {
2589 Some(FrameDestination::Individual { local: () }) | None => false,
2590 Some(FrameDestination::Broadcast) | Some(FrameDestination::Multicast) => true,
2591 };
2592 if (dst_ip.is_multicast() || multicast_frame_dst) && !allow_dst_multicast {
2593 return false;
2594 }
2595 if src_ip.is_multicast() {
2596 return false;
2597 }
2598 true
2599}
2600
2601fn is_icmp_error_or_redirect_message<I: IcmpIpExt>(proto: I::Proto, buf: &[u8]) -> bool {
2613 proto == I::ICMP_IP_PROTO
2614 && peek_message_type::<I::IcmpMessageType>(buf)
2615 .map(IcmpMessageType::is_error_or_redirect)
2616 .unwrap_or(true)
2617}
2618
2619#[cfg(any(test, feature = "testutils"))]
2621pub(crate) mod testutil {
2622 use alloc::vec::Vec;
2623 use net_types::ethernet::Mac;
2624 use net_types::ip::{Ipv6, Ipv6Addr};
2625 use netstack3_base::NetworkSerializationContext;
2626 use packet::{Buf, InnerPacketBuilder as _, NestableSerializer as _, Serializer as _};
2627 use packet_formats::icmp::ndp::options::NdpOptionBuilder;
2628 use packet_formats::icmp::ndp::{
2629 NeighborAdvertisement, NeighborSolicitation, OptionSequenceBuilder,
2630 };
2631 use packet_formats::icmp::{IcmpPacketBuilder, IcmpZeroCode};
2632 use packet_formats::ip::Ipv6Proto;
2633 use packet_formats::ipv6::Ipv6PacketBuilder;
2634
2635 use super::REQUIRED_NDP_IP_PACKET_HOP_LIMIT;
2636
2637 pub fn neighbor_advertisement_ip_packet(
2640 src_ip: Ipv6Addr,
2641 dst_ip: Ipv6Addr,
2642 router_flag: bool,
2643 solicited_flag: bool,
2644 override_flag: bool,
2645 mac: Mac,
2646 ) -> Buf<Vec<u8>> {
2647 OptionSequenceBuilder::new([NdpOptionBuilder::TargetLinkLayerAddress(&mac.bytes())].iter())
2648 .into_serializer()
2649 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2650 src_ip,
2651 dst_ip,
2652 IcmpZeroCode,
2653 NeighborAdvertisement::new(router_flag, solicited_flag, override_flag, src_ip),
2654 ))
2655 .wrap_in(Ipv6PacketBuilder::new(
2656 src_ip,
2657 dst_ip,
2658 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2659 Ipv6Proto::Icmpv6,
2660 ))
2661 .serialize_vec_outer(&mut NetworkSerializationContext::default())
2662 .unwrap()
2663 .unwrap_b()
2664 }
2665
2666 pub fn neighbor_solicitation_ip_packet(
2669 src_ip: Ipv6Addr,
2670 dst_ip: Ipv6Addr,
2671 target_addr: Ipv6Addr,
2672 mac: Mac,
2673 ) -> Buf<Vec<u8>> {
2674 OptionSequenceBuilder::new([NdpOptionBuilder::SourceLinkLayerAddress(&mac.bytes())].iter())
2675 .into_serializer()
2676 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
2677 src_ip,
2678 dst_ip,
2679 IcmpZeroCode,
2680 NeighborSolicitation::new(target_addr),
2681 ))
2682 .wrap_in(Ipv6PacketBuilder::new(
2683 src_ip,
2684 dst_ip,
2685 REQUIRED_NDP_IP_PACKET_HOP_LIMIT,
2686 Ipv6Proto::Icmpv6,
2687 ))
2688 .serialize_vec_outer(&mut NetworkSerializationContext::default())
2689 .unwrap()
2690 .unwrap_b()
2691 }
2692}
2693
2694#[cfg(test)]
2695mod tests {
2696 use alloc::vec;
2697 use alloc::vec::Vec;
2698 use packet_formats::icmp::ndp::options::NdpNonce;
2699
2700 use core::fmt::Debug;
2701 use core::time::Duration;
2702
2703 use net_types::ip::Subnet;
2704 use netstack3_base::testutil::{
2705 FakeBindingsCtx, FakeCoreCtx, FakeDeviceId, FakeInstant, FakeTxMetadata, FakeWeakDeviceId,
2706 TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt, set_logger_for_test,
2707 };
2708 use netstack3_base::{CtxPair, NetworkSerializationContext, Uninstantiable};
2709 use netstack3_filter::TransportPacketSerializer;
2710 use packet::{Buf, EmptyBuf, NestableSerializer as _, Serializer as _};
2711 use packet_formats::icmp::mld::MldPacket;
2712 use packet_formats::ip::IpProto;
2713 use packet_formats::utils::NonZeroDuration;
2714
2715 use super::*;
2716 use crate::internal::base::{IpDeviceEgressStateContext, RouterAdvertisementEvent};
2717 use crate::internal::gso::MaybeSegmentableTransportSerializer;
2718 use crate::internal::socket::testutil::{FakeDeviceConfig, FakeIpSocketCtx};
2719 use crate::internal::socket::{
2720 IpSock, IpSockCreationError, IpSockSendError, IpSocketHandler, SendOptions,
2721 };
2722 use crate::socket::RouteResolutionOptions;
2723
2724 pub(super) trait IcmpTestIpExt:
2725 TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt
2726 {
2727 }
2728 impl<I: TestIpExt + IpExt + FilterIpExt + IcmpCountersIpExt> IcmpTestIpExt for I {}
2729
2730 type InnerIpSocketCtx<I> = FakeCoreCtx<
2732 FakeIpSocketCtx<I, FakeDeviceId>,
2733 SendIpPacketMeta<I, FakeDeviceId, SpecifiedAddr<<I as Ip>::Addr>>,
2734 FakeDeviceId,
2735 >;
2736
2737 pub(super) struct FakeIcmpCoreCtx<I: IcmpTestIpExt> {
2739 ip_socket_ctx: InnerIpSocketCtx<I>,
2740 icmp: FakeIcmpCoreCtxState<I>,
2741 }
2742
2743 type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<
2745 (),
2746 RouterAdvertisementEvent<FakeDeviceId>,
2747 FakeIcmpBindingsCtxState<I>,
2748 (),
2749 >;
2750
2751 pub(super) type FakeIcmpCtx<I> = CtxPair<FakeIcmpCoreCtx<I>, FakeIcmpBindingsCtx<I>>;
2755
2756 pub(super) struct FakeIcmpCoreCtxState<I: IcmpTestIpExt> {
2757 error_send_bucket: TokenBucket<FakeInstant>,
2758 receive_icmp_error: Vec<I::ErrorCode>,
2759 rx_counters: IcmpRxCounters<I>,
2760 tx_counters: IcmpTxCounters<I>,
2761 ndp_counters: NdpCounters,
2762 }
2763
2764 impl<I: IcmpTestIpExt> FakeIcmpCoreCtx<I> {
2765 fn with_errors_per_second(errors_per_second: u64) -> Self {
2766 Self {
2767 icmp: FakeIcmpCoreCtxState {
2768 error_send_bucket: TokenBucket::new(errors_per_second),
2769 receive_icmp_error: Default::default(),
2770 rx_counters: Default::default(),
2771 tx_counters: Default::default(),
2772 ndp_counters: Default::default(),
2773 },
2774 ip_socket_ctx: InnerIpSocketCtx::with_state(FakeIpSocketCtx::new(
2775 core::iter::once(FakeDeviceConfig {
2776 device: FakeDeviceId,
2777 local_ips: vec![I::TEST_ADDRS.local_ip],
2778 remote_ips: vec![I::TEST_ADDRS.remote_ip],
2779 }),
2780 )),
2781 }
2782 }
2783 }
2784
2785 impl<I: IcmpTestIpExt> Default for FakeIcmpCoreCtx<I> {
2786 fn default() -> Self {
2787 Self::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND)
2788 }
2789 }
2790
2791 impl<I: IcmpTestIpExt> DeviceIdContext<AnyDevice> for FakeIcmpCoreCtx<I> {
2792 type DeviceId = FakeDeviceId;
2793 type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
2794 }
2795
2796 impl<I: IcmpTestIpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
2797 impl<I: IcmpTestIpExt> IcmpStateContext for InnerIpSocketCtx<I> {}
2798
2799 impl<I: IcmpTestIpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
2800 fn counters(&self) -> &IcmpRxCounters<I> {
2801 &self.icmp.rx_counters
2802 }
2803 }
2804
2805 impl<I: IcmpTestIpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
2806 fn counters(&self) -> &IcmpTxCounters<I> {
2807 &self.icmp.tx_counters
2808 }
2809 }
2810
2811 impl<I: IcmpTestIpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
2812 fn counters(&self) -> &NdpCounters {
2813 &self.icmp.ndp_counters
2814 }
2815 }
2816
2817 pub enum FakeEchoIpTransportContext {}
2818
2819 impl EchoTransportContextMarker for FakeEchoIpTransportContext {}
2820
2821 impl<I> IpTransportContext<I, FakeIcmpBindingsCtx<I>, FakeIcmpCoreCtx<I>>
2822 for FakeEchoIpTransportContext
2823 where
2824 I: IcmpTestIpExt + IpLayerIpExt,
2825 {
2826 type EarlyDemuxSocket = !;
2827
2828 fn early_demux<B: ParseBuffer>(
2829 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2830 _device: &FakeDeviceId,
2831 _src_ip: I::Addr,
2832 _dst_ip: I::Addr,
2833 _buffer: B,
2834 ) -> Option<Self::EarlyDemuxSocket> {
2835 None
2836 }
2837
2838 fn receive_icmp_error(
2839 core_ctx: &mut FakeIcmpCoreCtx<I>,
2840 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2841 _device: &FakeDeviceId,
2842 _original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2843 _original_dst_ip: SpecifiedAddr<I::Addr>,
2844 _original_body: &[u8],
2845 _err: I::ErrorCode,
2846 ) {
2847 core_ctx.icmp.rx_counters.error_delivered_to_socket.increment()
2848 }
2849
2850 fn receive_ip_packet<B: BufferMut, H: IpHeaderInfo<I>>(
2851 _core_ctx: &mut FakeIcmpCoreCtx<I>,
2852 _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2853 _device: &FakeDeviceId,
2854 _src_ip: I::RecvSrcAddr,
2855 _dst_ip: SpecifiedAddr<I::Addr>,
2856 _buffer: B,
2857 _info: &mut LocalDeliveryPacketInfo<I, H>,
2858 _early_demux_socket: Option<!>,
2859 ) -> Result<(), (B, I::IcmpError)> {
2860 unimplemented!()
2861 }
2862 }
2863
2864 impl<I: IpLayerIpExt + IcmpTestIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>>
2865 for FakeIcmpCoreCtx<I>
2866 {
2867 type EchoTransportContext = FakeEchoIpTransportContext;
2868
2869 fn receive_icmp_error(
2870 &mut self,
2871 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
2872 device: &Self::DeviceId,
2873 original_src_ip: Option<SpecifiedAddr<I::Addr>>,
2874 original_dst_ip: SpecifiedAddr<I::Addr>,
2875 original_proto: I::Proto,
2876 original_body: &[u8],
2877 err: I::ErrorCode,
2878 ) {
2879 CounterContext::<IcmpRxCounters<I>>::counters(self).error.increment();
2880 self.icmp.receive_icmp_error.push(err);
2881 if original_proto == I::ICMP_IP_PROTO {
2882 receive_ip_transport_icmp_error(
2883 self,
2884 bindings_ctx,
2885 device,
2886 original_src_ip,
2887 original_dst_ip,
2888 original_body,
2889 err,
2890 )
2891 }
2892 }
2893 }
2894
2895 impl<I: IpLayerIpExt + IcmpTestIpExt> IcmpSendContext<I, FakeIcmpBindingsCtx<I>>
2896 for FakeIcmpCoreCtx<I>
2897 {
2898 fn with_error_send_bucket_mut<O, F: FnOnce(&mut TokenBucket<FakeInstant>) -> O>(
2899 &mut self,
2900 cb: F,
2901 ) -> O {
2902 cb(&mut self.icmp.error_send_bucket)
2903 }
2904 }
2905
2906 #[test]
2907 fn test_should_send_icmpv4_error() {
2908 let src_ip = TEST_ADDRS_V4.local_ip;
2909 let dst_ip = TEST_ADDRS_V4.remote_ip;
2910 let frame_dst = FrameDestination::Individual { local: () };
2911 let multicast_ip_1 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 1])).unwrap();
2912 let multicast_ip_2 = SpecifiedAddr::new(Ipv4Addr::new([224, 0, 0, 2])).unwrap();
2913
2914 assert!(should_send_icmpv4_error(Some(frame_dst), src_ip, dst_ip));
2916 assert!(should_send_icmpv4_error(None, src_ip, dst_ip));
2917
2918 assert!(should_send_icmpv4_error(
2920 Some(frame_dst),
2921 Ipv4::LOOPBACK_ADDRESS,
2922 Ipv4::LOOPBACK_ADDRESS,
2923 ));
2924
2925 assert!(!should_send_icmpv4_error(
2927 Some(frame_dst),
2928 src_ip,
2929 Ipv4::LIMITED_BROADCAST_ADDRESS,
2930 ));
2931
2932 assert!(!should_send_icmpv4_error(Some(frame_dst), src_ip, multicast_ip_1,));
2934
2935 assert!(!should_send_icmpv4_error(Some(FrameDestination::Broadcast), src_ip, dst_ip,));
2937
2938 assert!(!should_send_icmpv4_error(Some(FrameDestination::Multicast), src_ip, dst_ip));
2940
2941 assert!(!should_send_icmpv4_error(
2943 Some(frame_dst),
2944 Ipv4::LIMITED_BROADCAST_ADDRESS,
2945 dst_ip,
2946 ));
2947
2948 assert!(!should_send_icmpv4_error(Some(frame_dst), multicast_ip_2, dst_ip));
2950
2951 assert!(!should_send_icmpv4_error(
2953 Some(frame_dst),
2954 SpecifiedAddr::new(Ipv4Addr::new([240, 0, 0, 1])).unwrap(),
2955 dst_ip,
2956 ));
2957 }
2958
2959 #[test]
2960 fn test_should_send_icmpv6_error() {
2961 let src_ip = TEST_ADDRS_V6.local_ip;
2962 let dst_ip = TEST_ADDRS_V6.remote_ip;
2963 let frame_dst = FrameDestination::Individual { local: () };
2964 let multicast_ip_1 =
2965 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 1])).unwrap();
2966 let multicast_ip_2 =
2967 SpecifiedAddr::new(Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 2])).unwrap();
2968
2969 assert!(should_send_icmpv6_error(
2971 Some(frame_dst),
2972 src_ip,
2973 dst_ip,
2974 false ));
2976 assert!(should_send_icmpv6_error(
2977 None, src_ip, dst_ip, false ));
2979 assert!(should_send_icmpv6_error(
2980 Some(frame_dst),
2981 src_ip,
2982 dst_ip,
2983 true ));
2985
2986 assert!(should_send_icmpv6_error(
2988 Some(frame_dst),
2989 Ipv6::LOOPBACK_ADDRESS,
2990 Ipv6::LOOPBACK_ADDRESS,
2991 false ));
2993 assert!(should_send_icmpv6_error(
2994 Some(frame_dst),
2995 Ipv6::LOOPBACK_ADDRESS,
2996 Ipv6::LOOPBACK_ADDRESS,
2997 true ));
2999
3000 assert!(!should_send_icmpv6_error(
3003 Some(frame_dst),
3004 src_ip,
3005 multicast_ip_1,
3006 false ));
3008 assert!(should_send_icmpv6_error(
3009 Some(frame_dst),
3010 src_ip,
3011 multicast_ip_1,
3012 true ));
3014
3015 assert!(!should_send_icmpv6_error(
3018 Some(FrameDestination::Broadcast),
3019 src_ip,
3020 dst_ip,
3021 false ));
3023 assert!(should_send_icmpv6_error(
3024 Some(FrameDestination::Broadcast),
3025 src_ip,
3026 dst_ip,
3027 true ));
3029
3030 assert!(!should_send_icmpv6_error(
3033 Some(FrameDestination::Multicast),
3034 src_ip,
3035 dst_ip,
3036 false ));
3038 assert!(should_send_icmpv6_error(
3039 Some(FrameDestination::Multicast),
3040 src_ip,
3041 dst_ip,
3042 true ));
3044
3045 assert!(!should_send_icmpv6_error(
3047 Some(frame_dst),
3048 multicast_ip_2,
3049 dst_ip,
3050 false ));
3052 assert!(!should_send_icmpv6_error(
3053 Some(frame_dst),
3054 multicast_ip_2,
3055 dst_ip,
3056 true ));
3058
3059 assert!(!should_send_icmpv6_error(
3062 Some(FrameDestination::Broadcast),
3063 multicast_ip_2,
3064 dst_ip,
3065 false ));
3067 assert!(!should_send_icmpv6_error(
3068 Some(FrameDestination::Broadcast),
3069 multicast_ip_2,
3070 dst_ip,
3071 true ));
3073 assert!(!should_send_icmpv6_error(
3074 Some(frame_dst),
3075 multicast_ip_2,
3076 multicast_ip_1,
3077 false ));
3079 assert!(!should_send_icmpv6_error(
3080 Some(frame_dst),
3081 multicast_ip_2,
3082 multicast_ip_1,
3083 true ));
3085 }
3086
3087 #[derive(Default)]
3094 pub(super) struct FakeIcmpBindingsCtxState<I: IpExt> {
3095 _marker: core::marker::PhantomData<I>,
3096 }
3097
3098 impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
3099 fn should_send_timestamp_reply(&self) -> bool {
3100 false
3101 }
3102 }
3103 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
3104 impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
3105
3106 impl<I: IcmpTestIpExt> IpSocketHandler<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
3107 fn new_ip_socket<O>(
3108 &mut self,
3109 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3110 args: IpSocketArgs<'_, Self::DeviceId, I, O>,
3111 ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>
3112 where
3113 O: RouteResolutionOptions<I>,
3114 {
3115 self.ip_socket_ctx.new_ip_socket(bindings_ctx, args)
3116 }
3117
3118 fn send_ip_packet<S, O>(
3119 &mut self,
3120 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3121 socket: &IpSock<I, Self::WeakDeviceId>,
3122 body: S,
3123 options: &O,
3124 tx_meta: FakeTxMetadata,
3125 ) -> Result<(), IpSockSendError>
3126 where
3127 S: TransportPacketSerializer<I> + MaybeSegmentableTransportSerializer,
3128 S::Buffer: BufferMut,
3129 O: SendOptions<I> + RouteResolutionOptions<I>,
3130 {
3131 self.ip_socket_ctx.send_ip_packet(bindings_ctx, socket, body, options, tx_meta)
3132 }
3133
3134 fn confirm_reachable<O>(
3135 &mut self,
3136 bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
3137 socket: &IpSock<I, Self::WeakDeviceId>,
3138 options: &O,
3139 ) where
3140 O: RouteResolutionOptions<I>,
3141 {
3142 self.ip_socket_ctx.confirm_reachable(bindings_ctx, socket, options)
3143 }
3144 }
3145
3146 impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3147 fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
3148 unimplemented!()
3149 }
3150
3151 fn set_default_hop_limit(&mut self, _device_id: &Self::DeviceId, _hop_limit: NonZeroU8) {
3152 unreachable!()
3153 }
3154
3155 fn handle_received_dad_packet(
3156 &mut self,
3157 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3158 _device_id: &Self::DeviceId,
3159 _addr: SpecifiedAddr<Ipv6Addr>,
3160 _probe_data: Option<NdpNonce<&'_ [u8]>>,
3161 ) -> Option<IpAddressState> {
3162 unimplemented!()
3163 }
3164 }
3165
3166 impl IpDeviceEgressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3167 fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
3168 cb(&())
3169 }
3170
3171 fn get_local_addr_for_remote(
3172 &mut self,
3173 _device_id: &Self::DeviceId,
3174 _remote: Option<SpecifiedAddr<Ipv6Addr>>,
3175 ) -> Option<IpDeviceAddr<Ipv6Addr>> {
3176 unimplemented!()
3177 }
3178
3179 fn get_hop_limit(&mut self, _device_id: &Self::DeviceId) -> NonZeroU8 {
3180 unimplemented!()
3181 }
3182 }
3183
3184 impl IpDeviceIngressStateContext<Ipv6> for FakeIcmpCoreCtx<Ipv6> {
3185 fn address_status_for_device(
3186 &mut self,
3187 _addr: SpecifiedAddr<Ipv6Addr>,
3188 _device_id: &Self::DeviceId,
3189 ) -> AddressStatus<Ipv6PresentAddressStatus> {
3190 unimplemented!()
3191 }
3192 }
3193
3194 impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3195 type LinkLayerAddr = Uninstantiable;
3196
3197 fn get_link_layer_addr(&mut self, _device_id: &Self::DeviceId) -> Option<Uninstantiable> {
3198 unimplemented!()
3199 }
3200
3201 fn set_discovered_retrans_timer(
3202 &mut self,
3203 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3204 _device_id: &Self::DeviceId,
3205 _retrans_timer: NonZeroDuration,
3206 ) {
3207 unimplemented!()
3208 }
3209
3210 fn set_link_mtu(&mut self, _device_id: &Self::DeviceId, _mtu: Mtu) {
3211 unimplemented!()
3212 }
3213
3214 fn update_discovered_ipv6_route(
3215 &mut self,
3216 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3217 _device_id: &Self::DeviceId,
3218 _route: Ipv6DiscoveredRoute,
3219 _properties: Ipv6DiscoveredRouteProperties,
3220 _lifetime: Option<NonZeroNdpLifetime>,
3221 ) {
3222 unimplemented!()
3223 }
3224
3225 fn apply_slaac_update(
3226 &mut self,
3227 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3228 _device_id: &Self::DeviceId,
3229 _subnet: Subnet<Ipv6Addr>,
3230 _preferred_lifetime: Option<NonZeroNdpLifetime>,
3231 _valid_lifetime: Option<NonZeroNdpLifetime>,
3232 ) {
3233 unimplemented!()
3234 }
3235
3236 fn receive_mld_packet<B: SplitByteSlice, H: IpHeaderInfo<Ipv6>>(
3237 &mut self,
3238 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3239 _device: &FakeDeviceId,
3240 _src_ip: Ipv6SourceAddr,
3241 _dst_ip: SpecifiedAddr<Ipv6Addr>,
3242 _packet: MldPacket<B>,
3243 _header_info: &H,
3244 ) {
3245 unimplemented!()
3246 }
3247 }
3248
3249 impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3250 fn send_ip_packet_from_device<S>(
3251 &mut self,
3252 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3253 _meta: SendIpPacketMeta<Ipv6, &Self::DeviceId, Option<SpecifiedAddr<Ipv6Addr>>>,
3254 _body: S,
3255 ) -> Result<(), IpSendFrameError<S>> {
3256 unimplemented!()
3257 }
3258
3259 fn send_ip_frame<S>(
3260 &mut self,
3261 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3262 _device: &Self::DeviceId,
3263 _destination: IpPacketDestination<Ipv6, &Self::DeviceId>,
3264 _body: S,
3265 ) -> Result<(), IpSendFrameError<S>>
3266 where
3267 S: NetworkSerializer,
3268 S::Buffer: BufferMut,
3269 {
3270 unimplemented!()
3271 }
3272 }
3273
3274 impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
3275 fn handle_neighbor_probe(
3276 &mut self,
3277 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3278 _device_id: &Self::DeviceId,
3279 _neighbor: SpecifiedAddr<Ipv6Addr>,
3280 _link_addr: &[u8],
3281 ) {
3282 unimplemented!()
3283 }
3284
3285 fn handle_neighbor_confirmation(
3286 &mut self,
3287 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3288 _device_id: &Self::DeviceId,
3289 _neighbor: SpecifiedAddr<Ipv6Addr>,
3290 _link_addr: Option<&[u8]>,
3291 _flags: ConfirmationFlags,
3292 ) {
3293 unimplemented!()
3294 }
3295
3296 fn flush_neighbor_table(
3297 &mut self,
3298 _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
3299 _device_id: &Self::DeviceId,
3300 ) {
3301 unimplemented!()
3302 }
3303 }
3304
3305 #[test]
3306 fn test_receive_icmpv4_error() {
3307 const ICMP_ID: u16 = 0x0F;
3310 const SEQ_NUM: u16 = 0xF0;
3311
3312 fn test_receive_icmpv4_error_helper<
3327 C: Debug,
3328 M: IcmpMessage<Ipv4, Code = C> + Debug,
3329 F: Fn(&FakeIcmpCtx<Ipv4>),
3330 >(
3331 original_packet: &mut [u8],
3332 code: C,
3333 msg: M,
3334 f: F,
3335 ) {
3336 set_logger_for_test();
3337
3338 let mut ctx: FakeIcmpCtx<Ipv4> = FakeIcmpCtx::default();
3339
3340 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3341 <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
3342 core_ctx,
3343 bindings_ctx,
3344 &FakeDeviceId,
3345 Ipv4SourceAddr::new(*TEST_ADDRS_V4.remote_ip).unwrap(),
3346 TEST_ADDRS_V4.local_ip,
3347 IcmpPacketBuilder::new(TEST_ADDRS_V4.remote_ip, TEST_ADDRS_V4.local_ip, code, msg)
3348 .wrap_body(Buf::new(original_packet, ..))
3349 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3350 .unwrap(),
3351 &mut LocalDeliveryPacketInfo::default(),
3352 None,
3353 )
3354 .unwrap();
3355 f(&ctx);
3356 }
3357 let mut buffer = EmptyBuf
3370 .wrap_in(IcmpPacketBuilder::<Ipv4, _>::new(
3371 TEST_ADDRS_V4.local_ip,
3372 TEST_ADDRS_V4.remote_ip,
3373 IcmpZeroCode,
3374 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3375 ))
3376 .wrap_in(<Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::<
3377 NetworkSerializationContext,
3378 >::new(
3379 TEST_ADDRS_V4.local_ip, TEST_ADDRS_V4.remote_ip, 64, Ipv4Proto::Icmp
3380 ))
3381 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3382 .unwrap();
3383
3384 test_receive_icmpv4_error_helper(
3385 buffer.as_mut(),
3386 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3387 IcmpDestUnreachable::default(),
3388 |CtxPair { core_ctx, bindings_ctx: _ }| {
3389 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3390 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3391 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3392 assert_eq!(
3393 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3394 1
3395 );
3396 let err = Icmpv4ErrorCode::DestUnreachable(
3397 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3398 IcmpDestUnreachable::default(),
3399 );
3400 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3401 },
3402 );
3403
3404 test_receive_icmpv4_error_helper(
3405 buffer.as_mut(),
3406 Icmpv4TimeExceededCode::TtlExpired,
3407 IcmpTimeExceeded::default(),
3408 |CtxPair { core_ctx, bindings_ctx: _ }| {
3409 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3410 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3411 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3412 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3413 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3414 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3415 },
3416 );
3417
3418 test_receive_icmpv4_error_helper(
3419 buffer.as_mut(),
3420 Icmpv4ParameterProblemCode::PointerIndicatesError,
3421 Icmpv4ParameterProblem::new(0),
3422 |CtxPair { core_ctx, bindings_ctx: _ }| {
3423 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3424 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3425 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3426 assert_eq!(
3427 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3428 1
3429 );
3430 let err = Icmpv4ErrorCode::ParameterProblem(
3431 Icmpv4ParameterProblemCode::PointerIndicatesError,
3432 );
3433 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3434 },
3435 );
3436
3437 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::<
3444 NetworkSerializationContext,
3445 >::new(
3446 TEST_ADDRS_V4.local_ip, TEST_ADDRS_V4.remote_ip, 64, Ipv4Proto::Icmp
3447 )
3448 .wrap_body(EmptyBuf)
3449 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3450 .unwrap();
3451
3452 test_receive_icmpv4_error_helper(
3453 buffer.as_mut(),
3454 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3455 IcmpDestUnreachable::default(),
3456 |CtxPair { core_ctx, bindings_ctx: _ }| {
3457 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3458 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3459 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3460 assert_eq!(
3461 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3462 1
3463 );
3464 let err = Icmpv4ErrorCode::DestUnreachable(
3465 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3466 IcmpDestUnreachable::default(),
3467 );
3468 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3469 },
3470 );
3471
3472 test_receive_icmpv4_error_helper(
3473 buffer.as_mut(),
3474 Icmpv4TimeExceededCode::TtlExpired,
3475 IcmpTimeExceeded::default(),
3476 |CtxPair { core_ctx, bindings_ctx: _ }| {
3477 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3478 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3479 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3480 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3481 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3482 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3483 },
3484 );
3485
3486 test_receive_icmpv4_error_helper(
3487 buffer.as_mut(),
3488 Icmpv4ParameterProblemCode::PointerIndicatesError,
3489 Icmpv4ParameterProblem::new(0),
3490 |CtxPair { core_ctx, bindings_ctx: _ }| {
3491 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3492 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3493 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3494 assert_eq!(
3495 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3496 1
3497 );
3498 let err = Icmpv4ErrorCode::ParameterProblem(
3499 Icmpv4ParameterProblemCode::PointerIndicatesError,
3500 );
3501 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3502 },
3503 );
3504
3505 let mut buffer = <Ipv4 as packet_formats::ip::IpExt>::PacketBuilder::<
3511 NetworkSerializationContext,
3512 >::new(
3513 TEST_ADDRS_V4.local_ip, TEST_ADDRS_V4.remote_ip, 64, IpProto::Udp.into()
3514 )
3515 .wrap_body(EmptyBuf)
3516 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3517 .unwrap();
3518
3519 test_receive_icmpv4_error_helper(
3520 buffer.as_mut(),
3521 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3522 IcmpDestUnreachable::default(),
3523 |CtxPair { core_ctx, bindings_ctx: _ }| {
3524 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3525 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3526 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3527 assert_eq!(
3528 core_ctx.icmp.rx_counters.dest_unreachable.dest_network_unreachable.get(),
3529 1
3530 );
3531 let err = Icmpv4ErrorCode::DestUnreachable(
3532 Icmpv4DestUnreachableCode::DestNetworkUnreachable,
3533 IcmpDestUnreachable::default(),
3534 );
3535 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3536 },
3537 );
3538
3539 test_receive_icmpv4_error_helper(
3540 buffer.as_mut(),
3541 Icmpv4TimeExceededCode::TtlExpired,
3542 IcmpTimeExceeded::default(),
3543 |CtxPair { core_ctx, bindings_ctx: _ }| {
3544 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3545 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3546 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3547 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.ttl_expired.get(), 1);
3548 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
3549 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3550 },
3551 );
3552
3553 test_receive_icmpv4_error_helper(
3554 buffer.as_mut(),
3555 Icmpv4ParameterProblemCode::PointerIndicatesError,
3556 Icmpv4ParameterProblem::new(0),
3557 |CtxPair { core_ctx, bindings_ctx: _ }| {
3558 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3559 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3560 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3561 assert_eq!(
3562 core_ctx.icmp.rx_counters.parameter_problem.pointer_indicates_error.get(),
3563 1
3564 );
3565 let err = Icmpv4ErrorCode::ParameterProblem(
3566 Icmpv4ParameterProblemCode::PointerIndicatesError,
3567 );
3568 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3569 },
3570 );
3571 }
3572
3573 #[test]
3574 fn test_receive_icmpv6_error() {
3575 const ICMP_ID: u16 = 0x0F;
3578 const SEQ_NUM: u16 = 0xF0;
3579
3580 fn test_receive_icmpv6_error_helper<
3595 C: Debug,
3596 M: IcmpMessage<Ipv6, Code = C> + Debug,
3597 F: Fn(&FakeIcmpCtx<Ipv6>),
3598 >(
3599 original_packet: &mut [u8],
3600 code: C,
3601 msg: M,
3602 f: F,
3603 ) {
3604 set_logger_for_test();
3605
3606 let mut ctx = FakeIcmpCtx::<Ipv6>::default();
3607 let CtxPair { core_ctx, bindings_ctx } = &mut ctx;
3608 <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
3609 core_ctx,
3610 bindings_ctx,
3611 &FakeDeviceId,
3612 TEST_ADDRS_V6.remote_ip.get().try_into().unwrap(),
3613 TEST_ADDRS_V6.local_ip,
3614 IcmpPacketBuilder::new(TEST_ADDRS_V6.remote_ip, TEST_ADDRS_V6.local_ip, code, msg)
3615 .wrap_body(Buf::new(original_packet, ..))
3616 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3617 .unwrap(),
3618 &mut LocalDeliveryPacketInfo::default(),
3619 None,
3620 )
3621 .unwrap();
3622 f(&ctx);
3623 }
3624 let mut buffer = EmptyBuf
3637 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
3638 TEST_ADDRS_V6.local_ip,
3639 TEST_ADDRS_V6.remote_ip,
3640 IcmpZeroCode,
3641 IcmpEchoRequest::new(ICMP_ID, SEQ_NUM),
3642 ))
3643 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::<
3644 NetworkSerializationContext,
3645 >::new(
3646 TEST_ADDRS_V6.local_ip, TEST_ADDRS_V6.remote_ip, 64, Ipv6Proto::Icmpv6
3647 ))
3648 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3649 .unwrap();
3650
3651 test_receive_icmpv6_error_helper(
3652 buffer.as_mut(),
3653 Icmpv6DestUnreachableCode::NoRoute,
3654 IcmpDestUnreachable::default(),
3655 |CtxPair { core_ctx, bindings_ctx: _ }| {
3656 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3657 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3658 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3659 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3660 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3661 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3662 },
3663 );
3664
3665 test_receive_icmpv6_error_helper(
3666 buffer.as_mut(),
3667 Icmpv6TimeExceededCode::HopLimitExceeded,
3668 IcmpTimeExceeded::default(),
3669 |CtxPair { core_ctx, bindings_ctx: _ }| {
3670 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3671 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3672 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3673 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3674 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3675 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3676 },
3677 );
3678
3679 test_receive_icmpv6_error_helper(
3680 buffer.as_mut(),
3681 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3682 Icmpv6ParameterProblem::new(0),
3683 |CtxPair { core_ctx, bindings_ctx: _ }| {
3684 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3685 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3686 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 1);
3687 assert_eq!(
3688 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3689 1
3690 );
3691 let err = Icmpv6ErrorCode::ParameterProblem(
3692 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3693 );
3694 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3695 },
3696 );
3697
3698 let mut buffer = EmptyBuf
3705 .wrap_in(<Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::<
3706 NetworkSerializationContext,
3707 >::new(
3708 TEST_ADDRS_V6.local_ip, TEST_ADDRS_V6.remote_ip, 64, Ipv6Proto::Icmpv6
3709 ))
3710 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3711 .unwrap();
3712
3713 test_receive_icmpv6_error_helper(
3714 buffer.as_mut(),
3715 Icmpv6DestUnreachableCode::NoRoute,
3716 IcmpDestUnreachable::default(),
3717 |CtxPair { core_ctx, bindings_ctx: _ }| {
3718 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3719 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3720 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3721 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3722 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3723 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3724 },
3725 );
3726
3727 test_receive_icmpv6_error_helper(
3728 buffer.as_mut(),
3729 Icmpv6TimeExceededCode::HopLimitExceeded,
3730 IcmpTimeExceeded::default(),
3731 |CtxPair { core_ctx, bindings_ctx: _ }| {
3732 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3733 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3734 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3735 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3736 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3737 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3738 },
3739 );
3740
3741 test_receive_icmpv6_error_helper(
3742 buffer.as_mut(),
3743 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3744 Icmpv6ParameterProblem::new(0),
3745 |CtxPair { core_ctx, bindings_ctx: _ }| {
3746 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3747 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 1);
3748 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3749 assert_eq!(
3750 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3751 1
3752 );
3753 let err = Icmpv6ErrorCode::ParameterProblem(
3754 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3755 );
3756 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3757 },
3758 );
3759
3760 let mut buffer = <Ipv6 as packet_formats::ip::IpExt>::PacketBuilder::<
3766 NetworkSerializationContext,
3767 >::new(
3768 TEST_ADDRS_V6.local_ip, TEST_ADDRS_V6.remote_ip, 64, IpProto::Udp.into()
3769 )
3770 .wrap_body(EmptyBuf)
3771 .serialize_vec_outer(&mut NetworkSerializationContext::default())
3772 .unwrap();
3773
3774 test_receive_icmpv6_error_helper(
3775 buffer.as_mut(),
3776 Icmpv6DestUnreachableCode::NoRoute,
3777 IcmpDestUnreachable::default(),
3778 |CtxPair { core_ctx, bindings_ctx: _ }| {
3779 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3780 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3781 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3782 assert_eq!(core_ctx.icmp.rx_counters.dest_unreachable.no_route.get(), 1);
3783 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
3784 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3785 },
3786 );
3787
3788 test_receive_icmpv6_error_helper(
3789 buffer.as_mut(),
3790 Icmpv6TimeExceededCode::HopLimitExceeded,
3791 IcmpTimeExceeded::default(),
3792 |CtxPair { core_ctx, bindings_ctx: _ }| {
3793 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3794 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3795 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3796 assert_eq!(core_ctx.icmp.rx_counters.time_exceeded.hop_limit_exceeded.get(), 1);
3797 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
3798 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3799 },
3800 );
3801
3802 test_receive_icmpv6_error_helper(
3803 buffer.as_mut(),
3804 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3805 Icmpv6ParameterProblem::new(0),
3806 |CtxPair { core_ctx, bindings_ctx: _ }| {
3807 assert_eq!(core_ctx.icmp.rx_counters.error.get(), 1);
3808 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_transport_layer.get(), 0);
3809 assert_eq!(core_ctx.icmp.rx_counters.error_delivered_to_socket.get(), 0);
3810 assert_eq!(
3811 core_ctx.icmp.rx_counters.parameter_problem.unrecognized_next_header_type.get(),
3812 1
3813 );
3814 let err = Icmpv6ErrorCode::ParameterProblem(
3815 Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
3816 );
3817 assert_eq!(core_ctx.icmp.receive_icmp_error, [err]);
3818 },
3819 );
3820 }
3821
3822 #[test]
3823 fn test_error_rate_limit() {
3824 set_logger_for_test();
3825
3826 fn send_icmpv4_ttl_expired_helper(
3828 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3829 ) {
3830 let error = Icmpv4Error::TtlExpired;
3831 core_ctx.send_icmp_error_message(
3832 bindings_ctx,
3833 Some(&FakeDeviceId),
3834 Some(FrameDestination::Individual { local: () }),
3835 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3836 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3837 EmptyBuf,
3838 error,
3839 0,
3840 packet_formats::ip::IpProto::Udp.into(),
3841 &Default::default(),
3842 );
3843 let count = core_ctx.icmp.tx_counters.time_exceeded.ttl_expired.get();
3844 assert!(count >= 1, "{count} >= 1");
3845 }
3846
3847 fn send_icmpv4_parameter_problem_helper(
3849 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3850 ) {
3851 let error = Icmpv4Error::ParameterProblem {
3852 code: Icmpv4ParameterProblemCode::PointerIndicatesError,
3853 pointer: 0,
3854 };
3855 core_ctx.send_icmp_error_message(
3856 bindings_ctx,
3857 Some(&FakeDeviceId),
3858 Some(FrameDestination::Individual { local: () }),
3859 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3860 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3861 EmptyBuf,
3862 error,
3863 0,
3864 packet_formats::ip::IpProto::Udp.into(),
3865 &Default::default(),
3866 );
3867 let count = core_ctx.icmp.tx_counters.parameter_problem.pointer_indicates_error.get();
3868 assert!(count >= 1, "{count} >= 1");
3869 }
3870
3871 fn send_icmpv4_dest_unreachable_helper(
3873 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
3874 ) {
3875 core_ctx.send_icmp_error_message(
3876 bindings_ctx,
3877 Some(&FakeDeviceId),
3878 Some(FrameDestination::Individual { local: () }),
3879 TEST_ADDRS_V4.remote_ip.try_into().unwrap(),
3880 TEST_ADDRS_V4.local_ip.try_into().unwrap(),
3881 EmptyBuf,
3882 Icmpv4Error::NetUnreachable,
3883 0,
3884 packet_formats::ip::IpProto::Udp.into(),
3885 &Default::default(),
3886 );
3887 let count = core_ctx.icmp.tx_counters.dest_unreachable.dest_network_unreachable.get();
3888 assert!(count >= 1, "{count} >= 1");
3889 }
3890
3891 fn send_icmpv6_ttl_expired_helper(
3893 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3894 ) {
3895 core_ctx.send_icmp_error_message(
3896 bindings_ctx,
3897 Some(&FakeDeviceId),
3898 Some(FrameDestination::Individual { local: () }),
3899 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3900 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3901 EmptyBuf,
3902 Icmpv6Error::TtlExpired,
3903 0,
3904 Ipv6Proto::NoNextHeader,
3905 &Default::default(),
3906 );
3907 let count = core_ctx.icmp.tx_counters.time_exceeded.hop_limit_exceeded.get();
3908 assert!(count >= 1, "{count} >= 1");
3909 }
3910
3911 fn send_icmpv6_packet_too_big_helper(
3913 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3914 ) {
3915 core_ctx.send_icmp_error_message(
3916 bindings_ctx,
3917 Some(&FakeDeviceId),
3918 Some(FrameDestination::Individual { local: () }),
3919 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3920 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3921 EmptyBuf,
3922 Icmpv6Error::PacketTooBig { mtu: Mtu::new(1280) },
3923 0,
3924 Ipv6Proto::NoNextHeader,
3925 &Default::default(),
3926 );
3927 let count = core_ctx.icmp.tx_counters.packet_too_big.get();
3928 assert!(count >= 1, "{count} >= 1");
3929 }
3930
3931 fn send_icmpv6_parameter_problem_helper(
3933 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3934 ) {
3935 let error = Icmpv6Error::ParameterProblem {
3936 code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
3937 pointer: 0,
3938 allow_dst_multicast: false,
3939 };
3940 core_ctx.send_icmp_error_message(
3941 bindings_ctx,
3942 Some(&FakeDeviceId),
3943 Some(FrameDestination::Individual { local: () }),
3944 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3945 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3946 EmptyBuf,
3947 error,
3948 0,
3949 Ipv6Proto::NoNextHeader,
3950 &Default::default(),
3951 );
3952 let count = core_ctx.icmp.tx_counters.parameter_problem.erroneous_header_field.get();
3953 assert!(count >= 1, "{count} >= 1");
3954 }
3955
3956 fn send_icmpv6_dest_unreachable_helper(
3958 CtxPair { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
3959 ) {
3960 core_ctx.send_icmp_error_message(
3961 bindings_ctx,
3962 Some(&FakeDeviceId),
3963 Some(FrameDestination::Individual { local: () }),
3964 TEST_ADDRS_V6.remote_ip.try_into().unwrap(),
3965 TEST_ADDRS_V6.local_ip.try_into().unwrap(),
3966 EmptyBuf,
3967 Icmpv6Error::NetUnreachable,
3968 0,
3969 Ipv6Proto::NoNextHeader,
3970 &Default::default(),
3971 );
3972 let count = core_ctx.icmp.tx_counters.dest_unreachable.no_route.get();
3973 assert!(count >= 1, "{count} >= 1");
3974 }
3975
3976 fn run_test<I: IcmpTestIpExt, W: Fn(u64) -> FakeIcmpCtx<I>, S: Fn(&mut FakeIcmpCtx<I>)>(
3980 with_errors_per_second: W,
3981 send: S,
3982 ) {
3983 const ERRORS_PER_SECOND: u64 = 64;
3997
3998 let mut ctx = with_errors_per_second(ERRORS_PER_SECOND);
3999
4000 for i in 0..ERRORS_PER_SECOND {
4001 send(&mut ctx);
4002 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), i + 1);
4003 }
4004
4005 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4006 send(&mut ctx);
4007 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), ERRORS_PER_SECOND);
4008
4009 let mut ctx = with_errors_per_second(0);
4013 send(&mut ctx);
4014 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4015 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4016 send(&mut ctx);
4017 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4018 ctx.bindings_ctx.timers.instant.sleep(Duration::from_secs(1));
4019 send(&mut ctx);
4020 assert_eq!(ctx.core_ctx.icmp.tx_counters.error.get(), 0);
4021 }
4022
4023 fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
4024 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4025 }
4026 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
4027 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_parameter_problem_helper);
4028 run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_dest_unreachable_helper);
4029
4030 fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
4031 CtxPair::with_core_ctx(FakeIcmpCoreCtx::with_errors_per_second(errors_per_second))
4032 }
4033
4034 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_ttl_expired_helper);
4035 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_packet_too_big_helper);
4036 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_parameter_problem_helper);
4037 run_test::<Ipv6, _, _>(with_errors_per_second_v6, send_icmpv6_dest_unreachable_helper);
4038 }
4039}