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