mirror of
https://github.com/espressif/openthread.git
synced 2026-08-22 10:29:52 +00:00
[vendor-info] generalize vendor OUI to support variable lengths (#13258)
This commit generalizes the Vendor OUI (Organizationally Unique
Identifier) handling to support IEEE MAC Address Block Large
(MA-L, 24-bit), Medium(MA-M, 28-bit), and Small (MA-S, 36-bit)
assignments.
Key enhancements:
- Backward-Compatible Config Parsing: The
`OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI` configuration remains fully
backward compatible. If the macro is set to a traditional 24-bit
integer (e.g., `0x641666`), it is implicitly parsed as a 24-bit
OUI.
For larger or variable-length OUIs, a new explicit 48-bit format is
supported: `0x[BitLengthInHex][5 OUI Bytes]` (e.g. `0x1c001a2b3000ULL`
for 28-bit, and `0x24001a2b3c40ULL` for 36-bit). This format
encodes both prefix length and value into a single integer, making
it trivial to pass through command-line flags (e.g. `-D...`).
- Compile-Time Validation: Introduced `VendorInfo::OuiParser` template
class to parse and validate the configured OUI at compile-time
(`static_assert`). It ensures invalid lengths, out-of-range
configurations, or non-zero trailing bits fail the build
immediately.
- New APIs: Replaced legacy `uint32_t` representations with the
`otThreadVendorOui` containing `mBitLength` and a 5-byte buffer
`mBytes`. Added new public APIs `otThreadGetVendorOuiInfo()` and
`otThreadSetVendorOuiInfo()`, while deprecating the older 24-bit OUI
getters and setters.
- Border Agent & CLI Updates:
- Updated Border Agent TXT data generation (`vo` key) and parsing
to correctly handling of new OUI lengths.
- Updated CLI command utilities to output variable-length OUI bytes
formatted correctly.
- Added new `test_vendor_oui.cpp` unit tests to thoroughly validate
compile-time parsing and runtime class logic.
This commit is contained in:
@@ -42,6 +42,7 @@
|
||||
#include <openthread/dataset.h>
|
||||
#include <openthread/error.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/netdiag.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -61,7 +62,6 @@ extern "C" {
|
||||
#define OT_BORDER_AGENT_THREAD_VERSION_SIZE (16) ///< Max size of Thread Version string in `otBorderAgentTxtDataInfo`.
|
||||
#define OT_BORDER_AGENT_VENDOR_NAME_SIZE (32) ///< Max size of Vendor Name string in `otBorderAgentTxtDataInfo`.
|
||||
#define OT_BORDER_AGENT_MODEL_NAME_SIZE (32) ///< Max size of Model Name string in `otBorderAgentTxtDataInfo`.
|
||||
#define OT_BORDER_AGENT_VENDOR_OUI_SIZE (3) ///< Size of Vendor OUI (in bytes) in `otBorderAgentTxtDataInfo`.
|
||||
|
||||
/**
|
||||
* Represents the Connection Mode in a Border Agent State Bitmap.
|
||||
@@ -169,7 +169,7 @@ typedef struct otBorderAgentTxtDataInfo
|
||||
otExtAddress mExtAddress; ///< Extended Address.
|
||||
char mVendorName[OT_BORDER_AGENT_VENDOR_NAME_SIZE]; ///< Vendor Name string.
|
||||
char mModelName[OT_BORDER_AGENT_MODEL_NAME_SIZE]; ///< Model Name string.
|
||||
uint8_t mVendorOui[OT_BORDER_AGENT_VENDOR_OUI_SIZE]; ///< Vendor OUI (24-bit).
|
||||
otThreadVendorOui mVendorOui; ///< Vendor OUI.
|
||||
} otBorderAgentTxtDataInfo;
|
||||
|
||||
/**
|
||||
|
||||
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (607)
|
||||
#define OPENTHREAD_API_VERSION (608)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
+107
-18
@@ -273,6 +273,50 @@ typedef struct otNetworkDiagChildTable
|
||||
*/
|
||||
typedef otBorderRoutingState otNetworkDiagBrState;
|
||||
|
||||
/**
|
||||
* Specifies the maximum size of a Thread Vendor OUI in bytes.
|
||||
*/
|
||||
#define OT_THREAD_VENDOR_OUI_MAX_SIZE 5
|
||||
|
||||
/**
|
||||
* Specifies the bit length of a MAC Address Block Large (MA-L) Vendor OUI.
|
||||
*/
|
||||
#define OT_THREAD_VENDOR_OUI_MA_L_BIT_LENGTH 24
|
||||
|
||||
/**
|
||||
* Specifies the bit length of a MAC Address Block Medium (MA-M) Vendor OUI.
|
||||
*/
|
||||
#define OT_THREAD_VENDOR_OUI_MA_M_BIT_LENGTH 28
|
||||
|
||||
/**
|
||||
* Specifies the bit length of a MAC Address Block Small (MA-S) Vendor OUI.
|
||||
*/
|
||||
#define OT_THREAD_VENDOR_OUI_MA_S_BIT_LENGTH 36
|
||||
|
||||
/**
|
||||
* Represents a Thread Vendor OUI (Organizationally Unique Identifier) which can have different lengths.
|
||||
*
|
||||
* A Vendor OUI can be assigned in one of the following formats:
|
||||
*
|
||||
* - 24-bit Prefix (MA-L): Exactly 3 bytes (24 bits).
|
||||
* Example: `00-1A-2B` is represented with `mBitLength = 24` and `mBytes = [0x00, 0x1A, 0x2B, 0x00, 0x00]`.
|
||||
*
|
||||
* - 28-bit Prefix (MA-M): Exactly 3.5 bytes (28 bits).
|
||||
* The half-byte (4 bits) at the end of the prefix occupies the Most Significant Nibble of the 4th byte.
|
||||
* The Least Significant Nibble of the 4th byte is set to zero.
|
||||
* Example: `00-1A-2B-3` is represented with `mBitLength = 28` and `mBytes = [0x00, 0x1A, 0x2B, 0x30, 0x00]`.
|
||||
*
|
||||
* - 36-bit Prefix (MA-S): Exactly 4.5 bytes (36 bits).
|
||||
* The half-byte (4 bits) at the end of the prefix occupies the Most Significant Nibble of the 5th byte.
|
||||
* The Least Significant Nibble of the 5th byte is set to zero.
|
||||
* Example: `00-1A-2B-3C-4` is represented with `mBitLength = 36` and `mBytes = [0x00, 0x1A, 0x2B, 0x3C, 0x40]`.
|
||||
*/
|
||||
typedef struct otThreadVendorOui
|
||||
{
|
||||
uint8_t mBitLength; ///< The OUI prefix length in bits (24, 28, or 36).
|
||||
uint8_t mBytes[OT_THREAD_VENDOR_OUI_MAX_SIZE]; ///< The OUI bytes in big-endian order.
|
||||
} otThreadVendorOui;
|
||||
|
||||
/**
|
||||
* Represents a Network Diagnostic TLV.
|
||||
*/
|
||||
@@ -426,19 +470,78 @@ const char *otThreadGetVendorSwVersion(otInstance *aInstance);
|
||||
const char *otThreadGetVendorAppUrl(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Represents an unspecified Vendor OUI.
|
||||
* Gets the vendor OUI.
|
||||
*
|
||||
* If no vendor OUI is yet set/configured on device, the `mBitLength` in @p aOui will be zero.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[out] aOui A pointer to an `otThreadVendorOui` to return the vendor OUI.
|
||||
*/
|
||||
#define OT_THREAD_UNSPECIFIED_VENDOR_OUI (0xffffffff)
|
||||
void otThreadGetVendorOuiInfo(otInstance *aInstance, otThreadVendorOui *aOui);
|
||||
|
||||
/**
|
||||
* Get the vendor OUI-24
|
||||
* Sets the vendor OUI.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE`.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aOui A pointer to the `otThreadVendorOui` to set.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the vendor OUI.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aOui has an invalid length.
|
||||
*/
|
||||
otError otThreadSetVendorOuiInfo(otInstance *aInstance, const otThreadVendorOui *aOui);
|
||||
|
||||
#define OT_THREAD_VENDOR_OUI_STRING_SIZE 16 ///< Recommended size for string representation of a vendor OUI.
|
||||
|
||||
/**
|
||||
* Converts a given vendor OUI to a human-readable string.
|
||||
*
|
||||
* The generated string format is hyphen-separated uppercase hexadecimal bytes (e.g., "00-1A-2B" for a 24-bit OUI).
|
||||
* For 28-bit and 36-bit OUIs, the trailing 4-bit nibble is appended as a single hexadecimal digit (e.g., "00-1A-2B-3"
|
||||
* for a 28-bit OUI). If @p aOui is invalid or unspecified, the string "unspecified" is returned.
|
||||
*
|
||||
* If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be truncated
|
||||
* but the outputted string is always null-terminated.
|
||||
*
|
||||
* @param[in] aOui The vendor OUI to convert.
|
||||
* @param[out] aBuffer A pointer to a char array to output the string (MUST NOT be NULL).
|
||||
* @param[in] aSize The size of @p aBuffer (in bytes). Recommended to use `OT_THREAD_VENDOR_OUI_STRING_SIZE`.
|
||||
*/
|
||||
void otThreadVendorOuiToString(const otThreadVendorOui *aOui, char *aBuffer, uint16_t aSize);
|
||||
|
||||
#define OT_THREAD_UNSPECIFIED_VENDOR_OUI (0xffffffff) ///< Represents an unspecified Vendor OUI.
|
||||
|
||||
/**
|
||||
* Gets the vendor OUI-24.
|
||||
*
|
||||
* @deprecated This function is deprecated. Use `otThreadGetVendorOuiInfo()` instead.
|
||||
*
|
||||
* If the configured Vendor OUI has a prefix length greater than 24 bits, this function returns the most significant
|
||||
* 24 bits (first 3 bytes) of the OUI to maintain backward compatibility.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @returns The vendor OUI-24 value in hex format, or `OT_THREAD_UNSPECIFIED_VENDOR_OUI` is not specified.
|
||||
* @returns The vendor OUI-24 value, or `OT_THREAD_UNSPECIFIED_VENDOR_OUI` if not specified.
|
||||
*/
|
||||
uint32_t otThreadGetVendorOui(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Sets the vendor OUI-24.
|
||||
*
|
||||
* @deprecated This function is deprecated. Use `otThreadSetVendorOuiInfo()` instead.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE`.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aVendorOui The vendor OUI-24 value in Hexadecimal representation (e.g., OUI 64-16-66 is represented as
|
||||
* `0x641666`). Must be a 24-bit value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the vendor OUI.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aVendorOui is not a valid 24-bit value.
|
||||
*/
|
||||
otError otThreadSetVendorOui(otInstance *aInstance, uint32_t aVendorOui);
|
||||
|
||||
/**
|
||||
* Set the vendor name string.
|
||||
*
|
||||
@@ -508,20 +611,6 @@ otError otThreadSetVendorSwVersion(otInstance *aInstance, const char *aVendorSwV
|
||||
*/
|
||||
otError otThreadSetVendorAppUrl(otInstance *aInstance, const char *aVendorAppUrl);
|
||||
|
||||
/**
|
||||
* Set the vendor OUI-24.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE`.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aVendorOui The vendor OUI-24 value in Hexadecimal representation (e.g., OUI 64-16-66 is represented as
|
||||
* `0x641666`). Must be a 24-bit value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the vendor OUI.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aVendorOui is not a valid 24-bit value.
|
||||
*/
|
||||
otError otThreadSetVendorOui(otInstance *aInstance, uint32_t aVendorOui);
|
||||
|
||||
/**
|
||||
* Callback function pointer to notify when a Network Diagnostic Reset request message is received for the
|
||||
* `OT_NETWORK_DIAGNOSTIC_TLV_NON_PREFERRED_CHANNELS` TLV.
|
||||
|
||||
+6
-13
@@ -756,8 +756,8 @@ void Interpreter::OutputBorderAgentTxtDataInfo(uint8_t aIndentSize, const otBord
|
||||
|
||||
if (aInfo.mHasVendorOui)
|
||||
{
|
||||
OutputLine(aIndentSize, "VendorOui: %02X-%02X-%02X", aInfo.mVendorOui[0], aInfo.mVendorOui[1],
|
||||
aInfo.mVendorOui[2]);
|
||||
OutputFormat(aIndentSize, "VendorOui: ");
|
||||
OutputVendorOuiLine(aInfo.mVendorOui);
|
||||
}
|
||||
|
||||
if (aInfo.mHasStateBitmap)
|
||||
@@ -7600,23 +7600,16 @@ template <> otError Interpreter::Process<Cmd("vendor")>(Arg aArgs[])
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otThreadGetVendorOui
|
||||
* #otThreadGetVendorOuiInfo
|
||||
*/
|
||||
else if (aArgs[0] == "oui")
|
||||
{
|
||||
if (aArgs[1].IsEmpty())
|
||||
{
|
||||
uint32_t oui = otThreadGetVendorOui(GetInstancePtr());
|
||||
otThreadVendorOui oui;
|
||||
|
||||
if (oui == OT_THREAD_UNSPECIFIED_VENDOR_OUI)
|
||||
{
|
||||
OutputLine("unspecified");
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputLine("%02X-%02X-%02X", static_cast<uint8_t>((oui >> 16) & 0xff),
|
||||
static_cast<uint8_t>((oui >> 8) & 0xff), static_cast<uint8_t>(oui & 0xff));
|
||||
}
|
||||
otThreadGetVendorOuiInfo(GetInstancePtr(), &oui);
|
||||
OutputVendorOuiLine(oui);
|
||||
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
@@ -231,6 +231,20 @@ void Utils::OutputSockAddrLine(const otSockAddr &aSockAddr)
|
||||
OutputNewLine();
|
||||
}
|
||||
|
||||
void Utils::OutputVendorOui(const otThreadVendorOui &aOui)
|
||||
{
|
||||
char string[OT_THREAD_VENDOR_OUI_STRING_SIZE];
|
||||
|
||||
otThreadVendorOuiToString(&aOui, string, sizeof(string));
|
||||
OutputFormat("%s", string);
|
||||
}
|
||||
|
||||
void Utils::OutputVendorOuiLine(const otThreadVendorOui &aOui)
|
||||
{
|
||||
OutputVendorOui(aOui);
|
||||
OutputNewLine();
|
||||
}
|
||||
|
||||
void Utils::OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLength)
|
||||
{
|
||||
OutputDnsTxtData(/* aKeyValuePerLine */ false, 0, aTxtData, aTxtDataLength);
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <openthread/border_routing.h>
|
||||
#include <openthread/cli.h>
|
||||
#include <openthread/joiner.h>
|
||||
#include <openthread/netdiag.h>
|
||||
#include <openthread/thread.h>
|
||||
|
||||
#include "cli_config.h"
|
||||
@@ -431,6 +432,20 @@ public:
|
||||
*/
|
||||
void OutputSockAddrLine(const otSockAddr &aSockAddr);
|
||||
|
||||
/**
|
||||
* Outputs the Vendor OUI to the CLI console.
|
||||
*
|
||||
* @param[in] aOui A reference to the Vendor OUI.
|
||||
*/
|
||||
void OutputVendorOui(const otThreadVendorOui &aOui);
|
||||
|
||||
/**
|
||||
* Outputs the Vendor OUI to the CLI console and appends a newline.
|
||||
*
|
||||
* @param[in] aOui A reference to the Vendor OUI.
|
||||
*/
|
||||
void OutputVendorOuiLine(const otThreadVendorOui &aOui);
|
||||
|
||||
/**
|
||||
* Outputs DNS TXT data to the CLI console.
|
||||
*
|
||||
|
||||
@@ -85,7 +85,24 @@ const char *otThreadGetVendorAppUrl(otInstance *aInstance)
|
||||
return AsCoreType(aInstance).Get<VendorInfo>().GetAppUrl();
|
||||
}
|
||||
|
||||
uint32_t otThreadGetVendorOui(otInstance *aInstance) { return AsCoreType(aInstance).Get<VendorInfo>().GetOui(); }
|
||||
void otThreadGetVendorOuiInfo(otInstance *aInstance, otThreadVendorOui *aOui)
|
||||
{
|
||||
AssertPointerIsNotNull(aOui);
|
||||
|
||||
*aOui = AsCoreType(aInstance).Get<VendorInfo>().GetOui();
|
||||
}
|
||||
|
||||
void otThreadVendorOuiToString(const otThreadVendorOui *aOui, char *aBuffer, uint16_t aSize)
|
||||
{
|
||||
AsCoreType(aOui).ToString(aBuffer, aSize);
|
||||
}
|
||||
|
||||
uint32_t otThreadGetVendorOui(otInstance *aInstance)
|
||||
{
|
||||
// This API is deprecated. Use `otThreadGetVendorOuiInfo()` instead
|
||||
|
||||
return AsCoreType(aInstance).Get<VendorInfo>().GetOui().GetAsOui24();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
|
||||
|
||||
@@ -109,9 +126,28 @@ otError otThreadSetVendorAppUrl(otInstance *aInstance, const char *aVendorAppUrl
|
||||
return AsCoreType(aInstance).Get<VendorInfo>().SetAppUrl(aVendorAppUrl);
|
||||
}
|
||||
|
||||
otError otThreadSetVendorOuiInfo(otInstance *aInstance, const otThreadVendorOui *aOui)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<VendorInfo>().SetOui(AsCoreType(aOui));
|
||||
}
|
||||
|
||||
otError otThreadSetVendorOui(otInstance *aInstance, uint32_t aVendorOui)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<VendorInfo>().SetOui(aVendorOui);
|
||||
// This API is deprecated, use `otThreadSetVendorOuiInfo()` instead
|
||||
|
||||
Error error;
|
||||
VendorInfo::Oui oui;
|
||||
|
||||
VerifyOrExit(aVendorOui <= 0xffffff, error = kErrorInvalidArgs);
|
||||
|
||||
oui.Clear();
|
||||
oui.mBitLength = 24;
|
||||
BigEndian::WriteUint24(aVendorOui, oui.mBytes);
|
||||
|
||||
error = AsCoreType(aInstance).Get<VendorInfo>().SetOui(oui);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
|
||||
|
||||
@@ -91,10 +91,22 @@
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI
|
||||
*
|
||||
* Specifies the default Vendor OUI-24 value in Hexadecimal representation (e.g., OUI 64-16-66 is represented as
|
||||
* `0x641666`).
|
||||
* Specifies the default Vendor OUI (Organizationally Unique Identifier) value.
|
||||
*
|
||||
* The value of `0xffffffff` (UINT32_MAX) is used to indicate OUI is not specified.
|
||||
* This configuration supports multiple layout formats to maintain backward compatibility:
|
||||
*
|
||||
* - 24-bit OUI (MA-L): Hexadecimal representation of a 24-bit value (e.g., OUI 64-16-66 is represented as
|
||||
* `0x641666`). Values <= `0xffffff` are implicitly treated as a 24-bit OUI.
|
||||
*
|
||||
* - Explicit OUI with various lengths (24, 28, or 36 bits): A 48-bit hexadecimal value where the most significant
|
||||
* byte (bits 40-47) represents the prefix bit-length, and the lower 5 bytes (bits 0-39) represent the OUI bytes
|
||||
* in big-endian order:
|
||||
* - 28-bit OUI `00-1A-2B-3` is represented as `0x1c001a2b3000ULL`.
|
||||
* - 36-bit OUI `00-1A-2B-3C-4` is represented as `0x24001a2b3c40ULL`.
|
||||
*
|
||||
* The value of `0xffffffff` (UINT32_MAX) is used to indicate the Vendor OUI is not specified.
|
||||
*
|
||||
* The configured value is validated at compile-time to ensure it conforms to one of the supported prefix lengths.
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI
|
||||
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI (0xffffffff)
|
||||
|
||||
@@ -171,12 +171,11 @@ Error TxtData::Prepare(uint8_t *aBuffer,
|
||||
SuccessOrExit(error = encoder.AppendStringEntry(Key::kModelName, Get<VendorInfo>().GetModel()));
|
||||
}
|
||||
|
||||
if (aAddVendorOui && Get<VendorInfo>().IsOuiSpecified())
|
||||
if (aAddVendorOui && Get<VendorInfo>().GetOui().IsValid())
|
||||
{
|
||||
uint8_t ouiData[kVendorOuiSize];
|
||||
const VendorInfo::Oui &oui = Get<VendorInfo>().GetOui();
|
||||
|
||||
BigEndian::WriteUint24(Get<VendorInfo>().GetOui(), ouiData);
|
||||
SuccessOrExit(error = encoder.AppendEntry(Key::kVendorOui, ouiData));
|
||||
SuccessOrExit(error = encoder.AppendBytesEntry(Key::kVendorOui, oui.GetBytes(), oui.GetSize()));
|
||||
}
|
||||
|
||||
aLength = encoder.GetLength();
|
||||
@@ -248,7 +247,7 @@ void TxtData::PrepareWithVendorData(Heap::Data &aTxtData)
|
||||
|
||||
if (mShouldAddVendorOui)
|
||||
{
|
||||
size += kVendorOuiSize + sizeof(Key::kVendorOui) + sizeof('=');
|
||||
size += VendorInfo::Oui::kMaxSize + sizeof(Key::kVendorOui) + sizeof('=');
|
||||
}
|
||||
|
||||
buffer = reinterpret_cast<uint8_t *>(Heap::CAlloc(size, sizeof(uint8_t)));
|
||||
@@ -509,7 +508,7 @@ void TxtData::Info::ProcessTxtEntry(const Dns::TxtEntry &aEntry)
|
||||
}
|
||||
else if (aEntry.MatchesKey(Key::kVendorOui))
|
||||
{
|
||||
mHasVendorOui = ReadValue(aEntry, mVendorOui);
|
||||
mHasVendorOui = ReadVendorOui(aEntry, AsCoreType(&mVendorOui));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,6 +550,11 @@ exit:
|
||||
return didRead;
|
||||
}
|
||||
|
||||
bool TxtData::Info::ReadVendorOui(const Dns::TxtEntry &aEntry, VendorInfo::Oui &aOui)
|
||||
{
|
||||
return (aOui.SetFrom(aEntry.mValue, aEntry.mValueLength) == kErrorNone);
|
||||
}
|
||||
|
||||
void TxtData::StateBitmap::Parse(uint32_t aBitmap, Info &aInfo)
|
||||
{
|
||||
ClearAllBytes(aInfo);
|
||||
|
||||
@@ -125,6 +125,7 @@ public:
|
||||
static bool ReadValue(const Dns::TxtEntry &aEntry, void *aBuffer, uint16_t aSize);
|
||||
static void ReadStringValue(const Dns::TxtEntry &aEntry, char *aString, uint16_t aStringSize);
|
||||
static bool ReadOmrPrefix(const Dns::TxtEntry &aEntry, Ip6::Prefix &aPrefix);
|
||||
static bool ReadVendorOui(const Dns::TxtEntry &aEntry, VendorInfo::Oui &aOui);
|
||||
|
||||
template <typename ObjectType> bool ReadValue(const Dns::TxtEntry &aEntry, ObjectType &aObject)
|
||||
{
|
||||
@@ -279,7 +280,6 @@ public:
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE
|
||||
|
||||
private:
|
||||
static constexpr uint8_t kVendorOuiSize = OT_BORDER_AGENT_VENDOR_OUI_SIZE;
|
||||
static constexpr uint16_t kMaxSizeNoVendorData = OT_BORDER_AGENT_MESHCOP_SERVICE_TXT_DATA_MAX_LENGTH;
|
||||
|
||||
static const char kRecordVersion[];
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
|
||||
namespace ot {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// VendorInfo
|
||||
|
||||
const char VendorInfo::kName[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME;
|
||||
const char VendorInfo::kModel[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_MODEL;
|
||||
const char VendorInfo::kSwVersion[] = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_SW_VERSION;
|
||||
@@ -49,6 +52,19 @@ static_assert(CheckConstStringPrefix(OPENTHREAD_CONFIG_NET_DIAG_VENDOR_NAME, kNa
|
||||
"VENDOR_NAME MUST start with 'RD:' prefix for a reference device.");
|
||||
#endif
|
||||
|
||||
static constexpr uint64_t kDefaultOuiConfig = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI;
|
||||
|
||||
const otThreadVendorOui VendorInfo::kOui = {
|
||||
OuiParser<kDefaultOuiConfig>::GetBitLength(),
|
||||
{
|
||||
OuiParser<kDefaultOuiConfig>::GetByte0(),
|
||||
OuiParser<kDefaultOuiConfig>::GetByte1(),
|
||||
OuiParser<kDefaultOuiConfig>::GetByte2(),
|
||||
OuiParser<kDefaultOuiConfig>::GetByte3(),
|
||||
OuiParser<kDefaultOuiConfig>::GetByte4(),
|
||||
},
|
||||
};
|
||||
|
||||
VendorInfo::VendorInfo(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
{
|
||||
@@ -57,14 +73,15 @@ VendorInfo::VendorInfo(Instance &aInstance)
|
||||
static_assert(sizeof(kSwVersion) <= sizeof(SwVersionStringType), "VENDOR_SW_VERSION is too long");
|
||||
static_assert(sizeof(kAppUrl) <= sizeof(AppUrlStringType), "VENDOR_APP_URL is too long");
|
||||
|
||||
static_assert((kOui == kUnspecifiedOui) || ((kOui & ~kOuiMask) == 0), "VENDOR_OUI is invalid, MUST be 24-bit");
|
||||
static_assert(OuiParser<OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI>::IsValid(),
|
||||
"VENDOR_OUI format is not valid - see the config documentation");
|
||||
|
||||
#if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
|
||||
memcpy(mName, kName, sizeof(kName));
|
||||
memcpy(mModel, kModel, sizeof(kModel));
|
||||
memcpy(mSwVersion, kSwVersion, sizeof(kSwVersion));
|
||||
memcpy(mAppUrl, kAppUrl, sizeof(kAppUrl));
|
||||
mOui = kOui;
|
||||
mOui = AsCoreType(&kOui);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -113,14 +130,14 @@ Error VendorInfo::SetSwVersion(const char *aSwVersion)
|
||||
|
||||
Error VendorInfo::SetAppUrl(const char *aAppUrl) { return StringCopy(mAppUrl, aAppUrl, kStringCheckUtf8Encoding); }
|
||||
|
||||
Error VendorInfo::SetOui(uint32_t aOui)
|
||||
Error VendorInfo::SetOui(const Oui &aOui)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit((aOui & ~kOuiMask) == 0, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(aOui.IsValid(), error = kErrorInvalidArgs);
|
||||
|
||||
VerifyOrExit(aOui != mOui);
|
||||
mOui = aOui;
|
||||
VerifyOrExit(mOui != aOui);
|
||||
mOui.SetFrom(aOui);
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_MESHCOP_SERVICE_ENABLE
|
||||
Get<MeshCoP::BorderAgent::TxtData>().HandleVendorOuiChange();
|
||||
@@ -132,4 +149,147 @@ exit:
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// VendorInfo::Oui
|
||||
|
||||
const uint8_t VendorInfo::Oui::kValidBitLengths[] = {24, 28, 36};
|
||||
|
||||
bool VendorInfo::Oui::IsValid(void) const { return DoesArrayContain(kValidBitLengths, GetBitLength()); }
|
||||
|
||||
void VendorInfo::Oui::SetFrom(const Oui &aOther)
|
||||
{
|
||||
*this = aOther;
|
||||
Tidy();
|
||||
}
|
||||
|
||||
Error VendorInfo::Oui::SetBitLengthFromSize(uint16_t aSize)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(IsValueInRange<uint16_t>(aSize, kMinSize, kMaxSize), error = kErrorInvalidArgs);
|
||||
|
||||
Clear();
|
||||
mBitLength = kValidBitLengths[aSize - kMinSize];
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error VendorInfo::Oui::SetFrom(const uint8_t *aData, uint16_t aSize)
|
||||
{
|
||||
Error error;
|
||||
|
||||
SuccessOrExit(error = SetBitLengthFromSize(aSize));
|
||||
memcpy(mBytes, aData, aSize);
|
||||
Tidy();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void VendorInfo::Oui::Tidy(void)
|
||||
{
|
||||
uint8_t index;
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
Clear();
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
index = GetBitLength() / kBitsPerByte;
|
||||
|
||||
if (GetBitLength() > index * kBitsPerByte)
|
||||
{
|
||||
mBytes[index] &= kTopNibbleMask;
|
||||
index++;
|
||||
}
|
||||
|
||||
for (; index < kMaxSize; index++)
|
||||
{
|
||||
mBytes[index] = 0;
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t VendorInfo::Oui::GetAsOui24(void) const
|
||||
{
|
||||
uint32_t oui24;
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
oui24 = VendorInfo::Oui::kUnspecified;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
oui24 = BigEndian::ReadUint24(GetBytes());
|
||||
|
||||
exit:
|
||||
return oui24;
|
||||
}
|
||||
|
||||
bool VendorInfo::Oui::operator==(const Oui &aOther) const
|
||||
{
|
||||
bool isEqual = false;
|
||||
Oui tidyOther;
|
||||
|
||||
VerifyOrExit(GetBitLength() == aOther.GetBitLength());
|
||||
|
||||
tidyOther = aOther;
|
||||
tidyOther.Tidy();
|
||||
|
||||
VerifyOrExit(memcmp(GetBytes(), tidyOther.GetBytes(), GetSize()) == 0);
|
||||
isEqual = true;
|
||||
|
||||
exit:
|
||||
return isEqual;
|
||||
}
|
||||
|
||||
VendorInfo::Oui::InfoString VendorInfo::Oui::ToString(void) const
|
||||
{
|
||||
InfoString string;
|
||||
|
||||
ToString(string);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
void VendorInfo::Oui::ToString(char *aBuffer, uint16_t aSize) const
|
||||
{
|
||||
StringWriter writer(aBuffer, aSize);
|
||||
ToString(writer);
|
||||
}
|
||||
|
||||
void VendorInfo::Oui::ToString(StringWriter &aWriter) const
|
||||
{
|
||||
uint8_t index = 0;
|
||||
uint8_t numFullBytes = GetBitLength() / kBitsPerByte;
|
||||
|
||||
if (!IsValid())
|
||||
{
|
||||
aWriter.Append("unspecified");
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
for (index = 0; index < numFullBytes; index++)
|
||||
{
|
||||
if (index != 0)
|
||||
{
|
||||
aWriter.Append("-");
|
||||
}
|
||||
|
||||
aWriter.Append("%02X", mBytes[index]);
|
||||
}
|
||||
|
||||
if (GetBitLength() > numFullBytes * kBitsPerByte)
|
||||
{
|
||||
aWriter.Append("-%1X", ReadBits<uint8_t, kTopNibbleMask>(mBytes[index]));
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
+243
-28
@@ -38,23 +38,165 @@
|
||||
|
||||
#include <openthread/netdiag.h>
|
||||
|
||||
#include "common/as_core_type.hpp"
|
||||
#include "common/bit_utils.hpp"
|
||||
#include "common/clearable.hpp"
|
||||
#include "common/equatable.hpp"
|
||||
#include "common/error.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/non_copyable.hpp"
|
||||
#include "common/string.hpp"
|
||||
#include "thread/net_diag_tlvs.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
class UnitTester;
|
||||
|
||||
/**
|
||||
* Represents the vendor information.
|
||||
*/
|
||||
class VendorInfo : public InstanceLocator, private NonCopyable
|
||||
{
|
||||
friend class UnitTester;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Unspecified Vendor OUI value.
|
||||
* Represents a Thread Vendor OUI (Organizationally Unique Identifier).
|
||||
*/
|
||||
static constexpr uint32_t kUnspecifiedOui = OT_THREAD_UNSPECIFIED_VENDOR_OUI;
|
||||
class Oui : public otThreadVendorOui, public Clearable<Oui>, public Unequatable<Oui>
|
||||
{
|
||||
friend class UnitTester;
|
||||
|
||||
public:
|
||||
/**
|
||||
* The minimum size of the OUI in bytes.
|
||||
*/
|
||||
static constexpr uint8_t kMinSize = 3;
|
||||
|
||||
/**
|
||||
* The maximum size of the OUI in bytes.
|
||||
*/
|
||||
static constexpr uint8_t kMaxSize = OT_THREAD_VENDOR_OUI_MAX_SIZE;
|
||||
|
||||
/**
|
||||
* The unspecified Vendor OUI value.
|
||||
*/
|
||||
static constexpr uint32_t kUnspecified = OT_THREAD_UNSPECIFIED_VENDOR_OUI;
|
||||
|
||||
/**
|
||||
* The size of `InfoString` (used in `ToString()`).
|
||||
*/
|
||||
static constexpr uint16_t kInfoStringSize = OT_THREAD_VENDOR_OUI_STRING_SIZE;
|
||||
|
||||
/**
|
||||
* Defines the fixed-length `String` returned from `ToString()`.
|
||||
*/
|
||||
typedef String<kInfoStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the OUI value is valid.
|
||||
*
|
||||
* @retval TRUE The OUI is valid.
|
||||
* @retval FALSE The OUI is not valid.
|
||||
*/
|
||||
bool IsValid(void) const;
|
||||
|
||||
/**
|
||||
* Returns the OUI prefix length in bits (24, 28, or 36)
|
||||
*
|
||||
* @returns The OUI prefix length in bits.
|
||||
*/
|
||||
uint8_t GetBitLength(void) const { return mBitLength; }
|
||||
|
||||
/**
|
||||
* Returns a pointer to the OUI bytes.
|
||||
*
|
||||
* @returns A pointer to the OUI bytes.
|
||||
*/
|
||||
const uint8_t *GetBytes(void) const { return mBytes; }
|
||||
|
||||
/**
|
||||
* Returns the OUI size in bytes.
|
||||
*
|
||||
* @returns The OUI size in bytes.
|
||||
*/
|
||||
uint8_t GetSize(void) const { return BytesForBitSize(mBitLength); }
|
||||
|
||||
/**
|
||||
* Sets the OUI from another OUI, tidying unused bits.
|
||||
*
|
||||
* @param[in] aOther The other OUI to set from.
|
||||
*/
|
||||
void SetFrom(const Oui &aOther);
|
||||
|
||||
/**
|
||||
* Sets the OUI from a byte buffer.
|
||||
*
|
||||
* @param[in] aData A pointer to the buffer.
|
||||
* @param[in] aSize The size of the buffer in bytes.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the OUI.
|
||||
* @retval kErrorInvalidArgs The @p aSize is not valid and not within valid range [kMinSize, kMaxSize].
|
||||
*/
|
||||
Error SetFrom(const uint8_t *aData, uint16_t aSize);
|
||||
|
||||
/**
|
||||
* Returns the OUI as a 24-bit OUI value.
|
||||
*
|
||||
* @deprecated This method is deprecated.
|
||||
*
|
||||
* If the configured Vendor OUI has a prefix length greater than 24 bits, this method returns the most
|
||||
* significant 24 bits (first 3 bytes) of the OUI.
|
||||
*
|
||||
* @returns The 24-bit OUI value, or `kUnspecified` if it is not valid.
|
||||
*/
|
||||
uint32_t GetAsOui24(void) const;
|
||||
|
||||
/**
|
||||
* Overloads operator== to check for equality with another OUI.
|
||||
*
|
||||
* @param[in] aOther The other OUI to compare with.
|
||||
*
|
||||
* @retval TRUE The OUIs are equal.
|
||||
* @retval FALSE The OUIs are not equal.
|
||||
*/
|
||||
bool operator==(const Oui &aOther) const;
|
||||
|
||||
/**
|
||||
* Converts the OUI to a human-readable string
|
||||
*
|
||||
* The generated string format is hyphen-separated uppercase hexadecimal bytes (e.g., "00-1A-2B" for a 24-bit
|
||||
* OUI). For 28-bit and 36-bit OUIs, the trailing 4-bit nibble is appended as a single hexadecimal digit
|
||||
* (e.g., "00-1A-2B-3" for a 28-bit OUI). If @p aOui is invalid, the string "unspecified" is returned.
|
||||
*
|
||||
* @returns An `InfoString` containing the string representation of the OUI.
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
/**
|
||||
* Converts the OUI to a human-readable string.
|
||||
*
|
||||
* The generated string format is hyphen-separated uppercase hexadecimal bytes (e.g., "00-1A-2B" for a 24-bit
|
||||
* OUI). For 28-bit and 36-bit OUIs, the trailing 4-bit nibble is appended as a single hexadecimal digit
|
||||
* (e.g., "00-1A-2B-3" for a 28-bit OUI). If @p aOui is invalid, the string "unspecified" is returned.
|
||||
*
|
||||
* If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be
|
||||
* truncated but the outputted string is always null-terminated.
|
||||
*
|
||||
* @param[out] aBuffer A pointer to a character buffer to output the string.
|
||||
* @param[in] aSize The size of @p aBuffer in bytes.
|
||||
*/
|
||||
void ToString(char *aBuffer, uint16_t aSize) const;
|
||||
|
||||
private:
|
||||
static constexpr uint8_t kTopNibbleMask = 0xf0;
|
||||
|
||||
static const uint8_t kValidBitLengths[];
|
||||
|
||||
Error SetBitLengthFromSize(uint16_t aSize);
|
||||
void Tidy(void);
|
||||
void ToString(StringWriter &aWriter) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the `VendorInfo`.
|
||||
@@ -138,64 +280,137 @@ public:
|
||||
Error SetAppUrl(const char *aAppUrl);
|
||||
|
||||
/**
|
||||
* Indicates whether the Vendor OUI is specified.
|
||||
* Returns the Vendor OUI.
|
||||
*
|
||||
* @retval TRUE The Vendor OUI is specified.
|
||||
* @retval FALSE The Vendor OUI is not specified.
|
||||
* If the Vendor OUI is not set, the returned `Oui` object's `IsValid()` will return `false`.
|
||||
*
|
||||
* @returns The Vendor OUI.
|
||||
*/
|
||||
bool IsOuiSpecified(void) const { return mOui != kUnspecifiedOui; }
|
||||
const Oui &GetOui(void) const { return mOui; }
|
||||
|
||||
/**
|
||||
* Returns the Vendor OUI-24.
|
||||
* Sets the Vendor OUI.
|
||||
*
|
||||
* @returns The Vendor OUI-24 value. Returns `kUnspecifiedOui` if it is not set.
|
||||
*/
|
||||
uint32_t GetOui(void) const { return mOui; }
|
||||
|
||||
/**
|
||||
* Sets the Vendor OUI-24.
|
||||
*
|
||||
* @param[in] aOui The Vendor OUI-24 value in Hexadecimal representation (e.g., OUI 64-16-66 is represented as
|
||||
* `0x641666`). Must be a 24-bit value.
|
||||
* @param[in] aOui The Vendor OUI.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the Vendor OUI.
|
||||
* @retval kErrorInvalidArgs @p aOui is not a valid 24-bit value.
|
||||
* @retval kErrorInvalidArgs @p aOui is not valid.
|
||||
*/
|
||||
Error SetOui(uint32_t aOui);
|
||||
Error SetOui(const Oui &aOui);
|
||||
|
||||
#else
|
||||
const char *GetName(void) const { return kName; }
|
||||
const char *GetModel(void) const { return kModel; }
|
||||
const char *GetSwVersion(void) const { return kSwVersion; }
|
||||
const char *GetAppUrl(void) const { return kAppUrl; }
|
||||
uint32_t GetOui(void) const { return kOui; }
|
||||
bool IsOuiSpecified(void) const { return kOui != kUnspecifiedOui; }
|
||||
const Oui &GetOui(void) const { return static_cast<const Oui &>(kOui); }
|
||||
#endif // OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kOui = OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI;
|
||||
static constexpr uint32_t kOuiMask = 0xffffff;
|
||||
|
||||
// String buffer types (max size specified by corresponding TLV)
|
||||
typedef NetDiag::VendorNameTlv::StringType NameStringType;
|
||||
typedef NetDiag::VendorModelTlv::StringType ModelStringType;
|
||||
typedef NetDiag::VendorSwVersionTlv::StringType SwVersionStringType;
|
||||
typedef NetDiag::VendorAppUrlTlv::StringType AppUrlStringType;
|
||||
|
||||
static const char kName[];
|
||||
static const char kModel[];
|
||||
static const char kSwVersion[];
|
||||
static const char kAppUrl[];
|
||||
template <uint64_t kOuiConfig> class OuiParser
|
||||
{
|
||||
// Helper template class to parse and validate the compile-time configured OUI.
|
||||
// It supports both the legacy 24-bit OUI (implicit length of 24) and the new 48-bit
|
||||
// format (explicit length in the high byte) to maintain backward compatibility.
|
||||
|
||||
public:
|
||||
static constexpr bool IsSpecified(void) { return (kOuiConfig != VendorInfo::Oui::kUnspecified); }
|
||||
|
||||
static constexpr uint8_t GetBitLength(void)
|
||||
{
|
||||
return !IsSpecified() ? 0 : (IsShort24BitLayout() ? 24 : ReadBits(kLenMask));
|
||||
}
|
||||
|
||||
static constexpr bool IsValid(void)
|
||||
{
|
||||
return !IsSpecified() || IsShort24BitLayout() || Is24Bit() || Is28Bit() || Is36Bit();
|
||||
}
|
||||
|
||||
static constexpr uint8_t GetByte0(void)
|
||||
{
|
||||
return !IsSpecified() ? 0 : IsShort24BitLayout() ? ReadBits(kShortLayoutByte0Mask) : ReadBits(kByte0Mask);
|
||||
}
|
||||
|
||||
static constexpr uint8_t GetByte1(void)
|
||||
{
|
||||
return !IsSpecified() ? 0 : IsShort24BitLayout() ? ReadBits(kShortLayoutByte1Mask) : ReadBits(kByte1Mask);
|
||||
}
|
||||
|
||||
static constexpr uint8_t GetByte2(void)
|
||||
{
|
||||
return !IsSpecified() ? 0 : IsShort24BitLayout() ? ReadBits(kShortLayoutByte2Mask) : ReadBits(kByte2Mask);
|
||||
}
|
||||
|
||||
static constexpr uint8_t GetByte3(void)
|
||||
{
|
||||
return !IsSpecified() ? 0 : IsShort24BitLayout() ? 0 : ReadBits(kByte3Mask);
|
||||
}
|
||||
|
||||
static constexpr uint8_t GetByte4(void)
|
||||
{
|
||||
return !IsSpecified() ? 0 : IsShort24BitLayout() ? 0 : ReadBits(kByte4Mask);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr uint64_t kMaxUint48 = 0xffffffffffffULL; // 6 bytes
|
||||
static constexpr uint64_t kLenMask = 0xff0000000000ULL;
|
||||
static constexpr uint64_t kByte0Mask = 0x00ff00000000ULL;
|
||||
static constexpr uint64_t kByte1Mask = 0x0000ff000000ULL;
|
||||
static constexpr uint64_t kByte2Mask = 0x000000ff0000ULL;
|
||||
static constexpr uint64_t kByte3Mask = 0x00000000ff00ULL;
|
||||
static constexpr uint64_t kByte4Mask = 0x0000000000ffULL;
|
||||
static constexpr uint64_t kMaxUint24 = 0x000000ffffffULL; // 3 bytes
|
||||
static constexpr uint64_t kShortLayoutByte0Mask = 0x000000ff0000ULL;
|
||||
static constexpr uint64_t kShortLayoutByte1Mask = 0x00000000ff00ULL;
|
||||
static constexpr uint64_t kShortLayoutByte2Mask = 0x0000000000ffULL;
|
||||
|
||||
static constexpr bool IsShort24BitLayout(void) { return (kOuiConfig <= kMaxUint24); }
|
||||
static constexpr bool IsConfigValueValid(void) { return (kOuiConfig <= kMaxUint48); }
|
||||
|
||||
static constexpr bool Is24Bit(void)
|
||||
{
|
||||
return IsConfigValueValid() && (GetBitLength() == 24) && (GetByte3() == 0) && (GetByte4() == 0);
|
||||
}
|
||||
|
||||
static constexpr bool Is28Bit(void)
|
||||
{
|
||||
return IsConfigValueValid() && GetBitLength() == 28 && ((GetByte3() & 0x0f) == 0) && (GetByte4() == 0);
|
||||
}
|
||||
|
||||
static constexpr bool Is36Bit(void)
|
||||
{
|
||||
return IsConfigValueValid() && GetBitLength() == 36 && ((GetByte4() & 0x0f) == 0);
|
||||
}
|
||||
|
||||
static constexpr uint8_t ReadBits(uint64_t aMask)
|
||||
{
|
||||
return static_cast<uint8_t>((kOuiConfig & aMask) >> BitOffsetOfMask(aMask));
|
||||
}
|
||||
};
|
||||
|
||||
static const char kName[];
|
||||
static const char kModel[];
|
||||
static const char kSwVersion[];
|
||||
static const char kAppUrl[];
|
||||
static const otThreadVendorOui kOui;
|
||||
|
||||
#if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
|
||||
NameStringType mName;
|
||||
ModelStringType mModel;
|
||||
SwVersionStringType mSwVersion;
|
||||
AppUrlStringType mAppUrl;
|
||||
uint32_t mOui;
|
||||
Oui mOui;
|
||||
#endif
|
||||
};
|
||||
|
||||
DefineCoreType(otThreadVendorOui, VendorInfo::Oui);
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OT_CORE_THREAD_VENDOR_INFO_HPP_
|
||||
|
||||
@@ -1495,12 +1495,11 @@ void ValidateMeshCoPTxtData(TxtData &aTxtData, Node &aNode, bool aExpectVendorIn
|
||||
VerifyOrQuit(info.mHasModelName);
|
||||
VerifyOrQuit(StringMatch(info.mModelName, expectedModelName));
|
||||
|
||||
if (aNode.Get<VendorInfo>().IsOuiSpecified())
|
||||
if (aNode.Get<VendorInfo>().GetOui().IsValid())
|
||||
{
|
||||
uint8_t ouiData[3];
|
||||
const VendorInfo::Oui &oui = aNode.Get<VendorInfo>().GetOui();
|
||||
|
||||
BigEndian::WriteUint24(aNode.Get<VendorInfo>().GetOui(), ouiData);
|
||||
aTxtData.ValidateKey("vo", ouiData);
|
||||
aTxtData.ValidateKey("vo", oui.GetBytes(), oui.GetSize());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -271,6 +271,7 @@ ot_unit_test(tlv)
|
||||
ot_unit_test(toolchain test_toolchain_c.c)
|
||||
ot_unit_test(trickle_timer)
|
||||
ot_unit_test(url)
|
||||
ot_unit_test(vendor_oui)
|
||||
|
||||
ot_unit_ncp_test(cli)
|
||||
ot_unit_ncp_test(dnssd)
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2026, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "test_platform.h"
|
||||
#include "test_util.h"
|
||||
|
||||
#include <openthread/config.h>
|
||||
|
||||
#include "thread/vendor_info.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
class UnitTester
|
||||
{
|
||||
public:
|
||||
template <uint64_t kConfig>
|
||||
static void TestParserCase(bool aIsSpecified, bool aIsValid, uint8_t aBitLength, const uint8_t aExpectedBytes[5])
|
||||
{
|
||||
using Parser = VendorInfo::OuiParser<kConfig>;
|
||||
|
||||
VerifyOrQuit(Parser::IsSpecified() == aIsSpecified, "IsSpecified() failed");
|
||||
VerifyOrQuit(Parser::IsValid() == aIsValid, "IsValid() failed");
|
||||
|
||||
if (aIsValid && aIsSpecified)
|
||||
{
|
||||
VerifyOrQuit(Parser::GetBitLength() == aBitLength, "GetBitLength() failed");
|
||||
|
||||
VerifyOrQuit(Parser::GetByte0() == aExpectedBytes[0]);
|
||||
VerifyOrQuit(Parser::GetByte1() == aExpectedBytes[1]);
|
||||
VerifyOrQuit(Parser::GetByte2() == aExpectedBytes[2]);
|
||||
VerifyOrQuit(Parser::GetByte3() == aExpectedBytes[3]);
|
||||
VerifyOrQuit(Parser::GetByte4() == aExpectedBytes[4]);
|
||||
}
|
||||
}
|
||||
|
||||
static void TestCompileTimeOuiParser(void)
|
||||
{
|
||||
printf("TestCompileTimeOuiParser\n");
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 1. Unspecified cases
|
||||
{
|
||||
uint8_t expected[5] = {0};
|
||||
TestParserCase<0xffffffffULL>(/* aIsSpecified */ false, /* aIsValid */ true, 0, expected);
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 2. Implicit 24-bit (legacy OUI format)
|
||||
{
|
||||
uint8_t expected[5] = {0x64, 0x16, 0x66, 0, 0};
|
||||
TestParserCase<0x641666>(/* aIsSpecified */ true, /* aIsValid */ true, 24, expected);
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t expected[5] = {0x00, 0x00, 0x01, 0, 0};
|
||||
TestParserCase<0x000001>(/* aIsSpecified */ true, /* aIsValid */ true, 24, expected);
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 3. Explicit 24-bit OUI (length in bits 40-47, bytes in bits 0-39)
|
||||
{
|
||||
uint8_t expected[5] = {0x00, 0x1a, 0x2b, 0, 0};
|
||||
TestParserCase<0x18001a2b0000ULL>(/* aIsSpecified */ true, /* aIsValid */ true, 24, expected);
|
||||
}
|
||||
|
||||
// Invalid: non-zero in byte index 3
|
||||
{
|
||||
uint8_t expected[5] = {0};
|
||||
TestParserCase<0x18001a2b0300ULL>(/* aIsSpecified */ true, /* aIsValid */ false, 24, expected);
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 4. Explicit 28-bit OUI
|
||||
{
|
||||
uint8_t expected[5] = {0x00, 0x1a, 0x2b, 0x30, 0};
|
||||
TestParserCase<0x1c001a2b3000ULL>(/* aIsSpecified */ true, /* aIsValid */ true, 28, expected);
|
||||
}
|
||||
|
||||
// Invalid: non-zero in byte index 4
|
||||
{
|
||||
uint8_t expected[5] = {0};
|
||||
TestParserCase<0x1c001a2b3005ULL>(/* aIsSpecified */ true, /* aIsValid */ false, 28, expected);
|
||||
}
|
||||
|
||||
// Invalid: non-zero in lower nibble of byte index 3
|
||||
{
|
||||
uint8_t expected[5] = {0};
|
||||
TestParserCase<0x1c001a2b3500ULL>(/* aIsSpecified */ true, /* aIsValid */ false, 28, expected);
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 5. Explicit 36-bit OUI
|
||||
{
|
||||
uint8_t expected[5] = {0x00, 0x1a, 0x2b, 0x3c, 0x40};
|
||||
TestParserCase<0x24001a2b3c40ULL>(/* aIsSpecified */ true, /* aIsValid */ true, 36, expected);
|
||||
}
|
||||
// Invalid: non-zero in lower nibble of byte index 4
|
||||
{
|
||||
uint8_t expected[5] = {0};
|
||||
TestParserCase<0x24001a2b3c43ULL>(/* aIsSpecified */ true, /* aIsValid */ false, 36, expected);
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 6. Invalid Bit Length (e.g. 32 bits)
|
||||
{
|
||||
uint8_t expected[5] = {0};
|
||||
TestParserCase<0x20001a2b3c40ULL>(/* aIsSpecified */ true, /* aIsValid */ false, 32, expected);
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 7. Value out of valid range (exceeds 6 bytes)
|
||||
{
|
||||
uint8_t expected[5] = {0};
|
||||
TestParserCase<0x1c11001a2b3000ULL>(/* aIsSpecified */ true, /* aIsValid */ false, 28, expected);
|
||||
}
|
||||
}
|
||||
|
||||
static void TestOuiClass(void)
|
||||
{
|
||||
VendorInfo::Oui oui;
|
||||
VendorInfo::Oui oui1;
|
||||
VendorInfo::Oui oui2;
|
||||
VendorInfo::Oui oui3;
|
||||
uint8_t bytes24[] = {0x64, 0x16, 0x66};
|
||||
uint8_t bytes28[] = {0x00, 0x1a, 0x2b, 0x35};
|
||||
uint8_t bytes36[] = {0x00, 0x1a, 0x2b, 0x3c, 0x42};
|
||||
|
||||
printf("TestOuiClass\n");
|
||||
|
||||
// Test ToString() on unspecified OUI
|
||||
oui.Clear();
|
||||
VerifyOrQuit(StringMatch(oui.ToString().AsCString(), "unspecified"));
|
||||
|
||||
// Test `SetFrom()` with bytes (24-bit)
|
||||
SuccessOrQuit(oui.SetFrom(bytes24, sizeof(bytes24)));
|
||||
VerifyOrQuit(oui.IsValid());
|
||||
VerifyOrQuit(oui.GetBitLength() == 24);
|
||||
VerifyOrQuit(oui.GetSize() == 3);
|
||||
VerifyOrQuit(oui.GetAsOui24() == 0x641666);
|
||||
VerifyOrQuit(StringMatch(oui.ToString().AsCString(), "64-16-66"));
|
||||
|
||||
// Test `SetFrom()` with non-tidy 28-bit
|
||||
SuccessOrQuit(oui.SetFrom(bytes28, sizeof(bytes28)));
|
||||
VerifyOrQuit(oui.IsValid());
|
||||
VerifyOrQuit(oui.GetBitLength() == 28);
|
||||
VerifyOrQuit(oui.GetSize() == 4);
|
||||
VerifyOrQuit(oui.GetBytes()[3] == 0x30);
|
||||
VerifyOrQuit(StringMatch(oui.ToString().AsCString(), "00-1A-2B-3"));
|
||||
|
||||
// Test `SetFrom()` with non-tidy 36-bit
|
||||
SuccessOrQuit(oui.SetFrom(bytes36, sizeof(bytes36)));
|
||||
VerifyOrQuit(oui.IsValid());
|
||||
VerifyOrQuit(oui.GetBitLength() == 36);
|
||||
VerifyOrQuit(oui.GetSize() == 5);
|
||||
VerifyOrQuit(oui.GetBytes()[4] == 0x40);
|
||||
VerifyOrQuit(StringMatch(oui.ToString().AsCString(), "00-1A-2B-3C-4"));
|
||||
|
||||
// Test `operator==` (with tidy check on right-hand side)
|
||||
SuccessOrQuit(oui1.SetFrom(bytes28, sizeof(bytes28))); // will be tidied
|
||||
|
||||
oui2.Clear();
|
||||
oui2.mBitLength = 28;
|
||||
memcpy(oui2.mBytes, bytes28, sizeof(bytes28)); // manually write untidied bytes
|
||||
|
||||
VerifyOrQuit(oui1 == oui2);
|
||||
|
||||
// Test `SetFrom(const Oui &)` tidying
|
||||
oui3.SetFrom(oui2);
|
||||
VerifyOrQuit(oui3.GetBytes()[3] == 0x30, "SetFrom(const Oui&) failed to tidy");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::UnitTester::TestCompileTimeOuiParser();
|
||||
ot::UnitTester::TestOuiClass();
|
||||
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user