From ae10bd51f6add07c8c57ba749e0ff58a8feb7dad Mon Sep 17 00:00:00 2001 From: jinran-google Date: Thu, 12 Aug 2021 16:19:13 +0800 Subject: [PATCH] [dbus] add AttachAllNodesTo API (#23) Cherry picked from internal commit 1134e905e. --- src/dbus/client/client_error.cpp | 1 + src/dbus/client/thread_api_dbus.cpp | 6 ++ src/dbus/client/thread_api_dbus.hpp | 18 +++++ src/dbus/common/constants.hpp | 1 + src/dbus/common/error.hpp | 5 ++ src/dbus/server/dbus_thread_object.cpp | 21 ++++++ src/dbus/server/dbus_thread_object.hpp | 1 + src/dbus/server/error_helper.cpp | 1 + src/dbus/server/introspect.xml | 8 +++ src/utils/thread_helper.cpp | 95 ++++++++++++++++++++++---- src/utils/thread_helper.hpp | 16 ++++- tests/dbus/CMakeLists.txt | 2 +- tests/dbus/test-client | 36 ++++++++++ 13 files changed, 196 insertions(+), 15 deletions(-) diff --git a/src/dbus/client/client_error.cpp b/src/dbus/client/client_error.cpp index f311eeba6ff..98535dddc48 100644 --- a/src/dbus/client/client_error.cpp +++ b/src/dbus/client/client_error.cpp @@ -71,6 +71,7 @@ static const std::pair sErrorNames[] = { {ClientError::OT_ERROR_NOT_TMF, OTBR_OPENTHREAD_ERROR_PREFIX ".NotTmf"}, {ClientError::OT_ERROR_NOT_LOWPAN_DATA_FRAME, OTBR_OPENTHREAD_ERROR_PREFIX ".NonLowpanDatatFrame"}, {ClientError::OT_ERROR_LINK_MARGIN_LOW, OTBR_OPENTHREAD_ERROR_PREFIX ".LinkMarginLow"}, + {ClientError::OT_ERROR_REJECTED, OTBR_OPENTHREAD_ERROR_PREFIX ".Rejected"}, }; ClientError ConvertFromDBusErrorName(const std::string &aErrorName) diff --git a/src/dbus/client/thread_api_dbus.cpp b/src/dbus/client/thread_api_dbus.cpp index 48e71679dbb..57ffed346b0 100644 --- a/src/dbus/client/thread_api_dbus.cpp +++ b/src/dbus/client/thread_api_dbus.cpp @@ -713,5 +713,11 @@ void ThreadApiDBus::sHandleDBusPendingCall(DBusPendingCall *aPending, void *aThr (api->*Handler)(aPending); } +ClientError ThreadApiDBus::AttachAllNodesTo(const std::vector &aDataset) +{ + auto args = std::tie(aDataset); + return CallDBusMethodSync(OTBR_DBUS_ATTACH_ALL_NODES_TO_METHOD, args); +} + } // namespace DBus } // namespace otbr diff --git a/src/dbus/client/thread_api_dbus.hpp b/src/dbus/client/thread_api_dbus.hpp index d75354c8617..abf6fcef787 100644 --- a/src/dbus/client/thread_api_dbus.hpp +++ b/src/dbus/client/thread_api_dbus.hpp @@ -145,6 +145,24 @@ class ThreadApiDBus */ ClientError Attach(const OtResultHandler &aHandler); + /** + * This method attaches the device to the specified Thread network. If already attached to a network, sends a + * request to migrate the existing network. + * + * @param aDataset The Operational Dataset that contains parameter values of the Thread network to attach to. It + * must have a valid Delay Timer and Pending Timestamp. + * + * @retval ERROR_NONE successfully requested the Thread network migration. + * @retval ERROR_DBUS dbus encode/decode error. + * @retval OT_ERROR_REJECTED the request was rejected by the leader. + * @retval OT_ERROR_FAILED failed to send the request. + * @retval OT_ERROR_INVALID_STATE the device is attaching. + * @retval OT_ERROR_INVALID_ARGS arguments are invalid. + * @retval OT_ERROR_BUSY there is an ongoing request. + * + */ + ClientError AttachAllNodesTo(const std::vector &aDataset); + /** * This method performs a factory reset. * diff --git a/src/dbus/common/constants.hpp b/src/dbus/common/constants.hpp index fd9b7c5938a..2004f0a994d 100644 --- a/src/dbus/common/constants.hpp +++ b/src/dbus/common/constants.hpp @@ -56,6 +56,7 @@ #define OTBR_DBUS_JOINER_STOP_METHOD "JoinerStop" #define OTBR_DBUS_ADD_EXTERNAL_ROUTE_METHOD "AddExternalRoute" #define OTBR_DBUS_REMOVE_EXTERNAL_ROUTE_METHOD "RemoveExternalRoute" +#define OTBR_DBUS_ATTACH_ALL_NODES_TO_METHOD "AttachAllNodesTo" #define OTBR_DBUS_PROPERTY_MESH_LOCAL_PREFIX "MeshLocalPrefix" #define OTBR_DBUS_PROPERTY_LEGACY_ULA_PREFIX "LegacyULAPrefix" diff --git a/src/dbus/common/error.hpp b/src/dbus/common/error.hpp index 05b470599fa..8eed9d65950 100644 --- a/src/dbus/common/error.hpp +++ b/src/dbus/common/error.hpp @@ -216,6 +216,11 @@ enum class ClientError */ OT_ERROR_LINK_MARGIN_LOW = 34, + /** + * Request rejected. + */ + OT_ERROR_REJECTED = 37, + /** * Generic error (should not use). */ diff --git a/src/dbus/server/dbus_thread_object.cpp b/src/dbus/server/dbus_thread_object.cpp index b7397e425d6..ea1cce4471b 100644 --- a/src/dbus/server/dbus_thread_object.cpp +++ b/src/dbus/server/dbus_thread_object.cpp @@ -131,6 +131,8 @@ otbrError DBusThreadObject::Init(void) std::bind(&DBusThreadObject::AddExternalRouteHandler, this, _1)); RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_REMOVE_EXTERNAL_ROUTE_METHOD, std::bind(&DBusThreadObject::RemoveExternalRouteHandler, this, _1)); + RegisterMethod(OTBR_DBUS_THREAD_INTERFACE, OTBR_DBUS_ATTACH_ALL_NODES_TO_METHOD, + std::bind(&DBusThreadObject::AttachAllNodesToHandler, this, _1)); RegisterMethod(DBUS_INTERFACE_INTROSPECTABLE, DBUS_INTROSPECT_METHOD, std::bind(&DBusThreadObject::IntrospectHandler, this, _1)); @@ -291,6 +293,25 @@ void DBusThreadObject::AttachHandler(DBusRequest &aRequest) } } +void DBusThreadObject::AttachAllNodesToHandler(DBusRequest &aRequest) +{ + std::vector dataset; + otError error = OT_ERROR_NONE; + + auto args = std::tie(dataset); + + VerifyOrExit(DBusMessageToTuple(*aRequest.GetMessage(), args) == OTBR_ERROR_NONE, error = OT_ERROR_INVALID_ARGS); + + mNcp->GetThreadHelper()->AttachAllNodesTo(dataset, + [aRequest](otError error) mutable { aRequest.ReplyOtResult(error); }); + +exit: + if (error != OT_ERROR_NONE) + { + aRequest.ReplyOtResult(error); + } +} + void DBusThreadObject::DetachHandler(DBusRequest &aRequest) { aRequest.ReplyOtResult(mNcp->GetThreadHelper()->Detach()); diff --git a/src/dbus/server/dbus_thread_object.hpp b/src/dbus/server/dbus_thread_object.hpp index 45aff4b9ab8..7a86214a380 100644 --- a/src/dbus/server/dbus_thread_object.hpp +++ b/src/dbus/server/dbus_thread_object.hpp @@ -86,6 +86,7 @@ class DBusThreadObject : public DBusObject void ScanHandler(DBusRequest &aRequest); void AttachHandler(DBusRequest &aRequest); + void AttachAllNodesToHandler(DBusRequest &aRequest); void DetachHandler(DBusRequest &aRequest); void LeaveHandler(DBusRequest &aRequest); void FactoryResetHandler(DBusRequest &aRequest); diff --git a/src/dbus/server/error_helper.cpp b/src/dbus/server/error_helper.cpp index 9ff2f058672..95d24bdf75c 100644 --- a/src/dbus/server/error_helper.cpp +++ b/src/dbus/server/error_helper.cpp @@ -67,6 +67,7 @@ static const std::pair sErrorNames[] = { {OT_ERROR_NOT_TMF, OPENTHREAD_ERROR_PREFIX ".NotTmf"}, {OT_ERROR_NOT_LOWPAN_DATA_FRAME, OPENTHREAD_ERROR_PREFIX ".NonLowpanDatatFrame"}, {OT_ERROR_LINK_MARGIN_LOW, OPENTHREAD_ERROR_PREFIX ".LinkMarginLow"}, + {OT_ERROR_REJECTED, OPENTHREAD_ERROR_PREFIX ".Rejected"}, }; namespace otbr { diff --git a/src/dbus/server/introspect.xml b/src/dbus/server/introspect.xml index 1544fdf6dbe..a4db56e5ded 100644 --- a/src/dbus/server/introspect.xml +++ b/src/dbus/server/introspect.xml @@ -46,6 +46,14 @@ + + + + + diff --git a/src/utils/thread_helper.cpp b/src/utils/thread_helper.cpp index 37da51a66b6..da497df6c5a 100644 --- a/src/utils/thread_helper.cpp +++ b/src/utils/thread_helper.cpp @@ -50,7 +50,6 @@ namespace otbr { namespace agent { - ThreadHelper::ThreadHelper(otInstance *aInstance, otbr::Ncp::ControllerOpenThread *aNcp) : mInstance(aInstance) , mNcp(aNcp) @@ -98,7 +97,7 @@ void ThreadHelper::Scan(ScanHandler aHandler) mScanResults.clear(); error = - otLinkActiveScan(mInstance, /*scanChannels =*/0, /*scanDuration=*/0, &ThreadHelper::sActiveScanHandler, this); + otLinkActiveScan(mInstance, /*scanChannels =*/0, /*scanDuration=*/0, &ThreadHelper::ActiveScanHandler, this); exit: if (error != OT_ERROR_NONE) @@ -122,7 +121,7 @@ void ThreadHelper::RandomFill(void *aBuf, size_t size) } } -void ThreadHelper::sActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper) +void ThreadHelper::ActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper) { ThreadHelper *helper = static_cast(aThreadHelper); @@ -193,7 +192,6 @@ void ThreadHelper::Attach(const std::string & aNetworkName, VerifyOrExit(aHandler != nullptr, error = OT_ERROR_INVALID_ARGS); VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE); - mAttachHandler = aHandler; VerifyOrExit(aNetworkKey.empty() || aNetworkKey.size() == sizeof(networkKey.m8), error = OT_ERROR_INVALID_ARGS); VerifyOrExit(aPSKc.empty() || aPSKc.size() == sizeof(pskc.m8), error = OT_ERROR_INVALID_ARGS); VerifyOrExit(aChannelMask != 0, error = OT_ERROR_INVALID_ARGS); @@ -259,6 +257,8 @@ void ThreadHelper::Attach(const std::string & aNetworkName, SuccessOrExit(error = otThreadSetPskc(mInstance, &pskc)); SuccessOrExit(error = otThreadSetEnabled(mInstance, true)); + mAttachHandler = aHandler; + exit: if (error != OT_ERROR_NONE) { @@ -266,7 +266,6 @@ void ThreadHelper::Attach(const std::string & aNetworkName, { aHandler(error); } - mAttachHandler = nullptr; } } @@ -275,13 +274,13 @@ void ThreadHelper::Attach(ResultHandler aHandler) otError error = OT_ERROR_NONE; VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE); - mAttachHandler = aHandler; if (!otIp6IsEnabled(mInstance)) { SuccessOrExit(error = otIp6SetEnabled(mInstance, true)); } SuccessOrExit(error = otThreadSetEnabled(mInstance, true)); + mAttachHandler = aHandler; exit: if (error != OT_ERROR_NONE) @@ -290,7 +289,6 @@ void ThreadHelper::Attach(ResultHandler aHandler) { aHandler(error); } - mAttachHandler = nullptr; } } @@ -325,14 +323,16 @@ void ThreadHelper::JoinerStart(const std::string &aPskd, VerifyOrExit(aHandler != nullptr, error = OT_ERROR_INVALID_ARGS); VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_INVALID_STATE); - mJoinerHandler = aHandler; if (!otIp6IsEnabled(mInstance)) { SuccessOrExit(error = otIp6SetEnabled(mInstance, true)); } - error = otJoinerStart(mInstance, aPskd.c_str(), aProvisioningUrl.c_str(), aVendorName.c_str(), aVendorModel.c_str(), - aVendorSwVersion.c_str(), aVendorData.c_str(), sJoinerCallback, this); + SuccessOrExit(error = otJoinerStart(mInstance, aPskd.c_str(), aProvisioningUrl.c_str(), aVendorName.c_str(), + aVendorModel.c_str(), aVendorSwVersion.c_str(), aVendorData.c_str(), + JoinerCallback, this)); + mJoinerHandler = aHandler; + exit: if (error != OT_ERROR_NONE) { @@ -340,11 +340,10 @@ void ThreadHelper::JoinerStart(const std::string &aPskd, { aHandler(error); } - mJoinerHandler = nullptr; } } -void ThreadHelper::sJoinerCallback(otError aError, void *aThreadHelper) +void ThreadHelper::JoinerCallback(otError aError, void *aThreadHelper) { ThreadHelper *helper = static_cast(aThreadHelper); @@ -399,6 +398,78 @@ void ThreadHelper::LogOpenThreadResult(const char *aAction, otError aError) } } +void ThreadHelper::AttachAllNodesTo(const std::vector &aDatasetTlvs, ResultHandler aHandler) +{ + otError error = OT_ERROR_NONE; + otOperationalDataset emptyDataset{}; + otDeviceRole role = otThreadGetDeviceRole(mInstance); + + assert(aHandler != nullptr); + VerifyOrExit(mAttachHandler == nullptr && mJoinerHandler == nullptr, error = OT_ERROR_BUSY); + + if (role == OT_DEVICE_ROLE_DISABLED || role == OT_DEVICE_ROLE_DETACHED) + { + otOperationalDataset existingDataset; + + error = otDatasetGetActive(mInstance, &existingDataset); + VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_NOT_FOUND); + + VerifyOrExit(error == OT_ERROR_NOT_FOUND, error = OT_ERROR_INVALID_STATE); + + otOperationalDatasetTlvs datasetTlvs; + + VerifyOrExit(aDatasetTlvs.size() <= sizeof(datasetTlvs.mTlvs), error = OT_ERROR_INVALID_ARGS); + std::copy(aDatasetTlvs.begin(), aDatasetTlvs.end(), datasetTlvs.mTlvs); + datasetTlvs.mLength = aDatasetTlvs.size(); + + SuccessOrExit(error = otDatasetSetActiveTlvs(mInstance, &datasetTlvs)); + + if (!otIp6IsEnabled(mInstance)) + { + SuccessOrExit(error = otIp6SetEnabled(mInstance, true)); + } + SuccessOrExit(error = otThreadSetEnabled(mInstance, true)); + + aHandler(OT_ERROR_NONE); + ExitNow(); + } + + SuccessOrExit(error = otDatasetSendMgmtPendingSet(mInstance, &emptyDataset, aDatasetTlvs.data(), + aDatasetTlvs.size(), MgmtSetResponseHandler, this)); + mAttachHandler = aHandler; + +exit: + if (error != OT_ERROR_NONE) + { + aHandler(error); + } +} + +void ThreadHelper::MgmtSetResponseHandler(otError aResult, void *aContext) +{ + static_cast(aContext)->MgmtSetResponseHandler(aResult); +} + +void ThreadHelper::MgmtSetResponseHandler(otError aResult) +{ + LogOpenThreadResult("MgmtSetResponseHandler()", aResult); + + assert(mAttachHandler != nullptr); + + switch (aResult) + { + case OT_ERROR_NONE: + case OT_ERROR_REJECTED: + break; + default: + aResult = OT_ERROR_FAILED; + break; + } + + mAttachHandler(aResult); + mAttachHandler = nullptr; +} + #if OTBR_ENABLE_UNSECURE_JOIN otError ThreadHelper::PermitUnsecureJoin(uint16_t aPort, uint32_t aSeconds) { diff --git a/src/utils/thread_helper.hpp b/src/utils/thread_helper.hpp index 8edab39a239..aefa19610b6 100644 --- a/src/utils/thread_helper.hpp +++ b/src/utils/thread_helper.hpp @@ -144,6 +144,15 @@ class ThreadHelper */ void Attach(ResultHandler aHandler); + /** + * This method makes all nodes in the current network attach to the network specified by the dataset TLVs. + * + * @param[in] aDatasetTlvs The dataset TLVs. + * @param[in] aHandler The result handler. + * + */ + void AttachAllNodesTo(const std::vector &aDatasetTlvs, ResultHandler aHandler); + /** * This method resets the OpenThread stack. * @@ -208,12 +217,15 @@ class ThreadHelper static void LogOpenThreadResult(const char *aAction, otError aError); private: - static void sActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper); + static void ActiveScanHandler(otActiveScanResult *aResult, void *aThreadHelper); void ActiveScanHandler(otActiveScanResult *aResult); - static void sJoinerCallback(otError aError, void *aThreadHelper); + static void JoinerCallback(otError aError, void *aThreadHelper); void JoinerCallback(otError aResult); + static void MgmtSetResponseHandler(otError aResult, void *aContext); + void MgmtSetResponseHandler(otError aResult); + void RandomFill(void *aBuf, size_t size); uint8_t RandomChannelFromChannelMask(uint32_t aChannelMask); diff --git a/tests/dbus/CMakeLists.txt b/tests/dbus/CMakeLists.txt index 6b4775dcad6..17882697eaa 100644 --- a/tests/dbus/CMakeLists.txt +++ b/tests/dbus/CMakeLists.txt @@ -53,4 +53,4 @@ add_test( set_tests_properties(dbus-client PROPERTIES ENVIRONMENT CMAKE_BINARY_DIR=${CMAKE_BINARY_DIR} ) -set_tests_properties(dbus-client PROPERTIES TIMEOUT 120) +set_tests_properties(dbus-client PROPERTIES TIMEOUT 420) diff --git a/tests/dbus/test-client b/tests/dbus/test-client index 78746f7ba4a..82e26b572ed 100755 --- a/tests/dbus/test-client +++ b/tests/dbus/test-client @@ -118,13 +118,49 @@ EOF string:ABCDEF string:mock string:mock \ string:mock string:mock string:mock sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl state | grep -e child -e router + sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ io.openthread.BorderRouter.Detach sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl state | grep disabled + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl factoryreset sleep 1 + sudo "${CMAKE_BINARY_DIR}"/tests/dbus/otbr-test-dbus-client + + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl factoryreset + sleep 1 + + sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ + --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ + io.openthread.BorderRouter.Attach \ + array:byte: \ + uint16:0xffff \ + string:OpenThread \ + uint64:0xffffffffffffffff \ + array:byte: \ + uint32:0xffffffff + + local dataset="0x0e,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x33,0x08,0x00,0x00,0x00," + dataset+="0x00,0x00,0x01,0x00,0x00,0x34,0x04,0x00,0x04,0x80,0x88,0x00,0x03,0x00,0x00,0x0d," + dataset+="0x35,0x06,0x00,0x04,0x00,0x1f,0xff,0xe0,0x02,0x08,0xae,0x9b,0xd4,0x19,0x59,0x55," + dataset+="0x56,0x43,0x07,0x08,0xfd,0xc2,0x04,0x93,0xa7,0x64,0x6c,0x28,0x05,0x10,0x3c,0x2e," + dataset+="0x53,0xb6,0xd6,0x42,0xc5,0x9e,0x25,0x79,0xe4,0x3a,0x5a,0x0d,0xb2,0xfb,0x03,0x0f," + dataset+="0x4f,0x70,0x65,0x6e,0x54,0x68,0x72,0x65,0x61,0x64,0x2d,0x32,0x36,0x35,0x38,0x01," + dataset+="0x02,0x26,0x58,0x04,0x10,0x84,0xd7,0x14,0x51,0x72,0xb9,0xdc,0x74,0x22,0x45,0xe7," + dataset+="0x89,0x97,0x87,0xd3,0xb2,0x0c,0x04,0x02,0xa0,0xff,0xf8" + sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ + --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ + io.openthread.BorderRouter.AttachAllNodesTo \ + "array:byte:${dataset}" + + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl dataset pending | grep "Active Timestamp: 2" + + sleep 310 + + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl dataset active | grep "Active Timestamp: 2" + sudo "${CMAKE_BINARY_DIR}"/third_party/openthread/repo/src/posix/ot-ctl networkkey | grep 3c2e53b6d642c59e2579e43a5a0db2fb } main "$@"