1 /* 2 * Copyright (c) 2020, 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 Neighbor Discovery (ND). 32 * 33 * See RFC 4861 (https://tools.ietf.org/html/rfc4861) and RFC 4191 (https://tools.ietf.org/html/rfc4191). 34 * 35 */ 36 37 #ifndef ND6_HPP_ 38 #define ND6_HPP_ 39 40 #include "openthread-core-config.h" 41 42 #include <stdint.h> 43 44 #include <openthread/netdata.h> 45 #include <openthread/platform/toolchain.h> 46 47 #include "common/const_cast.hpp" 48 #include "common/encoding.hpp" 49 #include "common/equatable.hpp" 50 #include "net/icmp6.hpp" 51 #include "net/ip6.hpp" 52 #include "thread/network_data_types.hpp" 53 54 using ot::Encoding::BigEndian::HostSwap16; 55 using ot::Encoding::BigEndian::HostSwap32; 56 57 namespace ot { 58 namespace Ip6 { 59 namespace Nd { 60 61 typedef NetworkData::RoutePreference RoutePreference; ///< Route Preference 62 63 /** 64 * Represents the variable length options in Neighbor Discovery messages. 65 * 66 * @sa PrefixInfoOption 67 * @sa RouteInfoOption 68 * 69 */ 70 OT_TOOL_PACKED_BEGIN 71 class Option 72 { 73 friend class RouterAdvertMessage; 74 75 public: 76 enum Type : uint8_t 77 { 78 kTypePrefixInfo = 3, ///< Prefix Information Option. 79 kTypeRouteInfo = 24, ///< Route Information Option. 80 }; 81 82 static constexpr uint16_t kLengthUnit = 8; ///< The unit of length in octets. 83 84 /** 85 * Gets the option type. 86 * 87 * @returns The option type. 88 * 89 */ GetType(void) const90 uint8_t GetType(void) const { return mType; } 91 92 /** 93 * Sets the option type. 94 * 95 * @param[in] aType The option type. 96 * 97 * 98 */ SetType(Type aType)99 void SetType(Type aType) { mType = aType; } 100 101 /** 102 * Sets the length based on a given total option size in bytes. 103 * 104 * Th option must end on a 64-bit boundary, so the length is derived as `(aSize + 7) / 8 * 8`. 105 * 106 * @param[in] aSize The size of option in bytes. 107 * 108 */ SetSize(uint16_t aSize)109 void SetSize(uint16_t aSize) { mLength = static_cast<uint8_t>((aSize + kLengthUnit - 1) / kLengthUnit); } 110 111 /** 112 * Returns the size of the option in bytes. 113 * 114 * @returns The size of the option in bytes. 115 * 116 */ GetSize(void) const117 uint16_t GetSize(void) const { return mLength * kLengthUnit; } 118 119 /** 120 * Sets the length of the option (in unit of 8 bytes). 121 * 122 * @param[in] aLength The length of the option in unit of 8 bytes. 123 * 124 */ SetLength(uint8_t aLength)125 void SetLength(uint8_t aLength) { mLength = aLength; } 126 127 /** 128 * Returns the length of the option (in unit of 8 bytes). 129 * 130 * @returns The length of the option in unit of 8 bytes. 131 * 132 */ GetLength(void) const133 uint16_t GetLength(void) const { return mLength; } 134 135 /** 136 * Indicates whether or not this option is valid. 137 * 138 * @retval TRUE The option is valid. 139 * @retval FALSE The option is not valid. 140 * 141 */ IsValid(void) const142 bool IsValid(void) const { return mLength > 0; } 143 144 private: 145 class Iterator : public Unequatable<Iterator> 146 { 147 public: 148 Iterator(void); 149 Iterator(const void *aStart, const void *aEnd); 150 operator *(void)151 const Option &operator*(void) { return *mOption; } operator ++(void)152 void operator++(void) { Advance(); } operator ++(int)153 void operator++(int) { Advance(); } operator ==(const Iterator & aOther) const154 bool operator==(const Iterator &aOther) const { return mOption == aOther.mOption; } 155 156 private: 157 static const Option *Next(const Option *aOption); 158 void Advance(void); 159 const Option *Validate(const Option *aOption) const; 160 161 const Option *mOption; 162 const Option *mEnd; 163 }; 164 165 uint8_t mType; // Type of the option. 166 uint8_t mLength; // Length of the option in unit of 8 octets, including the `mType` and `mLength` fields. 167 } OT_TOOL_PACKED_END; 168 169 /** 170 * Represents the Prefix Information Option. 171 * 172 * See section 4.6.2 of RFC 4861 for definition of this option [https://tools.ietf.org/html/rfc4861#section-4.6.2] 173 * 174 */ 175 OT_TOOL_PACKED_BEGIN 176 class PrefixInfoOption : public Option, private Clearable<PrefixInfoOption> 177 { 178 friend class Clearable<PrefixInfoOption>; 179 180 public: 181 static constexpr Type kType = kTypePrefixInfo; ///< Prefix Information Option Type. 182 183 /** 184 * Initializes the Prefix Info option with proper type and length and sets all other fields to zero. 185 * 186 */ 187 void Init(void); 188 189 /** 190 * Indicates whether or not the on-link flag is set. 191 * 192 * @retval TRUE The on-link flag is set. 193 * @retval FALSE The on-link flag is not set. 194 * 195 */ IsOnLinkFlagSet(void) const196 bool IsOnLinkFlagSet(void) const { return (mFlags & kOnLinkFlagMask) != 0; } 197 198 /** 199 * Sets the on-link (L) flag. 200 * 201 */ SetOnLinkFlag(void)202 void SetOnLinkFlag(void) { mFlags |= kOnLinkFlagMask; } 203 204 /** 205 * Clears the on-link (L) flag. 206 * 207 */ ClearOnLinkFlag(void)208 void ClearOnLinkFlag(void) { mFlags &= ~kOnLinkFlagMask; } 209 210 /** 211 * Indicates whether or not the autonomous address-configuration (A) flag is set. 212 * 213 * @retval TRUE The auto address-config flag is set. 214 * @retval FALSE The auto address-config flag is not set. 215 * 216 */ IsAutoAddrConfigFlagSet(void) const217 bool IsAutoAddrConfigFlagSet(void) const { return (mFlags & kAutoConfigFlagMask) != 0; } 218 219 /** 220 * Sets the autonomous address-configuration (A) flag. 221 * 222 */ SetAutoAddrConfigFlag(void)223 void SetAutoAddrConfigFlag(void) { mFlags |= kAutoConfigFlagMask; } 224 225 /** 226 * Clears the autonomous address-configuration (A) flag. 227 * 228 */ ClearAutoAddrConfigFlag(void)229 void ClearAutoAddrConfigFlag(void) { mFlags &= ~kAutoConfigFlagMask; } 230 231 /** 232 * Sets the valid lifetime of the prefix in seconds. 233 * 234 * @param[in] aValidLifetime The valid lifetime in seconds. 235 * 236 */ SetValidLifetime(uint32_t aValidLifetime)237 void SetValidLifetime(uint32_t aValidLifetime) { mValidLifetime = HostSwap32(aValidLifetime); } 238 239 /** 240 * THis method gets the valid lifetime of the prefix in seconds. 241 * 242 * @returns The valid lifetime in seconds. 243 * 244 */ GetValidLifetime(void) const245 uint32_t GetValidLifetime(void) const { return HostSwap32(mValidLifetime); } 246 247 /** 248 * Sets the preferred lifetime of the prefix in seconds. 249 * 250 * @param[in] aPreferredLifetime The preferred lifetime in seconds. 251 * 252 */ SetPreferredLifetime(uint32_t aPreferredLifetime)253 void SetPreferredLifetime(uint32_t aPreferredLifetime) { mPreferredLifetime = HostSwap32(aPreferredLifetime); } 254 255 /** 256 * THis method returns the preferred lifetime of the prefix in seconds. 257 * 258 * @returns The preferred lifetime in seconds. 259 * 260 */ GetPreferredLifetime(void) const261 uint32_t GetPreferredLifetime(void) const { return HostSwap32(mPreferredLifetime); } 262 263 /** 264 * Sets the prefix. 265 * 266 * @param[in] aPrefix The prefix contained in this option. 267 * 268 */ 269 void SetPrefix(const Prefix &aPrefix); 270 271 /** 272 * Gets the prefix in this option. 273 * 274 * @param[out] aPrefix Reference to a `Prefix` to return the prefix. 275 * 276 */ 277 void GetPrefix(Prefix &aPrefix) const; 278 279 /** 280 * Indicates whether or not the option is valid. 281 * 282 * @retval TRUE The option is valid 283 * @retval FALSE The option is not valid. 284 * 285 */ 286 bool IsValid(void) const; 287 288 PrefixInfoOption(void) = delete; 289 290 private: 291 // Prefix Information Option 292 // 293 // 0 1 2 3 294 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 295 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 296 // | Type | Length | Prefix Length |L|A| Reserved1 | 297 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 298 // | Valid Lifetime | 299 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 300 // | Preferred Lifetime | 301 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 302 // | Reserved2 | 303 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 304 // | | 305 // + + 306 // | | 307 // + Prefix + 308 // | | 309 // + + 310 // | | 311 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 312 313 static constexpr uint8_t kAutoConfigFlagMask = 0x40; // Autonomous address-configuration flag. 314 static constexpr uint8_t kOnLinkFlagMask = 0x80; // On-link flag. 315 316 uint8_t mPrefixLength; // The prefix length in bits. 317 uint8_t mFlags; // The flags field. 318 uint32_t mValidLifetime; // The valid lifetime of the prefix. 319 uint32_t mPreferredLifetime; // The preferred lifetime of the prefix. 320 uint32_t mReserved2; // The reserved field. 321 Address mPrefix; // The prefix. 322 } OT_TOOL_PACKED_END; 323 324 static_assert(sizeof(PrefixInfoOption) == 32, "invalid PrefixInfoOption structure"); 325 326 /** 327 * Represents the Route Information Option. 328 * 329 * See section 2.3 of RFC 4191 for definition of this option. [https://tools.ietf.org/html/rfc4191#section-2.3] 330 * 331 */ 332 OT_TOOL_PACKED_BEGIN 333 class RouteInfoOption : public Option, private Clearable<RouteInfoOption> 334 { 335 friend class Clearable<RouteInfoOption>; 336 337 public: 338 static constexpr uint16_t kMinSize = kLengthUnit; ///< Minimum size (in bytes) of a Route Info Option 339 static constexpr Type kType = kTypeRouteInfo; ///< Route Information Option Type. 340 341 /** 342 * Initializes the option setting the type and clearing (setting to zero) all other fields. 343 * 344 */ 345 void Init(void); 346 347 /** 348 * Sets the route preference. 349 * 350 * @param[in] aPreference The route preference. 351 * 352 */ 353 void SetPreference(RoutePreference aPreference); 354 355 /** 356 * Gets the route preference. 357 * 358 * @returns The route preference. 359 * 360 */ 361 RoutePreference GetPreference(void) const; 362 363 /** 364 * Sets the lifetime of the route in seconds. 365 * 366 * @param[in] aLifetime The lifetime of the route in seconds. 367 * 368 */ SetRouteLifetime(uint32_t aLifetime)369 void SetRouteLifetime(uint32_t aLifetime) { mRouteLifetime = HostSwap32(aLifetime); } 370 371 /** 372 * Gets Route Lifetime in seconds. 373 * 374 * @returns The Route Lifetime in seconds. 375 * 376 */ GetRouteLifetime(void) const377 uint32_t GetRouteLifetime(void) const { return HostSwap32(mRouteLifetime); } 378 379 /** 380 * Sets the prefix and adjusts the option length based on the prefix length. 381 * 382 * @param[in] aPrefix The prefix contained in this option. 383 * 384 */ 385 void SetPrefix(const Prefix &aPrefix); 386 387 /** 388 * Gets the prefix in this option. 389 * 390 * @param[out] aPrefix Reference to a `Prefix` to return the prefix. 391 * 392 */ 393 void GetPrefix(Prefix &aPrefix) const; 394 395 /** 396 * Tells whether this option is valid. 397 * 398 * @returns A boolean indicates whether this option is valid. 399 * 400 */ 401 bool IsValid(void) const; 402 403 /** 404 * Calculates the minimum option length for a given prefix length. 405 * 406 * The option length (which is in unit of 8 octets) can be 1, 2, or 3 depending on the prefix length. It can be 1 407 * for a zero prefix length, 2 if the prefix length is not greater than 64, and 3 otherwise. 408 * 409 * @param[in] aPrefixLength The prefix length (in bits). 410 * 411 * @returns The option length (in unit of 8 octet) for @p aPrefixLength. 412 * 413 */ 414 static uint8_t OptionLengthForPrefix(uint8_t aPrefixLength); 415 416 /** 417 * Calculates the minimum option size (in bytes) for a given prefix length. 418 * 419 * @param[in] aPrefixLength The prefix length (in bits). 420 * 421 * @returns The option size (in bytes) for @p aPrefixLength. 422 * 423 */ OptionSizeForPrefix(uint8_t aPrefixLength)424 static uint16_t OptionSizeForPrefix(uint8_t aPrefixLength) 425 { 426 return kLengthUnit * OptionLengthForPrefix(aPrefixLength); 427 } 428 429 RouteInfoOption(void) = delete; 430 431 private: 432 // Route Information Option 433 // 434 // 0 1 2 3 435 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 436 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 437 // | Type | Length | Prefix Length |Resvd|Prf|Resvd| 438 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 439 // | Route Lifetime | 440 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 441 // | Prefix (Variable Length) | 442 // . . 443 // . . 444 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 445 446 static constexpr uint8_t kPreferenceOffset = 3; 447 static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset; 448 GetPrefixBytes(void)449 uint8_t *GetPrefixBytes(void) { return AsNonConst(AsConst(this)->GetPrefixBytes()); } GetPrefixBytes(void) const450 const uint8_t *GetPrefixBytes(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); } 451 452 uint8_t mPrefixLength; // The prefix length in bits. 453 uint8_t mResvdPrf; // The preference. 454 uint32_t mRouteLifetime; // The lifetime in seconds. 455 // Followed by prefix bytes (variable length). 456 457 } OT_TOOL_PACKED_END; 458 459 static_assert(sizeof(RouteInfoOption) == 8, "invalid RouteInfoOption structure"); 460 461 /** 462 * Represents a Router Advertisement message. 463 * 464 */ 465 class RouterAdvertMessage 466 { 467 public: 468 /** 469 * Implements the RA message header. 470 * 471 * See section 2.2 of RFC 4191 [https://datatracker.ietf.org/doc/html/rfc4191] 472 * 473 */ 474 OT_TOOL_PACKED_BEGIN 475 class Header : public Equatable<Header>, private Clearable<Header> 476 { 477 friend class Clearable<Header>; 478 479 public: 480 /** 481 * Initializes the Router Advertisement message with 482 * zero router lifetime, reachable time and retransmission timer. 483 * 484 */ Header(void)485 Header(void) { SetToDefault(); } 486 487 /** 488 * Sets the RA message to default values. 489 * 490 */ 491 void SetToDefault(void); 492 493 /** 494 * Sets the checksum value. 495 * 496 * @param[in] aChecksum The checksum value. 497 * 498 */ SetChecksum(uint16_t aChecksum)499 void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); } 500 501 /** 502 * Sets the Router Lifetime in seconds. 503 * 504 * @param[in] aRouterLifetime The router lifetime in seconds. 505 * 506 */ SetRouterLifetime(uint16_t aRouterLifetime)507 void SetRouterLifetime(uint16_t aRouterLifetime) { mRouterLifetime = HostSwap16(aRouterLifetime); } 508 509 /** 510 * Gets the Router Lifetime (in seconds). 511 * 512 * Router Lifetime set to zero indicates that the sender is not a default router. 513 * 514 * @returns The router lifetime in seconds. 515 * 516 */ GetRouterLifetime(void) const517 uint16_t GetRouterLifetime(void) const { return HostSwap16(mRouterLifetime); } 518 519 /** 520 * Sets the default router preference. 521 * 522 * @param[in] aPreference The router preference. 523 * 524 */ 525 void SetDefaultRouterPreference(RoutePreference aPreference); 526 527 /** 528 * Gets the default router preference. 529 * 530 * @returns The router preference. 531 * 532 */ 533 RoutePreference GetDefaultRouterPreference(void) const; 534 535 /** 536 * This method returns the ICMPv6 message type. 537 * 538 * @returns The ICMPv6 message type. 539 * 540 */ GetType(void) const541 Icmp::Header::Type GetType(void) const { return static_cast<Icmp::Header::Type>(mType); } 542 543 private: 544 // Router Advertisement Message 545 // 546 // 0 1 2 3 547 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 548 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 549 // | Type | Code | Checksum | 550 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 551 // | Cur Hop Limit |M|O|H|Prf|Resvd| Router Lifetime | 552 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 553 // | Reachable Time | 554 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 555 // | Retrans Timer | 556 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 557 // | Options ... 558 // +-+-+-+-+-+-+-+-+-+-+-+- 559 560 static constexpr uint8_t kPreferenceOffset = 3; 561 static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset; 562 563 uint8_t mType; 564 uint8_t mCode; 565 uint16_t mChecksum; 566 uint8_t mCurHopLimit; 567 uint8_t mFlags; 568 uint16_t mRouterLifetime; 569 uint32_t mReachableTime; 570 uint32_t mRetransTimer; 571 } OT_TOOL_PACKED_END; 572 573 static_assert(sizeof(Header) == 16, "Invalid RA `Header`"); 574 575 typedef Data<kWithUint16Length> Icmp6Packet; ///< A data buffer containing an ICMPv6 packet. 576 577 /** 578 * Initializes the RA message from a received packet data buffer. 579 * 580 * @param[in] aPacket A received packet data. 581 * 582 */ RouterAdvertMessage(const Icmp6Packet & aPacket)583 explicit RouterAdvertMessage(const Icmp6Packet &aPacket) 584 : mData(aPacket) 585 , mMaxLength(0) 586 { 587 } 588 589 /** 590 * This template constructor initializes the RA message with a given header using a given buffer to store the RA 591 * message. 592 * 593 * @tparam kBufferSize The size of the buffer used to store the RA message. 594 * 595 * @param[in] aHeader The RA message header. 596 * @param[in] aBuffer The data buffer to store the RA message in. 597 * 598 */ 599 template <uint16_t kBufferSize> RouterAdvertMessage(const Header & aHeader,uint8_t (& aBuffer)[kBufferSize])600 RouterAdvertMessage(const Header &aHeader, uint8_t (&aBuffer)[kBufferSize]) 601 : mMaxLength(kBufferSize) 602 { 603 static_assert(kBufferSize >= sizeof(Header), "Buffer for RA msg is too small"); 604 605 memcpy(aBuffer, &aHeader, sizeof(Header)); 606 mData.Init(aBuffer, sizeof(Header)); 607 } 608 609 /** 610 * Gets the RA message as an `Icmp6Packet`. 611 * 612 * @returns The RA message as an `Icmp6Packet`. 613 * 614 */ GetAsPacket(void) const615 const Icmp6Packet &GetAsPacket(void) const { return mData; } 616 617 /** 618 * Indicates whether or not the RA message is valid. 619 * 620 * @retval TRUE If the RA message is valid. 621 * @retval FALSE If the RA message is not valid. 622 * 623 */ IsValid(void) const624 bool IsValid(void) const 625 { 626 return (mData.GetBytes() != nullptr) && (mData.GetLength() >= sizeof(Header)) && 627 (GetHeader().GetType() == Icmp::Header::kTypeRouterAdvert); 628 } 629 630 /** 631 * Gets the RA message's header. 632 * 633 * @returns The RA message's header. 634 * 635 */ GetHeader(void) const636 const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); } 637 638 /** 639 * Appends a Prefix Info Option to the RA message. 640 * 641 * The appended Prefix Info Option will have both on-link (L) and autonomous address-configuration (A) flags set. 642 * 643 * @param[in] aPrefix The prefix. 644 * @param[in] aValidLifetime The valid lifetime in seconds. 645 * @param[in] aPreferredLifetime The preferred lifetime in seconds. 646 * 647 * @retval kErrorNone Option is appended successfully. 648 * @retval kErrorNoBufs No more space in the buffer to append the option. 649 * 650 */ 651 Error AppendPrefixInfoOption(const Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime); 652 653 /** 654 * Appends a Route Info Option to the RA message. 655 * 656 * @param[in] aPrefix The prefix. 657 * @param[in] aRouteLifetime The route lifetime in seconds. 658 * @param[in] aPreference The route preference. 659 * 660 * @retval kErrorNone Option is appended successfully. 661 * @retval kErrorNoBufs No more space in the buffer to append the option. 662 * 663 */ 664 Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference); 665 666 /** 667 * Indicates whether or not the RA message contains any options. 668 * 669 * @retval TRUE If the RA message contains at least one option. 670 * @retval FALSE If the RA message contains no options. 671 * 672 */ ContainsAnyOptions(void) const673 bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); } 674 675 // The following methods are intended to support range-based `for` 676 // loop iteration over `Option`s in the RA message. 677 begin(void) const678 Option::Iterator begin(void) const { return Option::Iterator(GetOptionStart(), GetDataEnd()); } end(void) const679 Option::Iterator end(void) const { return Option::Iterator(); } 680 681 private: GetOptionStart(void) const682 const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); } GetDataEnd(void) const683 const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); } 684 Option *AppendOption(uint16_t aOptionSize); 685 686 Data<kWithUint16Length> mData; 687 uint16_t mMaxLength; 688 }; 689 690 /** 691 * Implements the Router Solicitation message. 692 * 693 * See section 4.1 of RFC 4861 for definition of this message. 694 * https://tools.ietf.org/html/rfc4861#section-4.1 695 * 696 */ 697 OT_TOOL_PACKED_BEGIN 698 class RouterSolicitMessage 699 { 700 public: 701 /** 702 * Initializes the Router Solicitation message. 703 * 704 */ 705 RouterSolicitMessage(void); 706 707 private: 708 Icmp::Header mHeader; // The common ICMPv6 header. 709 } OT_TOOL_PACKED_END; 710 711 static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure"); 712 713 /** 714 * Represents a Neighbor Solicitation (NS) message. 715 * 716 */ 717 OT_TOOL_PACKED_BEGIN 718 class NeighborSolicitMessage : public Clearable<NeighborSolicitMessage> 719 { 720 public: 721 /** 722 * Initializes the Neighbor Solicitation message. 723 * 724 */ 725 NeighborSolicitMessage(void); 726 727 /** 728 * Indicates whether the Neighbor Solicitation message is valid (proper Type and Code). 729 * 730 * @retval TRUE If the message is valid. 731 * @retval FALSE If the message is not valid. 732 * 733 */ IsValid(void) const734 bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborSolicit) && (mCode == 0); } 735 736 /** 737 * Gets the Target Address field. 738 * 739 * @returns The Target Address. 740 * 741 */ GetTargetAddress(void) const742 const Address &GetTargetAddress(void) const { return mTargetAddress; } 743 744 /** 745 * Sets the Target Address field. 746 * 747 * @param[in] aTargetAddress The Target Address. 748 * 749 */ SetTargetAddress(const Address & aTargetAddress)750 void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; } 751 752 private: 753 // Neighbor Solicitation Message (RFC 4861) 754 // 755 // 0 1 2 3 756 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 757 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 758 // | Type | Code | Checksum | 759 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 760 // | Reserved | 761 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 762 // | | 763 // + + 764 // | | 765 // + Target Address + 766 // | | 767 // + + 768 // | | 769 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 770 // | Options ... 771 // +-+-+-+-+-+-+-+-+-+-+-+- 772 773 uint8_t mType; 774 uint8_t mCode; 775 uint16_t mChecksum; 776 uint32_t mReserved; 777 Address mTargetAddress; 778 } OT_TOOL_PACKED_END; 779 780 static_assert(sizeof(NeighborSolicitMessage) == 24, "Invalid NeighborSolicitMessage definition"); 781 782 /** 783 * Represents a Neighbor Advertisement (NA) message. 784 * 785 */ 786 OT_TOOL_PACKED_BEGIN 787 class NeighborAdvertMessage : public Clearable<NeighborAdvertMessage> 788 { 789 public: 790 NeighborAdvertMessage(void); 791 792 /** 793 * Indicates whether the Neighbor Advertisement message is valid (proper Type and Code). 794 * 795 * @retval TRUE If the message is valid. 796 * @retval FALSE If the message is not valid. 797 * 798 */ IsValid(void) const799 bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborAdvert) && (mCode == 0); } 800 801 /** 802 * Indicates whether or not the Router Flag is set in the NA message. 803 * 804 * @retval TRUE The Router Flag is set. 805 * @retval FALSE The Router Flag is not set. 806 * 807 */ IsRouterFlagSet(void) const808 bool IsRouterFlagSet(void) const { return (mFlags & kRouterFlag) != 0; } 809 810 /** 811 * Sets the Router Flag in the NA message. 812 * 813 */ SetRouterFlag(void)814 void SetRouterFlag(void) { mFlags |= kRouterFlag; } 815 816 /** 817 * Indicates whether or not the Solicited Flag is set in the NA message. 818 * 819 * @retval TRUE The Solicited Flag is set. 820 * @retval FALSE The Solicited Flag is not set. 821 * 822 */ IsSolicitedFlagSet(void) const823 bool IsSolicitedFlagSet(void) const { return (mFlags & kSolicitedFlag) != 0; } 824 825 /** 826 * Sets the Solicited Flag in the NA message. 827 * 828 */ SetSolicitedFlag(void)829 void SetSolicitedFlag(void) { mFlags |= kSolicitedFlag; } 830 831 /** 832 * Indicates whether or not the Override Flag is set in the NA message. 833 * 834 * @retval TRUE The Override Flag is set. 835 * @retval FALSE The Override Flag is not set. 836 * 837 */ IsOverrideFlagSet(void) const838 bool IsOverrideFlagSet(void) const { return (mFlags & kOverrideFlag) != 0; } 839 840 /** 841 * Sets the Override Flag in the NA message. 842 * 843 */ SetOverrideFlag(void)844 void SetOverrideFlag(void) { mFlags |= kOverrideFlag; } 845 846 /** 847 * Gets the Target Address field. 848 * 849 * @returns The Target Address. 850 * 851 */ GetTargetAddress(void) const852 const Address &GetTargetAddress(void) const { return mTargetAddress; } 853 854 /** 855 * Sets the Target Address field. 856 * 857 * @param[in] aTargetAddress The Target Address. 858 * 859 */ SetTargetAddress(const Address & aTargetAddress)860 void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; } 861 862 private: 863 // Neighbor Advertisement Message (RFC 4861) 864 // 865 // 0 1 2 3 866 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 867 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 868 // | Type | Code | Checksum | 869 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 870 // |R|S|O| Reserved | 871 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 872 // | | 873 // + + 874 // | | 875 // + Target Address + 876 // | | 877 // + + 878 // | | 879 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 880 // | Options ... 881 // +-+-+-+-+-+-+-+-+-+-+-+- 882 883 static constexpr uint8_t kRouterFlag = (1 << 7); 884 static constexpr uint8_t kSolicitedFlag = (1 << 6); 885 static constexpr uint8_t kOverrideFlag = (1 << 5); 886 887 uint8_t mType; 888 uint8_t mCode; 889 uint16_t mChecksum; 890 uint8_t mFlags; 891 uint8_t mReserved[3]; 892 Address mTargetAddress; 893 } OT_TOOL_PACKED_END; 894 895 static_assert(sizeof(NeighborAdvertMessage) == 24, "Invalid NeighborAdvertMessage definition"); 896 897 } // namespace Nd 898 } // namespace Ip6 899 } // namespace ot 900 901 #endif // ND6_HPP_ 902