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>, private 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 * Sets the RA message to default values. 556 * 557 */ 558 void SetToDefault(void); 559 560 /** 561 * Sets the checksum value. 562 * 563 * @param[in] aChecksum The checksum value. 564 * 565 */ SetChecksum(uint16_t aChecksum)566 void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); } 567 568 /** 569 * Sets the Router Lifetime in seconds. 570 * 571 * @param[in] aRouterLifetime The router lifetime in seconds. 572 * 573 */ SetRouterLifetime(uint16_t aRouterLifetime)574 void SetRouterLifetime(uint16_t aRouterLifetime) { mRouterLifetime = BigEndian::HostSwap16(aRouterLifetime); } 575 576 /** 577 * Gets the Router Lifetime (in seconds). 578 * 579 * Router Lifetime set to zero indicates that the sender is not a default router. 580 * 581 * @returns The router lifetime in seconds. 582 * 583 */ GetRouterLifetime(void) const584 uint16_t GetRouterLifetime(void) const { return BigEndian::HostSwap16(mRouterLifetime); } 585 586 /** 587 * Sets the default router preference. 588 * 589 * @param[in] aPreference The router preference. 590 * 591 */ 592 void SetDefaultRouterPreference(RoutePreference aPreference); 593 594 /** 595 * Gets the default router preference. 596 * 597 * @returns The router preference. 598 * 599 */ 600 RoutePreference GetDefaultRouterPreference(void) const; 601 602 /** 603 * Indicates whether or not the Managed Address Config Flag is set in the RA message header. 604 * 605 * @retval TRUE The Managed Address Config Flag is set. 606 * @retval FALSE The Managed Address Config Flag is not set. 607 * 608 */ IsManagedAddressConfigFlagSet(void) const609 bool IsManagedAddressConfigFlagSet(void) const { return (mFlags & kManagedAddressConfigFlag) != 0; } 610 611 /** 612 * Sets the Managed Address Config Flag in the RA message. 613 * 614 */ SetManagedAddressConfigFlag(void)615 void SetManagedAddressConfigFlag(void) { mFlags |= kManagedAddressConfigFlag; } 616 617 /** 618 * Indicates whether or not the Other Config Flag is set in the RA message header. 619 * 620 * @retval TRUE The Other Config Flag is set. 621 * @retval FALSE The Other Config Flag is not set. 622 * 623 */ IsOtherConfigFlagSet(void) const624 bool IsOtherConfigFlagSet(void) const { return (mFlags & kOtherConfigFlag) != 0; } 625 626 /** 627 * Sets the Other Config Flag in the RA message. 628 * 629 */ SetOtherConfigFlag(void)630 void SetOtherConfigFlag(void) { mFlags |= kOtherConfigFlag; } 631 632 /** 633 * This method returns the ICMPv6 message type. 634 * 635 * @returns The ICMPv6 message type. 636 * 637 */ GetType(void) const638 Icmp::Header::Type GetType(void) const { return static_cast<Icmp::Header::Type>(mType); } 639 640 private: 641 // Router Advertisement Message 642 // 643 // 0 1 2 3 644 // 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 645 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 646 // | Type | Code | Checksum | 647 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 648 // | Cur Hop Limit |M|O| |Prf| | Router Lifetime | 649 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 650 // | Reachable Time | 651 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 652 // | Retrans Timer | 653 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 654 // | Options ... 655 // +-+-+-+-+-+-+-+-+-+-+-+- 656 657 static constexpr uint8_t kManagedAddressConfigFlag = 1 << 7; 658 static constexpr uint8_t kOtherConfigFlag = 1 << 6; 659 static constexpr uint8_t kPreferenceOffset = 3; 660 static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset; 661 662 uint8_t mType; 663 uint8_t mCode; 664 uint16_t mChecksum; 665 uint8_t mCurHopLimit; 666 uint8_t mFlags; 667 uint16_t mRouterLifetime; 668 uint32_t mReachableTime; 669 uint32_t mRetransTimer; 670 } OT_TOOL_PACKED_END; 671 672 static_assert(sizeof(Header) == 16, "Invalid RA `Header`"); 673 674 typedef Data<kWithUint16Length> Icmp6Packet; ///< A data buffer containing an ICMPv6 packet. 675 676 /** 677 * Represents a received RA message. 678 * 679 */ 680 class RxMessage 681 { 682 public: 683 /** 684 * Initializes the RA message from a received packet data buffer. 685 * 686 * @param[in] aPacket A received packet data. 687 * 688 */ RxMessage(const Icmp6Packet & aPacket)689 explicit RxMessage(const Icmp6Packet &aPacket) 690 : mData(aPacket) 691 { 692 } 693 694 /** 695 * Gets the RA message as an `Icmp6Packet`. 696 * 697 * @returns The RA message as an `Icmp6Packet`. 698 * 699 */ GetAsPacket(void) const700 const Icmp6Packet &GetAsPacket(void) const { return mData; } 701 702 /** 703 * Indicates whether or not the received RA message is valid. 704 * 705 * @retval TRUE If the RA message is valid. 706 * @retval FALSE If the RA message is not valid. 707 * 708 */ IsValid(void) const709 bool IsValid(void) const 710 { 711 return (mData.GetBytes() != nullptr) && (mData.GetLength() >= sizeof(Header)) && 712 (GetHeader().GetType() == Icmp::Header::kTypeRouterAdvert); 713 } 714 715 /** 716 * Gets the RA message's header. 717 * 718 * @returns The RA message's header. 719 * 720 */ GetHeader(void) const721 const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); } 722 723 /** 724 * Indicates whether or not the received RA message contains any options. 725 * 726 * @retval TRUE If the RA message contains at least one option. 727 * @retval FALSE If the RA message contains no options. 728 * 729 */ ContainsAnyOptions(void) const730 bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); } 731 732 // The following methods are intended to support range-based `for` 733 // loop iteration over `Option`s in the RA message. 734 begin(void) const735 Option::Iterator begin(void) const { return Option::Iterator(GetOptionStart(), GetDataEnd()); } end(void) const736 Option::Iterator end(void) const { return Option::Iterator(); } 737 738 private: GetOptionStart(void) const739 const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); } GetDataEnd(void) const740 const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); } 741 742 Data<kWithUint16Length> mData; 743 }; 744 745 /** 746 * Represents an RA message to be sent. 747 * 748 */ 749 class TxMessage 750 { 751 public: 752 /** 753 * Gets the prepared RA message as an `Icmp6Packet`. 754 * 755 * @param[out] aPacket A reference to an `Icmp6Packet`. 756 * 757 */ GetAsPacket(Icmp6Packet & aPacket) const758 void GetAsPacket(Icmp6Packet &aPacket) const { aPacket.Init(mArray.AsCArray(), mArray.GetLength()); } 759 760 /** 761 * Appends the RA header. 762 * 763 * @param[in] aHeader The RA header. 764 * 765 * @retval kErrorNone Header is written successfully. 766 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 767 * 768 */ 769 Error AppendHeader(const Header &aHeader); 770 771 /** 772 * Appends a Prefix Info Option to the RA message. 773 * 774 * The appended Prefix Info Option will have both on-link (L) and autonomous address-configuration (A) flags 775 * set. 776 * 777 * @param[in] aPrefix The prefix. 778 * @param[in] aValidLifetime The valid lifetime in seconds. 779 * @param[in] aPreferredLifetime The preferred lifetime in seconds. 780 * 781 * @retval kErrorNone Option is appended successfully. 782 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 783 * 784 */ 785 Error AppendPrefixInfoOption(const Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime); 786 787 /** 788 * Appends a Route Info Option to the RA message. 789 * 790 * @param[in] aPrefix The prefix. 791 * @param[in] aRouteLifetime The route lifetime in seconds. 792 * @param[in] aPreference The route preference. 793 * 794 * @retval kErrorNone Option is appended successfully. 795 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 796 * 797 */ 798 Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference); 799 800 /** 801 * Appends a Flags Extension Option to the RA message. 802 * 803 * @param[in] aStubRouterFlag The stub router flag. 804 * 805 * @retval kErrorNone Option is appended successfully. 806 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 807 * 808 */ 809 Error AppendFlagsExtensionOption(bool aStubRouterFlag); 810 811 /** 812 * Appends bytes from a given buffer to the RA message. 813 * 814 * @param[in] aBytes A pointer to the buffer containing the bytes to append. 815 * @param[in] aLength The buffer length. 816 * 817 * @retval kErrorNone Bytes are appended successfully. 818 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 819 * 820 */ 821 Error AppendBytes(const uint8_t *aBytes, uint16_t aLength); 822 823 /** 824 * Indicates whether or not the received RA message contains any options. 825 * 826 * @retval TRUE If the RA message contains at least one option. 827 * @retval FALSE If the RA message contains no options. 828 * 829 */ ContainsAnyOptions(void) const830 bool ContainsAnyOptions(void) const { return (mArray.GetLength() > sizeof(Header)); } 831 832 private: 833 static constexpr uint16_t kCapacityIncrement = 256; 834 835 Option *AppendOption(uint16_t aOptionSize); 836 837 Heap::Array<uint8_t, kCapacityIncrement> mArray; 838 }; 839 840 RouterAdvert(void) = delete; 841 }; 842 843 /** 844 * Implements the Router Solicitation message. 845 * 846 * See section 4.1 of RFC 4861 for definition of this message. 847 * https://tools.ietf.org/html/rfc4861#section-4.1 848 * 849 */ 850 OT_TOOL_PACKED_BEGIN 851 class RouterSolicitMessage 852 { 853 public: 854 /** 855 * Initializes the Router Solicitation message. 856 * 857 */ 858 RouterSolicitMessage(void); 859 860 private: 861 Icmp::Header mHeader; // The common ICMPv6 header. 862 } OT_TOOL_PACKED_END; 863 864 static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure"); 865 866 /** 867 * Represents a Neighbor Solicitation (NS) message. 868 * 869 */ 870 OT_TOOL_PACKED_BEGIN 871 class NeighborSolicitMessage : public Clearable<NeighborSolicitMessage> 872 { 873 public: 874 /** 875 * Initializes the Neighbor Solicitation message. 876 * 877 */ 878 NeighborSolicitMessage(void); 879 880 /** 881 * Indicates whether the Neighbor Solicitation message is valid (proper Type and Code). 882 * 883 * @retval TRUE If the message is valid. 884 * @retval FALSE If the message is not valid. 885 * 886 */ IsValid(void) const887 bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborSolicit) && (mCode == 0); } 888 889 /** 890 * Gets the Target Address field. 891 * 892 * @returns The Target Address. 893 * 894 */ GetTargetAddress(void) const895 const Address &GetTargetAddress(void) const { return mTargetAddress; } 896 897 /** 898 * Sets the Target Address field. 899 * 900 * @param[in] aTargetAddress The Target Address. 901 * 902 */ SetTargetAddress(const Address & aTargetAddress)903 void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; } 904 905 private: 906 // Neighbor Solicitation Message (RFC 4861) 907 // 908 // 0 1 2 3 909 // 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 910 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 911 // | Type | Code | Checksum | 912 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 913 // | Reserved | 914 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 915 // | | 916 // + + 917 // | | 918 // + Target Address + 919 // | | 920 // + + 921 // | | 922 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 923 // | Options ... 924 // +-+-+-+-+-+-+-+-+-+-+-+- 925 926 uint8_t mType; 927 uint8_t mCode; 928 uint16_t mChecksum; 929 uint32_t mReserved; 930 Address mTargetAddress; 931 } OT_TOOL_PACKED_END; 932 933 static_assert(sizeof(NeighborSolicitMessage) == 24, "Invalid NeighborSolicitMessage definition"); 934 935 /** 936 * Represents a Neighbor Advertisement (NA) message. 937 * 938 */ 939 OT_TOOL_PACKED_BEGIN 940 class NeighborAdvertMessage : public Clearable<NeighborAdvertMessage> 941 { 942 public: 943 NeighborAdvertMessage(void); 944 945 /** 946 * Indicates whether the Neighbor Advertisement message is valid (proper Type and Code). 947 * 948 * @retval TRUE If the message is valid. 949 * @retval FALSE If the message is not valid. 950 * 951 */ IsValid(void) const952 bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborAdvert) && (mCode == 0); } 953 954 /** 955 * Indicates whether or not the Router Flag is set in the NA message. 956 * 957 * @retval TRUE The Router Flag is set. 958 * @retval FALSE The Router Flag is not set. 959 * 960 */ IsRouterFlagSet(void) const961 bool IsRouterFlagSet(void) const { return (mFlags & kRouterFlag) != 0; } 962 963 /** 964 * Sets the Router Flag in the NA message. 965 * 966 */ SetRouterFlag(void)967 void SetRouterFlag(void) { mFlags |= kRouterFlag; } 968 969 /** 970 * Indicates whether or not the Solicited Flag is set in the NA message. 971 * 972 * @retval TRUE The Solicited Flag is set. 973 * @retval FALSE The Solicited Flag is not set. 974 * 975 */ IsSolicitedFlagSet(void) const976 bool IsSolicitedFlagSet(void) const { return (mFlags & kSolicitedFlag) != 0; } 977 978 /** 979 * Sets the Solicited Flag in the NA message. 980 * 981 */ SetSolicitedFlag(void)982 void SetSolicitedFlag(void) { mFlags |= kSolicitedFlag; } 983 984 /** 985 * Indicates whether or not the Override Flag is set in the NA message. 986 * 987 * @retval TRUE The Override Flag is set. 988 * @retval FALSE The Override Flag is not set. 989 * 990 */ IsOverrideFlagSet(void) const991 bool IsOverrideFlagSet(void) const { return (mFlags & kOverrideFlag) != 0; } 992 993 /** 994 * Sets the Override Flag in the NA message. 995 * 996 */ SetOverrideFlag(void)997 void SetOverrideFlag(void) { mFlags |= kOverrideFlag; } 998 999 /** 1000 * Gets the Target Address field. 1001 * 1002 * @returns The Target Address. 1003 * 1004 */ GetTargetAddress(void) const1005 const Address &GetTargetAddress(void) const { return mTargetAddress; } 1006 1007 /** 1008 * Sets the Target Address field. 1009 * 1010 * @param[in] aTargetAddress The Target Address. 1011 * 1012 */ SetTargetAddress(const Address & aTargetAddress)1013 void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; } 1014 1015 private: 1016 // Neighbor Advertisement Message (RFC 4861) 1017 // 1018 // 0 1 2 3 1019 // 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 1020 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1021 // | Type | Code | Checksum | 1022 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1023 // |R|S|O| Reserved | 1024 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1025 // | | 1026 // + + 1027 // | | 1028 // + Target Address + 1029 // | | 1030 // + + 1031 // | | 1032 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1033 // | Options ... 1034 // +-+-+-+-+-+-+-+-+-+-+-+- 1035 1036 static constexpr uint8_t kRouterFlag = (1 << 7); 1037 static constexpr uint8_t kSolicitedFlag = (1 << 6); 1038 static constexpr uint8_t kOverrideFlag = (1 << 5); 1039 1040 uint8_t mType; 1041 uint8_t mCode; 1042 uint16_t mChecksum; 1043 uint8_t mFlags; 1044 uint8_t mReserved[3]; 1045 Address mTargetAddress; 1046 } OT_TOOL_PACKED_END; 1047 1048 static_assert(sizeof(NeighborAdvertMessage) == 24, "Invalid NeighborAdvertMessage definition"); 1049 1050 } // namespace Nd 1051 } // namespace Ip6 1052 } // namespace ot 1053 1054 #endif // ND6_HPP_ 1055