mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[netdiag] require 'RD:' prefix for vendor name on reference devices (#12233)
When `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is active, this change mandates that the vendor name string MUST begin with the "RD:" prefix. This ensures that reference devices are clearly and consistently identifiable through network diagnostic queries. The enforcement is applied at two levels: - A compile-time `static_assert` is added to validate the default `OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME` at build time. This uses a new `constexpr` helper utility `CheckConstStringPrefix()`. - A runtime check is added to `otThreadSetVendorName()`, which will now return `OT_ERROR_INVALID_ARGS` if an invalid name is provided on a reference device build. All related test configurations (`scan-build`, `toranj`, `nexus`) and CLI tests are updated to reflect this new requirement and validate it.
This commit is contained in:
committed by
GitHub
parent
5fd62a9acf
commit
b3d3b5c3c7
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (572)
|
||||
#define OPENTHREAD_API_VERSION (573)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -433,11 +433,16 @@ const char *otThreadGetVendorAppUrl(otInstance *aInstance);
|
||||
* @p aVendorName should be UTF8 with max length of 32 chars (`MAX_VENDOR_NAME_TLV_LENGTH`). Maximum length does not
|
||||
* include the null `\0` character.
|
||||
*
|
||||
* If `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled, @p aVendorName must start with the "RD:" prefix.
|
||||
* This is enforced to ensure reference devices are identifiable. If @p aVendorName does not follow this pattern,
|
||||
* the name is rejected, and `OT_ERROR_INVALID_ARGS` is returned.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aVendorName The vendor name string.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the vendor name.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aVendorName is not valid (too long or not UTF8).
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aVendorName is not valid. It is too long, is not UTF-8, or does not start with
|
||||
* the "RD:" prefix when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
|
||||
*/
|
||||
otError otThreadSetVendorName(otInstance *aInstance, const char *aVendorName);
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ OT_BUILD_OPTIONS=(
|
||||
"-DOT_SRP_SERVER=ON"
|
||||
"-DOT_SRP_SERVER_FAST_START_MODE=ON"
|
||||
"-DOT_UPTIME=ON"
|
||||
"-DOT_VENDOR_NAME=OpenThread"
|
||||
"-DOT_VENDOR_NAME=RD:OpenThread"
|
||||
"-DOT_VENDOR_MODEL=Scan-build"
|
||||
"-DOT_VENDOR_SW_VERSION=OT"
|
||||
)
|
||||
|
||||
@@ -396,6 +396,25 @@ inline constexpr bool AreConstStringsEqual(const char *aFirst, const char *aSeco
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This `constexpr` function checks whether a given C string starts with a given prefix string.
|
||||
*
|
||||
* This is intended for use in `static_assert`, e.g., checking the hardcoded vendor name on a reference device. It is
|
||||
* not recommended to use this function in other situations as it uses recursion so that it can be `constexpr`.
|
||||
*
|
||||
* @param[in] aString The string to check.
|
||||
* @param[in] aPrefix The prefix string.
|
||||
*
|
||||
* @retval TRUE If @p aString starts with @p aPrefix.
|
||||
* @retval FALSE If @p aString does not start with @p aPrefix.
|
||||
*/
|
||||
inline constexpr bool CheckConstStringPrefix(const char *aString, const char *aPrefix)
|
||||
{
|
||||
return (*aPrefix == kNullChar)
|
||||
? true
|
||||
: ((*aString == *aPrefix) ? CheckConstStringPrefix(aString + 1, aPrefix + 1) : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements writing to a string buffer.
|
||||
*/
|
||||
|
||||
@@ -43,14 +43,23 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "config/misc.h"
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME
|
||||
*
|
||||
* Specifies the default Vendor Name string.
|
||||
*
|
||||
* If `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled, the Vendor Name string MUST start with the "RD:" prefix
|
||||
* to ensure reference devices are identifiable. This is checked and enforced at build-time (`static_assert`).
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME "RD:"
|
||||
#else
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME ""
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL
|
||||
|
||||
@@ -46,6 +46,13 @@ 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;
|
||||
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
static constexpr char kVendorNamePrefix[] = "RD:";
|
||||
|
||||
static_assert(CheckConstStringPrefix(OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME, kVendorNamePrefix),
|
||||
"VENDOR_NAME MUST start with 'RD:' prefix for a reference device.");
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Server
|
||||
|
||||
@@ -70,7 +77,16 @@ Server::Server(Instance &aInstance)
|
||||
|
||||
Error Server::SetVendorName(const char *aVendorName)
|
||||
{
|
||||
return StringCopy(mVendorName, aVendorName, kStringCheckUtf8Encoding);
|
||||
Error error;
|
||||
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
VerifyOrExit(aVendorName != nullptr && StringStartsWith(aVendorName, kVendorNamePrefix), error = kErrorInvalidArgs);
|
||||
#endif
|
||||
|
||||
SuccessOrExit(error = StringCopy(mVendorName, aVendorName, kStringCheckUtf8Encoding));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Server::SetVendorModel(const char *aVendorModel)
|
||||
|
||||
@@ -131,8 +131,13 @@ public:
|
||||
*
|
||||
* @param[in] aVendorName The vendor name string.
|
||||
*
|
||||
* If `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled, @p aVendorName must start with the "RD:" prefix.
|
||||
* This is enforced to ensure reference devices are identifiable. If @p aVendorName does not follow this pattern,
|
||||
* the name is rejected, and `kErrorInvalidArgs` is returned.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the vendor name.
|
||||
* @retval kErrorInvalidArgs @p aVendorName is not valid (too long or not UTF8).
|
||||
* @retval kErrorInvalidArgs @p aVendorName is not valid. It is too long, is not UTF-8, or does not start with
|
||||
* the "RD:" prefix when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
|
||||
*/
|
||||
Error SetVendorName(const char *aVendorName);
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
#define OPENTHREAD_CONFIG_NAT64_IDLE_TIMEOUT_SECONDS 600
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE OPENTHREAD_FTD
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL "Nexus Simulation"
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME "OpenThread by Google Nest"
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME "RD:OpenThread by Google Nest"
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSION "OT-simul-nexus"
|
||||
#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE 1
|
||||
#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 256
|
||||
|
||||
@@ -71,8 +71,8 @@ expect -re {\tVALUE:\t0x2242([0-9a-fA-F]{132})}
|
||||
|
||||
send "diagnostic_tlvs channelpages maxchildtimeout eui64 vendorname vendormodel vendorswversion vendorappurl\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
|
||||
expect_line "\tLEN:\t27"
|
||||
expect_line "\tVALUE:\t0x1101001304000000f0170818b430000000000119001a001b002300"
|
||||
expect_line "\tLEN:\t30"
|
||||
expect_line "\tVALUE:\t0x1101001304000000f0170818b4300000000001190352443a1a001b002300"
|
||||
|
||||
send "diagnostic_tlvs childtable\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
|
||||
|
||||
@@ -75,12 +75,12 @@ NON_PREFERRED_CHANNELS_TLV = 36
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Check setting vendor name, model, ans sw version
|
||||
|
||||
r1.set_vendor_name('nest')
|
||||
r1.set_vendor_name('RD:nest')
|
||||
r1.set_vendor_model('marble')
|
||||
r1.set_vendor_sw_version('ot-1.4')
|
||||
r1.set_vendor_app_url('https://example.com/vendor-app')
|
||||
|
||||
verify(r1.get_vendor_name() == 'nest')
|
||||
verify(r1.get_vendor_name() == 'RD:nest')
|
||||
verify(r1.get_vendor_model() == 'marble')
|
||||
verify(r1.get_vendor_sw_version() == 'ot-1.4')
|
||||
verify(r1.get_vendor_app_url() == 'https://example.com/vendor-app')
|
||||
@@ -90,12 +90,24 @@ verify(r1.get_vendor_app_url() == 'https://example.com/vendor-app')
|
||||
|
||||
# Vendor name should accept up to 32 chars
|
||||
|
||||
r2.set_vendor_name('01234567890123456789012345678901') # 32 chars
|
||||
r2.set_vendor_name('RD:01234567890123456789012345678') # 32 chars
|
||||
|
||||
errored = False
|
||||
|
||||
try:
|
||||
r2.set_vendor_name('012345678901234567890123456789012') # 33 chars
|
||||
r2.set_vendor_name('RD:012345678901234567890123456789') # 33 chars
|
||||
except cli.CliError as e:
|
||||
verify(e.message == 'InvalidArgs')
|
||||
errored = True
|
||||
|
||||
verify(errored)
|
||||
|
||||
# Vendor name under `REFERENCE_DEVICE` build MUST start with "RD:".
|
||||
|
||||
errored = False
|
||||
|
||||
try:
|
||||
r2.set_vendor_name('name_without_RD_prefix')
|
||||
except cli.CliError as e:
|
||||
verify(e.message == 'InvalidArgs')
|
||||
errored = True
|
||||
@@ -143,21 +155,21 @@ r2_rloc = r2.get_rloc_ip_addr()
|
||||
result = r2.cli('networkdiagnostic get', r1_rloc, VENDOR_NAME_TLV)
|
||||
verify(len(result) == 2)
|
||||
verify(result[1].startswith("Vendor Name:"))
|
||||
verify(result[1].split(':')[1].strip() == r1.get_vendor_name())
|
||||
verify(result[1].split(':', 1)[1].strip() == r1.get_vendor_name())
|
||||
|
||||
# Get vendor model (TLV 28)
|
||||
|
||||
result = r2.cli('networkdiagnostic get', r1_rloc, VENDOR_MODEL_TLV)
|
||||
verify(len(result) == 2)
|
||||
verify(result[1].startswith("Vendor Model:"))
|
||||
verify(result[1].split(':')[1].strip() == r1.get_vendor_model())
|
||||
verify(result[1].split(':', 1)[1].strip() == r1.get_vendor_model())
|
||||
|
||||
# Get vendor sw version (TLV 29)
|
||||
|
||||
result = r2.cli('networkdiagnostic get', r1_rloc, VENDOR_SW_VERSION_TLV)
|
||||
verify(len(result) == 2)
|
||||
verify(result[1].startswith("Vendor SW Version:"))
|
||||
verify(result[1].split(':')[1].strip() == r1.get_vendor_sw_version())
|
||||
verify(result[1].split(':', 1)[1].strip() == r1.get_vendor_sw_version())
|
||||
|
||||
# Get vendor app URL (TLV 35)
|
||||
|
||||
@@ -180,11 +192,11 @@ result = r1.cli('networkdiagnostic get', r2_rloc, VENDOR_NAME_TLV, VENDOR_MODEL_
|
||||
verify(len(result) == 6)
|
||||
for line in result[1:]:
|
||||
if line.startswith("Vendor Name:"):
|
||||
verify(line.split(':')[1].strip() == r2.get_vendor_name())
|
||||
verify(line.split(':', 1)[1].strip() == r2.get_vendor_name())
|
||||
elif line.startswith("Vendor Model:"):
|
||||
verify(line.split(':')[1].strip() == r2.get_vendor_model())
|
||||
verify(line.split(':', 1)[1].strip() == r2.get_vendor_model())
|
||||
elif line.startswith("Vendor SW Version:"):
|
||||
verify(line.split(':')[1].strip() == r2.get_vendor_sw_version())
|
||||
verify(line.split(':', 1)[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:"):
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
#define OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE 1
|
||||
|
||||
#ifndef OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME "OpenThread by Google Nest"
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME "RD:OpenThread by Google Nest"
|
||||
#endif
|
||||
|
||||
#ifndef OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL
|
||||
|
||||
@@ -466,6 +466,15 @@ static_assert(!ot::AreStringsInOrder("z", "abcd"), "AreStringsInOrder() failed")
|
||||
static_assert(!ot::AreStringsInOrder("0", ""), "AreStringsInOrder() failed");
|
||||
#endif
|
||||
|
||||
static_assert(ot::CheckConstStringPrefix("abc", "a"), "CheckConstStringPrefix() failed");
|
||||
static_assert(ot::CheckConstStringPrefix("abc", "ab"), "CheckConstStringPrefix() failed");
|
||||
static_assert(ot::CheckConstStringPrefix("abc", "abc"), "CheckConstStringPrefix() failed");
|
||||
static_assert(ot::CheckConstStringPrefix("abc", ""), "CheckConstStringPrefix() failed");
|
||||
|
||||
static_assert(!ot::CheckConstStringPrefix("abc", "b"), "CheckConstStringPrefix() failed");
|
||||
static_assert(!ot::CheckConstStringPrefix("abc", "abcd"), "CheckConstStringPrefix() failed");
|
||||
static_assert(!ot::CheckConstStringPrefix("", "a"), "CheckConstStringPrefix() failed");
|
||||
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
|
||||
@@ -353,8 +353,8 @@ class TestOTCI(unittest.TestCase):
|
||||
logging.info('dataset active -x: %r', leader.get_dataset_bytes('active'))
|
||||
logging.info('dataset pending -x: %r', leader.get_dataset_bytes('pending'))
|
||||
|
||||
leader.set_vendor_name('OpenThread')
|
||||
self.assertEqual('OpenThread', leader.get_vendor_name())
|
||||
leader.set_vendor_name('RD:OpenThread')
|
||||
self.assertEqual('RD:OpenThread', leader.get_vendor_name())
|
||||
leader.set_vendor_model('some_model')
|
||||
self.assertEqual('some_model', leader.get_vendor_model())
|
||||
leader.set_vendor_sw_version('1.0.0')
|
||||
|
||||
Reference in New Issue
Block a user