From 2485f72d150692caca507687a622adfa8e3479f6 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Wed, 20 May 2020 14:27:41 -0700 Subject: [PATCH] [meshcop] do not send MGMT_*_SET.req while one is outstanding (#4981) This commit helps ensure the following: - At most one MGMT_ACTIVE_SET.req message is outstanding. - At most one MGMT_PENDING_SET.req message is outstanding. --- src/core/meshcop/dataset_manager.cpp | 88 +++++++++++++++++++--------- src/core/meshcop/dataset_manager.hpp | 21 +++++-- 2 files changed, 74 insertions(+), 35 deletions(-) diff --git a/src/core/meshcop/dataset_manager.cpp b/src/core/meshcop/dataset_manager.cpp index 2efaa2a14..ec2b2d392 100644 --- a/src/core/meshcop/dataset_manager.cpp +++ b/src/core/meshcop/dataset_manager.cpp @@ -60,6 +60,7 @@ DatasetManager::DatasetManager(Instance & aInstance, , mTimer(aInstance, aTimerHandler, this) , mUriGet(aUriGet) , mUriSet(aUriSet) + , mCoapPending(false) { mTimestamp.Init(); } @@ -168,7 +169,7 @@ otError DatasetManager::Save(const Dataset &aDataset) } else if (compare < 0) { - mTimer.Start(1000); + SendSet(); } exit: @@ -188,11 +189,11 @@ otError DatasetManager::Save(const otOperationalDataset &aDataset) break; case Mle::kRoleChild: - mTimer.Start(1000); + SendSet(); break; #if OPENTHREAD_FTD case Mle::kRoleRouter: - mTimer.Start(1000); + SendSet(); break; case Mle::kRoleLeader: @@ -232,39 +233,35 @@ exit: void DatasetManager::HandleTimer(void) { - VerifyOrExit(Get().IsAttached(), OT_NOOP); + SendSet(); +} - VerifyOrExit(mLocal.Compare(GetTimestamp()) < 0, OT_NOOP); +void DatasetManager::SendSet(void) +{ + otError error; + Coap::Message * message = NULL; + Ip6::MessageInfo messageInfo; + Dataset dataset(mLocal.GetType()); + + VerifyOrExit(!mCoapPending, error = OT_ERROR_BUSY); + VerifyOrExit(Get().IsAttached(), error = OT_ERROR_INVALID_STATE); + VerifyOrExit(mLocal.Compare(GetTimestamp()) < 0, error = OT_ERROR_INVALID_STATE); if (mLocal.GetType() == Dataset::kActive) { - Dataset dataset(Dataset::kPending); - IgnoreError(Get().Read(dataset)); + Dataset pendingDataset(Dataset::kPending); + IgnoreError(Get().Read(pendingDataset)); - const ActiveTimestampTlv *tlv = dataset.GetTlv(); + const ActiveTimestampTlv *tlv = pendingDataset.GetTlv(); const Timestamp * pendingActiveTimestamp = static_cast(tlv); if (pendingActiveTimestamp != NULL && mLocal.Compare(pendingActiveTimestamp) == 0) { // stop registration attempts during dataset transition - ExitNow(); + ExitNow(error = OT_ERROR_INVALID_STATE); } } - IgnoreError(Register()); - mTimer.Start(1000); - -exit: - return; -} - -otError DatasetManager::Register(void) -{ - otError error = OT_ERROR_NONE; - Coap::Message * message; - Ip6::MessageInfo messageInfo; - Dataset dataset(mLocal.GetType()); - VerifyOrExit((message = NewMeshCoPMessage(Get())) != NULL, error = OT_ERROR_NO_BUFS); SuccessOrExit(error = message->Init(OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST, mUriSet)); @@ -276,18 +273,51 @@ otError DatasetManager::Register(void) messageInfo.SetSockAddr(Get().GetMeshLocal16()); IgnoreError(Get().GetLeaderAloc(messageInfo.GetPeerAddr())); messageInfo.SetPeerPort(kCoapUdpPort); - SuccessOrExit(error = Get().SendMessage(*message, messageInfo)); + SuccessOrExit(error = + Get().SendMessage(*message, messageInfo, &DatasetManager::HandleCoapResponse, this)); - otLogInfoMeshCoP("sent dataset to leader"); + otLogInfoMeshCoP("Sent %s to leader", mUriSet); exit: - if (error != OT_ERROR_NONE && message != NULL) + switch (error) { - message->Free(); - } + case OT_ERROR_NONE: + mCoapPending = true; + break; - return error; + case OT_ERROR_NO_BUFS: + mTimer.Start(kDelayNoBufs); + // fall through + + default: + otLogWarnMeshCoP("Failed to send %s to leader: %s", mUriSet, otThreadErrorToString(error)); + + if (message != NULL) + { + message->Free(); + } + + break; + } +} + +void DatasetManager::HandleCoapResponse(void * aContext, + otMessage * aMessage, + const otMessageInfo *aMessageInfo, + otError aError) +{ + OT_UNUSED_VARIABLE(aMessage); + OT_UNUSED_VARIABLE(aMessageInfo); + OT_UNUSED_VARIABLE(aError); + + static_cast(aContext)->HandleCoapResponse(); +} + +void DatasetManager::HandleCoapResponse(void) +{ + mCoapPending = false; + SendSet(); } void DatasetManager::HandleGet(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) const diff --git a/src/core/meshcop/dataset_manager.hpp b/src/core/meshcop/dataset_manager.hpp index 9f5ffe42d..cd1b244fd 100644 --- a/src/core/meshcop/dataset_manager.hpp +++ b/src/core/meshcop/dataset_manager.hpp @@ -278,15 +278,22 @@ private: static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); void HandleUdpReceive(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - otError Register(void); - void SendGetResponse(const Coap::Message & aRequest, - const Ip6::MessageInfo &aMessageInfo, - uint8_t * aTlvs, - uint8_t aLength) const; + static void HandleCoapResponse(void * aContext, + otMessage * aMessage, + const otMessageInfo *aMessageInfo, + otError aError); + void HandleCoapResponse(void); + + void SendSet(void); + void SendGetResponse(const Coap::Message & aRequest, + const Ip6::MessageInfo &aMessageInfo, + uint8_t * aTlvs, + uint8_t aLength) const; enum { - kMaxDatasetTlvs = 16, // Maximum number of TLVs in an `otOperationalDataset`. + kMaxDatasetTlvs = 16, // Maximum number of TLVs in an `otOperationalDataset`. + kDelayNoBufs = 1000, // Milliseconds }; TimerMilli mTimer; @@ -294,6 +301,8 @@ private: const char *mUriGet; const char *mUriSet; + bool mCoapPending : 1; + #if OPENTHREAD_FTD public: /**