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 #ifndef ND6_HPP_ 37 #define ND6_HPP_ 38 39 #include "openthread-core-config.h" 40 41 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 42 43 #include <stdint.h> 44 45 #include <openthread/netdata.h> 46 #include <openthread/platform/infra_if.h> 47 #include <openthread/platform/toolchain.h> 48 49 #include "border_router/infra_if.hpp" 50 #include "common/const_cast.hpp" 51 #include "common/encoding.hpp" 52 #include "common/equatable.hpp" 53 #include "common/heap_array.hpp" 54 #include "net/icmp6.hpp" 55 #include "net/ip6.hpp" 56 #include "net/ip6_headers.hpp" 57 #include "thread/network_data_types.hpp" 58 59 namespace ot { 60 namespace Ip6 { 61 namespace Nd { 62 63 typedef NetworkData::RoutePreference RoutePreference; ///< Route Preference 64 typedef Data<kWithUint16Length> Icmp6Packet; ///< A data buffer for an ICMPv6 packet. 65 typedef otPlatInfraIfLinkLayerAddress LinkLayerAddress; ///< An infra-if link-layer address. 66 67 /** 68 * Represents the variable length options in Neighbor Discovery messages. 69 * 70 * @sa PrefixInfoOption 71 * @sa RouteInfoOption 72 */ 73 OT_TOOL_PACKED_BEGIN 74 class Option 75 { 76 friend class RouterAdvert; 77 78 public: 79 enum Type : uint8_t 80 { 81 kSourceLinkLayerAddr = 1, ///< Source Link Layer Address Option. 82 kTargetLinkLayerAddr = 2, ///< Target Link Layer Address Option. 83 kTypePrefixInfo = 3, ///< Prefix Information Option. 84 kTypeRouteInfo = 24, ///< Route Information Option. 85 kTypeRaFlagsExtension = 26, ///< RA Flags Extension Option. 86 }; 87 88 static constexpr uint16_t kLengthUnit = 8; ///< The unit of length in octets. 89 90 /** 91 * Gets the option type. 92 * 93 * @returns The option type. 94 */ GetType(void) const95 uint8_t GetType(void) const { return mType; } 96 97 /** 98 * Sets the option type. 99 * 100 * @param[in] aType The option type. 101 */ SetType(Type aType)102 void SetType(Type aType) { mType = aType; } 103 104 /** 105 * Sets the length based on a given total option size in bytes. 106 * 107 * Th option must end on a 64-bit boundary, so the length is derived as `(aSize + 7) / 8 * 8`. 108 * 109 * @param[in] aSize The size of option in bytes. 110 */ SetSize(uint16_t aSize)111 void SetSize(uint16_t aSize) { mLength = static_cast<uint8_t>(DivideAndRoundUp(aSize, kLengthUnit)); } 112 113 /** 114 * Returns the size of the option in bytes. 115 * 116 * @returns The size of the option in bytes. 117 */ GetSize(void) const118 uint16_t GetSize(void) const { return mLength * kLengthUnit; } 119 120 /** 121 * Sets the length of the option (in unit of 8 bytes). 122 * 123 * @param[in] aLength The length of the option in unit of 8 bytes. 124 */ SetLength(uint8_t aLength)125 void SetLength(uint8_t aLength) { mLength = aLength; } 126 127 /** 128 * Returns the length of the option (in unit of 8 bytes). 129 * 130 * @returns The length of the option in unit of 8 bytes. 131 */ 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 */ 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 OT_TOOL_PACKED_BEGIN 173 class PrefixInfoOption : public Option, private Clearable<PrefixInfoOption> 174 { 175 friend class Clearable<PrefixInfoOption>; 176 177 public: 178 static constexpr Type kType = kTypePrefixInfo; ///< Prefix Information Option Type. 179 180 /** 181 * Initializes the Prefix Info option with proper type and length and sets all other fields to zero. 182 */ 183 void Init(void); 184 185 /** 186 * Indicates whether or not the on-link flag is set. 187 * 188 * @retval TRUE The on-link flag is set. 189 * @retval FALSE The on-link flag is not set. 190 */ IsOnLinkFlagSet(void) const191 bool IsOnLinkFlagSet(void) const { return (mFlags & kOnLinkFlagMask) != 0; } 192 193 /** 194 * Sets the on-link (L) flag. 195 */ SetOnLinkFlag(void)196 void SetOnLinkFlag(void) { mFlags |= kOnLinkFlagMask; } 197 198 /** 199 * Clears the on-link (L) flag. 200 */ ClearOnLinkFlag(void)201 void ClearOnLinkFlag(void) { mFlags &= ~kOnLinkFlagMask; } 202 203 /** 204 * Indicates whether or not the autonomous address-configuration (A) flag is set. 205 * 206 * @retval TRUE The auto address-config flag is set. 207 * @retval FALSE The auto address-config flag is not set. 208 */ IsAutoAddrConfigFlagSet(void) const209 bool IsAutoAddrConfigFlagSet(void) const { return (mFlags & kAutoConfigFlagMask) != 0; } 210 211 /** 212 * Sets the autonomous address-configuration (A) flag. 213 */ SetAutoAddrConfigFlag(void)214 void SetAutoAddrConfigFlag(void) { mFlags |= kAutoConfigFlagMask; } 215 216 /** 217 * Clears the autonomous address-configuration (A) flag. 218 */ ClearAutoAddrConfigFlag(void)219 void ClearAutoAddrConfigFlag(void) { mFlags &= ~kAutoConfigFlagMask; } 220 221 /** 222 * Indicates whether or not the DhCPv6-PD Preferred (P) flag is set. 223 * 224 * @retval TRUE The DHCPv6-PD Preferred (P) flag is set. 225 * @retval FALSE The DHCPv6-PD Preferred (P) flag is not set. 226 */ IsDhcp6PdPreferredFlagSet(void) const227 bool IsDhcp6PdPreferredFlagSet(void) const { return (mFlags & kDhcp6PdPreferredFlagMask) != 0; } 228 229 /** 230 * Sets the valid lifetime of the prefix in seconds. 231 * 232 * @param[in] aValidLifetime The valid lifetime in seconds. 233 */ SetValidLifetime(uint32_t aValidLifetime)234 void SetValidLifetime(uint32_t aValidLifetime) { mValidLifetime = BigEndian::HostSwap32(aValidLifetime); } 235 236 /** 237 * THis method gets the valid lifetime of the prefix in seconds. 238 * 239 * @returns The valid lifetime in seconds. 240 */ GetValidLifetime(void) const241 uint32_t GetValidLifetime(void) const { return BigEndian::HostSwap32(mValidLifetime); } 242 243 /** 244 * Sets the preferred lifetime of the prefix in seconds. 245 * 246 * @param[in] aPreferredLifetime The preferred lifetime in seconds. 247 */ SetPreferredLifetime(uint32_t aPreferredLifetime)248 void SetPreferredLifetime(uint32_t aPreferredLifetime) 249 { 250 mPreferredLifetime = BigEndian::HostSwap32(aPreferredLifetime); 251 } 252 253 /** 254 * THis method returns the preferred lifetime of the prefix in seconds. 255 * 256 * @returns The preferred lifetime in seconds. 257 */ GetPreferredLifetime(void) const258 uint32_t GetPreferredLifetime(void) const { return BigEndian::HostSwap32(mPreferredLifetime); } 259 260 /** 261 * Sets the prefix. 262 * 263 * @param[in] aPrefix The prefix contained in this option. 264 */ 265 void SetPrefix(const Prefix &aPrefix); 266 267 /** 268 * Gets the prefix in this option. 269 * 270 * @param[out] aPrefix Reference to a `Prefix` to return the prefix. 271 */ 272 void GetPrefix(Prefix &aPrefix) const; 273 274 /** 275 * Indicates whether or not the option is valid. 276 * 277 * @retval TRUE The option is valid 278 * @retval FALSE The option is not valid. 279 */ 280 bool IsValid(void) const; 281 282 PrefixInfoOption(void) = delete; 283 284 private: 285 // Prefix Information Option 286 // 287 // 0 1 2 3 288 // 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 289 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 290 // | Type | Length | Prefix Length |L|A|R|P| Rsvd1 | 291 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 292 // | Valid Lifetime | 293 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 294 // | Preferred Lifetime | 295 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 296 // | Reserved2 | 297 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 298 // | | 299 // + + 300 // | | 301 // + Prefix + 302 // | | 303 // + + 304 // | | 305 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 306 // 307 // Reference for P Flag (DHCPv6-PD preferred flag): 308 // https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.ietf-6man-pio-pflag.xml 309 310 static constexpr uint8_t kOnLinkFlagMask = 0x80; // On-link - L flag. 311 static constexpr uint8_t kAutoConfigFlagMask = 0x40; // Autonomous address-configuration - A flag. 312 static constexpr uint8_t kDhcp6PdPreferredFlagMask = 0x10; // DHCPv6-PD preferred - P flag. 313 314 uint8_t mPrefixLength; // The prefix length in bits. 315 uint8_t mFlags; // The flags field. 316 uint32_t mValidLifetime; // The valid lifetime of the prefix. 317 uint32_t mPreferredLifetime; // The preferred lifetime of the prefix. 318 uint32_t mReserved2; // The reserved field. 319 Address mPrefix; // The prefix. 320 } OT_TOOL_PACKED_END; 321 322 static_assert(sizeof(PrefixInfoOption) == 32, "invalid PrefixInfoOption structure"); 323 324 /** 325 * Represents the Route Information Option. 326 * 327 * See section 2.3 of RFC 4191 for definition of this option. [https://tools.ietf.org/html/rfc4191#section-2.3] 328 */ 329 OT_TOOL_PACKED_BEGIN 330 class RouteInfoOption : public Option, private Clearable<RouteInfoOption> 331 { 332 friend class Clearable<RouteInfoOption>; 333 334 public: 335 static constexpr uint16_t kMinSize = kLengthUnit; ///< Minimum size (in bytes) of a Route Info Option 336 static constexpr Type kType = kTypeRouteInfo; ///< Route Information Option Type. 337 338 /** 339 * Initializes the option setting the type and clearing (setting to zero) all other fields. 340 */ 341 void Init(void); 342 343 /** 344 * Sets the route preference. 345 * 346 * @param[in] aPreference The route preference. 347 */ 348 void SetPreference(RoutePreference aPreference); 349 350 /** 351 * Gets the route preference. 352 * 353 * @returns The route preference. 354 */ 355 RoutePreference GetPreference(void) const; 356 357 /** 358 * Sets the lifetime of the route in seconds. 359 * 360 * @param[in] aLifetime The lifetime of the route in seconds. 361 */ SetRouteLifetime(uint32_t aLifetime)362 void SetRouteLifetime(uint32_t aLifetime) { mRouteLifetime = BigEndian::HostSwap32(aLifetime); } 363 364 /** 365 * Gets Route Lifetime in seconds. 366 * 367 * @returns The Route Lifetime in seconds. 368 */ GetRouteLifetime(void) const369 uint32_t GetRouteLifetime(void) const { return BigEndian::HostSwap32(mRouteLifetime); } 370 371 /** 372 * Sets the prefix and adjusts the option length based on the prefix length. 373 * 374 * @param[in] aPrefix The prefix contained in this option. 375 */ 376 void SetPrefix(const Prefix &aPrefix); 377 378 /** 379 * Gets the prefix in this option. 380 * 381 * @param[out] aPrefix Reference to a `Prefix` to return the prefix. 382 */ 383 void GetPrefix(Prefix &aPrefix) const; 384 385 /** 386 * Tells whether this option is valid. 387 * 388 * @returns A boolean indicates whether this option is valid. 389 */ 390 bool IsValid(void) const; 391 392 /** 393 * Calculates the minimum option length for a given prefix length. 394 * 395 * 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 396 * for a zero prefix length, 2 if the prefix length is not greater than 64, and 3 otherwise. 397 * 398 * @param[in] aPrefixLength The prefix length (in bits). 399 * 400 * @returns The option length (in unit of 8 octet) for @p aPrefixLength. 401 */ 402 static uint8_t OptionLengthForPrefix(uint8_t aPrefixLength); 403 404 /** 405 * Calculates the minimum option size (in bytes) for a given prefix length. 406 * 407 * @param[in] aPrefixLength The prefix length (in bits). 408 * 409 * @returns The option size (in bytes) for @p aPrefixLength. 410 */ OptionSizeForPrefix(uint8_t aPrefixLength)411 static uint16_t OptionSizeForPrefix(uint8_t aPrefixLength) 412 { 413 return kLengthUnit * OptionLengthForPrefix(aPrefixLength); 414 } 415 416 RouteInfoOption(void) = delete; 417 418 private: 419 // Route Information Option 420 // 421 // 0 1 2 3 422 // 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 423 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 424 // | Type | Length | Prefix Length |Resvd|Prf|Resvd| 425 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 426 // | Route Lifetime | 427 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 428 // | Prefix (Variable Length) | 429 // . . 430 // . . 431 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 432 433 static constexpr uint8_t kPreferenceOffset = 3; 434 static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset; 435 GetPrefixBytes(void)436 uint8_t *GetPrefixBytes(void) { return AsNonConst(AsConst(this)->GetPrefixBytes()); } GetPrefixBytes(void) const437 const uint8_t *GetPrefixBytes(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); } 438 439 uint8_t mPrefixLength; // The prefix length in bits. 440 uint8_t mResvdPrf; // The preference. 441 uint32_t mRouteLifetime; // The lifetime in seconds. 442 // Followed by prefix bytes (variable length). 443 444 } OT_TOOL_PACKED_END; 445 446 static_assert(sizeof(RouteInfoOption) == 8, "invalid RouteInfoOption structure"); 447 448 /** 449 * Represents an RA Flags Extension Option. 450 * 451 * See RFC-5175 [https://tools.ietf.org/html/rfc5175] 452 */ 453 OT_TOOL_PACKED_BEGIN 454 class RaFlagsExtOption : public Option, private Clearable<RaFlagsExtOption> 455 { 456 friend class Clearable<RaFlagsExtOption>; 457 458 public: 459 static constexpr Type kType = kTypeRaFlagsExtension; ///< RA Flags Extension Option type. 460 461 /** 462 * Initializes the RA Flags Extension option with proper type and length and sets all flags to zero. 463 */ 464 void Init(void); 465 466 /** 467 * Tells whether this option is valid. 468 * 469 * @returns A boolean indicates whether this option is valid. 470 */ IsValid(void) const471 bool IsValid(void) const { return GetSize() >= sizeof(*this); } 472 473 RaFlagsExtOption(void) = delete; 474 475 private: 476 // RA Flags Extension Option 477 // 478 // 0 1 2 3 479 // 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 480 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 481 // | Type | Length | Bit fields available .. 482 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 483 // ... for assignment | 484 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ . 485 486 uint8_t mFlags[6]; 487 } OT_TOOL_PACKED_END; 488 489 static_assert(sizeof(RaFlagsExtOption) == 8, "invalid RaFlagsExtOption structure"); 490 491 /** 492 * Defines the ND6 Tx Message. 493 */ 494 class TxMessage 495 { 496 public: 497 /** 498 * Gets the prepared ND6 message as an `Icmp6Packet`. 499 * 500 * @param[out] aPacket A reference to an `Icmp6Packet`. 501 */ GetAsPacket(Icmp6Packet & aPacket) const502 void GetAsPacket(Icmp6Packet &aPacket) const { aPacket.Init(mArray.AsCArray(), mArray.GetLength()); } 503 504 /** 505 * Appends bytes from a given buffer to the ND6 message. 506 * 507 * @param[in] aBytes A pointer to the buffer containing the bytes to append. 508 * @param[in] aLength The buffer length. 509 * 510 * @retval kErrorNone Bytes are appended successfully. 511 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 512 */ 513 Error AppendBytes(const uint8_t *aBytes, uint16_t aLength); 514 515 /** 516 * Appends a Source/Target Link Layer Address Option to the ND6 message. 517 * 518 * @param[in] aLinkLayerAddress The AIL Layer Address. 519 * @param[in] aType The type of Link Layer Address Option, Source or Target 520 * 521 * @retval kErrorNone Option is appended successfully. 522 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 523 */ 524 Error AppendLinkLayerOption(LinkLayerAddress &aLinkLayerAddress, Option::Type aType); 525 526 /** 527 * Appends an object to the ND6 message. 528 * 529 * @tparam ObjectType The object type to append to the message. 530 * 531 * @param[in] aObject A reference to the object to append to the message. 532 * 533 * @retval kErrorNone Successfully appended the object. 534 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 535 */ Append(const ObjectType & aObject)536 template <typename ObjectType> Error Append(const ObjectType &aObject) 537 { 538 static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer"); 539 540 return AppendBytes(reinterpret_cast<const uint8_t *>(&aObject), sizeof(ObjectType)); 541 } 542 543 protected: 544 static constexpr uint16_t kCapacityIncrement = 256; 545 546 Option *AppendOption(uint16_t aOptionSize); 547 548 Heap::Array<uint8_t, kCapacityIncrement> mArray; 549 }; 550 551 /** 552 * Defines Router Advertisement components. 553 */ 554 class RouterAdvert 555 { 556 public: 557 /** 558 * Represent an RA message header. 559 * 560 * See section 2.2 of RFC 4191 [https://datatracker.ietf.org/doc/html/rfc4191] 561 */ 562 OT_TOOL_PACKED_BEGIN 563 class Header : public Equatable<Header>, public Clearable<Header> 564 { 565 friend class Clearable<Header>; 566 567 public: 568 /** 569 * Initializes the Router Advertisement message with 570 * zero router lifetime, reachable time and retransmission timer. 571 */ Header(void)572 Header(void) { SetToDefault(); } 573 574 /** 575 * Indicates whether the header is valid by checking the type field to match Router Advertisement ICMPv6 type. 576 * 577 * @retval TRUE The header is valid. 578 * @retval FALSE The header is not valid. 579 */ IsValid(void) const580 bool IsValid(void) const { return GetType() == Icmp::Header::kTypeRouterAdvert; } 581 582 /** 583 * Sets the RA message to default values. 584 */ 585 void SetToDefault(void); 586 587 /** 588 * Sets the checksum value. 589 * 590 * @param[in] aChecksum The checksum value. 591 */ SetChecksum(uint16_t aChecksum)592 void SetChecksum(uint16_t aChecksum) { mChecksum = BigEndian::HostSwap16(aChecksum); } 593 594 /** 595 * Sets the Router Lifetime in seconds. 596 * 597 * @param[in] aRouterLifetime The router lifetime in seconds. 598 */ SetRouterLifetime(uint16_t aRouterLifetime)599 void SetRouterLifetime(uint16_t aRouterLifetime) { mRouterLifetime = BigEndian::HostSwap16(aRouterLifetime); } 600 601 /** 602 * Gets the Router Lifetime (in seconds). 603 * 604 * Router Lifetime set to zero indicates that the sender is not a default router. 605 * 606 * @returns The router lifetime in seconds. 607 */ GetRouterLifetime(void) const608 uint16_t GetRouterLifetime(void) const { return BigEndian::HostSwap16(mRouterLifetime); } 609 610 /** 611 * Sets the default router preference. 612 * 613 * @param[in] aPreference The router preference. 614 */ 615 void SetDefaultRouterPreference(RoutePreference aPreference); 616 617 /** 618 * Gets the default router preference. 619 * 620 * @returns The router preference. 621 */ 622 RoutePreference GetDefaultRouterPreference(void) const; 623 624 /** 625 * Indicates whether or not the Managed Address Config Flag is set in the RA message header. 626 * 627 * @retval TRUE The Managed Address Config Flag is set. 628 * @retval FALSE The Managed Address Config Flag is not set. 629 */ IsManagedAddressConfigFlagSet(void) const630 bool IsManagedAddressConfigFlagSet(void) const { return (mFlags & kManagedAddressConfigFlag) != 0; } 631 632 /** 633 * Sets the Managed Address Config Flag in the RA message. 634 */ SetManagedAddressConfigFlag(void)635 void SetManagedAddressConfigFlag(void) { mFlags |= kManagedAddressConfigFlag; } 636 637 /** 638 * Indicates whether or not the Other Config Flag is set in the RA message header. 639 * 640 * @retval TRUE The Other Config Flag is set. 641 * @retval FALSE The Other Config Flag is not set. 642 */ IsOtherConfigFlagSet(void) const643 bool IsOtherConfigFlagSet(void) const { return (mFlags & kOtherConfigFlag) != 0; } 644 645 /** 646 * Sets the Other Config Flag in the RA message. 647 */ SetOtherConfigFlag(void)648 void SetOtherConfigFlag(void) { mFlags |= kOtherConfigFlag; } 649 650 /** 651 * Indicates whether or not the SNAC Router Flag is set in the RA message header. 652 * 653 * @retval TRUE The SNAC Router Flag is set. 654 * @retval FALSE The SNAC Router Flag is not set. 655 */ IsSnacRouterFlagSet(void) const656 bool IsSnacRouterFlagSet(void) const { return (mFlags & kSnacRouterFlag) != 0; } 657 658 /** 659 * Sets the SNAC Router Flag in the RA message header. 660 */ SetSnacRouterFlag(void)661 void SetSnacRouterFlag(void) { mFlags |= kSnacRouterFlag; } 662 663 /** 664 * This method returns the ICMPv6 message type. 665 * 666 * @returns The ICMPv6 message type. 667 */ GetType(void) const668 Icmp::Header::Type GetType(void) const { return static_cast<Icmp::Header::Type>(mType); } 669 670 private: 671 // Router Advertisement Message 672 // 673 // 0 1 2 3 674 // 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 675 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 676 // | Type | Code | Checksum | 677 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 678 // | Cur Hop Limit |M|O| |Prf| |S| | Router Lifetime | 679 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 680 // | Reachable Time | 681 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 682 // | Retrans Timer | 683 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 684 // | Options ... 685 // +-+-+-+-+-+-+-+-+-+-+-+- 686 687 static constexpr uint8_t kManagedAddressConfigFlag = 1 << 7; 688 static constexpr uint8_t kOtherConfigFlag = 1 << 6; 689 static constexpr uint8_t kSnacRouterFlag = 1 << 1; 690 static constexpr uint8_t kPreferenceOffset = 3; 691 static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset; 692 693 uint8_t mType; 694 uint8_t mCode; 695 uint16_t mChecksum; 696 uint8_t mCurHopLimit; 697 uint8_t mFlags; 698 uint16_t mRouterLifetime; 699 uint32_t mReachableTime; 700 uint32_t mRetransTimer; 701 } OT_TOOL_PACKED_END; 702 703 static_assert(sizeof(Header) == 16, "Invalid RA `Header`"); 704 705 /** 706 * Represents a received RA message. 707 */ 708 class RxMessage 709 { 710 public: 711 /** 712 * Initializes the RA message from a received packet data buffer. 713 * 714 * @param[in] aPacket A received packet data. 715 */ RxMessage(const Icmp6Packet & aPacket)716 explicit RxMessage(const Icmp6Packet &aPacket) 717 : mData(aPacket) 718 { 719 } 720 721 /** 722 * Gets the RA message as an `Icmp6Packet`. 723 * 724 * @returns The RA message as an `Icmp6Packet`. 725 */ GetAsPacket(void) const726 const Icmp6Packet &GetAsPacket(void) const { return mData; } 727 728 /** 729 * Indicates whether or not the received RA message is valid. 730 * 731 * @retval TRUE If the RA message is valid. 732 * @retval FALSE If the RA message is not valid. 733 */ IsValid(void) const734 bool IsValid(void) const 735 { 736 return (mData.GetBytes() != nullptr) && (mData.GetLength() >= sizeof(Header)) && 737 (GetHeader().GetType() == Icmp::Header::kTypeRouterAdvert); 738 } 739 740 /** 741 * Gets the RA message's header. 742 * 743 * @returns The RA message's header. 744 */ GetHeader(void) const745 const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); } 746 747 /** 748 * Indicates whether or not the received RA message contains any options. 749 * 750 * @retval TRUE If the RA message contains at least one option. 751 * @retval FALSE If the RA message contains no options. 752 */ ContainsAnyOptions(void) const753 bool ContainsAnyOptions(void) const { return (mData.GetLength() > sizeof(Header)); } 754 755 /** 756 * Returns pointer to the start of option bytes (after header). 757 * 758 * @returns Pointer to start of options. 759 */ GetOptionStart(void) const760 const uint8_t *GetOptionStart(void) const { return (mData.GetBytes() + sizeof(Header)); } 761 762 /** 763 * Gets the length (number of bytes) of options. 764 * 765 * @returns Number of bytes after header specifying RA options. 766 */ GetOptionLength(void) const767 uint16_t GetOptionLength(void) const { return ContainsAnyOptions() ? mData.GetLength() - sizeof(Header) : 0; } 768 769 // The following methods are intended to support range-based `for` 770 // loop iteration over `Option`s in the RA message. 771 begin(void) const772 Option::Iterator begin(void) const { return Option::Iterator(GetOptionStart(), GetDataEnd()); } end(void) const773 Option::Iterator end(void) const { return Option::Iterator(); } 774 775 private: GetDataEnd(void) const776 const uint8_t *GetDataEnd(void) const { return mData.GetBytes() + mData.GetLength(); } 777 778 Data<kWithUint16Length> mData; 779 }; 780 781 /** 782 * Represents an RA message to be sent. 783 */ 784 class TxMessage : public ot::Ip6::Nd::TxMessage 785 { 786 public: 787 /** 788 * Appends a Prefix Info Option to the RA message. 789 * 790 * The appended Prefix Info Option will have both on-link (L) and autonomous address-configuration (A) flags 791 * set. 792 * 793 * @param[in] aPrefix The prefix. 794 * @param[in] aValidLifetime The valid lifetime in seconds. 795 * @param[in] aPreferredLifetime The preferred lifetime in seconds. 796 * 797 * @retval kErrorNone Option is appended successfully. 798 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 799 */ 800 Error AppendPrefixInfoOption(const Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime); 801 802 /** 803 * Appends a Route Info Option to the RA message. 804 * 805 * @param[in] aPrefix The prefix. 806 * @param[in] aRouteLifetime The route lifetime in seconds. 807 * @param[in] aPreference The route preference. 808 * 809 * @retval kErrorNone Option is appended successfully. 810 * @retval kErrorNoBufs Insufficient available buffers to grow the message. 811 */ 812 Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference); 813 814 /** 815 * Indicates whether or not the received RA message contains any options. 816 * 817 * @retval TRUE If the RA message contains at least one option. 818 * @retval FALSE If the RA message contains no options. 819 */ ContainsAnyOptions(void) const820 bool ContainsAnyOptions(void) const { return (mArray.GetLength() > sizeof(Header)); } 821 }; 822 823 RouterAdvert(void) = delete; 824 }; 825 826 /** 827 * Implements the Router Solicitation message. 828 * 829 * See section 4.1 of RFC 4861 for definition of this message. 830 * https://tools.ietf.org/html/rfc4861#section-4.1 831 */ 832 OT_TOOL_PACKED_BEGIN 833 class RouterSolicitHeader 834 { 835 public: 836 /** 837 * Initializes the Router Solicitation message. 838 */ 839 RouterSolicitHeader(void); 840 841 private: 842 Icmp::Header mHeader; // The common ICMPv6 header. 843 } OT_TOOL_PACKED_END; 844 845 static_assert(sizeof(RouterSolicitHeader) == 8, "invalid RouterSolicitHeader structure"); 846 /** 847 * Represents a Neighbor Solicitation (NS) message. 848 */ 849 OT_TOOL_PACKED_BEGIN 850 class NeighborSolicitHeader : public Clearable<NeighborSolicitHeader> 851 { 852 public: 853 /** 854 * Initializes the Neighbor Solicitation message header. 855 */ 856 NeighborSolicitHeader(void); 857 858 /** 859 * Indicates whether the Neighbor Solicitation message is valid (proper Type and Code). 860 * 861 * @retval TRUE If the message header is valid. 862 * @retval FALSE If the message header is not valid. 863 */ IsValid(void) const864 bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborSolicit) && (mCode == 0); } 865 866 /** 867 * Gets the Target Address field. 868 * 869 * @returns The Target Address. 870 */ GetTargetAddress(void) const871 const Address &GetTargetAddress(void) const { return mTargetAddress; } 872 873 /** 874 * Sets the Target Address field. 875 * 876 * @param[in] aTargetAddress The Target Address. 877 */ SetTargetAddress(const Address & aTargetAddress)878 void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; } 879 880 private: 881 // Neighbor Solicitation Message (RFC 4861) 882 // 883 // 0 1 2 3 884 // 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 885 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 886 // | Type | Code | Checksum | 887 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 888 // | Reserved | 889 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 890 // | | 891 // + + 892 // | | 893 // + Target Address + 894 // | | 895 // + + 896 // | | 897 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 898 // | Options ... 899 // +-+-+-+-+-+-+-+-+-+-+-+- 900 901 uint8_t mType; 902 uint8_t mCode; 903 uint16_t mChecksum; 904 uint32_t mReserved; 905 Address mTargetAddress; 906 } OT_TOOL_PACKED_END; 907 908 static_assert(sizeof(NeighborSolicitHeader) == 24, "Invalid NeighborSolicitHeader definition"); 909 910 /** 911 * Represents a Neighbor Advertisement (NA) message. 912 */ 913 OT_TOOL_PACKED_BEGIN 914 class NeighborAdvertMessage : public Clearable<NeighborAdvertMessage> 915 { 916 public: 917 NeighborAdvertMessage(void); 918 919 /** 920 * Indicates whether the Neighbor Advertisement message is valid (proper Type and Code). 921 * 922 * @retval TRUE If the message is valid. 923 * @retval FALSE If the message is not valid. 924 */ IsValid(void) const925 bool IsValid(void) const { return (mType == Icmp::Header::kTypeNeighborAdvert) && (mCode == 0); } 926 927 /** 928 * Indicates whether or not the Router Flag is set in the NA message. 929 * 930 * @retval TRUE The Router Flag is set. 931 * @retval FALSE The Router Flag is not set. 932 */ IsRouterFlagSet(void) const933 bool IsRouterFlagSet(void) const { return (mFlags & kRouterFlag) != 0; } 934 935 /** 936 * Sets the Router Flag in the NA message. 937 */ SetRouterFlag(void)938 void SetRouterFlag(void) { mFlags |= kRouterFlag; } 939 940 /** 941 * Indicates whether or not the Solicited Flag is set in the NA message. 942 * 943 * @retval TRUE The Solicited Flag is set. 944 * @retval FALSE The Solicited Flag is not set. 945 */ IsSolicitedFlagSet(void) const946 bool IsSolicitedFlagSet(void) const { return (mFlags & kSolicitedFlag) != 0; } 947 948 /** 949 * Sets the Solicited Flag in the NA message. 950 */ SetSolicitedFlag(void)951 void SetSolicitedFlag(void) { mFlags |= kSolicitedFlag; } 952 953 /** 954 * Indicates whether or not the Override Flag is set in the NA message. 955 * 956 * @retval TRUE The Override Flag is set. 957 * @retval FALSE The Override Flag is not set. 958 */ IsOverrideFlagSet(void) const959 bool IsOverrideFlagSet(void) const { return (mFlags & kOverrideFlag) != 0; } 960 961 /** 962 * Sets the Override Flag in the NA message. 963 */ SetOverrideFlag(void)964 void SetOverrideFlag(void) { mFlags |= kOverrideFlag; } 965 966 /** 967 * Gets the Target Address field. 968 * 969 * @returns The Target Address. 970 */ GetTargetAddress(void) const971 const Address &GetTargetAddress(void) const { return mTargetAddress; } 972 973 /** 974 * Sets the Target Address field. 975 * 976 * @param[in] aTargetAddress The Target Address. 977 */ SetTargetAddress(const Address & aTargetAddress)978 void SetTargetAddress(const Address &aTargetAddress) { mTargetAddress = aTargetAddress; } 979 980 private: 981 // Neighbor Advertisement Message (RFC 4861) 982 // 983 // 0 1 2 3 984 // 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 985 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 986 // | Type | Code | Checksum | 987 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 988 // |R|S|O| Reserved | 989 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 990 // | | 991 // + + 992 // | | 993 // + Target Address + 994 // | | 995 // + + 996 // | | 997 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 998 // | Options ... 999 // +-+-+-+-+-+-+-+-+-+-+-+- 1000 1001 static constexpr uint8_t kRouterFlag = (1 << 7); 1002 static constexpr uint8_t kSolicitedFlag = (1 << 6); 1003 static constexpr uint8_t kOverrideFlag = (1 << 5); 1004 1005 uint8_t mType; 1006 uint8_t mCode; 1007 uint16_t mChecksum; 1008 uint8_t mFlags; 1009 uint8_t mReserved[3]; 1010 Address mTargetAddress; 1011 } OT_TOOL_PACKED_END; 1012 1013 static_assert(sizeof(NeighborAdvertMessage) == 24, "Invalid NeighborAdvertMessage definition"); 1014 1015 } // namespace Nd 1016 } // namespace Ip6 1017 } // namespace ot 1018 1019 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 1020 1021 #endif // ND6_HPP_ 1022