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 "meshcop/dataset.hpp"
41 #include "thread/mle.hpp"
42
43 namespace ot {
44
45 RegisterLogModule("Settings");
46
47 //---------------------------------------------------------------------------------------------------------------------
48 // SettingsBase
49
50 // LCOV_EXCL_START
51
52 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
53
Log(Action aAction) const54 void SettingsBase::NetworkInfo::Log(Action aAction) const
55 {
56 LogInfo("%s NetworkInfo {rloc:0x%04x, extaddr:%s, role:%s, mode:0x%02x, version:%hu, keyseq:0x%x, ...",
57 ActionToString(aAction), GetRloc16(), GetExtAddress().ToString().AsCString(),
58 Mle::Mle::RoleToString(static_cast<Mle::DeviceRole>(GetRole())), GetDeviceMode(), GetVersion(),
59 GetKeySequence());
60
61 LogInfo("... pid:0x%x, mlecntr:0x%x, maccntr:0x%x, mliid:%s}", GetPreviousPartitionId(), GetMleFrameCounter(),
62 GetMacFrameCounter(), GetMeshLocalIid().ToString().AsCString());
63 }
64
Log(Action aAction) const65 void SettingsBase::ParentInfo::Log(Action aAction) const
66 {
67 LogInfo("%s ParentInfo {extaddr:%s, version:%hu}", ActionToString(aAction), GetExtAddress().ToString().AsCString(),
68 GetVersion());
69 }
70
71 #if OPENTHREAD_FTD
Log(Action aAction) const72 void SettingsBase::ChildInfo::Log(Action aAction) const
73 {
74 LogInfo("%s ChildInfo {rloc:0x%04x, extaddr:%s, timeout:%u, mode:0x%02x, version:%hu}", ActionToString(aAction),
75 GetRloc16(), GetExtAddress().ToString().AsCString(), GetTimeout(), GetMode(), GetVersion());
76 }
77 #endif
78
79 #if OPENTHREAD_CONFIG_DUA_ENABLE
Log(Action aAction) const80 void SettingsBase::DadInfo::Log(Action aAction) const
81 {
82 LogInfo("%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 LogInfo("%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 LogInfo("%s SrpClientInfo {Server:[%s]:%u}", ActionToString(aAction), GetServerAddress().ToString().AsCString(),
97 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 LogInfo("%s SrpServerInfo {port:%u}", ActionToString(aAction), GetPort());
105 }
106 #endif
107
108 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
109
110 #if OT_SHOULD_LOG_AT(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 // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
138
139 #if OT_SHOULD_LOG_AT(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) Removed (previously auto-start).
150 "SlaacIidSecretKey", // (7) kKeySlaacIidSecretKey
151 "DadInfo", // (8) kKeyDadInfo
152 "", // (9) Removed (previously OMR prefix).
153 "", // (10) Removed (previously on-link prefix).
154 "SrpEcdsaKey", // (11) kKeySrpEcdsaKey
155 "SrpClientInfo", // (12) kKeySrpClientInfo
156 "SrpServerInfo", // (13) kKeySrpServerInfo
157 "", // (14) Removed (previously NAT64 prefix)
158 "BrUlaPrefix", // (15) kKeyBrUlaPrefix
159 };
160
161 static_assert(1 == kKeyActiveDataset, "kKeyActiveDataset value is incorrect");
162 static_assert(2 == kKeyPendingDataset, "kKeyPendingDataset value is incorrect");
163 static_assert(3 == kKeyNetworkInfo, "kKeyNetworkInfo value is incorrect");
164 static_assert(4 == kKeyParentInfo, "kKeyParentInfo value is incorrect");
165 static_assert(5 == kKeyChildInfo, "kKeyChildInfo value is incorrect");
166 static_assert(7 == kKeySlaacIidSecretKey, "kKeySlaacIidSecretKey value is incorrect");
167 static_assert(8 == kKeyDadInfo, "kKeyDadInfo value is incorrect");
168 static_assert(11 == kKeySrpEcdsaKey, "kKeySrpEcdsaKey value is incorrect");
169 static_assert(12 == kKeySrpClientInfo, "kKeySrpClientInfo value is incorrect");
170 static_assert(13 == kKeySrpServerInfo, "kKeySrpServerInfo value is incorrect");
171 static_assert(15 == kKeyBrUlaPrefix, "kKeyBrUlaPrefix value is incorrect");
172
173 static_assert(kLastKey == kKeyBrUlaPrefix, "kLastKey is not valid");
174
175 OT_ASSERT(aKey <= kLastKey);
176
177 return kKeyStrings[aKey];
178 }
179 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
180
181 // LCOV_EXCL_STOP
182
183 //---------------------------------------------------------------------------------------------------------------------
184 // Settings
185
186 // This array contains sensitive keys that should be stored in the secure area.
187 const uint16_t Settings::kSensitiveKeys[] = {
188 SettingsBase::kKeyActiveDataset,
189 SettingsBase::kKeyPendingDataset,
190 SettingsBase::kKeySrpEcdsaKey,
191 };
192
Init(void)193 void Settings::Init(void)
194 {
195 Get<SettingsDriver>().Init(kSensitiveKeys, GetArrayLength(kSensitiveKeys));
196 }
197
Deinit(void)198 void Settings::Deinit(void)
199 {
200 Get<SettingsDriver>().Deinit();
201 }
202
Wipe(void)203 void Settings::Wipe(void)
204 {
205 Get<SettingsDriver>().Wipe();
206 LogInfo("Wiped all info");
207 }
208
KeyForDatasetType(MeshCoP::Dataset::Type aType)209 Settings::Key Settings::KeyForDatasetType(MeshCoP::Dataset::Type aType)
210 {
211 return (aType == MeshCoP::Dataset::kActive) ? kKeyActiveDataset : kKeyPendingDataset;
212 }
213
SaveOperationalDataset(MeshCoP::Dataset::Type aType,const MeshCoP::Dataset & aDataset)214 Error Settings::SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshCoP::Dataset &aDataset)
215 {
216 Key key = KeyForDatasetType(aType);
217 Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetSize());
218
219 Log(kActionSave, error, key);
220
221 return error;
222 }
223
ReadOperationalDataset(MeshCoP::Dataset::Type aType,MeshCoP::Dataset & aDataset) const224 Error Settings::ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Dataset &aDataset) const
225 {
226 Error error = kErrorNone;
227 uint16_t length = MeshCoP::Dataset::kMaxSize;
228
229 SuccessOrExit(error = Get<SettingsDriver>().Get(KeyForDatasetType(aType), aDataset.GetBytes(), &length));
230 VerifyOrExit(length <= MeshCoP::Dataset::kMaxSize, error = kErrorNotFound);
231
232 aDataset.SetSize(length);
233
234 exit:
235 return error;
236 }
237
DeleteOperationalDataset(MeshCoP::Dataset::Type aType)238 Error Settings::DeleteOperationalDataset(MeshCoP::Dataset::Type aType)
239 {
240 Key key = KeyForDatasetType(aType);
241 Error error = Get<SettingsDriver>().Delete(key);
242
243 Log(kActionDelete, error, key);
244
245 return error;
246 }
247
248 #if OPENTHREAD_FTD
AddChildInfo(const ChildInfo & aChildInfo)249 Error Settings::AddChildInfo(const ChildInfo &aChildInfo)
250 {
251 Error error = Get<SettingsDriver>().Add(kKeyChildInfo, &aChildInfo, sizeof(aChildInfo));
252
253 Log(kActionAdd, error, kKeyChildInfo, &aChildInfo);
254
255 return error;
256 }
257
DeleteAllChildInfo(void)258 Error Settings::DeleteAllChildInfo(void)
259 {
260 Error error = Get<SettingsDriver>().Delete(kKeyChildInfo);
261
262 Log(kActionDeleteAll, error, kKeyChildInfo);
263
264 return error;
265 }
266
ChildInfoIterator(Instance & aInstance)267 Settings::ChildInfoIterator::ChildInfoIterator(Instance &aInstance)
268 : SettingsBase(aInstance)
269 , mIndex(0)
270 , mIsDone(false)
271 {
272 Read();
273 }
274
Advance(void)275 void Settings::ChildInfoIterator::Advance(void)
276 {
277 if (!mIsDone)
278 {
279 mIndex++;
280 Read();
281 }
282 }
283
Delete(void)284 Error Settings::ChildInfoIterator::Delete(void)
285 {
286 Error error = kErrorNone;
287
288 VerifyOrExit(!mIsDone, error = kErrorInvalidState);
289 SuccessOrExit(error = Get<SettingsDriver>().Delete(kKeyChildInfo, mIndex));
290
291 exit:
292 Log(kActionRemove, error, kKeyChildInfo, &mChildInfo);
293 return error;
294 }
295
Read(void)296 void Settings::ChildInfoIterator::Read(void)
297 {
298 uint16_t length = sizeof(ChildInfo);
299 Error error;
300
301 mChildInfo.Init();
302 SuccessOrExit(
303 error = Get<SettingsDriver>().Get(kKeyChildInfo, mIndex, reinterpret_cast<uint8_t *>(&mChildInfo), &length));
304
305 exit:
306 Log(kActionRead, error, kKeyChildInfo, &mChildInfo);
307 mIsDone = (error != kErrorNone);
308 }
309 #endif // OPENTHREAD_FTD
310
ReadEntry(Key aKey,void * aValue,uint16_t aMaxLength) const311 Error Settings::ReadEntry(Key aKey, void *aValue, uint16_t aMaxLength) const
312 {
313 Error error;
314 uint16_t length = aMaxLength;
315
316 error = Get<SettingsDriver>().Get(aKey, aValue, &length);
317 Log(kActionRead, error, aKey, aValue);
318
319 return error;
320 }
321
SaveEntry(Key aKey,const void * aValue,void * aPrev,uint16_t aLength)322 Error Settings::SaveEntry(Key aKey, const void *aValue, void *aPrev, uint16_t aLength)
323 {
324 Error error = kErrorNone;
325 uint16_t readLength = aLength;
326 Action action = kActionSave;
327
328 if ((Get<SettingsDriver>().Get(aKey, aPrev, &readLength) == kErrorNone) && (readLength == aLength) &&
329 (memcmp(aValue, aPrev, aLength) == 0))
330 {
331 action = kActionResave;
332 }
333 else
334 {
335 error = Get<SettingsDriver>().Set(aKey, aValue, aLength);
336 }
337
338 Log(action, error, aKey, aValue);
339
340 return error;
341 }
342
DeleteEntry(Key aKey)343 Error Settings::DeleteEntry(Key aKey)
344 {
345 Error error = Get<SettingsDriver>().Delete(aKey);
346
347 Log(kActionDelete, error, aKey);
348
349 return error;
350 }
351
Log(Action aAction,Error aError,Key aKey,const void * aValue)352 void Settings::Log(Action aAction, Error aError, Key aKey, const void *aValue)
353 {
354 OT_UNUSED_VARIABLE(aAction);
355 OT_UNUSED_VARIABLE(aKey);
356 OT_UNUSED_VARIABLE(aError);
357 OT_UNUSED_VARIABLE(aValue);
358
359 if (aError != kErrorNone)
360 {
361 // Log error if log level is at "warn" or higher.
362
363 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
364 const char *actionText = "";
365
366 switch (aAction)
367 {
368 case kActionSave:
369 case kActionResave:
370 actionText = "saving";
371 break;
372
373 case kActionDelete:
374 VerifyOrExit(aError != kErrorNotFound);
375 actionText = "deleting";
376 break;
377
378 #if OPENTHREAD_FTD
379 case kActionAdd:
380 actionText = "adding";
381 break;
382
383 case kActionRemove:
384 VerifyOrExit(aError != kErrorNotFound);
385 actionText = "removing";
386 break;
387
388 case kActionDeleteAll:
389 VerifyOrExit(aError != kErrorNotFound);
390 actionText = "deleting all";
391 break;
392 #endif
393 case kActionRead:
394 ExitNow();
395 }
396
397 LogWarn("Error %s %s %s", ErrorToString(aError), actionText, KeyToString(aKey));
398
399 #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
400
401 ExitNow();
402 }
403
404 // We reach here when `aError` is `kErrorNone`.
405 // Log success if log level is at "info" or higher.
406
407 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
408 if (aValue != nullptr)
409 {
410 switch (aKey)
411 {
412 case kKeyNetworkInfo:
413 reinterpret_cast<const NetworkInfo *>(aValue)->Log(aAction);
414 break;
415
416 case kKeyParentInfo:
417 reinterpret_cast<const ParentInfo *>(aValue)->Log(aAction);
418 break;
419
420 #if OPENTHREAD_FTD
421 case kKeyChildInfo:
422 reinterpret_cast<const ChildInfo *>(aValue)->Log(aAction);
423 break;
424 #endif
425
426 #if OPENTHREAD_CONFIG_DUA_ENABLE
427 case kKeyDadInfo:
428 reinterpret_cast<const DadInfo *>(aValue)->Log(aAction);
429 break;
430 #endif
431
432 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
433 case kKeyBrUlaPrefix:
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 LogInfo("%s %s", ActionToString(aAction), KeyToString(aKey));
463 }
464 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
465
466 exit:
467 return;
468 }
469
470 } // namespace ot
471
472 //---------------------------------------------------------------------------------------------------------------------
473 // Default/weak implementation of settings platform APIs
474
otPlatSettingsSetCriticalKeys(otInstance * aInstance,const uint16_t * aKeys,uint16_t aKeysLength)475 OT_TOOL_WEAK void otPlatSettingsSetCriticalKeys(otInstance *aInstance, const uint16_t *aKeys, uint16_t aKeysLength)
476 {
477 OT_UNUSED_VARIABLE(aInstance);
478 OT_UNUSED_VARIABLE(aKeys);
479 OT_UNUSED_VARIABLE(aKeysLength);
480 }
481