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/code_utils.hpp"
37 #include "common/instance.hpp"
38 #include "common/locator_getters.hpp"
39 #include "common/logging.hpp"
40 #include "meshcop/dataset.hpp"
41 #include "thread/mle.hpp"
42
43 namespace ot {
44
45 //---------------------------------------------------------------------------------------------------------------------
46 // SettingsBase
47
48 // LCOV_EXCL_START
49
50 #if OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
51
Log(Action aAction) const52 void SettingsBase::NetworkInfo::Log(Action aAction) const
53 {
54 otLogInfoCore(
55 "[settings] %s NetworkInfo {rloc:0x%04x, extaddr:%s, role:%s, mode:0x%02x, version:%hu, keyseq:0x%x, ...",
56 ActionToString(aAction), GetRloc16(), GetExtAddress().ToString().AsCString(),
57 Mle::Mle::RoleToString(static_cast<Mle::DeviceRole>(GetRole())), GetDeviceMode(), GetVersion(),
58 GetKeySequence());
59
60 otLogInfoCore("[settings] ... pid:0x%x, mlecntr:0x%x, maccntr:0x%x, mliid:%s}", GetPreviousPartitionId(),
61 GetMleFrameCounter(), GetMacFrameCounter(), GetMeshLocalIid().ToString().AsCString());
62 }
63
Log(Action aAction) const64 void SettingsBase::ParentInfo::Log(Action aAction) const
65 {
66 otLogInfoCore("[settings] %s ParentInfo {extaddr:%s, version:%hu}", ActionToString(aAction),
67 GetExtAddress().ToString().AsCString(), GetVersion());
68 }
69
70 #if OPENTHREAD_FTD
Log(Action aAction) const71 void SettingsBase::ChildInfo::Log(Action aAction) const
72 {
73 otLogInfoCore("[settings] %s ChildInfo {rloc:0x%04x, extaddr:%s, timeout:%u, mode:0x%02x, version:%hu}",
74 ActionToString(aAction), GetRloc16(), GetExtAddress().ToString().AsCString(), GetTimeout(), GetMode(),
75 GetVersion());
76 }
77 #endif
78
79 #if OPENTHREAD_CONFIG_DUA_ENABLE
Log(Action aAction) const80 void SettingsBase::DadInfo::Log(Action aAction) const
81 {
82 otLogInfoCore("[settings] %s DadInfo {DadCounter:%2d}", ActionToString(aAction), GetDadCounter());
83 }
84 #endif
85
86 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
LogPrefix(Action aAction,Key aKey,const Ip6::Prefix & aPrefix)87 void SettingsBase::LogPrefix(Action aAction, Key aKey, const Ip6::Prefix &aPrefix)
88 {
89 otLogInfoCore("[settings] %s %s %s", ActionToString(aAction), KeyToString(aKey), aPrefix.ToString().AsCString());
90 }
91 #endif
92
93 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
Log(Action aAction) const94 void SettingsBase::SrpClientInfo::Log(Action aAction) const
95 {
96 otLogInfoCore("[settings] %s SrpClientInfo {Server:[%s]:%u}", ActionToString(aAction),
97 GetServerAddress().ToString().AsCString(), GetServerPort());
98 }
99 #endif
100
101 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
Log(Action aAction) const102 void SettingsBase::SrpServerInfo::Log(Action aAction) const
103 {
104 otLogInfoCore("[settings] %s SrpServerInfo {port:%u}", ActionToString(aAction), GetPort());
105 }
106 #endif
107
108 #endif // OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
109
110 #if OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
ActionToString(Action aAction)111 const char *SettingsBase::ActionToString(Action aAction)
112 {
113 static const char *const kActionStrings[] = {
114 "Read", // (0) kActionRead
115 "Saved", // (1) kActionSave
116 "Re-saved", // (2) kActionResave
117 "Deleted", // (3) kActionDelete
118 #if OPENTHREAD_FTD
119 "Added", // (4) kActionAdd,
120 "Removed", // (5) kActionRemove,
121 "Deleted all" // (6) kActionDeleteAll
122 #endif
123 };
124
125 static_assert(0 == kActionRead, "kActionRead value is incorrect");
126 static_assert(1 == kActionSave, "kActionSave value is incorrect");
127 static_assert(2 == kActionResave, "kActionResave value is incorrect");
128 static_assert(3 == kActionDelete, "kActionDelete value is incorrect");
129 #if OPENTHREAD_FTD
130 static_assert(4 == kActionAdd, "kActionAdd value is incorrect");
131 static_assert(5 == kActionRemove, "kActionRemove value is incorrect");
132 static_assert(6 == kActionDeleteAll, "kActionDeleteAll value is incorrect");
133 #endif
134
135 return kActionStrings[aAction];
136 }
137 #endif // OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
138
139 #if OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
KeyToString(Key aKey)140 const char *SettingsBase::KeyToString(Key aKey)
141 {
142 static const char *const kKeyStrings[] = {
143 "", // (0) (Unused)
144 "ActiveDataset", // (1) kKeyActiveDataset
145 "PendingDataset", // (2) kKeyPendingDataset
146 "NetworkInfo", // (3) kKeyNetworkInfo
147 "ParentInfo", // (4) kKeyParentInfo
148 "ChildInfo", // (5) kKeyChildInfo
149 "", // (6) kKeyReserved
150 "SlaacIidSecretKey", // (7) kKeySlaacIidSecretKey
151 "DadInfo", // (8) kKeyDadInfo
152 "OmrPrefix", // (9) kKeyOmrPrefix
153 "OnLinkPrefix", // (10) kKeyOnLinkPrefix
154 "SrpEcdsaKey", // (11) kKeySrpEcdsaKey
155 "SrpClientInfo", // (12) kKeySrpClientInfo
156 "SrpServerInfo", // (13) kKeySrpServerInfo
157 };
158
159 static_assert(1 == kKeyActiveDataset, "kKeyActiveDataset value is incorrect");
160 static_assert(2 == kKeyPendingDataset, "kKeyPendingDataset value is incorrect");
161 static_assert(3 == kKeyNetworkInfo, "kKeyNetworkInfo value is incorrect");
162 static_assert(4 == kKeyParentInfo, "kKeyParentInfo value is incorrect");
163 static_assert(5 == kKeyChildInfo, "kKeyChildInfo value is incorrect");
164 static_assert(6 == kKeyReserved, "kKeyReserved value is incorrect");
165 static_assert(7 == kKeySlaacIidSecretKey, "kKeySlaacIidSecretKey value is incorrect");
166 static_assert(8 == kKeyDadInfo, "kKeyDadInfo value is incorrect");
167 static_assert(9 == kKeyOmrPrefix, "kKeyOmrPrefix value is incorrect");
168 static_assert(10 == kKeyOnLinkPrefix, "kKeyOnLinkPrefix value is incorrect");
169 static_assert(11 == kKeySrpEcdsaKey, "kKeySrpEcdsaKey value is incorrect");
170 static_assert(12 == kKeySrpClientInfo, "kKeySrpClientInfo value is incorrect");
171 static_assert(13 == kKeySrpServerInfo, "kKeySrpServerInfo value is incorrect");
172
173 static_assert(kLastKey == kKeySrpServerInfo, "kLastKey is not valid");
174
175 OT_ASSERT(aKey <= kLastKey);
176
177 return kKeyStrings[aKey];
178 }
179 #endif // OPENTHREAD_CONFIG_LOG_UTIL && (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
180
181 // LCOV_EXCL_STOP
182
183 //---------------------------------------------------------------------------------------------------------------------
184 // Settings
185
186 // This array contains critical keys that should be stored in the secure area.
187 const uint16_t Settings::kCriticalKeys[] = {
188 SettingsBase::kKeyActiveDataset,
189 SettingsBase::kKeyPendingDataset,
190 SettingsBase::kKeySrpEcdsaKey,
191 };
192
Init(void)193 void Settings::Init(void)
194 {
195 Get<SettingsDriver>().Init();
196 Get<SettingsDriver>().SetCriticalKeys(kCriticalKeys, OT_ARRAY_LENGTH(kCriticalKeys));
197 }
198
Deinit(void)199 void Settings::Deinit(void)
200 {
201 Get<SettingsDriver>().Deinit();
202 }
203
Wipe(void)204 void Settings::Wipe(void)
205 {
206 Get<SettingsDriver>().Wipe();
207 otLogInfoCore("[settings] Wiped all info");
208 }
209
SaveOperationalDataset(bool aIsActive,const MeshCoP::Dataset & aDataset)210 Error Settings::SaveOperationalDataset(bool aIsActive, const MeshCoP::Dataset &aDataset)
211 {
212 Key key = (aIsActive ? kKeyActiveDataset : kKeyPendingDataset);
213 Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetSize());
214
215 Log(kActionSave, error, key);
216
217 return error;
218 }
219
ReadOperationalDataset(bool aIsActive,MeshCoP::Dataset & aDataset) const220 Error Settings::ReadOperationalDataset(bool aIsActive, MeshCoP::Dataset &aDataset) const
221 {
222 Error error = kErrorNone;
223 uint16_t length = MeshCoP::Dataset::kMaxSize;
224
225 SuccessOrExit(error = Get<SettingsDriver>().Get(aIsActive ? kKeyActiveDataset : kKeyPendingDataset,
226 aDataset.GetBytes(), &length));
227 VerifyOrExit(length <= MeshCoP::Dataset::kMaxSize, error = kErrorNotFound);
228
229 aDataset.SetSize(length);
230
231 exit:
232 return error;
233 }
234
DeleteOperationalDataset(bool aIsActive)235 Error Settings::DeleteOperationalDataset(bool aIsActive)
236 {
237 Key key = (aIsActive ? kKeyActiveDataset : kKeyPendingDataset);
238 Error error = Get<SettingsDriver>().Delete(key);
239
240 Log(kActionDelete, error, key);
241
242 return error;
243 }
244
245 #if OPENTHREAD_FTD
AddChildInfo(const ChildInfo & aChildInfo)246 Error Settings::AddChildInfo(const ChildInfo &aChildInfo)
247 {
248 Error error = Get<SettingsDriver>().Add(kKeyChildInfo, &aChildInfo, sizeof(aChildInfo));
249
250 Log(kActionAdd, error, kKeyChildInfo, &aChildInfo);
251
252 return error;
253 }
254
DeleteAllChildInfo(void)255 Error Settings::DeleteAllChildInfo(void)
256 {
257 Error error = Get<SettingsDriver>().Delete(kKeyChildInfo);
258
259 Log(kActionDeleteAll, error, kKeyChildInfo);
260
261 return error;
262 }
263
ChildInfoIterator(Instance & aInstance)264 Settings::ChildInfoIterator::ChildInfoIterator(Instance &aInstance)
265 : SettingsBase(aInstance)
266 , mIndex(0)
267 , mIsDone(false)
268 {
269 Read();
270 }
271
Advance(void)272 void Settings::ChildInfoIterator::Advance(void)
273 {
274 if (!mIsDone)
275 {
276 mIndex++;
277 Read();
278 }
279 }
280
Delete(void)281 Error Settings::ChildInfoIterator::Delete(void)
282 {
283 Error error = kErrorNone;
284
285 VerifyOrExit(!mIsDone, error = kErrorInvalidState);
286 SuccessOrExit(error = Get<SettingsDriver>().Delete(kKeyChildInfo, mIndex));
287
288 exit:
289 Log(kActionRemove, error, kKeyChildInfo, &mChildInfo);
290 return error;
291 }
292
Read(void)293 void Settings::ChildInfoIterator::Read(void)
294 {
295 uint16_t length = sizeof(ChildInfo);
296 Error error;
297
298 mChildInfo.Init();
299 SuccessOrExit(
300 error = Get<SettingsDriver>().Get(kKeyChildInfo, mIndex, reinterpret_cast<uint8_t *>(&mChildInfo), &length));
301
302 exit:
303 Log(kActionRead, error, kKeyChildInfo, &mChildInfo);
304 mIsDone = (error != kErrorNone);
305 }
306 #endif // OPENTHREAD_FTD
307
ReadEntry(Key aKey,void * aValue,uint16_t aMaxLength) const308 Error Settings::ReadEntry(Key aKey, void *aValue, uint16_t aMaxLength) const
309 {
310 Error error;
311 uint16_t length = aMaxLength;
312
313 error = Get<SettingsDriver>().Get(aKey, aValue, &length);
314 Log(kActionRead, error, aKey, aValue);
315
316 return error;
317 }
318
SaveEntry(Key aKey,const void * aValue,void * aPrev,uint16_t aLength)319 Error Settings::SaveEntry(Key aKey, const void *aValue, void *aPrev, uint16_t aLength)
320 {
321 Error error = kErrorNone;
322 uint16_t readLength = aLength;
323 Action action = kActionSave;
324
325 if ((Get<SettingsDriver>().Get(aKey, aPrev, &readLength) == kErrorNone) && (readLength == aLength) &&
326 (memcmp(aValue, aPrev, aLength) == 0))
327 {
328 action = kActionResave;
329 }
330 else
331 {
332 error = Get<SettingsDriver>().Set(aKey, aValue, aLength);
333 }
334
335 Log(action, error, aKey, aValue);
336
337 return error;
338 }
339
DeleteEntry(Key aKey)340 Error Settings::DeleteEntry(Key aKey)
341 {
342 Error error = Get<SettingsDriver>().Delete(aKey);
343
344 Log(kActionDelete, error, aKey);
345
346 return error;
347 }
348
Log(Action aAction,Error aError,Key aKey,const void * aValue)349 void Settings::Log(Action aAction, Error aError, Key aKey, const void *aValue)
350 {
351 OT_UNUSED_VARIABLE(aAction);
352 OT_UNUSED_VARIABLE(aKey);
353 OT_UNUSED_VARIABLE(aError);
354 OT_UNUSED_VARIABLE(aValue);
355
356 #if OPENTHREAD_CONFIG_LOG_UTIL
357
358 if (aError != kErrorNone)
359 {
360 // Log error if log level is at "warn" or higher.
361
362 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
363 const char *actionText = "";
364
365 switch (aAction)
366 {
367 case kActionSave:
368 case kActionResave:
369 actionText = "saving";
370 break;
371
372 case kActionDelete:
373 VerifyOrExit(aError != kErrorNotFound);
374 actionText = "deleting";
375 break;
376
377 #if OPENTHREAD_FTD
378 case kActionAdd:
379 actionText = "adding";
380 break;
381
382 case kActionRemove:
383 VerifyOrExit(aError != kErrorNotFound);
384 actionText = "removing";
385 break;
386
387 case kActionDeleteAll:
388 VerifyOrExit(aError != kErrorNotFound);
389 actionText = "deleting all";
390 break;
391 #endif
392 case kActionRead:
393 ExitNow();
394 }
395
396 otLogWarnCore("[settings] Error %s %s %s", ErrorToString(aError), actionText, KeyToString(aKey));
397
398 #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
399
400 ExitNow();
401 }
402
403 // We reach here when `aError` is `kErrorNone`.
404 // Log success if log level is at "info" or higher.
405
406 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
407 if (aValue != nullptr)
408 {
409 switch (aKey)
410 {
411 case kKeyNetworkInfo:
412 reinterpret_cast<const NetworkInfo *>(aValue)->Log(aAction);
413 break;
414
415 case kKeyParentInfo:
416 reinterpret_cast<const ParentInfo *>(aValue)->Log(aAction);
417 break;
418
419 #if OPENTHREAD_FTD
420 case kKeyChildInfo:
421 reinterpret_cast<const ChildInfo *>(aValue)->Log(aAction);
422 break;
423 #endif
424
425 #if OPENTHREAD_CONFIG_DUA_ENABLE
426 case kKeyDadInfo:
427 reinterpret_cast<const DadInfo *>(aValue)->Log(aAction);
428 break;
429 #endif
430
431 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
432 case kKeyOmrPrefix:
433 case kKeyOnLinkPrefix:
434 LogPrefix(aAction, aKey, *reinterpret_cast<const Ip6::Prefix *>(aValue));
435 break;
436 #endif
437
438 #if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
439 case kKeySrpClientInfo:
440 reinterpret_cast<const SrpClientInfo *>(aValue)->Log(aAction);
441 break;
442 #endif
443
444 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
445 case kKeySrpServerInfo:
446 reinterpret_cast<const SrpServerInfo *>(aValue)->Log(aAction);
447 break;
448 #endif
449
450 default:
451 // For any other keys, we do not want to include the value
452 // in the log, so even if it is given we set `aValue` to
453 // `nullptr`. This ensures that we just log the action and
454 // the key.
455 aValue = nullptr;
456 break;
457 }
458 }
459
460 if (aValue == nullptr)
461 {
462 otLogInfoCore("[settings] %s %s", ActionToString(aAction), KeyToString(aKey));
463 }
464 #endif // (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
465
466 exit:
467
468 #endif // OPENTHREAD_CONFIG_LOG_UTIL
469 return;
470 }
471
472 } // namespace ot
473
474 //---------------------------------------------------------------------------------------------------------------------
475 // Default/weak implementation of settings platform APIs
476
otPlatSettingsSetCriticalKeys(otInstance * aInstance,const uint16_t * aKeys,uint16_t aKeysLength)477 OT_TOOL_WEAK void otPlatSettingsSetCriticalKeys(otInstance *aInstance, const uint16_t *aKeys, uint16_t aKeysLength)
478 {
479 OT_UNUSED_VARIABLE(aInstance);
480 OT_UNUSED_VARIABLE(aKeys);
481 OT_UNUSED_VARIABLE(aKeysLength);
482 }
483