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