From 08d21f1f0718b7ff680022731d5f48253a3a0d91 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 20 Feb 2024 12:49:42 -0800 Subject: [PATCH] [netdiag] add support for Vendor App URL TLV (#9816) This commit contains the following: - Adds support for the Vendor App URL TLV. - Includes new public OT APIs and configurations to get and set the TLV value. - Enables use of the TLV in the CLI `networkdiagnostic` command. - Updates `test-020-net-diag-vendor-info.py` to validate the new TLV. --- include/openthread/instance.h | 2 +- include/openthread/netdiag.h | 31 +++++++++++++- src/cli/cli.cpp | 40 +++++++++++++++++-- src/core/api/netdiag_api.cpp | 10 +++++ src/core/config/network_diagnostic.h | 10 +++++ src/core/thread/network_diagnostic.cpp | 16 ++++++++ src/core/thread/network_diagnostic.hpp | 22 ++++++++++ src/core/thread/network_diagnostic_tlvs.hpp | 13 ++++++ tests/toranj/cli/cli.py | 6 +++ .../cli/test-020-net-diag-vendor-info.py | 18 ++++++++- 10 files changed, 161 insertions(+), 7 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 335199707..fd5704ab6 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (395) +#define OPENTHREAD_API_VERSION (396) /** * @addtogroup api-instance diff --git a/include/openthread/netdiag.h b/include/openthread/netdiag.h index 955595257..8485475a5 100644 --- a/include/openthread/netdiag.h +++ b/include/openthread/netdiag.h @@ -95,13 +95,14 @@ enum OT_NETWORK_DIAGNOSTIC_TLV_ANSWER = 32, ///< Answer TLV OT_NETWORK_DIAGNOSTIC_TLV_QUERY_ID = 33, ///< Query ID TLV OT_NETWORK_DIAGNOSTIC_TLV_MLE_COUNTERS = 34, ///< MLE Counters TLV - + OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_APP_URL = 35, ///< Vendor App URL TLV }; #define OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_NAME_TLV_LENGTH 32 ///< Max length of Vendor Name TLV. #define OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_MODEL_TLV_LENGTH 32 ///< Max length of Vendor Model TLV. #define OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_SW_VERSION_TLV_LENGTH 16 ///< Max length of Vendor SW Version TLV. #define OT_NETWORK_DIAGNOSTIC_MAX_THREAD_STACK_VERSION_TLV_LENGTH 64 ///< Max length of Thread Stack Version TLV. +#define OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_APP_URL_TLV_LENGTH 96 ///< Max length of Vendor App URL TLV. typedef uint16_t otNetworkDiagIterator; ///< Used to iterate through Network Diagnostic TLV. @@ -294,6 +295,7 @@ typedef struct otNetworkDiagTlv char mVendorModel[OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_MODEL_TLV_LENGTH + 1]; char mVendorSwVersion[OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_SW_VERSION_TLV_LENGTH + 1]; char mThreadStackVersion[OT_NETWORK_DIAGNOSTIC_MAX_THREAD_STACK_VERSION_TLV_LENGTH + 1]; + char mVendorAppUrl[OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_APP_URL_TLV_LENGTH + 1]; struct { uint8_t mCount; @@ -428,6 +430,16 @@ const char *otThreadGetVendorModel(otInstance *aInstance); */ const char *otThreadGetVendorSwVersion(otInstance *aInstance); +/** + * Get the vendor app URL string. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The vendor app URL string. + * + */ +const char *otThreadGetVendorAppUrl(otInstance *aInstance); + /** * Set the vendor name string. * @@ -479,6 +491,23 @@ otError otThreadSetVendorModel(otInstance *aInstance, const char *aVendorModel); */ otError otThreadSetVendorSwVersion(otInstance *aInstance, const char *aVendorSwVersion); +/** + * Set the vendor app URL string. + * + * Requires `OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE`. + * + * @p aVendorAppUrl should be UTF8 with max length of 64 chars (`MAX_VENDOR_APPL_URL_TLV_LENGTH`). Maximum length + * does not include the null `\0` character. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aVendorAppUrl The vendor app URL string. + * + * @retval OT_ERROR_NONE Successfully set the vendor app URL string. + * @retval OT_ERROR_INVALID_ARGS @p aVendorAppUrl is not valid (too long or not UTF8). + * + */ +otError otThreadSetVendorAppUrl(otInstance *aInstance, const char *aVendorAppUrl); + /** * @} * diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 454033409..570ac1af1 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -7682,7 +7682,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) error = ProcessGet(aArgs, otThreadGetVendorName); #else /** - * @cli vendor name (name) + * @cli vendor name (set) * @code * vendor name nest * Done @@ -7712,7 +7712,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) error = ProcessGet(aArgs, otThreadGetVendorModel); #else /** - * @cli vendor model (name) + * @cli vendor model (set) * @code * vendor model Hub\ Max * Done @@ -7742,7 +7742,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) error = ProcessGet(aArgs, otThreadGetVendorSwVersion); #else /** - * @cli vendor swversion (version) + * @cli vendor swversion (set) * @code * vendor swversion Marble3.5.1 * Done @@ -7754,6 +7754,36 @@ template <> otError Interpreter::Process(Arg aArgs[]) error = ProcessGetSet(aArgs, otThreadGetVendorSwVersion, otThreadSetVendorSwVersion); #endif } + /** + * @cli vendor appurl + * @code + * vendor appurl + * http://www.example.com + * Done + * @endcode + * @par api_copy + * #otThreadGetVendorAppUrl + */ + else if (aArgs[0] == "appurl") + { + aArgs++; + +#if !OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE + error = ProcessGet(aArgs, otThreadGetVendorAppUrl); +#else + /** + * @cli vendor appurl (set) + * @code + * vendor appurl http://www.example.com + * Done + * @endcode + * @par api_copy + * #otThreadSetVendorAppUrl + * @cparam vendor appurl @ca{url} + */ + error = ProcessGetSet(aArgs, otThreadGetVendorAppUrl, otThreadSetVendorAppUrl); +#endif + } return error; } @@ -7829,6 +7859,7 @@ template <> otError Interpreter::Process(Arg aArgs[]) * - `28`: Thread Stack Version TLV (version identifier as UTF-8 string for Thread stack codebase/commit/version) * - `29`: Child TLV * - `34`: MLE Counters TLV + * - `35`: Vendor App URL TLV * @par * Sends a network diagnostic request to retrieve specified Type Length Values (TLVs) * for the specified addresses(es). @@ -7996,6 +8027,9 @@ void Interpreter::HandleDiagnosticGetResponse(otError aError, case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_SW_VERSION: OutputLine("Vendor SW Version: %s", diagTlv.mData.mVendorSwVersion); break; + case OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_APP_URL: + OutputLine("Vendor App URL: %s", diagTlv.mData.mVendorAppUrl); + break; case OT_NETWORK_DIAGNOSTIC_TLV_THREAD_STACK_VERSION: OutputLine("Thread Stack Version: %s", diagTlv.mData.mThreadStackVersion); break; diff --git a/src/core/api/netdiag_api.cpp b/src/core/api/netdiag_api.cpp index ffcc4c121..36c084d40 100644 --- a/src/core/api/netdiag_api.cpp +++ b/src/core/api/netdiag_api.cpp @@ -89,6 +89,11 @@ const char *otThreadGetVendorSwVersion(otInstance *aInstance) return AsCoreType(aInstance).Get().GetVendorSwVersion(); } +const char *otThreadGetVendorAppUrl(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().GetVendorAppUrl(); +} + #if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE otError otThreadSetVendorName(otInstance *aInstance, const char *aVendorName) { @@ -104,4 +109,9 @@ otError otThreadSetVendorSwVersion(otInstance *aInstance, const char *aVendorSwV { return AsCoreType(aInstance).Get().SetVendorSwVersion(aVendorSwVersion); } + +otError otThreadSetVendorAppUrl(otInstance *aInstance, const char *aVendorAppUrl) +{ + return AsCoreType(aInstance).Get().SetVendorAppUrl(aVendorAppUrl); +} #endif diff --git a/src/core/config/network_diagnostic.h b/src/core/config/network_diagnostic.h index ccf128d38..6f670efc7 100644 --- a/src/core/config/network_diagnostic.h +++ b/src/core/config/network_diagnostic.h @@ -75,6 +75,16 @@ #define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSION "" #endif +/** + * @def OPENTHREAD_CONFIG_NET_DIAG_VENDOR_APP_URL + * + * Specifies the default Vendor App URL string. + * + */ +#ifndef OPENTHREAD_CONFIG_NET_DIAG_VENDOR_APP_URL +#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_APP_URL "" +#endif + /** * @def OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE * diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index 43c1ea736..f32e7813e 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -61,6 +61,7 @@ namespace NetworkDiagnostic { const char Server::kVendorName[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME; const char Server::kVendorModel[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL; const char Server::kVendorSwVersion[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSION; +const char Server::kVendorAppUrl[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_APP_URL; //--------------------------------------------------------------------------------------------------------------------- // Server @@ -71,11 +72,13 @@ Server::Server(Instance &aInstance) static_assert(sizeof(kVendorName) <= sizeof(VendorNameTlv::StringType), "VENDOR_NAME is too long"); static_assert(sizeof(kVendorModel) <= sizeof(VendorModelTlv::StringType), "VENDOR_MODEL is too long"); static_assert(sizeof(kVendorSwVersion) <= sizeof(VendorSwVersionTlv::StringType), "VENDOR_SW_VERSION is too long"); + static_assert(sizeof(kVendorAppUrl) <= sizeof(VendorAppUrlTlv::StringType), "VENDOR_APP_URL is too long"); #if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE memcpy(mVendorName, kVendorName, sizeof(kVendorName)); memcpy(mVendorModel, kVendorModel, sizeof(kVendorModel)); memcpy(mVendorSwVersion, kVendorSwVersion, sizeof(kVendorSwVersion)); + memcpy(mVendorAppUrl, kVendorAppUrl, sizeof(kVendorAppUrl)); #endif } @@ -96,6 +99,11 @@ Error Server::SetVendorSwVersion(const char *aVendorSwVersion) return StringCopy(mVendorSwVersion, aVendorSwVersion, kStringCheckUtf8Encoding); } +Error Server::SetVendorAppUrl(const char *aVendorAppUrl) +{ + return StringCopy(mVendorAppUrl, aVendorAppUrl, kStringCheckUtf8Encoding); +} + #endif void Server::PrepareMessageInfoForDest(const Ip6::Address &aDestination, Tmf::MessageInfo &aMessageInfo) const @@ -329,6 +337,10 @@ Error Server::AppendDiagTlv(uint8_t aTlvType, Message &aMessage) error = Tlv::Append(aMessage, GetVendorSwVersion()); break; + case Tlv::kVendorAppUrl: + error = Tlv::Append(aMessage, GetVendorAppUrl()); + break; + case Tlv::kThreadStackVersion: error = Tlv::Append(aMessage, otGetVersionString()); break; @@ -1225,6 +1237,10 @@ Error Client::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator, SuccessOrExit(error = Tlv::Read(aMessage, offset, aTlvInfo.mData.mVendorSwVersion)); break; + case Tlv::kVendorAppUrl: + SuccessOrExit(error = Tlv::Read(aMessage, offset, aTlvInfo.mData.mVendorAppUrl)); + break; + case Tlv::kThreadStackVersion: SuccessOrExit(error = Tlv::Read(aMessage, offset, aTlvInfo.mData.mThreadStackVersion)); diff --git a/src/core/thread/network_diagnostic.hpp b/src/core/thread/network_diagnostic.hpp index de16b7c70..fb9d2b844 100644 --- a/src/core/thread/network_diagnostic.hpp +++ b/src/core/thread/network_diagnostic.hpp @@ -141,10 +141,30 @@ public: */ Error SetVendorSwVersion(const char *aVendorSwVersion); + /** + * Returns the vendor app URL string. + * + * @returns the vendor app URL string. + * + */ + const char *GetVendorAppUrl(void) const { return mVendorAppUrl; } + + /** + * Sets the vendor app URL string. + * + * @param[in] aVendorAppUrl The vendor app URL string + * + * @retval kErrorNone Successfully set the vendor app URL. + * @retval kErrorInvalidArgs @p aVendorAppUrl is not valid (too long or not UTF8). + * + */ + Error SetVendorAppUrl(const char *aVendorAppUrl); + #else const char *GetVendorName(void) const { return kVendorName; } const char *GetVendorModel(void) const { return kVendorModel; } const char *GetVendorSwVersion(void) const { return kVendorSwVersion; } + const char *GetVendorAppUrl(void) const { return kVendorAppUrl; } #endif // OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE private: @@ -173,6 +193,7 @@ private: static const char kVendorName[]; static const char kVendorModel[]; static const char kVendorSwVersion[]; + static const char kVendorAppUrl[]; Error AppendDiagTlv(uint8_t aTlvType, Message &aMessage); Error AppendIp6AddressList(Message &aMessage); @@ -211,6 +232,7 @@ private: VendorNameTlv::StringType mVendorName; VendorModelTlv::StringType mVendorModel; VendorSwVersionTlv::StringType mVendorSwVersion; + VendorAppUrlTlv::StringType mVendorAppUrl; #endif #if OPENTHREAD_FTD diff --git a/src/core/thread/network_diagnostic_tlvs.hpp b/src/core/thread/network_diagnostic_tlvs.hpp index 2efa744f4..acbaf5cf3 100644 --- a/src/core/thread/network_diagnostic_tlvs.hpp +++ b/src/core/thread/network_diagnostic_tlvs.hpp @@ -96,6 +96,7 @@ public: kAnswer = OT_NETWORK_DIAGNOSTIC_TLV_ANSWER, kQueryId = OT_NETWORK_DIAGNOSTIC_TLV_QUERY_ID, kMleCounters = OT_NETWORK_DIAGNOSTIC_TLV_MLE_COUNTERS, + kVendorAppUrl = OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_APP_URL, }; /** @@ -122,6 +123,12 @@ public: */ static constexpr uint8_t kMaxThreadStackVersionLength = OT_NETWORK_DIAGNOSTIC_MAX_THREAD_STACK_VERSION_TLV_LENGTH; + /** + * Maximum length of Vendor SW Version TLV. + * + */ + static constexpr uint8_t kMaxVendorAppUrlLength = OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_APP_URL_TLV_LENGTH; + /** * Returns the Type value. * @@ -236,6 +243,12 @@ typedef StringTlvInfo Ven */ typedef StringTlvInfo ThreadStackVersionTlv; +/** + * Defines Vendor App URL TLV constants and types. + * + */ +typedef StringTlvInfo VendorAppUrlTlv; + /** * Defines Child IPv6 Address List TLV constants and types. * diff --git a/tests/toranj/cli/cli.py b/tests/toranj/cli/cli.py index 6bda0839e..385d8e584 100644 --- a/tests/toranj/cli/cli.py +++ b/tests/toranj/cli/cli.py @@ -378,6 +378,12 @@ class Node(object): def set_vendor_sw_version(self, version): return self._cli_no_output('vendor swversion', version) + def get_vendor_app_url(self): + return self._cli_single_output('vendor appurl') + + def set_vendor_app_url(self, url): + return self._cli_no_output('vendor appurl', url) + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # netdata diff --git a/tests/toranj/cli/test-020-net-diag-vendor-info.py b/tests/toranj/cli/test-020-net-diag-vendor-info.py index f923dde19..a8bb7daaa 100755 --- a/tests/toranj/cli/test-020-net-diag-vendor-info.py +++ b/tests/toranj/cli/test-020-net-diag-vendor-info.py @@ -69,6 +69,7 @@ VENDOR_MODEL_TLV = 26 VENDOR_SW_VERSION_TLV = 27 THREAD_STACK_VERSION_TLV = 28 MLE_COUNTERS_TLV = 34 +VENDOR_APP_URL = 35 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Check setting vendor name, model, ans sw version @@ -76,10 +77,12 @@ MLE_COUNTERS_TLV = 34 r1.set_vendor_name('nest') r1.set_vendor_model('marble') r1.set_vendor_sw_version('ot-1.3.1') +r1.set_vendor_app_url('https://example.com/vendor-app') verify(r1.get_vendor_name() == 'nest') verify(r1.get_vendor_model() == 'marble') verify(r1.get_vendor_sw_version() == 'ot-1.3.1') +verify(r1.get_vendor_app_url() == 'https://example.com/vendor-app') #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Check invalid names (too long) @@ -126,6 +129,8 @@ except cli.CliError as e: verify(errored) +r2.set_vendor_app_url("https://example.com/vendor-app") + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Perform net diag query @@ -153,6 +158,13 @@ verify(len(result) == 2) verify(result[1].startswith("Vendor SW Version:")) verify(result[1].split(':')[1].strip() == r1.get_vendor_sw_version()) +# Get vendor app URL (TLV 35) + +result = r2.cli('networkdiagnostic get', r1_rloc, VENDOR_APP_URL) +verify(len(result) == 2) +verify(result[1].startswith("Vendor App URL:")) +verify(result[1].split(':', 1)[1].strip() == r1.get_vendor_app_url()) + # Get thread stack version (TLV 30) result = r2.cli('networkdiagnostic get', r1_rloc, THREAD_STACK_VERSION_TLV) @@ -163,8 +175,8 @@ verify(r1.get_version().startswith(result[1].split(':', 1)[1].strip())) # Get all three TLVs (now from `r1`) result = r1.cli('networkdiagnostic get', r2_rloc, VENDOR_NAME_TLV, VENDOR_MODEL_TLV, VENDOR_SW_VERSION_TLV, - THREAD_STACK_VERSION_TLV) -verify(len(result) == 5) + THREAD_STACK_VERSION_TLV, VENDOR_APP_URL) +verify(len(result) == 6) for line in result[1:]: if line.startswith("Vendor Name:"): verify(line.split(':')[1].strip() == r2.get_vendor_name()) @@ -172,6 +184,8 @@ for line in result[1:]: verify(line.split(':')[1].strip() == r2.get_vendor_model()) elif line.startswith("Vendor SW Version:"): verify(line.split(':')[1].strip() == r2.get_vendor_sw_version()) + elif line.startswith("Vendor App URL:"): + verify(line.split(':', 1)[1].strip() == r2.get_vendor_app_url()) elif line.startswith("Thread Stack Version:"): verify(r2.get_version().startswith(line.split(':', 1)[1].strip())) else: