1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for ICMPv6.
32  */
33 
34 #ifndef ICMP6_HPP_
35 #define ICMP6_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/icmp6.h>
40 
41 #include "common/as_core_type.hpp"
42 #include "common/clearable.hpp"
43 #include "common/encoding.hpp"
44 #include "common/linked_list.hpp"
45 #include "common/locator.hpp"
46 #include "common/non_copyable.hpp"
47 #include "net/ip6_headers.hpp"
48 
49 namespace ot {
50 namespace Ip6 {
51 
52 /**
53  * @addtogroup core-ip6-icmp6
54  *
55  * @brief
56  *   This module includes definitions for ICMPv6.
57  *
58  * @{
59  */
60 
61 class Headers;
62 
63 /**
64  * Implements ICMPv6.
65  */
66 class Icmp : public InstanceLocator, private NonCopyable
67 {
68 public:
69     /*
70      * Implements ICMPv6 header generation and parsing.
71      */
72     OT_TOOL_PACKED_BEGIN
73     class Header : public otIcmp6Header, public Clearable<Header>
74     {
75     public:
76         /**
77          * ICMPv6 Message Types
78          */
79         enum Type : uint8_t
80         {
81             kTypeDstUnreach       = OT_ICMP6_TYPE_DST_UNREACH,       ///< Destination Unreachable
82             kTypePacketToBig      = OT_ICMP6_TYPE_PACKET_TO_BIG,     ///< Packet To Big
83             kTypeTimeExceeded     = OT_ICMP6_TYPE_TIME_EXCEEDED,     ///< Time Exceeded
84             kTypeParameterProblem = OT_ICMP6_TYPE_PARAMETER_PROBLEM, ///< Parameter Problem
85             kTypeEchoRequest      = OT_ICMP6_TYPE_ECHO_REQUEST,      ///< Echo Request
86             kTypeEchoReply        = OT_ICMP6_TYPE_ECHO_REPLY,        ///< Echo Reply
87             kTypeRouterSolicit    = OT_ICMP6_TYPE_ROUTER_SOLICIT,    ///< Router Solicitation
88             kTypeRouterAdvert     = OT_ICMP6_TYPE_ROUTER_ADVERT,     ///< Router Advertisement
89             kTypeNeighborSolicit  = OT_ICMP6_TYPE_NEIGHBOR_SOLICIT,  ///< Neighbor Solicitation
90             kTypeNeighborAdvert   = OT_ICMP6_TYPE_NEIGHBOR_ADVERT,   ///< Neighbor Advertisement
91         };
92 
93         /**
94          * ICMPv6 Message Codes
95          */
96         enum Code : uint8_t
97         {
98             kCodeDstUnreachNoRoute    = OT_ICMP6_CODE_DST_UNREACH_NO_ROUTE,   ///< Dest Unreachable - No Route
99             kCodeDstUnreachProhibited = OT_ICMP6_CODE_DST_UNREACH_PROHIBITED, ///< Dest Unreachable - Admin Prohibited
100             kCodeFragmReasTimeEx      = OT_ICMP6_CODE_FRAGM_REAS_TIME_EX,     ///< Time Exceeded - Frag Reassembly
101         };
102 
103         static constexpr uint8_t kTypeFieldOffset     = 0; ///< The byte offset of Type field in ICMP6 header.
104         static constexpr uint8_t kCodeFieldOffset     = 1; ///< The byte offset of Code field in ICMP6 header.
105         static constexpr uint8_t kChecksumFieldOffset = 2; ///< The byte offset of Checksum field in ICMP6 header.
106         static constexpr uint8_t kDataFieldOffset     = 4; ///< The byte offset of Data field in ICMP6 header.
107 
108         /**
109          * Indicates whether the ICMPv6 message is an error message.
110          *
111          * @retval TRUE if the ICMPv6 message is an error message.
112          * @retval FALSE if the ICMPv6 message is an informational message.
113          */
IsError(void) const114         bool IsError(void) const { return mType < OT_ICMP6_TYPE_ECHO_REQUEST; }
115 
116         /**
117          * Returns the ICMPv6 message type.
118          *
119          * @returns The ICMPv6 message type.
120          */
GetType(void) const121         Type GetType(void) const { return static_cast<Type>(mType); }
122 
123         /**
124          * Sets the ICMPv6 message type.
125          *
126          * @param[in]  aType  The ICMPv6 message type.
127          */
SetType(Type aType)128         void SetType(Type aType) { mType = static_cast<uint8_t>(aType); }
129 
130         /**
131          * Returns the ICMPv6 message code.
132          *
133          * @returns The ICMPv6 message code.
134          */
GetCode(void) const135         Code GetCode(void) const { return static_cast<Code>(mCode); }
136 
137         /**
138          * Sets the ICMPv6 message code.
139          *
140          * @param[in]  aCode  The ICMPv6 message code.
141          */
SetCode(Code aCode)142         void SetCode(Code aCode) { mCode = static_cast<uint8_t>(aCode); }
143 
144         /**
145          * Returns the ICMPv6 message checksum.
146          *
147          * @returns The ICMPv6 message checksum.
148          */
GetChecksum(void) const149         uint16_t GetChecksum(void) const { return BigEndian::HostSwap16(mChecksum); }
150 
151         /**
152          * Sets the ICMPv6 message checksum.
153          *
154          * @param[in]  aChecksum  The ICMPv6 message checksum.
155          */
SetChecksum(uint16_t aChecksum)156         void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); }
157 
158         /**
159          * Returns the ICMPv6 message ID for Echo Requests and Replies.
160          *
161          * @returns The ICMPv6 message ID.
162          */
GetId(void) const163         uint16_t GetId(void) const { return BigEndian::HostSwap16(mData.m16[0]); }
164 
165         /**
166          * Sets the ICMPv6 message ID for Echo Requests and Replies.
167          *
168          * @param[in]  aId  The ICMPv6 message ID.
169          */
SetId(uint16_t aId)170         void SetId(uint16_t aId) { mData.m16[0] = BigEndian::HostSwap16(aId); }
171 
172         /**
173          * Returns the ICMPv6 message sequence for Echo Requests and Replies.
174          *
175          * @returns The ICMPv6 message sequence.
176          */
GetSequence(void) const177         uint16_t GetSequence(void) const { return BigEndian::HostSwap16(mData.m16[1]); }
178 
179         /**
180          * Sets the ICMPv6 message sequence for Echo Requests and Replies.
181          *
182          * @param[in]  aSequence  The ICMPv6 message sequence.
183          */
SetSequence(uint16_t aSequence)184         void SetSequence(uint16_t aSequence) { mData.m16[1] = BigEndian::HostSwap16(aSequence); }
185     } OT_TOOL_PACKED_END;
186 
187     /**
188      * Implements ICMPv6 message handlers.
189      */
190     class Handler : public otIcmp6Handler, public LinkedListEntry<Handler>
191     {
192         friend class Icmp;
193 
194     public:
195         /**
196          * Creates an ICMPv6 message handler.
197          *
198          * @param[in]  aCallback  A pointer to the function that is called when receiving an ICMPv6 message.
199          * @param[in]  aContext   A pointer to arbitrary context information.
200          */
Handler(otIcmp6ReceiveCallback aCallback,void * aContext)201         Handler(otIcmp6ReceiveCallback aCallback, void *aContext)
202         {
203             mReceiveCallback = aCallback;
204             mContext         = aContext;
205             mNext            = nullptr;
206         }
207 
208     private:
HandleReceiveMessage(Message & aMessage,const MessageInfo & aMessageInfo,const Header & aIcmp6Header)209         void HandleReceiveMessage(Message &aMessage, const MessageInfo &aMessageInfo, const Header &aIcmp6Header)
210         {
211             mReceiveCallback(mContext, &aMessage, &aMessageInfo, &aIcmp6Header);
212         }
213     };
214 
215     /**
216      * Initializes the object.
217      *
218      * @param[in]  aInstance A reference to the OpenThread instance.
219      */
220     explicit Icmp(Instance &aInstance);
221 
222     /**
223      * Returns a new ICMP message with sufficient header space reserved.
224      *
225      * @returns A pointer to the message or `nullptr` if no buffers are available.
226      */
227     Message *NewMessage(void);
228 
229     /**
230      * Registers ICMPv6 handler.
231      *
232      * @param[in]  aHandler  A reference to the ICMPv6 handler.
233      *
234      * @retval kErrorNone     Successfully registered the ICMPv6 handler.
235      * @retval kErrorAlready  The ICMPv6 handler is already registered.
236      */
237     Error RegisterHandler(Handler &aHandler);
238 
239     /**
240      * Sends an ICMPv6 Echo Request message.
241      *
242      * @param[in]  aMessage      A reference to the Echo Request payload.
243      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
244      * @param[in]  aIdentifier   An identifier to aid in matching Echo Replies to this Echo Request.
245      *                           May be zero.
246      *
247      * @retval kErrorNone     Successfully enqueued the ICMPv6 Echo Request message.
248      * @retval kErrorNoBufs   Insufficient buffers available to generate an ICMPv6 Echo Request message.
249      */
250     Error SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, uint16_t aIdentifier);
251 
252     /**
253      * Sends an ICMPv6 error message.
254      *
255      * @param[in]  aType         The ICMPv6 message type.
256      * @param[in]  aCode         The ICMPv6 message code.
257      * @param[in]  aMessageInfo  A reference to the message info.
258      * @param[in]  aMessage      The error-causing IPv6 message.
259      *
260      * @retval kErrorNone     Successfully enqueued the ICMPv6 error message.
261      * @retval kErrorNoBufs   Insufficient buffers available.
262      */
263     Error SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage);
264 
265     /**
266      * Sends an ICMPv6 error message.
267      *
268      * @param[in]  aType         The ICMPv6 message type.
269      * @param[in]  aCode         The ICMPv6 message code.
270      * @param[in]  aMessageInfo  A reference to the message info.
271      * @param[in]  aHeaders      The parsed headers from the error-causing IPv6 message.
272      *
273      * @retval kErrorNone     Successfully enqueued the ICMPv6 error message.
274      * @retval kErrorNoBufs   Insufficient buffers available.
275      */
276     Error SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Headers &aHeaders);
277 
278     /**
279      * Handles an ICMPv6 message.
280      *
281      * @param[in]  aMessage      A reference to the ICMPv6 message.
282      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
283      *
284      * @retval kErrorNone     Successfully processed the ICMPv6 message.
285      * @retval kErrorNoBufs   Insufficient buffers available to generate the reply.
286      * @retval kErrorDrop     The ICMPv6 message was invalid and dropped.
287      */
288     Error HandleMessage(Message &aMessage, MessageInfo &aMessageInfo);
289 
290     /**
291      * Indicates whether or not ICMPv6 Echo processing is enabled.
292      *
293      * @retval TRUE   ICMPv6 Echo processing is enabled.
294      * @retval FALSE  ICMPv6 Echo processing is disabled.
295      */
GetEchoMode(void) const296     otIcmp6EchoMode GetEchoMode(void) const { return mEchoMode; }
297 
298     /**
299      * Sets the ICMPv6 echo mode.
300      *
301      * @param[in]  aMode  The ICMPv6 echo mode.
302      */
SetEchoMode(otIcmp6EchoMode aMode)303     void SetEchoMode(otIcmp6EchoMode aMode) { mEchoMode = aMode; }
304 
305     /**
306      * Indicates whether or not the ICMPv6 Echo Request should be handled.
307      *
308      * @param[in] aAddress    The ICMPv6 destination IPv6 address.
309      *
310      * @retval TRUE if OpenThread should respond with an ICMPv6 Echo Reply.
311      * @retval FALSE if OpenThread should not respond with an ICMPv6 Echo Reply.
312      */
313     bool ShouldHandleEchoRequest(const Address &aAddress);
314 
315     /**
316      * Returns the ICMPv6 Echo sequence number.
317      *
318      * @returns The sequence number of the next ICMPv6 Echo request.
319      */
GetEchoSequence(void) const320     uint16_t GetEchoSequence(void) const { return mEchoSequence; }
321 
322 private:
323     Error HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo);
324 
325     LinkedList<Handler> mHandlers;
326 
327     uint16_t        mEchoSequence;
328     otIcmp6EchoMode mEchoMode;
329 };
330 
331 /**
332  * @}
333  */
334 
335 } // namespace Ip6
336 
337 DefineCoreType(otIcmp6Header, Ip6::Icmp::Header);
338 DefineCoreType(otIcmp6Handler, Ip6::Icmp::Handler);
339 
340 } // namespace ot
341 
342 #endif // ICMP6_HPP_
343