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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This method 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 * This class 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 * This method 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 * This constructor 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 * This method 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 * This method clears the Operational Dataset. 229 * 230 */ 231 void Clear(void); 232 233 /** 234 * This method 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 * This method 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 * This method 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 * This method sets the Operational Dataset for the partition. 268 * 269 * This method 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 * This method 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 * This method 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 * This method 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 * This method initiates a network data registration message with the Leader. 313 * 314 */ 315 void HandleTimer(void); 316 317 #if OPENTHREAD_FTD 318 /** 319 * This method 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 * This constructor 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 * This method indicates whether the Active Dataset is partially complete. 381 * 382 * This method 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 * This method indicates whether or not a valid network is present in the Active Operational Dataset. 393 * 394 * @retval TRUE if a valid network is present in the Active Dataset. 395 * @retval FALSE if a valid network is not present in the Active Dataset. 396 * 397 */ 398 bool IsCommissioned(void) const; 399 400 /** 401 * This method clears the Active Operational Dataset. 402 * 403 */ Clear(void)404 void Clear(void) { DatasetManager::Clear(); } 405 406 /** 407 * This method saves the Operational Dataset in non-volatile memory. 408 * 409 * This method also reconfigures the Thread interface. 410 * 411 * @param[in] aDataset The Operational Dataset. 412 * 413 */ Save(const Dataset & aDataset)414 void Save(const Dataset &aDataset) { IgnoreError(DatasetManager::Save(aDataset)); } 415 416 /** 417 * This method sets the Operational Dataset for the partition. 418 * 419 * This method also reconfigures the Thread interface. 420 * This method also updates the non-volatile version if the partition's Operational Dataset is newer. 421 * 422 * @param[in] aTimestamp The timestamp for the Operational Dataset. 423 * @param[in] aMessage The message buffer. 424 * @param[in] aOffset The offset where the Operational Dataset begins. 425 * @param[in] aLength The length of the Operational Dataset. 426 * 427 * @retval kErrorNone Successfully parsed the Dataset from the @p aMessage and saved it. 428 * @retval kErrorParse Could not parse the Dataset from @p aMessage. 429 * 430 */ 431 Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength); 432 433 /** 434 * This method sets the Operational Dataset in non-volatile memory. 435 * 436 * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. 437 * 438 * @retval kErrorNone Successfully saved the dataset. 439 * @retval kErrorNotImplemented The platform does not implement settings functionality. 440 * 441 */ Save(const Dataset::Info & aDatasetInfo)442 Error Save(const Dataset::Info &aDatasetInfo) { return DatasetManager::Save(aDatasetInfo); } 443 444 /** 445 * This method sets the Operational Dataset in non-volatile memory. 446 * 447 * @param[in] aDataset The Operational Dataset. 448 * 449 * @retval kErrorNone Successfully saved the dataset. 450 * @retval kErrorNotImplemented The platform does not implement settings functionality. 451 * 452 */ Save(const otOperationalDatasetTlvs & aDataset)453 Error Save(const otOperationalDatasetTlvs &aDataset) { return DatasetManager::Save(aDataset); } 454 455 #if OPENTHREAD_FTD 456 457 /** 458 * This method creates a new Operational Dataset to use when forming a new network. 459 * 460 * @param[out] aDatasetInfo The Operational Dataset as `Dataset::Info`. 461 * 462 * @retval kErrorNone Successfully created a new Operational Dataset. 463 * @retval kErrorFailed Failed to generate random values for new parameters. 464 * 465 */ CreateNewNetwork(Dataset::Info & aDatasetInfo)466 Error CreateNewNetwork(Dataset::Info &aDatasetInfo) { return aDatasetInfo.GenerateRandom(GetInstance()); } 467 468 /** 469 * This method starts the Leader functions for maintaining the Active Operational Dataset. 470 * 471 */ 472 void StartLeader(void); 473 474 /** 475 * This method generate a default Active Operational Dataset. 476 * 477 * @retval kErrorNone Successfully generated an Active Operational Dataset. 478 * @retval kErrorAlready A valid Active Operational Dataset already exists. 479 * @retval kErrorInvalidState Device is not currently attached to a network. 480 * 481 */ 482 Error GenerateLocal(void); 483 #endif 484 485 private: 486 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 487 488 static void HandleTimer(Timer &aTimer); HandleTimer(void)489 void HandleTimer(void) { DatasetManager::HandleTimer(); } 490 }; 491 492 DeclareTmfHandler(ActiveDatasetManager, kUriActiveGet); 493 #if OPENTHREAD_FTD 494 DeclareTmfHandler(ActiveDatasetManager, kUriActiveSet); 495 #endif 496 497 class PendingDatasetManager : public DatasetManager, private NonCopyable 498 { 499 friend class Tmf::Agent; 500 501 public: 502 /** 503 * This constructor initializes the PendingDatasetManager object. 504 * 505 * @param[in] aInstance A reference to the OpenThread instance. 506 * 507 */ 508 explicit PendingDatasetManager(Instance &aInstance); 509 510 /** 511 * This method clears the Pending Operational Dataset. 512 * 513 * This method also stops the Delay Timer if it was active. 514 * 515 */ 516 void Clear(void); 517 518 /** 519 * This method clears the network Pending Operational Dataset. 520 * 521 * This method also stops the Delay Timer if it was active. 522 * 523 */ 524 void ClearNetwork(void); 525 526 /** 527 * This method saves the Operational Dataset in non-volatile memory. 528 * 529 * This method also starts the Delay Timer. 530 * 531 * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. 532 * 533 * @retval kErrorNone Successfully saved the dataset. 534 * @retval kErrorNotImplemented The platform does not implement settings functionality. 535 * 536 */ 537 Error Save(const Dataset::Info &aDatasetInfo); 538 539 /** 540 * This method saves the Operational Dataset in non-volatile memory. 541 * 542 * This method also starts the Delay Timer. 543 * 544 * @param[in] aDataset The Operational Dataset. 545 * 546 * @retval kErrorNone Successfully saved the dataset. 547 * @retval kErrorNotImplemented The platform does not implement settings functionality. 548 * 549 */ 550 Error Save(const otOperationalDatasetTlvs &aDataset); 551 552 /** 553 * This method sets the Operational Dataset for the partition. 554 * 555 * This method also updates the non-volatile version if the partition's Operational Dataset is newer. 556 * 557 * This method also starts the Delay Timer. 558 * 559 * @param[in] aTimestamp The timestamp for the Operational Dataset. 560 * @param[in] aMessage The message buffer. 561 * @param[in] aOffset The offset where the Operational Dataset begins. 562 * @param[in] aLength The length of the Operational Dataset. 563 * 564 */ 565 Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength); 566 567 /** 568 * This method saves the Operational Dataset in non-volatile memory. 569 * 570 * @param[in] aDataset The Operational Dataset. 571 * 572 * @retval kErrorNone Successfully applied configuration. 573 * @retval kErrorParse The dataset has at least one TLV with invalid format. 574 * 575 */ 576 Error Save(const Dataset &aDataset); 577 578 #if OPENTHREAD_FTD 579 /** 580 * This method starts the Leader functions for maintaining the Active Operational Dataset. 581 * 582 */ 583 void StartLeader(void); 584 585 /** 586 * This method generates a Pending Dataset from an Active Dataset. 587 * 588 * @param[in] aTimestamp The Active Dataset Timestamp. 589 * @param[in] aMessage The MGMT_SET message that contains an Active Dataset. 590 * 591 */ 592 void ApplyActiveDataset(const Timestamp &aTimestamp, Coap::Message &aMessage); 593 #endif 594 595 private: 596 void StartDelayTimer(void); 597 598 static void HandleTimer(Timer &aTimer); HandleTimer(void)599 void HandleTimer(void) { DatasetManager::HandleTimer(); } 600 601 void HandleDelayTimer(void); 602 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 603 604 using DelayTimer = TimerMilliIn<PendingDatasetManager, &PendingDatasetManager::HandleDelayTimer>; 605 606 DelayTimer mDelayTimer; 607 }; 608 609 DeclareTmfHandler(PendingDatasetManager, kUriPendingGet); 610 #if OPENTHREAD_FTD 611 DeclareTmfHandler(PendingDatasetManager, kUriPendingSet); 612 #endif 613 614 } // namespace MeshCoP 615 } // namespace ot 616 617 #endif // MESHCOP_DATASET_MANAGER_HPP_ 618