From 64d49153bdc63bbe03dcbe73e5dd87f80ddbbada Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Tue, 27 Dec 2016 08:06:18 -0800 Subject: [PATCH] Add callback to indicate when joiner operation completes. (#1094) --- examples/apps/cli/Makefile.am | 3 +- examples/drivers/windows/otApi/otApi.cpp | 4 +- examples/drivers/windows/otLwf/iocontrol.c | 10 +- .../drivers/windows/otNodeApi/otNodeApi.cpp | 3 +- include/commissioning/joiner.h | 17 ++- src/cli/cli.cpp | 21 +++- src/cli/cli.hpp | 2 + src/core/coap/secure_coap_client.cpp | 23 ++-- src/core/coap/secure_coap_client.hpp | 8 +- src/core/coap/secure_coap_server.cpp | 12 ++- src/core/coap/secure_coap_server.hpp | 3 + src/core/meshcop/commissioner.cpp | 2 +- src/core/meshcop/commissioner.hpp | 2 +- src/core/meshcop/dtls.cpp | 31 ++++-- src/core/meshcop/dtls.hpp | 24 +++-- src/core/meshcop/joiner.cpp | 101 ++++++++++++++++-- src/core/meshcop/joiner.hpp | 24 ++++- src/core/openthread.cpp | 5 +- 18 files changed, 247 insertions(+), 48 deletions(-) diff --git a/examples/apps/cli/Makefile.am b/examples/apps/cli/Makefile.am index bf75f08ed..99b941d5d 100644 --- a/examples/apps/cli/Makefile.am +++ b/examples/apps/cli/Makefile.am @@ -40,7 +40,6 @@ CPPFLAGS_COMMON = \ $(NULL) LDADD_COMMON = \ - $(top_builddir)/src/cli/libopenthread-cli.a \ $(NULL) LDFLAGS_COMMON = \ @@ -84,6 +83,7 @@ ot_cli_ftd_CPPFLAGS = \ $(NULL) ot_cli_ftd_LDADD = \ + $(top_builddir)/src/cli/libopenthread-cli.a \ $(top_builddir)/src/core/libopenthread-ftd.a \ $(LDADD_COMMON) \ $(NULL) @@ -101,6 +101,7 @@ ot_cli_mtd_CPPFLAGS = \ $(NULL) ot_cli_mtd_LDADD = \ + $(top_builddir)/src/cli/libopenthread-cli.a \ $(top_builddir)/src/core/libopenthread-mtd.a \ $(LDADD_COMMON) \ $(NULL) diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp index 4fa9863db..8451c0522 100644 --- a/examples/drivers/windows/otApi/otApi.cpp +++ b/examples/drivers/windows/otApi/otApi.cpp @@ -3490,7 +3490,9 @@ OTCALL otJoinerStart( _In_ otInstance *aInstance, const char *aPSKd, - const char *aProvisioningUrl + const char *aProvisioningUrl, + _In_ otJoinerCallback aCallback, + _In_ void *aCallbackContext ) { if (aInstance == nullptr || aPSKd == nullptr) return kThreadError_InvalidArgs; diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c index 260280e75..d4d6ae185 100644 --- a/examples/drivers/windows/otLwf/iocontrol.c +++ b/examples/drivers/windows/otLwf/iocontrol.c @@ -5270,8 +5270,14 @@ otLwfIoCtl_otJoinerStart( if (InBufferLength >= sizeof(otCommissionConfig)) { otCommissionConfig *aConfig = (otCommissionConfig*)InBuffer; - status = ThreadErrorToNtstatus(otJoinerStart( - pFilter->otCtx, (const char*)aConfig->PSKd, (const char*)aConfig->ProvisioningUrl)); + status = ThreadErrorToNtstatus( + otJoinerStart( + pFilter->otCtx, + (const char*)aConfig->PSKd, + (const char*)aConfig->ProvisioningUrl, + NULL, // TODO: handle the joiner completion callback + NULL) + ); } return status; diff --git a/examples/drivers/windows/otNodeApi/otNodeApi.cpp b/examples/drivers/windows/otNodeApi/otNodeApi.cpp index 74a29b4de..67a987a1a 100644 --- a/examples/drivers/windows/otNodeApi/otNodeApi.cpp +++ b/examples/drivers/windows/otNodeApi/otNodeApi.cpp @@ -949,7 +949,8 @@ OTNODEAPI int32_t OTCALL otNodeJoinerStart(otNode* aNode, const char *aPSKd, con otLogFuncEntryMsg("[%d] %s %s", aNode->mId, aPSKd, aProvisioningUrl); printf("%d: joiner start %s %s\r\n", aNode->mId, aPSKd, aProvisioningUrl); - auto error = otJoinerStart(aNode->mInstance, aPSKd, aProvisioningUrl); + // TODO: handle the joiner completion callback + auto error = otJoinerStart(aNode->mInstance, aPSKd, aProvisioningUrl, NULL, NULL); otLogFuncExit(); return error; diff --git a/include/commissioning/joiner.h b/include/commissioning/joiner.h index 011797978..7a4c4ab9b 100644 --- a/include/commissioning/joiner.h +++ b/include/commissioning/joiner.h @@ -48,18 +48,33 @@ extern "C" { * */ +/** + * This function pointer is called to notify the completion of a join operation. + * + * @param[in] aError kThreadError_None if the join process succeeded. + * kThreadError_Security if the join process failed due to security credentials. + * kThreadError_NotFound if no joinable network was discovered. + * kThreadError_ResponseTimeout if a response timed out. + * @param[in] aContext A pointer to application-specific context. + * + */ +typedef void (OTCALL *otJoinerCallback)(ThreadError aError, void *aContext); + /** * This function enables the Thread Joiner role. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aPSKd A pointer to the PSKd. * @param[in] aProvisioningUrl A pointer to the Provisioning URL (may be NULL). + * @param[in] aCallback A pointer to a function that is called when the join operation completes. + * @param[in] aContext A pointer to application-specific context. * * @retval kThreadError_None Successfully started the Commissioner role. * @retval kThreadError_InvalidArgs @p aPSKd or @p aProvisioningUrl is invalid. * */ -OTAPI ThreadError OTCALL otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl); +OTAPI ThreadError OTCALL otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl, + otJoinerCallback aCallback, void *aContext); /** * This function disables the Thread Joiner role. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 76105f45a..c7c031824 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -2438,7 +2438,7 @@ void Interpreter::ProcessJoiner(int argc, char *argv[]) const char *provisioningUrl; VerifyOrExit(argc > 1, error = kThreadError_Parse); provisioningUrl = (argc > 2) ? argv[2] : NULL; - otJoinerStart(mInstance, argv[1], provisioningUrl); + otJoinerStart(mInstance, argv[1], provisioningUrl, &Interpreter::s_HandleJoinerCallback, this); } else if (strcmp(argv[0], "stop") == 0) { @@ -2451,6 +2451,25 @@ exit: #endif // OPENTHREAD_ENABLE_JOINER +void Interpreter::s_HandleJoinerCallback(ThreadError aError, void *aContext) +{ + static_cast(aContext)->HandleJoinerCallback(aError); +} + +void Interpreter::HandleJoinerCallback(ThreadError aError) +{ + switch (aError) + { + case kThreadError_None: + sServer->OutputFormat("Join success\r\n"); + break; + + default: + sServer->OutputFormat("Join failed [%s]\r\n", otThreadErrorToString(aError)); + break; + } +} + void Interpreter::ProcessJoinerPort(int argc, char *argv[]) { ThreadError error = kThreadError_None; diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 82460889e..00eed6ef2 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -225,6 +225,7 @@ private: void *aContext); static void s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext); static void s_HandleDiagnosticGetResponse(otMessage aMessage, const otMessageInfo *aMessageInfo, void *aContext); + static void s_HandleJoinerCallback(ThreadError aError, void *aContext); void HandleEchoResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void HandlePingTimer(); @@ -234,6 +235,7 @@ private: void HandleEnergyReport(uint32_t aChannelMask, const uint8_t *aEnergyList, uint8_t aEnergyListLength); void HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask); void HandleDiagnosticGetResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + void HandleJoinerCallback(ThreadError aError); static const struct Command sCommands[]; diff --git a/src/core/coap/secure_coap_client.cpp b/src/core/coap/secure_coap_client.cpp index 107a4f336..53e9d1d89 100644 --- a/src/core/coap/secure_coap_client.cpp +++ b/src/core/coap/secure_coap_client.cpp @@ -73,7 +73,8 @@ ThreadError SecureClient::Connect(const Ip6::MessageInfo &aMessageInfo, Connecte mConnectedCallback = aCallback; mContext = aContext; - return mNetif.GetDtls().Start(true, &SecureClient::HandleDtlsReceive, &SecureClient::HandleDtlsSend, this); + return mNetif.GetDtls().Start(true, &SecureClient::HandleDtlsConnected, &SecureClient::HandleDtlsReceive, + &SecureClient::HandleDtlsSend, this); } bool SecureClient::IsConnectionActive(void) @@ -136,17 +137,23 @@ void SecureClient::Receive(Message &aMessage, const Ip6::MessageInfo &aMessageIn mNetif.GetDtls().Receive(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset()); - if ((IsConnected()) && (mConnectedCallback != NULL)) - { - mConnectedCallback(mContext); - mConnectedCallback = NULL; - mContext = NULL; - } - exit: otLogFuncExit(); } +void SecureClient::HandleDtlsConnected(void *aContext, bool aConnected) +{ + return static_cast(aContext)->HandleDtlsConnected(aConnected); +} + +void SecureClient::HandleDtlsConnected(bool aConnected) +{ + if (mConnectedCallback != NULL) + { + mConnectedCallback(aConnected, mContext); + } +} + void SecureClient::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength) { return static_cast(aContext)->HandleDtlsReceive(aBuf, aLength); diff --git a/src/core/coap/secure_coap_client.hpp b/src/core/coap/secure_coap_client.hpp index a7a34ea10..a513339c2 100644 --- a/src/core/coap/secure_coap_client.hpp +++ b/src/core/coap/secure_coap_client.hpp @@ -49,10 +49,11 @@ public: /** * This function pointer is called once DTLS connection is established. * - * @param[in] aContext A pointer to arbitrary context information. + * @param[in] aConnected TRUE if a connection was established, FALSE otherwise. + * @param[in] aContext A pointer to arbitrary context information. * */ - typedef void (*ConnectedCallback)(void *aContext); + typedef void (*ConnectedCallback)(bool aConnected, void *aContext); /** * This constructor initializes the object. @@ -140,6 +141,9 @@ private: static void Receive(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void Receive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + static void HandleDtlsConnected(void *aContext, bool aConnected); + void HandleDtlsConnected(bool aConnected); + static void HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength); void HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength); diff --git a/src/core/coap/secure_coap_server.cpp b/src/core/coap/secure_coap_server.cpp index 12060bd7e..f15ac6cd8 100644 --- a/src/core/coap/secure_coap_server.cpp +++ b/src/core/coap/secure_coap_server.cpp @@ -118,7 +118,7 @@ void SecureServer::Receive(Message &aMessage, const Ip6::MessageInfo &aMessageIn mPeerAddress.SetPeerAddr(aMessageInfo.GetPeerAddr()); mPeerAddress.SetPeerPort(aMessageInfo.GetPeerPort()); - mNetif.GetDtls().Start(false, HandleDtlsReceive, HandleDtlsSend, this); + mNetif.GetDtls().Start(false, HandleDtlsConnected, HandleDtlsReceive, HandleDtlsSend, this); } else { @@ -140,6 +140,16 @@ ThreadError SecureServer::SetPsk(const uint8_t *aPsk, uint8_t aPskLength) return mNetif.GetDtls().SetPsk(aPsk, aPskLength); } +void SecureServer::HandleDtlsConnected(void *aContext, bool aConnected) +{ + return static_cast(aContext)->HandleDtlsConnected(aConnected); +} + +void SecureServer::HandleDtlsConnected(bool aConnected) +{ + (void)aConnected; +} + void SecureServer::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength) { return static_cast(aContext)->HandleDtlsReceive(aBuf, aLength); diff --git a/src/core/coap/secure_coap_server.hpp b/src/core/coap/secure_coap_server.hpp index 1544d3d7a..c6edf3ea3 100644 --- a/src/core/coap/secure_coap_server.hpp +++ b/src/core/coap/secure_coap_server.hpp @@ -120,6 +120,9 @@ private: static void Receive(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + static void HandleDtlsConnected(void *aContext, bool aConnected); + void HandleDtlsConnected(bool aConnected); + static void HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength); void HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength); diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 68cf79fe4..4ef7a7d9e 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -66,8 +66,8 @@ Commissioner::Commissioner(ThreadNetif &aThreadNetif): mState(kStateDisabled), mJoinerPort(0), mJoinerRloc(0), - mSessionId(0), mTimer(aThreadNetif.GetIp6().mTimerScheduler, HandleTimer, this), + mSessionId(0), mTransmitAttempts(0), mSendKek(false), mRelayReceive(OPENTHREAD_URI_RELAY_RX, &Commissioner::HandleRelayReceive, this), diff --git a/src/core/meshcop/commissioner.hpp b/src/core/meshcop/commissioner.hpp index e1589a279..490660fea 100644 --- a/src/core/meshcop/commissioner.hpp +++ b/src/core/meshcop/commissioner.hpp @@ -248,8 +248,8 @@ private: uint16_t mJoinerPort; uint16_t mJoinerRloc; - uint16_t mSessionId; Timer mTimer; + uint16_t mSessionId; uint8_t mTransmitAttempts; bool mSendKek; diff --git a/src/core/meshcop/dtls.cpp b/src/core/meshcop/dtls.cpp index e3bed88cf..047cf83da 100644 --- a/src/core/meshcop/dtls.cpp +++ b/src/core/meshcop/dtls.cpp @@ -56,6 +56,7 @@ Dtls::Dtls(ThreadNetif &aNetif): mReceiveMessage(NULL), mReceiveOffset(0), mReceiveLength(0), + mConnectedHandler(NULL), mReceiveHandler(NULL), mSendHandler(NULL), mContext(NULL), @@ -71,11 +72,13 @@ Dtls::Dtls(ThreadNetif &aNetif): mProvisioningUrl.Init(); } -ThreadError Dtls::Start(bool aClient, ReceiveHandler aReceiveHandler, SendHandler aSendHandler, void *aContext) +ThreadError Dtls::Start(bool aClient, ConnectedHandler aConnectedHandler, ReceiveHandler aReceiveHandler, + SendHandler aSendHandler, void *aContext) { static const int ciphersuites[2] = {0xC0FF, 0}; // EC-JPAKE cipher suite int rval; + mConnectedHandler = aConnectedHandler; mReceiveHandler = aReceiveHandler; mSendHandler = aSendHandler; mContext = aContext; @@ -142,15 +145,22 @@ ThreadError Dtls::Stop(void) void Dtls::Close(void) { - if (mStarted) + VerifyOrExit(mStarted,); + + mStarted = false; + mbedtls_ssl_free(&mSsl); + mbedtls_ssl_config_free(&mConf); + mbedtls_ctr_drbg_free(&mCtrDrbg); + mbedtls_entropy_free(&mEntropy); + mbedtls_ssl_cookie_free(&mCookieCtx); + + if (mConnectedHandler != NULL) { - mStarted = false; - mbedtls_ssl_free(&mSsl); - mbedtls_ssl_config_free(&mConf); - mbedtls_ctr_drbg_free(&mCtrDrbg); - mbedtls_entropy_free(&mEntropy); - mbedtls_ssl_cookie_free(&mCookieCtx); + mConnectedHandler(mContext, false); } + +exit: + return; } bool Dtls::IsStarted(void) @@ -367,6 +377,11 @@ void Dtls::Process(void) if (mSsl.state != MBEDTLS_SSL_HANDSHAKE_OVER) { rval = mbedtls_ssl_handshake(&mSsl); + + if ((mSsl.state == MBEDTLS_SSL_HANDSHAKE_OVER) && (mConnectedHandler != NULL)) + { + mConnectedHandler(mContext, true); + } } else { diff --git a/src/core/meshcop/dtls.hpp b/src/core/meshcop/dtls.hpp index ae8457401..c86923cc5 100644 --- a/src/core/meshcop/dtls.hpp +++ b/src/core/meshcop/dtls.hpp @@ -70,6 +70,15 @@ public: */ Dtls(ThreadNetif &aNetif); + /** + * This function pointer is called when a connection is established or torn down. + * + * @param[in] aContext A pointer to application-specific context. + * @param[in] aConnected TRUE if a connection was established, FALSE otherwise. + * + */ + typedef void (*ConnectedHandler)(void *aContext, bool aConnected); + /** * This function pointer is called when data is received from the DTLS session. * @@ -93,15 +102,17 @@ public: /** * This method starts the DTLS service. * - * @param[in] aClient TRUE if operating as a client, FALSE if operating as a server. - * @param[in] aReceiveHandler A pointer to the receive handler. - * @param[in] aSendHandler A pointer to the send handler. - * @param[in] aContext A pointer to application-specific context. + * @param[in] aClient TRUE if operating as a client, FALSE if operating as a server. + * @param[in] aConnectedHandler A pointer to the connected handler. + * @param[in] aReceiveHandler A pointer to the receive handler. + * @param[in] aSendHandler A pointer to the send handler. + * @param[in] aContext A pointer to application-specific context. * - * @retval kThreadError_None Successfully started the DTLS service. + * @retval kThreadError_None Successfully started the DTLS service. * */ - ThreadError Start(bool aClient, ReceiveHandler aReceiveHandler, SendHandler aSendHandler, void *aContext); + ThreadError Start(bool aClient, ConnectedHandler aConnectedHandler, ReceiveHandler aReceiveHandler, + SendHandler aSendHandler, void *aContext); /** * This method stops the DTLS service. @@ -227,6 +238,7 @@ private: uint16_t mReceiveOffset; uint16_t mReceiveLength; + ConnectedHandler mConnectedHandler; ReceiveHandler mReceiveHandler; SendHandler mSendHandler; void *mContext; diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index 0e384d22a..762bae458 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -59,6 +60,9 @@ namespace Thread { namespace MeshCoP { Joiner::Joiner(ThreadNetif &aNetif): + mState(kStateIdle), + mCallback(NULL), + mContext(NULL), mJoinerRouterChannel(0), mJoinerRouterPanId(0), mJoinerUdpPort(0), @@ -71,13 +75,15 @@ Joiner::Joiner(ThreadNetif &aNetif): mCoapServer.AddResource(mJoinerEntrust); } -ThreadError Joiner::Start(const char *aPSKd, const char *aProvisioningUrl) +ThreadError Joiner::Start(const char *aPSKd, const char *aProvisioningUrl, otJoinerCallback aCallback, void *aContext) { ThreadError error; Mac::ExtAddress extAddress; otLogFuncEntry(); + VerifyOrExit(mState == kStateIdle, error = kThreadError_Busy); + // use extended address based on factory-assigned IEEE EUI-64 mNetif.GetMac().GetHashMacAddress(&extAddress); mNetif.GetMac().SetExtAddress(extAddress); @@ -90,6 +96,10 @@ ThreadError Joiner::Start(const char *aPSKd, const char *aProvisioningUrl) mJoinerRouterPanId = Mac::kPanIdBroadcast; SuccessOrExit(error = mNetif.GetMle().Discover(0, 0, mNetif.GetMac().GetPanId(), HandleDiscoverResult, this)); + mCallback = aCallback; + mContext = aContext; + mState = kStateDiscover; + exit: otLogFuncExitErr(error); return error; @@ -115,6 +125,18 @@ void Joiner::Close(void) otLogFuncExit(); } +void Joiner::Complete(ThreadError aError) +{ + mState = kStateIdle; + + if (mCallback) + { + otJoinerCallback callback = mCallback; + mCallback = NULL; + callback(aError, mContext); + } +} + void Joiner::HandleDiscoverResult(otActiveScanResult *aResult, void *aContext) { static_cast(aContext)->HandleDiscoverResult(aResult); @@ -173,14 +195,43 @@ void Joiner::HandleDiscoverResult(otActiveScanResult *aResult) messageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD; mSecureCoapClient.Connect(messageInfo, Joiner::HandleSecureCoapClientConnect, this); + mState = kStateConnect; + } + else + { + otLogDebgMeshCoP("No joinable network found"); + Complete(kThreadError_NotFound); } otLogFuncExit(); } -void Joiner::HandleSecureCoapClientConnect(void *aContext) +void Joiner::HandleSecureCoapClientConnect(bool aConnected, void *aContext) { - static_cast(aContext)->SendJoinerFinalize(); + static_cast(aContext)->HandleSecureCoapClientConnect(aConnected); +} + +void Joiner::HandleSecureCoapClientConnect(bool aConnected) +{ + switch (mState) + { + case kStateConnect: + if (aConnected) + { + mState = kStateConnected; + SendJoinerFinalize(); + mTimer.Start(kTimeout); + } + else + { + Complete(kThreadError_Security); + } + + break; + + default: + break; + } } void Joiner::SendJoinerFinalize(void) @@ -247,13 +298,17 @@ void Joiner::HandleJoinerFinalizeResponse(Coap::Header *aHeader, Message *aMessa otLogFuncEntry(); - VerifyOrExit(aResult == kThreadError_None && + VerifyOrExit(mState == kStateConnected && + aResult == kThreadError_None && aHeader->GetType() == kCoapTypeAcknowledgment && aHeader->GetCode() == kCoapResponseChanged, ;); SuccessOrExit(Tlv::GetTlv(*aMessage, Tlv::kState, sizeof(state), state)); VerifyOrExit(state.IsValid(), ;); + mState = kStateEntrust; + mTimer.Start(kTimeout); + otLogInfoMeshCoP("received joiner finalize response %d", static_cast(state.GetState())); otLogCertMeshCoP("[THCI] direction=recv | type=JOIN_FIN.rsp"); @@ -282,7 +337,8 @@ void Joiner::HandleJoinerEntrust(Coap::Header &aHeader, Message &aMessage, const otLogFuncEntry(); - VerifyOrExit(aHeader.GetType() == kCoapTypeConfirmable && + VerifyOrExit(mState == kStateEntrust && + aHeader.GetType() == kCoapTypeConfirmable && aHeader.GetCode() == kCoapRequestPost, error = kThreadError_Drop); otLogInfoMeshCoP("Received joiner entrust"); @@ -340,6 +396,8 @@ void Joiner::SendJoinerEntrustResponse(const Coap::Header &aRequestHeader, memset(&responseInfo.mSockAddr, 0, sizeof(responseInfo.mSockAddr)); SuccessOrExit(error = mCoapServer.SendMessage(*message, responseInfo)); + mState = kStateJoined; + otLogInfoArp("Sent Joiner Entrust response"); exit: @@ -359,15 +417,38 @@ void Joiner::HandleTimer(void *aContext) void Joiner::HandleTimer(void) { - Mac::ExtAddress extAddress; + ThreadError error = kThreadError_Error; - for (size_t i = 0; i < sizeof(extAddress); i++) + switch (mState) { - extAddress.m8[i] = static_cast(otPlatRandomGet()); + case kStateIdle: + case kStateDiscover: + case kStateConnect: + assert(false); + break; + + case kStateConnected: + case kStateEntrust: + error = kThreadError_ResponseTimeout; + break; + + case kStateJoined: + Mac::ExtAddress extAddress; + + for (size_t i = 0; i < sizeof(extAddress); i++) + { + extAddress.m8[i] = static_cast(otPlatRandomGet()); + } + + mNetif.GetMac().SetExtAddress(extAddress); + mNetif.GetMle().UpdateLinkLocalAddress(); + + error = kThreadError_None; + break; + } - mNetif.GetMac().SetExtAddress(extAddress); - mNetif.GetMle().UpdateLinkLocalAddress(); + Complete(error); } } // namespace MeshCoP diff --git a/src/core/meshcop/joiner.hpp b/src/core/meshcop/joiner.hpp index 642e6a906..cdc0a70c8 100644 --- a/src/core/meshcop/joiner.hpp +++ b/src/core/meshcop/joiner.hpp @@ -35,6 +35,7 @@ #define JOINER_HPP_ #include +#include #include #include @@ -66,11 +67,13 @@ public: * * @param[in] aPSKd A pointer to the PSKd. * @param[in] aProvisioningUrl A pointer to the Provisioning URL (may be NULL). + * @param[in] aCallback A pointer to a function that is called when the join operation completes. + * @param[in] aContext A pointer to application-specific context. * * @retval kThreadError_None Successfully started the Joiner service. * */ - ThreadError Start(const char *aPSKd, const char *aProvisioningUrl); + ThreadError Start(const char *aPSKd, const char *aProvisioningUrl, otJoinerCallback aCallback, void *aContext); /** * This method stops the Joiner service. @@ -84,6 +87,7 @@ private: enum { kConfigExtAddressDelay = 100, ///< milliseconds + kTimeout = 4000, ///< milliseconds }; static void HandleDiscoverResult(otActiveScanResult *aResult, void *aContext); @@ -93,8 +97,10 @@ private: void HandleTimer(void); void Close(void); + void Complete(ThreadError aError); - static void HandleSecureCoapClientConnect(void *aContext); + static void HandleSecureCoapClientConnect(bool aConnected, void *aContext); + void HandleSecureCoapClientConnect(bool aConnected); void SendJoinerFinalize(void); static void HandleJoinerFinalizeResponse(void *aContext, otCoapHeader *aHeader, otMessage aMessage, @@ -107,6 +113,20 @@ private: void HandleJoinerEntrust(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); void SendJoinerEntrustResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestInfo); + enum State + { + kStateIdle = 0, + kStateDiscover = 1, + kStateConnect = 2, + kStateConnected = 3, + kStateEntrust = 4, + kStateJoined = 5, + }; + State mState; + + otJoinerCallback mCallback; + void *mContext; + uint8_t mJoinerRouterChannel; uint16_t mJoinerRouterPanId; uint16_t mJoinerUdpPort; diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index dc97c6cbc..f25728331 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -1690,9 +1690,10 @@ uint16_t otCommissionerGetSessionId(otInstance *aInstance) #endif // OPENTHREAD_ENABLE_COMMISSIONER #if OPENTHREAD_ENABLE_JOINER -ThreadError otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl) +ThreadError otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl, + otJoinerCallback aCallback, void *aContext) { - return aInstance->mThreadNetif.GetJoiner().Start(aPSKd, aProvisioningUrl); + return aInstance->mThreadNetif.GetJoiner().Start(aPSKd, aProvisioningUrl, aCallback, aContext); } ThreadError otJoinerStop(otInstance *aInstance)