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