packet_formats/icmp/
common.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Common ICMP packets.
6
7use core::num::NonZeroU16;
8
9use zerocopy::byteorder::network_endian::U16;
10use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
11
12use super::{IcmpZeroCode, IdAndSeq, OriginalPacket};
13
14/// An ICMP Destination Unreachable message.
15#[derive(
16    Copy,
17    Clone,
18    Debug,
19    Default,
20    Eq,
21    PartialEq,
22    KnownLayout,
23    FromBytes,
24    IntoBytes,
25    Immutable,
26    Unaligned,
27)]
28#[repr(C)]
29pub struct IcmpDestUnreachable {
30    // Rest of Header in ICMP, unused in ICMPv6.
31    //
32    // RFC 1191 outlines a method for path MTU discovery for IPv4. When sending a
33    // Destination Unreachable message with code = FragmentationRequired (4) (when
34    // the don't fragment flag is set and the packet size is too big to send out some
35    // link due to its MTU being too small), the RFC requires nodes to include the MTU
36    // of the link that was unable to send the packet in bytes 6 and 7 of the message.
37    // The new ICMP Destination Unreachable message with code = Fragmentation Required
38    // packet format now looks like this (RFC 1191 section 4):
39    //
40    //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41    //  |   Type = 3    |   Code = 4    |           Checksum            |
42    //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43    //  |           unused = 0          |         Next-Hop MTU          |
44    //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45    //  |      Internet Header + 64 bits of Original Datagram Data      |
46    //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47    //
48    // Note, the Next-Hop MTU field is still considered unused in all other ICMP
49    // messages and all nodes that do not implement RFC 1191.
50    _unused: [u8; 2],
51    // Used only when DestinationUnreachable Code = FragmentationRequired (4);
52    //
53    // Note, if this value from an incoming ICMP message is `0`, then we assume the
54    // source node of the ICMP message does not implement RFC 1191 and therefore
55    // does not actually use the Next-Hop MTU field and still considers it as
56    // an unused field.
57    next_hop_mtu: U16,
58    /* Body of IcmpDestUnreachable is entirely variable-length, so is stored in
59     * the message_body field in IcmpPacket */
60}
61
62impl IcmpDestUnreachable {
63    /// Create a new ICMP Destination Unreachable message for a message with
64    /// Code = Fragmentation Required (4) which requires a next hop MTU value
65    /// as defined in RFC 1191 section 4.
66    pub fn new_for_frag_req(mtu: NonZeroU16) -> Self {
67        Self { _unused: [0; 2], next_hop_mtu: U16::new(mtu.get()) }
68    }
69
70    /// Get the Next Hop MTU value as defined in RFC 1191 section 4.
71    ///
72    /// Note, this field is considered unused in all Destination Unreachable
73    /// ICMP messages, except for ICMPv4 Destination Unreachable messages with
74    /// Code = Fragmentation Required (4).
75    pub fn next_hop_mtu(&self) -> Option<NonZeroU16> {
76        NonZeroU16::new(self.next_hop_mtu.get())
77    }
78}
79
80/// An ICMP Echo Request message.
81#[derive(
82    Copy, Clone, Debug, Eq, PartialEq, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned,
83)]
84#[repr(C)]
85pub struct IcmpEchoRequest {
86    pub(super) id_seq: IdAndSeq,
87    /* The rest of of IcmpEchoRequest is variable-length, so is stored in the
88     * message_body field in IcmpPacket */
89}
90
91impl IcmpEchoRequest {
92    /// Constructs a new `IcmpEchoRequest`.
93    pub fn new(id: u16, seq: u16) -> IcmpEchoRequest {
94        IcmpEchoRequest { id_seq: IdAndSeq::new(id, seq) }
95    }
96
97    /// Constructs an Echo Reply to this Echo Request.
98    ///
99    /// `reply` constructs an `IcmpEchoReply` with the same ID and sequence
100    /// number as the original request.
101    pub fn reply(self) -> IcmpEchoReply {
102        IcmpEchoReply { id_seq: self.id_seq }
103    }
104
105    /// The ID of this message.
106    pub fn id(&self) -> u16 {
107        self.id_seq.id.get()
108    }
109
110    /// Sets the ID of this message.
111    ///
112    /// WARNING: If this message is part of a parsed [`IcmpPacket`], the
113    /// packet's checksum must also be updated accordingly.
114    pub fn set_id(&mut self, id: u16) {
115        self.id_seq.id = id.into();
116    }
117
118    /// The sequence number of this message.
119    pub fn seq(&self) -> u16 {
120        self.id_seq.seq.get()
121    }
122}
123
124/// An ICMP Echo Reply message.
125#[derive(
126    Copy, Clone, Debug, Eq, PartialEq, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned,
127)]
128#[repr(C)]
129pub struct IcmpEchoReply {
130    pub(super) id_seq: IdAndSeq,
131    /* The rest of of IcmpEchoReply is variable-length, so is stored in the
132     * message_body field in IcmpPacket */
133}
134
135impl IcmpEchoReply {
136    /// Constructs a new `IcmpEchoReply`.
137    pub fn new(id: u16, seq: u16) -> Self {
138        Self { id_seq: IdAndSeq::new(id, seq) }
139    }
140
141    /// The ID of this message.
142    pub fn id(&self) -> u16 {
143        self.id_seq.id.get()
144    }
145
146    /// Sets the ID of this message.
147    ///
148    /// WARNING: If this message is part of a parsed [`IcmpPacket`], the
149    /// packet's checksum must also be updated accordingly.
150    pub fn set_id(&mut self, id: u16) {
151        self.id_seq.id = id.into();
152    }
153
154    /// The sequence number of this message.
155    pub fn seq(&self) -> u16 {
156        self.id_seq.seq.get()
157    }
158}
159
160/// An ICMP Time Exceeded message.
161#[derive(
162    Copy,
163    Clone,
164    Default,
165    Debug,
166    Eq,
167    PartialEq,
168    KnownLayout,
169    FromBytes,
170    IntoBytes,
171    Immutable,
172    Unaligned,
173)]
174#[repr(C)]
175pub struct IcmpTimeExceeded {
176    // Rest of Header in ICMP, unused in ICMPv6
177    _unused: [u8; 4],
178    /* Body of IcmpTimeExceeded is entirely variable-length, so is stored in
179     * the message_body field in IcmpPacket */
180}
181
182impl_common_icmp_message!(IcmpEchoReply, ECHO_REPLY, IcmpZeroCode, OriginalPacket<B>);
183impl_common_icmp_message!(IcmpEchoRequest, ECHO_REQUEST, IcmpZeroCode, OriginalPacket<B>);