From a7415b53a45087702680ed60ed7c23dd8fb1c032 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Sat, 20 Jun 2020 00:35:57 -0700 Subject: [PATCH] [ncp] add support for Joiner Discerner and getting list of joiners (#5137) This commit adds/updates spinel properties to add Joiner Discerner support on joiner and commissioner side. It also adds support for getting the list of joiners on commissioner by implementing property get handler for spinel property `MESHCOP_COMMISSIONER_JOINERS`. --- src/lib/spinel/spinel.c | 4 ++ src/lib/spinel/spinel.h | 43 ++++++++++++-- src/ncp/ncp_base_dispatcher.cpp | 7 +++ src/ncp/ncp_base_ftd.cpp | 101 +++++++++++++++++++++++++++----- src/ncp/ncp_base_mtd.cpp | 42 ++++++++++++- 5 files changed, 177 insertions(+), 20 deletions(-) diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index c09fcd57f..ae0753f48 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1891,6 +1891,10 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "MESHCOP_COMMISSIONER_SESSION_ID"; break; + case SPINEL_PROP_MESHCOP_JOINER_DISCERNER: + ret = "MESHCOP_JOINER_DISCERNER"; + break; + case SPINEL_PROP_MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN: ret = "MESHCOP_COMMISSIONER_ANNOUNCE_BEGIN"; break; diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index dcc6e06ac..082279574 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -3112,15 +3112,22 @@ enum SPINEL_PROP_MESHCOP_COMMISSIONER_STATE = SPINEL_PROP_MESHCOP__BEGIN + 2, // Thread Commissioner Joiners - /** Format `A(t(E)UL)` - insert or remove only + /** Format `A(t(t(E|CX)UL))` - get, insert or remove. * * Required capability: SPINEL_CAP_THREAD_COMMISSIONER * - * Data per item is: + * Data per array entry is: * - * `t(E)` | `t()`: Joiner EUI64. Empty struct indicates any Joiner - * `L` : Timeout (in seconds) after which the Joiner is automatically removed - * `U` : PSKd + * `t()` | `t(E)` | `t(CX)` : Joiner info struct (formatting varies). + * + * - `t()` or empty struct indicates any joiner. + * - `t(E)` specifies the Joiner EUI-64. + * - `t(CX) specifies Joiner Discerner, `C` is Discerner length (in bits), and `X` is Discerner value. + * + * The struct is followed by: + * + * `L` : Timeout after which to remove Joiner (when written should be in seconds, when read is in milliseconds) + * `U` : PSKd * * For CMD_PROP_VALUE_REMOVE the timeout and PSKd are optional. * @@ -3143,6 +3150,32 @@ enum */ SPINEL_PROP_MESHCOP_COMMISSIONER_SESSION_ID = SPINEL_PROP_MESHCOP__BEGIN + 5, + /// Thread Joiner Discerner + /** Format `CX` - Read-write + * + * Required capability: SPINEL_CAP_THREAD_JOINER + * + * This property represents a 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. + * + * Format: + * + * 'C' : The Joiner Discerner bit length (number of bits). + * `X` : The Joiner Discerner value (64-bit unsigned) - Only present/applicable when length is non-zero. + * + * When writing to this property, the length can be set to zero to clear any previously set Joiner Discerner value. + * + * When reading this property if there is no currently set Joiner Discerner, zero is returned as the length (with + * no value field). + * + */ + SPINEL_PROP_MESHCOP_JOINER_DISCERNER = SPINEL_PROP_MESHCOP__BEGIN + 6, + SPINEL_PROP_MESHCOP__END = 0x90, SPINEL_PROP_MESHCOP_EXT__BEGIN = 0x1800, diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index 74714edf7..7eadb8c45 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -135,10 +135,14 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) #if OPENTHREAD_FTD #if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_COMMISSIONER_STATE), + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_COMMISSIONER_JOINERS), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_COMMISSIONER_SESSION_ID), #endif #endif // OPENTHREAD_FTD +#if OPENTHREAD_CONFIG_JOINER_ENABLE + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_JOINER_DISCERNER), +#endif #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_SERVER_SERVICES), @@ -404,6 +408,9 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_COMMISSIONER_PROVISIONING_URL), #endif #endif // OPENTHREAD_FTD +#if OPENTHREAD_CONFIG_JOINER_ENABLE + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MESHCOP_JOINER_DISCERNER), +#endif #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE), #endif diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 2e6262212..38df0d7ba 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -538,23 +538,72 @@ exit: return error; } +template <> otError NcpBase::HandlePropertyGet(void) +{ + otError error = OT_ERROR_NONE; + uint16_t iter = 0; + otJoinerInfo joinerInfo; + + while (otCommissionerGetNextJoinerInfo(mInstance, &iter, &joinerInfo) == OT_ERROR_NONE) + { + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.OpenStruct()); // Joiner Id (any, EUI64 or a Joiner Discerner) struct + + switch (joinerInfo.mType) + { + case OT_JOINER_INFO_TYPE_ANY: + break; + + case OT_JOINER_INFO_TYPE_EUI64: + SuccessOrExit(error = mEncoder.WriteEui64(joinerInfo.mSharedId.mEui64)); + break; + + case OT_JOINER_INFO_TYPE_DISCERNER: + SuccessOrExit(error = mEncoder.WriteUint8(joinerInfo.mSharedId.mDiscerner.mLength)); + SuccessOrExit(error = mEncoder.WriteUint64(joinerInfo.mSharedId.mDiscerner.mValue)); + break; + } + + SuccessOrExit(error = mEncoder.CloseStruct()); + + SuccessOrExit(error = mEncoder.WriteUint32(joinerInfo.mExpirationTime)); + SuccessOrExit(error = mEncoder.WriteUtf8(joinerInfo.mPskd.m8)); + + SuccessOrExit(error = mEncoder.CloseStruct()); + } + +exit: + return error; +} + template <> otError NcpBase::HandlePropertyInsert(void) { otError error = OT_ERROR_NONE; + otJoinerDiscerner discerner; + bool withDiscerner = false; const otExtAddress *eui64; uint32_t timeout; const char * psk; SuccessOrExit(error = mDecoder.OpenStruct()); - if (!mDecoder.IsAllReadInStruct()) + switch (mDecoder.GetRemainingLengthInStruct()) { - SuccessOrExit(error = mDecoder.ReadEui64(eui64)); - } - else - { - // Empty struct indicates any Joiner (no EUI64 is given so nullptr is used.). + case 0: + // Empty struct indicates any joiner eui64 = nullptr; + break; + + case sizeof(spinel_eui64_t): + SuccessOrExit(error = mDecoder.ReadEui64(eui64)); + break; + + default: + SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength)); + SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue)); + withDiscerner = true; + break; } SuccessOrExit(error = mDecoder.CloseStruct()); @@ -562,7 +611,14 @@ template <> otError NcpBase::HandlePropertyInsert otError NcpBase::HandlePropertyRemove(void) { otError error = OT_ERROR_NONE; + otJoinerDiscerner discerner; + bool withDiscerner = false; const otExtAddress *eui64; SuccessOrExit(error = mDecoder.OpenStruct()); - if (!mDecoder.IsAllReadInStruct()) + switch (mDecoder.GetRemainingLengthInStruct()) { - SuccessOrExit(error = mDecoder.ReadEui64(eui64)); - } - else - { - // Empty struct indicates any Joiner (no EUI64 is given so nullptr is used.). + case 0: + // Empty struct indicates any joiner eui64 = nullptr; + break; + + case sizeof(spinel_eui64_t): + SuccessOrExit(error = mDecoder.ReadEui64(eui64)); + break; + + default: + SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength)); + SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue)); + withDiscerner = true; + break; } SuccessOrExit(error = mDecoder.CloseStruct()); - error = otCommissionerRemoveJoiner(mInstance, eui64); + if (withDiscerner) + { + error = otCommissionerRemoveJoinerWithDiscerner(mInstance, &discerner); + } + else + { + error = otCommissionerRemoveJoiner(mInstance, eui64); + } exit: return error; diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 7dda234f2..9d1765bb7 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -1532,7 +1532,47 @@ exit: return error; } -#endif +template <> otError NcpBase::HandlePropertyGet(void) +{ + otError error; + const otJoinerDiscerner *discerner = otJoinerGetDiscerner(mInstance); + + if (discerner == nullptr) + { + SuccessOrExit(error = mEncoder.WriteUint8(0)); + } + else + { + SuccessOrExit(error = mEncoder.WriteUint8(discerner->mLength)); + SuccessOrExit(error = mEncoder.WriteUint64(discerner->mValue)); + } + +exit: + return error; +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + otError error = OT_ERROR_NONE; + otJoinerDiscerner discerner; + + SuccessOrExit(error = mDecoder.ReadUint8(discerner.mLength)); + + if (discerner.mLength == 0) + { + // Clearing any previously set Joiner Discerner + error = otJoinerSetDiscerner(mInstance, nullptr); + ExitNow(); + } + + SuccessOrExit(error = mDecoder.ReadUint64(discerner.mValue)); + error = otJoinerSetDiscerner(mInstance, &discerner); + +exit: + return error; +} + +#endif // OPENTHREAD_CONFIG_JOINER_ENABLE template <> otError NcpBase::HandlePropertyGet(void) {