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 "net/udp6.hpp" 47 #include "thread/tmf.hpp" 48 49 namespace ot { 50 51 namespace MeshCoP { 52 53 class ActiveDatasetManager; 54 class PendingDatasetManager; 55 56 class DatasetManager : public InstanceLocator 57 { 58 friend class ActiveDatasetManager; 59 friend class PendingDatasetManager; 60 61 public: 62 /** 63 * Callback function pointer, invoked when a response to a MGMT_SET request is received or times out. 64 * 65 */ 66 typedef otDatasetMgmtSetCallback MgmtSetCallback; 67 68 /** 69 * Indicates whether to check or ignore Security Policy flag when processing an MGMT_GET request message. 70 * 71 * This is used as input in `ProcessGetRequest(). 72 * 73 */ 74 enum SecurityPolicyCheckMode : uint8_t 75 { 76 kCheckSecurityPolicyFlags, ///< Check Security Policy flags. 77 kIgnoreSecurityPolicyFlags, ///< Ignore Security Policy flags. 78 }; 79 80 /** 81 * Returns the network Timestamp. 82 * 83 * @returns The network Timestamp. 84 * 85 */ GetTimestamp(void) const86 const Timestamp &GetTimestamp(void) const { return mNetworkTimestamp; } 87 88 /** 89 * Clears the Operational Dataset. 90 * 91 */ 92 void Clear(void); 93 94 /** 95 * Restores the Operational Dataset from non-volatile memory. 96 * 97 * @retval kErrorNone Successfully restore the dataset. 98 * @retval kErrorNotFound There is no corresponding dataset stored in non-volatile memory. 99 * 100 */ 101 Error Restore(void); 102 103 /** 104 * Retrieves the dataset from non-volatile memory. 105 * 106 * @param[out] aDataset Where to place the dataset. 107 * 108 * @retval kErrorNone Successfully retrieved the dataset. 109 * @retval kErrorNotFound There is no corresponding dataset stored in non-volatile memory. 110 * 111 */ 112 Error Read(Dataset &aDataset) const; 113 114 /** 115 * Retrieves the dataset from non-volatile memory. 116 * 117 * @param[out] aDatasetInfo Where to place the dataset (as `Dataset::Info`). 118 * 119 * @retval kErrorNone Successfully retrieved the dataset. 120 * @retval kErrorNotFound There is no corresponding dataset stored in non-volatile memory. 121 * 122 */ 123 Error Read(Dataset::Info &aDatasetInfo) const; 124 125 /** 126 * Retrieves the dataset from non-volatile memory. 127 * 128 * @param[out] aDatasetTlvs Where to place the dataset. 129 * 130 * @retval kErrorNone Successfully retrieved the dataset. 131 * @retval kErrorNotFound There is no corresponding dataset stored in non-volatile memory. 132 * 133 */ 134 Error Read(Dataset::Tlvs &aDatasetTlvs) const; 135 136 /** 137 * Saves the Operational Dataset in non-volatile memory. 138 * 139 * @param[in] aDataset The Operational Dataset. 140 * 141 */ 142 void SaveLocal(const Dataset &aDataset); 143 144 /** 145 * Saves the Operational Dataset in non-volatile memory. 146 * 147 * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. 148 * 149 */ 150 void SaveLocal(const Dataset::Info &aDatasetInfo); 151 152 /** 153 * Saves the Operational Dataset in non-volatile memory. 154 * 155 * @param[in] aDatasetTlvs The Operational Dataset as `Dataset::Tlvs`. 156 * 157 * @retval kErrorNone Successfully saved the dataset. 158 * @retval kErrorInvalidArgs The @p aDatasetTlvs is invalid. It is too long or contains incorrect TLV formatting. 159 * 160 */ 161 Error SaveLocal(const Dataset::Tlvs &aDatasetTlvs); 162 163 /** 164 * Sets the Operational Dataset for the partition. 165 * 166 * Also updates the non-volatile local version if the partition's Operational Dataset is newer. If Active 167 * Operational Dataset is changed, applies the configuration to to Thread interface. 168 * 169 * @param[in] aDataset The Operational Dataset. 170 * 171 * @retval kErrorNone Successfully applied configuration. 172 * @retval kErrorParse The dataset has at least one TLV with invalid format. 173 * 174 */ Save(const Dataset & aDataset)175 Error Save(const Dataset &aDataset) { return Save(aDataset, /* aAllowOlderTimestamp */ false); } 176 177 /** 178 * Retrieves the channel mask from local dataset. 179 * 180 * @param[out] aChannelMask A reference to the channel mask. 181 * 182 * @retval kErrorNone Successfully retrieved the channel mask. 183 * @retval kErrorNotFound There is no valid channel mask stored in local dataset. 184 * 185 */ 186 Error GetChannelMask(Mac::ChannelMask &aChannelMask) const; 187 188 /** 189 * Applies the Active or Pending Dataset to the Thread interface. 190 * 191 * @retval kErrorNone Successfully applied configuration. 192 * @retval kErrorParse The dataset has at least one TLV with invalid format. 193 * 194 */ 195 Error ApplyConfiguration(void) const; 196 197 /** 198 * Sends a MGMT_SET request to the Leader. 199 * 200 * @param[in] aDatasetInfo The Operational Dataset. 201 * @param[in] aTlvs Any additional raw TLVs to include. 202 * @param[in] aLength Number of bytes in @p aTlvs. 203 * @param[in] aCallback A pointer to a function that is called on response reception or timeout. 204 * @param[in] aContext A pointer to application-specific context for @p aCallback. 205 * 206 * @retval kErrorNone Successfully send the meshcop dataset command. 207 * @retval kErrorNoBufs Insufficient buffer space to send. 208 * @retval kErrorBusy A previous request is ongoing. 209 * 210 */ 211 Error SendSetRequest(const Dataset::Info &aDatasetInfo, 212 const uint8_t *aTlvs, 213 uint8_t aLength, 214 MgmtSetCallback aCallback, 215 void *aContext); 216 217 /** 218 * Sends a MGMT_GET request. 219 * 220 * @param[in] aDatasetComponents An Operational Dataset components structure specifying components to request. 221 * @param[in] aTlvTypes A pointer to array containing additional raw TLV types to be requested. 222 * @param[in] aLength Number of bytes in @p aTlvTypes. 223 * @param[in] aAddress The IPv6 destination address for the MGMT_GET request. 224 * 225 * @retval kErrorNone Successfully send the meshcop dataset command. 226 * @retval kErrorNoBufs Insufficient buffer space to send. 227 * 228 */ 229 Error SendGetRequest(const Dataset::Components &aDatasetComponents, 230 const uint8_t *aTlvTypes, 231 uint8_t aLength, 232 const otIp6Address *aAddress) const; 233 234 /** 235 * Processes a MGMT_GET request message and prepares the response. 236 * 237 * @param[in] aRequest The MGMT_GET request message. 238 * @param[in] aCheckMode Indicates whether to check or ignore the Security Policy flags. 239 * 240 * @returns The prepared response, or `nullptr` if fails to parse the request or cannot allocate message. 241 * 242 */ 243 Coap::Message *ProcessGetRequest(const Coap::Message &aRequest, SecurityPolicyCheckMode aCheckMode) const; 244 245 private: 246 static constexpr uint8_t kMaxGetTypes = 64; // Max number of types in MGMT_GET.req 247 static constexpr uint32_t kSendSetDelay = 5000; // in msec. 248 249 using Type = Dataset::Type; 250 251 class TlvList : public Array<uint8_t, kMaxGetTypes> 252 { 253 public: 254 TlvList(void) = default; 255 void Add(uint8_t aTlvType); 256 }; 257 258 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 259 using KeyRef = Crypto::Storage::KeyRef; 260 261 struct SecurelyStoredTlv 262 { GetKeyRefot::MeshCoP::DatasetManager::SecurelyStoredTlv263 KeyRef GetKeyRef(Dataset::Type aType) const 264 { 265 return (aType == Dataset::kActive) ? mActiveKeyRef : mPendingKeyRef; 266 } 267 268 Tlv::Type mTlvType; 269 KeyRef mActiveKeyRef; 270 KeyRef mPendingKeyRef; 271 }; 272 273 static const SecurelyStoredTlv kSecurelyStoredTlvs[]; 274 #endif 275 276 #if OPENTHREAD_FTD 277 enum MgmtCommand : uint8_t 278 { 279 kMgmtSet, 280 kMgmtReplace, 281 }; 282 283 struct RequestInfo : Clearable<RequestInfo> // Info from a MGMT_SET or MGMT_REPLACE request. 284 { 285 Dataset mDataset; 286 bool mIsFromCommissioner; 287 bool mAffectsConnectivity; 288 bool mAffectsNetworkKey; 289 }; 290 #endif 291 292 DatasetManager(Instance &aInstance, Type aType, TimerMilli::Handler aTimerHandler); 293 IsActiveDataset(void) const294 bool IsActiveDataset(void) const { return (mType == Dataset::kActive); } IsPendingDataset(void) const295 bool IsPendingDataset(void) const { return (mType == Dataset::kPending); } 296 void Restore(const Dataset &aDataset); 297 Error ApplyConfiguration(const Dataset &aDataset) const; 298 void HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const; 299 void HandleTimer(void); 300 Error Save(const Dataset &aDataset, bool aAllowOlderTimestamp); 301 void LocalSave(const Dataset &aDataset); 302 void SignalDatasetChange(void) const; 303 void SyncLocalWithLeader(const Dataset &aDataset); 304 Error SendSetRequest(const Dataset &aDataset); 305 void HandleMgmtSetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aError); 306 307 static void HandleMgmtSetResponse(void *aContext, 308 otMessage *aMessage, 309 const otMessageInfo *aMessageInfo, 310 Error aError); 311 312 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE 313 void MoveKeysToSecureStorage(Dataset &aDataset) const; 314 void DestroySecurelyStoredKeys(void) const; 315 void EmplaceSecurelyStoredKeys(Dataset &aDataset) const; 316 void SaveTlvInSecureStorageAndClearValue(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const; 317 Error ReadTlvFromSecureStorage(Dataset &aDataset, Tlv::Type aTlvType, KeyRef aKeyRef) const; 318 #endif 319 320 #if OPENTHREAD_FTD 321 Error HandleSetOrReplace(MgmtCommand aCommand, const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 322 Error ProcessSetOrReplaceRequest(MgmtCommand aCommand, const Coap::Message &aMessage, RequestInfo &aInfo) const; 323 void SendSetOrReplaceResponse(const Coap::Message &aRequest, 324 const Ip6::MessageInfo &aMessageInfo, 325 StateTlv::State aState); 326 #endif 327 328 Type mType; 329 bool mLocalSaved : 1; 330 bool mMgmtPending : 1; 331 TimeMilli mLocalUpdateTime; 332 Timestamp mLocalTimestamp; 333 Timestamp mNetworkTimestamp; 334 TimerMilli mTimer; 335 Callback<MgmtSetCallback> mMgmtSetCallback; 336 }; 337 338 //---------------------------------------------------------------------------------------------------------------------- 339 340 class ActiveDatasetManager : public DatasetManager, private NonCopyable 341 { 342 friend class Tmf::Agent; 343 344 public: 345 /** 346 * Initializes the ActiveDatasetManager object. 347 * 348 * @param[in] aInstance A reference to the OpenThread instance. 349 * 350 */ 351 explicit ActiveDatasetManager(Instance &aInstance); 352 353 /** 354 * Indicates whether the Active Dataset is partially complete. 355 * 356 * Is primarily used to determine whether a user has supplied a partial Active Dataset for use 357 * with joining a network. 358 * 359 * @retval TRUE If an Active Dataset is saved but does not include an Active Timestamp. 360 * @retval FALSE If an Active Dataset is not saved or does include an Active Timestamp. 361 * 362 */ 363 bool IsPartiallyComplete(void) const; 364 365 /** 366 * Indicates whether the Active Dataset is complete. 367 * 368 * @retval TRUE If an Active Dataset is saved and includes an Active Timestamp. 369 * @retval FALSE If an Active Dataset is not saved or does include an Active Timestamp. 370 * 371 */ 372 bool IsComplete(void) const; 373 374 /** 375 * Indicates whether or not a valid network is present in the Active Operational Dataset. 376 * 377 * @retval TRUE if a valid network is present in the Active Dataset. 378 * @retval FALSE if a valid network is not present in the Active Dataset. 379 * 380 */ 381 bool IsCommissioned(void) const; 382 383 #if OPENTHREAD_FTD 384 385 /** 386 * Creates a new Operational Dataset to use when forming a new network. 387 * 388 * @param[out] aDatasetInfo The Operational Dataset as `Dataset::Info`. 389 * 390 * @retval kErrorNone Successfully created a new Operational Dataset. 391 * @retval kErrorFailed Failed to generate random values for new parameters. 392 * 393 */ CreateNewNetwork(Dataset::Info & aDatasetInfo)394 Error CreateNewNetwork(Dataset::Info &aDatasetInfo) { return aDatasetInfo.GenerateRandom(GetInstance()); } 395 396 /** 397 * Starts the Leader functions for maintaining the Active Operational Dataset. 398 * 399 */ 400 void StartLeader(void); 401 402 #if OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT 403 /** 404 * Generate a default Active Operational Dataset. 405 * 406 * @retval kErrorNone Successfully generated an Active Operational Dataset. 407 * @retval kErrorAlready A valid Active Operational Dataset already exists. 408 * @retval kErrorInvalidState Device is not currently attached to a network. 409 * 410 */ 411 Error GenerateLocal(void); 412 #endif 413 #endif 414 415 private: 416 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 417 418 static void HandleTimer(Timer &aTimer); HandleTimer(void)419 void HandleTimer(void) { DatasetManager::HandleTimer(); } 420 }; 421 422 DeclareTmfHandler(ActiveDatasetManager, kUriActiveGet); 423 #if OPENTHREAD_FTD 424 DeclareTmfHandler(ActiveDatasetManager, kUriActiveSet); 425 DeclareTmfHandler(ActiveDatasetManager, kUriActiveReplace); 426 #endif 427 428 //---------------------------------------------------------------------------------------------------------------------- 429 430 class PendingDatasetManager : public DatasetManager, private NonCopyable 431 { 432 friend class Tmf::Agent; 433 friend class DatasetManager; 434 435 public: 436 /** 437 * Initializes the PendingDatasetManager object. 438 * 439 * @param[in] aInstance A reference to the OpenThread instance. 440 * 441 */ 442 explicit PendingDatasetManager(Instance &aInstance); 443 444 /** 445 * Reads the Active Timestamp in the Pending Operational Dataset. 446 * 447 * @param[out] aTimestamp A reference to return the read timestamp. 448 * 449 * @retval kErrorNone The active timestamp was successfully fetched. 450 * @retval kErrorNotFound The pending dataset is not currently valid. 451 * 452 */ 453 Error ReadActiveTimestamp(Timestamp &aTimestamp) const; 454 455 /** 456 * Reads the remaining delay time in ms. 457 * 458 * @param[out] aRemainingDelay A reference to return the remaining delay time. 459 * 460 * @retval kErrorNone The remaining delay time was successfully fetched. 461 * @retval kErrorNotFound The pending dataset is not currently valid. 462 * 463 */ 464 Error ReadRemainingDelay(uint32_t &aRemainingDelay) const; 465 466 #if OPENTHREAD_FTD 467 /** 468 * Starts the Leader functions for maintaining the Active Operational Dataset. 469 * 470 */ 471 void StartLeader(void); 472 #endif 473 474 private: 475 #if OPENTHREAD_FTD 476 void ApplyActiveDataset(Dataset &aDataset); 477 #endif 478 479 void StartDelayTimer(void); 480 void StartDelayTimer(const Dataset &aDataset); 481 482 static void HandleTimer(Timer &aTimer); HandleTimer(void)483 void HandleTimer(void) { DatasetManager::HandleTimer(); } 484 485 void HandleDelayTimer(void); 486 template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 487 488 using DelayTimer = TimerMilliIn<PendingDatasetManager, &PendingDatasetManager::HandleDelayTimer>; 489 490 DelayTimer mDelayTimer; 491 }; 492 493 DeclareTmfHandler(PendingDatasetManager, kUriPendingGet); 494 #if OPENTHREAD_FTD 495 DeclareTmfHandler(PendingDatasetManager, kUriPendingSet); 496 #endif 497 498 } // namespace MeshCoP 499 } // namespace ot 500 501 #endif // MESHCOP_DATASET_MANAGER_HPP_ 502