Skip to content

Commit c34311f

Browse files
authored
[vendor-info] generalize vendor OUI to support variable lengths (openthread#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.
1 parent ac689dd commit c34311f

15 files changed

Lines changed: 828 additions & 83 deletions

include/openthread/border_agent_txt_data.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <openthread/dataset.h>
4343
#include <openthread/error.h>
4444
#include <openthread/ip6.h>
45+
#include <openthread/netdiag.h>
4546
#include <openthread/platform/radio.h>
4647

4748
#ifdef __cplusplus
@@ -61,7 +62,6 @@ extern "C" {
6162
#define OT_BORDER_AGENT_THREAD_VERSION_SIZE (16) ///< Max size of Thread Version string in `otBorderAgentTxtDataInfo`.
6263
#define OT_BORDER_AGENT_VENDOR_NAME_SIZE (32) ///< Max size of Vendor Name string in `otBorderAgentTxtDataInfo`.
6364
#define OT_BORDER_AGENT_MODEL_NAME_SIZE (32) ///< Max size of Model Name string in `otBorderAgentTxtDataInfo`.
64-
#define OT_BORDER_AGENT_VENDOR_OUI_SIZE (3) ///< Size of Vendor OUI (in bytes) in `otBorderAgentTxtDataInfo`.
6565

6666
/**
6767
* Represents the Connection Mode in a Border Agent State Bitmap.
@@ -169,7 +169,7 @@ typedef struct otBorderAgentTxtDataInfo
169169
otExtAddress mExtAddress; ///< Extended Address.
170170
char mVendorName[OT_BORDER_AGENT_VENDOR_NAME_SIZE]; ///< Vendor Name string.
171171
char mModelName[OT_BORDER_AGENT_MODEL_NAME_SIZE]; ///< Model Name string.
172-
uint8_t mVendorOui[OT_BORDER_AGENT_VENDOR_OUI_SIZE]; ///< Vendor OUI (24-bit).
172+
otThreadVendorOui mVendorOui; ///< Vendor OUI.
173173
} otBorderAgentTxtDataInfo;
174174

175175
/**

include/openthread/instance.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extern "C" {
5252
*
5353
* @note This number versions both OpenThread platform and user APIs.
5454
*/
55-
#define OPENTHREAD_API_VERSION (607)
55+
#define OPENTHREAD_API_VERSION (608)
5656

5757
/**
5858
* @addtogroup api-instance

include/openthread/netdiag.h

Lines changed: 107 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,50 @@ typedef struct otNetworkDiagChildTable
273273
*/
274274
typedef otBorderRoutingState otNetworkDiagBrState;
275275

276+
/**
277+
* Specifies the maximum size of a Thread Vendor OUI in bytes.
278+
*/
279+
#define OT_THREAD_VENDOR_OUI_MAX_SIZE 5
280+
281+
/**
282+
* Specifies the bit length of a MAC Address Block Large (MA-L) Vendor OUI.
283+
*/
284+
#define OT_THREAD_VENDOR_OUI_MA_L_BIT_LENGTH 24
285+
286+
/**
287+
* Specifies the bit length of a MAC Address Block Medium (MA-M) Vendor OUI.
288+
*/
289+
#define OT_THREAD_VENDOR_OUI_MA_M_BIT_LENGTH 28
290+
291+
/**
292+
* Specifies the bit length of a MAC Address Block Small (MA-S) Vendor OUI.
293+
*/
294+
#define OT_THREAD_VENDOR_OUI_MA_S_BIT_LENGTH 36
295+
296+
/**
297+
* Represents a Thread Vendor OUI (Organizationally Unique Identifier) which can have different lengths.
298+
*
299+
* A Vendor OUI can be assigned in one of the following formats:
300+
*
301+
* - 24-bit Prefix (MA-L): Exactly 3 bytes (24 bits).
302+
* Example: `00-1A-2B` is represented with `mBitLength = 24` and `mBytes = [0x00, 0x1A, 0x2B, 0x00, 0x00]`.
303+
*
304+
* - 28-bit Prefix (MA-M): Exactly 3.5 bytes (28 bits).
305+
* The half-byte (4 bits) at the end of the prefix occupies the Most Significant Nibble of the 4th byte.
306+
* The Least Significant Nibble of the 4th byte is set to zero.
307+
* Example: `00-1A-2B-3` is represented with `mBitLength = 28` and `mBytes = [0x00, 0x1A, 0x2B, 0x30, 0x00]`.
308+
*
309+
* - 36-bit Prefix (MA-S): Exactly 4.5 bytes (36 bits).
310+
* The half-byte (4 bits) at the end of the prefix occupies the Most Significant Nibble of the 5th byte.
311+
* The Least Significant Nibble of the 5th byte is set to zero.
312+
* Example: `00-1A-2B-3C-4` is represented with `mBitLength = 36` and `mBytes = [0x00, 0x1A, 0x2B, 0x3C, 0x40]`.
313+
*/
314+
typedef struct otThreadVendorOui
315+
{
316+
uint8_t mBitLength; ///< The OUI prefix length in bits (24, 28, or 36).
317+
uint8_t mBytes[OT_THREAD_VENDOR_OUI_MAX_SIZE]; ///< The OUI bytes in big-endian order.
318+
} otThreadVendorOui;
319+
276320
/**
277321
* Represents a Network Diagnostic TLV.
278322
*/
@@ -426,19 +470,78 @@ const char *otThreadGetVendorSwVersion(otInstance *aInstance);
426470
const char *otThreadGetVendorAppUrl(otInstance *aInstance);
427471

428472
/**
429-
* Represents an unspecified Vendor OUI.
473+
* Gets the vendor OUI.
474+
*
475+
* If no vendor OUI is yet set/configured on device, the `mBitLength` in @p aOui will be zero.
476+
*
477+
* @param[in] aInstance A pointer to an OpenThread instance.
478+
* @param[out] aOui A pointer to an `otThreadVendorOui` to return the vendor OUI.
479+
*/
480+
void otThreadGetVendorOuiInfo(otInstance *aInstance, otThreadVendorOui *aOui);
481+
482+
/**
483+
* Sets the vendor OUI.
484+
*
485+
* Requires `OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE`.
486+
*
487+
* @param[in] aInstance A pointer to an OpenThread instance.
488+
* @param[in] aOui A pointer to the `otThreadVendorOui` to set.
489+
*
490+
* @retval OT_ERROR_NONE Successfully set the vendor OUI.
491+
* @retval OT_ERROR_INVALID_ARGS @p aOui has an invalid length.
492+
*/
493+
otError otThreadSetVendorOuiInfo(otInstance *aInstance, const otThreadVendorOui *aOui);
494+
495+
#define OT_THREAD_VENDOR_OUI_STRING_SIZE 16 ///< Recommended size for string representation of a vendor OUI.
496+
497+
/**
498+
* Converts a given vendor OUI to a human-readable string.
499+
*
500+
* The generated string format is hyphen-separated uppercase hexadecimal bytes (e.g., "00-1A-2B" for a 24-bit OUI).
501+
* 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"
502+
* for a 28-bit OUI). If @p aOui is invalid or unspecified, the string "unspecified" is returned.
503+
*
504+
* If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be truncated
505+
* but the outputted string is always null-terminated.
506+
*
507+
* @param[in] aOui The vendor OUI to convert.
508+
* @param[out] aBuffer A pointer to a char array to output the string (MUST NOT be NULL).
509+
* @param[in] aSize The size of @p aBuffer (in bytes). Recommended to use `OT_THREAD_VENDOR_OUI_STRING_SIZE`.
430510
*/
431-
#define OT_THREAD_UNSPECIFIED_VENDOR_OUI (0xffffffff)
511+
void otThreadVendorOuiToString(const otThreadVendorOui *aOui, char *aBuffer, uint16_t aSize);
512+
513+
#define OT_THREAD_UNSPECIFIED_VENDOR_OUI (0xffffffff) ///< Represents an unspecified Vendor OUI.
432514

433515
/**
434-
* Get the vendor OUI-24
516+
* Gets the vendor OUI-24.
517+
*
518+
* @deprecated This function is deprecated. Use `otThreadGetVendorOuiInfo()` instead.
519+
*
520+
* If the configured Vendor OUI has a prefix length greater than 24 bits, this function returns the most significant
521+
* 24 bits (first 3 bytes) of the OUI to maintain backward compatibility.
435522
*
436523
* @param[in] aInstance A pointer to an OpenThread instance.
437524
*
438-
* @returns The vendor OUI-24 value in hex format, or `OT_THREAD_UNSPECIFIED_VENDOR_OUI` is not specified.
525+
* @returns The vendor OUI-24 value, or `OT_THREAD_UNSPECIFIED_VENDOR_OUI` if not specified.
439526
*/
440527
uint32_t otThreadGetVendorOui(otInstance *aInstance);
441528

529+
/**
530+
* Sets the vendor OUI-24.
531+
*
532+
* @deprecated This function is deprecated. Use `otThreadSetVendorOuiInfo()` instead.
533+
*
534+
* Requires `OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE`.
535+
*
536+
* @param[in] aInstance A pointer to an OpenThread instance.
537+
* @param[in] aVendorOui The vendor OUI-24 value in Hexadecimal representation (e.g., OUI 64-16-66 is represented as
538+
* `0x641666`). Must be a 24-bit value.
539+
*
540+
* @retval OT_ERROR_NONE Successfully set the vendor OUI.
541+
* @retval OT_ERROR_INVALID_ARGS @p aVendorOui is not a valid 24-bit value.
542+
*/
543+
otError otThreadSetVendorOui(otInstance *aInstance, uint32_t aVendorOui);
544+
442545
/**
443546
* Set the vendor name string.
444547
*
@@ -508,20 +611,6 @@ otError otThreadSetVendorSwVersion(otInstance *aInstance, const char *aVendorSwV
508611
*/
509612
otError otThreadSetVendorAppUrl(otInstance *aInstance, const char *aVendorAppUrl);
510613

511-
/**
512-
* Set the vendor OUI-24.
513-
*
514-
* Requires `OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE`.
515-
*
516-
* @param[in] aInstance A pointer to an OpenThread instance.
517-
* @param[in] aVendorOui The vendor OUI-24 value in Hexadecimal representation (e.g., OUI 64-16-66 is represented as
518-
* `0x641666`). Must be a 24-bit value.
519-
*
520-
* @retval OT_ERROR_NONE Successfully set the vendor OUI.
521-
* @retval OT_ERROR_INVALID_ARGS @p aVendorOui is not a valid 24-bit value.
522-
*/
523-
otError otThreadSetVendorOui(otInstance *aInstance, uint32_t aVendorOui);
524-
525614
/**
526615
* Callback function pointer to notify when a Network Diagnostic Reset request message is received for the
527616
* `OT_NETWORK_DIAGNOSTIC_TLV_NON_PREFERRED_CHANNELS` TLV.

src/cli/cli.cpp

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -756,8 +756,8 @@ void Interpreter::OutputBorderAgentTxtDataInfo(uint8_t aIndentSize, const otBord
756756

757757
if (aInfo.mHasVendorOui)
758758
{
759-
OutputLine(aIndentSize, "VendorOui: %02X-%02X-%02X", aInfo.mVendorOui[0], aInfo.mVendorOui[1],
760-
aInfo.mVendorOui[2]);
759+
OutputFormat(aIndentSize, "VendorOui: ");
760+
OutputVendorOuiLine(aInfo.mVendorOui);
761761
}
762762

763763
if (aInfo.mHasStateBitmap)
@@ -7600,23 +7600,16 @@ template <> otError Interpreter::Process<Cmd("vendor")>(Arg aArgs[])
76007600
* Done
76017601
* @endcode
76027602
* @par api_copy
7603-
* #otThreadGetVendorOui
7603+
* #otThreadGetVendorOuiInfo
76047604
*/
76057605
else if (aArgs[0] == "oui")
76067606
{
76077607
if (aArgs[1].IsEmpty())
76087608
{
7609-
uint32_t oui = otThreadGetVendorOui(GetInstancePtr());
7609+
otThreadVendorOui oui;
76107610

7611-
if (oui == OT_THREAD_UNSPECIFIED_VENDOR_OUI)
7612-
{
7613-
OutputLine("unspecified");
7614-
}
7615-
else
7616-
{
7617-
OutputLine("%02X-%02X-%02X", static_cast<uint8_t>((oui >> 16) & 0xff),
7618-
static_cast<uint8_t>((oui >> 8) & 0xff), static_cast<uint8_t>(oui & 0xff));
7619-
}
7611+
otThreadGetVendorOuiInfo(GetInstancePtr(), &oui);
7612+
OutputVendorOuiLine(oui);
76207613

76217614
error = OT_ERROR_NONE;
76227615
}

src/cli/cli_utils.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,20 @@ void Utils::OutputSockAddrLine(const otSockAddr &aSockAddr)
231231
OutputNewLine();
232232
}
233233

234+
void Utils::OutputVendorOui(const otThreadVendorOui &aOui)
235+
{
236+
char string[OT_THREAD_VENDOR_OUI_STRING_SIZE];
237+
238+
otThreadVendorOuiToString(&aOui, string, sizeof(string));
239+
OutputFormat("%s", string);
240+
}
241+
242+
void Utils::OutputVendorOuiLine(const otThreadVendorOui &aOui)
243+
{
244+
OutputVendorOui(aOui);
245+
OutputNewLine();
246+
}
247+
234248
void Utils::OutputDnsTxtData(const uint8_t *aTxtData, uint16_t aTxtDataLength)
235249
{
236250
OutputDnsTxtData(/* aKeyValuePerLine */ false, 0, aTxtData, aTxtDataLength);

src/cli/cli_utils.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <openthread/border_routing.h>
4343
#include <openthread/cli.h>
4444
#include <openthread/joiner.h>
45+
#include <openthread/netdiag.h>
4546
#include <openthread/thread.h>
4647

4748
#include "cli_config.h"
@@ -431,6 +432,20 @@ class Utils
431432
*/
432433
void OutputSockAddrLine(const otSockAddr &aSockAddr);
433434

435+
/**
436+
* Outputs the Vendor OUI to the CLI console.
437+
*
438+
* @param[in] aOui A reference to the Vendor OUI.
439+
*/
440+
void OutputVendorOui(const otThreadVendorOui &aOui);
441+
442+
/**
443+
* Outputs the Vendor OUI to the CLI console and appends a newline.
444+
*
445+
* @param[in] aOui A reference to the Vendor OUI.
446+
*/
447+
void OutputVendorOuiLine(const otThreadVendorOui &aOui);
448+
434449
/**
435450
* Outputs DNS TXT data to the CLI console.
436451
*

src/core/api/netdiag_api.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,24 @@ const char *otThreadGetVendorAppUrl(otInstance *aInstance)
8585
return AsCoreType(aInstance).Get<VendorInfo>().GetAppUrl();
8686
}
8787

88-
uint32_t otThreadGetVendorOui(otInstance *aInstance) { return AsCoreType(aInstance).Get<VendorInfo>().GetOui(); }
88+
void otThreadGetVendorOuiInfo(otInstance *aInstance, otThreadVendorOui *aOui)
89+
{
90+
AssertPointerIsNotNull(aOui);
91+
92+
*aOui = AsCoreType(aInstance).Get<VendorInfo>().GetOui();
93+
}
94+
95+
void otThreadVendorOuiToString(const otThreadVendorOui *aOui, char *aBuffer, uint16_t aSize)
96+
{
97+
AsCoreType(aOui).ToString(aBuffer, aSize);
98+
}
99+
100+
uint32_t otThreadGetVendorOui(otInstance *aInstance)
101+
{
102+
// This API is deprecated. Use `otThreadGetVendorOuiInfo()` instead
103+
104+
return AsCoreType(aInstance).Get<VendorInfo>().GetOui().GetAsOui24();
105+
}
89106

90107
#if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
91108

@@ -109,9 +126,28 @@ otError otThreadSetVendorAppUrl(otInstance *aInstance, const char *aVendorAppUrl
109126
return AsCoreType(aInstance).Get<VendorInfo>().SetAppUrl(aVendorAppUrl);
110127
}
111128

129+
otError otThreadSetVendorOuiInfo(otInstance *aInstance, const otThreadVendorOui *aOui)
130+
{
131+
return AsCoreType(aInstance).Get<VendorInfo>().SetOui(AsCoreType(aOui));
132+
}
133+
112134
otError otThreadSetVendorOui(otInstance *aInstance, uint32_t aVendorOui)
113135
{
114-
return AsCoreType(aInstance).Get<VendorInfo>().SetOui(aVendorOui);
136+
// This API is deprecated, use `otThreadSetVendorOuiInfo()` instead
137+
138+
Error error;
139+
VendorInfo::Oui oui;
140+
141+
VerifyOrExit(aVendorOui <= 0xffffff, error = kErrorInvalidArgs);
142+
143+
oui.Clear();
144+
oui.mBitLength = 24;
145+
BigEndian::WriteUint24(aVendorOui, oui.mBytes);
146+
147+
error = AsCoreType(aInstance).Get<VendorInfo>().SetOui(oui);
148+
149+
exit:
150+
return error;
115151
}
116152

117153
#endif // OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE

src/core/config/net_diag.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,22 @@
9191
/**
9292
* @def OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI
9393
*
94-
* Specifies the default Vendor OUI-24 value in Hexadecimal representation (e.g., OUI 64-16-66 is represented as
95-
* `0x641666`).
94+
* Specifies the default Vendor OUI (Organizationally Unique Identifier) value.
9695
*
97-
* The value of `0xffffffff` (UINT32_MAX) is used to indicate OUI is not specified.
96+
* This configuration supports multiple layout formats to maintain backward compatibility:
97+
*
98+
* - 24-bit OUI (MA-L): Hexadecimal representation of a 24-bit value (e.g., OUI 64-16-66 is represented as
99+
* `0x641666`). Values <= `0xffffff` are implicitly treated as a 24-bit OUI.
100+
*
101+
* - Explicit OUI with various lengths (24, 28, or 36 bits): A 48-bit hexadecimal value where the most significant
102+
* byte (bits 40-47) represents the prefix bit-length, and the lower 5 bytes (bits 0-39) represent the OUI bytes
103+
* in big-endian order:
104+
* - 28-bit OUI `00-1A-2B-3` is represented as `0x1c001a2b3000ULL`.
105+
* - 36-bit OUI `00-1A-2B-3C-4` is represented as `0x24001a2b3c40ULL`.
106+
*
107+
* The value of `0xffffffff` (UINT32_MAX) is used to indicate the Vendor OUI is not specified.
108+
*
109+
* The configured value is validated at compile-time to ensure it conforms to one of the supported prefix lengths.
98110
*/
99111
#ifndef OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI
100112
#define OPENTHREAD_CONFIG_NET_DIAG_VENDOR_OUI (0xffffffff)

0 commit comments

Comments
 (0)