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 "instance/instance.hpp"
37 
38 namespace ot {
39 
40 RegisterLogModule("Settings");
41 
42 //---------------------------------------------------------------------------------------------------------------------
43 // SettingsBase
44 
45 // LCOV_EXCL_START
46 
47 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
48 
Log(Action aAction) const49 void SettingsBase::NetworkInfo::Log(Action aAction) const
50 {
51     LogInfo("%s NetworkInfo {rloc:0x%04x, extaddr:%s, role:%s, mode:0x%02x, version:%u, keyseq:0x%lx, ...",
52             ActionToString(aAction), GetRloc16(), GetExtAddress().ToString().AsCString(),
53             Mle::RoleToString(static_cast<Mle::DeviceRole>(GetRole())), GetDeviceMode(), GetVersion(),
54             ToUlong(GetKeySequence()));
55 
56     LogInfo("... pid:0x%lx, mlecntr:0x%lx, maccntr:0x%lx, mliid:%s}", ToUlong(GetPreviousPartitionId()),
57             ToUlong(GetMleFrameCounter()), ToUlong(GetMacFrameCounter()), GetMeshLocalIid().ToString().AsCString());
58 }
59 
Log(Action aAction) const60 void SettingsBase::ParentInfo::Log(Action aAction) const
61 {
62     LogInfo("%s ParentInfo {extaddr:%s, version:%u}", ActionToString(aAction), GetExtAddress().ToString().AsCString(),
63             GetVersion());
64 }
65 
66 #if OPENTHREAD_FTD
Log(Action aAction) const67 void SettingsBase::ChildInfo::Log(Action aAction) const
68 {
69     LogInfo("%s ChildInfo {rloc:0x%04x, extaddr:%s, timeout:%lu, mode:0x%02x, version:%u}", ActionToString(aAction),
70             GetRloc16(), GetExtAddress().ToString().AsCString(), ToUlong(GetTimeout()), GetMode(), GetVersion());
71 }
72 #endif
73 
74 #if OPENTHREAD_CONFIG_DUA_ENABLE
Log(Action aAction) const75 void SettingsBase::DadInfo::Log(Action aAction) const
76 {
77     LogInfo("%s DadInfo {DadCounter:%2d}", ActionToString(aAction), GetDadCounter());
78 }
79 #endif
80 
81 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
LogPrefix(Action aAction,Key aKey,const Ip6::Prefix & aPrefix)82 void SettingsBase::LogPrefix(Action aAction, Key aKey, const Ip6::Prefix &aPrefix)
83 {
84     LogInfo("%s %s %s", ActionToString(aAction), KeyToString(aKey), aPrefix.ToString().AsCString());
85 }
86 #endif
87 
88 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
Log(Action aAction) const89 void SettingsBase::SrpClientInfo::Log(Action aAction) const
90 {
91     LogInfo("%s SrpClientInfo {Server:[%s]:%u}", ActionToString(aAction), GetServerAddress().ToString().AsCString(),
92             GetServerPort());
93 }
94 #endif
95 
96 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
Log(Action aAction) const97 void SettingsBase::SrpServerInfo::Log(Action aAction) const
98 {
99     LogInfo("%s SrpServerInfo {port:%u}", ActionToString(aAction), GetPort());
100 }
101 #endif
102 
103 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
Log(Action aAction,const MeshCoP::BorderAgent::Id & aId)104 void SettingsBase::BorderAgentId::Log(Action aAction, const MeshCoP::BorderAgent::Id &aId)
105 {
106     static constexpr uint8_t kStringSize = sizeof(MeshCoP::BorderAgent::Id) * 2 + 1;
107 
108     String<kStringSize> string;
109 
110     string.AppendHexBytes(aId.mId, sizeof(aId));
111     LogInfo("%s BorderAgentId {id:%s}", ActionToString(aAction), string.AsCString());
112 }
113 #endif
114 
115 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
116 
117 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
ActionToString(Action aAction)118 const char *SettingsBase::ActionToString(Action aAction)
119 {
120     static const char *const kActionStrings[] = {
121         "Read",     // (0) kActionRead
122         "Saved",    // (1) kActionSave
123         "Re-saved", // (2) kActionResave
124         "Deleted",  // (3) kActionDelete
125 #if OPENTHREAD_FTD
126         "Added",      // (4) kActionAdd,
127         "Removed",    // (5) kActionRemove,
128         "Deleted all" // (6) kActionDeleteAll
129 #endif
130     };
131 
132     struct EnumCheck
133     {
134         InitEnumValidatorCounter();
135         ValidateNextEnum(kActionRead);
136         ValidateNextEnum(kActionSave);
137         ValidateNextEnum(kActionResave);
138         ValidateNextEnum(kActionDelete);
139 #if OPENTHREAD_FTD
140         ValidateNextEnum(kActionAdd);
141         ValidateNextEnum(kActionRemove);
142         ValidateNextEnum(kActionDeleteAll);
143 #endif
144     };
145 
146     return kActionStrings[aAction];
147 }
148 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
149 
150 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
KeyToString(Key aKey)151 const char *SettingsBase::KeyToString(Key aKey)
152 {
153     static const char *const kKeyStrings[] = {
154         "",                  // (0)  (Unused)
155         "ActiveDataset",     // (1)  kKeyActiveDataset
156         "PendingDataset",    // (2)  kKeyPendingDataset
157         "NetworkInfo",       // (3)  kKeyNetworkInfo
158         "ParentInfo",        // (4)  kKeyParentInfo
159         "ChildInfo",         // (5)  kKeyChildInfo
160         "",                  // (6)  Removed (previously auto-start).
161         "SlaacIidSecretKey", // (7)  kKeySlaacIidSecretKey
162         "DadInfo",           // (8)  kKeyDadInfo
163         "",                  // (9)  Removed (previously OMR prefix).
164         "",                  // (10) Removed (previously on-link prefix).
165         "SrpEcdsaKey",       // (11) kKeySrpEcdsaKey
166         "SrpClientInfo",     // (12) kKeySrpClientInfo
167         "SrpServerInfo",     // (13) kKeySrpServerInfo
168         "",                  // (14) Removed (previously NAT64 prefix)
169         "BrUlaPrefix",       // (15) kKeyBrUlaPrefix
170         "BrOnLinkPrefixes",  // (16) kKeyBrOnLinkPrefixes
171         "BorderAgentId"      // (17) kKeyBorderAgentId
172     };
173 
174     struct EnumCheck
175     {
176         InitEnumValidatorCounter();
177         SkipNextEnum();
178         ValidateNextEnum(kKeyActiveDataset);
179         ValidateNextEnum(kKeyPendingDataset);
180         ValidateNextEnum(kKeyNetworkInfo);
181         ValidateNextEnum(kKeyParentInfo);
182         ValidateNextEnum(kKeyChildInfo);
183         SkipNextEnum();
184         ValidateNextEnum(kKeySlaacIidSecretKey);
185         ValidateNextEnum(kKeyDadInfo);
186         SkipNextEnum();
187         SkipNextEnum();
188         ValidateNextEnum(kKeySrpEcdsaKey);
189         ValidateNextEnum(kKeySrpClientInfo);
190         ValidateNextEnum(kKeySrpServerInfo);
191         SkipNextEnum();
192         ValidateNextEnum(kKeyBrUlaPrefix);
193         ValidateNextEnum(kKeyBrOnLinkPrefixes);
194         ValidateNextEnum(kKeyBorderAgentId);
195     };
196 
197     static_assert(kLastKey == kKeyBorderAgentId, "kLastKey is not valid");
198 
199     OT_ASSERT(aKey <= kLastKey);
200 
201     return kKeyStrings[aKey];
202 }
203 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
204 
205 // LCOV_EXCL_STOP
206 
207 //---------------------------------------------------------------------------------------------------------------------
208 // Settings
209 
210 // This array contains sensitive keys that should be stored in the secure area.
211 const uint16_t Settings::kSensitiveKeys[] = {
212     SettingsBase::kKeyActiveDataset,
213     SettingsBase::kKeyPendingDataset,
214     SettingsBase::kKeySrpEcdsaKey,
215 };
216 
Init(void)217 void Settings::Init(void) { Get<SettingsDriver>().Init(kSensitiveKeys, GetArrayLength(kSensitiveKeys)); }
218 
Deinit(void)219 void Settings::Deinit(void) { Get<SettingsDriver>().Deinit(); }
220 
Wipe(void)221 void Settings::Wipe(void)
222 {
223     Get<SettingsDriver>().Wipe();
224     LogInfo("Wiped all info");
225 }
226 
KeyForDatasetType(MeshCoP::Dataset::Type aType)227 Settings::Key Settings::KeyForDatasetType(MeshCoP::Dataset::Type aType)
228 {
229     return (aType == MeshCoP::Dataset::kActive) ? kKeyActiveDataset : kKeyPendingDataset;
230 }
231 
SaveOperationalDataset(MeshCoP::Dataset::Type aType,const MeshCoP::Dataset & aDataset)232 void Settings::SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshCoP::Dataset &aDataset)
233 {
234     Key   key   = KeyForDatasetType(aType);
235     Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetLength());
236 
237     Log(kActionSave, error, key);
238 
239     SuccessOrAssert(error);
240 }
241 
ReadOperationalDataset(MeshCoP::Dataset::Type aType,MeshCoP::Dataset & aDataset) const242 Error Settings::ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Dataset &aDataset) const
243 {
244     Error    error  = kErrorNone;
245     uint16_t length = MeshCoP::Dataset::kMaxLength;
246 
247     SuccessOrExit(error = Get<SettingsDriver>().Get(KeyForDatasetType(aType), aDataset.GetBytes(), &length));
248     VerifyOrExit(length <= MeshCoP::Dataset::kMaxLength, error = kErrorNotFound);
249 
250     aDataset.SetLength(static_cast<uint8_t>(length));
251 
252 exit:
253     OT_ASSERT(error != kErrorNotImplemented);
254     return error;
255 }
256 
DeleteOperationalDataset(MeshCoP::Dataset::Type aType)257 void Settings::DeleteOperationalDataset(MeshCoP::Dataset::Type aType)
258 {
259     Key   key   = KeyForDatasetType(aType);
260     Error error = Get<SettingsDriver>().Delete(key);
261 
262     Log(kActionDelete, error, key);
263     OT_ASSERT(error != kErrorNotImplemented);
264 }
265 
266 #if OPENTHREAD_FTD
AddChildInfo(const ChildInfo & aChildInfo)267 Error Settings::AddChildInfo(const ChildInfo &aChildInfo)
268 {
269     Error error = Get<SettingsDriver>().Add(kKeyChildInfo, &aChildInfo, sizeof(aChildInfo));
270 
271     Log(kActionAdd, error, kKeyChildInfo, &aChildInfo);
272 
273     return error;
274 }
275 
DeleteAllChildInfo(void)276 Error Settings::DeleteAllChildInfo(void)
277 {
278     Error error = Get<SettingsDriver>().Delete(kKeyChildInfo);
279 
280     Log(kActionDeleteAll, error, kKeyChildInfo);
281 
282     return error;
283 }
284 
ChildInfoIterator(Instance & aInstance)285 Settings::ChildInfoIterator::ChildInfoIterator(Instance &aInstance)
286     : SettingsBase(aInstance)
287     , mIndex(0)
288     , mIsDone(false)
289 {
290     Read();
291 }
292 
Advance(void)293 void Settings::ChildInfoIterator::Advance(void)
294 {
295     if (!mIsDone)
296     {
297         mIndex++;
298         Read();
299     }
300 }
301 
Delete(void)302 Error Settings::ChildInfoIterator::Delete(void)
303 {
304     Error error = kErrorNone;
305 
306     VerifyOrExit(!mIsDone, error = kErrorInvalidState);
307     SuccessOrExit(error = Get<SettingsDriver>().Delete(kKeyChildInfo, mIndex));
308 
309 exit:
310     Log(kActionRemove, error, kKeyChildInfo, &mChildInfo);
311     return error;
312 }
313 
Read(void)314 void Settings::ChildInfoIterator::Read(void)
315 {
316     uint16_t length = sizeof(ChildInfo);
317     Error    error;
318 
319     mChildInfo.Init();
320     SuccessOrExit(
321         error = Get<SettingsDriver>().Get(kKeyChildInfo, mIndex, reinterpret_cast<uint8_t *>(&mChildInfo), &length));
322 
323 exit:
324     Log(kActionRead, error, kKeyChildInfo, &mChildInfo);
325     mIsDone = (error != kErrorNone);
326 }
327 #endif // OPENTHREAD_FTD
328 
329 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
AddOrUpdateBrOnLinkPrefix(const BrOnLinkPrefix & aBrOnLinkPrefix)330 Error Settings::AddOrUpdateBrOnLinkPrefix(const BrOnLinkPrefix &aBrOnLinkPrefix)
331 {
332     Error          error = kErrorNone;
333     int            index = 0;
334     BrOnLinkPrefix brPrefix;
335     bool           didUpdate = false;
336 
337     while (ReadBrOnLinkPrefix(index, brPrefix) == kErrorNone)
338     {
339         if (brPrefix.GetPrefix() == aBrOnLinkPrefix.GetPrefix())
340         {
341             if (brPrefix.GetLifetime() == aBrOnLinkPrefix.GetLifetime())
342             {
343                 // Existing entry fully matches `aBrOnLinkPrefix`.
344                 // No need to make any changes.
345                 ExitNow();
346             }
347 
348             SuccessOrExit(error = Get<SettingsDriver>().Delete(kKeyBrOnLinkPrefixes, index));
349             didUpdate = true;
350             break;
351         }
352 
353         index++;
354     }
355 
356     SuccessOrExit(error = Get<SettingsDriver>().Add(kKeyBrOnLinkPrefixes, &aBrOnLinkPrefix, sizeof(BrOnLinkPrefix)));
357     brPrefix.Log(didUpdate ? "Updated" : "Added");
358 
359 exit:
360     return error;
361 }
362 
RemoveBrOnLinkPrefix(const Ip6::Prefix & aPrefix)363 Error Settings::RemoveBrOnLinkPrefix(const Ip6::Prefix &aPrefix)
364 {
365     Error          error = kErrorNotFound;
366     BrOnLinkPrefix brPrefix;
367 
368     for (int index = 0; ReadBrOnLinkPrefix(index, brPrefix) == kErrorNone; index++)
369     {
370         if (brPrefix.GetPrefix() == aPrefix)
371         {
372             SuccessOrExit(error = Get<SettingsDriver>().Delete(kKeyBrOnLinkPrefixes, index));
373             brPrefix.Log("Removed");
374             break;
375         }
376     }
377 
378 exit:
379     return error;
380 }
381 
DeleteAllBrOnLinkPrefixes(void)382 Error Settings::DeleteAllBrOnLinkPrefixes(void) { return Get<SettingsDriver>().Delete(kKeyBrOnLinkPrefixes); }
383 
ReadBrOnLinkPrefix(int aIndex,BrOnLinkPrefix & aBrOnLinkPrefix)384 Error Settings::ReadBrOnLinkPrefix(int aIndex, BrOnLinkPrefix &aBrOnLinkPrefix)
385 {
386     uint16_t length = sizeof(BrOnLinkPrefix);
387 
388     aBrOnLinkPrefix.Init();
389 
390     return Get<SettingsDriver>().Get(kKeyBrOnLinkPrefixes, aIndex, &aBrOnLinkPrefix, &length);
391 }
392 
Log(const char * aActionText) const393 void Settings::BrOnLinkPrefix::Log(const char *aActionText) const
394 {
395     OT_UNUSED_VARIABLE(aActionText);
396 
397     LogInfo("%s %s entry {prefix:%s,lifetime:%lu}", aActionText, KeyToString(kKeyBrOnLinkPrefixes),
398             GetPrefix().ToString().AsCString(), ToUlong(GetLifetime()));
399 }
400 
401 #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
402 
ReadEntry(Key aKey,void * aValue,uint16_t aMaxLength) const403 Error Settings::ReadEntry(Key aKey, void *aValue, uint16_t aMaxLength) const
404 {
405     Error    error;
406     uint16_t length = aMaxLength;
407 
408     error = Get<SettingsDriver>().Get(aKey, aValue, &length);
409     Log(kActionRead, error, aKey, aValue);
410 
411     return error;
412 }
413 
SaveEntry(Key aKey,const void * aValue,void * aPrev,uint16_t aLength)414 Error Settings::SaveEntry(Key aKey, const void *aValue, void *aPrev, uint16_t aLength)
415 {
416     Error    error      = kErrorNone;
417     uint16_t readLength = aLength;
418     Action   action     = kActionSave;
419 
420     if ((Get<SettingsDriver>().Get(aKey, aPrev, &readLength) == kErrorNone) && (readLength == aLength) &&
421         (memcmp(aValue, aPrev, aLength) == 0))
422     {
423         action = kActionResave;
424     }
425     else
426     {
427         error = Get<SettingsDriver>().Set(aKey, aValue, aLength);
428     }
429 
430     Log(action, error, aKey, aValue);
431 
432     return error;
433 }
434 
DeleteEntry(Key aKey)435 Error Settings::DeleteEntry(Key aKey)
436 {
437     Error error = Get<SettingsDriver>().Delete(aKey);
438 
439     Log(kActionDelete, error, aKey);
440 
441     return error;
442 }
443 
Log(Action aAction,Error aError,Key aKey,const void * aValue)444 void Settings::Log(Action aAction, Error aError, Key aKey, const void *aValue)
445 {
446     OT_UNUSED_VARIABLE(aAction);
447     OT_UNUSED_VARIABLE(aKey);
448     OT_UNUSED_VARIABLE(aError);
449     OT_UNUSED_VARIABLE(aValue);
450 
451     if (aError != kErrorNone)
452     {
453         // Log error if log level is at "warn" or higher.
454 
455 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
456         const char *actionText = "";
457 
458         switch (aAction)
459         {
460         case kActionSave:
461         case kActionResave:
462             actionText = "saving";
463             break;
464 
465         case kActionDelete:
466             VerifyOrExit(aError != kErrorNotFound);
467             actionText = "deleting";
468             break;
469 
470 #if OPENTHREAD_FTD
471         case kActionAdd:
472             actionText = "adding";
473             break;
474 
475         case kActionRemove:
476             VerifyOrExit(aError != kErrorNotFound);
477             actionText = "removing";
478             break;
479 
480         case kActionDeleteAll:
481             VerifyOrExit(aError != kErrorNotFound);
482             actionText = "deleting all";
483             break;
484 #endif
485         case kActionRead:
486             ExitNow();
487         }
488 
489         LogWarn("Error %s %s %s", ErrorToString(aError), actionText, KeyToString(aKey));
490 
491 #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
492 
493         ExitNow();
494     }
495 
496     // We reach here when `aError` is `kErrorNone`.
497     // Log success if log level is at "info" or higher.
498 
499 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
500     if (aValue != nullptr)
501     {
502         switch (aKey)
503         {
504         case kKeyNetworkInfo:
505             reinterpret_cast<const NetworkInfo *>(aValue)->Log(aAction);
506             break;
507 
508         case kKeyParentInfo:
509             reinterpret_cast<const ParentInfo *>(aValue)->Log(aAction);
510             break;
511 
512 #if OPENTHREAD_FTD
513         case kKeyChildInfo:
514             reinterpret_cast<const ChildInfo *>(aValue)->Log(aAction);
515             break;
516 #endif
517 
518 #if OPENTHREAD_CONFIG_DUA_ENABLE
519         case kKeyDadInfo:
520             reinterpret_cast<const DadInfo *>(aValue)->Log(aAction);
521             break;
522 #endif
523 
524 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
525         case kKeyBrUlaPrefix:
526             LogPrefix(aAction, aKey, *reinterpret_cast<const Ip6::Prefix *>(aValue));
527             break;
528 #endif
529 
530 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
531         case kKeySrpClientInfo:
532             reinterpret_cast<const SrpClientInfo *>(aValue)->Log(aAction);
533             break;
534 #endif
535 
536 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
537         case kKeySrpServerInfo:
538             reinterpret_cast<const SrpServerInfo *>(aValue)->Log(aAction);
539             break;
540 #endif
541 
542 #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE
543         case kKeyBorderAgentId:
544             BorderAgentId::Log(aAction, *reinterpret_cast<const MeshCoP::BorderAgent::Id *>(aValue));
545             break;
546 #endif
547 
548         default:
549             // For any other keys, we do not want to include the value
550             // in the log, so even if it is given we set `aValue` to
551             // `nullptr`. This ensures that we just log the action and
552             // the key.
553             aValue = nullptr;
554             break;
555         }
556     }
557 
558     if (aValue == nullptr)
559     {
560         LogInfo("%s %s", ActionToString(aAction), KeyToString(aKey));
561     }
562 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
563 
564 exit:
565     return;
566 }
567 
568 } // namespace ot
569 
570 //---------------------------------------------------------------------------------------------------------------------
571 // Default/weak implementation of settings platform APIs
572 
otPlatSettingsSetCriticalKeys(otInstance * aInstance,const uint16_t * aKeys,uint16_t aKeysLength)573 OT_TOOL_WEAK void otPlatSettingsSetCriticalKeys(otInstance *aInstance, const uint16_t *aKeys, uint16_t aKeysLength)
574 {
575     OT_UNUSED_VARIABLE(aInstance);
576     OT_UNUSED_VARIABLE(aKeys);
577     OT_UNUSED_VARIABLE(aKeysLength);
578 }
579