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