From 204d0a91a3de1298de7e91554cae54f4402a2d70 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 20 May 2019 13:47:46 -0700 Subject: [PATCH] [commissioner] add callback for joiner events (#3862) --- examples/drivers/windows/otApi/otApi.cpp | 1 + examples/drivers/windows/otLwf/iocontrol.c | 2 +- .../drivers/windows/otNodeApi/otNodeApi.cpp | 2 +- include/openthread/commissioner.h | 33 +++++++- include/openthread/instance.h | 23 +++--- src/cli/cli_commissioner.cpp | 38 ++++++++- src/cli/cli_commissioner.hpp | 5 ++ src/core/api/commissioner_api.cpp | 9 ++- src/core/common/notifier.cpp | 4 - src/core/meshcop/commissioner.cpp | 81 ++++++++++++++----- src/core/meshcop/commissioner.hpp | 15 +++- src/core/meshcop/joiner.cpp | 1 - src/ncp/ncp_base_ftd.cpp | 4 +- 13 files changed, 169 insertions(+), 49 deletions(-) diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp index a398c9d97..85d2ba962 100644 --- a/examples/drivers/windows/otApi/otApi.cpp +++ b/examples/drivers/windows/otApi/otApi.cpp @@ -3666,6 +3666,7 @@ OTCALL otCommissionerStart( _In_ otInstance *aInstance, _In_ otCommissionerStateCallback aStateCallback, + _In_ otCommissionerJoinerCallback aJoinerCallback, _In_ void *aContext ) { diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c index cfb63e7c8..08b83084d 100644 --- a/examples/drivers/windows/otLwf/iocontrol.c +++ b/examples/drivers/windows/otLwf/iocontrol.c @@ -5367,7 +5367,7 @@ otLwfIoCtl_otCommissionerStart( UNREFERENCED_PARAMETER(OutBuffer); *OutBufferLength = 0; - return ThreadErrorToNtstatus(otCommissionerStart(pFilter->otCtx, NULL, NULL)); + return ThreadErrorToNtstatus(otCommissionerStart(pFilter->otCtx, NULL, NULL, NULL)); } _IRQL_requires_max_(PASSIVE_LEVEL) diff --git a/examples/drivers/windows/otNodeApi/otNodeApi.cpp b/examples/drivers/windows/otNodeApi/otNodeApi.cpp index 51afa1f0f..39ad50e28 100644 --- a/examples/drivers/windows/otNodeApi/otNodeApi.cpp +++ b/examples/drivers/windows/otNodeApi/otNodeApi.cpp @@ -999,7 +999,7 @@ OTNODEAPI int32_t OTCALL otNodeCommissionerStart(otNode* aNode) printf("%d: commissioner start\r\n", aNode->mId); // TODO: handle commissioner callback - auto error = otCommissionerStart(aNode->mInstance, NULL, NULL); + auto error = otCommissionerStart(aNode->mInstance, NULL, NULL, NULL); otLogFuncExit(); return error; diff --git a/include/openthread/commissioner.h b/include/openthread/commissioner.h index 595f9fa97..015d6eb94 100644 --- a/include/openthread/commissioner.h +++ b/include/openthread/commissioner.h @@ -65,6 +65,19 @@ typedef enum otCommissionerState OT_COMMISSIONER_STATE_ACTIVE = 2, ///< Commissioner role is active. } otCommissionerState; +/** + * This enumeration defines a Joiner Event on the Commissioner. + * + */ +typedef enum otCommissionerJoinerEvent +{ + OT_COMMISSIONER_JOINER_START = 0, + OT_COMMISSIONER_JOINER_CONNECTED = 1, + OT_COMMISSIONER_JOINER_FINALIZE = 2, + OT_COMMISSIONER_JOINER_END = 3, + OT_COMMISSIONER_JOINER_REMOVED = 4, +} otCommissionerJoinerEvent; + #define OT_COMMISSIONING_PASSPHRASE_MIN_SIZE 6 ///< Minimum size of the Commissioning Passphrase #define OT_COMMISSIONING_PASSPHRASE_MAX_SIZE 255 ///< Maximum size of the Commissioning Passphrase @@ -108,20 +121,34 @@ typedef struct otCommissioningDataset */ typedef void(OTCALL *otCommissionerStateCallback)(otCommissionerState aState, void *aContext); +/** + * 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. + * + */ +typedef void(OTCALL *otCommissionerJoinerCallback)(otCommissionerJoinerEvent aEvent, + const otExtAddress * aJoinerId, + void * aContext); + /** * This function enables the Thread Commissioner role. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aStateCallback A pointer to a function that is called when the commissioner state changes. + * @param[in] aJoinerCallback A pointer to a function that is called with a joiner event occurs. * @param[in] aCallbackContext A pointer to application-specific context. * * @retval OT_ERROR_NONE Successfully started the Commissioner role. * @retval OT_ERROR_INVALID_STATE Commissioner is already started. * */ -OTAPI otError OTCALL otCommissionerStart(otInstance * aInstance, - otCommissionerStateCallback aStateCallback, - void * aCallbackContext); +OTAPI otError OTCALL otCommissionerStart(otInstance * aInstance, + otCommissionerStateCallback aStateCallback, + otCommissionerJoinerCallback aJoinerCallback, + void * aCallbackContext); /** * This function disables the Thread Commissioner role. diff --git a/include/openthread/instance.h b/include/openthread/instance.h index a910ab35d..71978f868 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -270,18 +270,17 @@ enum OT_CHANGED_THREAD_CHILD_REMOVED = 1 << 11, ///< Child was removed OT_CHANGED_IP6_MULTICAST_SUBSRCRIBED = 1 << 12, ///< Subscribed to a IPv6 multicast address OT_CHANGED_IP6_MULTICAST_UNSUBSRCRIBED = 1 << 13, ///< Unsubscribed from a IPv6 multicast address - OT_CHANGED_JOINER_STATE = 1 << 14, ///< Joiner state changed - OT_CHANGED_THREAD_CHANNEL = 1 << 15, ///< Thread network channel changed - OT_CHANGED_THREAD_PANID = 1 << 16, ///< Thread network PAN Id changed - OT_CHANGED_THREAD_NETWORK_NAME = 1 << 17, ///< Thread network name changed - OT_CHANGED_THREAD_EXT_PANID = 1 << 18, ///< Thread network extended PAN ID changed - OT_CHANGED_MASTER_KEY = 1 << 19, ///< Master key changed - OT_CHANGED_PSKC = 1 << 20, ///< PSKc changed - OT_CHANGED_SECURITY_POLICY = 1 << 21, ///< Security Policy changed - OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL = 1 << 22, ///< Channel Manager new pending Thread channel changed - OT_CHANGED_SUPPORTED_CHANNEL_MASK = 1 << 23, ///< Supported channel mask changed - OT_CHANGED_BORDER_AGENT_STATE = 1 << 24, ///< Border agent state changed - OT_CHANGED_THREAD_NETIF_STATE = 1 << 25, ///< Thread network interface state changed + OT_CHANGED_THREAD_CHANNEL = 1 << 14, ///< Thread network channel changed + OT_CHANGED_THREAD_PANID = 1 << 15, ///< Thread network PAN Id changed + OT_CHANGED_THREAD_NETWORK_NAME = 1 << 16, ///< Thread network name changed + OT_CHANGED_THREAD_EXT_PANID = 1 << 17, ///< Thread network extended PAN ID changed + OT_CHANGED_MASTER_KEY = 1 << 18, ///< Master key changed + OT_CHANGED_PSKC = 1 << 19, ///< PSKc changed + OT_CHANGED_SECURITY_POLICY = 1 << 20, ///< Security Policy changed + OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL = 1 << 21, ///< Channel Manager new pending Thread channel changed + OT_CHANGED_SUPPORTED_CHANNEL_MASK = 1 << 22, ///< Supported channel mask changed + OT_CHANGED_BORDER_AGENT_STATE = 1 << 23, ///< Border agent state changed + OT_CHANGED_THREAD_NETIF_STATE = 1 << 24, ///< Thread network interface state changed }; /** diff --git a/src/cli/cli_commissioner.cpp b/src/cli/cli_commissioner.cpp index 5b971447d..13e294866 100644 --- a/src/cli/cli_commissioner.cpp +++ b/src/cli/cli_commissioner.cpp @@ -317,7 +317,8 @@ otError Commissioner::ProcessStart(int argc, char *argv[]) OT_UNUSED_VARIABLE(argc); OT_UNUSED_VARIABLE(argv); - return otCommissionerStart(mInterpreter.mInstance, &Commissioner::HandleStateChanged, this); + return otCommissionerStart(mInterpreter.mInstance, &Commissioner::HandleStateChanged, + &Commissioner::HandleJoinerEvent, this); } void OTCALL Commissioner::HandleStateChanged(otCommissionerState aState, void *aContext) @@ -343,6 +344,41 @@ void Commissioner::HandleStateChanged(otCommissionerState aState) } } +void OTCALL Commissioner::HandleJoinerEvent(otCommissionerJoinerEvent aEvent, + const otExtAddress * aJoinerId, + void * aContext) +{ + static_cast(aContext)->HandleJoinerEvent(aEvent, aJoinerId); +} + +void Commissioner::HandleJoinerEvent(otCommissionerJoinerEvent aEvent, const otExtAddress *aJoinerId) +{ + mInterpreter.mServer->OutputFormat("Commissioner: Joiner "); + + switch (aEvent) + { + case OT_COMMISSIONER_JOINER_START: + mInterpreter.mServer->OutputFormat("start "); + break; + case OT_COMMISSIONER_JOINER_CONNECTED: + mInterpreter.mServer->OutputFormat("connect "); + break; + case OT_COMMISSIONER_JOINER_FINALIZE: + mInterpreter.mServer->OutputFormat("finalize "); + break; + case OT_COMMISSIONER_JOINER_END: + mInterpreter.mServer->OutputFormat("end "); + break; + case OT_COMMISSIONER_JOINER_REMOVED: + mInterpreter.mServer->OutputFormat("remove "); + break; + } + + mInterpreter.OutputBytes(aJoinerId->m8, sizeof(*aJoinerId)); + + mInterpreter.mServer->OutputFormat("\r\n"); +} + otError Commissioner::ProcessStop(int argc, char *argv[]) { OT_UNUSED_VARIABLE(argc); diff --git a/src/cli/cli_commissioner.hpp b/src/cli/cli_commissioner.hpp index 0656839ca..d0c9d0ceb 100644 --- a/src/cli/cli_commissioner.hpp +++ b/src/cli/cli_commissioner.hpp @@ -99,6 +99,11 @@ private: static void OTCALL HandleStateChanged(otCommissionerState aState, void *aContext); void HandleStateChanged(otCommissionerState aState); + static void OTCALL HandleJoinerEvent(otCommissionerJoinerEvent aJoinerEvent, + const otExtAddress * aJoinerId, + void * aContext); + void HandleJoinerEvent(otCommissionerJoinerEvent aJoinerEvent, const otExtAddress *aJoinerId); + static void OTCALL HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength, diff --git a/src/core/api/commissioner_api.cpp b/src/core/api/commissioner_api.cpp index f549bca17..487fb719f 100644 --- a/src/core/api/commissioner_api.cpp +++ b/src/core/api/commissioner_api.cpp @@ -40,7 +40,10 @@ using namespace ot; -otError otCommissionerStart(otInstance *aInstance, otCommissionerStateCallback aStateCallback, void *aCallbackContext) +otError otCommissionerStart(otInstance * aInstance, + otCommissionerStateCallback aStateCallback, + otCommissionerJoinerCallback aJoinerCallback, + void * aCallbackContext) { otError error = OT_ERROR_DISABLED_FEATURE; @@ -50,11 +53,13 @@ otError otCommissionerStart(otInstance *aInstance, otCommissionerStateCallback a #if OPENTHREAD_ENABLE_BORDER_AGENT SuccessOrExit(error = instance.Get().Stop()); #endif - SuccessOrExit(error = instance.Get().Start(aStateCallback, aCallbackContext)); + SuccessOrExit(error = + instance.Get().Start(aStateCallback, aJoinerCallback, aCallbackContext)); exit: #else OT_UNUSED_VARIABLE(aInstance); OT_UNUSED_VARIABLE(aStateCallback); + OT_UNUSED_VARIABLE(aJoinerCallback); OT_UNUSED_VARIABLE(aCallbackContext); #endif diff --git a/src/core/common/notifier.cpp b/src/core/common/notifier.cpp index caabf5392..87f0975bd 100644 --- a/src/core/common/notifier.cpp +++ b/src/core/common/notifier.cpp @@ -273,10 +273,6 @@ const char *Notifier::FlagToString(otChangedFlags aFlag) const retval = "Ip6Mult-"; break; - case OT_CHANGED_JOINER_STATE: - retval = "JoinerState"; - break; - case OT_CHANGED_THREAD_CHANNEL: retval = "Channel"; break; diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 721a3e5c3..547bb7ab7 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -71,6 +71,7 @@ Commissioner::Commissioner(Instance &aInstance) , mEnergyScan(aInstance) , mPanIdQuery(aInstance) , mStateCallback(NULL) + , mJoinerCallback(NULL) , mCallbackContext(NULL) , mState(OT_COMMISSIONER_STATE_DISABLED) { @@ -99,6 +100,14 @@ exit: return; } +void Commissioner::SignalJoinerEvent(otCommissionerJoinerEvent aEvent, const Mac::ExtAddress &aJoinerId) +{ + if (mJoinerCallback) + { + mJoinerCallback(aEvent, &aJoinerId, mCallbackContext); + } +} + void Commissioner::AddCoapResources(void) { Get().AddResource(mRelayReceive); @@ -113,15 +122,37 @@ void Commissioner::RemoveCoapResources(void) Get().RemoveResource(mJoinerFinalize); } -otError Commissioner::Start(otCommissionerStateCallback aStateCallback, void *aCallbackContext) +void Commissioner::HandleCoapsConnected(bool aConnected, void *aContext) +{ + static_cast(aContext)->HandleCoapsConnected(aConnected); +} + +void Commissioner::HandleCoapsConnected(bool aConnected) +{ + otCommissionerJoinerEvent event; + Mac::ExtAddress joinerId; + + event = aConnected ? OT_COMMISSIONER_JOINER_CONNECTED : OT_COMMISSIONER_JOINER_END; + + memcpy(&joinerId, mJoinerIid, sizeof(joinerId)); + joinerId.m8[0] ^= 0x2; + + SignalJoinerEvent(event, joinerId); +} + +otError Commissioner::Start(otCommissionerStateCallback aStateCallback, + otCommissionerJoinerCallback aJoinerCallback, + void * aCallbackContext) { otError error = OT_ERROR_NONE; VerifyOrExit(mState == OT_COMMISSIONER_STATE_DISABLED, error = OT_ERROR_INVALID_STATE); SuccessOrExit(error = Get().Start(SendRelayTransmit, this)); + Get().SetConnectedCallback(&Commissioner::HandleCoapsConnected, this); mStateCallback = aStateCallback; + mJoinerCallback = aJoinerCallback; mCallbackContext = aCallbackContext; mTransmitAttempts = 0; @@ -276,6 +307,8 @@ otError Commissioner::RemoveJoiner(const Mac::ExtAddress *aEui64, uint32_t aDela for (size_t i = 0; i < OT_ARRAY_LENGTH(mJoiners); i++) { + Mac::ExtAddress joinerId; + if (!mJoiners[i].mValid) { continue; @@ -309,24 +342,24 @@ otError Commissioner::RemoveJoiner(const Mac::ExtAddress *aEui64, uint32_t aDela mJoiners[i].mValid = false; UpdateJoinerExpirationTimer(); SendCommissionerSet(); + + if (aEui64) + { + otLogInfoMeshCoP("Removed Joiner (%s)", aEui64->ToString().AsCString()); + } + else + { + otLogInfoMeshCoP("Removed Joiner (*)"); + } + + ComputeJoinerId(mJoiners[i].mEui64, joinerId); + SignalJoinerEvent(OT_COMMISSIONER_JOINER_REMOVED, joinerId); } ExitNow(error = OT_ERROR_NONE); } exit: - if (error == OT_ERROR_NONE) - { - if (aEui64) - { - otLogInfoMeshCoP("Removed Joiner (%s)", aEui64->ToString().AsCString()); - } - else - { - otLogInfoMeshCoP("Removed Joiner (*)"); - } - } - return error; } @@ -833,7 +866,7 @@ void Commissioner::HandleRelayReceive(Coap::Message &aMessage, const Ip6::Messag memcpy(mJoinerIid, joinerIid.GetIid(), sizeof(mJoinerIid)); mJoinerIid[0] ^= 0x2; - for (size_t i = 0; i < OT_ARRAY_LENGTH(mJoiners); i++) + for (uint8_t i = 0; i < OT_ARRAY_LENGTH(mJoiners); i++) { if (!mJoiners[i].mValid) { @@ -847,8 +880,12 @@ void Commissioner::HandleRelayReceive(Coap::Message &aMessage, const Ip6::Messag error = Get().SetPsk(reinterpret_cast(mJoiners[i].mPsk), static_cast(strlen(mJoiners[i].mPsk))); SuccessOrExit(error); - otLogInfoMeshCoP("found joiner, starting new session"); + mJoinerIndex = i; enableJoiner = true; + + otLogInfoMeshCoP("found joiner, starting new session"); + SignalJoinerEvent(OT_COMMISSIONER_JOINER_START, joinerId); + break; } } @@ -947,7 +984,7 @@ void Commissioner::SendJoinFinalizeResponse(const Coap::Message &aRequest, State Ip6::MessageInfo joinerMessageInfo; MeshCoP::StateTlv stateTlv; Coap::Message * message; - Mac::ExtAddress extAddr; + Mac::ExtAddress joinerId; VerifyOrExit((message = NewMeshCoPMessage(Get())) != NULL, error = OT_ERROR_NO_BUFS); @@ -974,9 +1011,15 @@ void Commissioner::SendJoinFinalizeResponse(const Coap::Message &aRequest, State SuccessOrExit(error = Get().SendMessage(*message, joinerMessageInfo)); - memcpy(extAddr.m8, mJoinerIid, sizeof(extAddr.m8)); - extAddr.SetLocal(!extAddr.IsLocal()); - RemoveJoiner(&extAddr, kRemoveJoinerDelay); // remove after kRemoveJoinerDelay (seconds) + memcpy(&joinerId, mJoinerIid, sizeof(joinerId)); + joinerId.m8[0] ^= 0x2; + SignalJoinerEvent(OT_COMMISSIONER_JOINER_FINALIZE, joinerId); + + if (!mJoiners[mJoinerIndex].mAny) + { + // remove after kRemoveJoinerDelay (seconds) + RemoveJoiner(&mJoiners[mJoinerIndex].mEui64, kRemoveJoinerDelay); + } otLogInfoMeshCoP("sent joiner finalize response"); diff --git a/src/core/meshcop/commissioner.hpp b/src/core/meshcop/commissioner.hpp index 4868a2cc6..9c4097dae 100644 --- a/src/core/meshcop/commissioner.hpp +++ b/src/core/meshcop/commissioner.hpp @@ -69,13 +69,16 @@ public: * This method starts the Commissioner service. * * @param[in] aStateCallback A pointer to a function that is called when the commissioner state changes. + * @param[in] aJoinerCallback A pointer to a function that is called when a joiner event occurs. * @param[in] aCallbackContext A pointer to application-specific context. * * @retval OT_ERROR_NONE Successfully started the Commissioner service. * @retval OT_ERROR_INVALID_STATE Commissioner is already started. * */ - otError Start(otCommissionerStateCallback aStateCallback, void *aCallbackContext); + otError Start(otCommissionerStateCallback aStateCallback, + otCommissionerJoinerCallback aJoinerCallback, + void * aCallbackContext); /** * This method stops the Commissioner service. @@ -288,6 +291,9 @@ private: otError aResult); void HandleLeaderKeepAliveResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, otError aResult); + static void HandleCoapsConnected(bool aConnected, void *aContext); + void HandleCoapsConnected(bool aConnected); + static void HandleRelayReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo); void HandleRelayReceive(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); @@ -307,6 +313,7 @@ private: otError SendKeepAlive(void); void SetState(otCommissionerState aState); + void SignalJoinerEvent(otCommissionerJoinerEvent aEvent, const Mac::ExtAddress &aJoinerId); struct Joiner { @@ -321,6 +328,7 @@ private: uint8_t mJoinerIid[8]; uint16_t mJoinerPort; uint16_t mJoinerRloc; + uint8_t mJoinerIndex; TimerMilli mJoinerExpirationTimer; TimerMilli mTimer; @@ -339,8 +347,9 @@ private: ProvisioningUrlTlv mProvisioningUrl; - otCommissionerStateCallback mStateCallback; - void * mCallbackContext; + otCommissionerStateCallback mStateCallback; + otCommissionerJoinerCallback mJoinerCallback; + void * mCallbackContext; otCommissionerState mState; }; diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index 99284472b..e3959b27f 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -83,7 +83,6 @@ void Joiner::SetState(otJoinerState aState) otLogInfoMeshCoP("JoinerState: %s -> %s", JoinerStateToString(mState), JoinerStateToString(aState)); mState = aState; - Get().Signal(OT_CHANGED_JOINER_STATE); exit: return; diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 90d67c690..1963d54dc 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -476,7 +476,7 @@ template <> otError NcpBase::HandlePropertySet