mirror of
https://github.com/espressif/openthread.git
synced 2026-08-02 00:57:47 +00:00
[meshcop] adding otJoinerDiscerner (#5137)
The `otJoinerDiscerner` enables new a mechanism for Thread commissioning. The traditional Thread commissioning process uses factory assigned EUI-64 of the device to derive the Joiner ID and identify/filter a joiner (through steering data bloom filter). The Joiner Discerner (which is an unsigned value along with a user-specified bit length up to 64 bits) allows users to have more control and do not rely on factory-assigned EUI-64. On joiner side, when a a Joiner Discerner value is provided, the Joiner code uses the discerner value to derive Joiner ID (appending a random prefix to extend the value to 64 bits) and bloom filter. On commissioner side, users can add different joiners providing either an EUI-64 or an associated Joiner Discerner and the code accordingly match the Joiner IDs and compute steering data bloom filter.
This commit is contained in:
committed by
Jonathan Hui
parent
2ebdf874eb
commit
5210ca3eee
@@ -37,6 +37,7 @@
|
||||
|
||||
#include <openthread/dataset.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/joiner.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/platform/toolchain.h>
|
||||
|
||||
@@ -114,17 +115,31 @@ typedef struct otCommissioningDataset
|
||||
|
||||
#define OT_PSKD_MAX_SIZE 32 ///< Size of a Joiner PSKd (bytes)
|
||||
|
||||
/**
|
||||
* This enumeration defines a Joiner Info Typer.
|
||||
*
|
||||
*/
|
||||
typedef enum otJoinerInfoType
|
||||
{
|
||||
OT_JOINER_INFO_TYPE_ANY = 0, ///< Accept any Joiner (no EUI64 or Discerner is specified).
|
||||
OT_JOINER_INFO_TYPE_EUI64 = 1, ///< Joiner EUI-64 is specified (`mSharedId.mEui64` in `otJoinerInfo`).
|
||||
OT_JOINER_INFO_TYPE_DISCERNER = 2, ///< Joiner Discerner is specified (`mSharedId.mDiscerner` in `otJoinerInfo`).
|
||||
} otJoinerInfoType;
|
||||
|
||||
/**
|
||||
* This structure represents a Joiner Info.
|
||||
*
|
||||
*/
|
||||
typedef struct otJoinerInfo
|
||||
{
|
||||
otExtAddress mEui64; ///< Joiner eui64
|
||||
char mPsk[OT_PSKD_MAX_SIZE + 1]; ///< Joiner pskd
|
||||
uint32_t mExpirationTime; ///< Joiner expiration time in msec
|
||||
|
||||
bool mAny : 1; /// TRUE if eui64 isn't set, FALSE otherwise.
|
||||
otJoinerInfoType mType; ///< Joiner type.
|
||||
union
|
||||
{
|
||||
otExtAddress mEui64; ///< Joiner EUI64 (when `mType` is `OT_JOINER_INFO_TYPE_EUI64`)
|
||||
otJoinerDiscerner mDiscerner; ///< Joiner Discerner (when `mType` is `OT_JOINER_INFO_TYPE_DISCERNER`)
|
||||
} mSharedId; ///< Shared fields
|
||||
char mPsk[OT_PSKD_MAX_SIZE + 1]; ///< Joiner PSKd
|
||||
uint32_t mExpirationTime; ///< Joiner expiration time in msec
|
||||
} otJoinerInfo;
|
||||
|
||||
/**
|
||||
@@ -141,12 +156,14 @@ typedef void (*otCommissionerStateCallback)(otCommissionerState aState, void *aC
|
||||
/**
|
||||
* This function pointer is called whenever the joiner state changes.
|
||||
*
|
||||
* @param[in] aEvent The joiner event type.
|
||||
* @param[in] aJoinerId A pointer to the Joiner ID.
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
* @param[in] aEvent The joiner event type.
|
||||
* @param[in] aJoinerInfo A pointer to the Joiner Info.
|
||||
* @param[in] aJoinerId A pointer to the Joiner ID (if not known, it will be NULL).
|
||||
* @param[in] aContext A pointer to application-specific context.
|
||||
*
|
||||
*/
|
||||
typedef void (*otCommissionerJoinerCallback)(otCommissionerJoinerEvent aEvent,
|
||||
const otJoinerInfo * aJoinerInfo,
|
||||
const otExtAddress * aJoinerId,
|
||||
void * aContext);
|
||||
|
||||
@@ -200,6 +217,27 @@ otError otCommissionerAddJoiner(otInstance * aInstance,
|
||||
const char * aPskd,
|
||||
uint32_t aTimeout);
|
||||
|
||||
/**
|
||||
* This function adds a Joiner entry with a given Joiner Discerner value.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aDiscerner A pointer to the Joiner Discerner.
|
||||
* @param[in] aPskd A pointer to the PSKd.
|
||||
* @param[in] aTimeout A time after which a Joiner is automatically removed, in seconds.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully added the Joiner.
|
||||
* @retval OT_ERROR_NO_BUFS No buffers available to add the Joiner.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aDiscerner or @p aPskd is invalid.
|
||||
* @retval OT_ERROR_INVALID_STATE The commissioner is not active.
|
||||
*
|
||||
* @note Only use this after successfully starting the Commissioner role with otCommissionerStart().
|
||||
*
|
||||
*/
|
||||
otError otCommissionerAddJoinerWithDiscerner(otInstance * aInstance,
|
||||
const otJoinerDiscerner *aDiscerner,
|
||||
const char * aPskd,
|
||||
uint32_t aTimeout);
|
||||
|
||||
/**
|
||||
* This method get joiner info at aIterator position.
|
||||
*
|
||||
@@ -229,6 +267,22 @@ otError otCommissionerGetNextJoinerInfo(otInstance *aInstance, uint16_t *aIterat
|
||||
*/
|
||||
otError otCommissionerRemoveJoiner(otInstance *aInstance, const otExtAddress *aEui64);
|
||||
|
||||
/**
|
||||
* This function removes a Joiner entry.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aEui64 A pointer to the Joiner Discerner.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully removed the Joiner.
|
||||
* @retval OT_ERROR_NOT_FOUND The Joiner specified by @p aEui64 was not found.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aDiscerner is invalid.
|
||||
* @retval OT_ERROR_INVALID_STATE The commissioner is not active.
|
||||
*
|
||||
* @note Only use this after successfully starting the Commissioner role with otCommissionerStart().
|
||||
*
|
||||
*/
|
||||
otError otCommissionerRemoveJoinerWithDiscerner(otInstance *aInstance, const otJoinerDiscerner *aDiscerner);
|
||||
|
||||
/**
|
||||
* This function gets the Provisioning URL.
|
||||
*
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (7)
|
||||
#define OPENTHREAD_API_VERSION (8)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -69,6 +69,18 @@ typedef enum otJoinerState
|
||||
OT_JOINER_STATE_JOINED = 5,
|
||||
} otJoinerState;
|
||||
|
||||
#define OT_JOINER_MAX_DISCERNER_LENGTH 64 ///< Maximum length of a Joiner Discerner in bits.
|
||||
|
||||
/**
|
||||
* This structure represents a Joiner Discerner.
|
||||
*
|
||||
*/
|
||||
typedef struct otJoinerDiscerner
|
||||
{
|
||||
uint64_t mValue; ///< Discerner value (the lowest `mLength` bits specify the discerner).
|
||||
uint8_t mLength; ///< Length (number of bits) - must be non-zero and at most `OT_JOINER_MAX_DISCERNER_LENGTH`.
|
||||
} otJoinerDiscerner;
|
||||
|
||||
/**
|
||||
* This function pointer is called to notify the completion of a join operation.
|
||||
*
|
||||
@@ -132,16 +144,48 @@ void otJoinerStop(otInstance *aInstance);
|
||||
otJoinerState otJoinerGetState(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Get the Joiner ID.
|
||||
* This method gets the Joiner ID.
|
||||
*
|
||||
* Joiner ID is the first 64 bits of the result of computing SHA-256 over factory-assigned
|
||||
* IEEE EUI-64, which is used as IEEE 802.15.4 Extended Address during commissioning process.
|
||||
* If a Joiner Discerner is not set, Joiner ID is the first 64 bits of the result of computing SHA-256 over
|
||||
* factory-assigned IEEE EUI-64. Otherwise the Joiner ID is calculated from the Joiner Discerner value.
|
||||
*
|
||||
* The Joiner ID is also used as the device's IEEE 802.15.4 Extended Address during commissioning process.
|
||||
*
|
||||
* @param[in] aInstance A pointer to the OpenThread instance.
|
||||
* @param[out] aJoinerId A pointer to where the Joiner ID is placed.
|
||||
*
|
||||
* @returns A pointer to the Joiner ID.
|
||||
*
|
||||
*/
|
||||
void otJoinerGetId(otInstance *aInstance, otExtAddress *aJoinerId);
|
||||
const otExtAddress *otJoinerGetId(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* This method sets the Joiner Discerner.
|
||||
*
|
||||
* The Joiner Discerner is used to calculate the Joiner ID used during commissioning/joining process.
|
||||
*
|
||||
* By default (when a discerner is not provided or set to NULL), Joiner ID is derived as first 64 bits of the result
|
||||
* of computing SHA-256 over factory-assigned IEEE EUI-64. Note that this is the main behavior expected by Thread
|
||||
* specification.
|
||||
*
|
||||
* @param[in] aInstance A pointer to the OpenThread instance.
|
||||
* @param[in] aDiscerner A pointer to a Joiner Discerner. If NULL clears any previously set discerner.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The Joiner Discerner updated successfully.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aDisciminrator is not valid (specified length is not within valid range).
|
||||
* @retval OT_ERROR_INVALID_STATE There is an ongoing Joining process so Joiner Discerner could not be changed.
|
||||
*
|
||||
*/
|
||||
otError otJoinerSetDiscerner(otInstance *aInstance, otJoinerDiscerner *aDiscerner);
|
||||
|
||||
/**
|
||||
* This method gets the Joiner Discerner.
|
||||
*
|
||||
* @param[in] aInstance A pointer to the OpenThread instance.
|
||||
*
|
||||
* @returns A pointer to Joiner Discerner or NULL if none is set.
|
||||
*
|
||||
*/
|
||||
const otJoinerDiscerner *otJoinerGetDiscerner(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -345,13 +345,20 @@ void Commissioner::HandleStateChanged(otCommissionerState aState)
|
||||
}
|
||||
}
|
||||
|
||||
void Commissioner::HandleJoinerEvent(otCommissionerJoinerEvent aEvent, const otExtAddress *aJoinerId, void *aContext)
|
||||
void Commissioner::HandleJoinerEvent(otCommissionerJoinerEvent aEvent,
|
||||
const otJoinerInfo * aJoinerInfo,
|
||||
const otExtAddress * aJoinerId,
|
||||
void * aContext)
|
||||
{
|
||||
static_cast<Commissioner *>(aContext)->HandleJoinerEvent(aEvent, aJoinerId);
|
||||
static_cast<Commissioner *>(aContext)->HandleJoinerEvent(aEvent, aJoinerInfo, aJoinerId);
|
||||
}
|
||||
|
||||
void Commissioner::HandleJoinerEvent(otCommissionerJoinerEvent aEvent, const otExtAddress *aJoinerId)
|
||||
void Commissioner::HandleJoinerEvent(otCommissionerJoinerEvent aEvent,
|
||||
const otJoinerInfo * aJoinerInfo,
|
||||
const otExtAddress * aJoinerId)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aJoinerInfo);
|
||||
|
||||
mInterpreter.mServer->OutputFormat("Commissioner: Joiner ");
|
||||
|
||||
switch (aEvent)
|
||||
@@ -373,7 +380,10 @@ void Commissioner::HandleJoinerEvent(otCommissionerJoinerEvent aEvent, const otE
|
||||
break;
|
||||
}
|
||||
|
||||
mInterpreter.OutputBytes(aJoinerId->m8, sizeof(*aJoinerId));
|
||||
if (aJoinerId != nullptr)
|
||||
{
|
||||
mInterpreter.OutputBytes(aJoinerId->m8, sizeof(*aJoinerId));
|
||||
}
|
||||
|
||||
mInterpreter.mServer->OutputFormat("\r\n");
|
||||
}
|
||||
|
||||
@@ -100,9 +100,12 @@ private:
|
||||
void HandleStateChanged(otCommissionerState aState);
|
||||
|
||||
static void HandleJoinerEvent(otCommissionerJoinerEvent aJoinerEvent,
|
||||
const otJoinerInfo * aJoinerInfo,
|
||||
const otExtAddress * aJoinerId,
|
||||
void * aContext);
|
||||
void HandleJoinerEvent(otCommissionerJoinerEvent aJoinerEvent, const otExtAddress *aJoinerId);
|
||||
void HandleJoinerEvent(otCommissionerJoinerEvent aJoinerEvent,
|
||||
const otJoinerInfo * aJoinerInfo,
|
||||
const otExtAddress * aJoinerId);
|
||||
|
||||
static void HandleEnergyReport(uint32_t aChannelMask,
|
||||
const uint8_t *aEnergyList,
|
||||
|
||||
@@ -66,11 +66,11 @@ otError Joiner::ProcessId(uint8_t aArgsLength, char *aArgs[])
|
||||
OT_UNUSED_VARIABLE(aArgsLength);
|
||||
OT_UNUSED_VARIABLE(aArgs);
|
||||
|
||||
otExtAddress joinerId;
|
||||
const otExtAddress *joinerId;
|
||||
|
||||
otJoinerGetId(mInterpreter.mInstance, &joinerId);
|
||||
joinerId = otJoinerGetId(mInterpreter.mInstance);
|
||||
|
||||
mInterpreter.OutputBytes(joinerId.m8, sizeof(joinerId));
|
||||
mInterpreter.OutputBytes(joinerId->m8, sizeof(otExtAddress));
|
||||
mInterpreter.mServer->OutputFormat("\r\n");
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
|
||||
@@ -46,33 +46,44 @@ otError otCommissionerStart(otInstance * aInstance,
|
||||
otCommissionerJoinerCallback aJoinerCallback,
|
||||
void * aCallbackContext)
|
||||
{
|
||||
otError error;
|
||||
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
SuccessOrExit(error =
|
||||
instance.Get<MeshCoP::Commissioner>().Start(aStateCallback, aJoinerCallback, aCallbackContext));
|
||||
exit:
|
||||
return error;
|
||||
return instance.Get<MeshCoP::Commissioner>().Start(aStateCallback, aJoinerCallback, aCallbackContext);
|
||||
}
|
||||
|
||||
otError otCommissionerStop(otInstance *aInstance)
|
||||
{
|
||||
otError error;
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
SuccessOrExit(error = instance.Get<MeshCoP::Commissioner>().Stop(/* aResign */ true));
|
||||
return instance.Get<MeshCoP::Commissioner>().Stop(/* aResign */ true);
|
||||
}
|
||||
|
||||
otError otCommissionerAddJoiner(otInstance *aInstance, const otExtAddress *aEui64, const char *aPskd, uint32_t aTimeout)
|
||||
{
|
||||
otError error;
|
||||
MeshCoP::Commissioner &commissioner = static_cast<Instance *>(aInstance)->Get<MeshCoP::Commissioner>();
|
||||
|
||||
if (aEui64 == nullptr)
|
||||
{
|
||||
error = commissioner.AddJoinerAny(aPskd, aTimeout);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
error = commissioner.AddJoiner(*static_cast<const Mac::ExtAddress *>(aEui64), aPskd, aTimeout);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otCommissionerAddJoiner(otInstance *aInstance, const otExtAddress *aEui64, const char *aPskd, uint32_t aTimeout)
|
||||
otError otCommissionerAddJoinerWithDiscerner(otInstance * aInstance,
|
||||
const otJoinerDiscerner *aDiscerner,
|
||||
const char * aPskd,
|
||||
uint32_t aTimeout)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.Get<MeshCoP::Commissioner>().AddJoiner(static_cast<const Mac::ExtAddress *>(aEui64), aPskd,
|
||||
aTimeout);
|
||||
return instance.Get<MeshCoP::Commissioner>().AddJoiner(*static_cast<const MeshCoP::JoinerDiscerner *>(aDiscerner),
|
||||
aPskd, aTimeout);
|
||||
}
|
||||
|
||||
otError otCommissionerGetNextJoinerInfo(otInstance *aInstance, uint16_t *aIterator, otJoinerInfo *aJoiner)
|
||||
@@ -83,10 +94,28 @@ otError otCommissionerGetNextJoinerInfo(otInstance *aInstance, uint16_t *aIterat
|
||||
}
|
||||
|
||||
otError otCommissionerRemoveJoiner(otInstance *aInstance, const otExtAddress *aEui64)
|
||||
{
|
||||
otError error;
|
||||
MeshCoP::Commissioner &commissioner = static_cast<Instance *>(aInstance)->Get<MeshCoP::Commissioner>();
|
||||
|
||||
if (aEui64 == nullptr)
|
||||
{
|
||||
error = commissioner.RemoveJoinerAny(/* aTimeout */ 0);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
error = commissioner.RemoveJoiner(*static_cast<const Mac::ExtAddress *>(aEui64), /* aTimeout */ 0);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otCommissionerRemoveJoinerWithDiscerner(otInstance *aInstance, const otJoinerDiscerner *aDiscerner)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.Get<MeshCoP::Commissioner>().RemoveJoiner(static_cast<const Mac::ExtAddress *>(aEui64), 0);
|
||||
return instance.Get<MeshCoP::Commissioner>().RemoveJoiner(
|
||||
*static_cast<const MeshCoP::JoinerDiscerner *>(aDiscerner), 0);
|
||||
}
|
||||
|
||||
otError otCommissionerSetProvisioningUrl(otInstance *aInstance, const char *aProvisioningUrl)
|
||||
|
||||
@@ -71,10 +71,35 @@ otJoinerState otJoinerGetState(otInstance *aInstance)
|
||||
return instance.Get<MeshCoP::Joiner>().GetState();
|
||||
}
|
||||
|
||||
void otJoinerGetId(otInstance *aInstance, otExtAddress *aJoinerId)
|
||||
const otExtAddress *otJoinerGetId(otInstance *aInstance)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
instance.Get<MeshCoP::Joiner>().GetJoinerId(*static_cast<Mac::ExtAddress *>(aJoinerId));
|
||||
return &instance.Get<MeshCoP::Joiner>().GetId();
|
||||
}
|
||||
|
||||
otError otJoinerSetDiscerner(otInstance *aInstance, otJoinerDiscerner *aDiscerner)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
MeshCoP::Joiner &joiner = static_cast<Instance *>(aInstance)->Get<MeshCoP::Joiner>();
|
||||
|
||||
if (aDiscerner != NULL)
|
||||
{
|
||||
error = joiner.SetDiscerner(*static_cast<const MeshCoP::JoinerDiscerner *>(aDiscerner));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = joiner.ClearDiscerner();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
const otJoinerDiscerner *otJoinerGetDiscerner(otInstance *aInstance)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.Get<MeshCoP::Joiner>().GetDiscerner();
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_JOINER_ENABLE
|
||||
|
||||
+249
-109
@@ -57,10 +57,10 @@ namespace MeshCoP {
|
||||
|
||||
Commissioner::Commissioner(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mActiveJoiner(nullptr)
|
||||
, mJoinerPort(0)
|
||||
, mJoinerRloc(0)
|
||||
, mSessionId(0)
|
||||
, mJoinerIndex(0)
|
||||
, mTransmitAttempts(0)
|
||||
, mJoinerExpirationTimer(aInstance, HandleJoinerExpirationTimer, this)
|
||||
, mTimer(aInstance, HandleTimer, this)
|
||||
@@ -70,10 +70,10 @@ Commissioner::Commissioner(Instance &aInstance)
|
||||
, mAnnounceBegin(aInstance)
|
||||
, mEnergyScan(aInstance)
|
||||
, mPanIdQuery(aInstance)
|
||||
, mState(OT_COMMISSIONER_STATE_DISABLED)
|
||||
, mStateCallback(nullptr)
|
||||
, mJoinerCallback(nullptr)
|
||||
, mCallbackContext(nullptr)
|
||||
, mState(OT_COMMISSIONER_STATE_DISABLED)
|
||||
{
|
||||
memset(mJoiners, 0, sizeof(mJoiners));
|
||||
|
||||
@@ -105,12 +105,34 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Commissioner::SignalJoinerEvent(otCommissionerJoinerEvent aEvent, const Mac::ExtAddress &aJoinerId)
|
||||
void Commissioner::SignalJoinerEvent(otCommissionerJoinerEvent aEvent, const Joiner *aJoiner) const
|
||||
{
|
||||
if (mJoinerCallback)
|
||||
otJoinerInfo joinerInfo;
|
||||
Mac::ExtAddress joinerId;
|
||||
bool noJoinerId = false;
|
||||
|
||||
VerifyOrExit((mJoinerCallback != nullptr) && (aJoiner != nullptr), OT_NOOP);
|
||||
|
||||
aJoiner->CopyToJoinerInfo(joinerInfo);
|
||||
|
||||
if (aJoiner->mType == Joiner::kTypeEui64)
|
||||
{
|
||||
mJoinerCallback(aEvent, &aJoinerId, mCallbackContext);
|
||||
ComputeJoinerId(aJoiner->mSharedId.mEui64, joinerId);
|
||||
}
|
||||
else if (aJoiner == mActiveJoiner)
|
||||
{
|
||||
joinerId.Set(mJoinerIid.m8);
|
||||
joinerId.ToggleLocal();
|
||||
}
|
||||
else
|
||||
{
|
||||
noJoinerId = true;
|
||||
}
|
||||
|
||||
mJoinerCallback(aEvent, &joinerInfo, noJoinerId ? nullptr : &joinerId, mCallbackContext);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Commissioner::AddCoapResources(void)
|
||||
@@ -134,15 +156,7 @@ void Commissioner::HandleCoapsConnected(bool aConnected, void *aContext)
|
||||
|
||||
void Commissioner::HandleCoapsConnected(bool aConnected)
|
||||
{
|
||||
otCommissionerJoinerEvent event;
|
||||
Mac::ExtAddress joinerId;
|
||||
|
||||
event = aConnected ? OT_COMMISSIONER_JOINER_CONNECTED : OT_COMMISSIONER_JOINER_END;
|
||||
|
||||
joinerId.Set(mJoinerIid.m8);
|
||||
joinerId.ToggleLocal();
|
||||
|
||||
SignalJoinerEvent(event, joinerId);
|
||||
SignalJoinerEvent(aConnected ? OT_COMMISSIONER_JOINER_CONNECTED : OT_COMMISSIONER_JOINER_END, mActiveJoiner);
|
||||
}
|
||||
|
||||
Commissioner::Joiner *Commissioner::GetUnusedJoinerEntry(void)
|
||||
@@ -151,7 +165,7 @@ Commissioner::Joiner *Commissioner::GetUnusedJoinerEntry(void)
|
||||
|
||||
for (joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++)
|
||||
{
|
||||
if (!joiner->mValid)
|
||||
if (joiner->mType == Joiner::kTypeUnused)
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
@@ -169,24 +183,43 @@ Commissioner::Joiner *Commissioner::FindJoinerEntry(const Mac::ExtAddress *aEui6
|
||||
|
||||
for (joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++)
|
||||
{
|
||||
if (!joiner->mValid)
|
||||
switch (joiner->mType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
case Joiner::kTypeUnused:
|
||||
case Joiner::kTypeDiscerner:
|
||||
break;
|
||||
|
||||
if (aEui64 == nullptr)
|
||||
{
|
||||
if (joiner->mAny)
|
||||
case Joiner::kTypeAny:
|
||||
if (aEui64 == nullptr)
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
break;
|
||||
|
||||
case Joiner::kTypeEui64:
|
||||
if ((aEui64 != nullptr) && (joiner->mSharedId.mEui64 == *aEui64))
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
joiner = nullptr;
|
||||
|
||||
exit:
|
||||
return joiner;
|
||||
}
|
||||
|
||||
Commissioner::Joiner *Commissioner::FindJoinerEntry(const JoinerDiscerner &aDiscerner)
|
||||
{
|
||||
Joiner *joiner;
|
||||
|
||||
for (joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++)
|
||||
{
|
||||
if ((joiner->mType == Joiner::kTypeDiscerner) && (aDiscerner == joiner->mSharedId.mDiscerner))
|
||||
{
|
||||
if (!joiner->mAny && (joiner->mEui64 == *aEui64))
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,32 +231,45 @@ exit:
|
||||
|
||||
Commissioner::Joiner *Commissioner::FindBestMatchingJoinerEntry(const Mac::ExtAddress &aReceivedJoinerId)
|
||||
{
|
||||
Joiner *best = nullptr;
|
||||
Joiner * best = nullptr;
|
||||
Mac::ExtAddress joinerId;
|
||||
|
||||
// Prefer a full Joiner ID match, if not found use the entry
|
||||
// accepting any joiner.
|
||||
|
||||
for (Joiner *joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++)
|
||||
{
|
||||
if (!joiner->mValid)
|
||||
switch (joiner->mType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
case Joiner::kTypeUnused:
|
||||
break;
|
||||
|
||||
if (!joiner->mAny)
|
||||
{
|
||||
Mac::ExtAddress joinerId;
|
||||
|
||||
ComputeJoinerId(joiner->mEui64, joinerId);
|
||||
case Joiner::kTypeAny:
|
||||
if (best == nullptr)
|
||||
{
|
||||
best = joiner;
|
||||
}
|
||||
break;
|
||||
|
||||
case Joiner::kTypeEui64:
|
||||
ComputeJoinerId(joiner->mSharedId.mEui64, joinerId);
|
||||
if (joinerId == aReceivedJoinerId)
|
||||
{
|
||||
ExitNow(best = joiner);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
best = joiner;
|
||||
break;
|
||||
|
||||
case Joiner::kTypeDiscerner:
|
||||
if (joiner->mSharedId.mDiscerner.Matches(aReceivedJoinerId))
|
||||
{
|
||||
if ((best == nullptr) ||
|
||||
((best->mType == Joiner::kTypeDiscerner) &&
|
||||
(best->mSharedId.mDiscerner.GetLength() < joiner->mSharedId.mDiscerner.GetLength())))
|
||||
{
|
||||
best = joiner;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,16 +279,25 @@ exit:
|
||||
|
||||
void Commissioner::RemoveJoinerEntry(Commissioner::Joiner &aJoiner)
|
||||
{
|
||||
Mac::ExtAddress joinerId;
|
||||
// Create a copy of `aJoiner` to use for signaling joiner event
|
||||
// and logging after the entry is removed. This ensures the joiner
|
||||
// event callback is invoked after all states are cleared.
|
||||
|
||||
Joiner joinerCopy = aJoiner;
|
||||
|
||||
aJoiner.mType = Joiner::kTypeUnused;
|
||||
|
||||
if (&aJoiner == mActiveJoiner)
|
||||
{
|
||||
mActiveJoiner = nullptr;
|
||||
}
|
||||
|
||||
aJoiner.mValid = false;
|
||||
UpdateJoinerExpirationTimer();
|
||||
|
||||
SendCommissionerSet();
|
||||
LogJoinerEntry("Removed", aJoiner);
|
||||
|
||||
ComputeJoinerId(aJoiner.mEui64, joinerId);
|
||||
SignalJoinerEvent(OT_COMMISSIONER_JOINER_REMOVED, joinerId);
|
||||
LogJoinerEntry("Removed", joinerCopy);
|
||||
SignalJoinerEvent(OT_COMMISSIONER_JOINER_REMOVED, &joinerCopy);
|
||||
}
|
||||
|
||||
otError Commissioner::Start(otCommissionerStateCallback aStateCallback,
|
||||
@@ -322,12 +377,42 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Commissioner::ComputeBloomFilter(SteeringData &aSteeringData) const
|
||||
{
|
||||
Mac::ExtAddress joinerId;
|
||||
|
||||
aSteeringData.Init();
|
||||
|
||||
for (const Joiner *joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++)
|
||||
{
|
||||
switch (joiner->mType)
|
||||
{
|
||||
case Joiner::kTypeUnused:
|
||||
break;
|
||||
|
||||
case Joiner::kTypeEui64:
|
||||
ComputeJoinerId(joiner->mSharedId.mEui64, joinerId);
|
||||
aSteeringData.UpdateBloomFilter(joinerId);
|
||||
break;
|
||||
|
||||
case Joiner::kTypeDiscerner:
|
||||
aSteeringData.UpdateBloomFilter(joiner->mSharedId.mDiscerner);
|
||||
break;
|
||||
|
||||
case Joiner::kTypeAny:
|
||||
aSteeringData.SetToPermitAllJoiners();
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Commissioner::SendCommissionerSet(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otCommissioningDataset dataset;
|
||||
SteeringData & steeringData = static_cast<SteeringData &>(dataset.mSteeringData);
|
||||
Mac::ExtAddress joinerId;
|
||||
|
||||
VerifyOrExit(mState == OT_COMMISSIONER_STATE_ACTIVE, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
@@ -336,26 +421,7 @@ void Commissioner::SendCommissionerSet(void)
|
||||
dataset.mSessionId = mSessionId;
|
||||
dataset.mIsSessionIdSet = true;
|
||||
|
||||
// Compute bloom filter
|
||||
steeringData.Init();
|
||||
|
||||
for (Joiner *joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++)
|
||||
{
|
||||
if (!joiner->mValid)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (joiner->mAny)
|
||||
{
|
||||
steeringData.SetToPermitAllJoiners();
|
||||
break;
|
||||
}
|
||||
|
||||
ComputeJoinerId(joiner->mEui64, joinerId);
|
||||
steeringData.UpdateBloomFilter(joinerId);
|
||||
}
|
||||
|
||||
ComputeBloomFilter(static_cast<SteeringData &>(dataset.mSteeringData));
|
||||
dataset.mIsSteeringDataSet = true;
|
||||
|
||||
error = SendMgmtCommissionerSetRequest(dataset, nullptr, 0);
|
||||
@@ -371,13 +437,16 @@ void Commissioner::ClearJoiners(void)
|
||||
{
|
||||
for (Joiner *joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++)
|
||||
{
|
||||
joiner->mValid = false;
|
||||
joiner->mType = Joiner::kTypeUnused;
|
||||
}
|
||||
|
||||
SendCommissionerSet();
|
||||
}
|
||||
|
||||
otError Commissioner::AddJoiner(const Mac::ExtAddress *aEui64, const char *aPskd, uint32_t aTimeout)
|
||||
otError Commissioner::AddJoiner(const Mac::ExtAddress *aEui64,
|
||||
const JoinerDiscerner *aDiscerner,
|
||||
const char * aPskd,
|
||||
uint32_t aTimeout)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Joiner *joiner;
|
||||
@@ -385,7 +454,15 @@ otError Commissioner::AddJoiner(const Mac::ExtAddress *aEui64, const char *aPskd
|
||||
VerifyOrExit(mState == OT_COMMISSIONER_STATE_ACTIVE, error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(IsPskdValid(aPskd), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
joiner = FindJoinerEntry(aEui64);
|
||||
if (aDiscerner != nullptr)
|
||||
{
|
||||
VerifyOrExit(aDiscerner->IsValid(), error = OT_ERROR_INVALID_ARGS);
|
||||
joiner = FindJoinerEntry(*aDiscerner);
|
||||
}
|
||||
else
|
||||
{
|
||||
joiner = FindJoinerEntry(aEui64);
|
||||
}
|
||||
|
||||
if (joiner == nullptr)
|
||||
{
|
||||
@@ -394,18 +471,24 @@ otError Commissioner::AddJoiner(const Mac::ExtAddress *aEui64, const char *aPskd
|
||||
|
||||
VerifyOrExit(joiner != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
if (aEui64 != nullptr)
|
||||
if (aDiscerner != nullptr)
|
||||
{
|
||||
joiner->mAny = false;
|
||||
joiner->mEui64 = *aEui64;
|
||||
joiner->mType = Joiner::kTypeDiscerner;
|
||||
joiner->mSharedId.mDiscerner = *aDiscerner;
|
||||
}
|
||||
else if (aEui64 != nullptr)
|
||||
{
|
||||
joiner->mType = Joiner::kTypeEui64;
|
||||
joiner->mSharedId.mEui64 = *aEui64;
|
||||
}
|
||||
else
|
||||
{
|
||||
joiner->mAny = true;
|
||||
joiner->mType = Joiner::kTypeAny;
|
||||
}
|
||||
|
||||
strncpy(joiner->mPsk, aPskd, sizeof(joiner->mPsk) - 1);
|
||||
joiner->mValid = true;
|
||||
joiner->mPsk[sizeof(joiner->mPsk) - 1] = '\0';
|
||||
|
||||
joiner->mExpirationTime = TimerMilli::GetNow() + Time::SecToMsec(aTimeout);
|
||||
|
||||
UpdateJoinerExpirationTimer();
|
||||
@@ -418,26 +501,50 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Commissioner::GetNextJoinerInfo(uint16_t &aIterator, otJoinerInfo &aJoiner) const
|
||||
void Commissioner::Joiner::CopyToJoinerInfo(otJoinerInfo &aInfo) const
|
||||
{
|
||||
memset(&aInfo, 0, sizeof(aInfo));
|
||||
|
||||
switch (mType)
|
||||
{
|
||||
case kTypeAny:
|
||||
aInfo.mType = OT_JOINER_INFO_TYPE_ANY;
|
||||
break;
|
||||
|
||||
case kTypeEui64:
|
||||
aInfo.mType = OT_JOINER_INFO_TYPE_EUI64;
|
||||
aInfo.mSharedId.mEui64 = mSharedId.mEui64;
|
||||
break;
|
||||
|
||||
case kTypeDiscerner:
|
||||
aInfo.mType = OT_JOINER_INFO_TYPE_DISCERNER;
|
||||
aInfo.mSharedId.mDiscerner = mSharedId.mDiscerner;
|
||||
break;
|
||||
|
||||
case kTypeUnused:
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
strncpy(aInfo.mPsk, mPsk, sizeof(aInfo.mPsk) - 1);
|
||||
aInfo.mExpirationTime = mExpirationTime - TimerMilli::GetNow();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
otError Commissioner::GetNextJoinerInfo(uint16_t &aIterator, otJoinerInfo &aInfo) const
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
size_t index;
|
||||
|
||||
for (index = aIterator; index < OT_ARRAY_LENGTH(mJoiners); index++)
|
||||
while (aIterator < OT_ARRAY_LENGTH(mJoiners))
|
||||
{
|
||||
if (!mJoiners[index].mValid)
|
||||
const Joiner &joiner = mJoiners[aIterator++];
|
||||
|
||||
if (joiner.mType != Joiner::kTypeUnused)
|
||||
{
|
||||
continue;
|
||||
joiner.CopyToJoinerInfo(aInfo);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
memset(&aJoiner, 0, sizeof(aJoiner));
|
||||
|
||||
aJoiner.mAny = mJoiners[index].mAny;
|
||||
aJoiner.mEui64 = mJoiners[index].mEui64;
|
||||
strncpy(aJoiner.mPsk, mJoiners[index].mPsk, sizeof(aJoiner.mPsk) - 1);
|
||||
aJoiner.mExpirationTime = mJoiners[index].mExpirationTime - TimerMilli::GetNow();
|
||||
aIterator = static_cast<uint16_t>(index) + 1;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
error = OT_ERROR_NOT_FOUND;
|
||||
@@ -446,33 +553,47 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Commissioner::RemoveJoiner(const Mac::ExtAddress *aEui64, uint32_t aDelay)
|
||||
otError Commissioner::RemoveJoiner(const Mac::ExtAddress *aEui64, const JoinerDiscerner *aDiscerner, uint32_t aDelay)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Joiner *joiner;
|
||||
|
||||
VerifyOrExit(mState == OT_COMMISSIONER_STATE_ACTIVE, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
joiner = FindJoinerEntry(aEui64);
|
||||
if (aDiscerner != nullptr)
|
||||
{
|
||||
VerifyOrExit(aDiscerner->IsValid(), error = OT_ERROR_INVALID_ARGS);
|
||||
joiner = FindJoinerEntry(*aDiscerner);
|
||||
}
|
||||
else
|
||||
{
|
||||
joiner = FindJoinerEntry(aEui64);
|
||||
}
|
||||
|
||||
VerifyOrExit(joiner != nullptr, error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
RemoveJoiner(*joiner, aDelay);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Commissioner::RemoveJoiner(Joiner &aJoiner, uint32_t aDelay)
|
||||
{
|
||||
if (aDelay > 0)
|
||||
{
|
||||
TimeMilli newExpirationTime = TimerMilli::GetNow() + Time::SecToMsec(aDelay);
|
||||
|
||||
if (joiner->mExpirationTime > newExpirationTime)
|
||||
if (aJoiner.mExpirationTime > newExpirationTime)
|
||||
{
|
||||
joiner->mExpirationTime = newExpirationTime;
|
||||
aJoiner.mExpirationTime = newExpirationTime;
|
||||
UpdateJoinerExpirationTimer();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveJoinerEntry(*joiner);
|
||||
RemoveJoinerEntry(aJoiner);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Commissioner::SetProvisioningUrl(const char *aProvisioningUrl)
|
||||
@@ -530,7 +651,12 @@ void Commissioner::HandleJoinerExpirationTimer(void)
|
||||
|
||||
for (Joiner *joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++)
|
||||
{
|
||||
if (joiner->mValid && (joiner->mExpirationTime <= now))
|
||||
if (joiner->mType == Joiner::kTypeUnused)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (joiner->mExpirationTime <= now)
|
||||
{
|
||||
otLogDebgMeshCoP("removing joiner due to timeout or successfully joined");
|
||||
RemoveJoinerEntry(*joiner);
|
||||
@@ -547,7 +673,7 @@ void Commissioner::UpdateJoinerExpirationTimer(void)
|
||||
|
||||
for (Joiner *joiner = &mJoiners[0]; joiner < OT_ARRAY_END(mJoiners); joiner++)
|
||||
{
|
||||
if (!joiner->mValid)
|
||||
if (joiner->mType == Joiner::kTypeUnused)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -939,10 +1065,10 @@ void Commissioner::HandleRelayReceive(Coap::Message &aMessage, const Ip6::Messag
|
||||
|
||||
SuccessOrExit(error = Get<Coap::CoapSecure>().SetPsk(reinterpret_cast<const uint8_t *>(joiner->mPsk),
|
||||
static_cast<uint8_t>(strlen(joiner->mPsk))));
|
||||
mJoinerIndex = static_cast<uint8_t>(joiner - mJoiners);
|
||||
mActiveJoiner = joiner;
|
||||
|
||||
LogJoinerEntry("Starting new session with", *joiner);
|
||||
SignalJoinerEvent(OT_COMMISSIONER_JOINER_START, receivedId);
|
||||
SignalJoinerEvent(OT_COMMISSIONER_JOINER_START, joiner);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1032,7 +1158,6 @@ void Commissioner::SendJoinFinalizeResponse(const Coap::Message &aRequest, State
|
||||
otError error = OT_ERROR_NONE;
|
||||
Ip6::MessageInfo joinerMessageInfo;
|
||||
Coap::Message * message;
|
||||
Mac::ExtAddress joinerId;
|
||||
|
||||
VerifyOrExit((message = NewMeshCoPMessage(Get<Coap::CoapSecure>())) != nullptr, error = OT_ERROR_NO_BUFS);
|
||||
|
||||
@@ -1057,14 +1182,12 @@ void Commissioner::SendJoinFinalizeResponse(const Coap::Message &aRequest, State
|
||||
|
||||
SuccessOrExit(error = Get<Coap::CoapSecure>().SendMessage(*message, joinerMessageInfo));
|
||||
|
||||
joinerId.Set(mJoinerIid.m8);
|
||||
joinerId.ToggleLocal();
|
||||
SignalJoinerEvent(OT_COMMISSIONER_JOINER_FINALIZE, joinerId);
|
||||
SignalJoinerEvent(OT_COMMISSIONER_JOINER_FINALIZE, mActiveJoiner);
|
||||
|
||||
if (!mJoiners[mJoinerIndex].mAny)
|
||||
if ((mActiveJoiner != nullptr) && (mActiveJoiner->mType != Joiner::kTypeAny))
|
||||
{
|
||||
// remove after kRemoveJoinerDelay (seconds)
|
||||
IgnoreError(RemoveJoiner(&mJoiners[mJoinerIndex].mEui64, kRemoveJoinerDelay));
|
||||
// Remove after kRemoveJoinerDelay (seconds)
|
||||
RemoveJoiner(*mActiveJoiner, kRemoveJoinerDelay);
|
||||
}
|
||||
|
||||
otLogInfoMeshCoP("sent joiner finalize response");
|
||||
@@ -1173,8 +1296,25 @@ const char *Commissioner::StateToString(otCommissionerState aState)
|
||||
|
||||
void Commissioner::LogJoinerEntry(const char *aAction, const Joiner &aJoiner) const
|
||||
{
|
||||
otLogInfoMeshCoP("%s Joiner (%s, %s)", aAction, aJoiner.mAny ? "*" : aJoiner.mEui64.ToString().AsCString(),
|
||||
aJoiner.mPsk);
|
||||
switch (aJoiner.mType)
|
||||
{
|
||||
case Joiner::kTypeUnused:
|
||||
break;
|
||||
|
||||
case Joiner::kTypeAny:
|
||||
otLogInfoMeshCoP("%s Joiner (any, %s)", aAction, aJoiner.mPsk);
|
||||
break;
|
||||
|
||||
case Joiner::kTypeEui64:
|
||||
otLogInfoMeshCoP("%s Joiner (eui64:%s, %s)", aAction, aJoiner.mSharedId.mEui64.ToString().AsCString(),
|
||||
aJoiner.mPsk);
|
||||
break;
|
||||
|
||||
case Joiner::kTypeDiscerner:
|
||||
otLogInfoMeshCoP("%s Joiner (disc:%s, %s)", aAction, aJoiner.mSharedId.mDiscerner.ToString().AsCString(),
|
||||
aJoiner.mPsk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -101,9 +101,8 @@ public:
|
||||
void ClearJoiners(void);
|
||||
|
||||
/**
|
||||
* This method adds a Joiner entry.
|
||||
* This method adds a Joiner entry accepting any Joiner.
|
||||
*
|
||||
* @param[in] aEui64 A pointer to the Joiner's IEEE EUI-64 or nullptr for any Joiner.
|
||||
* @param[in] aPskd A pointer to the PSKd.
|
||||
* @param[in] aTimeout A time after which a Joiner is automatically removed, in seconds.
|
||||
*
|
||||
@@ -112,7 +111,41 @@ public:
|
||||
* @retval OT_ERROR_INVALID_STATE Commissioner service is not started.
|
||||
*
|
||||
*/
|
||||
otError AddJoiner(const Mac::ExtAddress *aEui64, const char *aPskd, uint32_t aTimeout);
|
||||
otError AddJoinerAny(const char *aPskd, uint32_t aTimeout) { return AddJoiner(nullptr, nullptr, aPskd, aTimeout); }
|
||||
|
||||
/**
|
||||
* This method adds a Joiner entry.
|
||||
*
|
||||
* @param[in] aEui64 The Joiner's IEEE EUI-64.
|
||||
* @param[in] aPskd A pointer to the PSKd.
|
||||
* @param[in] aTimeout A time after which a Joiner is automatically removed, in seconds.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully added the Joiner.
|
||||
* @retval OT_ERROR_NO_BUFS No buffers available to add the Joiner.
|
||||
* @retval OT_ERROR_INVALID_STATE Commissioner service is not started.
|
||||
*
|
||||
*/
|
||||
otError AddJoiner(const Mac::ExtAddress &aEui64, const char *aPskd, uint32_t aTimeout)
|
||||
{
|
||||
return AddJoiner(&aEui64, nullptr, aPskd, aTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds a Joiner entry with a Joiner Discerner.
|
||||
*
|
||||
* @param[in] aDiscerner A Joiner Discerner.
|
||||
* @param[in] aPskd A pointer to the PSKd.
|
||||
* @param[in] aTimeout A time after which a Joiner is automatically removed, in seconds.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully added the Joiner.
|
||||
* @retval OT_ERROR_NO_BUFS No buffers available to add the Joiner.
|
||||
* @retval OT_ERROR_INVALID_STATE Commissioner service is not started.
|
||||
*
|
||||
*/
|
||||
otError AddJoiner(const JoinerDiscerner &aDiscerner, const char *aPskd, uint32_t aTimeout)
|
||||
{
|
||||
return AddJoiner(nullptr, &aDiscerner, aPskd, aTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method get joiner info at aIterator position.
|
||||
@@ -126,10 +159,22 @@ public:
|
||||
*/
|
||||
otError GetNextJoinerInfo(uint16_t &aIterator, otJoinerInfo &aJoiner) const;
|
||||
|
||||
/**
|
||||
* This method removes a Joiner entry accepting any Joiner.
|
||||
*
|
||||
* @param[in] aDelay The delay to remove Joiner (in seconds).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully added the Joiner.
|
||||
* @retval OT_ERROR_NOT_FOUND The Joiner entry accepting any Joiner was not found.
|
||||
* @retval OT_ERROR_INVALID_STATE Commissioner service is not started.
|
||||
*
|
||||
*/
|
||||
otError RemoveJoinerAny(uint32_t aDelay) { return RemoveJoiner(nullptr, nullptr, aDelay); }
|
||||
|
||||
/**
|
||||
* This method removes a Joiner entry.
|
||||
*
|
||||
* @param[in] aEui64 A pointer to the Joiner's IEEE EUI-64 or nullptr for any Joiner.
|
||||
* @param[in] aEui64 The Joiner's IEEE EUI-64.
|
||||
* @param[in] aDelay The delay to remove Joiner (in seconds).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully added the Joiner.
|
||||
@@ -137,7 +182,26 @@ public:
|
||||
* @retval OT_ERROR_INVALID_STATE Commissioner service is not started.
|
||||
*
|
||||
*/
|
||||
otError RemoveJoiner(const Mac::ExtAddress *aEui64, uint32_t aDelay);
|
||||
otError RemoveJoiner(const Mac::ExtAddress &aEui64, uint32_t aDelay)
|
||||
{
|
||||
return RemoveJoiner(&aEui64, nullptr, aDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method removes a Joiner entry.
|
||||
*
|
||||
* @param[in] aDiscerner A Joiner Discerner.
|
||||
* @param[in] aDelay The delay to remove Joiner (in seconds).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully added the Joiner.
|
||||
* @retval OT_ERROR_NOT_FOUND The Joiner specified by @p aEui64 was not found.
|
||||
* @retval OT_ERROR_INVALID_STATE Commissioner service is not started.
|
||||
*
|
||||
*/
|
||||
otError RemoveJoiner(const JoinerDiscerner &aDiscerner, uint32_t aDelay)
|
||||
{
|
||||
return RemoveJoiner(nullptr, &aDiscerner, aDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the Provisioning URL.
|
||||
@@ -265,18 +329,41 @@ private:
|
||||
|
||||
struct Joiner
|
||||
{
|
||||
Mac::ExtAddress mEui64;
|
||||
TimeMilli mExpirationTime;
|
||||
char mPsk[Dtls::kPskMaxLength + 1];
|
||||
bool mValid : 1;
|
||||
bool mAny : 1;
|
||||
enum Type
|
||||
{
|
||||
kTypeUnused = 0, // Need to be 0 to ensure `memset()` clears all `Joiners`
|
||||
kTypeAny,
|
||||
kTypeEui64,
|
||||
kTypeDiscerner,
|
||||
};
|
||||
|
||||
TimeMilli mExpirationTime;
|
||||
|
||||
union
|
||||
{
|
||||
Mac::ExtAddress mEui64;
|
||||
JoinerDiscerner mDiscerner;
|
||||
} mSharedId;
|
||||
|
||||
char mPsk[Dtls::kPskMaxLength + 1];
|
||||
Type mType;
|
||||
|
||||
void CopyToJoinerInfo(otJoinerInfo &aInfo) const;
|
||||
};
|
||||
|
||||
Joiner *GetUnusedJoinerEntry(void);
|
||||
Joiner *FindJoinerEntry(const Mac::ExtAddress *aEui64);
|
||||
Joiner *FindJoinerEntry(const JoinerDiscerner &aDiscerner);
|
||||
Joiner *FindBestMatchingJoinerEntry(const Mac::ExtAddress &aRxJoinerId);
|
||||
void RemoveJoinerEntry(Joiner &aJoiner);
|
||||
|
||||
otError AddJoiner(const Mac::ExtAddress *aEui64,
|
||||
const JoinerDiscerner *aDiscerner,
|
||||
const char * aPskd,
|
||||
uint32_t aTimeout);
|
||||
otError RemoveJoiner(const Mac::ExtAddress *aEui64, const JoinerDiscerner *aDiscerner, uint32_t aDelay);
|
||||
void RemoveJoiner(Joiner &aJoiner, uint32_t aDelay);
|
||||
|
||||
void AddCoapResources(void);
|
||||
void RemoveCoapResources(void);
|
||||
|
||||
@@ -330,24 +417,25 @@ private:
|
||||
static otError SendRelayTransmit(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
otError SendRelayTransmit(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
|
||||
void ComputeBloomFilter(SteeringData &aSteeringData) const;
|
||||
void SendCommissionerSet(void);
|
||||
otError SendPetition(void);
|
||||
void SendKeepAlive(void);
|
||||
void SendKeepAlive(uint16_t aSessionId);
|
||||
|
||||
void SetState(otCommissionerState aState);
|
||||
void SignalJoinerEvent(otCommissionerJoinerEvent aEvent, const Mac::ExtAddress &aJoinerId);
|
||||
void SignalJoinerEvent(otCommissionerJoinerEvent aEvent, const Joiner *aJoiner) const;
|
||||
void LogJoinerEntry(const char *aAction, const Joiner &aJoiner) const;
|
||||
|
||||
static const char *StateToString(otCommissionerState aState);
|
||||
|
||||
Joiner mJoiners[OPENTHREAD_CONFIG_COMMISSIONER_MAX_JOINER_ENTRIES];
|
||||
|
||||
Joiner * mActiveJoiner;
|
||||
Ip6::InterfaceIdentifier mJoinerIid;
|
||||
uint16_t mJoinerPort;
|
||||
uint16_t mJoinerRloc;
|
||||
uint16_t mSessionId;
|
||||
uint8_t mJoinerIndex;
|
||||
uint8_t mTransmitAttempts;
|
||||
TimerMilli mJoinerExpirationTimer;
|
||||
TimerMilli mTimer;
|
||||
@@ -364,11 +452,11 @@ private:
|
||||
|
||||
char mProvisioningUrl[OT_PROVISIONING_URL_MAX_SIZE + 1]; // + 1 is for null char at end of string.
|
||||
|
||||
otCommissionerState mState;
|
||||
|
||||
otCommissionerStateCallback mStateCallback;
|
||||
otCommissionerJoinerCallback mJoinerCallback;
|
||||
void * mCallbackContext;
|
||||
|
||||
otCommissionerState mState;
|
||||
};
|
||||
|
||||
} // namespace MeshCoP
|
||||
|
||||
+56
-12
@@ -57,6 +57,8 @@ namespace MeshCoP {
|
||||
|
||||
Joiner::Joiner(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mId()
|
||||
, mDiscerner()
|
||||
, mState(OT_JOINER_STATE_IDLE)
|
||||
, mCallback(nullptr)
|
||||
, mContext(nullptr)
|
||||
@@ -65,14 +67,51 @@ Joiner::Joiner(Instance &aInstance)
|
||||
, mTimer(aInstance, Joiner::HandleTimer, this)
|
||||
, mJoinerEntrust(OT_URI_PATH_JOINER_ENTRUST, &Joiner::HandleJoinerEntrust, this)
|
||||
{
|
||||
SetIdFromIeeeEui64();
|
||||
mDiscerner.Clear();
|
||||
memset(mJoinerRouters, 0, sizeof(mJoinerRouters));
|
||||
Get<Coap::Coap>().AddResource(mJoinerEntrust);
|
||||
}
|
||||
|
||||
void Joiner::GetJoinerId(Mac::ExtAddress &aJoinerId) const
|
||||
void Joiner::SetIdFromIeeeEui64(void)
|
||||
{
|
||||
Get<Radio>().GetIeeeEui64(aJoinerId);
|
||||
ComputeJoinerId(aJoinerId, aJoinerId);
|
||||
Mac::ExtAddress eui64;
|
||||
|
||||
Get<Radio>().GetIeeeEui64(eui64);
|
||||
ComputeJoinerId(eui64, mId);
|
||||
}
|
||||
|
||||
const JoinerDiscerner *Joiner::GetDiscerner(void) const
|
||||
{
|
||||
return mDiscerner.IsEmpty() ? nullptr : &mDiscerner;
|
||||
}
|
||||
|
||||
otError Joiner::SetDiscerner(const JoinerDiscerner &aDiscerner)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(aDiscerner.IsValid(), error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(mState == OT_JOINER_STATE_IDLE, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
mDiscerner = aDiscerner;
|
||||
mDiscerner.GenerateJoinerId(mId);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Joiner::ClearDiscerner(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mState == OT_JOINER_STATE_IDLE, error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(!mDiscerner.IsEmpty(), OT_NOOP);
|
||||
|
||||
mDiscerner.Clear();
|
||||
SetIdFromIeeeEui64();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Joiner::SetState(otJoinerState aState)
|
||||
@@ -96,8 +135,9 @@ otError Joiner::Start(const char * aPskd,
|
||||
otJoinerCallback aCallback,
|
||||
void * aContext)
|
||||
{
|
||||
otError error;
|
||||
Mac::ExtAddress randomAddress;
|
||||
otError error;
|
||||
Mac::ExtAddress randomAddress;
|
||||
SteeringData::HashBitIndexes filterIndexes;
|
||||
|
||||
otLogInfoMeshCoP("Joiner starting");
|
||||
|
||||
@@ -122,10 +162,18 @@ otError Joiner::Start(const char * aPskd,
|
||||
SuccessOrExit(error = PrepareJoinerFinalizeMessage(aProvisioningUrl, aVendorName, aVendorModel, aVendorSwVersion,
|
||||
aVendorData));
|
||||
|
||||
if (!mDiscerner.IsEmpty())
|
||||
{
|
||||
SteeringData::CalculateHashBitIndexes(mDiscerner, filterIndexes);
|
||||
}
|
||||
else
|
||||
{
|
||||
SteeringData::CalculateHashBitIndexes(mId, filterIndexes);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = Get<Mle::DiscoverScanner>().Discover(Mac::ChannelMask(0), Get<Mac::Mac>().GetPanId(),
|
||||
/* aJoiner */ true, /* aEnableFiltering */ true,
|
||||
/* aFilterIndexes (use hash of factory EUI64) */ nullptr,
|
||||
HandleDiscoverResult, this));
|
||||
&filterIndexes, HandleDiscoverResult, this));
|
||||
mCallback = aCallback;
|
||||
mContext = aContext;
|
||||
|
||||
@@ -226,8 +274,6 @@ void Joiner::HandleDiscoverResult(otActiveScanResult *aResult, void *aContext)
|
||||
|
||||
void Joiner::HandleDiscoverResult(otActiveScanResult *aResult)
|
||||
{
|
||||
Mac::ExtAddress joinerId;
|
||||
|
||||
VerifyOrExit(mState == OT_JOINER_STATE_DISCOVER, OT_NOOP);
|
||||
|
||||
if (aResult != nullptr)
|
||||
@@ -236,9 +282,7 @@ void Joiner::HandleDiscoverResult(otActiveScanResult *aResult)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use extended address based on factory-assigned IEEE EUI-64
|
||||
GetJoinerId(joinerId);
|
||||
Get<Mac::Mac>().SetExtAddress(joinerId);
|
||||
Get<Mac::Mac>().SetExtAddress(mId);
|
||||
Get<Mle::MleRouter>().UpdateLinkLocalAddress();
|
||||
|
||||
mJoinerRouterIndex = 0;
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "common/message.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "meshcop/dtls.hpp"
|
||||
#include "meshcop/meshcop.hpp"
|
||||
#include "meshcop/meshcop_tlvs.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -104,10 +105,47 @@ public:
|
||||
/**
|
||||
* This method retrieves the Joiner ID.
|
||||
*
|
||||
* @param[out] aJoinerId The Joiner ID.
|
||||
* @returns The Joiner ID.
|
||||
*
|
||||
*/
|
||||
void GetJoinerId(Mac::ExtAddress &aJoinerId) const;
|
||||
const Mac::ExtAddress &GetId(void) const { return mId; }
|
||||
|
||||
/**
|
||||
* This method gets the Jointer Discerner.
|
||||
*
|
||||
* @returns A pointer to the current Joiner Discerner or `nullptr` if none is set.
|
||||
*
|
||||
*/
|
||||
const JoinerDiscerner *GetDiscerner(void) const;
|
||||
|
||||
/**
|
||||
* This method sets the Joiner Discerner.
|
||||
*
|
||||
* The Joiner Discerner is used to calculate the Joiner ID used during commissioning/joining process.
|
||||
*
|
||||
* By default (when a discerner is not provided or cleared), Joiner ID is derived as first 64 bits of the
|
||||
* result of computing SHA-256 over factory-assigned IEEE EUI-64. Note that this is the main behavior expected by
|
||||
* Thread specification.
|
||||
*
|
||||
* @param[in] aDiscerner A Joiner Discerner
|
||||
*
|
||||
* @retval OT_ERROR_NONE The Joiner Discerner updated successfully.
|
||||
* @retval OT_ERROR_INVALID_ARGS @p aDisciminrator is not valid (specified length is not within valid range).
|
||||
* @retval OT_ERROR_INVALID_STATE There is an ongoing Joining process so Joiner Discerner could not be changed.
|
||||
*
|
||||
*/
|
||||
otError SetDiscerner(const JoinerDiscerner &aDiscerner);
|
||||
|
||||
/**
|
||||
* This method clears any previously set Joiner Discerner.
|
||||
*
|
||||
* When cleared, Joiner ID is derived as first 64 bits of SHA-256 of factory-assigned IEEE EUI-64.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The Joiner Discerner cleared and Joiner ID updated.
|
||||
* @retval OT_ERROR_INVALID_STATE There is an ongoing Joining process so Joiner Discerner could not be changed.
|
||||
*
|
||||
*/
|
||||
otError ClearDiscerner(void);
|
||||
|
||||
private:
|
||||
enum
|
||||
@@ -147,6 +185,7 @@ private:
|
||||
static const char *JoinerStateToString(otJoinerState aState);
|
||||
|
||||
void SetState(otJoinerState aState);
|
||||
void SetIdFromIeeeEui64(void);
|
||||
void SaveDiscoveredJoinerRouter(const otActiveScanResult &aResult);
|
||||
void TryNextJoinerRouter(otError aPrevError);
|
||||
otError Connect(JoinerRouter &aRouter);
|
||||
@@ -166,6 +205,9 @@ private:
|
||||
void LogCertMessage(const char *aText, const Coap::Message &aMessage) const;
|
||||
#endif
|
||||
|
||||
Mac::ExtAddress mId;
|
||||
JoinerDiscerner mDiscerner;
|
||||
|
||||
otJoinerState mState;
|
||||
|
||||
otJoinerCallback mCallback;
|
||||
|
||||
@@ -50,6 +50,88 @@ enum
|
||||
kPskdMaxLength = 32, ///< Maximum PSKd Length.
|
||||
};
|
||||
|
||||
void JoinerDiscerner::GenerateJoinerId(Mac::ExtAddress &aJoinerId) const
|
||||
{
|
||||
aJoinerId.GenerateRandom();
|
||||
CopyTo(aJoinerId);
|
||||
aJoinerId.SetLocal(true);
|
||||
}
|
||||
|
||||
bool JoinerDiscerner::Matches(const Mac::ExtAddress &aJoinerId) const
|
||||
{
|
||||
uint64_t mask;
|
||||
|
||||
OT_ASSERT(IsValid());
|
||||
|
||||
mask = GetMask();
|
||||
|
||||
return (Encoding::BigEndian::ReadUint64(aJoinerId.m8) & mask) == (mValue & mask);
|
||||
}
|
||||
|
||||
void JoinerDiscerner::CopyTo(Mac::ExtAddress &aExtAddress) const
|
||||
{
|
||||
// Copies the discerner value up to its bit length to `aExtAddress`
|
||||
// array, assuming big-endian encoding (i.e., the discerner lowest bits
|
||||
// are copied at end of `aExtAddress.m8[]` array). Any initial/remaining
|
||||
// bits of `aExtAddress` array remain unchanged.
|
||||
|
||||
uint8_t *cur = &aExtAddress.m8[sizeof(Mac::ExtAddress) - 1];
|
||||
uint8_t remaining = mLength;
|
||||
uint64_t value = mValue;
|
||||
|
||||
OT_ASSERT(IsValid());
|
||||
|
||||
// Write full bytes
|
||||
while (remaining >= CHAR_BIT)
|
||||
{
|
||||
*cur = static_cast<uint8_t>(value & 0xff);
|
||||
value >>= CHAR_BIT;
|
||||
cur--;
|
||||
remaining -= CHAR_BIT;
|
||||
}
|
||||
|
||||
// Write any remaining bits (not a full byte)
|
||||
if (remaining != 0)
|
||||
{
|
||||
uint8_t mask = static_cast<uint8_t>((1U << remaining) - 1);
|
||||
|
||||
// `mask` has it lower (lsb) `remaining` bits as `1` and rest as `0`.
|
||||
// Example with `remaining = 3` -> (1 << 3) - 1 = 0b1000 - 1 = 0b0111.
|
||||
|
||||
*cur &= ~mask;
|
||||
*cur |= static_cast<uint8_t>(value & mask);
|
||||
}
|
||||
}
|
||||
|
||||
bool JoinerDiscerner::operator==(const JoinerDiscerner &aOther) const
|
||||
{
|
||||
uint64_t mask = GetMask();
|
||||
|
||||
return IsValid() && (mLength == aOther.mLength) && ((mValue & mask) == (aOther.mValue & mask));
|
||||
}
|
||||
|
||||
JoinerDiscerner::InfoString JoinerDiscerner::ToString(void) const
|
||||
{
|
||||
InfoString str;
|
||||
|
||||
if (mLength <= sizeof(uint16_t) * CHAR_BIT)
|
||||
{
|
||||
IgnoreError(str.Set("0x%04x", static_cast<uint16_t>(mValue)));
|
||||
}
|
||||
else if (mLength <= sizeof(uint32_t) * CHAR_BIT)
|
||||
{
|
||||
IgnoreError(str.Set("0x%08x", static_cast<uint32_t>(mValue)));
|
||||
}
|
||||
else
|
||||
{
|
||||
IgnoreError(str.Set("0x%x-%08x", static_cast<uint32_t>(mValue >> 32), static_cast<uint32_t>(mValue)));
|
||||
}
|
||||
|
||||
IgnoreError(str.Append("/len:%d", mLength));
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void SteeringData::Init(uint8_t aLength)
|
||||
{
|
||||
OT_ASSERT(aLength <= kMaxLength);
|
||||
@@ -67,12 +149,24 @@ void SteeringData::UpdateBloomFilter(const Mac::ExtAddress &aJoinerId)
|
||||
{
|
||||
HashBitIndexes indexes;
|
||||
|
||||
CalculateHashBitIndexes(aJoinerId, indexes);
|
||||
UpdateBloomFilter(indexes);
|
||||
}
|
||||
|
||||
void SteeringData::UpdateBloomFilter(const JoinerDiscerner &aDiscerner)
|
||||
{
|
||||
HashBitIndexes indexes;
|
||||
|
||||
CalculateHashBitIndexes(aDiscerner, indexes);
|
||||
UpdateBloomFilter(indexes);
|
||||
}
|
||||
|
||||
void SteeringData::UpdateBloomFilter(const HashBitIndexes &aIndexes)
|
||||
{
|
||||
OT_ASSERT((mLength > 0) && (mLength <= kMaxLength));
|
||||
|
||||
CalculateHashBitIndexes(aJoinerId, indexes);
|
||||
|
||||
SetBit(indexes.mIndex[0] % GetNumBits());
|
||||
SetBit(indexes.mIndex[1] % GetNumBits());
|
||||
SetBit(aIndexes.mIndex[0] % GetNumBits());
|
||||
SetBit(aIndexes.mIndex[1] % GetNumBits());
|
||||
}
|
||||
|
||||
bool SteeringData::Contains(const Mac::ExtAddress &aJoinerId) const
|
||||
@@ -84,6 +178,15 @@ bool SteeringData::Contains(const Mac::ExtAddress &aJoinerId) const
|
||||
return Contains(indexes);
|
||||
}
|
||||
|
||||
bool SteeringData::Contains(const JoinerDiscerner &aDiscerner) const
|
||||
{
|
||||
HashBitIndexes indexes;
|
||||
|
||||
CalculateHashBitIndexes(aDiscerner, indexes);
|
||||
|
||||
return Contains(indexes);
|
||||
}
|
||||
|
||||
bool SteeringData::Contains(const HashBitIndexes &aIndexes) const
|
||||
{
|
||||
return (mLength > 0) && GetBit(aIndexes.mIndex[0] % GetNumBits()) && GetBit(aIndexes.mIndex[1] % GetNumBits());
|
||||
@@ -104,6 +207,16 @@ void SteeringData::CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, Has
|
||||
aIndexes.mIndex[1] = ansi.Get();
|
||||
}
|
||||
|
||||
void SteeringData::CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, HashBitIndexes &aIndexes)
|
||||
{
|
||||
Mac::ExtAddress address;
|
||||
|
||||
address.Clear();
|
||||
aDiscerner.CopyTo(address);
|
||||
|
||||
CalculateHashBitIndexes(address, aIndexes);
|
||||
}
|
||||
|
||||
bool SteeringData::DoesAllMatch(uint8_t aMatch) const
|
||||
{
|
||||
bool matches = true;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/joiner.h>
|
||||
|
||||
#include "coap/coap.hpp"
|
||||
#include "common/message.hpp"
|
||||
@@ -57,6 +58,119 @@ enum
|
||||
kBorderAgentUdpPort = 49191, ///< UDP port of border agent service.
|
||||
};
|
||||
|
||||
/**
|
||||
* This type represents a Joiner Discerner.
|
||||
*
|
||||
*/
|
||||
class JoinerDiscerner : public otJoinerDiscerner
|
||||
{
|
||||
friend class SteeringData;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kMaxLength = OT_JOINER_MAX_DISCERNER_LENGTH, ///< Maximum length of a Joiner Discerner in bits.
|
||||
kInfoStringSize = 45, ///< Size of `InfoString` to use with `ToString()
|
||||
};
|
||||
|
||||
/**
|
||||
* This type defines the fixed-length `String` object returned from `ToString()`.
|
||||
*
|
||||
*/
|
||||
typedef String<kInfoStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method clears the Joiner Discerner.
|
||||
*
|
||||
*/
|
||||
void Clear(void) { mLength = 0; }
|
||||
|
||||
/**
|
||||
* This method indicates whether the Joiner Discerner is empty (no value set).
|
||||
*
|
||||
* @returns TRUE if empty, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsEmpty(void) const { return mLength == 0; }
|
||||
|
||||
/**
|
||||
* This method gets the Joiner Discerner's value.
|
||||
*
|
||||
* @returns The Joiner Discerner value.
|
||||
*
|
||||
*/
|
||||
uint64_t GetValue(void) const { return mValue; }
|
||||
|
||||
/**
|
||||
* This method gets the Joiner Discerner's length (in bits).
|
||||
*
|
||||
* @return The Joiner Discerner length.
|
||||
*
|
||||
*/
|
||||
uint8_t GetLength(void) const { return mLength; }
|
||||
|
||||
/**
|
||||
* This method indicates whether the Joiner Discerner is valid (i.e. it not empty and its length is within
|
||||
* valid range).
|
||||
*
|
||||
* @returns TRUE if Joiner Discerner is valid, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return (0 < mLength) && (mLength <= kMaxLength); }
|
||||
|
||||
/**
|
||||
* This method generates a Joiner ID from the Discerner.
|
||||
*
|
||||
* @param[out] aJoinerId A reference to `Mac::ExtAddress` to output the generated Joiner ID.
|
||||
*
|
||||
*/
|
||||
void GenerateJoinerId(Mac::ExtAddress &aJoinerId) const;
|
||||
|
||||
/**
|
||||
* This method indicates whether a given Joiner ID matches the Discerner.
|
||||
*
|
||||
* @param[in] aJoiner A Joiner ID to match with the Discerner.
|
||||
*
|
||||
* @returns TRUE if the Joiner ID matches the Discerner, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool Matches(const Mac::ExtAddress &aJoinerId) const;
|
||||
|
||||
/**
|
||||
* This method overloads operator `==` to evaluate whether or not two Joiner Discerner instances are equal.
|
||||
*
|
||||
* @param[in] aOther The other Joiner Discerner to compare with.
|
||||
*
|
||||
* @retval TRUE If the two are equal.
|
||||
* @retval FALSE If the two are not equal.
|
||||
*
|
||||
*/
|
||||
bool operator==(const JoinerDiscerner &aOther) const;
|
||||
|
||||
/**
|
||||
* This method overloads operator `!=` to evaluate whether or not two Joiner Discerner instances are equal.
|
||||
*
|
||||
* @param[in] aOther The other Joiner Discerner to compare with.
|
||||
*
|
||||
* @retval TRUE If the two are not equal.
|
||||
* @retval FALSE If the two are equal.
|
||||
*
|
||||
*/
|
||||
bool operator!=(const JoinerDiscerner &aOther) const { return !(*this == aOther); }
|
||||
|
||||
/**
|
||||
* This method converts the Joiner Discerner to a string.
|
||||
*
|
||||
* @returns An `InfoString` representation of Joiner Discerner.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
private:
|
||||
uint64_t GetMask(void) const { return (static_cast<uint64_t>(1ULL) << mLength) - 1; }
|
||||
void CopyTo(Mac::ExtAddress &aExtAddress) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* This type represents Steering Data (bloom filter).
|
||||
*
|
||||
@@ -141,6 +255,14 @@ public:
|
||||
*/
|
||||
void UpdateBloomFilter(const Mac::ExtAddress &aJoinerId);
|
||||
|
||||
/**
|
||||
* This method updates the bloom filter adding a given Joiner Discerner.
|
||||
*
|
||||
* @param[in] aDiscerner The Joiner Discerner to add to bloom filter.
|
||||
*
|
||||
*/
|
||||
void UpdateBloomFilter(const JoinerDiscerner &aDiscerner);
|
||||
|
||||
/**
|
||||
* This method indicates whether the bloom filter is empty (all the bits are cleared).
|
||||
*
|
||||
@@ -160,13 +282,23 @@ public:
|
||||
/**
|
||||
* This method indicates whether the bloom filter contains a given Joiner ID.
|
||||
*
|
||||
* @param[in] aJoinderId A Joiner ID.
|
||||
* @param[in] aJoinerId A Joiner ID.
|
||||
*
|
||||
* @returns TRUE if the bloom filter contains @p aJoinerId, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool Contains(const Mac::ExtAddress &aJoinerId) const;
|
||||
|
||||
/**
|
||||
* This method indicates whether the bloom filter contains a given Joiner Discerner.
|
||||
*
|
||||
* @param[in] aDiscerner A Joiner Discerner.
|
||||
*
|
||||
* @returns TRUE if the bloom filter contains @p aDiscerner, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool Contains(const JoinerDiscerner &aDiscerner) const;
|
||||
|
||||
/**
|
||||
* This method indicates whether the bloom filter contains the hash bit indexes (derived from a Joiner ID).
|
||||
*
|
||||
@@ -188,6 +320,17 @@ public:
|
||||
*/
|
||||
static void CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes);
|
||||
|
||||
/**
|
||||
* This static method calculates the bloom filter hash bit indexes from a given Joiner Discerner.
|
||||
*
|
||||
* The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
|
||||
*
|
||||
* @param[in] aDiscerner The Joiner Discerner to calculate the hash bit indexes.
|
||||
* @param[out] aIndexes A reference to a `HashBitIndexes` structure to output the calculated index values.
|
||||
*
|
||||
*/
|
||||
static void CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, HashBitIndexes &aIndexes);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
@@ -204,6 +347,7 @@ private:
|
||||
void ClearBit(uint8_t aBit) { m8[BitIndex(aBit)] &= ~BitFlag(aBit); }
|
||||
|
||||
bool DoesAllMatch(uint8_t aMatch) const;
|
||||
void UpdateBloomFilter(const HashBitIndexes &aIndexes);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user