[joiner] add build config for for experimental Joiner Adv feature (#12276)

This change introduces a new build-time configuration flag,
`OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE`, to control the
inclusion of the experimental Joiner Advertisement feature.

This behavior was first added in PR #5299. It allows optional
inclusion of a newly proposed Joiner Adv TLV in an MLE Discovery Scan
Request message.

This is an experimental feature and is not part of the Thread
specification. OpenThread's implementation is limited and partial: it
only provides the mechanism for a Joiner to include a new Joiner Adv
TLV in its emitted Discovery Scan Request messages, but does not
include the corresponding logic for the receiver of Scan Request to
read or parse this TLV.

The new flag conditionally compiles this behavior. It allows for the
entire feature to be compiled out, reducing code size and memory
usage for devices that do not require this experimental
functionality. Additionally, this change clarifies the experimental
status of the feature in the documentation.

By default, this is now disabled. It is enabled under posix build for
`toranj` tests so that it is covered in GitHub CI.
This commit is contained in:
Abtin Keshavarzian
2026-01-12 12:13:42 -08:00
committed by GitHub
parent 61e2f2877d
commit c9665886fa
9 changed files with 68 additions and 27 deletions
+1 -1
View File
@@ -306,7 +306,7 @@ typedef enum otMeshcopTlvType
OT_MESHCOP_TLV_WAKEUP_CHANNEL = 74, ///< meshcop Wake-up Channel TLV
OT_MESHCOP_TLV_DISCOVERYREQUEST = 128, ///< meshcop Discovery Request TLV
OT_MESHCOP_TLV_DISCOVERYRESPONSE = 129, ///< meshcop Discovery Response TLV
OT_MESHCOP_TLV_JOINERADVERTISEMENT = 241, ///< meshcop Joiner Advertisement TLV
OT_MESHCOP_TLV_JOINERADVERTISEMENT = 241, ///< meshcop Joiner Advertisement TLV (experimental)
} otMeshcopTlvType;
/**
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (569)
#define OPENTHREAD_API_VERSION (570)
/**
* @addtogroup api-instance
+12 -5
View File
@@ -303,17 +303,24 @@ otError otThreadDiscover(otInstance *aInstance,
bool otThreadIsDiscoverInProgress(otInstance *aInstance);
/**
* Sets the Thread Joiner Advertisement when discovering Thread network.
* Sets the Thread Joiner Advertisement used when discovering a Thread network.
*
* Thread Joiner Advertisement is used to allow a Joiner to advertise its own application-specific information
* (such as Vendor ID, Product ID, Discriminator, etc.) via a newly-proposed Joiner Advertisement TLV,
* and to make this information available to Commissioners or Commissioner Candidates without human interaction.
* Requires `OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE`.
*
* @note This is an experimental feature and is not part of the Thread specification. OpenThread's implementation is
* partial: it provides the mechanism for a Joiner to include a new Joiner Adv TLV in its emitted Discovery Scan
* Request messages, but does not include the corresponding logic for the receiver of Scan Request to read or
* parse this TLV.
*
* A Joiner can use this to advertise its own application-specific information (such as Vendor ID, Product ID,
* Discriminator, etc.) using a newly proposed Joiner Advertisement TLV (`OT_MESHCOP_TLV_JOINERADVERTISEMENT`).
* This TLV is appended as a sub-TLV within the MLE Discovery TLV in an MLE Discovery Scan Request message.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aOui The Vendor IEEE OUI value that will be included in the Joiner Advertisement. Only the
* least significant 3 bytes will be used, and the most significant byte will be ignored.
* @param[in] aAdvData A pointer to the AdvData that will be included in the Joiner Advertisement.
* @param[in] aAdvDataLength The length of AdvData in bytes.
* @param[in] aAdvDataLength The length of AdvData in bytes. Must not exceed `OT_JOINER_ADVDATA_MAX_LENGTH`.
*
* @retval OT_ERROR_NONE Successfully set Joiner Advertisement.
* @retval OT_ERROR_INVALID_ARGS Invalid AdvData.
+2
View File
@@ -419,6 +419,7 @@ otError otThreadDiscover(otInstance *aInstance,
/* aFilterIndexes (use hash of factory EUI64) */ nullptr, aCallback, aCallbackContext);
}
#if OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
otError otThreadSetJoinerAdvertisement(otInstance *aInstance,
uint32_t aOui,
const uint8_t *aAdvData,
@@ -426,6 +427,7 @@ otError otThreadSetJoinerAdvertisement(otInstance *aInstance,
{
return AsCoreType(aInstance).Get<Mle::DiscoverScanner>().SetJoinerAdvertisement(aOui, aAdvData, aAdvDataLength);
}
#endif
bool otThreadIsDiscoverInProgress(otInstance *aInstance)
{
+12
View File
@@ -61,6 +61,18 @@
#define OPENTHREAD_CONFIG_JOINER_MAX_CANDIDATES 2
#endif
/**
* @def OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
*
* Define as 1 to enable including Joiner Advertisement TLV during discovery scan by the Joiner.
*
* This is an experimental feature. It is not part of the Thread specification. See `otThreadSetJoinerAdvertisement`
* for more details.
*/
#ifndef OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
#define OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE 0
#endif
/**
* @}
*/
+4
View File
@@ -1120,6 +1120,8 @@ private:
uint8_t mReserved;
} OT_TOOL_PACKED_END;
#if OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
/**
* Implements Joiner Advertisement TLV generation and parsing.
*/
@@ -1193,6 +1195,8 @@ private:
uint8_t mAdvData[kAdvDataMaxLength];
} OT_TOOL_PACKED_END;
#endif // OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
} // namespace MeshCoP
} // namespace ot
+21 -15
View File
@@ -45,9 +45,11 @@ DiscoverScanner::DiscoverScanner(Instance &aInstance)
, mFilterIndexes()
, mState(kStateIdle)
, mScanChannel(0)
, mAdvDataLength(0)
, mEnableFiltering(false)
, mShouldRestorePanId(false)
#if OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
, mAdvDataLength(0)
#endif
{
}
@@ -59,12 +61,11 @@ Error DiscoverScanner::Discover(const Mac::ChannelMask &aScanChannels,
Handler aCallback,
void *aContext)
{
Error error = kErrorNone;
Mle::TxMessage *message = nullptr;
Tlv::Bookmark tlvBookmark;
Ip6::Address destination;
MeshCoP::DiscoveryRequestTlv discoveryRequest;
MeshCoP::JoinerAdvertisementTlv joinerAdvertisement;
Error error = kErrorNone;
Mle::TxMessage *message = nullptr;
Tlv::Bookmark tlvBookmark;
Ip6::Address destination;
MeshCoP::DiscoveryRequestTlv discoveryRequest;
VerifyOrExit(Get<ThreadNetif>().IsUp(), error = kErrorInvalidState);
@@ -109,13 +110,17 @@ Error DiscoverScanner::Discover(const Mac::ChannelMask &aScanChannels,
discoveryRequest.SetJoiner(aJoiner);
SuccessOrExit(error = discoveryRequest.AppendTo(*message));
#if OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
if (mAdvDataLength != 0)
{
joinerAdvertisement.Init();
joinerAdvertisement.SetOui(mOui);
joinerAdvertisement.SetAdvData(mAdvData, mAdvDataLength);
SuccessOrExit(error = joinerAdvertisement.AppendTo(*message));
MeshCoP::JoinerAdvertisementTlv joinerAdvTlv;
joinerAdvTlv.Init();
joinerAdvTlv.SetOui(mOui);
joinerAdvTlv.SetAdvData(mAdvData, mAdvDataLength);
SuccessOrExit(error = joinerAdvTlv.AppendTo(*message));
}
#endif
SuccessOrExit(error = Tlv::EndTlv(*message, tlvBookmark));
@@ -153,22 +158,23 @@ exit:
return error;
}
#if OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
Error DiscoverScanner::SetJoinerAdvertisement(uint32_t aOui, const uint8_t *aAdvData, uint8_t aAdvDataLength)
{
Error error = kErrorNone;
VerifyOrExit((aAdvData != nullptr) && (aAdvDataLength != 0) &&
(aAdvDataLength <= MeshCoP::JoinerAdvertisementTlv::kAdvDataMaxLength) && (aOui <= kMaxOui),
error = kErrorInvalidArgs);
VerifyOrExit(aAdvData != nullptr, error = kErrorInvalidArgs);
VerifyOrExit(IsValueInRange(aAdvDataLength, kMinAdvDataLength, kMaxAdvDataLength), error = kErrorInvalidArgs);
VerifyOrExit(aOui <= kMaxOui, error = kErrorInvalidArgs);
mOui = aOui;
mAdvDataLength = aAdvDataLength;
memcpy(mAdvData, aAdvData, aAdvDataLength);
exit:
return error;
}
#endif
Mac::TxFrame *DiscoverScanner::PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame)
{
+13 -5
View File
@@ -132,6 +132,7 @@ public:
*/
bool IsInProgress(void) const { return (mState != kStateIdle); }
#if OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
/**
* Sets Joiner Advertisement.
*
@@ -143,8 +144,15 @@ public:
* @retval kErrorInvalidArgs Invalid AdvData.
*/
Error SetJoinerAdvertisement(uint32_t aOui, const uint8_t *aAdvData, uint8_t aAdvDataLength);
#endif
private:
#if OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
static constexpr uint32_t kMaxOui = 0xffffff;
static constexpr uint8_t kMinAdvDataLength = 1;
static constexpr uint8_t kMaxAdvDataLength = MeshCoP::JoinerAdvertisementTlv::kAdvDataMaxLength;
#endif
enum State : uint8_t
{
kStateIdle,
@@ -152,8 +160,6 @@ private:
kStateScanDone,
};
static constexpr uint32_t kMaxOui = 0xffffff;
// Methods used by `MeshForwarder`
Mac::TxFrame *PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame);
void Stop(void) { HandleDiscoverComplete(); }
@@ -176,12 +182,14 @@ private:
FilterIndexes mFilterIndexes;
Mac::ChannelMask mScanChannels;
State mState;
uint32_t mOui;
uint8_t mScanChannel;
uint8_t mAdvDataLength;
uint8_t mAdvData[MeshCoP::JoinerAdvertisementTlv::kAdvDataMaxLength];
bool mEnableFiltering : 1;
bool mShouldRestorePanId : 1;
#if OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE
uint8_t mAdvDataLength;
uint8_t mAdvData[kMaxAdvDataLength];
uint32_t mOui;
#endif
};
} // namespace Mle
@@ -60,6 +60,8 @@
#define OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE 1
#define OPENTHREAD_CONFIG_JOINER_ADV_EXPERIMENTAL_ENABLE 1
#define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 1