• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020, 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 implements Dataset Updater.
32  *
33  */
34 
35 #include "dataset_updater.hpp"
36 
37 #if (OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE || OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE) && OPENTHREAD_FTD
38 
39 #include "common/code_utils.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/random.hpp"
44 #include "meshcop/timestamp.hpp"
45 
46 namespace ot {
47 namespace MeshCoP {
48 
DatasetUpdater(Instance & aInstance)49 DatasetUpdater::DatasetUpdater(Instance &aInstance)
50     : InstanceLocator(aInstance)
51     , mCallback(nullptr)
52     , mCallbackContext(nullptr)
53     , mTimer(aInstance, DatasetUpdater::HandleTimer)
54     , mDataset(nullptr)
55 {
56 }
57 
RequestUpdate(const Dataset::Info & aDataset,Callback aCallback,void * aContext)58 Error DatasetUpdater::RequestUpdate(const Dataset::Info &aDataset, Callback aCallback, void *aContext)
59 {
60     Error    error   = kErrorNone;
61     Message *message = nullptr;
62 
63     VerifyOrExit(!Get<Mle::Mle>().IsDisabled(), error = kErrorInvalidState);
64     VerifyOrExit(mDataset == nullptr, error = kErrorBusy);
65 
66     VerifyOrExit(!aDataset.IsActiveTimestampPresent() && !aDataset.IsPendingTimestampPresent(),
67                  error = kErrorInvalidArgs);
68 
69     message = Get<MessagePool>().Allocate(Message::kTypeOther);
70     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
71 
72     SuccessOrExit(error = message->Append(aDataset));
73 
74     mCallback        = aCallback;
75     mCallbackContext = aContext;
76     mDataset         = message;
77 
78     mTimer.Start(1);
79 
80 exit:
81     FreeMessageOnError(message, error);
82     return error;
83 }
84 
CancelUpdate(void)85 void DatasetUpdater::CancelUpdate(void)
86 {
87     VerifyOrExit(mDataset != nullptr);
88 
89     FreeMessage(mDataset);
90     mDataset = nullptr;
91     mTimer.Stop();
92 
93 exit:
94     return;
95 }
96 
HandleTimer(Timer & aTimer)97 void DatasetUpdater::HandleTimer(Timer &aTimer)
98 {
99     aTimer.Get<DatasetUpdater>().HandleTimer();
100 }
101 
HandleTimer(void)102 void DatasetUpdater::HandleTimer(void)
103 {
104     PreparePendingDataset();
105 }
106 
PreparePendingDataset(void)107 void DatasetUpdater::PreparePendingDataset(void)
108 {
109     Dataset       dataset;
110     Dataset::Info requestedDataset;
111     Error         error;
112 
113     VerifyOrExit(!Get<Mle::Mle>().IsDisabled(), error = kErrorInvalidState);
114 
115     IgnoreError(mDataset->Read(0, requestedDataset));
116 
117     error = Get<ActiveDatasetManager>().Read(dataset);
118 
119     if (error != kErrorNone)
120     {
121         // If there is no valid Active Dataset but MLE is not disabled,
122         // set the timer to try again after the retry interval. This
123         // handles the situation where a dataset update request comes
124         // right after the network is formed but before the active
125         // dataset is created.
126 
127         mTimer.Start(kRetryInterval);
128         ExitNow(error = kErrorNone);
129     }
130 
131     IgnoreError(dataset.SetFrom(requestedDataset));
132 
133     if (!requestedDataset.IsDelayPresent())
134     {
135         uint32_t delay = kDefaultDelay;
136 
137         SuccessOrExit(error = dataset.SetTlv(Tlv::kDelayTimer, delay));
138     }
139 
140     {
141         Timestamp timestamp;
142 
143         if (Get<PendingDatasetManager>().GetTimestamp() != nullptr)
144         {
145             timestamp = *Get<PendingDatasetManager>().GetTimestamp();
146         }
147 
148         timestamp.AdvanceRandomTicks();
149         dataset.SetTimestamp(Dataset::kPending, timestamp);
150     }
151 
152     {
153         ActiveTimestampTlv *tlv = dataset.GetTlv<ActiveTimestampTlv>();
154 
155         tlv->GetTimestamp().AdvanceRandomTicks();
156     }
157 
158     SuccessOrExit(error = Get<PendingDatasetManager>().Save(dataset));
159 
160 exit:
161     if (error != kErrorNone)
162     {
163         Finish(error);
164     }
165 }
166 
Finish(Error aError)167 void DatasetUpdater::Finish(Error aError)
168 {
169     OT_ASSERT(mDataset != nullptr);
170 
171     FreeMessage(mDataset);
172     mDataset = nullptr;
173 
174     if (mCallback != nullptr)
175     {
176         mCallback(aError, mCallbackContext);
177     }
178 }
179 
HandleNotifierEvents(Events aEvents)180 void DatasetUpdater::HandleNotifierEvents(Events aEvents)
181 {
182     Dataset::Info requestedDataset;
183     Dataset::Info dataset;
184 
185     VerifyOrExit(mDataset != nullptr);
186 
187     VerifyOrExit(aEvents.ContainsAny(kEventActiveDatasetChanged | kEventPendingDatasetChanged));
188 
189     IgnoreError(mDataset->Read(0, requestedDataset));
190 
191     if (aEvents.Contains(kEventActiveDatasetChanged) && Get<ActiveDatasetManager>().Read(dataset) == kErrorNone)
192     {
193         if (requestedDataset.IsSubsetOf(dataset))
194         {
195             Finish(kErrorNone);
196         }
197         else
198         {
199             Timestamp requestedDatasetTimestamp;
200             Timestamp activeDatasetTimestamp;
201 
202             requestedDataset.GetActiveTimestamp(requestedDatasetTimestamp);
203             dataset.GetActiveTimestamp(activeDatasetTimestamp);
204             if (Timestamp::Compare(requestedDatasetTimestamp, activeDatasetTimestamp) <= 0)
205             {
206                 Finish(kErrorAlready);
207             }
208         }
209     }
210 
211     if (aEvents.Contains(kEventPendingDatasetChanged) && Get<PendingDatasetManager>().Read(dataset) == kErrorNone)
212     {
213         if (!requestedDataset.IsSubsetOf(dataset))
214         {
215             Finish(kErrorAlready);
216         }
217     }
218 
219 exit:
220     return;
221 }
222 
223 } // namespace MeshCoP
224 } // namespace ot
225 
226 #endif // #if (OPENTHREAD_CONFIG_DATASET_UPDATER_ENABLE || OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE) && OPENTHREAD_FTD
227