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, ///< Destination Unreachable No Route
104             kCodeFragmReasTimeEx   = OT_ICMP6_CODE_FRAGM_REAS_TIME_EX,   ///< Fragment Reassembly Time Exceeded
105         };
106 
107         static constexpr uint8_t kTypeFieldOffset     = 0; ///< The byte offset of Type field in ICMP6 header.
108         static constexpr uint8_t kCodeFieldOffset     = 1; ///< The byte offset of Code field in ICMP6 header.
109         static constexpr uint8_t kChecksumFieldOffset = 2; ///< The byte offset of Checksum field in ICMP6 header.
110         static constexpr uint8_t kDataFieldOffset     = 4; ///< The byte offset of Data field in ICMP6 header.
111 
112         /**
113          * Indicates whether the ICMPv6 message is an error message.
114          *
115          * @retval TRUE if the ICMPv6 message is an error message.
116          * @retval FALSE if the ICMPv6 message is an informational message.
117          *
118          */
IsError(void) const119         bool IsError(void) const { return mType < OT_ICMP6_TYPE_ECHO_REQUEST; }
120 
121         /**
122          * Returns the ICMPv6 message type.
123          *
124          * @returns The ICMPv6 message type.
125          *
126          */
GetType(void) const127         Type GetType(void) const { return static_cast<Type>(mType); }
128 
129         /**
130          * Sets the ICMPv6 message type.
131          *
132          * @param[in]  aType  The ICMPv6 message type.
133          *
134          */
SetType(Type aType)135         void SetType(Type aType) { mType = static_cast<uint8_t>(aType); }
136 
137         /**
138          * Returns the ICMPv6 message code.
139          *
140          * @returns The ICMPv6 message code.
141          *
142          */
GetCode(void) const143         Code GetCode(void) const { return static_cast<Code>(mCode); }
144 
145         /**
146          * Sets the ICMPv6 message code.
147          *
148          * @param[in]  aCode  The ICMPv6 message code.
149          *
150          */
SetCode(Code aCode)151         void SetCode(Code aCode) { mCode = static_cast<uint8_t>(aCode); }
152 
153         /**
154          * Returns the ICMPv6 message checksum.
155          *
156          * @returns The ICMPv6 message checksum.
157          *
158          */
GetChecksum(void) const159         uint16_t GetChecksum(void) const { return BigEndian::HostSwap16(mChecksum); }
160 
161         /**
162          * Sets the ICMPv6 message checksum.
163          *
164          * @param[in]  aChecksum  The ICMPv6 message checksum.
165          *
166          */
SetChecksum(uint16_t aChecksum)167         void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); }
168 
169         /**
170          * Returns the ICMPv6 message ID for Echo Requests and Replies.
171          *
172          * @returns The ICMPv6 message ID.
173          *
174          */
GetId(void) const175         uint16_t GetId(void) const { return BigEndian::HostSwap16(mData.m16[0]); }
176 
177         /**
178          * Sets the ICMPv6 message ID for Echo Requests and Replies.
179          *
180          * @param[in]  aId  The ICMPv6 message ID.
181          *
182          */
SetId(uint16_t aId)183         void SetId(uint16_t aId) { mData.m16[0] = BigEndian::HostSwap16(aId); }
184 
185         /**
186          * Returns the ICMPv6 message sequence for Echo Requests and Replies.
187          *
188          * @returns The ICMPv6 message sequence.
189          *
190          */
GetSequence(void) const191         uint16_t GetSequence(void) const { return BigEndian::HostSwap16(mData.m16[1]); }
192 
193         /**
194          * Sets the ICMPv6 message sequence for Echo Requests and Replies.
195          *
196          * @param[in]  aSequence  The ICMPv6 message sequence.
197          *
198          */
SetSequence(uint16_t aSequence)199         void SetSequence(uint16_t aSequence) { mData.m16[1] = BigEndian::HostSwap16(aSequence); }
200     } OT_TOOL_PACKED_END;
201 
202     /**
203      * Implements ICMPv6 message handlers.
204      *
205      */
206     class Handler : public otIcmp6Handler, public LinkedListEntry<Handler>
207     {
208         friend class Icmp;
209 
210     public:
211         /**
212          * Creates an ICMPv6 message handler.
213          *
214          * @param[in]  aCallback  A pointer to the function that is called when receiving an ICMPv6 message.
215          * @param[in]  aContext   A pointer to arbitrary context information.
216          *
217          */
Handler(otIcmp6ReceiveCallback aCallback,void * aContext)218         Handler(otIcmp6ReceiveCallback aCallback, void *aContext)
219         {
220             mReceiveCallback = aCallback;
221             mContext         = aContext;
222             mNext            = nullptr;
223         }
224 
225     private:
HandleReceiveMessage(Message & aMessage,const MessageInfo & aMessageInfo,const Header & aIcmp6Header)226         void HandleReceiveMessage(Message &aMessage, const MessageInfo &aMessageInfo, const Header &aIcmp6Header)
227         {
228             mReceiveCallback(mContext, &aMessage, &aMessageInfo, &aIcmp6Header);
229         }
230     };
231 
232     /**
233      * Initializes the object.
234      *
235      * @param[in]  aInstance A reference to the OpenThread instance.
236      *
237      */
238     explicit Icmp(Instance &aInstance);
239 
240     /**
241      * Returns a new ICMP message with sufficient header space reserved.
242      *
243      * @returns A pointer to the message or `nullptr` if no buffers are available.
244      *
245      */
246     Message *NewMessage(void);
247 
248     /**
249      * Registers ICMPv6 handler.
250      *
251      * @param[in]  aHandler  A reference to the ICMPv6 handler.
252      *
253      * @retval kErrorNone     Successfully registered the ICMPv6 handler.
254      * @retval kErrorAlready  The ICMPv6 handler is already registered.
255      *
256      */
257     Error RegisterHandler(Handler &aHandler);
258 
259     /**
260      * Sends an ICMPv6 Echo Request message.
261      *
262      * @param[in]  aMessage      A reference to the Echo Request payload.
263      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
264      * @param[in]  aIdentifier   An identifier to aid in matching Echo Replies to this Echo Request.
265      *                           May be zero.
266      *
267      * @retval kErrorNone     Successfully enqueued the ICMPv6 Echo Request message.
268      * @retval kErrorNoBufs   Insufficient buffers available to generate an ICMPv6 Echo Request message.
269      *
270      */
271     Error SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, uint16_t aIdentifier);
272 
273     /**
274      * Sends an ICMPv6 error message.
275      *
276      * @param[in]  aType         The ICMPv6 message type.
277      * @param[in]  aCode         The ICMPv6 message code.
278      * @param[in]  aMessageInfo  A reference to the message info.
279      * @param[in]  aMessage      The error-causing IPv6 message.
280      *
281      * @retval kErrorNone     Successfully enqueued the ICMPv6 error message.
282      * @retval kErrorNoBufs   Insufficient buffers available.
283      *
284      */
285     Error SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Message &aMessage);
286 
287     /**
288      * Sends an ICMPv6 error message.
289      *
290      * @param[in]  aType         The ICMPv6 message type.
291      * @param[in]  aCode         The ICMPv6 message code.
292      * @param[in]  aMessageInfo  A reference to the message info.
293      * @param[in]  aHeaders      The parsed headers from the error-causing IPv6 message.
294      *
295      * @retval kErrorNone     Successfully enqueued the ICMPv6 error message.
296      * @retval kErrorNoBufs   Insufficient buffers available.
297      *
298      */
299     Error SendError(Header::Type aType, Header::Code aCode, const MessageInfo &aMessageInfo, const Headers &aHeaders);
300 
301     /**
302      * Handles an ICMPv6 message.
303      *
304      * @param[in]  aMessage      A reference to the ICMPv6 message.
305      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
306      *
307      * @retval kErrorNone     Successfully processed the ICMPv6 message.
308      * @retval kErrorNoBufs   Insufficient buffers available to generate the reply.
309      * @retval kErrorDrop     The ICMPv6 message was invalid and dropped.
310      *
311      */
312     Error HandleMessage(Message &aMessage, MessageInfo &aMessageInfo);
313 
314     /**
315      * Indicates whether or not ICMPv6 Echo processing is enabled.
316      *
317      * @retval TRUE   ICMPv6 Echo processing is enabled.
318      * @retval FALSE  ICMPv6 Echo processing is disabled.
319      *
320      */
GetEchoMode(void) const321     otIcmp6EchoMode GetEchoMode(void) const { return mEchoMode; }
322 
323     /**
324      * Sets the ICMPv6 echo mode.
325      *
326      * @param[in]  aMode  The ICMPv6 echo mode.
327      *
328      */
SetEchoMode(otIcmp6EchoMode aMode)329     void SetEchoMode(otIcmp6EchoMode aMode) { mEchoMode = aMode; }
330 
331     /**
332      * Indicates whether or not the ICMPv6 Echo Request should be handled.
333      *
334      * @retval TRUE if OpenThread should respond with an ICMPv6 Echo Reply.
335      * @retval FALSE if OpenThread should not respond with an ICMPv6 Echo Reply.
336      *
337      */
338     bool ShouldHandleEchoRequest(const MessageInfo &aMessageInfo);
339 
340     /**
341      * Returns the ICMPv6 Echo sequence number.
342      *
343      * @returns The sequence number of the next ICMPv6 Echo request.
344      *
345      */
GetEchoSequence(void) const346     uint16_t GetEchoSequence(void) const { return mEchoSequence; }
347 
348 private:
349     Error HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo);
350 
351     LinkedList<Handler> mHandlers;
352 
353     uint16_t        mEchoSequence;
354     otIcmp6EchoMode mEchoMode;
355 };
356 
357 /**
358  * @}
359  *
360  */
361 
362 } // namespace Ip6
363 
364 DefineCoreType(otIcmp6Header, Ip6::Icmp::Header);
365 DefineCoreType(otIcmp6Handler, Ip6::Icmp::Handler);
366 
367 } // namespace ot
368 
369 #endif // ICMP6_HPP_
370