1 /*
2  *  Copyright (c) 2016-2017, 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 common methods for manipulating MeshCoP Datasets.
32  *
33  */
34 
35 #include "dataset_local.hpp"
36 
37 #include <stdio.h>
38 
39 #include "common/code_utils.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/logging.hpp"
43 #include "common/settings.hpp"
44 #include "meshcop/dataset.hpp"
45 #include "meshcop/meshcop_tlvs.hpp"
46 #include "thread/mle_tlvs.hpp"
47 
48 namespace ot {
49 namespace MeshCoP {
50 
DatasetLocal(Instance & aInstance,Dataset::Type aType)51 DatasetLocal::DatasetLocal(Instance &aInstance, Dataset::Type aType)
52     : InstanceLocator(aInstance)
53     , mUpdateTime(0)
54     , mType(aType)
55     , mTimestampPresent(false)
56     , mSaved(false)
57 {
58     mTimestamp.Init();
59 }
60 
Clear(void)61 void DatasetLocal::Clear(void)
62 {
63     IgnoreError(Get<Settings>().DeleteOperationalDataset(IsActive()));
64     mTimestamp.Init();
65     mTimestampPresent = false;
66     mSaved            = false;
67 }
68 
Restore(Dataset & aDataset)69 Error DatasetLocal::Restore(Dataset &aDataset)
70 {
71     const Timestamp *timestamp;
72     Error            error;
73 
74     mTimestampPresent = false;
75 
76     error = Read(aDataset);
77     SuccessOrExit(error);
78 
79     mSaved    = true;
80     timestamp = aDataset.GetTimestamp(mType);
81 
82     if (timestamp != nullptr)
83     {
84         mTimestamp        = *timestamp;
85         mTimestampPresent = true;
86     }
87 
88 exit:
89     return error;
90 }
91 
Read(Dataset & aDataset) const92 Error DatasetLocal::Read(Dataset &aDataset) const
93 {
94     DelayTimerTlv *delayTimer;
95     uint32_t       elapsed;
96     Error          error;
97 
98     error = Get<Settings>().ReadOperationalDataset(IsActive(), aDataset);
99     VerifyOrExit(error == kErrorNone, aDataset.mLength = 0);
100 
101     if (mType == Dataset::kActive)
102     {
103         aDataset.RemoveTlv(Tlv::kPendingTimestamp);
104         aDataset.RemoveTlv(Tlv::kDelayTimer);
105     }
106     else
107     {
108         delayTimer = aDataset.GetTlv<DelayTimerTlv>();
109         VerifyOrExit(delayTimer);
110 
111         elapsed = TimerMilli::GetNow() - mUpdateTime;
112 
113         if (delayTimer->GetDelayTimer() > elapsed)
114         {
115             delayTimer->SetDelayTimer(delayTimer->GetDelayTimer() - elapsed);
116         }
117         else
118         {
119             delayTimer->SetDelayTimer(0);
120         }
121     }
122 
123     aDataset.mUpdateTime = TimerMilli::GetNow();
124 
125 exit:
126     return error;
127 }
128 
Read(Dataset::Info & aDatasetInfo) const129 Error DatasetLocal::Read(Dataset::Info &aDatasetInfo) const
130 {
131     Dataset dataset;
132     Error   error;
133 
134     aDatasetInfo.Clear();
135 
136     SuccessOrExit(error = Read(dataset));
137     dataset.ConvertTo(aDatasetInfo);
138 
139 exit:
140     return error;
141 }
142 
Read(otOperationalDatasetTlvs & aDataset) const143 Error DatasetLocal::Read(otOperationalDatasetTlvs &aDataset) const
144 {
145     Dataset dataset;
146     Error   error;
147 
148     memset(&aDataset, 0, sizeof(aDataset));
149 
150     SuccessOrExit(error = Read(dataset));
151     dataset.ConvertTo(aDataset);
152 
153 exit:
154     return error;
155 }
156 
Save(const Dataset::Info & aDatasetInfo)157 Error DatasetLocal::Save(const Dataset::Info &aDatasetInfo)
158 {
159     Error   error;
160     Dataset dataset;
161 
162     SuccessOrExit(error = dataset.SetFrom(aDatasetInfo));
163     SuccessOrExit(error = Save(dataset));
164 
165 exit:
166     return error;
167 }
168 
Save(const otOperationalDatasetTlvs & aDataset)169 Error DatasetLocal::Save(const otOperationalDatasetTlvs &aDataset)
170 {
171     Dataset dataset;
172 
173     dataset.SetFrom(aDataset);
174 
175     return Save(dataset);
176 }
177 
Save(const Dataset & aDataset)178 Error DatasetLocal::Save(const Dataset &aDataset)
179 {
180     const Timestamp *timestamp;
181     Error            error = kErrorNone;
182 
183     if (aDataset.GetSize() == 0)
184     {
185         // do not propagate error back
186         IgnoreError(Get<Settings>().DeleteOperationalDataset(IsActive()));
187         mSaved = false;
188         otLogInfoMeshCoP("%s dataset deleted", Dataset::TypeToString(mType));
189     }
190     else
191     {
192         SuccessOrExit(error = Get<Settings>().SaveOperationalDataset(IsActive(), aDataset));
193         mSaved = true;
194         otLogInfoMeshCoP("%s dataset set", Dataset::TypeToString(mType));
195     }
196 
197     timestamp = aDataset.GetTimestamp(mType);
198 
199     if (timestamp != nullptr)
200     {
201         mTimestamp        = *timestamp;
202         mTimestampPresent = true;
203     }
204     else
205     {
206         mTimestampPresent = false;
207     }
208 
209     mUpdateTime = TimerMilli::GetNow();
210 
211 exit:
212     return error;
213 }
214 
Compare(const Timestamp * aCompare)215 int DatasetLocal::Compare(const Timestamp *aCompare)
216 {
217     return (aCompare == nullptr) ? (!mTimestampPresent ? 0 : -1)
218                                  : (!mTimestampPresent ? 1 : mTimestamp.Compare(*aCompare));
219 }
220 
221 } // namespace MeshCoP
222 } // namespace ot
223