1 /* 2 * Copyright (c) 2016, 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 MeshCoP. 32 * 33 */ 34 35 #ifndef MESHCOP_HPP_ 36 #define MESHCOP_HPP_ 37 38 #include "openthread-core-config.h" 39 40 #include <openthread/commissioner.h> 41 #include <openthread/instance.h> 42 #include <openthread/joiner.h> 43 44 #include "coap/coap.hpp" 45 #include "common/as_core_type.hpp" 46 #include "common/clearable.hpp" 47 #include "common/equatable.hpp" 48 #include "common/log.hpp" 49 #include "common/message.hpp" 50 #include "common/numeric_limits.hpp" 51 #include "common/string.hpp" 52 #include "mac/mac_types.hpp" 53 #include "meshcop/meshcop_tlvs.hpp" 54 55 namespace ot { 56 57 class ThreadNetif; 58 59 namespace MeshCoP { 60 61 /** 62 * Represents a Joiner PSKd. 63 * 64 */ 65 class JoinerPskd : public otJoinerPskd, public Clearable<JoinerPskd>, public Unequatable<JoinerPskd> 66 { 67 public: 68 static constexpr uint8_t kMinLength = 6; ///< Min PSKd string length (excludes null char) 69 static constexpr uint8_t kMaxLength = OT_JOINER_MAX_PSKD_LENGTH; ///< Max PSKd string length (excludes null char) 70 71 /** 72 * Indicates whether the PSKd if well-formed and valid. 73 * 74 * Per Thread specification, a Joining Device Credential is encoded as uppercase alphanumeric characters 75 * (base32-thread: 0-9, A-Z excluding I, O, Q, and Z for readability) with a minimum length of 6 such characters 76 * and a maximum length of 32 such characters. 77 * 78 * @returns TRUE if the PSKd is valid, FALSE otherwise. 79 * 80 */ IsValid(void) const81 bool IsValid(void) const { return IsPskdValid(m8); } 82 83 /** 84 * Sets the joiner PSKd from a given C string. 85 * 86 * @param[in] aPskdString A pointer to the PSKd C string array. 87 * 88 * @retval kErrorNone The PSKd was updated successfully. 89 * @retval kErrorInvalidArgs The given PSKd C string is not valid. 90 * 91 */ 92 Error SetFrom(const char *aPskdString); 93 94 /** 95 * Gets the PSKd as a null terminated C string. 96 * 97 * Must be used after the PSKd is validated, otherwise its behavior is undefined. 98 * 99 * @returns The PSKd as a C string. 100 * 101 */ GetAsCString(void) const102 const char *GetAsCString(void) const { return m8; } 103 104 /** 105 * Gets the PSKd string length. 106 * 107 * Must be used after the PSKd is validated, otherwise its behavior is undefined. 108 * 109 * @returns The PSKd string length. 110 * 111 */ GetLength(void) const112 uint8_t GetLength(void) const { return static_cast<uint8_t>(StringLength(m8, kMaxLength + 1)); } 113 114 /** 115 * Overloads operator `==` to evaluate whether or not two PSKds are equal. 116 * 117 * @param[in] aOther The other PSKd to compare with. 118 * 119 * @retval TRUE If the two are equal. 120 * @retval FALSE If the two are not equal. 121 * 122 */ 123 bool operator==(const JoinerPskd &aOther) const; 124 125 /** 126 * Indicates whether a given PSKd string if well-formed and valid. 127 * 128 * @param[in] aPskdString A pointer to a PSKd string array. 129 * 130 * @sa IsValid() 131 * 132 * @returns TRUE if @p aPskdString is valid, FALSE otherwise. 133 * 134 */ 135 static bool IsPskdValid(const char *aPskdString); 136 }; 137 138 /** 139 * Represents a Joiner Discerner. 140 * 141 */ 142 class JoinerDiscerner : public otJoinerDiscerner, public Unequatable<JoinerDiscerner> 143 { 144 friend class SteeringData; 145 146 public: 147 static constexpr uint8_t kMaxLength = OT_JOINER_MAX_DISCERNER_LENGTH; ///< Max length of a Discerner in bits. 148 149 static constexpr uint16_t kInfoStringSize = 45; ///< Size of `InfoString` to use with `ToString() 150 151 /** 152 * Defines the fixed-length `String` object returned from `ToString()`. 153 * 154 */ 155 typedef String<kInfoStringSize> InfoString; 156 157 /** 158 * Clears the Joiner Discerner. 159 * 160 */ Clear(void)161 void Clear(void) { mLength = 0; } 162 163 /** 164 * Indicates whether the Joiner Discerner is empty (no value set). 165 * 166 * @returns TRUE if empty, FALSE otherwise. 167 * 168 */ IsEmpty(void) const169 bool IsEmpty(void) const { return mLength == 0; } 170 171 /** 172 * Gets the Joiner Discerner's value. 173 * 174 * @returns The Joiner Discerner value. 175 * 176 */ GetValue(void) const177 uint64_t GetValue(void) const { return mValue; } 178 179 /** 180 * Gets the Joiner Discerner's length (in bits). 181 * 182 * @return The Joiner Discerner length. 183 * 184 */ GetLength(void) const185 uint8_t GetLength(void) const { return mLength; } 186 187 /** 188 * Indicates whether the Joiner Discerner is valid (i.e. it not empty and its length is within 189 * valid range). 190 * 191 * @returns TRUE if Joiner Discerner is valid, FALSE otherwise. 192 * 193 */ IsValid(void) const194 bool IsValid(void) const { return (0 < mLength) && (mLength <= kMaxLength); } 195 196 /** 197 * Generates a Joiner ID from the Discerner. 198 * 199 * @param[out] aJoinerId A reference to `Mac::ExtAddress` to output the generated Joiner ID. 200 * 201 */ 202 void GenerateJoinerId(Mac::ExtAddress &aJoinerId) const; 203 204 /** 205 * Indicates whether a given Joiner ID matches the Discerner. 206 * 207 * @param[in] aJoinerId A Joiner ID to match with the Discerner. 208 * 209 * @returns TRUE if the Joiner ID matches the Discerner, FALSE otherwise. 210 * 211 */ 212 bool Matches(const Mac::ExtAddress &aJoinerId) const; 213 214 /** 215 * Overloads operator `==` to evaluate whether or not two Joiner Discerner instances are equal. 216 * 217 * @param[in] aOther The other Joiner Discerner to compare with. 218 * 219 * @retval TRUE If the two are equal. 220 * @retval FALSE If the two are not equal. 221 * 222 */ 223 bool operator==(const JoinerDiscerner &aOther) const; 224 225 /** 226 * Converts the Joiner Discerner to a string. 227 * 228 * @returns An `InfoString` representation of Joiner Discerner. 229 * 230 */ 231 InfoString ToString(void) const; 232 233 private: GetMask(void) const234 uint64_t GetMask(void) const { return (static_cast<uint64_t>(1ULL) << mLength) - 1; } 235 void CopyTo(Mac::ExtAddress &aExtAddress) const; 236 }; 237 238 /** 239 * Represents Steering Data (bloom filter). 240 * 241 */ 242 class SteeringData : public otSteeringData 243 { 244 public: 245 static constexpr uint8_t kMaxLength = OT_STEERING_DATA_MAX_LENGTH; ///< Maximum Steering Data length (in bytes). 246 247 /** 248 * Represents the hash bit index values for the bloom filter calculated from a Joiner ID. 249 * 250 * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI. 251 * 252 */ 253 struct HashBitIndexes 254 { 255 static constexpr uint8_t kNumIndexes = 2; ///< Number of hash bit indexes. 256 257 uint16_t mIndex[kNumIndexes]; ///< The hash bit index array. 258 }; 259 260 /** 261 * Initializes the Steering Data and clears the bloom filter. 262 * 263 * @param[in] aLength The Steering Data length (in bytes) - MUST be smaller than or equal to `kMaxLength`. 264 * 265 */ 266 void Init(uint8_t aLength = kMaxLength); 267 268 /** 269 * Clears the bloom filter (all bits are cleared and no Joiner Id is accepted).. 270 * 271 * The Steering Data length (bloom filter length) is set to one byte with all bits cleared. 272 * 273 */ Clear(void)274 void Clear(void) { Init(1); } 275 276 /** 277 * Sets the bloom filter to permit all Joiner IDs. 278 * 279 * To permit all Joiner IDs, The Steering Data length (bloom filter length) is set to one byte with all bits set. 280 * 281 */ 282 void SetToPermitAllJoiners(void); 283 284 /** 285 * Returns the Steering Data length (in bytes). 286 * 287 * @returns The Steering Data length (in bytes). 288 * 289 */ GetLength(void) const290 uint8_t GetLength(void) const { return mLength; } 291 292 /** 293 * Gets the Steering Data buffer (bloom filter). 294 * 295 * @returns A pointer to the Steering Data buffer. 296 * 297 */ GetData(void) const298 const uint8_t *GetData(void) const { return m8; } 299 300 /** 301 * Gets the Steering Data buffer (bloom filter). 302 * 303 * @returns A pointer to the Steering Data buffer. 304 * 305 */ GetData(void)306 uint8_t *GetData(void) { return m8; } 307 308 /** 309 * Updates the bloom filter adding the given Joiner ID. 310 * 311 * @param[in] aJoinerId The Joiner ID to add to bloom filter. 312 * 313 */ 314 void UpdateBloomFilter(const Mac::ExtAddress &aJoinerId); 315 316 /** 317 * Updates the bloom filter adding a given Joiner Discerner. 318 * 319 * @param[in] aDiscerner The Joiner Discerner to add to bloom filter. 320 * 321 */ 322 void UpdateBloomFilter(const JoinerDiscerner &aDiscerner); 323 324 /** 325 * Indicates whether the bloom filter is empty (all the bits are cleared). 326 * 327 * @returns TRUE if the bloom filter is empty, FALSE otherwise. 328 * 329 */ IsEmpty(void) const330 bool IsEmpty(void) const { return DoesAllMatch(0); } 331 332 /** 333 * Indicates whether the bloom filter permits all Joiner IDs (all the bits are set). 334 * 335 * @returns TRUE if the bloom filter permits all Joiners IDs, FALSE otherwise. 336 * 337 */ PermitsAllJoiners(void) const338 bool PermitsAllJoiners(void) const { return (mLength > 0) && DoesAllMatch(kPermitAll); } 339 340 /** 341 * Indicates whether the bloom filter contains a given Joiner ID. 342 * 343 * @param[in] aJoinerId A Joiner ID. 344 * 345 * @returns TRUE if the bloom filter contains @p aJoinerId, FALSE otherwise. 346 * 347 */ 348 bool Contains(const Mac::ExtAddress &aJoinerId) const; 349 350 /** 351 * Indicates whether the bloom filter contains a given Joiner Discerner. 352 * 353 * @param[in] aDiscerner A Joiner Discerner. 354 * 355 * @returns TRUE if the bloom filter contains @p aDiscerner, FALSE otherwise. 356 * 357 */ 358 bool Contains(const JoinerDiscerner &aDiscerner) const; 359 360 /** 361 * Indicates whether the bloom filter contains the hash bit indexes (derived from a Joiner ID). 362 * 363 * @param[in] aIndexes A hash bit index structure (derived from a Joiner ID). 364 * 365 * @returns TRUE if the bloom filter contains the Joiner ID mapping to @p aIndexes, FALSE otherwise. 366 * 367 */ 368 bool Contains(const HashBitIndexes &aIndexes) const; 369 370 /** 371 * Calculates the bloom filter hash bit indexes from a given Joiner ID. 372 * 373 * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI. 374 * 375 * @param[in] aJoinerId The Joiner ID to calculate the hash bit indexes. 376 * @param[out] aIndexes A reference to a `HashBitIndexes` structure to output the calculated index values. 377 * 378 */ 379 static void CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes); 380 381 /** 382 * Calculates the bloom filter hash bit indexes from a given Joiner Discerner. 383 * 384 * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI. 385 * 386 * @param[in] aDiscerner The Joiner Discerner to calculate the hash bit indexes. 387 * @param[out] aIndexes A reference to a `HashBitIndexes` structure to output the calculated index values. 388 * 389 */ 390 static void CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, HashBitIndexes &aIndexes); 391 392 private: 393 static constexpr uint8_t kPermitAll = 0xff; 394 GetNumBits(void) const395 uint8_t GetNumBits(void) const { return (mLength * kBitsPerByte); } 396 BitIndex(uint8_t aBit) const397 uint8_t BitIndex(uint8_t aBit) const { return (mLength - 1 - (aBit / kBitsPerByte)); } BitFlag(uint8_t aBit) const398 uint8_t BitFlag(uint8_t aBit) const { return static_cast<uint8_t>(1U << (aBit % kBitsPerByte)); } 399 GetBit(uint8_t aBit) const400 bool GetBit(uint8_t aBit) const { return (m8[BitIndex(aBit)] & BitFlag(aBit)) != 0; } SetBit(uint8_t aBit)401 void SetBit(uint8_t aBit) { m8[BitIndex(aBit)] |= BitFlag(aBit); } ClearBit(uint8_t aBit)402 void ClearBit(uint8_t aBit) { m8[BitIndex(aBit)] &= ~BitFlag(aBit); } 403 404 bool DoesAllMatch(uint8_t aMatch) const; 405 void UpdateBloomFilter(const HashBitIndexes &aIndexes); 406 }; 407 408 /** 409 * Represents a Commissioning Dataset. 410 * 411 */ 412 class CommissioningDataset : public otCommissioningDataset, public Clearable<CommissioningDataset> 413 { 414 public: 415 /** 416 * Indicates whether or not the Border Router RLOC16 Locator is set in the Dataset. 417 * 418 * @returns TRUE if Border Router RLOC16 Locator is set, FALSE otherwise. 419 * 420 */ IsLocatorSet(void) const421 bool IsLocatorSet(void) const { return mIsLocatorSet; } 422 423 /** 424 * Gets the Border Router RLOC16 Locator in the Dataset. 425 * 426 * MUST be used when Locator is set in the Dataset, otherwise its behavior is undefined. 427 * 428 * @returns The Border Router RLOC16 Locator in the Dataset. 429 * 430 */ GetLocator(void) const431 uint16_t GetLocator(void) const { return mLocator; } 432 433 /** 434 * Sets the Border Router RLOCG16 Locator in the Dataset. 435 * 436 * @param[in] aLocator A Locator. 437 * 438 */ SetLocator(uint16_t aLocator)439 void SetLocator(uint16_t aLocator) 440 { 441 mIsLocatorSet = true; 442 mLocator = aLocator; 443 } 444 445 /** 446 * Indicates whether or not the Session ID is set in the Dataset. 447 * 448 * @returns TRUE if Session ID is set, FALSE otherwise. 449 * 450 */ IsSessionIdSet(void) const451 bool IsSessionIdSet(void) const { return mIsSessionIdSet; } 452 453 /** 454 * Gets the Session ID in the Dataset. 455 * 456 * MUST be used when Session ID is set in the Dataset, otherwise its behavior is undefined. 457 * 458 * @returns The Session ID in the Dataset. 459 * 460 */ GetSessionId(void) const461 uint16_t GetSessionId(void) const { return mSessionId; } 462 463 /** 464 * Sets the Session ID in the Dataset. 465 * 466 * @param[in] aSessionId The Session ID. 467 * 468 */ SetSessionId(uint16_t aSessionId)469 void SetSessionId(uint16_t aSessionId) 470 { 471 mIsSessionIdSet = true; 472 mSessionId = aSessionId; 473 } 474 475 /** 476 * Indicates whether or not the Steering Data is set in the Dataset. 477 * 478 * @returns TRUE if Steering Data is set, FALSE otherwise. 479 * 480 */ IsSteeringDataSet(void) const481 bool IsSteeringDataSet(void) const { return mIsSteeringDataSet; } 482 483 /** 484 * Gets the Steering Data in the Dataset. 485 * 486 * MUST be used when Steering Data is set in the Dataset, otherwise its behavior is undefined. 487 * 488 * @returns The Steering Data in the Dataset. 489 * 490 */ GetSteeringData(void) const491 const SteeringData &GetSteeringData(void) const { return static_cast<const SteeringData &>(mSteeringData); } 492 493 /** 494 * Returns a reference to the Steering Data in the Dataset to be updated by caller. 495 * 496 * @returns A reference to the Steering Data in the Dataset. 497 * 498 */ UpdateSteeringData(void)499 SteeringData &UpdateSteeringData(void) 500 { 501 mIsSteeringDataSet = true; 502 return static_cast<SteeringData &>(mSteeringData); 503 } 504 505 /** 506 * Indicates whether or not the Joiner UDP port is set in the Dataset. 507 * 508 * @returns TRUE if Joiner UDP port is set, FALSE otherwise. 509 * 510 */ IsJoinerUdpPortSet(void) const511 bool IsJoinerUdpPortSet(void) const { return mIsJoinerUdpPortSet; } 512 513 /** 514 * Gets the Joiner UDP port in the Dataset. 515 * 516 * MUST be used when Joiner UDP port is set in the Dataset, otherwise its behavior is undefined. 517 * 518 * @returns The Joiner UDP port in the Dataset. 519 * 520 */ GetJoinerUdpPort(void) const521 uint16_t GetJoinerUdpPort(void) const { return mJoinerUdpPort; } 522 523 /** 524 * Sets the Joiner UDP Port in the Dataset. 525 * 526 * @param[in] aJoinerUdpPort The Joiner UDP Port. 527 * 528 */ SetJoinerUdpPort(uint16_t aJoinerUdpPort)529 void SetJoinerUdpPort(uint16_t aJoinerUdpPort) 530 { 531 mIsJoinerUdpPortSet = true; 532 mJoinerUdpPort = aJoinerUdpPort; 533 } 534 }; 535 536 /** 537 * Generates PSKc. 538 * 539 * PSKc is used to establish the Commissioner Session. 540 * 541 * @param[in] aPassPhrase The commissioning passphrase. 542 * @param[in] aNetworkName The network name for PSKc computation. 543 * @param[in] aExtPanId The extended PAN ID for PSKc computation. 544 * @param[out] aPskc A reference to a PSKc where the generated PSKc will be placed. 545 * 546 * @retval kErrorNone Successfully generate PSKc. 547 * @retval kErrorInvalidArgs If the length of passphrase is out of range. 548 * 549 */ 550 Error GeneratePskc(const char *aPassPhrase, 551 const NetworkName &aNetworkName, 552 const ExtendedPanId &aExtPanId, 553 Pskc &aPskc); 554 555 /** 556 * Computes the Joiner ID from a factory-assigned IEEE EUI-64. 557 * 558 * @param[in] aEui64 The factory-assigned IEEE EUI-64. 559 * @param[out] aJoinerId The Joiner ID. 560 * 561 */ 562 void ComputeJoinerId(const Mac::ExtAddress &aEui64, Mac::ExtAddress &aJoinerId); 563 564 } // namespace MeshCoP 565 566 DefineCoreType(otJoinerPskd, MeshCoP::JoinerPskd); 567 DefineCoreType(otJoinerDiscerner, MeshCoP::JoinerDiscerner); 568 DefineCoreType(otSteeringData, MeshCoP::SteeringData); 569 DefineCoreType(otCommissioningDataset, MeshCoP::CommissioningDataset); 570 571 } // namespace ot 572 573 #endif // MESHCOP_HPP_ 574