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 managing MeshCoP Datasets. 32 * 33 */ 34 35 #ifndef MESHCOP_DATASET_MANAGER_HPP_ 36 #define MESHCOP_DATASET_MANAGER_HPP_ 37 38 #include "openthread-core-config.h" 39 40 #include "common/callback.hpp" 41 #include "common/locator.hpp" 42 #include "common/non_copyable.hpp" 43 #include "common/timer.hpp" 44 #include "mac/channel_mask.hpp" 45 #include "meshcop/dataset.hpp" 46 #include "meshcop/dataset_local.hpp" 47 #include "net/udp6.hpp" 48 #include "thread/tmf.hpp" 49 50 namespace ot { 51 52 namespace MeshCoP { 53 54 class DatasetManager : public InstanceLocator 55 { 56 public: 57 /** 58 * Returns a pointer to the Timestamp. 59 * 60 * @returns A pointer to the Timestamp. 61 * 62 */ 63 const Timestamp *GetTimestamp(void) const; 64 65 /** 66 * Restores the Operational Dataset from non-volatile memory. 67 * 68 * @retval kErrorNone Successfully restore the dataset. 69 * @retval kErrorNotFound There is no corresponding dataset stored in non-volatile memory. 70 * 71 */ 72 Error Restore(void); 73 74 /** 75 * Retrieves the dataset from non-volatile memory. 76 * 77 * @param[out] aDataset Where to place the dataset. 78 * 79 * @retval kErrorNone Successfully retrieved the dataset. 80 * @retval kErrorNotFound There is no corresponding dataset stored in non-volatile memory. 81 * 82 */ Read(Dataset & aDataset) const83 Error Read(Dataset &aDataset) const { return mLocal.Read(aDataset); } 84 85 /** 86 * Retrieves the dataset from non-volatile memory. 87 * 88 * @param[out] aDatasetInfo Where to place the dataset (as `Dataset::Info`). 89 * 90 * @retval kErrorNone Successfully retrieved the dataset. 91 * @retval kErrorNotFound There is no corresponding dataset stored in non-volatile memory. 92 * 93 */ Read(Dataset::Info & aDatasetInfo) const94 Error Read(Dataset::Info &aDatasetInfo) const { return mLocal.Read(aDatasetInfo); } 95 96 /** 97 * Retrieves the dataset from non-volatile memory. 98 * 99 * @param[out] aDataset Where to place the dataset. 100 * 101 * @retval kErrorNone Successfully retrieved the dataset. 102 * @retval kErrorNotFound There is no corresponding dataset stored in non-volatile memory. 103 * 104 */ Read(otOperationalDatasetTlvs & aDataset) const105 Error Read(otOperationalDatasetTlvs &aDataset) const { return mLocal.Read(aDataset); } 106 107 /** 108 * Retrieves the channel mask from local dataset. 109 * 110 * @param[out] aChannelMask A reference to the channel mask. 111 * 112 * @retval kErrorNone Successfully retrieved the channel mask. 113 * @retval kErrorNotFound There is no valid channel mask stored in local dataset. 114 * 115 */ 116 Error GetChannelMask(Mac::ChannelMask &aChannelMask) const; 117 118 /** 119 * Applies the Active or Pending Dataset to the Thread interface. 120 * 121 * @retval kErrorNone Successfully applied configuration. 122 * @retval kErrorParse The dataset has at least one TLV with invalid format. 123 * 124 */ 125 Error ApplyConfiguration(void) const; 126 127 /** 128 * Updates the Operational Dataset when detaching from the network. 129 * 130 * On detach, the Operational Dataset is restored from non-volatile memory. 131 * 132 */ 133 void HandleDetach(void); 134 135 /** 136 * Sends a MGMT_SET request to the Leader. 137 * 138 * @param[in] aDatasetInfo The Operational Dataset. 139 * @param[in] aTlvs Any additional raw TLVs to include. 140 * @param[in] aLength Number of bytes in @p aTlvs. 141 * @param[in] aCallback A pointer to a function that is called on response reception or timeout. 142 * @param[in] aContext A pointer to application-specific context for @p aCallback. 143 * 144 * @retval kErrorNone Successfully send the meshcop dataset command. 145 * @retval kErrorNoBufs Insufficient buffer space to send. 146 * @retval kErrorBusy A previous request is ongoing. 147 * 148 */ 149 Error SendSetRequest(const Dataset::Info &aDatasetInfo, 150 const uint8_t *aTlvs, 151 uint8_t aLength, 152 otDatasetMgmtSetCallback aCallback, 153 void *aContext); 154 155 /** 156 * Sends a MGMT_GET request. 157 * 158 * @param[in] aDatasetComponents An Operational Dataset components structure specifying components to request. 159 * @param[in] aTlvTypes A pointer to array containing additional raw TLV types to be requested. 160 * @param[in] aLength Number of bytes in @p aTlvTypes. 161 * @param[in] aAddress The IPv6 destination address for the MGMT_GET request. 162 * 163 * @retval kErrorNone Successfully send the meshcop dataset command. 164 * @retval kErrorNoBufs Insufficient buffer space to send. 165 * 166 */ 167 Error SendGetRequest(const Dataset::Components &aDatasetComponents, 168 const uint8_t *aTlvTypes, 169 uint8_t aLength, 170 const otIp6Address *aAddress) const; 171 #if OPENTHREAD_FTD 172 /** 173 * Appends the MLE Dataset TLV but excluding MeshCoP Sub Timestamp TLV. 174 * 175 * @param[in] aMessage The message to append the TLV to. 176 * 177 * @retval kErrorNone Successfully append MLE Dataset TLV without MeshCoP Sub Timestamp TLV. 178 * @retval kErrorNoBufs Insufficient available buffers to append the message with MLE Dataset TLV. 179 * 180 */ 181 Error AppendMleDatasetTlv(Message &aMessage) const; 182 #endif 183 184 protected: 185 /** 186 * Defines a generic Dataset TLV to read from a message. 187 * 188 */ 189 OT_TOOL_PACKED_BEGIN 190 class DatasetTlv : public Tlv 191 { 192 public: 193 /** 194 * Reads the Dataset TLV from a given message at a given offset. 195 * 196 * @param[in] aMessage A message to read the TLV from. 197 * @param[in] aOffset An offset into the message to read from. 198 * 199 * @retval kErrorNone The TLV was read successfully. 200 * @retval kErrorParse The TLV was not well-formed and could not be parsed. 201 * 202 */ 203 Error ReadFromMessage(const Message &aMessage, uint16_t aOffset); 204 205 private: 206 uint8_t mValue[Dataset::kMaxValueSize]; 207 } OT_TOOL_PACKED_END; 208 209 /** 210 * Initializes the object. 211 * 212 * @param[in] aInstance A reference to the OpenThread instance. 213 * @param[in] aType Dataset type, Active or Pending. 214 * @param[in] aTimerHandler The registration timer handler. 215 * 216 */ 217 DatasetManager(Instance &aInstance, Dataset::Type aType, TimerMilli::Handler aTimerHandler); 218 219 /** 220 * Gets the Operational Dataset type (Active or Pending). 221 * 222 * @returns The Operational Dataset type. 223 * 224 */ GetType(void) const225 Dataset::Type GetType(void) const { return mLocal.GetType(); } 226 227 /** 228 * Clears the Operational Dataset. 229 * 230 */ 231 void Clear(void); 232 233 /** 234 * Saves the Operational Dataset in non-volatile memory. 235 * 236 * @param[in] aDataset The Operational Dataset. 237 * 238 * @retval kErrorNone Successfully applied configuration. 239 * @retval kErrorParse The dataset has at least one TLV with invalid format. 240 * 241 */ 242 Error Save(const Dataset &aDataset); 243 244 /** 245 * Saves the Operational Dataset in non-volatile memory. 246 * 247 * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. 248 * 249 * @retval kErrorNone Successfully saved the dataset. 250 * @retval kErrorNotImplemented The platform does not implement settings functionality. 251 * 252 */ 253 Error Save(const Dataset::Info &aDatasetInfo); 254 255 /** 256 * Saves the Operational Dataset in non-volatile memory. 257 * 258 * @param[in] aDataset The Operational Dataset. 259 * 260 * @retval kErrorNone Successfully saved the dataset. 261 * @retval kErrorNotImplemented The platform does not implement settings functionality. 262 * 263 */ 264 Error Save(const otOperationalDatasetTlvs &aDataset); 265 266 /** 267 * Sets the Operational Dataset for the partition. 268 * 269 * Also updates the non-volatile version if the partition's Operational Dataset is newer. 270 * 271 * @param[in] aTimestamp The timestamp for the Operational Dataset. 272 * @param[in] aMessage The message buffer. 273 * @param[in] aOffset The offset where the Operational Dataset begins. 274 * @param[in] aLength The length of the Operational Dataset. 275 * 276 * @retval kErrorNone Successfully parsed the Dataset from the @p aMessage and saved it. 277 * @retval kErrorParse Could not parse the Dataset from @p aMessage. 278 * 279 */ 280 Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength); 281 282 /** 283 * Saves the Operational Dataset in non-volatile memory. 284 * 285 * @param[in] aDataset The Operational Dataset. 286 * 287 * @retval kErrorNone Successfully applied configuration. 288 * @retval kErrorParse The dataset has at least one TLV with invalid format. 289 * 290 */ 291 Error SaveLocal(const Dataset &aDataset); 292 293 /** 294 * Handles a MGMT_GET request message. 295 * 296 * @param[in] aMessage The CoAP message buffer. 297 * @param[in] aMessageInfo The message info. 298 * 299 */ 300 void HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const; 301 302 /** 303 * Compares the partition's Operational Dataset with that stored in non-volatile memory. 304 * 305 * If the partition's Operational Dataset is newer, the non-volatile storage is updated. 306 * If the partition's Operational Dataset is older, the registration process is started. 307 * 308 */ 309 void HandleNetworkUpdate(void); 310 311 /** 312 * Initiates a network data registration message with the Leader. 313 * 314 */ 315 void HandleTimer(void); 316 317 #if OPENTHREAD_FTD 318 /** 319 * Handles the MGMT_SET request message. 320 * 321 * @param[in] aMessage The CoAP message buffer. 322 * @param[in] aMessageInfo The message info. 323 * 324 * @retval kErrorNone The MGMT_SET request message was handled successfully. 325 * @retval kErrorDrop The MGMT_SET request message was dropped. 326 * 327 */ 328 Error HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 329 #endif 330 331 DatasetLocal mLocal; 332 Timestamp mTimestamp; 333 bool mTimestampValid : 1; 334 335 private: 336 static void HandleMgmtSetResponse(void *aContext, 337 otMessage *aMessage, 338 const otMessageInfo *aMessageInfo, 339 Error aError); 340 void HandleMgmtSetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aError); 341 IsActiveDataset(void) const342 bool IsActiveDataset(void) const { return GetType() == Dataset::kActive; } IsPendingDataset(void) const343 bool IsPendingDataset(void) const { return GetType() == Dataset::kPending; } 344 void SignalDatasetChange(void) const; 345 void HandleDatasetUpdated(void); 346 Error AppendDatasetToMessage(const Dataset::Info &aDatasetInfo, Message &aMessage) const; 347 void SendSet(void); 348 void SendGetResponse(const Coap::Message &aRequest, 349 const Ip6::MessageInfo &aMessageInfo, 350 uint8_t *aTlvs, 351 uint8_t aLength) const; 352 353 #if OPENTHREAD_FTD 354 void SendSetResponse(const Coap::Message &aRequest, const Ip6::MessageInfo &aMessageInfo, StateTlv::State aState); 355 #endif 356 357 static constexpr uint8_t kMaxDatasetTlvs = 16; // Maximum number of TLVs in a Dataset. 358 static constexpr uint32_t kSendSetDelay = 5000; // Milliseconds 359 360 bool mMgmtPending : 1; 361 TimerMilli mTimer; 362 363 Callback<otDatasetMgmtSetCallback> mMgmtSetCallback; 364 }; 365 366 class ActiveDatasetManager : public DatasetManager, private NonCopyable 367 { 368 friend class Tmf::Agent; 369 370 public: 371 /** 372 * Initializes the ActiveDatasetManager object. 373 * 374 * @param[in] aInstance A reference to the OpenThread instance. 375 * 376 */ 377 explicit ActiveDatasetManager(Instance &aInstance); 378 379 /** 380 * Indicates whether the Active Dataset is partially complete. 381 * 382 * Is primarily used to determine whether a user has supplied a partial Active Dataset for use 383 * with joining a network. 384 * 385 * @retval TRUE If an Active Dataset is saved but does not include an Active Timestamp. 386 * @retval FALSE If an Active Dataset is not saved or does include an Active Timestamp. 387 * 388 */ 389 bool IsPartiallyComplete(void) const; 390 391 /** 392 * Indicates whether the Active Dataset is complete. 393 * 394 * @retval TRUE If an Active Dataset is saved and includes an Active Timestamp. 395 * @retval FALSE If an Active Dataset is not saved or does include an Active Timestamp. 396 * 397 */ 398 bool IsComplete(void) const; 399 400 /** 401 * Indicates whether or not a valid network is present in the Active Operational Dataset. 402 * 403 * @retval TRUE if a valid network is present in the Active Dataset. 404 * @retval FALSE if a valid network is not present in the Active Dataset. 405 * 406 */ 407 bool IsCommissioned(void) const; 408 409 /** 410 * Clears the Active Operational Dataset. 411 * 412 */ Clear(void)413 void Clear(void) { DatasetManager::Clear(); } 414 415 /** 416 * Saves the Operational Dataset in non-volatile memory. 417 * 418 * Also reconfigures the Thread interface. 419 * 420 * @param[in] aDataset The Operational Dataset. 421 * 422 */ Save(const Dataset & aDataset)423 void Save(const Dataset &aDataset) { IgnoreError(DatasetManager::Save(aDataset)); } 424 425 /** 426 * Sets the Operational Dataset for the partition. 427 * 428 * Also reconfigures the Thread interface. 429 * Also updates the non-volatile version if the partition's Operational Dataset is newer. 430 * 431 * @param[in] aTimestamp The timestamp for the Operational Dataset. 432 * @param[in] aMessage The message buffer. 433 * @param[in] aOffset The offset where the Operational Dataset begins. 434 * @param[in] aLength The length of the Operational Dataset. 435 * 436 * @retval kErrorNone Successfully parsed the Dataset from the @p aMessage and saved it. 437 * @retval kErrorParse Could not parse the Dataset from @p aMessage. 438 * 439 */ 440 Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength); 441 442 /** 443 * Sets the Operational Dataset in non-volatile memory. 444 * 445 * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. 446 * 447 * @retval kErrorNone Successfully saved the dataset. 448 * @retval kErrorNotImplemented The platform does not implement settings functionality. 449 * 450 */ Save(const Dataset::Info & aDatasetInfo)451 Error Save(const Dataset::Info &aDatasetInfo) { return DatasetManager::Save(aDatasetInfo); } 452 453 /** 454 * Sets the Operational Dataset in non-volatile memory. 455 * 456 * @param[in] aDataset The Operational Dataset. 457 * 458 * @retval kErrorNone Successfully saved the dataset. 459 * @retval kErrorNotImplemented The platform does not implement settings functionality. 460 * 461 */ Save(const otOperationalDatasetTlvs & aDataset)462 Error Save(const otOperationalDatasetTlvs &aDataset) { return DatasetManager::Save(aDataset); } 463 464 #if OPENTHREAD_FTD 465 466 /** 467 * Creates a new Operational Dataset to use when forming a new network. 468 * 469 * @param[out] aDatasetInfo The Operational Dataset as `Dataset::Info`. 470 * 471 * @retval kErrorNone Successfully created a new Operational Dataset. 472 * @retval kErrorFailed Failed to generate random values for new parameters. 473 * 474 */ CreateNewNetwork(Dataset::Info & aDatasetInfo)475 Error CreateNewNetwork(Dataset::Info &aDatasetInfo) { return aDatasetInfo.GenerateRandom(GetInstance()); } 476 477 /** 478 * Starts the Leader functions for maintaining the Active Operational Dataset. 479 * 480 */ 481 void StartLeader(void); 482 483 #if OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT 484 /** 485 * Generate a default Active Operational Dataset. 486 * 487 * @retval kErrorNone Successfully generated an Active Operational Dataset. 488 * @retval kErrorAlready A valid Active Operational Dataset already exists. 489 * @retval kErrorInvalidState Device is not currently attached to a network. 490 * 491 */ 492 Error GenerateLocal(void); 493 #endif 494 #endif 495 496 private: 497 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 498 499 static void HandleTimer(Timer &aTimer); HandleTimer(void)500 void HandleTimer(void) { DatasetManager::HandleTimer(); } 501 }; 502 503 DeclareTmfHandler(ActiveDatasetManager, kUriActiveGet); 504 #if OPENTHREAD_FTD 505 DeclareTmfHandler(ActiveDatasetManager, kUriActiveSet); 506 #endif 507 508 class PendingDatasetManager : public DatasetManager, private NonCopyable 509 { 510 friend class Tmf::Agent; 511 512 public: 513 /** 514 * Initializes the PendingDatasetManager object. 515 * 516 * @param[in] aInstance A reference to the OpenThread instance. 517 * 518 */ 519 explicit PendingDatasetManager(Instance &aInstance); 520 521 /** 522 * Clears the Pending Operational Dataset. 523 * 524 * Also stops the Delay Timer if it was active. 525 * 526 */ 527 void Clear(void); 528 529 /** 530 * Clears the network Pending Operational Dataset. 531 * 532 * Also stops the Delay Timer if it was active. 533 * 534 */ 535 void ClearNetwork(void); 536 537 /** 538 * Saves the Operational Dataset in non-volatile memory. 539 * 540 * Also starts the Delay Timer. 541 * 542 * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. 543 * 544 * @retval kErrorNone Successfully saved the dataset. 545 * @retval kErrorNotImplemented The platform does not implement settings functionality. 546 * 547 */ 548 Error Save(const Dataset::Info &aDatasetInfo); 549 550 /** 551 * Saves the Operational Dataset in non-volatile memory. 552 * 553 * Also starts the Delay Timer. 554 * 555 * @param[in] aDataset The Operational Dataset. 556 * 557 * @retval kErrorNone Successfully saved the dataset. 558 * @retval kErrorNotImplemented The platform does not implement settings functionality. 559 * 560 */ 561 Error Save(const otOperationalDatasetTlvs &aDataset); 562 563 /** 564 * Sets the Operational Dataset for the partition. 565 * 566 * Also updates the non-volatile version if the partition's Operational Dataset is newer. 567 * 568 * Also starts the Delay Timer. 569 * 570 * @param[in] aTimestamp The timestamp for the Operational Dataset. 571 * @param[in] aMessage The message buffer. 572 * @param[in] aOffset The offset where the Operational Dataset begins. 573 * @param[in] aLength The length of the Operational Dataset. 574 * 575 */ 576 Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength); 577 578 /** 579 * Saves the Operational Dataset in non-volatile memory. 580 * 581 * @param[in] aDataset The Operational Dataset. 582 * 583 * @retval kErrorNone Successfully applied configuration. 584 * @retval kErrorParse The dataset has at least one TLV with invalid format. 585 * 586 */ 587 Error Save(const Dataset &aDataset); 588 589 #if OPENTHREAD_FTD 590 /** 591 * Starts the Leader functions for maintaining the Active Operational Dataset. 592 * 593 */ 594 void StartLeader(void); 595 596 /** 597 * Generates a Pending Dataset from an Active Dataset. 598 * 599 * @param[in] aTimestamp The Active Dataset Timestamp. 600 * @param[in] aMessage The MGMT_SET message that contains an Active Dataset. 601 * 602 */ 603 void ApplyActiveDataset(const Timestamp &aTimestamp, Coap::Message &aMessage); 604 #endif 605 606 private: 607 void StartDelayTimer(void); 608 609 static void HandleTimer(Timer &aTimer); HandleTimer(void)610 void HandleTimer(void) { DatasetManager::HandleTimer(); } 611 612 void HandleDelayTimer(void); 613 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 614 615 using DelayTimer = TimerMilliIn<PendingDatasetManager, &PendingDatasetManager::HandleDelayTimer>; 616 617 DelayTimer mDelayTimer; 618 }; 619 620 DeclareTmfHandler(PendingDatasetManager, kUriPendingGet); 621 #if OPENTHREAD_FTD 622 DeclareTmfHandler(PendingDatasetManager, kUriPendingSet); 623 #endif 624 625 } // namespace MeshCoP 626 } // namespace ot 627 628 #endif // MESHCOP_DATASET_MANAGER_HPP_ 629