diff --git a/examples/drivers/windows/include/otLwfIoctl.h b/examples/drivers/windows/include/otLwfIoctl.h index 30bb888fe..3a51dbe35 100644 --- a/examples/drivers/windows/include/otLwfIoctl.h +++ b/examples/drivers/windows/include/otLwfIoctl.h @@ -602,6 +602,7 @@ typedef struct otCommissionConfig // uint8_t - aExtAddressValid // otExtAddress - aExtAddress (optional) // char[OPENTHREAD_PSK_MAX_LENGTH + 1] - aPSKd + // uint32_t - aTimeout #define IOCTL_OTLWF_OT_COMMISIONER_REMOVE_JOINER \ OTLWF_CTL_CODE(181, METHOD_BUFFERED, FILE_WRITE_DATA) diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp index 4cfbff67b..942d2fc90 100644 --- a/examples/drivers/windows/otApi/otApi.cpp +++ b/examples/drivers/windows/otApi/otApi.cpp @@ -3513,7 +3513,8 @@ OTCALL otCommissionerAddJoiner( _In_ otInstance *aInstance, const otExtAddress *aExtAddress, - const char *aPSKd + const char *aPSKd, + uint32_t aTimeout ) { if (aInstance == nullptr || aPSKd == nullptr) return kThreadError_InvalidArgs; @@ -3526,13 +3527,14 @@ otCommissionerAddJoiner( uint8_t aExtAddressValid = aExtAddress ? 1 : 0; - const ULONG BufferLength = sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress) + (ULONG)aPSKdLength + 1; - BYTE Buffer[sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress) + OPENTHREAD_PSK_MAX_LENGTH + 1] = {0}; + const ULONG BufferLength = sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress) + (ULONG)aPSKdLength + 1 + sizeof(aTimeout); + BYTE Buffer[sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress) + OPENTHREAD_PSK_MAX_LENGTH + 1 + sizeof(aTimeout)] = {0}; memcpy_s(Buffer, sizeof(Buffer), &aInstance->InterfaceGuid, sizeof(GUID)); memcpy_s(Buffer + sizeof(GUID), sizeof(Buffer) - sizeof(GUID), &aExtAddressValid, sizeof(aExtAddressValid)); if (aExtAddressValid) memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t), sizeof(Buffer) - sizeof(GUID) - sizeof(uint8_t), aExtAddress, sizeof(otExtAddress)); memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress), sizeof(Buffer) - sizeof(GUID) - sizeof(uint8_t) - sizeof(otExtAddress), aPSKd, aPSKdLength); + memcpy_s(Buffer + sizeof(GUID) + sizeof(uint8_t) + sizeof(otExtAddress) + aPSKdLength + 1, sizeof(Buffer) - sizeof(GUID) - sizeof(uint8_t) - sizeof(otExtAddress) - aPSKdLength - 1, &aTimeout, sizeof(aTimeout)); return DwordToThreadError(SendIOCTL(aInstance->ApiHandle, IOCTL_OTLWF_OT_COMMISIONER_ADD_JOINER, Buffer, BufferLength, nullptr, 0)); } diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c index d00fa0443..5aea5f664 100644 --- a/examples/drivers/windows/otLwf/iocontrol.c +++ b/examples/drivers/windows/otLwf/iocontrol.c @@ -5596,19 +5596,20 @@ otLwfIoCtl_otCommissionerAddJoiner( if (InBufferLength >= sizeof(uint8_t) + sizeof(otExtAddress)) { - const ULONG aPSKdBufferLength = InBufferLength - sizeof(uint8_t) - sizeof(otExtAddress); + const ULONG aPSKdBufferLength = InBufferLength - sizeof(uint8_t) - sizeof(otExtAddress) - sizeof(uint32_t); if (aPSKdBufferLength <= OPENTHREAD_PSK_MAX_LENGTH + 1) { uint8_t aExtAddressValid = *(uint8_t*)InBuffer; const otExtAddress *aExtAddress = aExtAddressValid == 0 ? NULL : (otExtAddress*)(InBuffer + sizeof(uint8_t)); char *aPSKd = (char*)(InBuffer + sizeof(uint8_t) + sizeof(otExtAddress)); + uint32_t aTimeout = *(uint32_t*)(InBuffer + sizeof(uint8_t) + sizeof(otExtAddress) + aPSKdBufferLength); // Ensure aPSKd is NULL terminated in the buffer if (strnlen(aPSKd, aPSKdBufferLength) < aPSKdBufferLength) { status = ThreadErrorToNtstatus(otCommissionerAddJoiner( - pFilter->otCtx, aExtAddress, aPSKd)); + pFilter->otCtx, aExtAddress, aPSKd, aTimeout)); } } } diff --git a/examples/drivers/windows/otNodeApi/otNodeApi.cpp b/examples/drivers/windows/otNodeApi/otNodeApi.cpp index 86cb96fe8..1fed85d57 100644 --- a/examples/drivers/windows/otNodeApi/otNodeApi.cpp +++ b/examples/drivers/windows/otNodeApi/otNodeApi.cpp @@ -1010,11 +1010,13 @@ OTNODEAPI int32_t OTCALL otNodeCommissionerJoinerAdd(otNode* aNode, const char * otLogFuncEntryMsg("[%d] %s %s", aNode->mId, aExtAddr, aPSKd); printf("%d: commissioner joiner add %s %s\r\n", aNode->mId, aExtAddr, aPSKd); + const uint32_t kDefaultJoinerTimeout = 120; + ThreadError error; if (strcmp(aExtAddr, "*") == 0) { - error = otCommissionerAddJoiner(aNode->mInstance, nullptr, aPSKd); + error = otCommissionerAddJoiner(aNode->mInstance, nullptr, aPSKd, kDefaultJoinerTimeout); } else { @@ -1022,7 +1024,7 @@ OTNODEAPI int32_t OTCALL otNodeCommissionerJoinerAdd(otNode* aNode, const char * if (Hex2Bin(aExtAddr, extAddr.m8, sizeof(extAddr)) != sizeof(extAddr)) return kThreadError_Parse; - error = otCommissionerAddJoiner(aNode->mInstance, &extAddr, aPSKd); + error = otCommissionerAddJoiner(aNode->mInstance, &extAddr, aPSKd, kDefaultJoinerTimeout); } otLogFuncExit(); diff --git a/include/openthread/commissioner.h b/include/openthread/commissioner.h index 5524ac6a2..d671e6c4a 100644 --- a/include/openthread/commissioner.h +++ b/include/openthread/commissioner.h @@ -75,6 +75,7 @@ OTAPI ThreadError OTCALL otCommissionerStop(otInstance *aInstance); * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aExtAddress A pointer to the Joiner's extended address or NULL 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. * * @retval kThreadError_None Successfully added the Joiner. * @retval kThreadError_NoBufs No buffers available to add the Joiner. @@ -82,7 +83,7 @@ OTAPI ThreadError OTCALL otCommissionerStop(otInstance *aInstance); * */ OTAPI ThreadError OTCALL otCommissionerAddJoiner(otInstance *aInstance, const otExtAddress *aExtAddress, - const char *aPSKd); + const char *aPSKd, uint32_t aTimeout); /** * This function removes a Joiner entry. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 122e57d8b..b0512d52f 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -2327,7 +2327,15 @@ void Interpreter::ProcessCommissioner(int argc, char *argv[]) if (strcmp(argv[1], "add") == 0) { VerifyOrExit(argc > 3, error = kThreadError_Parse); - SuccessOrExit(error = otCommissionerAddJoiner(mInstance, addrPtr, argv[3])); + // Timeout parameter is optional - if not specified, use default value. + unsigned long timeout = kDefaultJoinerTimeout; + + if (argc > 4) + { + SuccessOrExit(error = ParseUnsignedLong(argv[4], timeout)); + } + + SuccessOrExit(error = otCommissionerAddJoiner(mInstance, addrPtr, argv[3], static_cast(timeout))); } else if (strcmp(argv[1], "remove") == 0) { diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index cf3864944..36cbafd53 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -147,6 +147,7 @@ private: { kMaxArgs = 32, kMaxAutoAddresses = 8, + kDefaultJoinerTimeout = 120, ///< Default timeout for Joiners, in seconds. }; void AppendResult(ThreadError error); diff --git a/src/core/api/commissioner_api.cpp b/src/core/api/commissioner_api.cpp index 23294a446..06e2e14e8 100644 --- a/src/core/api/commissioner_api.cpp +++ b/src/core/api/commissioner_api.cpp @@ -53,9 +53,11 @@ ThreadError otCommissionerStop(otInstance *aInstance) return aInstance->mThreadNetif.GetCommissioner().Stop(); } -ThreadError otCommissionerAddJoiner(otInstance *aInstance, const otExtAddress *aExtAddress, const char *aPSKd) +ThreadError otCommissionerAddJoiner(otInstance *aInstance, const otExtAddress *aExtAddress, const char *aPSKd, + uint32_t aTimeout) { - return aInstance->mThreadNetif.GetCommissioner().AddJoiner(static_cast(aExtAddress), aPSKd); + return aInstance->mThreadNetif.GetCommissioner().AddJoiner(static_cast(aExtAddress), aPSKd, + aTimeout); } ThreadError otCommissionerRemoveJoiner(otInstance *aInstance, const otExtAddress *aExtAddress) diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 7d8944987..2a53b28cd 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -68,6 +68,7 @@ Commissioner::Commissioner(ThreadNetif &aThreadNetif): mState(kStateDisabled), mJoinerPort(0), mJoinerRloc(0), + mJoinerExpirationTimer(aThreadNetif.GetIp6().mTimerScheduler, HandleJoinerExpirationTimer, this), mTimer(aThreadNetif.GetIp6().mTimerScheduler, HandleTimer, this), mSessionId(0), mTransmitAttempts(0), @@ -199,7 +200,7 @@ void Commissioner::ClearJoiners(void) otLogFuncExit(); } -ThreadError Commissioner::AddJoiner(const Mac::ExtAddress *aExtAddress, const char *aPSKd) +ThreadError Commissioner::AddJoiner(const Mac::ExtAddress *aExtAddress, const char *aPSKd, uint32_t aTimeout) { ThreadError error = kThreadError_NoBufs; @@ -226,6 +227,9 @@ ThreadError Commissioner::AddJoiner(const Mac::ExtAddress *aExtAddress, const ch strncpy(mJoiners[i].mPsk, aPSKd, sizeof(mJoiners[i].mPsk) - 1); mJoiners[i].mValid = true; + mJoiners[i].mExpirationTime = Timer::GetNow() + Timer::SecToMsec(aTimeout); + + UpdateJoinerExpirationTimer(); SendCommissionerSet(); @@ -264,6 +268,8 @@ ThreadError Commissioner::RemoveJoiner(const Mac::ExtAddress *aExtAddress) mJoiners[i].mValid = false; + UpdateJoinerExpirationTimer(); + SendCommissionerSet(); ExitNow(error = kThreadError_None); @@ -311,6 +317,66 @@ void Commissioner::HandleTimer(void) } } +void Commissioner::HandleJoinerExpirationTimer(void *aContext) +{ + static_cast(aContext)->HandleJoinerExpirationTimer(); +} + +void Commissioner::HandleJoinerExpirationTimer(void) +{ + uint32_t now = Timer::GetNow(); + + // Remove expired Joiners. + for (size_t i = 0; i < sizeof(mJoiners) / sizeof(mJoiners[0]); i++) + { + if (!mJoiners[i].mValid) + { + continue; + } + + if (static_cast(now - mJoiners[i].mExpirationTime) >= 0) + { + otLogDebgMeshCoP("removing joiner due to timeout"); + RemoveJoiner(&mJoiners[i].mExtAddress); + } + } + + UpdateJoinerExpirationTimer(); +} + +void Commissioner::UpdateJoinerExpirationTimer(void) +{ + uint32_t now = Timer::GetNow(); + uint32_t nextTimeout = 0xffffffff; + + // Check if timer should be set for next Joiner. + for (size_t i = 0; i < sizeof(mJoiners) / sizeof(mJoiners[0]); i++) + { + { + if (!mJoiners[i].mValid) + { + continue; + } + + if (mJoiners[i].mExpirationTime - now < nextTimeout) + { + nextTimeout = mJoiners[i].mExpirationTime - now; + } + } + } + + if (nextTimeout != 0xffffffff) + { + // Update the timer to the timeout of the next Joiner. + mJoinerExpirationTimer.Start(nextTimeout); + } + else + { + // No Joiners, stop the timer. + mJoinerExpirationTimer.Stop(); + } +} + ThreadError Commissioner::SendMgmtCommissionerGetRequest(const uint8_t *aTlvs, uint8_t aLength) { @@ -822,6 +888,7 @@ void Commissioner::SendJoinFinalizeResponse(const Coap::Header &aRequestHeader, Ip6::MessageInfo joinerMessageInfo; MeshCoP::StateTlv stateTlv; Message *message; + Mac::ExtAddress extAddr; otLogFuncEntry(); @@ -842,6 +909,10 @@ void Commissioner::SendJoinFinalizeResponse(const Coap::Header &aRequestHeader, mSendKek = true; SuccessOrExit(error = mNetif.GetSecureCoapServer().SendMessage(*message, joinerMessageInfo)); + memcpy(extAddr.m8, mJoinerIid, sizeof(extAddr.m8)); + extAddr.SetLocal(!extAddr.IsLocal()); + RemoveJoiner(&extAddr); + otLogInfoMeshCoP("sent joiner finalize response"); otLogCertMeshCoP("[THCI] direction=send | type=JOIN_FIN.rsp"); exit: diff --git a/src/core/meshcop/commissioner.hpp b/src/core/meshcop/commissioner.hpp index 8836b466b..005175c6e 100644 --- a/src/core/meshcop/commissioner.hpp +++ b/src/core/meshcop/commissioner.hpp @@ -92,13 +92,14 @@ public: * This method adds a Joiner entry. * * @param[in] aExtAddress A pointer to the Joiner's extended address or NULL for any Joiner. - * @param[in] aPSKd A pointer to the PSKd + * @param[in] aPSKd A pointer to the PSKd. + * @param[in] aTimeout A time after which a Joiner is automatically removed, in seconds. * * @retval kThreadError_None Successfully added the Joiner. * @retval kThreadError_NoBufs No buffers available to add the Joiner. * */ - ThreadError AddJoiner(const Mac::ExtAddress *aExtAddress, const char *aPSKd); + ThreadError AddJoiner(const Mac::ExtAddress *aExtAddress, const char *aPSKd, uint32_t aTimeout); /** * This method removes a Joiner entry. @@ -199,15 +200,20 @@ public: private: enum { - kPetitionAttemptDelay = 5, ///< COMM_PET_ATTEMPT_DELAY (seconds) - kPetitionRetryCount = 2, ///< COMM_PET_RETRY_COUNT - kPetitionRetryDelay = 1, ///< COMM_PET_RETRY_DELAY (seconds) - kKeepAliveTimeout = 50, ///< TIMEOUT_COMM_PET (seconds) + kPetitionAttemptDelay = 5, ///< COMM_PET_ATTEMPT_DELAY (seconds) + kPetitionRetryCount = 2, ///< COMM_PET_RETRY_COUNT + kPetitionRetryDelay = 1, ///< COMM_PET_RETRY_DELAY (seconds) + kKeepAliveTimeout = 50, ///< TIMEOUT_COMM_PET (seconds) }; static void HandleTimer(void *aContext); void HandleTimer(void); + static void HandleJoinerExpirationTimer(void *aContext); + void HandleJoinerExpirationTimer(void); + + void UpdateJoinerExpirationTimer(void); + static void HandleMgmtCommissionerSetResponse(void *aContext, otCoapHeader *aHeader, otMessage *aMessage, const otMessageInfo *aMessageInfo, ThreadError aResult); void HandleMgmtCommissisonerSetResponse(Coap::Header *aHeader, Message *aMessage, @@ -251,6 +257,7 @@ private: struct Joiner { Mac::ExtAddress mExtAddress; + uint32_t mExpirationTime; char mPsk[Dtls::kPskMaxLength + 1]; bool mValid : 1; bool mAny : 1; @@ -264,6 +271,7 @@ private: }; uint16_t mJoinerPort; uint16_t mJoinerRloc; + Timer mJoinerExpirationTimer; Timer mTimer; uint16_t mSessionId; diff --git a/src/core/meshcop/joiner_router.cpp b/src/core/meshcop/joiner_router.cpp index 4443bc6b4..7e766bc3d 100644 --- a/src/core/meshcop/joiner_router.cpp +++ b/src/core/meshcop/joiner_router.cpp @@ -60,9 +60,9 @@ JoinerRouter::JoinerRouter(ThreadNetif &aNetif): mSocket(aNetif.GetIp6().mUdp), mRelayTransmit(OPENTHREAD_URI_RELAY_TX, &JoinerRouter::HandleRelayTransmit, this), mNetif(aNetif), + mTimer(aNetif.GetIp6().mTimerScheduler, &JoinerRouter::HandleTimer, this), mJoinerUdpPort(0), mIsJoinerPortConfigured(false), - mTimer(aNetif.GetIp6().mTimerScheduler, &JoinerRouter::HandleTimer, this), mExpectJoinEntRsp(false) { mSocket.GetSockName().mPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT; diff --git a/src/core/meshcop/joiner_router_ftd.hpp b/src/core/meshcop/joiner_router_ftd.hpp index c75571a3d..d14ac5154 100644 --- a/src/core/meshcop/joiner_router_ftd.hpp +++ b/src/core/meshcop/joiner_router_ftd.hpp @@ -118,12 +118,13 @@ private: Coap::Resource mRelayTransmit; ThreadNetif &mNetif; - uint16_t mJoinerUdpPort; - bool mIsJoinerPortConfigured; - Timer mTimer; MessageQueue mDelayedJoinEnts; - bool mExpectJoinEntRsp; + + uint16_t mJoinerUdpPort; + + bool mIsJoinerPortConfigured : 1; + bool mExpectJoinEntRsp : 1; }; /**