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