Skip to content

Commit

Permalink
[dataset] add support for handling MGMT_ACTIVE_REPLACE on leader (o…
Browse files Browse the repository at this point in the history
  • Loading branch information
abtink committed May 13, 2024
1 parent 68b8c88 commit f12785d
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 75 deletions.
30 changes: 30 additions & 0 deletions src/core/meshcop/dataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,36 @@ bool Dataset::IsTlvValid(const Tlv &aTlv)
return isValid;
}

bool Dataset::ContainsAllRequiredTlvsFor(Type aType) const
{
static const Tlv::Type kActiveDatasetTlvs[] = {
Tlv::kActiveTimestamp, Tlv::kChannel, Tlv::kChannelMask, Tlv::kExtendedPanId, Tlv::kMeshLocalPrefix,
Tlv::kNetworkKey, Tlv::kNetworkName, Tlv::kPanId, Tlv::kPskc, Tlv::kSecurityPolicy,
};

static const Tlv::Type kPendingDatasetExtraTlvs[] = {Tlv::kPendingTimestamp, Tlv::kDelayTimer};

bool containsAll = false;

for (Tlv::Type tlvType : kActiveDatasetTlvs)
{
VerifyOrExit(ContainsTlv(tlvType));
}

if (aType == kPending)
{
for (Tlv::Type tlvType : kPendingDatasetExtraTlvs)
{
VerifyOrExit(ContainsTlv(tlvType));
}
}

containsAll = true;

exit:
return containsAll;
}

const Tlv *Dataset::FindTlv(Tlv::Type aType) const { return As<Tlv>(Tlv::FindTlv(mTlvs, mLength, aType)); }

void Dataset::ConvertTo(Info &aDatasetInfo) const
Expand Down
11 changes: 11 additions & 0 deletions src/core/meshcop/dataset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,17 @@ class Dataset
return ContainsTlv(static_cast<Tlv::Type>(TlvType::kType));
}

/**
* Indicates whether or not the Dataset contains all the required TLVs for an Active or Pending Dataset.
*
* @param[in] aType The Dataset type, Active or Pending.
*
* @retval TRUE The Dataset contains all the required TLVs for @p aType.
* @retval FALSE The Dataset does not contain all the required TLVs for @p aType.
*
*/
bool ContainsAllRequiredTlvsFor(Type aType) const;

/**
* Searches for a given TLV type in the Dataset.
*
Expand Down
25 changes: 18 additions & 7 deletions src/core/meshcop/dataset_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,17 +297,25 @@ class DatasetManager : public InstanceLocator
void HandleTimer(void);

#if OPENTHREAD_FTD
enum MgmtCommand : uint8_t ///< A MGMT command type.
{
kMgmtSet, ///< MGMT_SET command
kMgmtReplace, ///< MGMT_REPLACE command
};

/**
* Handles the MGMT_SET request message.
* Handles the MGMT_SET or MGMT_REPLACE request message.
*
*
* @param[in] aCommand The MGMT command type (MGMT_REPLACE or MGMT_SET).
* @param[in] aMessage The CoAP message buffer.
* @param[in] aMessageInfo The message info.
*
* @retval kErrorNone The MGMT_SET request message was handled successfully.
* @retval kErrorDrop The MGMT_SET request message was dropped.
* @retval kErrorNone The request message was handled successfully.
* @retval kErrorDrop The request message was dropped.
*
*/
Error HandleSet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
Error HandleSetOrReplace(MgmtCommand aCommand, const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
#endif

DatasetLocal mLocal;
Expand All @@ -325,7 +333,7 @@ class DatasetManager : public InstanceLocator
};

#if OPENTHREAD_FTD
struct SetRequestInfo : Clearable<SetRequestInfo> // Information from a MGMT_SET request message.
struct RequestInfo : Clearable<RequestInfo> // Info from a MGMT_SET or MGMT_REPLACE request.
{
Dataset mDataset;
bool mIsFromCommissioner;
Expand All @@ -351,8 +359,10 @@ class DatasetManager : public InstanceLocator
const TlvList &aTlvList) const;

