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