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 * This class implements ICMPv6. 68 * 69 */ 70 class Icmp : public InstanceLocator, private NonCopyable 71 { 72 public: 73 /* 74 * This class 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 }; 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method returns the ICMPv6 message checksum. 155 * 156 * @returns The ICMPv6 message checksum. 157 * 158 */ GetChecksum(void) const159 uint16_t GetChecksum(void) const { return HostSwap16(mChecksum); } 160 161 /** 162 * This method 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 = HostSwap16(aChecksum); } 168 169 /** 170 * This method 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 HostSwap16(mData.m16[0]); } 176 177 /** 178 * This method 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] = HostSwap16(aId); } 184 185 /** 186 * This method 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 HostSwap16(mData.m16[1]); } 192 193 /** 194 * This method 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] = HostSwap16(aSequence); } 200 } OT_TOOL_PACKED_END; 201 202 /** 203 * This class implements ICMPv6 message handlers. 204 * 205 */ 206 class Handler : public otIcmp6Handler, public LinkedListEntry<Handler> 207 { 208 friend class Icmp; 209 210 public: 211 /** 212 * This constructor 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 * This constructor initializes the object. 234 * 235 * @param[in] aInstance A reference to the OpenThread instance. 236 * 237 */ 238 explicit Icmp(Instance &aInstance); 239 240 /** 241 * This method returns a new ICMP message with sufficient header space reserved. 242 * 243 * @param[in] aReserved The number of header bytes to reserve after the ICMP header. 244 * 245 * @returns A pointer to the message or `nullptr` if no buffers are available. 246 * 247 */ 248 Message *NewMessage(uint16_t aReserved); 249 250 /** 251 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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