#if OPENTHREAD_FTD
Error ProcessSetRequest(const Coap::Message &aMessage, SetRequestInfo &aInfo) const;
void SendSetResponse(const Coap::Message &aRequest, const Ip6::MessageInfo &aMessageInfo, StateTlv::State aState);
Error ProcessSetOrReplaceRequest(MgmtCommand aCommand, const Coap::Message &aMessage, RequestInfo &aInfo) const;
void SendSetOrReplaceResponse(const Coap::Message &aRequest,
const Ip6::MessageInfo &aMessageInfo,
StateTlv::State aState);
#endif

static constexpr uint8_t kMaxDatasetTlvs = 16; // Maximum number of TLVs in a Dataset.
Expand Down Expand Up @@ -504,6 +514,7 @@ class ActiveDatasetManager : public DatasetManager, private NonCopyable
DeclareTmfHandler(ActiveDatasetManager, kUriActiveGet);
#if OPENTHREAD_FTD
DeclareTmfHandler(ActiveDatasetManager, kUriActiveSet);
DeclareTmfHandler(ActiveDatasetManager, kUriActiveReplace);
#endif

class PendingDatasetManager : public DatasetManager, private NonCopyable
Expand Down
55 changes: 41 additions & 14 deletions src/core/meshcop/dataset_manager_ftd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ Error DatasetManager::AppendMleDatasetTlv(Message &aMessage) const
return Tlv::AppendTlv(aMessage, mleTlvType, dataset.GetBytes(), dataset.GetLength());
}

Error DatasetManager::ProcessSetRequest(const Coap::Message &aMessage, SetRequestInfo &aInfo) const
Error DatasetManager::ProcessSetOrReplaceRequest(MgmtCommand aCommand,
const Coap::Message &aMessage,
RequestInfo &aInfo) const
{
Error error = kErrorParse;
Dataset dataset;
Expand Down Expand Up @@ -180,7 +182,19 @@ Error DatasetManager::ProcessSetRequest(const Coap::Message &aMessage, SetReques
// MGMT_ACTIVE_SET.req/MGMT_PENDING_SET.req from Commissioner
// based on existing active dataset.

IgnoreError(Get<ActiveDatasetManager>().Read(aInfo.mDataset));
if (aCommand == kMgmtSet)
{
IgnoreError(Get<ActiveDatasetManager>().Read(aInfo.mDataset));
}
}

if (aCommand == kMgmtReplace)
{
// MGMT_ACTIVE_REPLACE can only be used by commissioner.

VerifyOrExit(aInfo.mIsFromCommissioner);
VerifyOrExit(IsActiveDataset());
VerifyOrExit(dataset.ContainsAllRequiredTlvsFor(Dataset::kActive));
}

SuccessOrExit(error = aInfo.mDataset.WriteTlvsFrom(dataset));
Expand All @@ -207,19 +221,22 @@ Error DatasetManager::ProcessSetRequest(const Coap::Message &aMessage, SetReques
return error;
}

Error DatasetManager::HandleSet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
Error DatasetManager::HandleSetOrReplace(MgmtCommand aCommand,
const Coap::Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
StateTlv::State state = StateTlv::kReject;
SetRequestInfo info;
RequestInfo info;

VerifyOrExit(Get<Mle::Mle>().IsLeader());

SuccessOrExit(ProcessSetRequest(aMessage, info));
SuccessOrExit(ProcessSetOrReplaceRequest(aCommand, aMessage, info));

if (IsActiveDataset() && info.mAffectsConnectivity)
{
// MGMT_ACTIVE_SET.req which affects connectivity
// MUST be delayed using pending dataset.
// MGMT_ACTIVE_SET/REPLACE.req which affects
// connectivity MUST be delayed using pending
// dataset.

Get<PendingDatasetManager>().ApplyActiveDataset(info.mDataset);
}
Expand All @@ -244,14 +261,14 @@ Error DatasetManager::HandleSet(const Coap::Message &aMessage, const Ip6::Messag
}

exit:
SendSetResponse(aMessage, aMessageInfo, state);
SendSetOrReplaceResponse(aMessage, aMessageInfo, state);

return (state == StateTlv::kAccept) ? kErrorNone : kErrorDrop;
}

void DatasetManager::SendSetResponse(const Coap::Message &aRequest,
const Ip6::MessageInfo &aMessageInfo,
StateTlv::State aState)
void DatasetManager::SendSetOrReplaceResponse(const Coap::Message &aRequest,
const Ip6::MessageInfo &aMessageInfo,
StateTlv::State aState)
{
Error error = kErrorNone;
Coap::Message *message;
Expand All @@ -263,7 +280,7 @@ void DatasetManager::SendSetResponse(const Coap::Message &aRequest,

SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));

LogInfo("sent dataset set response");
LogInfo("sent dataset set/replace response");

exit:
FreeMessageOnError(message, error);
Expand Down Expand Up @@ -376,7 +393,17 @@ void ActiveDatasetManager::StartLeader(void) {}
template <>
void ActiveDatasetManager::HandleTmf<kUriActiveSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
SuccessOrExit(DatasetManager::HandleSet(aMessage, aMessageInfo));
SuccessOrExit(DatasetManager::HandleSetOrReplace(kMgmtSet, aMessage, aMessageInfo));
IgnoreError(ApplyConfiguration());

exit:
return;
}

