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 "common/heap_array.hpp" 51 #include "net/icmp6.hpp" 52 #include "net/ip6.hpp" 53 #include "thread/network_data_types.hpp" 54 55 namespace ot { 56 namespace Ip6 { 57 namespace Nd { 58 59 typedef NetworkData::RoutePreference RoutePreference; ///< Route Preference 60 61 /** 62 * Represents the variable length options in Neighbor Discovery messages. 63 * 64 * @sa PrefixInfoOption 65 * @sa RouteInfoOption 66 * 67 */ 68 OT_TOOL_PACKED_BEGIN 69 class Option 70 { 71 friend class RouterAdvert; 72 73 public: 74 enum Type : uint8_t 75 { 76 kTypePrefixInfo = 3, ///< Prefix Information Option. 77 kTypeRouteInfo = 24, ///< Route Information Option. 78 kTypeRaFlagsExtension = 26, ///< RA Flags Extension Option. 79 }; 80 81 static constexpr uint16_t kLengthUnit = 8; ///< The unit of length in octets. 82 83 /** 84 * Gets the option type. 85 * 86 * @returns The option type. 87 * 88 */ GetType(void) const89 uint8_t GetType(void) const { return mType; } 90 91 /** 92 * Sets the option type. 93 * 94 * @param[in] aType The option type. 95 * 96 * 97 */ SetType(Type aType)98 void SetType(Type aType) { mType = aType; } 99 100 /** 101 * Sets the length based on a given total option size in bytes. 102 * 103 * Th option must end on a 64-bit boundary, so the length is derived as `(aSize + 7) / 8 * 8`. 104 * 105 * @param[in] aSize The size of option in bytes. 106 * 107 */ SetSize(uint16_t aSize)108 void SetSize(uint16_t aSize) { mLength = static_cast<uint8_t>((aSize + kLengthUnit - 1) / kLengthUnit); } 109 110 /** 111 * Returns the size of the option in bytes. 112 * 113 * @returns The size of the option in bytes. 114 * 115 */ GetSize(void) const116 uint16_t GetSize(void) const { return mLength * kLengthUnit; } 117 118 /** 119 * Sets the length of the option (in unit of 8 bytes). 120 * 121 * @param[in] aLength The length of the option in unit of 8 bytes. 122 * 123 */ SetLength(uint8_t aLength)124 void SetLength(uint8_t aLength) { mLength = aLength; } 125 126 /** 127 * Returns the length of the option (in unit of 8 bytes). 128 * 129 * @returns The length of the option in unit of 8 bytes. 130 * 131 */ GetLength(void) const132 uint16_t GetLength(void) const { return mLength; } 133 134 /** 135 * Indicates whether or not this option is valid. 136 * 137 * @retval TRUE The option is valid. 138 * @retval FALSE The option is not valid. 139 * 140 */ IsValid(void) const141 bool IsValid(void) const { return mLength > 0; } 142 143 private: 144 class Iterator : public Unequatable<Iterator> 145 { 146 public: 147 Iterator(void); 148 Iterator(const void *aStart, const void *aEnd); 149 operator *(void)150 const Option &operator*(void) { return *mOption; } operator ++(void)151 void operator++(void) { Advance(); } operator ++(int)152 void operator++(int) { Advance(); } operator ==(const Iterator & aOther) const153 bool operator==(const Iterator &aOther) const { return mOption == aOther.mOption; } 154 155 private: 156 static const Option *Next(const Option *aOption); 157 void Advance(void); 158 const Option *Validate(const Option *aOption) const; 159 160 const Option *mOption; 161 const Option *mEnd; 162 }; 163 164 uint8_t mType; // Type of the option. 165 uint8_t mLength; // Length of the option in unit of 8 octets, including the `mType` and `mLength` fields. 166 } OT_TOOL_PACKED_END; 167 168 /** 169 * Represents the Prefix Information Option. 170 * 171 * See section 4.6.2 of RFC 4861 for definition of this option [https://tools.ietf.org/html/rfc4861#section-4.6.2] 172 * 173 */ 174 OT_TOOL_PACKED_BEGIN 175 class PrefixInfoOption : public Option, private Clearable<PrefixInfoOption> 176 { 177 friend class Clearable<PrefixInfoOption>; 178 179 public: 180 static constexpr Type kType = kTypePrefixInfo; ///< Prefix Information Option Type. 181 182 /** 183 * Initializes the Prefix Info option with proper type and length and sets all other fields to zero. 184 * 185 */ 186 void Init(void); 187 188 /** 189 * Indicates whether or not the on-link flag is set. 190 * 191 * @retval TRUE The on-link flag is set. 192 * @retval FALSE The on-link flag is not set. 193 * 194 */ IsOnLinkFlagSet(void) const195 bool IsOnLinkFlagSet(void) const { return (mFlags & kOnLinkFlagMask) != 0; } 196 197 /** 198 * Sets the on-link (L) flag. 199 * 200 */ SetOnLinkFlag(void)201 void SetOnLinkFlag(void) { mFlags |= kOnLinkFlagMask; } 202 203 /** 204 * Clears the on-link (L) flag. 205 * 206 */ ClearOnLinkFlag(void)207 void ClearOnLinkFlag(void) { mFlags &= ~kOnLinkFlagMask; } 208 209 /** 210 * Indicates whether or not the autonomous address-configuration (A) flag is set. 211 * 212 * @retval TRUE The auto address-config flag is set. 213 * @retval FALSE The auto address-config flag is not set. 214 * 215 */ IsAutoAddrConfigFlagSet(void) const216 bool IsAutoAddrConfigFlagSet(void) const { return (mFlags & kAutoConfigFlagMask) != 0; } 217 218 /** 219 * Sets the autonomous address-configuration (A) flag. 220 * 221 */ SetAutoAddrConfigFlag(void)222 void SetAutoAddrConfigFlag(void) { mFlags |= kAutoConfigFlagMask; } 223 224 /** 225 * Clears the autonomous address-configuration (A) flag. 226 * 227 */ ClearAutoAddrConfigFlag(void)228 void ClearAutoAddrConfigFlag(void) { mFlags &= ~kAutoConfigFlagMask; } 229 230 /** 231 * Sets the valid lifetime of the prefix in seconds. 232 * 233 * @param[in] aValidLifetime The valid lifetime in seconds. 234 * 235 */ SetValidLifetime(uint32_t aValidLifetime)236 void SetValidLifetime(uint32_t aValidLifetime) { mValidLifetime = BigEndian::HostSwap32(aValidLifetime); } 237 238 /** 239 * THis method gets the valid lifetime of the prefix in seconds. 240 * 241 * @returns The valid lifetime in seconds. 242 * 243 */ GetValidLifetime(void) const244 uint32_t GetValidLifetime(void) const { return BigEndian::HostSwap32(mValidLifetime); } 245 246 /** 247 * Sets the preferred lifetime of the prefix in seconds. 248 * 249 * @param[in] aPreferredLifetime The preferred lifetime in seconds. 250 * 251 */ SetPreferredLifetime(uint32_t aPreferredLifetime)252 void SetPreferredLifetime(uint32_t aPreferredLifetime) 253 { 254 mPreferredLifetime = BigEndian::HostSwap32(aPreferredLifetime); 255 } 256 257 /** 258 * THis method returns the preferred lifetime of the prefix in seconds. 259 * 260 * @returns The preferred lifetime in seconds. 261 * 262 */ GetPreferredLifetime(void) const263 uint32_t GetPreferredLifetime(void) const { return BigEndian::HostSwap32(mPreferredLifetime); } 264 265 /** 266 * Sets the prefix. 267 * 268 * @param[in] aPrefix The prefix contained in this option. 269 * 270 */ 271 void SetPrefix(const Prefix &aPrefix); 272 273 /** 274 * Gets the prefix in this option. 275 * 276 * @param[out] aPrefix Reference to a `Prefix` to return the prefix. 277 * 278 */ 279 void GetPrefix(Prefix &aPrefix) const; 280 281 /** 282 * Indicates whether or not the option is valid. 283 * 284 * @retval TRUE The option is valid 285 * @retval FALSE The option is not valid. 286 * 287 */ 288 bool IsValid(void) const; 289 290 PrefixInfoOption(void) = delete; 291 292 private: 293 // Prefix Information Option 294 // 295 // 0 1 2 3 296 // 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 297 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 298 // | Type | Length | Prefix Length |L|A| Reserved1 | 299 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 300 // | Valid Lifetime | 301 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 302 // | Preferred Lifetime | 303 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 304 // | Reserved2 | 305 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 306 // | | 307 // + + 308 // | | 309 // + Prefix + 310 // | | 311 // + + 312 // | | 313 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 314 315 static constexpr uint8_t kAutoConfigFlagMask = 0x40; // Autonomous address-configuration flag. 316 static constexpr uint8_t kOnLinkFlagMask = 0x80; // On-link flag. 317 318 uint8_t mPrefixLength; // The prefix length in bits. 319 uint8_t mFlags; // The flags field. 320 uint32_t mValidLifetime; // The valid lifetime of the prefix. 321 uint32_t mPreferredLifetime; // The preferred lifetime of the prefix. 322 uint32_t mReserved2; // The reserved field. 323 Address mPrefix; // The prefix. 324 } OT_TOOL_PACKED_END; 325 326 static_assert(sizeof(PrefixInfoOption) == 32, "invalid PrefixInfoOption structure"); 327 328 /** 329 * Represents the Route Information Option. 330 * 331 * See section 2.3 of RFC 4191 for definition of this option. [https://tools.ietf.org/html/rfc4191#section-2.3] 332 * 333 */ 334 OT_TOOL_PACKED_BEGIN 335 class RouteInfoOption : public Option, private Clearable<RouteInfoOption> 336 { 337 friend class Clearable<RouteInfoOption>; 338 339 public: 340 static constexpr uint16_t kMinSize = kLengthUnit; ///< Minimum size (in bytes) of a Route Info Option 341 static constexpr Type kType = kTypeRouteInfo; ///< Route Information Option Type. 342 343 /** 344 * Initializes the option setting the type and clearing (setting to zero) all other fields. 345 * 346 */ 347 void Init(void); 348 349 /** 350 * Sets the route preference. 351 * 352 * @param[in] aPreference The route preference. 353 * 354 */ 355 void SetPreference(RoutePreference aPreference); 356 357 /** 358 * Gets the route preference. 359 * 360 * @returns The route preference. 361 * 362 */ 363 RoutePreference GetPreference(void) const; 364 365 /** 366 * Sets the lifetime of the route in seconds. 367 * 368 * @param[in] aLifetime The lifetime of the route in seconds. 369 * 370 */ SetRouteLifetime(uint32_t aLifetime)371 void SetRouteLifetime(uint32_t aLifetime) { mRouteLifetime = BigEndian::HostSwap32(aLifetime); } 372 373 /** 374 * Gets Route Lifetime in seconds. 375 * 376 * @returns The Route Lifetime in seconds. 377 * 378 */ GetRouteLifetime(void) const379 uint32_t GetRouteLifetime(void) const { return BigEndian::HostSwap32(mRouteLifetime); } 380 381 /** 382 * Sets the prefix and adjusts the option length based on the prefix length. 383 * 384 * @param[in] aPrefix The prefix contained in this option. 385 * 386 */ 387 void SetPrefix(const Prefix &aPrefix); 388 389 /** 390 * Gets the prefix in this option. 391 * 392 * @param[out] aPrefix Reference to a `Prefix` to return the prefix. 393 * 394 */ 395 void GetPrefix(Prefix &aPrefix) const; 396 397 /** 398 * Tells whether this option is valid. 399 * 400 * @returns A boolean indicates whether this option is valid. 401 * 402 */ 403 bool IsValid(void) const; 404 405 /** 406 * Calculates the minimum option length for a given prefix length. 407 * 408 * 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 409 * for a zero prefix length, 2 if the prefix length is not greater than 64, and 3 otherwise. 410 * 411 * @param[in] aPrefixLength The prefix length (in bits). 412 * 413 * @returns The option length (in unit of 8 octet) for @p aPrefixLength. 414 * 415 */ 416 static uint8_t OptionLengthForPrefix(uint8_t aPrefixLength); 417 418 /** 419 * Calculates the minimum option size (in bytes) for a given prefix length. 420 * 421 * @param[in] aPrefixLength The prefix length (in bits). 422 * 423 * @returns The option size (in bytes) for @p aPrefixLength. 424 * 425 */ OptionSizeForPrefix(uint8_t aPrefixLength)426 static uint16_t OptionSizeForPrefix(uint8_t aPrefixLength) 427 { 428 return kLengthUnit * OptionLengthForPrefix(aPrefixLength); 429 } 430 431 RouteInfoOption(void) = delete; 432 433 private: 434 // Route Information Option 435 // 436 // 0 1 2 3 437 // 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 438 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 439 // | Type | Length | Prefix Length |Resvd|Prf|Resvd| 440 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 441 // | Route Lifetime | 442 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 443 // | Prefix (Variable Length) | 444 // . . 445 // . . 446 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 447 448 static constexpr uint8_t kPreferenceOffset = 3; 449 static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset; 450 GetPrefixBytes(void)451 uint8_t *GetPrefixBytes(void) { return AsNonConst(AsConst(this)->GetPrefixBytes()); } GetPrefixBytes(void) const452 const uint8_t *GetPrefixBytes(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); } 453 454 uint8_t mPrefixLength; // The prefix length in bits. 455 uint8_t mResvdPrf; // The preference. 456 uint32_t mRouteLifetime; // The lifetime in seconds. 457 // Followed by prefix bytes (variable length). 458 459 } OT_TOOL_PACKED_END; 460 461 static_assert(sizeof(RouteInfoOption) == 8, "invalid RouteInfoOption structure"); 462 463 /** 464 * Represents an RA Flags Extension Option. 465 * 466 * See RFC-5175 [https://tools.ietf.org/html/rfc5175] 467 * 468 */ 469 OT_TOOL_PACKED_BEGIN 470 class RaFlagsExtOption : public Option, private Clearable<RaFlagsExtOption> 471 { 472 friend class Clearable<RaFlagsExtOption>; 473 474 public: 475 static constexpr Type kType = kTypeRaFlagsExtension; ///< RA Flags Extension Option type. 476 477 /** 478 * Initializes the RA Flags Extension option with proper type and length and sets all flags to zero. 479 * 480 */ 481 void Init(void); 482 483 /** 484 * Tells whether this option is valid. 485 * 486 * @returns A boolean indicates whether this option is valid. 487 * 488 */ IsValid(void) const489 bool IsValid(void) const { return GetSize() >= sizeof(*this); } 490 491 /** 492 * Indicates whether or not the Stub Router Flag is set. 493 * 494 * @retval TRUE The Stub Router Flag is set. 495 * @retval FALSE The Stub Router Flag is not set. 496 * 497 */ IsStubRouterFlagSet(void) const498 bool IsStubRouterFlagSet(void) const { return (mFlags[0] & kStubRouterFlag) != 0; } 499 500 /** 501 * Sets the Stub Router Flag. 502 * 503 */ SetStubRouterFlag(void)504 void SetStubRouterFlag(void) { mFlags[0] |= kStubRouterFlag; } 505 506 RaFlagsExtOption(void) = delete; 507 508 private: 509 // RA Flags Extension Option 510 // 511 // 0 1 2 3 512 // 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 513 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 514 // | Type | Length | Bit fields available .. 515 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 516 // ... for assignment | 517 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ . 518 519 // Stub router flags defined in [https://www.ietf.org/archive/id/draft-hui-stub-router-ra-flag-01.txt] 520 521 static constexpr uint8_t kStubRouterFlag = 1 << 7; 522 523 uint8_t mFlags[6]; 524 } OT_TOOL_PACKED_END; 525 526 static_assert(sizeof(RaFlagsExtOption) == 8, "invalid RaFlagsExtOption structure"); 527 528 /** 529 * Defines Router Advertisement components. 530 * 531 */ 532 class RouterAdvert 533 { 534 public: 535 /** 536 * Represent an RA message header. 537 * 538 * See section 2.2 of RFC 4191 [https://datatracker.ietf.org/doc/html/rfc4191] 539 * 540 */ 541 OT_TOOL_PACKED_BEGIN 542 class Header : public Equatable<Header>, public Clearable<Header> 543 { 544 friend class Clearable<Header>; 545 546 public: 547 /** 548 * Initializes the Router Advertisement message with 549 * zero router lifetime, reachable time and retransmission timer. 550 * 551 */ Header(void)552 Header(void) { SetToDefault(); } 553 554 /** 555 * Indicates whether the header is valid by checking the type field to match Router Advertisement ICMPv6 type. 556 * 557 * @retval TRUE The header is valid. 558 * @retval FALSE The header is not valid. 559 * 560 */ IsValid(void) const561 bool IsValid(void) const { return GetType() == Icmp::Header::kTypeRouterAdvert; } 562 563 /** 564 * Sets the RA message to default values. 565 * 566 */ 567 void SetToDefault(void); 568 569 /** 570 * Sets the checksum value. 571 * 572 * @param[in] aChecksum The checksum value. 573 * 574 */ SetChecksum(uint16_t aChecksum)575 void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); } 576 577 /** 578 * Sets the Router Lifetime in seconds. 579 * 580 * @param[in] aRouterLifetime The router lifetime in seconds. 581 * 582 */ SetRouterLifetime(uint16_t aRouterLifetime)583 void SetRouterLifetime(uint16_t aRouterLifetime) { mRouterLifetime = BigEndian::HostSwap16(aRouterLifetime); } 584 585 /** 586 * Gets the Router Lifetime (in seconds). 587 * 588 * Router Lifetime set to zero indicates that the sender is not a default router. 589 * 590 * @returns The router lifetime in seconds. 591 * 592 */ GetRouterLifetime(void) const593 uint16_t GetRouterLifetime(void) const { return BigEndian::HostSwap16(mRouterLifetime); } 594 595 /** 596 * Sets the default router preference. 597 * 598 * @param[in] aPreference The router preference. 599 * 600 */ 601 void SetDefaultRouterPreference(RoutePreference aPreference); 602 603 /** 604 * Gets the default router preference. 605 * 606 * @returns The router preference. 607 * 608 */ 609 RoutePreference GetDefaultRouterPreference(void) const; 610 611 /** 612 * Indicates whether or not the Managed Address Config Flag is set in the RA message header. 613 * 614 * @retval TRUE The Managed Address Config Flag is set. 615 * @retval FALSE The Managed Address Config Flag is not set. 616 * 617 */ IsManagedAddressConfigFlagSet(void) const618 bool IsManagedAddressConfigFlagSet(void) const { return (mFlags & kManagedAddressConfigFlag) != 0; } 619 620 /** 621 * Sets the Managed Address Config Flag in the RA message. 622 * 623 */ SetManagedAddressConfigFlag(void)624 void SetManagedAddressConfigFlag(void) { mFlags |= kManagedAddressConfigFlag; } 625 626 /** 627 * Indicates whether or not the Other Config Flag is set in the RA message header. 628 * 629 * @retval TRUE The Other Config Flag is set. 630 * @retval FALSE The Other Config Flag is not set. 631 * 632 */ IsOtherConfigFlagSet(void) const633 bool IsOtherConfigFlagSet(void) const { return (mFlags & kOtherConfigFlag) != 0; } 634 635 /** 636 * Sets the Other Config Flag in the RA message. 637 * 638 */ SetOtherConfigFlag(void)639 void SetOtherConfigFlag(void) { mFlags |= kOtherConfigFlag; } 640 641 /** 642 * This method returns the ICMPv6 message type. 643 * 644 * @returns The ICMPv6 message type. 645 * 646 */ GetType(void) const647 Icmp::Header::Type GetType(void) const { return static_cast<Icmp::Header::Type>(mType); } 648 649 private: 650 // Router Advertisement Message 651 // 652 // 0 1 2 3 653 // 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 654 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 655 // | Type | Code | Checksum | 656 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 657 // | Cur Hop Limit |M|O| |Prf| | Router Lifetime | 658 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 659 // | Reachable Time | 660 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 661 // | Retrans Timer | 662 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 663 // | Options ... 664 // +-+-+-+-+-+-+-+-+-+-+-+- 665 666 static constexpr uint8_t kManagedAddressConfigFlag = 1 << 7; 667 static constexpr uint8_t kOtherConfigFlag = 1 << 6; 668 static constexpr uint8_t kPreferenceOffset = 3; 669 static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset; 670 671 uint8_t mType; 672 uint8_t mCode; 673 uint16_t mChecksum; 674 uint8_t mCurHopLimit; 675 uint8_t mFlags; 676 uint16_t mRouterLifetime; 677 uint32_t mReachableTime; 678 uint32_t mRetransTimer; 679 } OT_TOOL_PACKED_END; 680 681 static_assert(sizeof(Header) == 16, "Invalid RA `Header`"); 682 683 typedef Data<kWithUint16Length> Icmp6Packet; ///< A data buffer containing an ICMPv6 packet. 684 685 /** 686 * Represents a received RA message. 687 * 688 */ 689 class RxMessage 690 { 691 public: 692 /** 693 * Initializes the RA message from a received packet data buffer. 694 * 695 * @param[in] aPacket A received packet data. 696 * 697 */ RxMessage(const Icmp6Packet & aPacket)698 explicit RxMessage(const Icmp6Packet &aPacket) 699 : mData(aPacket) 700 { 701 } 702 703 /** 704 * Gets the RA message as an `Icmp6Packet`. 705 * 706 * @returns The RA message as an `Icmp6Packet`. 707 * 708 */ GetAsPacket(void) const709 const Icmp6Packet &GetAsPacket(void) const { return mData; } 710 711 /** 712 * Indicates whether or not the received RA message is valid. 713 * 714 * @retval TRUE If the RA message is valid. 715 * @retval FALSE If the RA message is not valid. 716 * 717 */ IsValid(void) const718 bool IsValid(void) const 719 { 720 return (mData.GetBytes() != nullptr) && (mData.GetLength() >= sizeof(Header)) && 721 (GetHeader().GetType() == Icmp::Header::kTypeRouterAdvert); 722 } 723 724 /** 725 * Gets the RA message's header. 726 * 727 * @returns The RA message's header. 728 * 729 */ GetHeader(void) const730 const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); } 731 732 /** 733 * Indicates whether or not the received RA message contains any options. 734 * 735 * @retval TRUE If the RA message contains at least one option. 736 * @retval FALSE If the RA message contains no options. 737 * 738 */ ContainsAnyOptions(void) const739 bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); } 740 741 /** 742 * Returns pointer to the start of option bytes (after header). 743 * 744 * @returns Pointer to start of options. 745 * 746 */ GetOptionStart(void) const747 const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); } 748 749 /** 750 * Gets the length (number of bytes) of options. 751 * 752 * @returns Number of bytes after header specifying RA options. 753 * 754 */ GetOptionLength(void) const755 uint16_t GetOptionLength(void) const { return ContainsAnyOptions() ? mData.GetLength() - sizeof(Header) : 0; } 756 757 // The following methods are intended to support range-based `for` 758 // loop iteration over `Option`s in the RA message. 759 begin(void) const760 Option::Iterator begin(void) const { return Option::Iterator(GetOptionStart(), GetDataEnd()); } end(void) const761 Option::Iterator end(void) const { return Option::Iterator(); } 762 763 private: GetDataEnd(void) const764 const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); } 765 766 Data<kWithUint16Length> mData; 767 }; 768 769 /** 770 * Represents an RA message to be sent. 771 * 772 */ 773 class TxMessage 774 { 775 public: 776 /** 777 * Gets the prepared RA message as an `Icmp6Packet`. 778 * 779 * @param[out] aPacket A reference to an `Icmp6Packet`. 780 * 781 */ GetAsPacket(Icmp6Packet & aPacket) const782 void GetAsPacket(Icmp6Packet &aPacket) const { aPacket.Init(mArray.AsCArray(), mArray.GetLength()); } 783 784 /** 785 * Appends the RA header. 786 * 787 * @param[in] aHeader The RA header. 788 * 789 * @retval kErrorNone Header is written successfully. 790 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 791 * 792 */ 793 Error AppendHeader(const Header &aHeader); 794 795 /** 796 * Appends a Prefix Info Option to the RA message. 797 * 798 * The appended Prefix Info Option will have both on-link (L) and autonomous address-configuration (A) flags 799 * set. 800 * 801 * @param[in] aPrefix The prefix. 802 * @param[in] aValidLifetime The valid lifetime in seconds. 803 * @param[in] aPreferredLifetime The preferred lifetime in seconds. 804 * 805 * @retval kErrorNone Option is appended successfully. 806 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 807 * 808 */ 809 Error AppendPrefixInfoOption(const Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime); 810 811 /** 812 * Appends a Route Info Option to the RA message. 813 * 814 * @param[in] aPrefix The prefix. 815 * @param[in] aRouteLifetime The route lifetime in seconds. 816 * @param[in] aPreference The route preference. 817 * 818 * @retval kErrorNone Option is appended successfully. 819 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 820 * 821 */ 822 Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference); 823 824 /** 825 * Appends a Flags Extension Option to the RA message. 826 * 827 * @param[in] aStubRouterFlag The stub router flag. 828 * 829 * @retval kErrorNone Option is appended successfully. 830 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 831 * 832 */ 833 Error AppendFlagsExtensionOption(bool aStubRouterFlag); 834 835 /** 836 * Appends bytes from a given buffer to the RA message. 837 * 838 * @param[in] aBytes A pointer to the buffer containing the bytes to append. 839 * @param[in] aLength The buffer length. 840 * 841 * @retval kErrorNone Bytes are appended successfully. 842 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 843 * 844 */ 845 Error AppendBytes(const uint8_t *aBytes, uint16_t aLength); 846 847 /** 848 * Indicates whether or not the received RA message contains any options. 849 * 850 * @retval TRUE If the RA message contains at least one option. 851 * @retval FALSE If the RA message contains no options. 852 * 853 */ ContainsAnyOptions(void) const854 bool ContainsAnyOptions(void) const { return (mArray.GetLength() > sizeof(Header)); } 855 856 private: 857 static constexpr uint16_t kCapacityIncrement = 256; 858 859 Option *AppendOption(uint16_t aOptionSize); 860 861 Heap::Array<uint8_t, kCapacityIncrement> mArray; 862 }; 863 864 RouterAdvert(void) = delete; 865 }; 866 867 /** 868 * Implements the Router Solicitation message. 869 * 870 * See section 4.1 of RFC 4861 for definition of this message. 871 * https://tools.ietf.org/html/rfc4861#section-4.1 872 * 873 */ 874 OT_TOOL_PACKED_BEGIN 875 class RouterSolicitMessage 876 { 877 public: 878 /** 879 * Initializes the Router Solicitation message. 880 * 881 */ 882 RouterSolicitMessage(void); 883 884 private: 885 Icmp::Header mHeader; // The common ICMPv6 header. 886 } OT_TOOL_PACKED_END; 887 888 static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure"); 889 890 /** 891 * Represents a Neighbor Solicitation (NS) message. 892 * 893 */ 894 OT_TOOL_PACKED_BEGIN 895 class NeighborSolicitMessage : public Clearable<NeighborSolicitMessage> 896 { 897 public: 898 /** 899 * Initializes the Neighbor Solicitation message. 900 * 901 */ 902 NeighborSolicitMessage(void); 903 904 /** 905 * Indicates whether the Neighbor Solicitation message is valid (proper Type and Code). 906 * 907 * @retval TRUE If the message is valid. 908 * @retval FALSE If the message is not valid. 909 * 910 */ IsValid(void) const911 bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborSolicit) && (mCode == 0); } 912 913 /** 914 * Gets the Target Address field. 915 * 916 * @returns The Target Address. 917 * 918 */ GetTargetAddress(void) const919 const Address &GetTargetAddress(void) const { return mTargetAddress; } 920 921 /** 922 * Sets the Target Address field. 923 * 924 * @param[in] aTargetAddress The Target Address. 925 * 926 */ SetTargetAddress(const Address & aTargetAddress)927 void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; } 928 929 private: 930 // Neighbor Solicitation Message (RFC 4861) 931 // 932 // 0 1 2 3 933 // 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 934 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 935 // | Type | Code | Checksum | 936 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 937 // | Reserved | 938 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 939 // | | 940 // + + 941 // | | 942 // + Target Address + 943 // | | 944 // + + 945 // | | 946 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 947 // | Options ... 948 // +-+-+-+-+-+-+-+-+-+-+-+- 949 950 uint8_t mType; 951 uint8_t mCode; 952 uint16_t mChecksum; 953 uint32_t mReserved; 954 Address mTargetAddress; 955 } OT_TOOL_PACKED_END; 956 957 static_assert(sizeof(NeighborSolicitMessage) == 24, "Invalid NeighborSolicitMessage definition"); 958 959 /** 960 * Represents a Neighbor Advertisement (NA) message. 961 * 962 */ 963 OT_TOOL_PACKED_BEGIN 964 class NeighborAdvertMessage : public Clearable<NeighborAdvertMessage> 965 { 966 public: 967 NeighborAdvertMessage(void); 968 969 /** 970 * Indicates whether the Neighbor Advertisement message is valid (proper Type and Code). 971 * 972 * @retval TRUE If the message is valid. 973 * @retval FALSE If the message is not valid. 974 * 975 */ IsValid(void) const976 bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborAdvert) && (mCode == 0); } 977 978 /** 979 * Indicates whether or not the Router Flag is set in the NA message. 980 * 981 * @retval TRUE The Router Flag is set. 982 * @retval FALSE The Router Flag is not set. 983 * 984 */ IsRouterFlagSet(void) const985 bool IsRouterFlagSet(void) const { return (mFlags & kRouterFlag) != 0; } 986 987 /** 988 * Sets the Router Flag in the NA message. 989 * 990 */ SetRouterFlag(void)991 void SetRouterFlag(void) { mFlags |= kRouterFlag; } 992 993 /** 994 * Indicates whether or not the Solicited Flag is set in the NA message. 995 * 996 * @retval TRUE The Solicited Flag is set. 997 * @retval FALSE The Solicited Flag is not set. 998 * 999 */ IsSolicitedFlagSet(void) const1000 bool IsSolicitedFlagSet(void) const { return (mFlags & kSolicitedFlag) != 0; } 1001 1002 /** 1003 * Sets the Solicited Flag in the NA message. 1004 * 1005 */ SetSolicitedFlag(void)1006 void SetSolicitedFlag(void) { mFlags |= kSolicitedFlag; } 1007 1008 /** 1009 * Indicates whether or not the Override Flag is set in the NA message. 1010 * 1011 * @retval TRUE The Override Flag is set. 1012 * @retval FALSE The Override Flag is not set. 1013 * 1014 */ IsOverrideFlagSet(void) const1015 bool IsOverrideFlagSet(void) const { return (mFlags & kOverrideFlag) != 0; } 1016 1017 /** 1018 * Sets the Override Flag in the NA message. 1019 * 1020 */ SetOverrideFlag(void)1021 void SetOverrideFlag(void) { mFlags |= kOverrideFlag; } 1022 1023 /** 1024 * Gets the Target Address field. 1025 * 1026 * @returns The Target Address. 1027 * 1028 */ GetTargetAddress(void) const1029 const Address &GetTargetAddress(void) const { return mTargetAddress; } 1030 1031 /** 1032 * Sets the Target Address field. 1033 * 1034 * @param[in] aTargetAddress The Target Address. 1035 * 1036 */ SetTargetAddress(const Address & aTargetAddress)1037 void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; } 1038 1039 private: 1040 // Neighbor Advertisement Message (RFC 4861) 1041 // 1042 // 0 1 2 3 1043 // 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 1044 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1045 // | Type | Code | Checksum | 1046 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1047 // |R|S|O| Reserved | 1048 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1049 // | | 1050 // + + 1051 // | | 1052 // + Target Address + 1053 // | | 1054 // + + 1055 // | | 1056 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1057 // | Options ... 1058 // +-+-+-+-+-+-+-+-+-+-+-+- 1059 1060 static constexpr uint8_t kRouterFlag = (1 << 7); 1061 static constexpr uint8_t kSolicitedFlag = (1 << 6); 1062 static constexpr uint8_t kOverrideFlag = (1 << 5); 1063 1064 uint8_t mType; 1065 uint8_t mCode; 1066 uint16_t mChecksum; 1067 uint8_t mFlags; 1068 uint8_t mReserved[3]; 1069 Address mTargetAddress; 1070 } OT_TOOL_PACKED_END; 1071 1072 static_assert(sizeof(NeighborAdvertMessage) == 24, "Invalid NeighborAdvertMessage definition"); 1073 1074 } // namespace Nd 1075 } // namespace Ip6 1076 } // namespace ot 1077 1078 #endif // ND6_HPP_ 1079