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