• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/array.hpp"
37 #include "common/code_utils.hpp"
38 #include "common/instance.hpp"
39 #include "common/locator_getters.hpp"
40 #include "meshcop/dataset.hpp"
41 #include "thread/mle.hpp"
42 
43 namespace ot {
44 
45 RegisterLogModule("Settings");
46 
47 //---------------------------------------------------------------------------------------------------------------------
48 // SettingsBase
49 
50 // LCOV_EXCL_START
51 
52 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
53 
Log(Action aAction) const54 void SettingsBase::NetworkInfo::Log(Action aAction) const
55 {
56     LogInfo("%s NetworkInfo {rloc:0x%04x, extaddr:%s, role:%s, mode:0x%02x, version:%hu, keyseq:0x%x, ...",
57             ActionToString(aAction), GetRloc16(), GetExtAddress().ToString().AsCString(),
58             Mle::Mle::RoleToString(static_cast<Mle::DeviceRole>(GetRole())), GetDeviceMode(), GetVersion(),
59             GetKeySequence());
60 
61     LogInfo("... pid:0x%x, mlecntr:0x%x, maccntr:0x%x, mliid:%s}", GetPreviousPartitionId(), GetMleFrameCounter(),
62             GetMacFrameCounter(), GetMeshLocalIid().ToString().AsCString());
63 }
64 
Log(Action aAction) const65 void SettingsBase::ParentInfo::Log(Action aAction) const
66 {
67     LogInfo("%s ParentInfo {extaddr:%s, version:%hu}", ActionToString(aAction), GetExtAddress().ToString().AsCString(),
68             GetVersion());
69 }
70 
71 #if OPENTHREAD_FTD
Log(Action aAction) const72 void SettingsBase::ChildInfo::Log(Action aAction) const
73 {
74     LogInfo("%s ChildInfo {rloc:0x%04x, extaddr:%s, timeout:%u, mode:0x%02x, version:%hu}", ActionToString(aAction),
75             GetRloc16(), GetExtAddress().ToString().AsCString(), GetTimeout(), GetMode(), GetVersion());
76 }
77 #endif
78 
79 #if OPENTHREAD_CONFIG_DUA_ENABLE
Log(Action aAction) const80 void SettingsBase::DadInfo::Log(Action aAction) const
81 {
82     LogInfo("%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     LogInfo("%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     LogInfo("%s SrpClientInfo {Server:[%s]:%u}", ActionToString(aAction), GetServerAddress().ToString().AsCString(),
97             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     LogInfo("%s SrpServerInfo {port:%u}", ActionToString(aAction), GetPort());
105 }
106 #endif
107 
108 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
109 
110 #if OT_SHOULD_LOG_AT(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 // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
138 
139 #if OT_SHOULD_LOG_AT(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)  Removed (previously auto-start).
150         "SlaacIidSecretKey", // (7)  kKeySlaacIidSecretKey
151         "DadInfo",           // (8)  kKeyDadInfo
152         "",                  // (9)  Removed (previously OMR prefix).
153         "",                  // (10) Removed (previously on-link prefix).
154         "SrpEcdsaKey",       // (11) kKeySrpEcdsaKey
155         "SrpClientInfo",     // (12) kKeySrpClientInfo
156         "SrpServerInfo",     // (13) kKeySrpServerInfo
157         "",                  // (14) Removed (previously NAT64 prefix)
158         "BrUlaPrefix",       // (15) kKeyBrUlaPrefix
159     };
160 
161     static_assert(1 == kKeyActiveDataset, "kKeyActiveDataset value is incorrect");
162     static_assert(2 == kKeyPendingDataset, "kKeyPendingDataset value is incorrect");
163     static_assert(3 == kKeyNetworkInfo, "kKeyNetworkInfo value is incorrect");
164     static_assert(4 == kKeyParentInfo, "kKeyParentInfo value is incorrect");
165     static_assert(5 == kKeyChildInfo, "kKeyChildInfo value is incorrect");
166     static_assert(7 == kKeySlaacIidSecretKey, "kKeySlaacIidSecretKey value is incorrect");
167     static_assert(8 == kKeyDadInfo, "kKeyDadInfo value is incorrect");
168     static_assert(11 == kKeySrpEcdsaKey, "kKeySrpEcdsaKey value is incorrect");
169     static_assert(12 == kKeySrpClientInfo, "kKeySrpClientInfo value is incorrect");
170     static_assert(13 == kKeySrpServerInfo, "kKeySrpServerInfo value is incorrect");
171     static_assert(15 == kKeyBrUlaPrefix, "kKeyBrUlaPrefix value is incorrect");
172 
173     static_assert(kLastKey == kKeyBrUlaPrefix, "kLastKey is not valid");
174 
175     OT_ASSERT(aKey <= kLastKey);
176 
177     return kKeyStrings[aKey];
178 }
179 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
180 
181 // LCOV_EXCL_STOP
182 
183 //---------------------------------------------------------------------------------------------------------------------
184 // Settings
185 
186 // This array contains sensitive keys that should be stored in the secure area.
187 const uint16_t Settings::kSensitiveKeys[] = {
188     SettingsBase::kKeyActiveDataset,
189     SettingsBase::kKeyPendingDataset,
190     SettingsBase::kKeySrpEcdsaKey,
191 };
192 
Init(void)193 void Settings::Init(void)
194 {
195     Get<SettingsDriver>().Init(kSensitiveKeys, GetArrayLength(kSensitiveKeys));
196 }
197 
Deinit(void)198 void Settings::Deinit(void)
199 {
200     Get<SettingsDriver>().Deinit();
201 }
202 
Wipe(void)203 void Settings::Wipe(void)
204 {
205     Get<SettingsDriver>().Wipe();
206     LogInfo("Wiped all info");
207 }
208 
KeyForDatasetType(MeshCoP::Dataset::Type aType)209 Settings::Key Settings::KeyForDatasetType(MeshCoP::Dataset::Type aType)
210 {
211     return (aType == MeshCoP::Dataset::kActive) ? kKeyActiveDataset : kKeyPendingDataset;
212 }
213 
SaveOperationalDataset(MeshCoP::Dataset::Type aType,const MeshCoP::Dataset & aDataset)214 Error Settings::SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshCoP::Dataset &aDataset)
215 {
216     Key   key   = KeyForDatasetType(aType);
217     Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetSize());
218 
219     Log(kActionSave, error, key);
220 
221     return error;
222 }
223 
ReadOperationalDataset(MeshCoP::Dataset::Type aType,MeshCoP::Dataset & aDataset) const224 Error Settings::ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Dataset &aDataset) const
225 {
226     Error    error  = kErrorNone;
227     uint16_t length = MeshCoP::Dataset::kMaxSize;
228 
229     SuccessOrExit(error = Get<SettingsDriver>().Get(KeyForDatasetType(aType), aDataset.GetBytes(), &length));
230     VerifyOrExit(length <= MeshCoP::Dataset::kMaxSize, error = kErrorNotFound);
231 
232     aDataset.SetSize(length);
233 
234 exit:
235     return error;
236 }
237 
DeleteOperationalDataset(MeshCoP::Dataset::Type aType)238 Error Settings::DeleteOperationalDataset(MeshCoP::Dataset::Type aType)
239 {
240     Key   key   = KeyForDatasetType(aType);
241     Error error = Get<SettingsDriver>().Delete(key);
242 
243     Log(kActionDelete, error, key);
244 
245     return error;
246 }
247 
248 #if OPENTHREAD_FTD
AddChildInfo(const ChildInfo & aChildInfo)249 Error Settings::AddChildInfo(const ChildInfo &aChildInfo)
250 {
251     Error error = Get<SettingsDriver>().Add(kKeyChildInfo, &aChildInfo, sizeof(aChildInfo));
252 
253     Log(kActionAdd, error, kKeyChildInfo, &aChildInfo);
254 
255     return error;
256 }
257 
DeleteAllChildInfo(void)258 Error Settings::DeleteAllChildInfo(void)
259 {
260     Error error = Get<SettingsDriver>().Delete(kKeyChildInfo);
261 
262     Log(kActionDeleteAll, error, kKeyChildInfo);
263 
264     return error;
265 }
266 
ChildInfoIterator(Instance & aInstance)267 Settings::ChildInfoIterator::ChildInfoIterator(Instance &aInstance)
268     : SettingsBase(aInstance)
269     , mIndex(0)
270     , mIsDone(false)
271 {
272     Read();
273 }
274 
Advance(void)275 void Settings::ChildInfoIterator::Advance(void)
276 {
277     if (!mIsDone)
278     {
279         mIndex++;
280         Read();
281     }
282 }
283 
Delete(void)284 Error Settings::ChildInfoIterator::Delete(void)
285 {
286     Error error = kErrorNone;
287 
288     VerifyOrExit(!mIsDone, error = kErrorInvalidState);
289     SuccessOrExit(error = Get<SettingsDriver>().Delete(kKeyChildInfo, mIndex));
290 
291 exit:
292     Log(kActionRemove, error, kKeyChildInfo, &mChildInfo);
293     return error;
294 }
295 
Read(void)296 void Settings::ChildInfoIterator::Read(void)
297 {
298     uint16_t length = sizeof(ChildInfo);
299     Error    error;
300 
301     mChildInfo.Init();
302     SuccessOrExit(
303         error = Get<SettingsDriver>().Get(kKeyChildInfo, mIndex, reinterpret_cast<uint8_t *>(&mChildInfo), &length));
304 
305 exit:
306     Log(kActionRead, error, kKeyChildInfo, &mChildInfo);
307     mIsDone = (error != kErrorNone);
308 }
309 #endif // OPENTHREAD_FTD
310 
ReadEntry(Key aKey,void * aValue,uint16_t aMaxLength) const311 Error Settings::ReadEntry(Key aKey, void *aValue, uint16_t aMaxLength) const
312 {
313     Error    error;
314     uint16_t length = aMaxLength;
315 
316     error = Get<SettingsDriver>().Get(aKey, aValue, &length);
317     Log(kActionRead, error, aKey, aValue);
318 
319     return error;
320 }
321 
SaveEntry(Key aKey,const void * aValue,void * aPrev,uint16_t aLength)322 Error Settings::SaveEntry(Key aKey, const void *aValue, void *aPrev, uint16_t aLength)
323 {
324     Error    error      = kErrorNone;
325     uint16_t readLength = aLength;
326     Action   action     = kActionSave;
327 
328     if ((Get<SettingsDriver>().Get(aKey, aPrev, &readLength) == kErrorNone) && (readLength == aLength) &&
329         (memcmp(aValue, aPrev, aLength) == 0))
330     {
331         action = kActionResave;
332     }
333     else
334     {
335         error = Get<SettingsDriver>().Set(aKey, aValue, aLength);
336     }
337 
338     Log(action, error, aKey, aValue);
339 
340     return error;
341 }
342 
DeleteEntry(Key aKey)343 Error Settings::DeleteEntry(Key aKey)
344 {
345     Error error = Get<SettingsDriver>().Delete(aKey);
346 
347     Log(kActionDelete, error, aKey);
348 
349     return error;
350 }
351 
Log(Action aAction,Error aError,Key aKey,const void * aValue)352 void Settings::Log(Action aAction, Error aError, Key aKey, const void *aValue)
353 {
354     OT_UNUSED_VARIABLE(aAction);
355     OT_UNUSED_VARIABLE(aKey);
356     OT_UNUSED_VARIABLE(aError);
357     OT_UNUSED_VARIABLE(aValue);
358 
359     if (aError != kErrorNone)
360     {
361         // Log error if log level is at "warn" or higher.
362 
363 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
364         const char *actionText = "";
365 
366         switch (aAction)
367         {
368         case kActionSave:
369         case kActionResave:
370             actionText = "saving";
371             break;
372 
373         case kActionDelete:
374             VerifyOrExit(aError != kErrorNotFound);
375             actionText = "deleting";
376             break;
377 
378 #if OPENTHREAD_FTD
379         case kActionAdd:
380             actionText = "adding";
381             break;
382 
383         case kActionRemove:
384             VerifyOrExit(aError != kErrorNotFound);
385             actionText = "removing";
386             break;
387 
388         case kActionDeleteAll:
389             VerifyOrExit(aError != kErrorNotFound);
390             actionText = "deleting all";
391             break;
392 #endif
393         case kActionRead:
394             ExitNow();
395         }
396 
397         LogWarn("Error %s %s %s", ErrorToString(aError), actionText, KeyToString(aKey));
398 
399 #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
400 
401         ExitNow();
402     }
403 
404     // We reach here when `aError` is `kErrorNone`.
405     // Log success if log level is at "info" or higher.
406 
407 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
408     if (aValue != nullptr)
409     {
410         switch (aKey)
411         {
412         case kKeyNetworkInfo:
413             reinterpret_cast<const NetworkInfo *>(aValue)->Log(aAction);
414             break;
415 
416         case kKeyParentInfo:
417             reinterpret_cast<const ParentInfo *>(aValue)->Log(aAction);
418             break;
419 
420 #if OPENTHREAD_FTD
421         case kKeyChildInfo:
422             reinterpret_cast<const ChildInfo *>(aValue)->Log(aAction);
423             break;
424 #endif
425 
426 #if OPENTHREAD_CONFIG_DUA_ENABLE
427         case kKeyDadInfo:
428             reinterpret_cast<const DadInfo *>(aValue)->Log(aAction);
429             break;
430 #endif
431 
432 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
433         case kKeyBrUlaPrefix:
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         LogInfo("%s %s", ActionToString(aAction), KeyToString(aKey));
463     }
464 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
465 
466 exit:
467     return;
468 }
469 
470 } // namespace ot
471 
472 //---------------------------------------------------------------------------------------------------------------------
473 // Default/weak implementation of settings platform APIs
474 
otPlatSettingsSetCriticalKeys(otInstance * aInstance,const uint16_t * aKeys,uint16_t aKeysLength)475 OT_TOOL_WEAK void otPlatSettingsSetCriticalKeys(otInstance *aInstance, const uint16_t *aKeys, uint16_t aKeysLength)
476 {
477     OT_UNUSED_VARIABLE(aInstance);
478     OT_UNUSED_VARIABLE(aKeys);
479     OT_UNUSED_VARIABLE(aKeysLength);
480 }
481