blob: c69b32261a56e185aa1edbed2102421fe1a976b9 [file] [log] [blame]
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for non-volatile storage of settings.
*/
#include "settings.hpp"
#include "common/array.hpp"
#include "common/code_utils.hpp"
#include "common/instance.hpp"
#include "common/locator_getters.hpp"
#include "meshcop/dataset.hpp"
#include "thread/mle.hpp"
namespace ot {
RegisterLogModule("Settings");
//---------------------------------------------------------------------------------------------------------------------
// SettingsBase
// LCOV_EXCL_START
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void SettingsBase::NetworkInfo::Log(Action aAction) const
{
LogInfo("%s NetworkInfo {rloc:0x%04x, extaddr:%s, role:%s, mode:0x%02x, version:%hu, keyseq:0x%x, ...",
ActionToString(aAction), GetRloc16(), GetExtAddress().ToString().AsCString(),
Mle::Mle::RoleToString(static_cast<Mle::DeviceRole>(GetRole())), GetDeviceMode(), GetVersion(),
GetKeySequence());
LogInfo("... pid:0x%x, mlecntr:0x%x, maccntr:0x%x, mliid:%s}", GetPreviousPartitionId(), GetMleFrameCounter(),
GetMacFrameCounter(), GetMeshLocalIid().ToString().AsCString());
}
void SettingsBase::ParentInfo::Log(Action aAction) const
{
LogInfo("%s ParentInfo {extaddr:%s, version:%hu}", ActionToString(aAction), GetExtAddress().ToString().AsCString(),
GetVersion());
}
#if OPENTHREAD_FTD
void SettingsBase::ChildInfo::Log(Action aAction) const
{
LogInfo("%s ChildInfo {rloc:0x%04x, extaddr:%s, timeout:%u, mode:0x%02x, version:%hu}", ActionToString(aAction),
GetRloc16(), GetExtAddress().ToString().AsCString(), GetTimeout(), GetMode(), GetVersion());
}
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE
void SettingsBase::DadInfo::Log(Action aAction) const
{
LogInfo("%s DadInfo {DadCounter:%2d}", ActionToString(aAction), GetDadCounter());
}
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
void SettingsBase::LogPrefix(Action aAction, Key aKey, const Ip6::Prefix &aPrefix)
{
LogInfo("%s %s %s", ActionToString(aAction), KeyToString(aKey), aPrefix.ToString().AsCString());
}
#endif
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
void SettingsBase::SrpClientInfo::Log(Action aAction) const
{
LogInfo("%s SrpClientInfo {Server:[%s]:%u}", ActionToString(aAction), GetServerAddress().ToString().AsCString(),
GetServerPort());
}
#endif
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
void SettingsBase::SrpServerInfo::Log(Action aAction) const
{
LogInfo("%s SrpServerInfo {port:%u}", ActionToString(aAction), GetPort());
}
#endif
#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
const char *SettingsBase::ActionToString(Action aAction)
{
static const char *const kActionStrings[] = {
"Read", // (0) kActionRead
"Saved", // (1) kActionSave
"Re-saved", // (2) kActionResave
"Deleted", // (3) kActionDelete
#if OPENTHREAD_FTD
"Added", // (4) kActionAdd,
"Removed", // (5) kActionRemove,
"Deleted all" // (6) kActionDeleteAll
#endif
};
static_assert(0 == kActionRead, "kActionRead value is incorrect");
static_assert(1 == kActionSave, "kActionSave value is incorrect");
static_assert(2 == kActionResave, "kActionResave value is incorrect");
static_assert(3 == kActionDelete, "kActionDelete value is incorrect");
#if OPENTHREAD_FTD
static_assert(4 == kActionAdd, "kActionAdd value is incorrect");
static_assert(5 == kActionRemove, "kActionRemove value is incorrect");
static_assert(6 == kActionDeleteAll, "kActionDeleteAll value is incorrect");
#endif
return kActionStrings[aAction];
}
#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
const char *SettingsBase::KeyToString(Key aKey)
{
static const char *const kKeyStrings[] = {
"", // (0) (Unused)
"ActiveDataset", // (1) kKeyActiveDataset
"PendingDataset", // (2) kKeyPendingDataset
"NetworkInfo", // (3) kKeyNetworkInfo
"ParentInfo", // (4) kKeyParentInfo
"ChildInfo", // (5) kKeyChildInfo
"", // (6) kKeyReserved
"SlaacIidSecretKey", // (7) kKeySlaacIidSecretKey
"DadInfo", // (8) kKeyDadInfo
"LegacyOmrPrefix", // (9) kKeyLegacyOmrPrefix
"OnLinkPrefix", // (10) kKeyOnLinkPrefix
"SrpEcdsaKey", // (11) kKeySrpEcdsaKey
"SrpClientInfo", // (12) kKeySrpClientInfo
"SrpServerInfo", // (13) kKeySrpServerInfo
"LegacyNat64Prefix", // (14) kKeyLegacyNat64Prefix
"BrUlaPrefix", // (15) kKeyBrUlaPrefix
};
static_assert(1 == kKeyActiveDataset, "kKeyActiveDataset value is incorrect");
static_assert(2 == kKeyPendingDataset, "kKeyPendingDataset value is incorrect");
static_assert(3 == kKeyNetworkInfo, "kKeyNetworkInfo value is incorrect");
static_assert(4 == kKeyParentInfo, "kKeyParentInfo value is incorrect");
static_assert(5 == kKeyChildInfo, "kKeyChildInfo value is incorrect");
static_assert(6 == kKeyReserved, "kKeyReserved value is incorrect");
static_assert(7 == kKeySlaacIidSecretKey, "kKeySlaacIidSecretKey value is incorrect");
static_assert(8 == kKeyDadInfo, "kKeyDadInfo value is incorrect");
static_assert(9 == kKeyLegacyOmrPrefix, "kKeyLegacyOmrPrefix value is incorrect");
static_assert(10 == kKeyOnLinkPrefix, "kKeyOnLinkPrefix value is incorrect");
static_assert(11 == kKeySrpEcdsaKey, "kKeySrpEcdsaKey value is incorrect");
static_assert(12 == kKeySrpClientInfo, "kKeySrpClientInfo value is incorrect");
static_assert(13 == kKeySrpServerInfo, "kKeySrpServerInfo value is incorrect");
static_assert(14 == kKeyLegacyNat64Prefix, "kKeyLegacyNat64Prefix value is incorrect");
static_assert(15 == kKeyBrUlaPrefix, "kKeyBrUlaPrefix value is incorrect");
static_assert(kLastKey == kKeyBrUlaPrefix, "kLastKey is not valid");
OT_ASSERT(aKey <= kLastKey);
return kKeyStrings[aKey];
}
#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
// LCOV_EXCL_STOP
//---------------------------------------------------------------------------------------------------------------------
// Settings
// This array contains sensitive keys that should be stored in the secure area.
const uint16_t Settings::kSensitiveKeys[] = {
SettingsBase::kKeyActiveDataset,
SettingsBase::kKeyPendingDataset,
SettingsBase::kKeySrpEcdsaKey,
};
void Settings::Init(void)
{
Get<SettingsDriver>().Init(kSensitiveKeys, GetArrayLength(kSensitiveKeys));
}
void Settings::Deinit(void)
{
Get<SettingsDriver>().Deinit();
}
void Settings::Wipe(void)
{
Get<SettingsDriver>().Wipe();
LogInfo("Wiped all info");
}
Settings::Key Settings::KeyForDatasetType(MeshCoP::Dataset::Type aType)
{
return (aType == MeshCoP::Dataset::kActive) ? kKeyActiveDataset : kKeyPendingDataset;
}
Error Settings::SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshCoP::Dataset &aDataset)
{
Key key = KeyForDatasetType(aType);
Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetSize());
Log(kActionSave, error, key);
return error;
}
Error Settings::ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Dataset &aDataset) const
{
Error error = kErrorNone;
uint16_t length = MeshCoP::Dataset::kMaxSize;
SuccessOrExit(error = Get<SettingsDriver>().Get(KeyForDatasetType(aType), aDataset.GetBytes(), &length));
VerifyOrExit(length <= MeshCoP::Dataset::kMaxSize, error = kErrorNotFound);
aDataset.SetSize(length);
exit:
return error;
}
Error Settings::DeleteOperationalDataset(MeshCoP::Dataset::Type aType)
{
Key key = KeyForDatasetType(aType);
Error error = Get<SettingsDriver>().Delete(key);
Log(kActionDelete, error, key);
return error;
}
#if OPENTHREAD_FTD
Error Settings::AddChildInfo(const ChildInfo &aChildInfo)
{
Error error = Get<SettingsDriver>().Add(kKeyChildInfo, &aChildInfo, sizeof(aChildInfo));
Log(kActionAdd, error, kKeyChildInfo, &aChildInfo);
return error;
}
Error Settings::DeleteAllChildInfo(void)
{
Error error = Get<SettingsDriver>().Delete(kKeyChildInfo);
Log(kActionDeleteAll, error, kKeyChildInfo);
return error;
}
Settings::ChildInfoIterator::ChildInfoIterator(Instance &aInstance)
: SettingsBase(aInstance)
, mIndex(0)
, mIsDone(false)
{
Read();
}
void Settings::ChildInfoIterator::Advance(void)
{
if (!mIsDone)
{
mIndex++;
Read();
}
}
Error Settings::ChildInfoIterator::Delete(void)
{
Error error = kErrorNone;
VerifyOrExit(!mIsDone, error = kErrorInvalidState);
SuccessOrExit(error = Get<SettingsDriver>().Delete(kKeyChildInfo, mIndex));
exit:
Log(kActionRemove, error, kKeyChildInfo, &mChildInfo);
return error;
}
void Settings::ChildInfoIterator::Read(void)
{
uint16_t length = sizeof(ChildInfo);
Error error;
mChildInfo.Init();
SuccessOrExit(
error = Get<SettingsDriver>().Get(kKeyChildInfo, mIndex, reinterpret_cast<uint8_t *>(&mChildInfo), &length));
exit:
Log(kActionRead, error, kKeyChildInfo, &mChildInfo);
mIsDone = (error != kErrorNone);
}
#endif // OPENTHREAD_FTD
Error Settings::ReadEntry(Key aKey, void *aValue, uint16_t aMaxLength) const
{
Error error;
uint16_t length = aMaxLength;
error = Get<SettingsDriver>().Get(aKey, aValue, &length);
Log(kActionRead, error, aKey, aValue);
return error;
}
Error Settings::SaveEntry(Key aKey, const void *aValue, void *aPrev, uint16_t aLength)
{
Error error = kErrorNone;
uint16_t readLength = aLength;
Action action = kActionSave;
if ((Get<SettingsDriver>().Get(aKey, aPrev, &readLength) == kErrorNone) && (readLength == aLength) &&
(memcmp(aValue, aPrev, aLength) == 0))
{
action = kActionResave;
}
else
{
error = Get<SettingsDriver>().Set(aKey, aValue, aLength);
}
Log(action, error, aKey, aValue);
return error;
}
Error Settings::DeleteEntry(Key aKey)
{
Error error = Get<SettingsDriver>().Delete(aKey);
Log(kActionDelete, error, aKey);
return error;
}
void Settings::Log(Action aAction, Error aError, Key aKey, const void *aValue)
{
OT_UNUSED_VARIABLE(aAction);
OT_UNUSED_VARIABLE(aKey);
OT_UNUSED_VARIABLE(aError);
OT_UNUSED_VARIABLE(aValue);
if (aError != kErrorNone)
{
// Log error if log level is at "warn" or higher.
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
const char *actionText = "";
switch (aAction)
{
case kActionSave:
case kActionResave:
actionText = "saving";
break;
case kActionDelete:
VerifyOrExit(aError != kErrorNotFound);
actionText = "deleting";
break;
#if OPENTHREAD_FTD
case kActionAdd:
actionText = "adding";
break;
case kActionRemove:
VerifyOrExit(aError != kErrorNotFound);
actionText = "removing";
break;
case kActionDeleteAll:
VerifyOrExit(aError != kErrorNotFound);
actionText = "deleting all";
break;
#endif
case kActionRead:
ExitNow();
}
LogWarn("Error %s %s %s", ErrorToString(aError), actionText, KeyToString(aKey));
#endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
ExitNow();
}
// We reach here when `aError` is `kErrorNone`.
// Log success if log level is at "info" or higher.
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
if (aValue != nullptr)
{
switch (aKey)
{
case kKeyNetworkInfo:
reinterpret_cast<const NetworkInfo *>(aValue)->Log(aAction);
break;
case kKeyParentInfo:
reinterpret_cast<const ParentInfo *>(aValue)->Log(aAction);
break;
#if OPENTHREAD_FTD
case kKeyChildInfo:
reinterpret_cast<const ChildInfo *>(aValue)->Log(aAction);
break;
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE
case kKeyDadInfo:
reinterpret_cast<const DadInfo *>(aValue)->Log(aAction);
break;
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
case kKeyBrUlaPrefix:
case kKeyLegacyOmrPrefix:
case kKeyOnLinkPrefix:
case kKeyLegacyNat64Prefix:
LogPrefix(aAction, aKey, *reinterpret_cast<const Ip6::Prefix *>(aValue));
break;
#endif
#if OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE && OPENTHREAD_CONFIG_SRP_CLIENT_SAVE_SELECTED_SERVER_ENABLE
case kKeySrpClientInfo:
reinterpret_cast<const SrpClientInfo *>(aValue)->Log(aAction);
break;
#endif
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE && OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
case kKeySrpServerInfo:
reinterpret_cast<const SrpServerInfo *>(aValue)->Log(aAction);
break;
#endif
default:
// For any other keys, we do not want to include the value
// in the log, so even if it is given we set `aValue` to
// `nullptr`. This ensures that we just log the action and
// the key.
aValue = nullptr;
break;
}
}
if (aValue == nullptr)
{
LogInfo("%s %s", ActionToString(aAction), KeyToString(aKey));
}
#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
exit:
return;
}
} // namespace ot
//---------------------------------------------------------------------------------------------------------------------
// Default/weak implementation of settings platform APIs
OT_TOOL_WEAK void otPlatSettingsSetCriticalKeys(otInstance *aInstance, const uint16_t *aKeys, uint16_t aKeysLength)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aKeys);
OT_UNUSED_VARIABLE(aKeysLength);
}