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