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 IPv6 packet processing. 32 */ 33 34 #ifndef IP6_HEADERS_HPP_ 35 #define IP6_HEADERS_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include <stddef.h> 40 41 #include "common/encoding.hpp" 42 #include "common/message.hpp" 43 #include "net/ip6_address.hpp" 44 #include "net/netif.hpp" 45 #include "net/socket.hpp" 46 47 namespace ot { 48 49 /** 50 * @namespace ot::Ip6 51 * 52 * @brief 53 * This namespace includes definitions for IPv6 networking. 54 * 55 */ 56 namespace Ip6 { 57 58 using ot::Encoding::BigEndian::HostSwap16; 59 using ot::Encoding::BigEndian::HostSwap32; 60 61 /** 62 * @addtogroup core-ipv6 63 * 64 * @brief 65 * This module includes definitions for the IPv6 network layer. 66 * 67 * @{ 68 * 69 * @defgroup core-ip6-icmp6 ICMPv6 70 * @defgroup core-ip6-ip6 IPv6 71 * @defgroup core-ip6-mpl MPL 72 * @defgroup core-ip6-netif Network Interfaces 73 * 74 * @} 75 * 76 */ 77 78 /** 79 * @addtogroup core-ip6-ip6 80 * 81 * @brief 82 * This module includes definitions for core IPv6 networking. 83 * 84 * @{ 85 * 86 */ 87 88 // Internet Protocol Numbers 89 static constexpr uint8_t kProtoHopOpts = OT_IP6_PROTO_HOP_OPTS; ///< IPv6 Hop-by-Hop Option 90 static constexpr uint8_t kProtoTcp = OT_IP6_PROTO_TCP; ///< Transmission Control Protocol 91 static constexpr uint8_t kProtoUdp = OT_IP6_PROTO_UDP; ///< User Datagram 92 static constexpr uint8_t kProtoIp6 = OT_IP6_PROTO_IP6; ///< IPv6 encapsulation 93 static constexpr uint8_t kProtoRouting = OT_IP6_PROTO_ROUTING; ///< Routing Header for IPv6 94 static constexpr uint8_t kProtoFragment = OT_IP6_PROTO_FRAGMENT; ///< Fragment Header for IPv6 95 static constexpr uint8_t kProtoIcmp6 = OT_IP6_PROTO_ICMP6; ///< ICMP for IPv6 96 static constexpr uint8_t kProtoNone = OT_IP6_PROTO_NONE; ///< No Next Header for IPv6 97 static constexpr uint8_t kProtoDstOpts = OT_IP6_PROTO_DST_OPTS; ///< Destination Options for IPv6 98 99 /** 100 * Class Selectors 101 */ 102 enum IpDscpCs : uint8_t 103 { 104 kDscpCs0 = 0, ///< Class selector codepoint 0 105 kDscpCs1 = 8, ///< Class selector codepoint 8 106 kDscpCs2 = 16, ///< Class selector codepoint 16 107 kDscpCs3 = 24, ///< Class selector codepoint 24 108 kDscpCs4 = 32, ///< Class selector codepoint 32 109 kDscpCs5 = 40, ///< Class selector codepoint 40 110 kDscpCs6 = 48, ///< Class selector codepoint 48 111 kDscpCs7 = 56, ///< Class selector codepoint 56 112 kDscpCsMask = 0x38, ///< Class selector mask 113 }; 114 115 /** 116 * This class implements IPv6 header generation and parsing. 117 * 118 */ 119 OT_TOOL_PACKED_BEGIN 120 class Header 121 { 122 public: 123 static constexpr uint8_t kPayloadLengthFieldOffset = 4; ///< Offset of Payload Length field in IPv6 header. 124 static constexpr uint8_t kNextHeaderFieldOffset = 6; ///< Offset of Next Header field in IPv6 header. 125 static constexpr uint8_t kHopLimitFieldOffset = 7; ///< Offset of Hop Limit field in IPv6 header. 126 static constexpr uint8_t kSourceFieldOffset = 8; ///< Offset of Source Address field in IPv6 header. 127 static constexpr uint8_t kDestinationFieldOffset = 24; ///< Offset of Destination Address field in IPv6 header. 128 129 /** 130 * This method initializes the IPv6 header. 131 * 132 */ Init(void)133 void Init(void) { mVersionClassFlow.m32 = HostSwap32(kVersionClassFlowInit); } 134 135 /** 136 * This method initializes the IPv6 header and sets Version, Traffic Control and Flow Label fields. 137 * 138 */ Init(uint32_t aVersionClassFlow)139 void Init(uint32_t aVersionClassFlow) { mVersionClassFlow.m32 = HostSwap32(aVersionClassFlow); } 140 141 /** 142 * This method reads the IPv6 header from @p aMessage. 143 * 144 * @param[in] aMessage The IPv6 datagram. 145 * 146 * @retval kErrorNone Successfully read the IPv6 header. 147 * @retval kErrorParse Malformed IPv6 header. 148 * 149 */ 150 Error Init(const Message &aMessage); 151 152 /** 153 * This method indicates whether or not the header appears to be well-formed. 154 * 155 * @retval TRUE if the header appears to be well-formed. 156 * @retval FALSE if the header does not appear to be well-formed. 157 * 158 */ 159 bool IsValid(void) const; 160 161 /** 162 * This method indicates whether or not the IPv6 Version is set to 6. 163 * 164 * @retval TRUE If the IPv6 Version is set to 6. 165 * @retval FALSE If the IPv6 Version is not set to 6. 166 * 167 */ IsVersion6(void) const168 bool IsVersion6(void) const { return (mVersionClassFlow.m8[0] & kVersionMask) == kVersion6; } 169 170 /** 171 * This method returns the IPv6 DSCP value. 172 * 173 * @returns The IPv6 DSCP value. 174 * 175 */ GetDscp(void) const176 uint8_t GetDscp(void) const 177 { 178 return static_cast<uint8_t>((HostSwap16(mVersionClassFlow.m16[0]) & kDscpMask) >> kDscpOffset); 179 } 180 181 /** 182 * This method sets the IPv6 DSCP value. 183 * 184 * @param[in] aDscp The IPv6 DSCP value. 185 * 186 */ SetDscp(uint8_t aDscp)187 void SetDscp(uint8_t aDscp) 188 { 189 mVersionClassFlow.m16[0] = HostSwap16((HostSwap16(mVersionClassFlow.m16[0]) & ~kDscpMask) | 190 ((static_cast<uint16_t>(aDscp) << kDscpOffset) & kDscpMask)); 191 } 192 193 /** 194 * This method returns the IPv6 ECN value. 195 * 196 * @returns The IPv6 ECN value. 197 * 198 */ GetEcn(void) const199 uint8_t GetEcn(void) const { return (mVersionClassFlow.m8[1] & kEcnMask) >> kEcnOffset; } 200 201 /** 202 * This method sets the Ipv6 ECN value. 203 * 204 * @param[in] aEcn The Ipv6 ECN value. 205 * 206 */ SetEcn(uint8_t aEcn)207 void SetEcn(uint8_t aEcn) 208 { 209 mVersionClassFlow.m8[1] = (mVersionClassFlow.m8[1] & ~kEcnMask) | ((aEcn << kEcnOffset) & kEcnMask); 210 } 211 212 /** 213 * This method returns the IPv6 Payload Length value. 214 * 215 * @returns The IPv6 Payload Length value. 216 * 217 */ GetPayloadLength(void) const218 uint16_t GetPayloadLength(void) const { return HostSwap16(mPayloadLength); } 219 220 /** 221 * This method sets the IPv6 Payload Length value. 222 * 223 * @param[in] aLength The IPv6 Payload Length value. 224 * 225 */ SetPayloadLength(uint16_t aLength)226 void SetPayloadLength(uint16_t aLength) { mPayloadLength = HostSwap16(aLength); } 227 228 /** 229 * This method returns the IPv6 Next Header value. 230 * 231 * @returns The IPv6 Next Header value. 232 * 233 */ GetNextHeader(void) const234 uint8_t GetNextHeader(void) const { return mNextHeader; } 235 236 /** 237 * This method sets the IPv6 Next Header value. 238 * 239 * @param[in] aNextHeader The IPv6 Next Header value. 240 * 241 */ SetNextHeader(uint8_t aNextHeader)242 void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; } 243 244 /** 245 * This method returns the IPv6 Hop Limit value. 246 * 247 * @returns The IPv6 Hop Limit value. 248 * 249 */ GetHopLimit(void) const250 uint8_t GetHopLimit(void) const { return mHopLimit; } 251 252 /** 253 * This method sets the IPv6 Hop Limit value. 254 * 255 * @param[in] aHopLimit The IPv6 Hop Limit value. 256 * 257 */ SetHopLimit(uint8_t aHopLimit)258 void SetHopLimit(uint8_t aHopLimit) { mHopLimit = aHopLimit; } 259 260 /** 261 * This method returns the IPv6 Source address. 262 * 263 * @returns A reference to the IPv6 Source address. 264 * 265 */ GetSource(void)266 Address &GetSource(void) { return mSource; } 267 268 /** 269 * This method returns the IPv6 Source address. 270 * 271 * @returns A reference to the IPv6 Source address. 272 * 273 */ GetSource(void) const274 const Address &GetSource(void) const { return mSource; } 275 276 /** 277 * This method sets the IPv6 Source address. 278 * 279 * @param[in] aSource A reference to the IPv6 Source address. 280 * 281 */ SetSource(const Address & aSource)282 void SetSource(const Address &aSource) { mSource = aSource; } 283 284 /** 285 * This method returns the IPv6 Destination address. 286 * 287 * @returns A reference to the IPv6 Destination address. 288 * 289 */ GetDestination(void)290 Address &GetDestination(void) { return mDestination; } 291 292 /** 293 * This method returns the IPv6 Destination address. 294 * 295 * @returns A reference to the IPv6 Destination address. 296 * 297 */ GetDestination(void) const298 const Address &GetDestination(void) const { return mDestination; } 299 300 /** 301 * This method sets the IPv6 Destination address. 302 * 303 * @param[in] aDestination A reference to the IPv6 Destination address. 304 * 305 */ SetDestination(const Address & aDestination)306 void SetDestination(const Address &aDestination) { mDestination = aDestination; } 307 308 private: 309 static constexpr uint8_t kVersion6 = 0x60; 310 static constexpr uint8_t kVersionMask = 0xf0; // To use with `mVersionClassFlow.m8[0]` 311 static constexpr uint8_t kDscpOffset = 6; // To use with `mVersionClassFlow.m16[0]` 312 static constexpr uint16_t kDscpMask = 0x0fc0; // To use with `mVersionClassFlow.m16[0]` 313 static constexpr uint8_t kEcnOffset = 4; // To use with `mVersionClassFlow.m8[1]` 314 static constexpr uint8_t kEcnMask = 0x30; // To use with `mVersionClassFlow.m8[1]` 315 static constexpr uint32_t kVersionClassFlowInit = 0x60000000; // Version 6, TC and flow zero. 316 317 static constexpr uint8_t kEcnNotCapable = OT_ECN_NOT_CAPABLE; ///< Non-ECT 318 static constexpr uint8_t kEcnCapable0 = OT_ECN_CAPABLE_0; ///< ECT(0) 319 static constexpr uint8_t kEcnCapable1 = OT_ECN_CAPABLE_1; ///< ECT(1) 320 static constexpr uint8_t kEcnMarked = OT_ECN_MARKED; ///< Congestion encountered (CE) 321 322 union OT_TOOL_PACKED_FIELD 323 { 324 uint8_t m8[sizeof(uint32_t) / sizeof(uint8_t)]; 325 uint16_t m16[sizeof(uint32_t) / sizeof(uint16_t)]; 326 uint32_t m32; 327 } mVersionClassFlow; 328 uint16_t mPayloadLength; 329 uint8_t mNextHeader; 330 uint8_t mHopLimit; 331 Address mSource; 332 Address mDestination; 333 } OT_TOOL_PACKED_END; 334 335 /** 336 * This class implements IPv6 Extension Header generation and processing. 337 * 338 */ 339 OT_TOOL_PACKED_BEGIN 340 class ExtensionHeader 341 { 342 public: 343 /** 344 * This method returns the IPv6 Next Header value. 345 * 346 * @returns The IPv6 Next Header value. 347 * 348 */ GetNextHeader(void) const349 uint8_t GetNextHeader(void) const { return mNextHeader; } 350 351 /** 352 * This method sets the IPv6 Next Header value. 353 * 354 * @param[in] aNextHeader The IPv6 Next Header value. 355 * 356 */ SetNextHeader(uint8_t aNextHeader)357 void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; } 358 359 /** 360 * This method returns the IPv6 Header Extension Length value. 361 * 362 * @returns The IPv6 Header Extension Length value. 363 * 364 */ GetLength(void) const365 uint8_t GetLength(void) const { return mLength; } 366 367 /** 368 * This method sets the IPv6 Header Extension Length value. 369 * 370 * @param[in] aLength The IPv6 Header Extension Length value. 371 * 372 */ SetLength(uint8_t aLength)373 void SetLength(uint8_t aLength) { mLength = aLength; } 374 375 private: 376 uint8_t mNextHeader; 377 uint8_t mLength; 378 } OT_TOOL_PACKED_END; 379 380 /** 381 * This class implements IPv6 Hop-by-Hop Options Header generation and parsing. 382 * 383 */ 384 OT_TOOL_PACKED_BEGIN 385 class HopByHopHeader : public ExtensionHeader 386 { 387 } OT_TOOL_PACKED_END; 388 389 /** 390 * This class implements IPv6 Options generation and parsing. 391 * 392 */ 393 OT_TOOL_PACKED_BEGIN 394 class OptionHeader 395 { 396 public: 397 /** 398 * Default constructor. 399 * 400 */ OptionHeader(void)401 OptionHeader(void) 402 : mType(0) 403 , mLength(0) 404 { 405 } 406 407 /** 408 * This method returns the IPv6 Option Type value. 409 * 410 * @returns The IPv6 Option Type value. 411 * 412 */ GetType(void) const413 uint8_t GetType(void) const { return mType; } 414 415 /** 416 * This method sets the IPv6 Option Type value. 417 * 418 * @param[in] aType The IPv6 Option Type value. 419 * 420 */ SetType(uint8_t aType)421 void SetType(uint8_t aType) { mType = aType; } 422 423 /** 424 * IPv6 Option Type actions for unrecognized IPv6 Options. 425 * 426 */ 427 enum Action : uint8_t 428 { 429 kActionSkip = 0x00, ///< skip over this option and continue processing the header 430 kActionDiscard = 0x40, ///< discard the packet 431 kActionForceIcmp = 0x80, ///< discard the packet and forcibly send an ICMP Parameter Problem 432 kActionIcmp = 0xc0, ///< discard packet and conditionally send an ICMP Parameter Problem 433 }; 434 435 /** 436 * This method returns the IPv6 Option action for unrecognized IPv6 Options. 437 * 438 * @returns The IPv6 Option action for unrecognized IPv6 Options. 439 * 440 */ GetAction(void) const441 Action GetAction(void) const { return static_cast<Action>(mType & kActionMask); } 442 443 /** 444 * This method returns the IPv6 Option Length value. 445 * 446 * @returns The IPv6 Option Length value. 447 * 448 */ GetLength(void) const449 uint8_t GetLength(void) const { return mLength; } 450 451 /** 452 * This method sets the IPv6 Option Length value. 453 * 454 * @param[in] aLength The IPv6 Option Length value. 455 * 456 */ SetLength(uint8_t aLength)457 void SetLength(uint8_t aLength) { mLength = aLength; } 458 459 private: 460 static constexpr uint8_t kActionMask = 0xc0; 461 462 uint8_t mType; 463 uint8_t mLength; 464 } OT_TOOL_PACKED_END; 465 466 /** 467 * This class implements IPv6 PadN Option generation and parsing. 468 * 469 */ 470 OT_TOOL_PACKED_BEGIN 471 class OptionPadN : public OptionHeader 472 { 473 public: 474 static constexpr uint8_t kType = 0x01; ///< PadN type 475 static constexpr uint8_t kData = 0x00; ///< PadN specific data 476 static constexpr uint8_t kMaxLength = 0x05; ///< Maximum length of PadN option data 477 478 /** 479 * This method initializes the PadN header. 480 * 481 * @param[in] aPadLength The length of needed padding. Allowed value from 482 * range 2-7. 483 * 484 */ Init(uint8_t aPadLength)485 void Init(uint8_t aPadLength) 486 { 487 SetType(kType); 488 SetLength(aPadLength - sizeof(OptionHeader)); 489 memset(mPad, kData, aPadLength - sizeof(OptionHeader)); 490 } 491 492 /** 493 * This method returns the total IPv6 Option Length value including option 494 * header. 495 * 496 * @returns The total IPv6 Option Length. 497 * 498 */ GetTotalLength(void) const499 uint8_t GetTotalLength(void) const { return GetLength() + sizeof(OptionHeader); } 500 501 private: 502 uint8_t mPad[kMaxLength]; 503 } OT_TOOL_PACKED_END; 504 505 /** 506 * This class implements IPv6 Pad1 Option generation and parsing. Pad1 does not follow default option header structure. 507 * 508 */ 509 OT_TOOL_PACKED_BEGIN 510 class OptionPad1 511 { 512 public: 513 static constexpr uint8_t kType = 0x00; 514 515 /** 516 * This method initializes the Pad1 header. 517 * 518 */ Init(void)519 void Init(void) { mType = kType; } 520 521 private: 522 uint8_t mType; 523 } OT_TOOL_PACKED_END; 524 525 /** 526 * This class implements IPv6 Fragment Header generation and parsing. 527 * 528 */ 529 OT_TOOL_PACKED_BEGIN 530 class FragmentHeader 531 { 532 public: 533 /** 534 * This method initializes the IPv6 Fragment header. 535 * 536 */ Init(void)537 void Init(void) 538 { 539 mReserved = 0; 540 mOffsetMore = 0; 541 mIdentification = 0; 542 } 543 544 /** 545 * This method returns the IPv6 Next Header value. 546 * 547 * @returns The IPv6 Next Header value. 548 * 549 */ GetNextHeader(void) const550 uint8_t GetNextHeader(void) const { return mNextHeader; } 551 552 /** 553 * This method sets the IPv6 Next Header value. 554 * 555 * @param[in] aNextHeader The IPv6 Next Header value. 556 * 557 */ SetNextHeader(uint8_t aNextHeader)558 void SetNextHeader(uint8_t aNextHeader) { mNextHeader = aNextHeader; } 559 560 /** 561 * This method returns the Fragment Offset value. 562 * 563 * @returns The Fragment Offset value. 564 * 565 */ GetOffset(void) const566 uint16_t GetOffset(void) const { return (HostSwap16(mOffsetMore) & kOffsetMask) >> kOffsetOffset; } 567 568 /** 569 * This method sets the Fragment Offset value. 570 * 571 * @param[in] aOffset The Fragment Offset value. 572 */ SetOffset(uint16_t aOffset)573 void SetOffset(uint16_t aOffset) 574 { 575 uint16_t tmp = HostSwap16(mOffsetMore); 576 tmp = (tmp & ~kOffsetMask) | ((aOffset << kOffsetOffset) & kOffsetMask); 577 mOffsetMore = HostSwap16(tmp); 578 } 579 580 /** 581 * This method returns the M flag value. 582 * 583 * @returns The M flag value. 584 * 585 */ IsMoreFlagSet(void) const586 bool IsMoreFlagSet(void) const { return HostSwap16(mOffsetMore) & kMoreFlag; } 587 588 /** 589 * This method clears the M flag value. 590 * 591 */ ClearMoreFlag(void)592 void ClearMoreFlag(void) { mOffsetMore = HostSwap16(HostSwap16(mOffsetMore) & ~kMoreFlag); } 593 594 /** 595 * This method sets the M flag value. 596 * 597 */ SetMoreFlag(void)598 void SetMoreFlag(void) { mOffsetMore = HostSwap16(HostSwap16(mOffsetMore) | kMoreFlag); } 599 600 /** 601 * This method returns the frame identification. 602 * 603 * @returns The frame identification. 604 * 605 */ GetIdentification(void) const606 uint32_t GetIdentification(void) const { return mIdentification; } 607 608 /** 609 * This method sets the frame identification. 610 * 611 * @param[in] aIdentification The fragment identification value. 612 */ SetIdentification(uint32_t aIdentification)613 void SetIdentification(uint32_t aIdentification) { mIdentification = aIdentification; } 614 615 /** 616 * This method returns the next valid payload length for a fragment. 617 * 618 * @param[in] aLength The payload length to be validated for a fragment. 619 * 620 * @returns Valid IPv6 fragment payload length. 621 * 622 */ MakeDivisibleByEight(uint16_t aLength)623 static inline uint16_t MakeDivisibleByEight(uint16_t aLength) { return aLength & 0xfff8; } 624 625 /** 626 * This method converts the fragment offset of 8-octet units into bytes. 627 * 628 * @param[in] aOffset The fragment offset in 8-octet units. 629 * 630 * @returns The fragment offset in bytes. 631 * 632 */ FragmentOffsetToBytes(uint16_t aOffset)633 static inline uint16_t FragmentOffsetToBytes(uint16_t aOffset) { return static_cast<uint16_t>(aOffset << 3); } 634 635 /** 636 * This method converts a fragment offset in bytes into a fragment offset in 8-octet units. 637 * 638 * @param[in] aOffset The fragment offset in bytes. 639 * 640 * @returns The fragment offset in 8-octet units. 641 */ BytesToFragmentOffset(uint16_t aOffset)642 static inline uint16_t BytesToFragmentOffset(uint16_t aOffset) { return aOffset >> 3; } 643 644 private: 645 static constexpr uint8_t kOffsetOffset = 3; 646 static constexpr uint16_t kOffsetMask = 0xfff8; 647 static constexpr uint16_t kMoreFlag = 1; 648 649 uint8_t mNextHeader; 650 uint8_t mReserved; 651 uint16_t mOffsetMore; 652 uint32_t mIdentification; 653 } OT_TOOL_PACKED_END; 654 655 /** 656 * @} 657 * 658 */ 659 660 } // namespace Ip6 661 } // namespace ot 662 663 #endif // IP6_HEADERS_HPP_ 664