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