[dataset] enforce successful Dataset saves in non-volatile (#10237)

This commit updates error handling when saving Active/Pending
Operational Datasets in non-volatile settings. Previously,
`kErrorNotImplemented` was permitted as a return value due to legacy
behavior. Since non-volatile storage is now a mandatory requirement
for Thread operation, we enforce successful saves by asserting on any
error encountered during this process. Methods returning error types
are updated, and some now return `void`.

The public APIs `otDatasetSetActive()` and `otDatasetSetPending()` are
affected by this change. They now always return `OT_ERROR_NONE` and
can essentially be treated as having a void return type. The `otError`
return type is maintained solely for backward compatibility.
This commit is contained in:
Abtin Keshavarzian
2024-05-15 17:29:26 -07:00
committed by GitHub
parent 0a4d6d34a8
commit 848de78c60
12 changed files with 55 additions and 72 deletions
+16 -12
View File
@@ -380,12 +380,15 @@ otError otDatasetGetActiveTlvs(otInstance *aInstance, otOperationalDatasetTlvs *
* its Parent. Note that a router-capable device will not transition to the Router or Leader roles until it has a * its Parent. Note that a router-capable device will not transition to the Router or Leader roles until it has a
* complete Active Dataset. * complete Active Dataset.
* *
* This function consistently returns `OT_ERROR_NONE` and can effectively be treated as having a `void` return type.
* Previously, other errors (e.g., `OT_ERROR_NOT_IMPLEMENTED`) were allowed for legacy reasons. However, as
* non-volatile storage is now mandatory for Thread operation, any failure to save the dataset will trigger an
* assertion. The `otError` return type is retained for backward compatibility.
*
* @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDataset A pointer to the Active Operational Dataset. * @param[in] aDataset A pointer to the Active Operational Dataset.
* *
* @retval OT_ERROR_NONE Successfully set the Active Operational Dataset. * @retval OT_ERROR_NONE Successfully set the Active Operational Dataset.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space to set the Active Operational Dataset.
* @retval OT_ERROR_NOT_IMPLEMENTED The platform does not implement settings functionality.
* *
*/ */
otError otDatasetSetActive(otInstance *aInstance, const otOperationalDataset *aDataset); otError otDatasetSetActive(otInstance *aInstance, const otOperationalDataset *aDataset);
@@ -409,9 +412,8 @@ otError otDatasetSetActive(otInstance *aInstance, const otOperationalDataset *aD
* @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDataset A pointer to the Active Operational Dataset. * @param[in] aDataset A pointer to the Active Operational Dataset.
* *
* @retval OT_ERROR_NONE Successfully set the Active Operational Dataset. * @retval OT_ERROR_NONE Successfully set the Active Operational Dataset.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space to set the Active Operational Dataset. * @retval OT_ERROR_INVALID_ARGS The @p aDataset is invalid. It is too long or contains incorrect TLV formatting.
* @retval OT_ERROR_NOT_IMPLEMENTED The platform does not implement settings functionality.
* *
*/ */
otError otDatasetSetActiveTlvs(otInstance *aInstance, const otOperationalDatasetTlvs *aDataset); otError otDatasetSetActiveTlvs(otInstance *aInstance, const otOperationalDatasetTlvs *aDataset);
@@ -443,12 +445,15 @@ otError otDatasetGetPendingTlvs(otInstance *aInstance, otOperationalDatasetTlvs
/** /**
* Sets the Pending Operational Dataset. * Sets the Pending Operational Dataset.
* *
* This function consistently returns `OT_ERROR_NONE` and can effectively be treated as having a `void` return type.
* Previously, other errors (e.g., `OT_ERROR_NOT_IMPLEMENTED`) were allowed for legacy reasons. However, as
* non-volatile storage is now mandatory for Thread operation, any failure to save the dataset will trigger an
* assertion. The `otError` return type is retained for backward compatibility.
*
* @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDataset A pointer to the Pending Operational Dataset. * @param[in] aDataset A pointer to the Pending Operational Dataset.
* *
* @retval OT_ERROR_NONE Successfully set the Pending Operational Dataset. * @retval OT_ERROR_NONE Successfully set the Pending Operational Dataset.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space to set the Pending Operational Dataset.
* @retval OT_ERROR_NOT_IMPLEMENTED The platform does not implement settings functionality.
* *
*/ */
otError otDatasetSetPending(otInstance *aInstance, const otOperationalDataset *aDataset); otError otDatasetSetPending(otInstance *aInstance, const otOperationalDataset *aDataset);
@@ -459,9 +464,8 @@ otError otDatasetSetPending(otInstance *aInstance, const otOperationalDataset *a
* @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDataset A pointer to the Pending Operational Dataset. * @param[in] aDataset A pointer to the Pending Operational Dataset.
* *
* @retval OT_ERROR_NONE Successfully set the Pending Operational Dataset. * @retval OT_ERROR_NONE Successfully set the Pending Operational Dataset.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space to set the Pending Operational Dataset. * @retval OT_ERROR_INVALID_ARGS The @p aDataset is invalid. It is too long or contains incorrect TLV formatting.
* @retval OT_ERROR_NOT_IMPLEMENTED The platform does not implement settings functionality.
* *
*/ */
otError otDatasetSetPendingTlvs(otInstance *aInstance, const otOperationalDatasetTlvs *aDataset); otError otDatasetSetPendingTlvs(otInstance *aInstance, const otOperationalDatasetTlvs *aDataset);
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs. * @note This number versions both OpenThread platform and user APIs.
* *
*/ */
#define OPENTHREAD_API_VERSION (412) #define OPENTHREAD_API_VERSION (413)
/** /**
* @addtogroup api-instance * @addtogroup api-instance
+6 -2
View File
@@ -61,7 +61,9 @@ otError otDatasetGetActiveTlvs(otInstance *aInstance, otOperationalDatasetTlvs *
otError otDatasetSetActive(otInstance *aInstance, const otOperationalDataset *aDataset) otError otDatasetSetActive(otInstance *aInstance, const otOperationalDataset *aDataset)
{ {
return AsCoreType(aInstance).Get<MeshCoP::ActiveDatasetManager>().SaveLocal(AsCoreType(aDataset)); AsCoreType(aInstance).Get<MeshCoP::ActiveDatasetManager>().SaveLocal(AsCoreType(aDataset));
return OT_ERROR_NONE;
} }
otError otDatasetSetActiveTlvs(otInstance *aInstance, const otOperationalDatasetTlvs *aDataset) otError otDatasetSetActiveTlvs(otInstance *aInstance, const otOperationalDatasetTlvs *aDataset)
@@ -85,7 +87,9 @@ otError otDatasetGetPendingTlvs(otInstance *aInstance, otOperationalDatasetTlvs
otError otDatasetSetPending(otInstance *aInstance, const otOperationalDataset *aDataset) otError otDatasetSetPending(otInstance *aInstance, const otOperationalDataset *aDataset)
{ {
return AsCoreType(aInstance).Get<MeshCoP::PendingDatasetManager>().SaveLocal(AsCoreType(aDataset)); AsCoreType(aInstance).Get<MeshCoP::PendingDatasetManager>().SaveLocal(AsCoreType(aDataset));
return OT_ERROR_NONE;
} }
otError otDatasetSetPendingTlvs(otInstance *aInstance, const otOperationalDatasetTlvs *aDataset) otError otDatasetSetPendingTlvs(otInstance *aInstance, const otOperationalDatasetTlvs *aDataset)
+6 -5
View File
@@ -35,6 +35,7 @@
#include "common/array.hpp" #include "common/array.hpp"
#include "common/code_utils.hpp" #include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/locator_getters.hpp" #include "common/locator_getters.hpp"
#include "common/num_utils.hpp" #include "common/num_utils.hpp"
#include "instance/instance.hpp" #include "instance/instance.hpp"
@@ -221,14 +222,14 @@ Settings::Key Settings::KeyForDatasetType(MeshCoP::Dataset::Type aType)
return (aType == MeshCoP::Dataset::kActive) ? kKeyActiveDataset : kKeyPendingDataset; return (aType == MeshCoP::Dataset::kActive) ? kKeyActiveDataset : kKeyPendingDataset;
} }
Error Settings::SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshCoP::Dataset &aDataset) void Settings::SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshCoP::Dataset &aDataset)
{ {
Key key = KeyForDatasetType(aType); Key key = KeyForDatasetType(aType);
Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetLength()); Error error = Get<SettingsDriver>().Set(key, aDataset.GetBytes(), aDataset.GetLength());
Log(kActionSave, error, key); Log(kActionSave, error, key);
return error; SuccessOrAssert(error);
} }
Error Settings::ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Dataset &aDataset) const Error Settings::ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Dataset &aDataset) const
@@ -242,17 +243,17 @@ Error Settings::ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Da
aDataset.SetLength(static_cast<uint8_t>(length)); aDataset.SetLength(static_cast<uint8_t>(length));
exit: exit:
OT_ASSERT(error != kErrorNotImplemented);
return error; return error;
} }
Error Settings::DeleteOperationalDataset(MeshCoP::Dataset::Type aType) void Settings::DeleteOperationalDataset(MeshCoP::Dataset::Type aType)
{ {
Key key = KeyForDatasetType(aType); Key key = KeyForDatasetType(aType);
Error error = Get<SettingsDriver>().Delete(key); Error error = Get<SettingsDriver>().Delete(key);
Log(kActionDelete, error, key); Log(kActionDelete, error, key);
OT_ASSERT(error != kErrorNotImplemented);
return error;
} }
#if OPENTHREAD_FTD #if OPENTHREAD_FTD
+2 -9
View File
@@ -881,11 +881,8 @@ public:
* @param[in] aType The Dataset type (active or pending) to save. * @param[in] aType The Dataset type (active or pending) to save.
* @param[in] aDataset A reference to a `Dataset` object to be saved. * @param[in] aDataset A reference to a `Dataset` object to be saved.
* *
* @retval kErrorNone Successfully saved the Dataset.
* @retval kErrorNotImplemented The platform does not implement settings functionality.
*
*/ */
Error SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshCoP::Dataset &aDataset); void SaveOperationalDataset(MeshCoP::Dataset::Type aType, const MeshCoP::Dataset &aDataset);
/** /**
* Reads the Operational Dataset (active or pending). * Reads the Operational Dataset (active or pending).
@@ -895,7 +892,6 @@ public:
* *
* @retval kErrorNone Successfully read the Dataset. * @retval kErrorNone Successfully read the Dataset.
* @retval kErrorNotFound No corresponding value in the setting store. * @retval kErrorNotFound No corresponding value in the setting store.
* @retval kErrorNotImplemented The platform does not implement settings functionality.
* *
*/ */
Error ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Dataset &aDataset) const; Error ReadOperationalDataset(MeshCoP::Dataset::Type aType, MeshCoP::Dataset &aDataset) const;
@@ -905,11 +901,8 @@ public:
* *
* @param[in] aType The Dataset type (active or pending) to delete. * @param[in] aType The Dataset type (active or pending) to delete.
* *
* @retval kErrorNone Successfully deleted the Dataset.
* @retval kErrorNotImplemented The platform does not implement settings functionality.
*
*/ */
Error DeleteOperationalDataset(MeshCoP::Dataset::Type aType); void DeleteOperationalDataset(MeshCoP::Dataset::Type aType);
/** /**
* Reads a specified settings entry. * Reads a specified settings entry.
+6 -12
View File
@@ -66,7 +66,7 @@ void DatasetLocal::Clear(void)
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
DestroySecurelyStoredKeys(); DestroySecurelyStoredKeys();
#endif #endif
IgnoreError(Get<Settings>().DeleteOperationalDataset(mType)); Get<Settings>().DeleteOperationalDataset(mType);
mTimestamp.Clear(); mTimestamp.Clear();
mTimestampPresent = false; mTimestampPresent = false;
mSaved = false; mSaved = false;
@@ -146,18 +146,15 @@ exit:
return error; return error;
} }
Error DatasetLocal::Save(const Dataset &aDataset) void DatasetLocal::Save(const Dataset &aDataset)
{ {
Error error = kErrorNone;
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
DestroySecurelyStoredKeys(); DestroySecurelyStoredKeys();
#endif #endif
if (aDataset.GetLength() == 0) if (aDataset.GetLength() == 0)
{ {
// do not propagate error back Get<Settings>().DeleteOperationalDataset(mType);
IgnoreError(Get<Settings>().DeleteOperationalDataset(mType));
mSaved = false; mSaved = false;
LogInfo("%s dataset deleted", Dataset::TypeToString(mType)); LogInfo("%s dataset deleted", Dataset::TypeToString(mType));
} }
@@ -169,9 +166,9 @@ Error DatasetLocal::Save(const Dataset &aDataset)
dataset.SetFrom(aDataset); dataset.SetFrom(aDataset);
MoveKeysToSecureStorage(dataset); MoveKeysToSecureStorage(dataset);
SuccessOrExit(error = Get<Settings>().SaveOperationalDataset(mType, dataset)); Get<Settings>().SaveOperationalDataset(mType, dataset);
#else #else
SuccessOrExit(error = Get<Settings>().SaveOperationalDataset(mType, aDataset)); Get<Settings>().SaveOperationalDataset(mType, aDataset);
#endif #endif
mSaved = true; mSaved = true;
@@ -180,9 +177,6 @@ Error DatasetLocal::Save(const Dataset &aDataset)
mTimestampPresent = (aDataset.ReadTimestamp(mType, mTimestamp) == kErrorNone); mTimestampPresent = (aDataset.ReadTimestamp(mType, mTimestamp) == kErrorNone);
mUpdateTime = TimerMilli::GetNow(); mUpdateTime = TimerMilli::GetNow();
exit:
return error;
} }
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
@@ -239,7 +233,7 @@ void DatasetLocal::EmplaceSecurelyStoredKeys(Dataset &aDataset) const
dataset.SetFrom(aDataset); dataset.SetFrom(aDataset);
MoveKeysToSecureStorage(dataset); MoveKeysToSecureStorage(dataset);
SuccessOrAssert(Get<Settings>().SaveOperationalDataset(mType, dataset)); Get<Settings>().SaveOperationalDataset(mType, dataset);
} }
} }
+1 -4
View File
@@ -155,11 +155,8 @@ public:
* *
* @param[in] aDataset The Dataset to save. * @param[in] aDataset The Dataset to save.
* *
* @retval kErrorNone Successfully saved the dataset.
* @retval kErrorNotImplemented The platform does not implement settings functionality.
*
*/ */
Error Save(const Dataset &aDataset); void Save(const Dataset &aDataset);
private: private:
#if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
+10 -14
View File
@@ -163,7 +163,7 @@ Error DatasetManager::Save(const Dataset &aDataset)
if (isNetworkKeyUpdated || compare > 0) if (isNetworkKeyUpdated || compare > 0)
{ {
SuccessOrExit(error = mLocal.Save(aDataset)); mLocal.Save(aDataset);
#if OPENTHREAD_FTD #if OPENTHREAD_FTD
Get<NetworkData::Leader>().IncrementVersionAndStableVersion(); Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
@@ -180,32 +180,31 @@ exit:
return error; return error;
} }
Error DatasetManager::SaveLocal(const Dataset::Info &aDatasetInfo) void DatasetManager::SaveLocal(const Dataset::Info &aDatasetInfo)
{ {
Dataset dataset; Dataset dataset;
dataset.SetFrom(aDatasetInfo); dataset.SetFrom(aDatasetInfo);
SaveLocal(dataset);
return SaveLocal(dataset);
} }
Error DatasetManager::SaveLocal(const Dataset::Tlvs &aDatasetTlvs) Error DatasetManager::SaveLocal(const Dataset::Tlvs &aDatasetTlvs)
{ {
Error error; Error error = kErrorInvalidArgs;
Dataset dataset; Dataset dataset;
SuccessOrExit(error = dataset.SetFrom(aDatasetTlvs)); SuccessOrExit(dataset.SetFrom(aDatasetTlvs));
error = SaveLocal(dataset); SuccessOrExit(dataset.ValidateTlvs());
SaveLocal(dataset);
error = kErrorNone;
exit: exit:
return error; return error;
} }
Error DatasetManager::SaveLocal(const Dataset &aDataset) void DatasetManager::SaveLocal(const Dataset &aDataset)
{ {
Error error; mLocal.Save(aDataset);
SuccessOrExit(error = mLocal.Save(aDataset));
if (IsPendingDataset()) if (IsPendingDataset())
{ {
@@ -237,9 +236,6 @@ Error DatasetManager::SaveLocal(const Dataset &aDataset)
} }
SignalDatasetChange(); SignalDatasetChange();
exit:
return error;
} }
void DatasetManager::SignalDatasetChange(void) const void DatasetManager::SignalDatasetChange(void) const
+4 -10
View File
@@ -115,30 +115,24 @@ public:
* *
* @param[in] aDataset The Operational Dataset. * @param[in] aDataset The Operational Dataset.
* *
* @retval kErrorNone Successfully applied configuration.
* @retval kErrorParse The dataset has at least one TLV with invalid format.
*
*/ */
Error SaveLocal(const Dataset &aDataset); void SaveLocal(const Dataset &aDataset);
/** /**
* Saves the Operational Dataset in non-volatile memory. * Saves the Operational Dataset in non-volatile memory.
* *
* @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`. * @param[in] aDatasetInfo The Operational Dataset as `Dataset::Info`.
* *
* @retval kErrorNone Successfully saved the dataset.
* @retval kErrorNotImplemented The platform does not implement settings functionality.
*
*/ */
Error SaveLocal(const Dataset::Info &aDatasetInfo); void SaveLocal(const Dataset::Info &aDatasetInfo);
/** /**
* Saves the Operational Dataset in non-volatile memory. * Saves the Operational Dataset in non-volatile memory.
* *
* @param[in] aDatasetTlvs The Operational Dataset as `Dataset::Tlvs`. * @param[in] aDatasetTlvs The Operational Dataset as `Dataset::Tlvs`.
* *
* @retval kErrorNone Successfully saved the dataset. * @retval kErrorNone Successfully saved the dataset.
* @retval kErrorNotImplemented The platform does not implement settings functionality. * @retval kErrorInvalidArgs The @p aDatasetTlvs is invalid. It is too long or contains incorrect TLV formatting.
* *
*/ */
Error SaveLocal(const Dataset::Tlvs &aDatasetTlvs); Error SaveLocal(const Dataset::Tlvs &aDatasetTlvs);
+1 -1
View File
@@ -376,7 +376,7 @@ Error ActiveDatasetManager::GenerateLocal(void)
IgnoreError(dataset.WriteTlv(tlv)); IgnoreError(dataset.WriteTlv(tlv));
} }
SuccessOrExit(error = mLocal.Save(dataset)); mLocal.Save(dataset);
IgnoreError(Restore()); IgnoreError(Restore());
LogInfo("Generated local dataset"); LogInfo("Generated local dataset");
+1 -1
View File
@@ -149,7 +149,7 @@ void DatasetUpdater::PreparePendingDataset(void)
IgnoreError(dataset.Write<ActiveTimestampTlv>(timestamp)); IgnoreError(dataset.Write<ActiveTimestampTlv>(timestamp));
} }
SuccessOrExit(error = Get<PendingDatasetManager>().SaveLocal(dataset)); Get<PendingDatasetManager>().SaveLocal(dataset);
exit: exit:
if (error != kErrorNone) if (error != kErrorNone)
+1 -1
View File
@@ -533,7 +533,7 @@ template <> void Joiner::HandleTmf<kUriJoinerEntrust>(Coap::Message &aMessage, c
datasetInfo.Set<Dataset::kChannel>(Get<Mac::Mac>().GetPanChannel()); datasetInfo.Set<Dataset::kChannel>(Get<Mac::Mac>().GetPanChannel());
datasetInfo.Set<Dataset::kPanId>(Get<Mac::Mac>().GetPanId()); datasetInfo.Set<Dataset::kPanId>(Get<Mac::Mac>().GetPanId());
IgnoreError(Get<ActiveDatasetManager>().SaveLocal(datasetInfo)); Get<ActiveDatasetManager>().SaveLocal(datasetInfo);
LogInfo("Joiner successful!"); LogInfo("Joiner successful!");