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