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