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