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 * Default Delay Timer value for a Pending Operational Dataset (ms) 187 * 188 */ 189 static constexpr uint32_t kDefaultDelayTimer = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_DEFAULT_DELAY; 190 191 /** 192 * Defines a generic Dataset TLV to read from a message. 193 * 194 */ 195 OT_TOOL_PACKED_BEGIN 196 class DatasetTlv : public Tlv 197 { 198 public: 199 /** 200 * Reads the Dataset TLV from a given message at a given offset. 201 * 202 * @param[in] aMessage A message to read the TLV from. 203 * @param[in] aOffset An offset into the message to read from. 204 * 205 * @retval kErrorNone The TLV was read successfully. 206 * @retval kErrorParse The TLV was not well-formed and could not be parsed. 207 * 208 */ 209 Error ReadFromMessage(const Message &aMessage, uint16_t aOffset); 210 211 private: 212 uint8_t mValue[Dataset::kMaxValueSize]; 213 } OT_TOOL_PACKED_END; 214 215 /** 216 * Initializes the object. 217 * 218 * @param[in] aInstance A reference to the OpenThread instance. 219 * @param[in] aType Dataset type, Active or Pending. 220 * @param[in] aTimerHandler The registration timer handler. 221 * 222 */ 223 DatasetManager(Instance &aInstance, Dataset::Type aType, TimerMilli::Handler aTimerHandler); 224 225 /** 226 * Gets the Operational Dataset type (Active or Pending). 227 * 228 * @returns The Operational Dataset type. 229 * 230 */ GetType(void) const231 Dataset::Type GetType(void) const { return mLocal.GetType(); } 232 233 /** 234 * Clears the Operational Dataset. 235 * 236 */ 237 void Clear(void); 238 239 /** 240 * Saves the Operational Dataset in non-volatile memory. 241 * 242 * @param[in] aDataset The Operational Dataset. 243 * 244 * @retval kErrorNone Successfully applied configuration. 245 * @retval kErrorParse The dataset has at least one TLV with invalid format. 246 * 247 */ 248 Error Save(const Dataset &aDataset); 249 250 /** 251 * Saves the Operational Dataset in non-volatile memory. 252 * 253 * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. 254 * 255 * @retval kErrorNone Successfully saved the dataset. 256 * @retval kErrorNotImplemented The platform does not implement settings functionality. 257 * 258 */ 259 Error Save(const Dataset::Info &aDatasetInfo); 260 261 /** 262 * Saves the Operational Dataset in non-volatile memory. 263 * 264 * @param[in] aDataset The Operational Dataset. 265 * 266 * @retval kErrorNone Successfully saved the dataset. 267 * @retval kErrorNotImplemented The platform does not implement settings functionality. 268 * 269 */ 270 Error Save(const otOperationalDatasetTlvs &aDataset); 271 272 /** 273 * Sets the Operational Dataset for the partition. 274 * 275 * Also updates the non-volatile version if the partition's Operational Dataset is newer. 276 * 277 * @param[in] aTimestamp The timestamp for the Operational Dataset. 278 * @param[in] aMessage The message buffer. 279 * @param[in] aOffset The offset where the Operational Dataset begins. 280 * @param[in] aLength The length of the Operational Dataset. 281 * 282 * @retval kErrorNone Successfully parsed the Dataset from the @p aMessage and saved it. 283 * @retval kErrorParse Could not parse the Dataset from @p aMessage. 284 * 285 */ 286 Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength); 287 288 /** 289 * Saves the Operational Dataset in non-volatile memory. 290 * 291 * @param[in] aDataset The Operational Dataset. 292 * 293 * @retval kErrorNone Successfully applied configuration. 294 * @retval kErrorParse The dataset has at least one TLV with invalid format. 295 * 296 */ 297 Error SaveLocal(const Dataset &aDataset); 298 299 /** 300 * Handles a MGMT_GET request message. 301 * 302 * @param[in] aMessage The CoAP message buffer. 303 * @param[in] aMessageInfo The message info. 304 * 305 */ 306 void HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const; 307 308 /** 309 * Compares the partition's Operational Dataset with that stored in non-volatile memory. 310 * 311 * If the partition's Operational Dataset is newer, the non-volatile storage is updated. 312 * If the partition's Operational Dataset is older, the registration process is started. 313 * 314 */ 315 void HandleNetworkUpdate(void); 316 317 /** 318 * Initiates a network data registration message with the Leader. 319 * 320 */ 321 void HandleTimer(void); 322 323 #if OPENTHREAD_FTD 324 /** 325 * Handles the MGMT_SET request message. 326 * 327 * @param[in] aMessage The CoAP message buffer. 328 * @param[in] aMessageInfo The message info. 329 * 330 * @retval kErrorNone The MGMT_SET request message was handled successfully. 331 * @retval kErrorDrop The MGMT_SET request message was dropped. 332 * 333 */ 334 Error HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 335 #endif 336 337 DatasetLocal mLocal; 338 Timestamp mTimestamp; 339 bool mTimestampValid : 1; 340 341 private: 342 static void HandleMgmtSetResponse(void *aContext, 343 otMessage *aMessage, 344 const otMessageInfo *aMessageInfo, 345 Error aError); 346 void HandleMgmtSetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aError); 347 IsActiveDataset(void) const348 bool IsActiveDataset(void) const { return GetType() == Dataset::kActive; } IsPendingDataset(void) const349 bool IsPendingDataset(void) const { return GetType() == Dataset::kPending; } 350 void SignalDatasetChange(void) const; 351 void HandleDatasetUpdated(void); 352 Error AppendDatasetToMessage(const Dataset::Info &aDatasetInfo, Message &aMessage) const; 353 void SendSet(void); 354 void SendGetResponse(const Coap::Message &aRequest, 355 const Ip6::MessageInfo &aMessageInfo, 356 uint8_t *aTlvs, 357 uint8_t aLength) const; 358 359 #if OPENTHREAD_FTD 360 void SendSetResponse(const Coap::Message &aRequest, const Ip6::MessageInfo &aMessageInfo, StateTlv::State aState); 361 #endif 362 363 static constexpr uint8_t kMaxDatasetTlvs = 16; // Maximum number of TLVs in a Dataset. 364 static constexpr uint32_t kSendSetDelay = 5000; // Milliseconds 365 366 bool mMgmtPending : 1; 367 TimerMilli mTimer; 368 369 Callback<otDatasetMgmtSetCallback> mMgmtSetCallback; 370 }; 371 372 class ActiveDatasetManager : public DatasetManager, private NonCopyable 373 { 374 friend class Tmf::Agent; 375 376 public: 377 /** 378 * Initializes the ActiveDatasetManager object. 379 * 380 * @param[in] aInstance A reference to the OpenThread instance. 381 * 382 */ 383 explicit ActiveDatasetManager(Instance &aInstance); 384 385 /** 386 * Indicates whether the Active Dataset is partially complete. 387 * 388 * Is primarily used to determine whether a user has supplied a partial Active Dataset for use 389 * with joining a network. 390 * 391 * @retval TRUE If an Active Dataset is saved but does not include an Active Timestamp. 392 * @retval FALSE If an Active Dataset is not saved or does include an Active Timestamp. 393 * 394 */ 395 bool IsPartiallyComplete(void) const; 396 397 /** 398 * Indicates whether the Active Dataset is complete. 399 * 400 * @retval TRUE If an Active Dataset is saved and includes an Active Timestamp. 401 * @retval FALSE If an Active Dataset is not saved or does include an Active Timestamp. 402 * 403 */ 404 bool IsComplete(void) const; 405 406 /** 407 * Indicates whether or not a valid network is present in the Active Operational Dataset. 408 * 409 * @retval TRUE if a valid network is present in the Active Dataset. 410 * @retval FALSE if a valid network is not present in the Active Dataset. 411 * 412 */ 413 bool IsCommissioned(void) const; 414 415 /** 416 * Clears the Active Operational Dataset. 417 * 418 */ Clear(void)419 void Clear(void) { DatasetManager::Clear(); } 420 421 /** 422 * Saves the Operational Dataset in non-volatile memory. 423 * 424 * Also reconfigures the Thread interface. 425 * 426 * @param[in] aDataset The Operational Dataset. 427 * 428 */ Save(const Dataset & aDataset)429 void Save(const Dataset &aDataset) { IgnoreError(DatasetManager::Save(aDataset)); } 430 431 /** 432 * Sets the Operational Dataset for the partition. 433 * 434 * Also reconfigures the Thread interface. 435 * Also updates the non-volatile version if the partition's Operational Dataset is newer. 436 * 437 * @param[in] aTimestamp The timestamp for the Operational Dataset. 438 * @param[in] aMessage The message buffer. 439 * @param[in] aOffset The offset where the Operational Dataset begins. 440 * @param[in] aLength The length of the Operational Dataset. 441 * 442 * @retval kErrorNone Successfully parsed the Dataset from the @p aMessage and saved it. 443 * @retval kErrorParse Could not parse the Dataset from @p aMessage. 444 * 445 */ 446 Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength); 447 448 /** 449 * Sets the Operational Dataset in non-volatile memory. 450 * 451 * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. 452 * 453 * @retval kErrorNone Successfully saved the dataset. 454 * @retval kErrorNotImplemented The platform does not implement settings functionality. 455 * 456 */ Save(const Dataset::Info & aDatasetInfo)457 Error Save(const Dataset::Info &aDatasetInfo) { return DatasetManager::Save(aDatasetInfo); } 458 459 /** 460 * Sets the Operational Dataset in non-volatile memory. 461 * 462 * @param[in] aDataset The Operational Dataset. 463 * 464 * @retval kErrorNone Successfully saved the dataset. 465 * @retval kErrorNotImplemented The platform does not implement settings functionality. 466 * 467 */ Save(const otOperationalDatasetTlvs & aDataset)468 Error Save(const otOperationalDatasetTlvs &aDataset) { return DatasetManager::Save(aDataset); } 469 470 #if OPENTHREAD_FTD 471 472 /** 473 * Creates a new Operational Dataset to use when forming a new network. 474 * 475 * @param[out] aDatasetInfo The Operational Dataset as `Dataset::Info`. 476 * 477 * @retval kErrorNone Successfully created a new Operational Dataset. 478 * @retval kErrorFailed Failed to generate random values for new parameters. 479 * 480 */ CreateNewNetwork(Dataset::Info & aDatasetInfo)481 Error CreateNewNetwork(Dataset::Info &aDatasetInfo) { return aDatasetInfo.GenerateRandom(GetInstance()); } 482 483 /** 484 * Starts the Leader functions for maintaining the Active Operational Dataset. 485 * 486 */ 487 void StartLeader(void); 488 489 #if OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT 490 /** 491 * Generate a default Active Operational Dataset. 492 * 493 * @retval kErrorNone Successfully generated an Active Operational Dataset. 494 * @retval kErrorAlready A valid Active Operational Dataset already exists. 495 * @retval kErrorInvalidState Device is not currently attached to a network. 496 * 497 */ 498 Error GenerateLocal(void); 499 #endif 500 #endif 501 502 private: 503 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 504 505 static void HandleTimer(Timer &aTimer); HandleTimer(void)506 void HandleTimer(void) { DatasetManager::HandleTimer(); } 507 }; 508 509 DeclareTmfHandler(ActiveDatasetManager, kUriActiveGet); 510 #if OPENTHREAD_FTD 511 DeclareTmfHandler(ActiveDatasetManager, kUriActiveSet); 512 #endif 513 514 class PendingDatasetManager : public DatasetManager, private NonCopyable 515 { 516 friend class Tmf::Agent; 517 518 public: 519 /** 520 * Initializes the PendingDatasetManager object. 521 * 522 * @param[in] aInstance A reference to the OpenThread instance. 523 * 524 */ 525 explicit PendingDatasetManager(Instance &aInstance); 526 527 /** 528 * Clears the Pending Operational Dataset. 529 * 530 * Also stops the Delay Timer if it was active. 531 * 532 */ 533 void Clear(void); 534 535 /** 536 * Clears the network Pending Operational Dataset. 537 * 538 * Also stops the Delay Timer if it was active. 539 * 540 */ 541 void ClearNetwork(void); 542 543 /** 544 * Saves the Operational Dataset in non-volatile memory. 545 * 546 * Also starts the Delay Timer. 547 * 548 * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. 549 * 550 * @retval kErrorNone Successfully saved the dataset. 551 * @retval kErrorNotImplemented The platform does not implement settings functionality. 552 * 553 */ 554 Error Save(const Dataset::Info &aDatasetInfo); 555 556 /** 557 * Saves the Operational Dataset in non-volatile memory. 558 * 559 * Also starts the Delay Timer. 560 * 561 * @param[in] aDataset The Operational Dataset. 562 * 563 * @retval kErrorNone Successfully saved the dataset. 564 * @retval kErrorNotImplemented The platform does not implement settings functionality. 565 * 566 */ 567 Error Save(const otOperationalDatasetTlvs &aDataset); 568 569 /** 570 * Sets the Operational Dataset for the partition. 571 * 572 * Also updates the non-volatile version if the partition's Operational Dataset is newer. 573 * 574 * Also starts the Delay Timer. 575 * 576 * @param[in] aTimestamp The timestamp for the Operational Dataset. 577 * @param[in] aMessage The message buffer. 578 * @param[in] aOffset The offset where the Operational Dataset begins. 579 * @param[in] aLength The length of the Operational Dataset. 580 * 581 */ 582 Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength); 583 584 /** 585 * Saves the Operational Dataset in non-volatile memory. 586 * 587 * @param[in] aDataset The Operational Dataset. 588 * 589 * @retval kErrorNone Successfully applied configuration. 590 * @retval kErrorParse The dataset has at least one TLV with invalid format. 591 * 592 */ 593 Error Save(const Dataset &aDataset); 594 595 #if OPENTHREAD_FTD 596 /** 597 * Starts the Leader functions for maintaining the Active Operational Dataset. 598 * 599 */ 600 void StartLeader(void); 601 602 /** 603 * Generates a Pending Dataset from an Active Dataset. 604 * 605 * @param[in] aTimestamp The Active Dataset Timestamp. 606 * @param[in] aMessage The MGMT_SET message that contains an Active Dataset. 607 * 608 */ 609 void ApplyActiveDataset(const Timestamp &aTimestamp, Coap::Message &aMessage); 610 #endif 611 612 private: 613 void StartDelayTimer(void); 614 615 static void HandleTimer(Timer &aTimer); HandleTimer(void)616 void HandleTimer(void) { DatasetManager::HandleTimer(); } 617 618 void HandleDelayTimer(void); 619 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 620 621 using DelayTimer = TimerMilliIn<PendingDatasetManager, &PendingDatasetManager::HandleDelayTimer>; 622 623 DelayTimer mDelayTimer; 624 }; 625 626 DeclareTmfHandler(PendingDatasetManager, kUriPendingGet); 627 #if OPENTHREAD_FTD 628 DeclareTmfHandler(PendingDatasetManager, kUriPendingSet); 629 #endif 630 631 } // namespace MeshCoP 632 } // namespace ot 633 634 #endif // MESHCOP_DATASET_MANAGER_HPP_ 635