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