blob: 8f6d5c79f464af74ce511addef8da4ebba74371a [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 <openthread/platform/settings.h>
#include "common/code_utils.hpp"
#include "common/instance.hpp"
#include "common/locator-getters.hpp"
#include "common/logging.hpp"
#include "meshcop/dataset.hpp"
#include "thread/mle.hpp"
namespace ot {
// LCOV_EXCL_START
#if (OPENTHREAD_CONFIG_LOG_UTIL != 0)
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
void SettingsBase::LogNetworkInfo(const char *aAction, const NetworkInfo &aNetworkInfo) const
{
otLogInfoCore(
"Non-volatile: %s NetworkInfo {rloc:0x%04x, extaddr:%s, role:%s, mode:0x%02x, version:%hu, keyseq:0x%x, ...",
aAction, aNetworkInfo.GetRloc16(), aNetworkInfo.GetExtAddress().ToString().AsCString(),
Mle::Mle::RoleToString(static_cast<Mle::DeviceRole>(aNetworkInfo.GetRole())), aNetworkInfo.GetDeviceMode(),
aNetworkInfo.GetVersion(), aNetworkInfo.GetKeySequence());
otLogInfoCore("Non-volatile: ... pid:0x%x, mlecntr:0x%x, maccntr:0x%x, mliid:%s}",
aNetworkInfo.GetPreviousPartitionId(), aNetworkInfo.GetMleFrameCounter(),
aNetworkInfo.GetMacFrameCounter(), aNetworkInfo.GetMeshLocalIid().ToString().AsCString());
}
void SettingsBase::LogParentInfo(const char *aAction, const ParentInfo &aParentInfo) const
{
otLogInfoCore("Non-volatile: %s ParentInfo {extaddr:%s, version:%hu}", aAction,
aParentInfo.GetExtAddress().ToString().AsCString(), aParentInfo.GetVersion());
}
void SettingsBase::LogChildInfo(const char *aAction, const ChildInfo &aChildInfo) const
{
otLogInfoCore("Non-volatile: %s ChildInfo {rloc:0x%04x, extaddr:%s, timeout:%u, mode:0x%02x, version:%hu}", aAction,
aChildInfo.GetRloc16(), aChildInfo.GetExtAddress().ToString().AsCString(), aChildInfo.GetTimeout(),
aChildInfo.GetMode(), aChildInfo.GetVersion());
}
#if OPENTHREAD_CONFIG_DUA_ENABLE
void SettingsBase::LogDadInfo(const char *aAction, const DadInfo &aDadInfo) const
{
otLogInfoCore("Non-volatile: %s DadInfo {DadCounter:%2d}", aAction, aDadInfo.GetDadCounter());
}
#endif
#endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO)
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
void SettingsBase::LogFailure(otError error, const char *aText, bool aIsDelete) const
{
if ((error != OT_ERROR_NONE) && (!aIsDelete || (error != OT_ERROR_NOT_FOUND)))
{
otLogWarnCore("Non-volatile: Error %s %s", otThreadErrorToString(error), aText);
}
}
#endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN)
#endif // #if (OPENTHREAD_CONFIG_LOG_UTIL != 0)
// LCOV_EXCL_STOP
#if !OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
SettingsDriver::SettingsDriver(Instance &aInstance)
: InstanceLocator(aInstance)
{
}
void SettingsDriver::Init(void)
{
otPlatSettingsInit(&GetInstance());
}
void SettingsDriver::Deinit(void)
{
otPlatSettingsDeinit(&GetInstance());
}
otError SettingsDriver::Add(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
{
return otPlatSettingsAdd(&GetInstance(), aKey, aValue, aValueLength);
}
otError SettingsDriver::Delete(uint16_t aKey, int aIndex)
{
return otPlatSettingsDelete(&GetInstance(), aKey, aIndex);
}
otError SettingsDriver::Get(uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) const
{
return otPlatSettingsGet(&GetInstance(), aKey, aIndex, aValue, aValueLength);
}
otError SettingsDriver::Set(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
{
return otPlatSettingsSet(&GetInstance(), aKey, aValue, aValueLength);
}
void SettingsDriver::Wipe(void)
{
otPlatSettingsWipe(&GetInstance());
}
#else // !OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
SettingsDriver::SettingsDriver(Instance &aInstance)
: InstanceLocator(aInstance)
, mFlash(aInstance)
{
}
void SettingsDriver::Init(void)
{
mFlash.Init();
}
void SettingsDriver::Deinit(void)
{
}
otError SettingsDriver::Add(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
{
return mFlash.Add(aKey, aValue, aValueLength);
}
otError SettingsDriver::Delete(uint16_t aKey, int aIndex)
{
return mFlash.Delete(aKey, aIndex);
}
otError SettingsDriver::Get(uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) const
{
return mFlash.Get(aKey, aIndex, aValue, aValueLength);
}
otError SettingsDriver::Set(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
{
return mFlash.Set(aKey, aValue, aValueLength);
}
void SettingsDriver::Wipe(void)
{
mFlash.Wipe();
}
#endif // !OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
void Settings::Init(void)
{
Get<SettingsDriver>().Init();
}
void Settings::Deinit(void)
{
Get<SettingsDriver>().Deinit();
}
void Settings::Wipe(void)
{
Get<SettingsDriver>().Wipe();
otLogInfoCore("Non-volatile: Wiped all info");
}
otError Settings::SaveOperationalDataset(bool aIsActive, const MeshCoP::Dataset &aDataset)
{
otError error = Save(aIsActive ? kKeyActiveDataset : kKeyPendingDataset, aDataset.GetBytes(), aDataset.GetSize());
LogFailure(error, "saving OperationalDataset", false);
return error;
}
otError Settings::ReadOperationalDataset(bool aIsActive, MeshCoP::Dataset &aDataset) const
{
otError error = OT_ERROR_NONE;
uint16_t length = MeshCoP::Dataset::kMaxSize;
SuccessOrExit(error = Read(aIsActive ? kKeyActiveDataset : kKeyPendingDataset, aDataset.GetBytes(), length));
VerifyOrExit(length <= MeshCoP::Dataset::kMaxSize, error = OT_ERROR_NOT_FOUND);
aDataset.SetSize(length);
exit:
return error;
}
otError Settings::DeleteOperationalDataset(bool aIsActive)
{
otError error = Delete(aIsActive ? kKeyActiveDataset : kKeyPendingDataset);
LogFailure(error, "deleting OperationalDataset", true);
return error;
}
otError Settings::ReadNetworkInfo(NetworkInfo &aNetworkInfo) const
{
otError error;
uint16_t length = sizeof(NetworkInfo);
aNetworkInfo.Init();
SuccessOrExit(error = Read(kKeyNetworkInfo, &aNetworkInfo, length));
LogNetworkInfo("Read", aNetworkInfo);
exit:
return error;
}
otError Settings::SaveNetworkInfo(const NetworkInfo &aNetworkInfo)
{
otError error = OT_ERROR_NONE;
NetworkInfo prevNetworkInfo;
uint16_t length = sizeof(prevNetworkInfo);
if ((Read(kKeyNetworkInfo, &prevNetworkInfo, length) == OT_ERROR_NONE) && (length == sizeof(NetworkInfo)) &&
(memcmp(&prevNetworkInfo, &aNetworkInfo, sizeof(NetworkInfo)) == 0))
{
LogNetworkInfo("Re-saved", aNetworkInfo);
ExitNow();
}
SuccessOrExit(error = Save(kKeyNetworkInfo, &aNetworkInfo, sizeof(NetworkInfo)));
LogNetworkInfo("Saved", aNetworkInfo);
exit:
LogFailure(error, "saving NetworkInfo", false);
return error;
}
otError Settings::DeleteNetworkInfo(void)
{
otError error;
SuccessOrExit(error = Delete(kKeyNetworkInfo));
otLogInfoCore("Non-volatile: Deleted NetworkInfo");
exit:
LogFailure(error, "deleting NetworkInfo", true);
return error;
}
otError Settings::ReadParentInfo(ParentInfo &aParentInfo) const
{
otError error;
uint16_t length = sizeof(ParentInfo);
aParentInfo.Init();
SuccessOrExit(error = Read(kKeyParentInfo, &aParentInfo, length));
LogParentInfo("Read", aParentInfo);
exit:
return error;
}
otError Settings::SaveParentInfo(const ParentInfo &aParentInfo)
{
otError error = OT_ERROR_NONE;
ParentInfo prevParentInfo;
uint16_t length = sizeof(ParentInfo);
if ((Read(kKeyParentInfo, &prevParentInfo, length) == OT_ERROR_NONE) && (length == sizeof(ParentInfo)) &&
(memcmp(&prevParentInfo, &aParentInfo, sizeof(ParentInfo)) == 0))
{
LogParentInfo("Re-saved", aParentInfo);
ExitNow();
}
SuccessOrExit(error = Save(kKeyParentInfo, &aParentInfo, sizeof(ParentInfo)));
LogParentInfo("Saved", aParentInfo);
exit:
LogFailure(error, "saving ParentInfo", false);
return error;
}
otError Settings::DeleteParentInfo(void)
{
otError error;
SuccessOrExit(error = Delete(kKeyParentInfo));
otLogInfoCore("Non-volatile: Deleted ParentInfo");
exit:
LogFailure(error, "deleting ParentInfo", true);
return error;
}
otError Settings::AddChildInfo(const ChildInfo &aChildInfo)
{
otError error;
SuccessOrExit(error = Add(kKeyChildInfo, &aChildInfo, sizeof(aChildInfo)));
LogChildInfo("Added", aChildInfo);
exit:
LogFailure(error, "adding ChildInfo", false);
return error;
}
otError Settings::DeleteChildInfo(void)
{
otError error;
SuccessOrExit(error = Delete(kKeyChildInfo));
otLogInfoCore("Non-volatile: Deleted all ChildInfo");
exit:
LogFailure(error, "deleting all ChildInfo", true);
return error;
}
Settings::ChildInfoIterator::ChildInfoIterator(Instance &aInstance)
: SettingsBase(aInstance)
, mIndex(0)
, mIsDone(false)
{
Reset();
}
void Settings::ChildInfoIterator::Reset(void)
{
mIndex = 0;
mIsDone = false;
Read();
}
void Settings::ChildInfoIterator::Advance(void)
{
if (!mIsDone)
{
mIndex++;
Read();
}
}
otError Settings::ChildInfoIterator::Delete(void)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(!mIsDone, error = OT_ERROR_INVALID_STATE);
SuccessOrExit(error = Get<SettingsDriver>().Delete(kKeyChildInfo, mIndex));
LogChildInfo("Removed", mChildInfo);
exit:
LogFailure(error, "removing ChildInfo entry", true);
return error;
}
void Settings::ChildInfoIterator::Read(void)
{
uint16_t length = sizeof(ChildInfo);
otError error;
mChildInfo.Init();
SuccessOrExit(
error = Get<SettingsDriver>().Get(kKeyChildInfo, mIndex, reinterpret_cast<uint8_t *>(&mChildInfo), &length));
LogChildInfo("Read", mChildInfo);
exit:
mIsDone = (error != OT_ERROR_NONE);
}
#if OPENTHREAD_CONFIG_DUA_ENABLE
otError Settings::ReadDadInfo(DadInfo &aDadInfo) const
{
otError error;
uint16_t length = sizeof(DadInfo);
aDadInfo.Init();
SuccessOrExit(error = Read(kKeyDadInfo, &aDadInfo, length));
LogDadInfo("Read", aDadInfo);
exit:
return error;
}
otError Settings::SaveDadInfo(const DadInfo &aDadInfo)
{
otError error = OT_ERROR_NONE;
DadInfo prevDadInfo;
uint16_t length = sizeof(DadInfo);
if ((Read(kKeyDadInfo, &prevDadInfo, length) == OT_ERROR_NONE) && (length == sizeof(DadInfo)) &&
(memcmp(&prevDadInfo, &aDadInfo, sizeof(DadInfo)) == 0))
{
LogDadInfo("Re-saved", aDadInfo);
ExitNow();
}
SuccessOrExit(error = Save(kKeyDadInfo, &aDadInfo, sizeof(DadInfo)));
LogDadInfo("Saved", aDadInfo);
exit:
LogFailure(error, "saving DadInfo", false);
return error;
}
otError Settings::DeleteDadInfo(void)
{
otError error;
SuccessOrExit(error = Delete(kKeyDadInfo));
otLogInfoCore("Non-volatile: Deleted DadInfo");
exit:
LogFailure(error, "deleting DadInfo", true);
return error;
}
#endif // OPENTHREAD_CONFIG_DUA_ENABLE
otError Settings::Read(Key aKey, void *aBuffer, uint16_t &aSize) const
{
return Get<SettingsDriver>().Get(aKey, 0, reinterpret_cast<uint8_t *>(aBuffer), &aSize);
}
otError Settings::Save(Key aKey, const void *aValue, uint16_t aSize)
{
return Get<SettingsDriver>().Set(aKey, reinterpret_cast<const uint8_t *>(aValue), aSize);
}
otError Settings::Add(Key aKey, const void *aValue, uint16_t aSize)
{
return Get<SettingsDriver>().Add(aKey, reinterpret_cast<const uint8_t *>(aValue), aSize);
}
otError Settings::Delete(Key aKey)
{
return Get<SettingsDriver>().Delete(aKey, -1);
}
} // namespace ot