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