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