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