[joiner-adv] initial implementation of Joiner Advertisement (#5299)

This commit implements Thread based Joiner Advertisement from Joiner
side, including:

- A new MeshCop TLV: Joiner Advertisement TLV which includes IEEE OUI
  and the Advertisement Data.

- New APIs to set Joiner Advertisement which will be sent along with
  Discovery Request messages.
This commit is contained in:
Yuwen Lan
2020-08-03 08:38:58 -07:00
committed by GitHub
parent b2f7414dac
commit addb1936c3
7 changed files with 192 additions and 7 deletions
+1
View File
@@ -287,6 +287,7 @@ typedef enum otMeshcopTlvType
OT_MESHCOP_TLV_ENERGY_LIST = 57, ///< meshcop Energy List 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
} otMeshcopTlvType;
/**
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (20)
#define OPENTHREAD_API_VERSION (21)
/**
* @addtogroup api-instance
+24
View File
@@ -264,6 +264,30 @@ otError otThreadDiscover(otInstance * aInstance,
*/
bool otThreadIsDiscoverInProgress(otInstance *aInstance);
/**
* This method sets the Thread Joiner Advertisement when discovering 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.
*
* @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.
*
* @retval OT_ERROR_NONE Successfully set Joiner Advertisement.
* @retval OT_ERROR_INVALID_ARGS Invalid AdvData.
*
*/
otError otThreadSetJoinerAdvertisement(otInstance * aInstance,
uint32_t aOui,
const uint8_t *aAdvData,
uint8_t aAdvDataLength);
#define OT_JOINER_ADVDATA_MAX_LENGTH 64 ///< Maximum AdvData Length of Joiner Advertisement
/**
* Get the Thread Child Timeout used when operating in the Child role.
*
+10
View File
@@ -462,6 +462,16 @@ otError otThreadDiscover(otInstance * aInstance,
/* aFilterIndexes (use hash of factory EUI64) */ nullptr, aCallback, aCallbackContext);
}
otError otThreadSetJoinerAdvertisement(otInstance * aInstance,
uint32_t aOui,
const uint8_t *aAdvData,
uint8_t aAdvDataLength)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<Mle::DiscoverScanner>().SetJoinerAdvertisement(aOui, aAdvData, aAdvDataLength);
}
bool otThreadIsDiscoverInProgress(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
+95
View File
@@ -111,6 +111,7 @@ public:
kEnergyList = OT_MESHCOP_TLV_ENERGY_LIST, ///< Energy List TLV
kDiscoveryRequest = OT_MESHCOP_TLV_DISCOVERYREQUEST, ///< Discovery Request TLV
kDiscoveryResponse = OT_MESHCOP_TLV_DISCOVERYRESPONSE, ///< Discovery Response TLV
kJoinerAdvertisement = OT_MESHCOP_TLV_JOINERADVERTISEMENT, ///< Joiner Advertisement TLV
};
/**
@@ -2354,6 +2355,100 @@ private:
uint8_t mReserved;
} OT_TOOL_PACKED_END;
/**
* This class implements Joiner Advertisement TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class JoinerAdvertisementTlv : public Tlv
{
public:
enum
{
kType = kJoinerAdvertisement, ///< The TLV Type.
kAdvDataMaxLength = OT_JOINER_ADVDATA_MAX_LENGTH, ///< The Max Length of AdvData
};
/**
* This method initializes the TLV.
*
*/
void Init(void)
{
SetType(kJoinerAdvertisement);
SetLength(sizeof(*this) - sizeof(Tlv));
}
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() >= sizeof(mOui) && GetLength() <= sizeof(mOui) + sizeof(mAdvData); }
/**
* This method returns the Vendor OUI value.
*
* @returns The Vendor OUI value.
*
*/
uint32_t GetOui(void) const
{
return (static_cast<uint32_t>(mOui[0]) << 16) | (static_cast<uint32_t>(mOui[1]) << 8) |
static_cast<uint32_t>(mOui[2]);
}
/**
* This method sets the Vendor OUI value.
*
* @param[in] aOui The Vendor OUI value.
*
*/
void SetOui(uint32_t aOui)
{
mOui[0] = (aOui >> 16) & 0xff;
mOui[1] = (aOui >> 8) & 0xff;
mOui[2] = aOui & 0xff;
}
/**
* This method returns the Adv Data length.
*
* @returns The AdvData length.
*
*/
uint8_t GetAdvDataLength(void) const { return GetLength() - sizeof(mOui); }
/**
* This method returns the Adv Data value.
*
* @returns A pointer to the Adv Data value.
*
*/
const uint8_t *GetAdvData(void) const { return mAdvData; }
/**
* This method sets the Adv Data value.
*
* @param[in] aAdvData A pointer to the AdvData value.
* @param[in] aAdvDataLength The length of AdvData in bytes.
*
*/
void SetAdvData(const uint8_t *aAdvData, uint8_t aAdvDataLength)
{
OT_ASSERT((aAdvData != nullptr) && (aAdvDataLength > 0) && (aAdvDataLength <= kAdvDataMaxLength));
SetLength(aAdvDataLength + sizeof(mOui));
memcpy(mAdvData, aAdvData, aAdvDataLength);
}
private:
uint8_t mOui[3];
uint8_t mAdvData[kAdvDataMaxLength];
} OT_TOOL_PACKED_END;
} // namespace MeshCoP
} // namespace ot
+45 -6
View File
@@ -53,6 +53,7 @@ DiscoverScanner::DiscoverScanner(Instance &aInstance)
, mScanChannels()
, mState(kStateIdle)
, mScanChannel(0)
, mAdvDataLength(0)
, mEnableFiltering(false)
, mShouldRestorePanId(false)
{
@@ -66,10 +67,12 @@ otError DiscoverScanner::Discover(const Mac::ChannelMask &aScanChannels,
Handler aCallback,
void * aContext)
{
otError error = OT_ERROR_NONE;
Message * message = nullptr;
Ip6::Address destination;
MeshCoP::DiscoveryRequestTlv discoveryRequest;
otError error = OT_ERROR_NONE;
Message * message = nullptr;
Tlv tlv;
Ip6::Address destination;
MeshCoP::DiscoveryRequestTlv discoveryRequest;
MeshCoP::JoinerAdvertisementTlv joinerAdvertisement;
VerifyOrExit(mState == kStateIdle, error = OT_ERROR_BUSY);
@@ -106,12 +109,31 @@ otError DiscoverScanner::Discover(const Mac::ChannelMask &aScanChannels,
message->SetPanId(aPanId);
SuccessOrExit(error = Get<Mle>().AppendHeader(*message, Header::kCommandDiscoveryRequest));
// Append MLE Discovery TLV with a single sub-TLV (MeshCoP Discovery Request).
// Prepare sub-TLV MeshCoP Discovery Request.
discoveryRequest.Init();
discoveryRequest.SetVersion(kThreadVersion);
discoveryRequest.SetJoiner(aJoiner);
SuccessOrExit(error = Tlv::AppendTlv(*message, Tlv::kDiscovery, &discoveryRequest, sizeof(discoveryRequest)));
if (mAdvDataLength != 0)
{
// Prepare sub-TLV MeshCoP Joiner Advertisement.
joinerAdvertisement.Init();
joinerAdvertisement.SetOui(mOui);
joinerAdvertisement.SetAdvData(mAdvData, mAdvDataLength);
}
// Append Discovery TLV with one or two sub-TLVs.
tlv.SetType(Tlv::kDiscovery);
tlv.SetLength(
static_cast<uint8_t>(discoveryRequest.GetSize() + ((mAdvDataLength != 0) ? joinerAdvertisement.GetSize() : 0)));
SuccessOrExit(error = message->Append(&tlv, sizeof(tlv)));
SuccessOrExit(error = discoveryRequest.AppendTo(*message));
if (mAdvDataLength != 0)
{
SuccessOrExit(error = joinerAdvertisement.AppendTo(*message));
}
destination.SetToLinkLocalAllRoutersMulticast();
@@ -144,6 +166,23 @@ exit:
return error;
}
otError DiscoverScanner::SetJoinerAdvertisement(uint32_t aOui, const uint8_t *aAdvData, uint8_t aAdvDataLength)
{
otError error = OT_ERROR_NONE;
VerifyOrExit((aAdvData != nullptr) && (aAdvDataLength != 0) &&
(aAdvDataLength <= MeshCoP::JoinerAdvertisementTlv::kAdvDataMaxLength),
error = OT_ERROR_INVALID_ARGS);
mOui = aOui;
mAdvDataLength = aAdvDataLength;
memcpy(mAdvData, aAdvData, aAdvDataLength);
exit:
return error;
}
otError DiscoverScanner::PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame)
{
otError error = OT_ERROR_NONE;
+16
View File
@@ -134,6 +134,19 @@ public:
*/
bool IsInProgress(void) const { return (mState != kStateIdle); }
/**
* This method sets Joiner Advertisement.
*
* @param[in] aOui The Vendor OUI for Joiner Advertisement.
* @param[in] aAdvData A pointer to AdvData for Joiner Advertisement.
* @param[in] aAdvDataLength The length of AdvData.
*
* @retval OT_ERROR_NONE Successfully set Joiner Advertisement.
* @retval OT_ERROR_INVALID_ARGS Invalid AdvData.
*
*/
otError SetJoinerAdvertisement(uint32_t aOui, const uint8_t *aAdvData, uint8_t aAdvDataLength);
private:
enum State
{
@@ -160,7 +173,10 @@ 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;
};