template <>
void ActiveDatasetManager::HandleTmf<kUriActiveReplace>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
SuccessOrExit(DatasetManager::HandleSetOrReplace(kMgmtReplace, aMessage, aMessageInfo));
IgnoreError(ApplyConfiguration());

exit:
Expand All @@ -388,7 +415,7 @@ void PendingDatasetManager::StartLeader(void) { StartDelayTimer(); }
template <>
void PendingDatasetManager::HandleTmf<kUriPendingSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
SuccessOrExit(DatasetManager::HandleSet(aMessage, aMessageInfo));
SuccessOrExit(DatasetManager::HandleSetOrReplace(kMgmtSet, aMessage, aMessageInfo));
StartDelayTimer();

exit:
Expand Down
1 change: 1 addition & 0 deletions src/core/thread/tmf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ bool Agent::HandleResource(const char *aUriPath, Message &aMessage, const Ip6::M
Case(kUriAddressSolicit, Mle::MleRouter);
Case(kUriAddressRelease, Mle::MleRouter);
Case(kUriActiveSet, MeshCoP::ActiveDatasetManager);
Case(kUriActiveReplace, MeshCoP::ActiveDatasetManager);
Case(kUriPendingSet, MeshCoP::PendingDatasetManager);
Case(kUriLeaderPetition, MeshCoP::Leader);
Case(kUriLeaderKeepAlive, MeshCoP::Leader);
Expand Down
111 changes: 57 additions & 54 deletions src/core/thread/uri_paths.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,33 +69,34 @@ static constexpr Entry kEntries[] = {
{"b/bq"}, // (9) kUriBackboneQuery
{"c/ab"}, // (10) kUriAnnounceBegin
{"c/ag"}, // (11) kUriActiveGet
{"c/as"}, // (12) kUriActiveSet
{"c/ca"}, // (13) kUriCommissionerKeepAlive
{"c/cg"}, // (14) kUriCommissionerGet
{"c/cp"}, // (15) kUriCommissionerPetition
{"c/cs"}, // (16) kUriCommissionerSet
{"c/dc"}, // (17) kUriDatasetChanged
{"c/er"}, // (18) kUriEnergyReport
{"c/es"}, // (19) kUriEnergyScan
{"c/je"}, // (20) kUriJoinerEntrust
{"c/jf"}, // (21) kUriJoinerFinalize
{"c/la"}, // (22) kUriLeaderKeepAlive
{"c/lp"}, // (23) kUriLeaderPetition
{"c/pc"}, // (24) kUriPanIdConflict
{"c/pg"}, // (25) kUriPendingGet
{"c/pq"}, // (26) kUriPanIdQuery
{"c/ps"}, // (27) kUriPendingSet
{"c/rx"}, // (28) kUriRelayRx
{"c/tx"}, // (29) kUriRelayTx
{"c/ur"}, // (30) kUriProxyRx
{"c/ut"}, // (31) kUriProxyTx
{"d/da"}, // (32) kUriDiagnosticGetAnswer
{"d/dg"}, // (33) kUriDiagnosticGetRequest
{"d/dq"}, // (34) kUriDiagnosticGetQuery
{"d/dr"}, // (35) kUriDiagnosticReset
{"n/dn"}, // (36) kUriDuaRegistrationNotify
{"n/dr"}, // (37) kUriDuaRegistrationRequest
{"n/mr"}, // (38) kUriMlr
{"c/ar"}, // (12) kUriActiveReplace
{"c/as"}, // (13) kUriActiveSet
{"c/ca"}, // (14) kUriCommissionerKeepAlive
{"c/cg"}, // (15) kUriCommissionerGet
{"c/cp"}, // (16) kUriCommissionerPetition
{"c/cs"}, // (17) kUriCommissionerSet
{"c/dc"}, // (18) kUriDatasetChanged
{"c/er"}, // (19) kUriEnergyReport
{"c/es"}, // (20) kUriEnergyScan
{"c/je"}, // (21) kUriJoinerEntrust
{"c/jf"}, // (22) kUriJoinerFinalize
{"c/la"}, // (23) kUriLeaderKeepAlive
{"c/lp"}, // (24) kUriLeaderPetition
{"c/pc"}, // (25) kUriPanIdConflict
{"c/pg"}, // (26) kUriPendingGet
{"c/pq"}, // (27) kUriPanIdQuery
{"c/ps"}, // (28) kUriPendingSet
{"c/rx"}, // (29) kUriRelayRx
{"c/tx"}, // (30) kUriRelayTx
{"c/ur"}, // (31) kUriProxyRx
{"c/ut"}, // (32) kUriProxyTx
{"d/da"}, // (33) kUriDiagnosticGetAnswer
{"d/dg"}, // (34) kUriDiagnosticGetRequest
{"d/dq"}, // (35) kUriDiagnosticGetQuery
{"d/dr"}, // (36) kUriDiagnosticReset
{"n/dn"}, // (37) kUriDuaRegistrationNotify
{"n/dr"}, // (38) kUriDuaRegistrationRequest
{"n/mr"}, // (39) kUriMlr
};

static_assert(BinarySearch::IsSorted(kEntries), "kEntries is not sorted");
Expand All @@ -112,33 +113,34 @@ static_assert(8 == kUriBackboneMlr, "kUriBackboneMlr (`b/bmr`) is invalid");
static_assert(9 == kUriBackboneQuery, "kUriBackboneQuery (`b/bq`) is invalid");
static_assert(10 == kUriAnnounceBegin, "kUriAnnounceBegin (`c/ab`) is invalid");
static_assert(11 == kUriActiveGet, "kUriActiveGet (`c/ag`) is invalid");
static_assert(12 == kUriActiveSet, "kUriActiveSet (`c/as`) is invalid");
static_assert(13 == kUriCommissionerKeepAlive, "kUriCommissionerKeepAlive (`c/ca`) is invalid");
static_assert(14 == kUriCommissionerGet, "kUriCommissionerGet (`c/cg`) is invalid");
static_assert(15 == kUriCommissionerPetition, "kUriCommissionerPetition (`c/cp`) is invalid");
static_assert(16 == kUriCommissionerSet, "kUriCommissionerSet (`c/cs`) is invalid");
static_assert(17 == kUriDatasetChanged, "kUriDatasetChanged (`c/dc`) is invalid");
static_assert(18 == kUriEnergyReport, "kUriEnergyReport (`c/er`) is invalid");
static_assert(19 == kUriEnergyScan, "kUriEnergyScan (`c/es`) is invalid");
static_assert(20 == kUriJoinerEntrust, "kUriJoinerEntrust (`c/je`) is invalid");
static_assert(21 == kUriJoinerFinalize, "kUriJoinerFinalize (`c/jf`) is invalid");
static_assert(22 == kUriLeaderKeepAlive, "kUriLeaderKeepAlive (`c/la`) is invalid");
static_assert(23 == kUriLeaderPetition, "kUriLeaderPetition (`c/lp`) is invalid");
static_assert(24 == kUriPanIdConflict, "kUriPanIdConflict (`c/pc`) is invalid");
static_assert(25 == kUriPendingGet, "kUriPendingGet (`c/pg`) is invalid");
static_assert(26 == kUriPanIdQuery, "kUriPanIdQuery (`c/pq`) is invalid");
static_assert(27 == kUriPendingSet, "kUriPendingSet (`c/ps`) is invalid");
static_assert(28 == kUriRelayRx, "kUriRelayRx (`c/rx`) is invalid");
static_assert(29 == kUriRelayTx, "kUriRelayTx (`c/tx`) is invalid");
static_assert(30 == kUriProxyRx, "kUriProxyRx (`c/ur`) is invalid");
static_assert(31 == kUriProxyTx, "kUriProxyTx (`c/ut`) is invalid");
static_assert(32 == kUriDiagnosticGetAnswer, "kUriDiagnosticGetAnswer (`d/da`) is invalid");
static_assert(33 == kUriDiagnosticGetRequest, "kUriDiagnosticGetRequest (`d/dg`) is invalid");
static_assert(34 == kUriDiagnosticGetQuery, "kUriDiagnosticGetQuery (`d/dq`) is invalid");
static_assert(35 == kUriDiagnosticReset, "kUriDiagnosticReset (`d/dr`) is invalid");
static_assert(36 == kUriDuaRegistrationNotify, "kUriDuaRegistrationNotify (`n/dn`) is invalid");
static_assert(37 == kUriDuaRegistrationRequest, "kUriDuaRegistrationRequest (`n/dr`) is invalid");
static_assert(38 == kUriMlr, "kUriMlr (`n/mr`) is invalid");
static_assert(12 == kUriActiveReplace, "kUriActiveReplace (`c/ar`) is invalid");
static_assert(13 == kUriActiveSet, "kUriActiveSet (`c/as`) is invalid");
static_assert(14 == kUriCommissionerKeepAlive, "kUriCommissionerKeepAlive (`c/ca`) is invalid");
static_assert(15 == kUriCommissionerGet, "kUriCommissionerGet (`c/cg`) is invalid");
static_assert(16 == kUriCommissionerPetition, "kUriCommissionerPetition (`c/cp`) is invalid");
static_assert(17 == kUriCommissionerSet, "kUriCommissionerSet (`c/cs`) is invalid");
static_assert(18 == kUriDatasetChanged, "kUriDatasetChanged (`c/dc`) is invalid");
static_assert(19 == kUriEnergyReport, "kUriEnergyReport (`c/er`) is invalid");
static_assert(20 == kUriEnergyScan, "kUriEnergyScan (`c/es`) is invalid");
static_assert(21 == kUriJoinerEntrust, "kUriJoinerEntrust (`c/je`) is invalid");
static_assert(22 == kUriJoinerFinalize, "kUriJoinerFinalize (`c/jf`) is invalid");
static_assert(23 == kUriLeaderKeepAlive, "kUriLeaderKeepAlive (`c/la`) is invalid");
static_assert(24 == kUriLeaderPetition, "kUriLeaderPetition (`c/lp`) is invalid");
static_assert(25 == kUriPanIdConflict, "kUriPanIdConflict (`c/pc`) is invalid");
static_assert(26 == kUriPendingGet, "kUriPendingGet (`c/pg`) is invalid");
static_assert(27 == kUriPanIdQuery, "kUriPanIdQuery (`c/pq`) is invalid");
static_assert(28 == kUriPendingSet, "kUriPendingSet (`c/ps`) is invalid");
static_assert(29 == kUriRelayRx, "kUriRelayRx (`c/rx`) is invalid");
static_assert(30 == kUriRelayTx, "kUriRelayTx (`c/tx`) is invalid");
static_assert(31 == kUriProxyRx, "kUriProxyRx (`c/ur`) is invalid");
static_assert(32 == kUriProxyTx, "kUriProxyTx (`c/ut`) is invalid");
static_assert(33 == kUriDiagnosticGetAnswer, "kUriDiagnosticGetAnswer (`d/da`) is invalid");
static_assert(34 == kUriDiagnosticGetRequest, "kUriDiagnosticGetRequest (`d/dg`) is invalid");
static_assert(35 == kUriDiagnosticGetQuery, "kUriDiagnosticGetQuery (`d/dq`) is invalid");
static_assert(36 == kUriDiagnosticReset, "kUriDiagnosticReset (`d/dr`) is invalid");
static_assert(37 == kUriDuaRegistrationNotify, "kUriDuaRegistrationNotify (`n/dn`) is invalid");
static_assert(38 == kUriDuaRegistrationRequest, "kUriDuaRegistrationRequest (`n/dr`) is invalid");
static_assert(39 == kUriMlr, "kUriMlr (`n/mr`) is invalid");

} // namespace UriList

