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 "meshcop/dataset_local.hpp"
47 #include "net/udp6.hpp"
48 #include "thread/tmf.hpp"
49 
50 namespace ot {
51 
52 namespace MeshCoP {
53 
54 class DatasetManager : public InstanceLocator
55 {
56 public:
57     /**
58      * Returns a pointer to the Timestamp.
59      *
60      * @returns A pointer to the Timestamp.
61      *
62      */
63     const Timestamp *GetTimestamp(void) const;
64 
65     /**
66      * Restores the Operational Dataset from non-volatile memory.
67      *
68      * @retval kErrorNone      Successfully restore the dataset.
69      * @retval kErrorNotFound  There is no corresponding dataset stored in non-volatile memory.
70      *
71      */
72     Error Restore(void);
73 
74     /**
75      * Retrieves the dataset from non-volatile memory.
76      *
77      * @param[out]  aDataset  Where to place the dataset.
78      *
79      * @retval kErrorNone      Successfully retrieved the dataset.
80      * @retval kErrorNotFound  There is no corresponding dataset stored in non-volatile memory.
81      *
82      */
Read(Dataset & aDataset) const83     Error Read(Dataset &aDataset) const { return mLocal.Read(aDataset); }
84 
85     /**
86      * Retrieves the dataset from non-volatile memory.
87      *
88      * @param[out]  aDatasetInfo  Where to place the dataset (as `Dataset::Info`).
89      *
90      * @retval kErrorNone      Successfully retrieved the dataset.
91      * @retval kErrorNotFound  There is no corresponding dataset stored in non-volatile memory.
92      *
93      */
Read(Dataset::Info & aDatasetInfo) const94     Error Read(Dataset::Info &aDatasetInfo) const { return mLocal.Read(aDatasetInfo); }
95 
96     /**
97      * Retrieves the dataset from non-volatile memory.
98      *
99      * @param[out]  aDataset  Where to place the dataset.
100      *
101      * @retval kErrorNone      Successfully retrieved the dataset.
102      * @retval kErrorNotFound  There is no corresponding dataset stored in non-volatile memory.
103      *
104      */
Read(otOperationalDatasetTlvs & aDataset) const105     Error Read(otOperationalDatasetTlvs &aDataset) const { return mLocal.Read(aDataset); }
106 
107     /**
108      * Retrieves the channel mask from local dataset.
109      *
110      * @param[out]  aChannelMask  A reference to the channel mask.
111      *
112      * @retval kErrorNone      Successfully retrieved the channel mask.
113      * @retval kErrorNotFound  There is no valid channel mask stored in local dataset.
114      *
115      */
116     Error GetChannelMask(Mac::ChannelMask &aChannelMask) const;
117 
118     /**
119      * Applies the Active or Pending Dataset to the Thread interface.
120      *
121      * @retval kErrorNone   Successfully applied configuration.
122      * @retval kErrorParse  The dataset has at least one TLV with invalid format.
123      *
124      */
125     Error ApplyConfiguration(void) const;
126 
127     /**
128      * Updates the Operational Dataset when detaching from the network.
129      *
130      * On detach, the Operational Dataset is restored from non-volatile memory.
131      *
132      */
133     void HandleDetach(void);
134 
135     /**
136      * Sends a MGMT_SET request to the Leader.
137      *
138      * @param[in]  aDatasetInfo  The Operational Dataset.
139      * @param[in]  aTlvs         Any additional raw TLVs to include.
140      * @param[in]  aLength       Number of bytes in @p aTlvs.
141      * @param[in]  aCallback     A pointer to a function that is called on response reception or timeout.
142      * @param[in]  aContext      A pointer to application-specific context for @p aCallback.
143      *
144      * @retval kErrorNone    Successfully send the meshcop dataset command.
145      * @retval kErrorNoBufs  Insufficient buffer space to send.
146      * @retval kErrorBusy    A previous request is ongoing.
147      *
148      */
149     Error SendSetRequest(const Dataset::Info     &aDatasetInfo,
150                          const uint8_t           *aTlvs,
151                          uint8_t                  aLength,
152                          otDatasetMgmtSetCallback aCallback,
153                          void                    *aContext);
154 
155     /**
156      * Sends a MGMT_GET request.
157      *
158      * @param[in]  aDatasetComponents  An Operational Dataset components structure specifying components to request.
159      * @param[in]  aTlvTypes           A pointer to array containing additional raw TLV types to be requested.
160      * @param[in]  aLength             Number of bytes in @p aTlvTypes.
161      * @param[in]  aAddress            The IPv6 destination address for the MGMT_GET request.
162      *
163      * @retval kErrorNone     Successfully send the meshcop dataset command.
164      * @retval kErrorNoBufs   Insufficient buffer space to send.
165      *
166      */
167     Error SendGetRequest(const Dataset::Components &aDatasetComponents,
168                          const uint8_t             *aTlvTypes,
169                          uint8_t                    aLength,
170                          const otIp6Address        *aAddress) const;
171 #if OPENTHREAD_FTD
172     /**
173      * Appends the MLE Dataset TLV but excluding MeshCoP Sub Timestamp TLV.
174      *
175      * @param[in] aMessage       The message to append the TLV to.
176      *
177      * @retval kErrorNone    Successfully append MLE Dataset TLV without MeshCoP Sub Timestamp TLV.
178      * @retval kErrorNoBufs  Insufficient available buffers to append the message with MLE Dataset TLV.
179      *
180      */
181     Error AppendMleDatasetTlv(Message &aMessage) const;
182 #endif
183 
184 protected:
185     /**
186      * Default Delay Timer value for a Pending Operational Dataset (ms)
187      *
188      */
189     static constexpr uint32_t kDefaultDelayTimer = OPENTHREAD_CONFIG_TMF_PENDING_DATASET_DEFAULT_DELAY;
190 
191     /**
192      * Defines a generic Dataset TLV to read from a message.
193      *
194      */
195     OT_TOOL_PACKED_BEGIN
196     class DatasetTlv : public Tlv
197     {
198     public:
199         /**
200          * Reads the Dataset TLV from a given message at a given offset.
201          *
202          * @param[in]  aMessage  A message to read the TLV from.
203          * @param[in]  aOffset   An offset into the message to read from.
204          *
205          * @retval kErrorNone    The TLV was read successfully.
206          * @retval kErrorParse   The TLV was not well-formed and could not be parsed.
207          *
208          */
209         Error ReadFromMessage(const Message &aMessage, uint16_t aOffset);
210 
211     private:
212         uint8_t mValue[Dataset::kMaxValueSize];
213     } OT_TOOL_PACKED_END;
214 
215     /**
216      * Initializes the object.
217      *
218      * @param[in]  aInstance      A reference to the OpenThread instance.
219      * @param[in]  aType          Dataset type, Active or Pending.
220      * @param[in]  aTimerHandler  The registration timer handler.
221      *
222      */
223     DatasetManager(Instance &aInstance, Dataset::Type aType, TimerMilli::Handler aTimerHandler);
224 
225     /**
226      * Gets the Operational Dataset type (Active or Pending).
227      *
228      * @returns The Operational Dataset type.
229      *
230      */
GetType(void) const231     Dataset::Type GetType(void) const { return mLocal.GetType(); }
232 
233     /**
234      * Clears the Operational Dataset.
235      *
236      */
237     void Clear(void);
238 
239     /**
240      * Saves the Operational Dataset in non-volatile memory.
241      *
242      * @param[in]  aDataset  The Operational Dataset.
243      *
244      * @retval kErrorNone   Successfully applied configuration.
245      * @retval kErrorParse  The dataset has at least one TLV with invalid format.
246      *
247      */
248     Error Save(const Dataset &aDataset);
249 
250     /**
251      * Saves the Operational Dataset in non-volatile memory.
252      *
253      * @param[in]  aDatasetInfo  The Operational Dataset as `Dataset::Info`.
254      *
255      * @retval kErrorNone             Successfully saved the dataset.
256      * @retval kErrorNotImplemented   The platform does not implement settings functionality.
257      *
258      */
259     Error Save(const Dataset::Info &aDatasetInfo);
260 
261     /**
262      * Saves the Operational Dataset in non-volatile memory.
263      *
264      * @param[in]  aDataset  The Operational Dataset.
265      *
266      * @retval kErrorNone             Successfully saved the dataset.
267      * @retval kErrorNotImplemented   The platform does not implement settings functionality.
268      *
269      */
270     Error Save(const otOperationalDatasetTlvs &aDataset);
271 
272     /**
273      * Sets the Operational Dataset for the partition.
274      *
275      * Also updates the non-volatile version if the partition's Operational Dataset is newer.
276      *
277      * @param[in]  aTimestamp  The timestamp for the Operational Dataset.
278      * @param[in]  aMessage    The message buffer.
279      * @param[in]  aOffset     The offset where the Operational Dataset begins.
280      * @param[in]  aLength     The length of the Operational Dataset.
281      *
282      * @retval kErrorNone     Successfully parsed the Dataset from the @p aMessage and saved it.
283      * @retval kErrorParse    Could not parse the Dataset from @p aMessage.
284      *
285      */
286     Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint8_t aLength);
287 
288     /**
289      * Saves the Operational Dataset in non-volatile memory.
290      *
291      * @param[in]  aDataset  The Operational Dataset.
292      *
293      * @retval kErrorNone   Successfully applied configuration.
294      * @retval kErrorParse  The dataset has at least one TLV with invalid format.
295      *
296      */
297     Error SaveLocal(const Dataset &aDataset);
298 
299     /**
300      * Handles a MGMT_GET request message.
301      *
302      * @param[in]  aMessage      The CoAP message buffer.
303      * @param[in]  aMessageInfo  The message info.
304      *
305      */
306     void HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const;
307 
308     /**
309      * Compares the partition's Operational Dataset with that stored in non-volatile memory.
310      *
311      * If the partition's Operational Dataset is newer, the non-volatile storage is updated.
312      * If the partition's Operational Dataset is older, the registration process is started.
313      *
314      */
315     void HandleNetworkUpdate(void);
316 
317     /**
318      * Initiates a network data registration message with the Leader.
319      *
320      */
321     void HandleTimer(void);
322 
323 #if OPENTHREAD_FTD
324     /**
325      * Handles the MGMT_SET request message.
326      *
327      * @param[in]  aMessage      The CoAP message buffer.
328      * @param[in]  aMessageInfo  The message info.
329      *
330      * @retval kErrorNone  The MGMT_SET request message was handled successfully.
331      * @retval kErrorDrop  The MGMT_SET request message was dropped.
332      *
333      */
334     Error HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
335 #endif
336 
337     DatasetLocal mLocal;
338     Timestamp    mTimestamp;
339     bool         mTimestampValid : 1;
340 
341 private:
342     static void HandleMgmtSetResponse(void                *aContext,
343                                       otMessage           *aMessage,
344                                       const otMessageInfo *aMessageInfo,
345                                       Error                aError);
346     void        HandleMgmtSetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aError);
347 
IsActiveDataset(void) const348     bool  IsActiveDataset(void) const { return GetType() == Dataset::kActive; }
IsPendingDataset(void) const349     bool  IsPendingDataset(void) const { return GetType() == Dataset::kPending; }
350     void  SignalDatasetChange(void) const;
351     void  HandleDatasetUpdated(void);
352     Error AppendDatasetToMessage(const Dataset::Info &aDatasetInfo, Message &aMessage) const;
353     void  SendSet(void);
354     void  SendGetResponse(const Coap::Message    &aRequest,
355                           const Ip6::MessageInfo &aMessageInfo,
356                           uint8_t                *aTlvs,
357                           uint8_t                 aLength) const;
358 
359 #if OPENTHREAD_FTD
360     void SendSetResponse(const Coap::Message &aRequest, const Ip6::MessageInfo &aMessageInfo, StateTlv::State aState);
361 #endif
362 
363     static constexpr uint8_t  kMaxDatasetTlvs = 16;   // Maximum number of TLVs in a Dataset.
364     static constexpr uint32_t kSendSetDelay   = 5000; // Milliseconds
365 
366     bool       mMgmtPending : 1;
367     TimerMilli mTimer;
368 
369     Callback<otDatasetMgmtSetCallback> mMgmtSetCallback;
370 };
371 
372 class ActiveDatasetManager : public DatasetManager, private NonCopyable
373 {
374     friend class Tmf::Agent;
375 
376 public:
377     /**
378      * Initializes the ActiveDatasetManager object.
379      *
380      * @param[in]  aInstance  A reference to the OpenThread instance.
381      *
382      */
383     explicit ActiveDatasetManager(Instance &aInstance);
384 
385     /**
386      * Indicates whether the Active Dataset is partially complete.
387      *
388      * Is primarily used to determine whether a user has supplied a partial Active Dataset for use
389      * with joining a network.
390      *
391      * @retval TRUE   If an Active Dataset is saved but does not include an Active Timestamp.
392      * @retval FALSE  If an Active Dataset is not saved or does include an Active Timestamp.
393      *
394      */
395     bool IsPartiallyComplete(void) const;
396 
397     /**
398      * Indicates whether the Active Dataset is complete.
399      *
400      * @retval TRUE   If an Active Dataset is saved and includes an Active Timestamp.
401      * @retval FALSE  If an Active Dataset is not saved or does include an Active Timestamp.
402      *
403      */
404     bool IsComplete(void) const;
405 
406     /**
407      * Indicates whether or not a valid network is present in the Active Operational Dataset.
408      *
409      * @retval TRUE if a valid network is present in the Active Dataset.
410      * @retval FALSE if a valid network is not present in the Active Dataset.
411      *
412      */
413     bool IsCommissioned(void) const;
414 
415     /**
416      * Clears the Active Operational Dataset.
417      *
418      */
Clear(void)419     void Clear(void) { DatasetManager::Clear(); }
420 
421     /**
422      * Saves the Operational Dataset in non-volatile memory.
423      *
424      * Also reconfigures the Thread interface.
425      *
426      * @param[in]  aDataset  The Operational Dataset.
427      *
428      */
Save(const Dataset & aDataset)429     void Save(const Dataset &aDataset) { IgnoreError(DatasetManager::Save(aDataset)); }
430 
431     /**
432      * Sets the Operational Dataset for the partition.
433      *
434      * Also reconfigures the Thread interface.
435      * Also updates the non-volatile version if the partition's Operational Dataset is newer.
436      *
437      * @param[in]  aTimestamp  The timestamp for the Operational Dataset.
438      * @param[in]  aMessage    The message buffer.
439      * @param[in]  aOffset     The offset where the Operational Dataset begins.
440      * @param[in]  aLength     The length of the Operational Dataset.
441      *
442      * @retval kErrorNone     Successfully parsed the Dataset from the @p aMessage and saved it.
443      * @retval kErrorParse    Could not parse the Dataset from @p aMessage.
444      *
445      */
446     Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength);
447 
448     /**
449      * Sets the Operational Dataset in non-volatile memory.
450      *
451      * @param[in]  aDatasetInfo  The Operational Dataset as `Dataset::Info`.
452      *
453      * @retval kErrorNone            Successfully saved the dataset.
454      * @retval kErrorNotImplemented  The platform does not implement settings functionality.
455      *
456      */
Save(const Dataset::Info & aDatasetInfo)457     Error Save(const Dataset::Info &aDatasetInfo) { return DatasetManager::Save(aDatasetInfo); }
458 
459     /**
460      * Sets the Operational Dataset in non-volatile memory.
461      *
462      * @param[in]  aDataset  The Operational Dataset.
463      *
464      * @retval kErrorNone            Successfully saved the dataset.
465      * @retval kErrorNotImplemented  The platform does not implement settings functionality.
466      *
467      */
Save(const otOperationalDatasetTlvs & aDataset)468     Error Save(const otOperationalDatasetTlvs &aDataset) { return DatasetManager::Save(aDataset); }
469 
470 #if OPENTHREAD_FTD
471 
472     /**
473      * Creates a new Operational Dataset to use when forming a new network.
474      *
475      * @param[out]  aDatasetInfo  The Operational Dataset as `Dataset::Info`.
476      *
477      * @retval kErrorNone    Successfully created a new Operational Dataset.
478      * @retval kErrorFailed  Failed to generate random values for new parameters.
479      *
480      */
CreateNewNetwork(Dataset::Info & aDatasetInfo)481     Error CreateNewNetwork(Dataset::Info &aDatasetInfo) { return aDatasetInfo.GenerateRandom(GetInstance()); }
482 
483     /**
484      * Starts the Leader functions for maintaining the Active Operational Dataset.
485      *
486      */
487     void StartLeader(void);
488 
489 #if OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT
490     /**
491      * Generate a default Active Operational Dataset.
492      *
493      * @retval kErrorNone          Successfully generated an Active Operational Dataset.
494      * @retval kErrorAlready       A valid Active Operational Dataset already exists.
495      * @retval kErrorInvalidState  Device is not currently attached to a network.
496      *
497      */
498     Error GenerateLocal(void);
499 #endif
500 #endif
501 
502 private:
503     template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
504 
505     static void HandleTimer(Timer &aTimer);
HandleTimer(void)506     void        HandleTimer(void) { DatasetManager::HandleTimer(); }
507 };
508 
509 DeclareTmfHandler(ActiveDatasetManager, kUriActiveGet);
510 #if OPENTHREAD_FTD
511 DeclareTmfHandler(ActiveDatasetManager, kUriActiveSet);
512 #endif
513 
514 class PendingDatasetManager : public DatasetManager, private NonCopyable
515 {
516     friend class Tmf::Agent;
517 
518 public:
519     /**
520      * Initializes the PendingDatasetManager object.
521      *
522      * @param[in]  aInstance     A reference to the OpenThread instance.
523      *
524      */
525     explicit PendingDatasetManager(Instance &aInstance);
526 
527     /**
528      * Clears the Pending Operational Dataset.
529      *
530      * Also stops the Delay Timer if it was active.
531      *
532      */
533     void Clear(void);
534 
535     /**
536      * Clears the network Pending Operational Dataset.
537      *
538      * Also stops the Delay Timer if it was active.
539      *
540      */
541     void ClearNetwork(void);
542 
543     /**
544      * Saves the Operational Dataset in non-volatile memory.
545      *
546      * Also starts the Delay Timer.
547      *
548      * @param[in]  aDatasetInfo  The Operational Dataset as `Dataset::Info`.
549      *
550      * @retval kErrorNone            Successfully saved the dataset.
551      * @retval kErrorNotImplemented  The platform does not implement settings functionality.
552      *
553      */
554     Error Save(const Dataset::Info &aDatasetInfo);
555 
556     /**
557      * Saves the Operational Dataset in non-volatile memory.
558      *
559      * Also starts the Delay Timer.
560      *
561      * @param[in]  aDataset  The Operational Dataset.
562      *
563      * @retval kErrorNone            Successfully saved the dataset.
564      * @retval kErrorNotImplemented  The platform does not implement settings functionality.
565      *
566      */
567     Error Save(const otOperationalDatasetTlvs &aDataset);
568 
569     /**
570      * Sets the Operational Dataset for the partition.
571      *
572      * Also updates the non-volatile version if the partition's Operational Dataset is newer.
573      *
574      * Also starts the Delay Timer.
575      *
576      * @param[in]  aTimestamp  The timestamp for the Operational Dataset.
577      * @param[in]  aMessage    The message buffer.
578      * @param[in]  aOffset     The offset where the Operational Dataset begins.
579      * @param[in]  aLength     The length of the Operational Dataset.
580      *
581      */
582     Error Save(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength);
583 
584     /**
585      * Saves the Operational Dataset in non-volatile memory.
586      *
587      * @param[in]  aDataset  The Operational Dataset.
588      *
589      * @retval kErrorNone   Successfully applied configuration.
590      * @retval kErrorParse  The dataset has at least one TLV with invalid format.
591      *
592      */
593     Error Save(const Dataset &aDataset);
594 
595 #if OPENTHREAD_FTD
596     /**
597      * Starts the Leader functions for maintaining the Active Operational Dataset.
598      *
599      */
600     void StartLeader(void);
601 
602     /**
603      * Generates a Pending Dataset from an Active Dataset.
604      *
605      * @param[in]  aTimestamp  The Active Dataset Timestamp.
606      * @param[in]  aMessage    The MGMT_SET message that contains an Active Dataset.
607      *
608      */
609     void ApplyActiveDataset(const Timestamp &aTimestamp, Coap::Message &aMessage);
610 #endif
611 
612 private:
613     void StartDelayTimer(void);
614 
615     static void HandleTimer(Timer &aTimer);
HandleTimer(void)616     void        HandleTimer(void) { DatasetManager::HandleTimer(); }
617 
618     void                     HandleDelayTimer(void);
619     template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
620 
621     using DelayTimer = TimerMilliIn<PendingDatasetManager, &PendingDatasetManager::HandleDelayTimer>;
622 
623     DelayTimer mDelayTimer;
624 };
625 
626 DeclareTmfHandler(PendingDatasetManager, kUriPendingGet);
627 #if OPENTHREAD_FTD
628 DeclareTmfHandler(PendingDatasetManager, kUriPendingSet);
629 #endif
630 
631 } // namespace MeshCoP
632 } // namespace ot
633 
634 #endif // MESHCOP_DATASET_MANAGER_HPP_
635