diff --git a/include/commissioning/commissioner.h b/include/commissioning/commissioner.h index 5ae900121..f411ec3f1 100644 --- a/include/commissioning/commissioner.h +++ b/include/commissioning/commissioner.h @@ -49,14 +49,15 @@ extern "C" { /** * This function enables the Thread Commissioner role. * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aPSKd A pointer to the PSKd. + * @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). * * @retval kThreadError_None Successfully started the Commissioner role. - * @retval kThreadError_InvalidArgs @p aPSKd is invalid. + * @retval kThreadError_InvalidArgs @p aPSKd or @p aProvisioningUrl is invalid. * */ -ThreadError otCommissionerStart(otInstance *aInstance, const char *aPSKd); +ThreadError otCommissionerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl); /** * This function disables the Thread Commissioner role. diff --git a/include/commissioning/joiner.h b/include/commissioning/joiner.h index cb7974423..db46bab8e 100644 --- a/include/commissioning/joiner.h +++ b/include/commissioning/joiner.h @@ -49,14 +49,15 @@ extern "C" { /** * 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] 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). * * @retval kThreadError_None Successfully started the Commissioner role. - * @retval kThreadError_InvalidArgs @p aPSKd is invalid. + * @retval kThreadError_InvalidArgs @p aPSKd or @p aProvisioningUrl is invalid. * */ -ThreadError otJoinerStart(otInstance *aInstance, const char *aPSKd); +ThreadError otJoinerStart(otInstance *aInstance, const char *aPSKd, const char *aProvisioningUrl); /** * This function disables the Thread Joiner role. diff --git a/include/openthread-types.h b/include/openthread-types.h index 207139fb9..4225deff2 100644 --- a/include/openthread-types.h +++ b/include/openthread-types.h @@ -402,6 +402,7 @@ typedef enum otMeshcopTlvType OT_MESHCOP_TLV_JOINER_IID = 19, ///< meshcop Joiner IID TLV OT_MESHCOP_TLV_JOINER_RLOC = 20, ///< meshcop Joiner Router Locator TLV OT_MESHCOP_TLV_JOINER_ROUTER_KEK = 21, ///< meshcop Joiner Router KEK TLV + OT_MESHCOP_TLV_PROVISIONING_URL = 32, ///< meshcop Provisioning URL TLV OT_MESHCOP_TLV_PENDINGTIMESTAMP = 51, ///< meshcop Pending Timestamp TLV OT_MESHCOP_TLV_DELAYTIMER = 52, ///< meshcop Delay Timer TLV OT_MESHCOP_TLV_CHANNELMASK = 53, ///< meshcop Channel Mask TLV diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 201334fc2..845528339 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -1912,8 +1912,10 @@ void Interpreter::ProcessCommissioner(int argc, char *argv[]) if (strcmp(argv[0], "start") == 0) { + const char *provisioningUrl; VerifyOrExit(argc > 1, error = kThreadError_Parse); - otCommissionerStart(mInstance, argv[1]); + provisioningUrl = argc > 2 ? argv[2] : NULL; + otCommissionerStart(mInstance, argv[1], provisioningUrl); } else if (strcmp(argv[0], "stop") == 0) { @@ -2022,8 +2024,10 @@ void Interpreter::ProcessJoiner(int argc, char *argv[]) if (strcmp(argv[0], "start") == 0) { + const char *provisioningUrl; VerifyOrExit(argc > 1, error = kThreadError_Parse); - otJoinerStart(mInstance, argv[1]); + provisioningUrl = (argc > 2) ? argv[2] : NULL; + otJoinerStart(mInstance, argv[1], provisioningUrl); } else if (strcmp(argv[0], "stop") == 0) { diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index a2b47098b..32cbb4068 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -65,7 +65,7 @@ Commissioner::Commissioner(ThreadNetif &aThreadNetif): aThreadNetif.GetCoapServer().AddResource(mRelayReceive); } -ThreadError Commissioner::Start(const char *aPSKd) +ThreadError Commissioner::Start(const char *aPSKd, const char *aProvisioningUrl) { ThreadError error = kThreadError_None; @@ -73,6 +73,7 @@ ThreadError Commissioner::Start(const char *aPSKd) SuccessOrExit(error = mNetif.GetDtls().SetPsk(reinterpret_cast(aPSKd), static_cast(strlen(aPSKd)))); + SuccessOrExit(error = mNetif.GetDtls().mProvisioningUrl.SetProvisioningUrl(aProvisioningUrl)); SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this)); mState = kStatePetition; SendPetition(); @@ -429,18 +430,21 @@ exit: void Commissioner::ReceiveJoinerFinalize(uint8_t *buf, uint16_t length) { - Message *message; + Message *message = NULL; Coap::Header header; char uriPath[16]; char *curUriPath = uriPath; const Coap::Header::Option *coapOption; + StateTlv::State state = StateTlv::kAccept; + ProvisioningUrlTlv provisioningUrl; + otLogInfoMeshCoP("receive joiner finalize 1\r\n"); VerifyOrExit((message = mNetif.GetIp6().mMessagePool.New(Message::kTypeIp6, 0)) != NULL, ;); SuccessOrExit(message->Append(buf, length)); SuccessOrExit(header.FromMessage(*message)); - message->SetOffset(header.GetLength()); + SuccessOrExit(message->SetOffset(header.GetLength())); coapOption = header.GetCurrentOption(); @@ -465,15 +469,34 @@ void Commissioner::ReceiveJoinerFinalize(uint8_t *buf, uint16_t length) coapOption = header.GetNextOption(); } - curUriPath[-1] = '\0'; + if (curUriPath > uriPath) + { + curUriPath[-1] = '\0'; + } - SendJoinFinalizeResponse(header); + VerifyOrExit(strcmp(uriPath, OPENTHREAD_URI_JOINER_FINALIZE) == 0,); + + if (Tlv::GetTlv(*message, Tlv::kProvisioningUrl, sizeof(provisioningUrl), provisioningUrl) == kThreadError_None) + { + if (provisioningUrl.GetLength() != mNetif.GetDtls().mProvisioningUrl.GetLength() || + memcmp(provisioningUrl.GetProvisioningUrl(), mNetif.GetDtls().mProvisioningUrl.GetProvisioningUrl(), + provisioningUrl.GetLength()) != 0) + { + state = StateTlv::kReject; + } + } + + SendJoinFinalizeResponse(header, state); exit: - return; + + if (message != NULL) + { + message->Free(); + } } -void Commissioner::SendJoinFinalizeResponse(const Coap::Header &aRequestHeader) +void Commissioner::SendJoinFinalizeResponse(const Coap::Header &aRequestHeader, StateTlv::State aState) { Coap::Header responseHeader; MeshCoP::StateTlv *stateTlv; @@ -491,7 +514,7 @@ void Commissioner::SendJoinFinalizeResponse(const Coap::Header &aRequestHeader) stateTlv = reinterpret_cast(cur); stateTlv->Init(); - stateTlv->SetState(MeshCoP::StateTlv::kAccept); + stateTlv->SetState(aState); cur += sizeof(*stateTlv); mSendKek = true; diff --git a/src/core/meshcop/commissioner.hpp b/src/core/meshcop/commissioner.hpp index 8b79e25e8..6dfc04e62 100644 --- a/src/core/meshcop/commissioner.hpp +++ b/src/core/meshcop/commissioner.hpp @@ -61,12 +61,13 @@ public: /** * This method starts the Commissioner service. * - * @param[in] aPSKd A pointer to the PSKd. + * @param[in] aPSKd A pointer to the PSKd. + * @param[in] aProvisioningUrl A pointer to the Provisioning URL (may be NULL). * * @retval kThreadError_None Successfully started the Commissioner service. * */ - ThreadError Start(const char *aPSKd); + ThreadError Start(const char *aPSKd, const char *aProvisioningUrl); /** * This method stops the Commissioner service. @@ -108,7 +109,7 @@ private: void HandleUdpTransmit(void); void ReceiveJoinerFinalize(uint8_t *buf, uint16_t length); - void SendJoinFinalizeResponse(const Coap::Header &aRequestHeader); + void SendJoinFinalizeResponse(const Coap::Header &aRequestHeader, StateTlv::State aState); ThreadError SendPetition(void); ThreadError SendKeepAlive(void); diff --git a/src/core/meshcop/dtls.cpp b/src/core/meshcop/dtls.cpp index c43d7cb47..633ff02a7 100644 --- a/src/core/meshcop/dtls.cpp +++ b/src/core/meshcop/dtls.cpp @@ -54,6 +54,7 @@ Dtls::Dtls(ThreadNetif &aNetif): mTimerSet(false), mNetif(aNetif) { + mProvisioningUrl.Init(); } ThreadError Dtls::Start(bool aClient, ReceiveHandler aReceiveHandler, SendHandler aSendHandler, void *aContext) diff --git a/src/core/meshcop/dtls.hpp b/src/core/meshcop/dtls.hpp index ba8701eb8..e34b0eca6 100644 --- a/src/core/meshcop/dtls.hpp +++ b/src/core/meshcop/dtls.hpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -158,6 +159,12 @@ public: */ ThreadError Receive(Message &aMessage, uint16_t aOffset, uint16_t aLength); + /** + * The provisioning URL is placed here so that both the Commissioner and Joiner can share the same object. + * + */ + ProvisioningUrlTlv mProvisioningUrl; + private: enum { diff --git a/src/core/meshcop/joiner.cpp b/src/core/meshcop/joiner.cpp index 2af9eb3ce..0aef3ebe6 100644 --- a/src/core/meshcop/joiner.cpp +++ b/src/core/meshcop/joiner.cpp @@ -64,7 +64,7 @@ Joiner::Joiner(ThreadNetif &aNetif): mNetif.GetCoapServer().AddResource(mJoinerEntrust); } -ThreadError Joiner::Start(const char *aPSKd) +ThreadError Joiner::Start(const char *aPSKd, const char *aProvisioningUrl) { ThreadError error; Mac::ExtAddress extAddress; @@ -76,6 +76,7 @@ ThreadError Joiner::Start(const char *aPSKd) SuccessOrExit(error = mNetif.GetDtls().SetPsk(reinterpret_cast(aPSKd), static_cast(strlen(aPSKd)))); + SuccessOrExit(error = mNetif.GetDtls().mProvisioningUrl.SetProvisioningUrl(aProvisioningUrl)); SuccessOrExit(error = mNetif.GetMle().Discover(0, 0, mNetif.GetMac().GetPanId(), HandleDiscoverResult, this)); exit: @@ -215,7 +216,8 @@ exit: void Joiner::SendJoinerFinalize(void) { Coap::Header header; - MeshCoP::StateTlv *stateTlv; + StateTlv *stateTlv; + uint8_t length; uint8_t buf[128]; uint8_t *cur = buf; @@ -234,6 +236,15 @@ void Joiner::SendJoinerFinalize(void) stateTlv->SetState(MeshCoP::StateTlv::kAccept); cur += sizeof(*stateTlv); + length = mNetif.GetDtls().mProvisioningUrl.GetLength(); + + if (length > 0) + { + length += sizeof(Tlv); + memcpy(cur, &mNetif.GetDtls().mProvisioningUrl, length); + cur += length; + } + mNetif.GetDtls().Send(buf, static_cast(cur - buf)); otLogInfoMeshCoP("Sent joiner finalize\r\n"); @@ -241,24 +252,33 @@ void Joiner::SendJoinerFinalize(void) void Joiner::ReceiveJoinerFinalizeResponse(uint8_t *buf, uint16_t length) { - Message *message; + Message *message = NULL; Coap::Header header; + StateTlv state; VerifyOrExit((message = mNetif.GetIp6().mMessagePool.New(Message::kTypeIp6, 0)) != NULL, ;); SuccessOrExit(message->Append(buf, length)); SuccessOrExit(header.FromMessage(*message)); + SuccessOrExit(message->SetOffset(header.GetLength())); VerifyOrExit(header.GetType() == Coap::Header::kTypeAcknowledgment && header.GetCode() == Coap::Header::kCodeChanged && header.GetMessageId() == 0 && header.GetTokenLength() == 0, ;); - otLogInfoMeshCoP("received joiner finalize response\r\n"); + SuccessOrExit(Tlv::GetTlv(*message, Tlv::kState, sizeof(state), state)); + VerifyOrExit(state.IsValid(), ;); + + otLogInfoMeshCoP("received joiner finalize response %d\r\n", static_cast(state.GetState())); Close(); exit: - return; + + if (message != NULL) + { + message->Free(); + } } void Joiner::HandleJoinerEntrust(void *aContext, Coap::Header &aHeader, diff --git a/src/core/meshcop/joiner.hpp b/src/core/meshcop/joiner.hpp index 37eb92953..73a89f845 100644 --- a/src/core/meshcop/joiner.hpp +++ b/src/core/meshcop/joiner.hpp @@ -63,12 +63,13 @@ public: /** * This method starts the Joiner service. * - * @param[in] aPSKd A pointer to the PSKd. + * @param[in] aPSKd A pointer to the PSKd. + * @param[in] aProvisioningUrl A pointer to the Provisioning URL (may be NULL). * * @retval kThreadError_None Successfully started the Joiner service. * */ - ThreadError Start(const char *aPSKd); + ThreadError Start(const char *aPSKd, const char *aProvisioningUrl); /** * This method stops the Joiner service. diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 3f119f343..cd73ebea0 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -1339,9 +1339,9 @@ ThreadError otSendPendingSet(otInstance *, const otOperationalDataset *aDataset, #if OPENTHREAD_ENABLE_COMMISSIONER #include -ThreadError otCommissionerStart(otInstance *, const char *aPSKd) +ThreadError otCommissionerStart(otInstance *, const char *aPSKd, const char *aProvisioningUrl) { - return sThreadNetif->GetCommissioner().Start(aPSKd); + return sThreadNetif->GetCommissioner().Start(aPSKd, aProvisioningUrl); } ThreadError otCommissionerStop(otInstance *) @@ -1369,9 +1369,9 @@ ThreadError otCommissionerPanIdQuery(otInstance *, uint16_t aPanId, uint32_t aCh #endif // OPENTHREAD_ENABLE_COMMISSIONER #if OPENTHREAD_ENABLE_JOINER -ThreadError otJoinerStart(otInstance *, const char *aPSKd) +ThreadError otJoinerStart(otInstance *, const char *aPSKd, const char *aProvisioningUrl) { - return sThreadNetif->GetJoiner().Start(aPSKd); + return sThreadNetif->GetJoiner().Start(aPSKd, aProvisioningUrl); } ThreadError otJoinerStop(otInstance *) diff --git a/src/core/thread/meshcop_tlvs.hpp b/src/core/thread/meshcop_tlvs.hpp index ce0fb20a3..c65f9413a 100644 --- a/src/core/thread/meshcop_tlvs.hpp +++ b/src/core/thread/meshcop_tlvs.hpp @@ -81,6 +81,7 @@ public: kJoinerIid = OT_MESHCOP_TLV_JOINER_IID, ///< Joiner IID TLV kJoinerRouterLocator = OT_MESHCOP_TLV_JOINER_RLOC, ///< Joiner Router Locator TLV kJoinerRouterKek = OT_MESHCOP_TLV_JOINER_ROUTER_KEK, ///< Joiner Router KEK TLV + kProvisioningUrl = OT_MESHCOP_TLV_PROVISIONING_URL, ///< Provisioning URL TLV kPendingTimestamp = OT_MESHCOP_TLV_PENDINGTIMESTAMP, ///< Pending Timestamp TLV kDelayTimer = OT_MESHCOP_TLV_DELAYTIMER, ///< Delay Timer TLV kChannelMask = OT_MESHCOP_TLV_CHANNELMASK, ///< Channel Mask TLV @@ -1491,6 +1492,62 @@ public: bool IsValid(void) const { return true; } } OT_TOOL_PACKED_END; +/** + * This class implements Provisioning URL TLV generation and parsing. + * + */ +OT_TOOL_PACKED_BEGIN +class ProvisioningUrlTlv: public Tlv +{ +public: + /** + * This method initializes the TLV. + * + */ + void Init(void) { SetType(kProvisioningUrl); SetLength(0); } + + /** + * This method indicates whether or not the TLV appears to be well-formed. + * + * @retval TRUE If the TLV appears to be well-formed. + * @retval FALSE If the TLV does not appear to be well-formed. + * + */ + bool IsValid(void) const { return GetLength() <= sizeof(*this) - sizeof(Tlv); } + + /** + * This method returns the Provisioning URL value. + * + * @returns The Provisioning URL value. + * + */ + const char *GetProvisioningUrl(void) const { return mProvisioningUrl; } + + /** + * This method sets the Provisioning URL value. + * + * @param[in] aProvisioningUrl A pointer to the Provisioning URL value. + * + */ + ThreadError SetProvisioningUrl(const char *aProvisioningUrl) { + ThreadError error = kThreadError_None; + size_t len = aProvisioningUrl ? strnlen(aProvisioningUrl, kMaxLength + 1) : 0; + SetLength(static_cast(len)); + VerifyOrExit(len <= kMaxLength, error = kThreadError_InvalidArgs); + memcpy(mProvisioningUrl, aProvisioningUrl, len); +exit: + return error; + } + +private: + enum + { + kMaxLength = 64, + }; + + char mProvisioningUrl[kMaxLength]; +} OT_TOOL_PACKED_END; + /** * This class implements Discovery Request TLV generation and parsing. *