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 Router Advertisement. 32 * 33 * See RFC 4861: Neighbor Discovery for IP version 6 (https://tools.ietf.org/html/rfc4861). 34 * 35 */ 36 37 #ifndef ROUTER_ADVERTISEMENT_HPP_ 38 #define ROUTER_ADVERTISEMENT_HPP_ 39 40 #include "openthread-core-config.h" 41 42 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 43 44 #include <stdint.h> 45 46 #include <openthread/netdata.h> 47 #include <openthread/platform/toolchain.h> 48 49 #include "common/encoding.hpp" 50 #include "common/equatable.hpp" 51 #include "net/icmp6.hpp" 52 #include "net/ip6.hpp" 53 #include "thread/network_data_types.hpp" 54 55 using ot::Encoding::BigEndian::HostSwap16; 56 using ot::Encoding::BigEndian::HostSwap32; 57 58 namespace ot { 59 60 namespace BorderRouter { 61 62 namespace RouterAdv { 63 64 /** 65 * This class represents the variable length options in Neighbor 66 * Discovery messages. 67 * 68 * @sa PrefixInfoOption 69 * @sa RouteInfoOption 70 * 71 */ 72 OT_TOOL_PACKED_BEGIN 73 class Option 74 { 75 public: 76 enum class Type : uint8_t 77 { 78 kPrefixInfo = 3, ///< Prefix Information Option. 79 kRouteInfo = 24, ///< Route Information Option. 80 }; 81 82 static constexpr uint8_t kLengthUnit = 8; ///< The unit of length in octets. 83 84 /** 85 * This constructor initializes the option with given type and length. 86 * 87 * @param[in] aType The type of this option. 88 * @param[in] aLength The length of this option in unit of 8 octets. 89 * 90 */ Option(Type aType,uint8_t aLength=0)91 explicit Option(Type aType, uint8_t aLength = 0) 92 : mType(aType) 93 , mLength(aLength) 94 { 95 } 96 97 /** 98 * This method returns the type of this option. 99 * 100 * @returns The option type. 101 * 102 */ GetType(void) const103 Type GetType(void) const { return mType; } 104 105 /** 106 * This method sets the size of the option (in bytes). 107 * 108 * Since the option must end on their natural 64-bits boundaries, 109 * the actual length set to the option is padded to (aSize + 7) / 8 * 8. 110 * 111 * @param[in] aSize The size of the option in unit of 1 byte. 112 * 113 */ SetSize(uint16_t aSize)114 void SetSize(uint16_t aSize) { mLength = static_cast<uint8_t>((aSize + kLengthUnit - 1) / kLengthUnit); } 115 116 /** 117 * This method returns the size of the option (in bytes). 118 * 119 * @returns The size of the option in unit of 1 byte. 120 * 121 */ GetSize(void) const122 uint16_t GetSize(void) const { return mLength * kLengthUnit; } 123 124 /** 125 * This method sets the length of the option (in unit of 8 bytes). 126 * 127 * @param[in] aLength The length of the option in unit of 8 bytes. 128 * 129 */ SetLength(uint8_t aLength)130 void SetLength(uint8_t aLength) { mLength = aLength; } 131 132 /** 133 * This method returns the length of the option (in unit of 8 bytes). 134 * 135 * @returns The length of the option in unit of 8 bytes. 136 * 137 */ GetLength(void) const138 uint16_t GetLength(void) const { return mLength; } 139 140 /** 141 * This helper method returns a pointer to the next valid option in the buffer. 142 * 143 * @param[in] aCurOption The current option. Use nullptr to get the first option. 144 * @param[in] aBuffer The buffer within which the options are held. 145 * @param[in] aBufferLength The length of the buffer. 146 * 147 * @returns A pointer to the next option if there are a valid one. Otherwise, nullptr. 148 * 149 */ 150 static const Option *GetNextOption(const Option *aCurOption, const uint8_t *aBuffer, uint16_t aBufferLength); 151 152 /** 153 * This method tells whether this option is valid. 154 * 155 * @return A boolean that indicates whether this option is valid. 156 * 157 */ IsValid(void) const158 bool IsValid(void) const { return mLength > 0; } 159 160 private: 161 Type mType; // Type of the option. 162 uint8_t mLength; // Length of the option in unit of 8 octets, 163 // including the `type` and `length` fields. 164 } OT_TOOL_PACKED_END; 165 166 /** 167 * This class represents the Prefix Information Option. 168 * 169 * See section 4.6.2 of RFC 4861 for definition of this option. 170 * https://tools.ietf.org/html/rfc4861#section-4.6.2 171 * 172 */ 173 OT_TOOL_PACKED_BEGIN 174 class PrefixInfoOption : public Option 175 { 176 public: 177 /** 178 * This constructor initializes this option with zero prefix 179 * length, valid lifetime and preferred lifetime. 180 * 181 */ 182 PrefixInfoOption(void); 183 184 /** 185 * This method returns the on-link flag. 186 * 187 * @returns A boolean which indicates whether the on-link flag is set. 188 * 189 */ GetOnLink(void) const190 bool GetOnLink(void) const { return (mReserved1 & kOnLinkFlagMask) != 0; } 191 192 /** 193 * This method sets the on-link (L) flag. 194 * 195 * @param[in] aOnLink A boolean indicates whether the prefix is on-link or off-link. 196 * 197 */ 198 void SetOnLink(bool aOnLink); 199 200 /** 201 * This method returns the autonomous address-configuration (A) flag. 202 * 203 * @returns A boolean which indicates whether the A flag is set. 204 * 205 */ GetAutoAddrConfig(void) const206 bool GetAutoAddrConfig(void) const { return (mReserved1 & kAutoConfigFlagMask) != 0; } 207 208 /** 209 * This method sets the autonomous address-configuration (A) flag. 210 * 211 * @param[in] aAutoAddrConfig A boolean indicates whether this prefix can be used 212 * for SLAAC. 213 * 214 */ 215 void SetAutoAddrConfig(bool aAutoAddrConfig); 216 217 /** 218 * This method set the valid lifetime of the prefix in seconds. 219 * 220 * @param[in] aValidLifetime The valid lifetime in seconds. 221 * 222 */ SetValidLifetime(uint32_t aValidLifetime)223 void SetValidLifetime(uint32_t aValidLifetime) { mValidLifetime = HostSwap32(aValidLifetime); } 224 225 /** 226 * THis method returns the valid lifetime of the prefix in seconds. 227 * 228 * @returns The valid lifetime in seconds. 229 * 230 */ GetValidLifetime(void) const231 uint32_t GetValidLifetime(void) const { return HostSwap32(mValidLifetime); } 232 233 /** 234 * This method sets the preferred lifetime of the prefix in seconds. 235 * 236 * @param[in] aPreferredLifetime The preferred lifetime in seconds. 237 * 238 */ SetPreferredLifetime(uint32_t aPreferredLifetime)239 void SetPreferredLifetime(uint32_t aPreferredLifetime) { mPreferredLifetime = HostSwap32(aPreferredLifetime); } 240 241 /** 242 * THis method returns the preferred lifetime of the prefix in seconds. 243 * 244 * @returns The preferred lifetime in seconds. 245 * 246 */ GetPreferredLifetime(void) const247 uint32_t GetPreferredLifetime(void) const { return HostSwap32(mPreferredLifetime); } 248 249 /** 250 * This method sets the prefix. 251 * 252 * @param[in] aPrefix The prefix contained in this option. 253 * 254 */ 255 void SetPrefix(const Ip6::Prefix &aPrefix); 256 257 /** 258 * This method returns the prefix in this option. 259 * 260 * @returns The IPv6 prefix in this option. 261 * 262 */ 263 Ip6::Prefix GetPrefix(void) const; 264 265 /** 266 * This method tells whether this option is valid. 267 * 268 * @returns A boolean indicates whether this option is valid. 269 * 270 */ IsValid(void) const271 bool IsValid(void) const 272 { 273 return (GetSize() == sizeof(*this)) && (mPrefixLength <= OT_IP6_ADDRESS_SIZE * CHAR_BIT) && 274 (GetPreferredLifetime() <= GetValidLifetime()); 275 } 276 277 private: 278 static constexpr uint8_t kAutoConfigFlagMask = 0x40; // Bit mask of the Automatic Address Configure flag. 279 static constexpr uint8_t kOnLinkFlagMask = 0x80; // Bit mask of the On-link flag. 280 281 uint8_t mPrefixLength; // The prefix length in bits. 282 uint8_t mReserved1; // The reserved field. 283 uint32_t mValidLifetime; // The valid lifetime of the prefix. 284 uint32_t mPreferredLifetime; // The preferred lifetime of the prefix. 285 uint32_t mReserved2; // The reserved field. 286 Ip6::Address mPrefix; // The prefix. 287 } OT_TOOL_PACKED_END; 288 289 static_assert(sizeof(PrefixInfoOption) == 32, "invalid PrefixInfoOption structure"); 290 291 /** 292 * This class represents the Route Information Option. 293 * 294 * See section 2.3 of RFC 4191 for definition of this option. 295 * https://tools.ietf.org/html/rfc4191#section-2.3 296 * 297 */ 298 OT_TOOL_PACKED_BEGIN 299 class RouteInfoOption : public Option 300 { 301 public: 302 /** 303 * This type represents a route preference. 304 * 305 */ 306 typedef NetworkData::RoutePreference RoutePreference; 307 308 /** 309 * This constructor initializes this option with zero prefix length. 310 * 311 */ 312 RouteInfoOption(void); 313 314 /** 315 * This method sets the route preference. 316 * 317 * @param[in] aPreference The route preference. 318 * 319 */ 320 void SetPreference(RoutePreference aPreference); 321 322 /** 323 * This method returns the route preference. 324 * 325 * @returns The route preference. 326 * 327 */ 328 RoutePreference GetPreference(void) const; 329 330 /** 331 * This method sets the lifetime of the route in seconds. 332 * 333 * @param[in] aLifetime The lifetime of the route in seconds. 334 * 335 */ SetRouteLifetime(uint32_t aLifetime)336 void SetRouteLifetime(uint32_t aLifetime) { mRouteLifetime = HostSwap32(aLifetime); } 337 338 /** 339 * This method returns Route Lifetime in seconds. 340 * 341 * @returns The Route Lifetime in seconds. 342 * 343 */ GetRouteLifetime(void) const344 uint32_t GetRouteLifetime(void) const { return HostSwap32(mRouteLifetime); } 345 346 /** 347 * This method sets the prefix. 348 * 349 * @param[in] aPrefix The prefix contained in this option. 350 * 351 */ 352 void SetPrefix(const Ip6::Prefix &aPrefix); 353 354 /** 355 * This method returns the prefix in this option. 356 * 357 * @returns The IPv6 prefix in this option. 358 * 359 */ 360 Ip6::Prefix GetPrefix(void) const; 361 362 /** 363 * This method tells whether this option is valid. 364 * 365 * @returns A boolean indicates whether this option is valid. 366 * 367 */ 368 bool IsValid(void) const; 369 370 private: 371 static constexpr uint8_t kPreferenceOffset = 3; 372 static constexpr uint8_t kPreferenceMask = 3 << kPreferenceOffset; 373 374 uint8_t mPrefixLength; // The prefix length in bits. 375 uint8_t mReserved; // The reserved field. 376 uint32_t mRouteLifetime; // The lifetime in seconds. 377 Ip6::Address mPrefix; // The prefix. 378 } OT_TOOL_PACKED_END; 379 380 static_assert(sizeof(RouteInfoOption) == 24, "invalid RouteInfoOption structure"); 381 382 /** 383 * This class implements the Router Advertisement message. 384 * 385 * See section 4.2 of RFC 4861 for definition of this message. 386 * https://tools.ietf.org/html/rfc4861#section-4.2 387 * 388 */ 389 OT_TOOL_PACKED_BEGIN 390 class RouterAdvMessage : public Unequatable<RouterAdvMessage> 391 { 392 public: 393 /** 394 * This constructor initializes the Router Advertisement message with 395 * zero router lifetime, reachable time and retransmission timer. 396 * 397 */ RouterAdvMessage(void)398 RouterAdvMessage(void) { SetToDefault(); } 399 400 /** 401 * This method sets the RA message to default values. 402 * 403 */ 404 void SetToDefault(void); 405 406 /** 407 * This method sets the checksum value. 408 * 409 * @param[in] aChecksum The checksum value. 410 * 411 */ SetChecksum(uint16_t aChecksum)412 void SetChecksum(uint16_t aChecksum) { mHeader.SetChecksum(aChecksum); } 413 414 /** 415 * This method sets the Router Lifetime in seconds. 416 * 417 * Zero Router Lifetime means we are not a default router. 418 * 419 * @param[in] aRouterLifetime The router lifetime in seconds. 420 * 421 */ SetRouterLifetime(uint16_t aRouterLifetime)422 void SetRouterLifetime(uint16_t aRouterLifetime) 423 { 424 mHeader.mData.m16[kRouteLifetimeIdx] = HostSwap16(aRouterLifetime); 425 } 426 427 /** 428 * This method returns the Router Lifetime. 429 * 430 * Zero Router Lifetime means we are not a default router. 431 * 432 * @returns The router lifetime in seconds. 433 * 434 */ GetRouterLifetime(void) const435 uint16_t GetRouterLifetime(void) const { return HostSwap16(mHeader.mData.m16[kRouteLifetimeIdx]); } 436 437 /** 438 * This method returns the Managed Address Configuration ('m') flag. 439 * 440 * @returns A boolean which indicates whether the 'm' flag is set. 441 * 442 */ GetManagedAddrConfig(void) const443 bool GetManagedAddrConfig(void) const { return (mHeader.mData.m8[kReservedIdx] & kManagedAddressConfigMask) != 0; } 444 445 /** 446 * This method overloads the assignment operator. 447 * 448 */ 449 const RouterAdvMessage &operator=(const RouterAdvMessage &aOther); 450 451 /** 452 * This method overloads operator `==` to evaluate whether or not 453 * two instances of `RouterAdvMessage` are equal. 454 * 455 * @param[in] aOther The other `RouterAdvMessage` instance to compare with. 456 * 457 * @retval TRUE If the two `RouterAdvMessage` instances are equal. 458 * @retval FALSE If the two `RouterAdvMessage` instances are not equal. 459 * 460 */ 461 bool operator==(const RouterAdvMessage &aOther) const; 462 463 private: 464 // The index of Route Lifetime in ICMPv6 Header Data. In unit of 2 octets. 465 static constexpr uint8_t kRouteLifetimeIdx = 1; 466 467 // The index of Reserved byte in ICMPv6 Header Data. In unit of 1 octet. 468 static constexpr uint8_t kReservedIdx = 1; 469 470 // The bitmask of the Managed Address Configuration ('m') flag. 471 static constexpr uint8_t kManagedAddressConfigMask = 0x80; 472 473 Ip6::Icmp::Header mHeader; // The common ICMPv6 header. 474 uint32_t mReachableTime; // The reachable time. In milliseconds. 475 uint32_t mRetransTimer; // The retransmission timer. In milliseconds. 476 } OT_TOOL_PACKED_END; 477 478 static_assert(sizeof(RouterAdvMessage) == 16, "invalid RouterAdvMessage structure"); 479 480 /** 481 * This class implements the Router Solicitation message. 482 * 483 * See section 4.1 of RFC 4861 for definition of this message. 484 * https://tools.ietf.org/html/rfc4861#section-4.1 485 * 486 */ 487 OT_TOOL_PACKED_BEGIN 488 class RouterSolicitMessage 489 { 490 public: 491 /** 492 * This constructor initializes the Router Solicitation message. 493 * 494 */ 495 RouterSolicitMessage(void); 496 497 private: 498 Ip6::Icmp::Header mHeader; // The common ICMPv6 header. 499 } OT_TOOL_PACKED_END; 500 501 static_assert(sizeof(RouterSolicitMessage) == 8, "invalid RouterSolicitMessage structure"); 502 503 } // namespace RouterAdv 504 505 } // namespace BorderRouter 506 507 } // namespace ot 508 509 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 510 511 #endif // ROUTER_ADVERTISEMENT_HPP_ 512