1 /*
2  *  Copyright (c) 2018, 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 non-volatile storage of settings.
32  */
33 
34 #include "settings.hpp"
35 
36 #include "common/code_utils.hpp"
37 #include "common/instance.hpp"
38 #include "common/locator_getters.hpp"
39 #include "common/logging.hpp"
40 #include "meshcop/dataset.hpp"
41 #include "thread/mle.hpp"
42 
43 namespace ot {
44 
45 //---------------------------------------------------------------------------------------------------------------------
46 // SettingsBase
47 
48 // LCOV_EXCL_START
49 
50 #if OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
51 
Log(Action aAction) const52 void SettingsBase::NetworkInfo::Log(Action aAction) const
53 {
54     otLogInfoCore(
55         "[settings] %s NetworkInfo {rloc:0x%04x, extaddr:%s, role:%s, mode:0x%02x, version:%hu, keyseq:0x%x, ...",
56         ActionToString(aAction), GetRloc16(), GetExtAddress().ToString().AsCString(),
57         Mle::Mle::RoleToString(static_cast<Mle::DeviceRole>(GetRole())), GetDeviceMode(), GetVersion(),
58         GetKeySequence());
59 
60     otLogInfoCore("[settings] ... pid:0x%x, mlecntr:0x%x, maccntr:0x%x, mliid:%s}", GetPreviousPartitionId(),
61                   GetMleFrameCounter(), GetMacFrameCounter(), GetMeshLocalIid().ToString().AsCString());
62 }
63 
Log(Action aAction) const64 void SettingsBase::ParentInfo::Log(Action aAction) const
65 {
66     otLogInfoCore("[settings] %s ParentInfo {extaddr:%s, version:%hu}", ActionToString(aAction),
67                   GetExtAddress().ToString().AsCString(), GetVersion());
68 }
69 
70 #if OPENTHREAD_FTD
Log(Action aAction) const71 void SettingsBase::ChildInfo::Log(Action aAction) const
72 {
73     otLogInfoCore("[settings] %s ChildInfo {rloc:0x%04x, extaddr:%s, timeout:%u, mode:0x%02x, version:%hu}",
74                   ActionToString(aAction), GetRloc16(), GetExtAddress().ToString().AsCString(), GetTimeout(), GetMode(),
75                   GetVersion());
76 }
77 #endif
78 
79 #if OPENTHREAD_CONFIG_DUA_ENABLE
Log(Action aAction) const80 void SettingsBase::DadInfo::Log(Action aAction) const
81 {
82     otLogInfoCore("[settings] %s DadInfo {DadCounter:%2d}", ActionToString(aAction), GetDadCounter());
83 }
84 #endif
85 
86 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
LogPrefix(Action aAction,Key aKey,const Ip6::Prefix & aPrefix)87 void SettingsBase::LogPrefix(Action aAction, Key aKey, const Ip6::Prefix &aPrefix)
88 {
89     otLogInfoCore("[settings] %s %s %s", ActionToString(aAction), KeyToString(aKey), aPrefix.ToString().AsCString());
90 }
91 #endif
92 
93 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
Log(Action aAction) const94 void SettingsBase::SrpClientInfo::Log(Action aAction) const
95 {
96     otLogInfoCore("[settings] %s SrpClientInfo {Server:[%s]:%u}", ActionToString(aAction),
97                   GetServerAddress().ToString().AsCString(), GetServerPort());
98 }
99 #endif
100 
101 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
Log(Action aAction) const102 void SettingsBase::SrpServerInfo::Log(Action aAction) const
103 {
104     otLogInfoCore("[settings] %s SrpServerInfo {port:%u}", ActionToString(aAction), GetPort());
105 }
106 #endif
107 
108 #endif // OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
109 
110 #if OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
ActionToString(Action aAction)111 const char *SettingsBase::ActionToString(Action aAction)
112 {
113     static const char *const kActionStrings[] = {
114         "Read",     // (0) kActionRead
115         "Saved",    // (1) kActionSave
116         "Re-saved", // (2) kActionResave
117         "Deleted",  // (3) kActionDelete
118 #if OPENTHREAD_FTD
119         "Added",      // (4) kActionAdd,
120         "Removed",    // (5) kActionRemove,
121         "Deleted all" // (6) kActionDeleteAll
122 #endif
123     };
124 
125     static_assert(0 == kActionRead, "kActionRead value is incorrect");
126     static_assert(1 == kActionSave, "kActionSave value is incorrect");
127     static_assert(2 == kActionResave, "kActionResave value is incorrect");
128     static_assert(3 == kActionDelete, "kActionDelete value is incorrect");
129 #if OPENTHREAD_FTD
130     static_assert(4 == kActionAdd, "kActionAdd value is incorrect");
131     static_assert(5 == kActionRemove, "kActionRemove value is incorrect");
132     static_assert(6 == kActionDeleteAll, "kActionDeleteAll value is incorrect");
133 #endif
134 
135     return kActionStrings[aAction];
136 }
137 #endif // OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
138 
139 #if OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
KeyToString(Key aKey)140 const char *SettingsBase::KeyToString(Key aKey)
141 {
142     static const char *const kKeyStrings[] = {
143         "",                  // (0)  (Unused)
144         "ActiveDataset",     // (1)  kKeyActiveDataset
145         "PendingDataset",    // (2)  kKeyPendingDataset
146         "NetworkInfo",       // (3)  kKeyNetworkInfo
147         "ParentInfo",        // (4)  kKeyParentInfo
148         "ChildInfo",         // (5)  kKeyChildInfo
149         "",                  // (6)  kKeyReserved
150         "SlaacIidSecretKey", // (7)  kKeySlaacIidSecretKey
151         "DadInfo",           // (8)  kKeyDadInfo
152         "OmrPrefix",         // (9)  kKeyOmrPrefix
153         "OnLinkPrefix",      // (10) kKeyOnLinkPrefix
154         "SrpEcdsaKey",       // (11) kKeySrpEcdsaKey
155         "SrpClientInfo",     // (12) kKeySrpClientInfo
156         "SrpServerInfo",     // (13) kKeySrpServerInfo
157     };
158 
159     static_assert(1 == kKeyActiveDataset, "kKeyActiveDataset value is incorrect");
160     static_assert(2 == kKeyPendingDataset, "kKeyPendingDataset value is incorrect");
161     static_assert(3 == kKeyNetworkInfo, "kKeyNetworkInfo value is incorrect");
162     static_assert(4 == kKeyParentInfo, "kKeyParentInfo value is incorrect");
163     static_assert(5 == kKeyChildInfo, "kKeyChildInfo value is incorrect");
164     static_assert(6 == kKeyReserved, "kKeyReserved value is incorrect");
165     static_assert(7 == kKeySlaacIidSecretKey, "kKeySlaacIidSecretKey value is incorrect");
166     static_assert(8 == kKeyDadInfo, "kKeyDadInfo value is incorrect");
167     static_assert(9 == kKeyOmrPrefix, "kKeyOmrPrefix value is incorrect");
168     static_assert(10 == kKeyOnLinkPrefix, "kKeyOnLinkPrefix value is incorrect");
169     static_assert(11 == kKeySrpEcdsaKey, "kKeySrpEcdsaKey value is incorrect");
170     static_assert(12 == kKeySrpClientInfo, "kKeySrpClientInfo value is incorrect");
171     static_assert(13 == kKeySrpServerInfo, "kKeySrpServerInfo value is incorrect");
172 
173     static_assert(kLastKey == kKeySrpServerInfo, "kLastKey is not valid");
174 
175     OT_ASSERT(aKey <= kLastKey);
176 
177     return kKeyStrings[aKey];
178 }
179 #endif // OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
180 
181 // LCOV_EXCL_STOP
182 
183 //---------------------------------------------------------------------------------------------------------------------
184 // Settings
185 
186 // This array contains critical keys that should be stored in the secure area.
187 const uint16_t Settings::kCriticalKeys[] = {
188     SettingsBase::kKeyActiveDataset,
189     SettingsBase::kKeyPendingDataset,
190     SettingsBase::kKeySrpEcdsaKey,
191 };
192 
Init(void)193 void Settings::Init(void)
194 {
195     Get<SettingsDriver>().Init();
196     Get<SettingsDriver>().SetCriticalKeys(kCriticalKeys, OT_ARRAY_LENGTH(kCriticalKeys));
197 }
198 
Deinit(void)199 void Settings::Deinit(void)
200 {
201     Get<SettingsDriver>().Deinit();
202 }
203 
Wipe(void)204 void Settings::Wipe(void)
205 {
206     Get<SettingsDriver>().Wipe();
207     otLogInfoCore("[settings] Wiped all info");
208 }
209 
SaveOperationalDataset(bool aIsActive,const MeshCoP::Dataset & aDataset)210 Error Settings::SaveOperationalDataset(bool aIsActive, const MeshCoP::Dataset &aDataset)
211 {
212     Key   key   = (aIsActive ? kKeyActiveDataset : kKeyPendingDataset);
213     Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetSize());
214 
215     Log(kActionSave, error, key);
216 
217     return error;
218 }
219 
ReadOperationalDataset(bool aIsActive,MeshCoP::Dataset & aDataset) const220 Error Settings::ReadOperationalDataset(bool aIsActive, MeshCoP::Dataset &aDataset) const
221 {
222     Error    error  = kErrorNone;
223     uint16_t length = MeshCoP::Dataset::kMaxSize;
224 
225     SuccessOrExit(error = Get<SettingsDriver>().Get(aIsActive ? kKeyActiveDataset : kKeyPendingDataset,
226                                                     aDataset.GetBytes(), &length));
227     VerifyOrExit(length <= MeshCoP::Dataset::kMaxSize, error = kErrorNotFound);
228 
229     aDataset.SetSize(length);
230 
231 exit:
232     return error;
233 }
234 
DeleteOperationalDataset(bool aIsActive)235 Error Settings::DeleteOperationalDataset(bool aIsActive)
236 {
237     Key   key   = (aIsActive ? kKeyActiveDataset : kKeyPendingDataset);
238     Error error = Get<SettingsDriver>().Delete(key);
239 
240     Log(kActionDelete, error, key);
241 
242     return error;
243 }
244 
245 #if OPENTHREAD_FTD
AddChildInfo(const ChildInfo & aChildInfo)246 Error Settings::AddChildInfo(const ChildInfo &aChildInfo)
247 {
248     Error error = Get<SettingsDriver>().Add(kKeyChildInfo, &aChildInfo, sizeof(aChildInfo));
249 
250     Log(kActionAdd, error, kKeyChildInfo, &aChildInfo);
251 
252     return error;
253 }
254 
DeleteAllChildInfo(void)255 Error Settings::DeleteAllChildInfo(void)
256 {
257     Error error = Get<SettingsDriver>().Delete(kKeyChildInfo);
258 
259     Log(kActionDeleteAll, error, kKeyChildInfo);
260 
261     return error;
262 }
263 
ChildInfoIterator(Instance & aInstance)264 Settings::ChildInfoIterator::ChildInfoIterator(Instance &aInstance)
265     : SettingsBase(aInstance)
266     , mIndex(0)
267     , mIsDone(false)
268 {
269     Read();
270 }
271 
Advance(void)272 void Settings::ChildInfoIterator::Advance(void)
273 {
274     if (!mIsDone)
275     {
276         mIndex++;
277         Read();
278     }
279 }
280 
Delete(void)281 Error Settings::ChildInfoIterator::Delete(void)
282 {
283     Error error = kErrorNone;
284 
285     VerifyOrExit(!mIsDone, error = kErrorInvalidState);
286     SuccessOrExit(error = Get<SettingsDriver>().Delete(kKeyChildInfo, mIndex));
287 
288 exit:
289     Log(kActionRemove, error, kKeyChildInfo, &mChildInfo);
290     return error;
291 }
292 
Read(void)293 void Settings::ChildInfoIterator::Read(void)
294 {
295     uint16_t length = sizeof(ChildInfo);
296     Error    error;
297 
298     mChildInfo.Init();
299     SuccessOrExit(
300         error = Get<SettingsDriver>().Get(kKeyChildInfo, mIndex, reinterpret_cast<uint8_t *>(&mChildInfo), &length));
301 
302 exit:
303     Log(kActionRead, error, kKeyChildInfo, &mChildInfo);
304     mIsDone = (error != kErrorNone);
305 }
306 #endif // OPENTHREAD_FTD
307 
ReadEntry(Key aKey,void * aValue,uint16_t aMaxLength) const308 Error Settings::ReadEntry(Key aKey, void *aValue, uint16_t aMaxLength) const
309 {
310     Error    error;
311     uint16_t length = aMaxLength;
312 
313     error = Get<SettingsDriver>().Get(aKey, aValue, &length);
314     Log(kActionRead, error, aKey, aValue);
315 
316     return error;
317 }
318 
SaveEntry(Key aKey,const void * aValue,void * aPrev,uint16_t aLength)319 Error Settings::SaveEntry(Key aKey, const void *aValue, void *aPrev, uint16_t aLength)
320 {
321     Error    error      = kErrorNone;
322     uint16_t readLength = aLength;
323     Action   action     = kActionSave;
324 
325     if ((Get<SettingsDriver>().Get(aKey, aPrev, &readLength) == kErrorNone) && (readLength == aLength) &&
326         (memcmp(aValue, aPrev, aLength) == 0))
327     {
328         action = kActionResave;
329     }
330     else
331     {
332         error = Get<SettingsDriver>().Set(aKey, aValue, aLength);
333     }
334 
335     Log(action, error, aKey, aValue);
336 
337     return error;
338 }
339 
DeleteEntry(Key aKey)340 Error Settings::DeleteEntry(Key aKey)
341 {
342     Error error = Get<SettingsDriver>().Delete(aKey);
343 
344     Log(kActionDelete, error, aKey);
345 
346     return error;
347 }
348 
Log(Action aAction,Error aError,Key aKey,const void * aValue)349 void Settings::Log(Action aAction, Error aError, Key aKey, const void *aValue)
350 {
351     OT_UNUSED_VARIABLE(aAction);
352     OT_UNUSED_VARIABLE(aKey);
353     OT_UNUSED_VARIABLE(aError);
354     OT_UNUSED_VARIABLE(aValue);
355 
356 #if OPENTHREAD_CONFIG_LOG_UTIL
357 
358     if (aError != kErrorNone)
359     {
360         // Log error if log level is at "warn" or higher.
361 
362 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
363         const char *actionText = "";
364 
365         switch (aAction)
366         {
367         case kActionSave:
368         case kActionResave:
369             actionText = "saving";
370             break;
371 
372         case kActionDelete:
373             VerifyOrExit(aError != kErrorNotFound);
374             actionText = "deleting";
375             break;
376 
377 #if OPENTHREAD_FTD
378         case kActionAdd:
379             actionText = "adding";
380             break;
381 
382         case kActionRemove:
383             VerifyOrExit(aError != kErrorNotFound);
384             actionText = "removing";
385             break;
386 
387         case kActionDeleteAll:
388             VerifyOrExit(aError != kErrorNotFound);
389             actionText = "deleting all";
390             break;
391 #endif
392         case kActionRead:
393             ExitNow();
394         }
395 
396         otLogWarnCore("[settings] Error %s %s %s", ErrorToString(aError), actionText, KeyToString(aKey));
397 
398 #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
399 
400         ExitNow();
401     }
402 
403     // We reach here when `aError` is `kErrorNone`.
404     // Log success if log level is at "info" or higher.
405 
406 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
407     if (aValue != nullptr)
408     {
409         switch (aKey)
410         {
411         case kKeyNetworkInfo:
412             reinterpret_cast<const NetworkInfo *>(aValue)->Log(aAction);
413             break;
414 
415         case kKeyParentInfo:
416             reinterpret_cast<const ParentInfo *>(aValue)->Log(aAction);
417             break;
418 
419 #if OPENTHREAD_FTD
420         case kKeyChildInfo:
421             reinterpret_cast<const ChildInfo *>(aValue)->Log(aAction);
422             break;
423 #endif
424 
425 #if OPENTHREAD_CONFIG_DUA_ENABLE
426         case kKeyDadInfo:
427             reinterpret_cast<const DadInfo *>(aValue)->Log(aAction);
428             break;
429 #endif
430 
431 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
432         case kKeyOmrPrefix:
433         case kKeyOnLinkPrefix:
434             LogPrefix(aAction, aKey, *reinterpret_cast<const Ip6::Prefix *>(aValue));
435             break;
436 #endif
437 
438 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
439         case kKeySrpClientInfo:
440             reinterpret_cast<const SrpClientInfo *>(aValue)->Log(aAction);
441             break;
442 #endif
443 
444 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
445         case kKeySrpServerInfo:
446             reinterpret_cast<const SrpServerInfo *>(aValue)->Log(aAction);
447             break;
448 #endif
449 
450         default:
451             // For any other keys, we do not want to include the value
452             // in the log, so even if it is given we set `aValue` to
453             // `nullptr`. This ensures that we just log the action and
454             // the key.
455             aValue = nullptr;
456             break;
457         }
458     }
459 
460     if (aValue == nullptr)
461     {
462         otLogInfoCore("[settings] %s %s", ActionToString(aAction), KeyToString(aKey));
463     }
464 #endif // (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
465 
466 exit:
467 
468 #endif // OPENTHREAD_CONFIG_LOG_UTIL
469     return;
470 }
471 
472 } // namespace ot
473 
474 //---------------------------------------------------------------------------------------------------------------------
475 // Default/weak implementation of settings platform APIs
476 
otPlatSettingsSetCriticalKeys(otInstance * aInstance,const uint16_t * aKeys,uint16_t aKeysLength)477 OT_TOOL_WEAK void otPlatSettingsSetCriticalKeys(otInstance *aInstance, const uint16_t *aKeys, uint16_t aKeysLength)
478 {
479     OT_UNUSED_VARIABLE(aInstance);
480     OT_UNUSED_VARIABLE(aKeys);
481     OT_UNUSED_VARIABLE(aKeysLength);
482 }
483