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