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 using ot::Encoding::BigEndian::HostSwap16;
53 
54 /**
55  * @addtogroup core-ip6-icmp6
56  *
57  * @brief
58  *   This module includes definitions for ICMPv6.
59  *
60  * @{
61  *
62  */
63 
64 class Headers;
65 
66 /**
67  * Implements ICMPv6.
68  *
69  */
70 class Icmp : public InstanceLocator, private NonCopyable
71 {
72 public:
73     /*
74      * Implements ICMPv6 header generation and parsing.
75      *
76      */
77     OT_TOOL_PACKED_BEGIN
78     class Header : public otIcmp6Header, public Clearable<Header>
79     {
80     public:
81         /**
82          * ICMPv6 Message Types
83          *
84          */
85         enum Type : uint8_t
86         {
87             kTypeDstUnreach       = OT_ICMP6_TYPE_DST_UNREACH,       ///< Destination Unreachable
88             kTypePacketToBig      = OT_ICMP6_TYPE_PACKET_TO_BIG,     ///< Packet To Big
89             kTypeTimeExceeded     = OT_ICMP6_TYPE_TIME_EXCEEDED,     ///< Time Exceeded
90             kTypeParameterProblem = OT_ICMP6_TYPE_PARAMETER_PROBLEM, ///< Parameter Problem
91             kTypeEchoRequest      = OT_ICMP6_TYPE_ECHO_REQUEST,      ///< Echo Request
92             kTypeEchoReply        = OT_ICMP6_TYPE_ECHO_REPLY,        ///< Echo Reply
93             kTypeRouterSolicit    = OT_ICMP6_TYPE_ROUTER_SOLICIT,    ///< Router Solicitation
94             kTypeRouterAdvert     = OT_ICMP6_TYPE_ROUTER_ADVERT,     ///< Router Advertisement
95             kTypeNeighborSolicit  = OT_ICMP6_TYPE_NEIGHBOR_SOLICIT,  ///< Neighbor Solicitation
96             kTypeNeighborAdvert   = OT_ICMP6_TYPE_NEIGHBOR_ADVERT,   ///< Neighbor Advertisement
97         };
98 
99         /**
100          * ICMPv6 Message Codes
101          *
102          */
103         enum Code : uint8_t
104         {
105             kCodeDstUnreachNoRoute = OT_ICMP6_CODE_DST_UNREACH_NO_ROUTE, ///< Destination Unreachable No Route
106             kCodeFragmReasTimeEx   = OT_ICMP6_CODE_FRAGM_REAS_TIME_EX,   ///< Fragment Reassembly Time Exceeded
107         };
108 
109         static constexpr uint8_t kTypeFieldOffset     = 0; ///< The byte offset of Type field in ICMP6 header.
110         static constexpr uint8_t kCodeFieldOffset     = 1; ///< The byte offset of Code field in ICMP6 header.
111         static constexpr uint8_t kChecksumFieldOffset = 2; ///< The byte offset of Checksum field in ICMP6 header.
112         static constexpr uint8_t kDataFieldOffset     = 4; ///< The byte offset of Data field in ICMP6 header.
113 
114         /**
115          * Indicates whether the ICMPv6 message is an error message.
116          *
117          * @retval TRUE if the ICMPv6 message is an error message.
118          * @retval FALSE if the ICMPv6 message is an informational message.
119          *
120          */
IsError(void) const121         bool IsError(void) const { return mType < OT_ICMP6_TYPE_ECHO_REQUEST; }
122 
123         /**
124          * Returns the ICMPv6 message type.
125          *
126          * @returns The ICMPv6 message type.
127          *
128          */
GetType(void) const129         Type GetType(void) const { return static_cast<Type>(mType); }
130 
131         /**
132          * Sets the ICMPv6 message type.
133          *
134          * @param[in]  aType  The ICMPv6 message type.
135          *
136          */
SetType(Type aType)137         void SetType(Type aType) { mType = static_cast<uint8_t>(aType); }
138 
139         /**
140          * Returns the ICMPv6 message code.
141          *
142          * @returns The ICMPv6 message code.
143          *
144          */
GetCode(void) const145         Code GetCode(void) const { return static_cast<Code>(mCode); }
146 
147         /**
148          * Sets the ICMPv6 message code.
149          *
150          * @param[in]  aCode  The ICMPv6 message code.
151          *
152          */
SetCode(Code aCode)153         void SetCode(Code aCode) { mCode = static_cast<uint8_t>(aCode); }
154 
155         /**
156          * Returns the ICMPv6 message checksum.
157          *
158          * @returns The ICMPv6 message checksum.
159          *
160          */
GetChecksum(void) const161         uint16_t GetChecksum(void) const { return HostSwap16(mChecksum); }
162 
163         /**
164          * Sets the ICMPv6 message checksum.
165          *
166          * @param[in]  aChecksum  The ICMPv6 message checksum.
167          *
168          */
SetChecksum(uint16_t aChecksum)169         void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); }
170 
171         /**
172          * Returns the ICMPv6 message ID for Echo Requests and Replies.
173          *
174          * @returns The ICMPv6 message ID.
175          *
176          */
GetId(void) const177         uint16_t GetId(void) const { return HostSwap16(mData.m16[0]); }
178 
179         /**
180          * Sets the ICMPv6 message ID for Echo Requests and Replies.
181          *
182          * @param[in]  aId  The ICMPv6 message ID.
183          *
184          */
SetId(uint16_t aId)185         void SetId(uint16_t aId) { mData.m16[0] = HostSwap16(aId); }
186 
187         /**
188          * Returns the ICMPv6 message sequence for Echo Requests and Replies.
189          *
190          * @returns The ICMPv6 message sequence.
191          *
192          */
GetSequence(void) const193         uint16_t GetSequence(void) const { return HostSwap16(mData.m16[1]); }
194 
195         /**
196          * Sets the ICMPv6 message sequence for Echo Requests and Replies.
197          *
198          * @param[in]  aSequence  The ICMPv6 message sequence.
199          *
200          */
SetSequence(uint16_t aSequence)201         void SetSequence(uint16_t aSequence) { mData.m16[1] = HostSwap16(aSequence); }
202     } OT_TOOL_PACKED_END;
203 
204     /**
205      * Implements ICMPv6 message handlers.
206      *
207      */
208     class Handler : public otIcmp6Handler, public LinkedListEntry<Handler>
209     {
210         friend class Icmp;
211 
212     public:
213         /**
214          * Creates an ICMPv6 message handler.
215          *
216          * @param[in]  aCallback  A pointer to the function that is called when receiving an ICMPv6 message.
217          * @param[in]  aContext   A pointer to arbitrary context information.
218          *
219          */
Handler(otIcmp6ReceiveCallback aCallback,void * aContext)220         Handler(otIcmp6ReceiveCallback aCallback, void *aContext)
221         {
222             mReceiveCallback = aCallback;
223             mContext         = aContext;
224             mNext            = nullptr;
225         }
226 
227     private:
HandleReceiveMessage(Message & aMessage,const MessageInfo & aMessageInfo,const Header & aIcmp6Header)228         void HandleReceiveMessage(Message &aMessage, const MessageInfo &aMessageInfo, const Header &aIcmp6Header)
229         {
230             mReceiveCallback(mContext, &aMessage, &aMessageInfo, &aIcmp6Header);
231         }
232     };
233 
234     /**
235      * Initializes the object.
236      *
237      * @param[in]  aInstance A reference to the OpenThread instance.
238      *
239      */
240     explicit Icmp(Instance &aInstance);
241 
242     /**
243      * Returns a new ICMP message with sufficient header space reserved.
244      *
245      * @returns A pointer to the message or `nullptr` if no buffers are available.
246      *
247      */
248     Message *NewMessage(void);
249 
250     /**
251      * Registers ICMPv6 handler.
252      *
253      * @param[in]  aHandler  A reference to the ICMPv6 handler.
254      *
255      * @retval kErrorNone     Successfully registered the ICMPv6 handler.
256      * @retval kErrorAlready  The ICMPv6 handler is already registered.
257      *
258      */
259     Error RegisterHandler(Handler &aHandler);
260 
261     /**
262      * Sends an ICMPv6 Echo Request message.
263      *
264      * @param[in]  aMessage      A reference to the Echo Request payload.
265      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
266      * @param[in]  aIdentifier   An identifier to aid in matching Echo Replies to this Echo Request.
267      *                           May be zero.
268      *
269      * @retval kErrorNone     Successfully enqueued the ICMPv6 Echo Request message.
270      * @retval kErrorNoBufs   Insufficient buffers available to generate an ICMPv6 Echo Request message.
271      *
272      */
273     Error SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, uint16_t aIdentifier);
274 
275     /**
276      * Sends an ICMPv6 error message.
277      *
278      * @param[in]  aType         The ICMPv6 message type.
279      * @param[in]  aCode         The ICMPv6 message code.
280      * @param[in]  aMessageInfo  A reference to the message info.
281      * @param[in]  aMessage      The error-causing IPv6 message.
282      *
283      * @retval kErrorNone     Successfully enqueued the ICMPv6 error message.
284      * @retval kErrorNoBufs   Insufficient buffers available.
285      *
286      */
287     Error SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage);
288 
289     /**
290      * Sends an ICMPv6 error message.
291      *
292      * @param[in]  aType         The ICMPv6 message type.
293      * @param[in]  aCode         The ICMPv6 message code.
294      * @param[in]  aMessageInfo  A reference to the message info.
295      * @param[in]  aHeaders      The parsed headers from the error-causing IPv6 message.
296      *
297      * @retval kErrorNone     Successfully enqueued the ICMPv6 error message.
298      * @retval kErrorNoBufs   Insufficient buffers available.
299      *
300      */
301     Error SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Headers &aHeaders);
302 
303     /**
304      * Handles an ICMPv6 message.
305      *
306      * @param[in]  aMessage      A reference to the ICMPv6 message.
307      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
308      *
309      * @retval kErrorNone     Successfully processed the ICMPv6 message.
310      * @retval kErrorNoBufs   Insufficient buffers available to generate the reply.
311      * @retval kErrorDrop     The ICMPv6 message was invalid and dropped.
312      *
313      */
314     Error HandleMessage(Message &aMessage, MessageInfo &aMessageInfo);
315 
316     /**
317      * Indicates whether or not ICMPv6 Echo processing is enabled.
318      *
319      * @retval TRUE   ICMPv6 Echo processing is enabled.
320      * @retval FALSE  ICMPv6 Echo processing is disabled.
321      *
322      */
GetEchoMode(void) const323     otIcmp6EchoMode GetEchoMode(void) const { return mEchoMode; }
324 
325     /**
326      * Sets the ICMPv6 echo mode.
327      *
328      * @param[in]  aMode  The ICMPv6 echo mode.
329      *
330      */
SetEchoMode(otIcmp6EchoMode aMode)331     void SetEchoMode(otIcmp6EchoMode aMode) { mEchoMode = aMode; }
332 
333     /**
334      * Indicates whether or not the ICMPv6 Echo Request should be handled.
335      *
336      * @retval TRUE if OpenThread should respond with an ICMPv6 Echo Reply.
337      * @retval FALSE if OpenThread should not respond with an ICMPv6 Echo Reply.
338      *
339      */
340     bool ShouldHandleEchoRequest(const MessageInfo &aMessageInfo);
341 
342     /**
343      * Returns the ICMPv6 Echo sequence number.
344      *
345      * @returns The sequence number of the next ICMPv6 Echo request.
346      *
347      */
GetEchoSequence(void) const348     uint16_t GetEchoSequence(void) const { return mEchoSequence; }
349 
350 private:
351     Error HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo);
352 
353     LinkedList<Handler> mHandlers;
354 
355     uint16_t        mEchoSequence;
356     otIcmp6EchoMode mEchoMode;
357 };
358 
359 /**
360  * @}
361  *
362  */
363 
364 } // namespace Ip6
365 
366 DefineCoreType(otIcmp6Header, Ip6::Icmp::Header);
367 DefineCoreType(otIcmp6Handler, Ip6::Icmp::Handler);
368 
369 } // namespace ot
370 
371 #endif // ICMP6_HPP_
372