Expand Down Expand Up @@ -173,6 +175,7 @@ template <> const char *UriToString<kUriBackboneMlr>(void) { return "BackboneMlr
template <> const char *UriToString<kUriBackboneQuery>(void) { return "BackboneQuery"; }
template <> const char *UriToString<kUriAnnounceBegin>(void) { return "AnnounceBegin"; }
template <> const char *UriToString<kUriActiveGet>(void) { return "ActiveGet"; }
template <> const char *UriToString<kUriActiveReplace>(void) { return "ActiveReplace"; }
template <> const char *UriToString<kUriActiveSet>(void) { return "ActiveSet"; }
template <> const char *UriToString<kUriCommissionerKeepAlive>(void) { return "CommissionerKeepAlive"; }
template <> const char *UriToString<kUriCommissionerGet>(void) { return "CommissionerGet"; }
Expand Down
2 changes: 2 additions & 0 deletions src/core/thread/uri_paths.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ enum Uri : uint8_t
kUriBackboneQuery, ///< Backbone Query ("b/bq")
kUriAnnounceBegin, ///< Announce Begin ("c/ab")
kUriActiveGet, ///< MGMT_ACTIVE_GET "c/ag"
kUriActiveReplace, ///< MGMT_ACTIVE_REPLACE ("c/ar")
kUriActiveSet, ///< MGMT_ACTIVE_SET ("c/as")
kUriCommissionerKeepAlive, ///< Commissioner Keep Alive ("c/ca")
kUriCommissionerGet, ///< MGMT_COMMISSIONER_GET ("c/cg")
Expand Down Expand Up @@ -131,6 +132,7 @@ template <> const char *UriToString<kUriBackboneMlr>(void);
template <> const char *UriToString<kUriBackboneQuery>(void);
template <> const char *UriToString<kUriAnnounceBegin>(void);
template <> const char *UriToString<kUriActiveGet>(void);
template <> const char *UriToString<kUriActiveReplace>(void);
template <> const char *UriToString<kUriActiveSet>(void);
template <> const char *UriToString<kUriCommissionerKeepAlive>(void);
template <> const char *UriToString<kUriCommissionerGet>(void);
Expand Down

0 comments on commit f12785d

Please sign in to comment.