From 9b97c1c7d0bd757eebfecdb26887236a8d0c1dd3 Mon Sep 17 00:00:00 2001 From: Lu Wang Date: Sat, 24 Sep 2016 00:38:21 +0800 Subject: [PATCH] Add support for MGMT_COMMISSIONER_GET and MGMT_COMMISSIONER_SET (#634) * - Add support for MGMT_COMMISSIONER_GET and MGMT_COMMISSIONER_SET - Add CLI for sending this two commands * - Move MGMT_COMMISSIONER_GET and MGMT_COMMISSIONER_SET to MeshCoP::commissioner --- include/commissioning/commissioner.h | 28 ++++ include/openthread-types.h | 29 ++++ src/cli/cli.cpp | 106 ++++++++++++ src/core/meshcop/commissioner.cpp | 148 +++++++++++++++++ src/core/meshcop/commissioner.hpp | 29 ++++ src/core/openthread.cpp | 11 ++ src/core/thread/meshcop_tlvs.hpp | 6 +- src/core/thread/network_data_leader.cpp | 209 ++++++++++++++++++++++++ src/core/thread/network_data_leader.hpp | 15 ++ src/core/thread/thread_uris.hpp | 16 ++ 10 files changed, 592 insertions(+), 5 deletions(-) diff --git a/include/commissioning/commissioner.h b/include/commissioning/commissioner.h index f411ec3f1..f78d24760 100644 --- a/include/commissioning/commissioner.h +++ b/include/commissioning/commissioner.h @@ -127,6 +127,34 @@ ThreadError otCommissionerPanIdQuery(otInstance *aInstance, uint16_t aPanId, uin const otIp6Address *aAddress, otCommissionerPanIdConflictCallback aCallback, void *aContext); +/** + * This function sends MGMT_COMMISSIONER_GET. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aTlvs A pointer to TLVs. + * @param[in] aLength The length of TLVs. + * + * @retval kThreadError_None Successfully send the meshcop dataset command. + * @retval kThreadError_NoBufs Insufficient buffer space to send. + * + */ +ThreadError otSendMgmtCommissionerGet(otInstance *, const uint8_t *aTlvs, uint8_t aLength); + +/** + * This function sends MGMT_COMMISSIONER_SET. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aDataset A pointer to commissioning dataset. + * @param[in] aTlvs A pointer to TLVs. + * @param[in] aLength The length of TLVs. + * + * @retval kThreadError_None Successfully send the meshcop dataset command. + * @retval kThreadError_NoBufs Insufficient buffer space to send. + * + */ +ThreadError otSendMgmtCommissionerSet(otInstance *, const otCommissioningDataset *aDataset, + const uint8_t *aTlvs, uint8_t aLength); + /** * @} * diff --git a/include/openthread-types.h b/include/openthread-types.h index 4225deff2..f6884ebf2 100644 --- a/include/openthread-types.h +++ b/include/openthread-types.h @@ -376,6 +376,35 @@ typedef struct otOperationalDataset bool mIsChannelMaskPage0Set : 1; ///< TRUE if Channel Mask Page 0 is set, FALSE otherwise. } otOperationalDataset; +#define OT_STEERING_DATA_MAX_LENGTH 16 ///< Max steering data length (bytes) + +/** + * This structure represents the steering data. + * + */ +typedef struct otSteeringData +{ + uint8_t mLength; + uint8_t m8[OT_STEERING_DATA_MAX_LENGTH]; +} otSteeringData; + +/** + * This structure represents a Commissioning Dataset. + * + */ +typedef struct otCommissioningDataset +{ + uint16_t mLocator; ///< Border Router RLOC16 + uint16_t mSessionId; ///< Commissioner Session Id + otSteeringData mSteeringData; ///< Steering Data + uint16_t mJoinerUdpPort; ///< Joiner UDP Port + + bool mIsLocatorSet : 1; ///< TRUE if Border Router RLOC16 is set, FALSE otherwise. + bool mIsSessionIdSet: 1; ///< TRUE if Commissioner Session Id is set, FALSE otherwise. + bool mIsSteeringDataSet : 1; ///< TRUE if Steering Data is set, FALSE otherwise. + bool mIsJoinerUdpPortSet : 1; ///< TRUE if Joiner UDP Port is set, FALSE otherwise. +} otCommissioningDataset; + /** * This enumeration represents meshcop TLV types. * diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 51e500924..fcfa5c815 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -2038,6 +2038,112 @@ void Interpreter::ProcessCommissioner(int argc, char *argv[]) Interpreter::s_HandlePanIdConflict, this)); } + else if (strcmp(argv[0], "mgmtget") == 0) + { + uint8_t tlvs[32]; + long value; + int length = 0; + + for (uint8_t index = 1; index < argc; index++) + { + VerifyOrExit(static_cast(length) < sizeof(tlvs), error = kThreadError_NoBufs); + + if (strcmp(argv[index], "locator") == 0) + { + tlvs[length++] = OT_MESHCOP_TLV_BORDER_AGENT_RLOC; + } + else if (strcmp(argv[index], "sessionid") == 0) + { + tlvs[length++] = OT_MESHCOP_TLV_COMM_SESSION_ID; + } + else if (strcmp(argv[index], "steeringdata") == 0) + { + tlvs[length++] = OT_MESHCOP_TLV_STEERING_DATA; + } + else if (strcmp(argv[index], "joinerudpport") == 0) + { + tlvs[length++] = OT_MESHCOP_TLV_JOINER_UDP_PORT; + } + else if (strcmp(argv[index], "binary") == 0) + { + VerifyOrExit((index + 1) < argc, error = kThreadError_Parse); + value = static_cast(strlen(argv[++index]) + 1) / 2; + VerifyOrExit(static_cast(value) <= (sizeof(tlvs) - static_cast(length)), error = kThreadError_NoBufs); + VerifyOrExit(Interpreter::Hex2Bin(argv[index], tlvs + length, static_cast(value)) >= 0, + error = kThreadError_Parse); + length += value; + } + else + { + ExitNow(error = kThreadError_Parse); + } + } + + SuccessOrExit(error = otSendMgmtCommissionerGet(mInstance, tlvs, static_cast(length))); + } + else if (strcmp(argv[0], "mgmtset") == 0) + { + otCommissioningDataset dataset; + uint8_t tlvs[32]; + long value; + int length = 0; + + VerifyOrExit(argc > 0, error = kThreadError_Parse); + + memset(&dataset, 0, sizeof(dataset)); + + for (uint8_t index = 1; index < argc; index++) + { + VerifyOrExit(static_cast(length) < sizeof(tlvs), error = kThreadError_NoBufs); + + if (strcmp(argv[index], "locator") == 0) + { + VerifyOrExit(index < argc, error = kThreadError_Parse); + dataset.mIsLocatorSet = true; + SuccessOrExit(error = Interpreter::ParseLong(argv[++index], value)); + dataset.mLocator = static_cast(value); + } + else if (strcmp(argv[index], "sessionid") == 0) + { + VerifyOrExit(index < argc, error = kThreadError_Parse); + dataset.mIsSessionIdSet = true; + SuccessOrExit(error = Interpreter::ParseLong(argv[++index], value)); + dataset.mSessionId = static_cast(value); + } + else if (strcmp(argv[index], "steeringdata") == 0) + { + VerifyOrExit((index + 1) < argc, error = kThreadError_Parse); + dataset.mIsSteeringDataSet = true; + length = static_cast((strlen(argv[++index]) + 1) / 2); + VerifyOrExit(static_cast(length) <= OT_STEERING_DATA_MAX_LENGTH, error = kThreadError_NoBufs); + VerifyOrExit(Interpreter::Hex2Bin(argv[index], dataset.mSteeringData.m8, static_cast(length)) >= 0, + error = kThreadError_Parse); + dataset.mSteeringData.mLength = length; + length = 0; + } + else if (strcmp(argv[index], "joinerudpport") == 0) + { + VerifyOrExit(index < argc, error = kThreadError_Parse); + dataset.mIsJoinerUdpPortSet = true; + SuccessOrExit(error = Interpreter::ParseLong(argv[++index], value)); + dataset.mJoinerUdpPort = static_cast(value); + } + else if (strcmp(argv[index], "binary") == 0) + { + VerifyOrExit((index + 1) < argc, error = kThreadError_Parse); + length = static_cast((strlen(argv[++index]) + 1) / 2); + VerifyOrExit(static_cast(length) <= sizeof(tlvs), error = kThreadError_NoBufs); + VerifyOrExit(Interpreter::Hex2Bin(argv[index], tlvs, static_cast(length)) >= 0, + error = kThreadError_Parse); + } + else + { + ExitNow(error = kThreadError_Parse); + } + } + + SuccessOrExit(error = otSendMgmtCommissionerSet(mInstance, &dataset, tlvs, static_cast(length))); + } exit: AppendResult(error); diff --git a/src/core/meshcop/commissioner.cpp b/src/core/meshcop/commissioner.cpp index 32cbb4068..7d198b6e9 100644 --- a/src/core/meshcop/commissioner.cpp +++ b/src/core/meshcop/commissioner.cpp @@ -119,6 +119,145 @@ void Commissioner::HandleTimer(void) } } +ThreadError Commissioner::SendMgmtCommissionerGetRequest(const uint8_t *aTlvs, + uint8_t aLength) +{ + ThreadError error = kThreadError_None; + Coap::Header header; + Message *message; + Ip6::MessageInfo messageInfo; + MeshCoP::Tlv tlv; + + mIsSendMgmtCommRequest = true; + + for (size_t i = 0; i < sizeof(mCoapToken); i++) + { + mCoapToken[i] = static_cast(otPlatRandomGet()); + } + + header.Init(); + header.SetVersion(1); + header.SetType(Coap::Header::kTypeConfirmable); + header.SetCode(Coap::Header::kCodePost); + header.SetMessageId(++mCoapMessageId); + header.SetToken(mCoapToken, sizeof(mCoapToken)); + header.AppendUriPathOptions(OPENTHREAD_URI_COMMISSIONER_GET); + header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + header.Finalize(); + + VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); + + if (aLength > 0) + { + tlv.SetType(MeshCoP::Tlv::kGet); + tlv.SetLength(aLength); + SuccessOrExit(error = message->Append(&tlv, sizeof(tlv))); + SuccessOrExit(error = message->Append(aTlvs, aLength)); + } + + memset(&messageInfo, 0, sizeof(messageInfo)); + mNetif.GetMle().GetLeaderAddress(messageInfo.GetPeerAddr()); + messageInfo.mPeerPort = kCoapUdpPort; + SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); + + otLogInfoMeshCoP("sent MGMT_COMMISSIONER_GET.req to leader\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + mIsSendMgmtCommRequest = false; + message->Free(); + } + + return error; +} + +ThreadError Commissioner::SendMgmtCommissionerSetRequest(const otCommissioningDataset &aDataset, + const uint8_t *aTlvs, uint8_t aLength) +{ + ThreadError error = kThreadError_None; + Coap::Header header; + Message *message; + Ip6::MessageInfo messageInfo; + + mIsSendMgmtCommRequest = true; + + for (size_t i = 0; i < sizeof(mCoapToken); i++) + { + mCoapToken[i] = static_cast(otPlatRandomGet()); + } + + header.Init(); + header.SetVersion(1); + header.SetType(Coap::Header::kTypeConfirmable); + header.SetCode(Coap::Header::kCodePost); + header.SetMessageId(++mCoapMessageId); + header.SetToken(mCoapToken, sizeof(mCoapToken)); + header.AppendUriPathOptions(OPENTHREAD_URI_COMMISSIONER_SET); + header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + header.Finalize(); + + VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); + + if (aDataset.mIsLocatorSet) + { + MeshCoP::BorderAgentLocatorTlv locator; + locator.Init(); + locator.SetBorderAgentLocator(aDataset.mLocator); + SuccessOrExit(error = message->Append(&locator, sizeof(locator))); + } + + if (aDataset.mIsSessionIdSet) + { + MeshCoP::CommissionerSessionIdTlv sessionId; + sessionId.Init(); + sessionId.SetCommissionerSessionId(aDataset.mSessionId); + SuccessOrExit(error = message->Append(&sessionId, sizeof(sessionId))); + } + + if (aDataset.mIsSteeringDataSet) + { + MeshCoP::SteeringDataTlv steeringData; + steeringData.Init(); + steeringData.SetLength(aDataset.mSteeringData.mLength); + SuccessOrExit(error = message->Append(&steeringData, sizeof(MeshCoP::Tlv))); + SuccessOrExit(error = message->Append(&aDataset.mSteeringData.m8, aDataset.mSteeringData.mLength)); + } + + if (aDataset.mIsJoinerUdpPortSet) + { + MeshCoP::JoinerUdpPortTlv joinerUdpPort; + joinerUdpPort.Init(); + joinerUdpPort.SetUdpPort(aDataset.mJoinerUdpPort); + SuccessOrExit(error = message->Append(&joinerUdpPort, sizeof(joinerUdpPort))); + } + + if (aLength > 0) + { + SuccessOrExit(error = message->Append(aTlvs, aLength)); + } + + memset(&messageInfo, 0, sizeof(messageInfo)); + mNetif.GetMle().GetLeaderAddress(messageInfo.GetPeerAddr()); + messageInfo.mPeerPort = kCoapUdpPort; + SuccessOrExit(error = mSocket.SendTo(*message, messageInfo)); + + otLogInfoMeshCoP("sent MGMT_COMMISSIONER_SET.req to leader\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + mIsSendMgmtCommRequest = false; + message->Free(); + } + + return error; +} + ThreadError Commissioner::SendPetition(void) { ThreadError error = kThreadError_None; @@ -278,6 +417,15 @@ void Commissioner::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &a memcmp(mCoapToken, header.GetToken(), sizeof(mCoapToken)) == 0, ;); aMessage.MoveOffset(header.GetLength()); + if (mIsSendMgmtCommRequest) + { + mIsSendMgmtCommRequest = false; + + otLogInfoMeshCoP("received MGMT_COMMISSIONER_SET and MGMT_COMMISSIONER_GET response\r\n"); + + ExitNow(); + } + SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kState, sizeof(state), state)); VerifyOrExit(state.IsValid(), ;); diff --git a/src/core/meshcop/commissioner.hpp b/src/core/meshcop/commissioner.hpp index 6dfc04e62..1165defc0 100644 --- a/src/core/meshcop/commissioner.hpp +++ b/src/core/meshcop/commissioner.hpp @@ -88,6 +88,33 @@ public: EnergyScanClient mEnergyScan; PanIdQueryClient mPanIdQuery; + + /** + * This method sends MGMT_COMMISSIONER_GET. + * + * @param[in] aTlvs A pointer to Commissioning Data TLVs. + * @param[in] aLength The length of requested TLVs in bytes. + * + * @retval kThreadError_None Send MGMT_COMMISSIONER_GET successfully. + * @retval kThreadError_Failed Send MGMT_COMMISSIONER_GET fail. + * + */ + ThreadError SendMgmtCommissionerGetRequest(const uint8_t *aTlvs, uint8_t aLength); + + /** + * This method sends MGMT_COMMISSIONER_SET. + * + * @param[in] aDataset A reference to Commissioning Data. + * @param[in] aTlvs A pointer to user specific Commissioning Data TLVs. + * @param[in] aLength The length of user specific TLVs in bytes. + * + * @retval kThreadError_None Send MGMT_COMMISSIONER_SET successfully. + * @retval kThreadError_Failed Send MGMT_COMMISSIONER_SET fail. + * + */ + ThreadError SendMgmtCommissionerSetRequest(const otCommissioningDataset &aDataset, + const uint8_t *aTlvs, uint8_t aLength); + private: static void HandleTimer(void *aContext); void HandleTimer(void); @@ -139,6 +166,8 @@ private: Coap::Resource mRelayReceive; ThreadNetif &mNetif; + + bool mIsSendMgmtCommRequest = false; }; } // namespace MeshCoP diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 9e9d1405b..fca6307df 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -1366,6 +1366,17 @@ ThreadError otCommissionerPanIdQuery(otInstance *, uint16_t aPanId, uint32_t aCh *static_cast(aAddress), aCallback, aContext); } + +ThreadError otSendMgmtCommissionerGet(otInstance *, const uint8_t *aTlvs, uint8_t aLength) +{ + return sThreadNetif->GetCommissioner().SendMgmtCommissionerGetRequest(aTlvs, aLength); +} + +ThreadError otSendMgmtCommissionerSet(otInstance *, const otCommissioningDataset *aDataset, + const uint8_t *aTlvs, uint8_t aLength) +{ + return sThreadNetif->GetCommissioner().SendMgmtCommissionerSetRequest(*aDataset, aTlvs, aLength); +} #endif // OPENTHREAD_ENABLE_COMMISSIONER #if OPENTHREAD_ENABLE_JOINER diff --git a/src/core/thread/meshcop_tlvs.hpp b/src/core/thread/meshcop_tlvs.hpp index 558892717..99f3477d8 100644 --- a/src/core/thread/meshcop_tlvs.hpp +++ b/src/core/thread/meshcop_tlvs.hpp @@ -604,11 +604,7 @@ public: void SetBit(uint8_t aBit) { mSteeringData[aBit / 8] |= 1 << (aBit % 8); } private: - enum - { - kMaxLength = 16, - }; - uint8_t mSteeringData[kMaxLength]; + uint8_t mSteeringData[OT_STEERING_DATA_MAX_LENGTH]; } OT_TOOL_PACKED_END; /** diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index e26610301..b704ef804 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -55,6 +55,8 @@ Leader::Leader(ThreadNetif &aThreadNetif): NetworkData(aThreadNetif, false), mTimer(aThreadNetif.GetIp6().mTimerScheduler, &Leader::HandleTimer, this), mServerData(OPENTHREAD_URI_SERVER_DATA, &Leader::HandleServerData, this), + mCommissioningDataGet(OPENTHREAD_URI_COMMISSIONER_GET, &Leader::HandleCommissioningGet, this), + mCommissioningDataSet(OPENTHREAD_URI_COMMISSIONER_SET, &Leader::HandleCommissioningSet, this), mCoapServer(aThreadNetif.GetCoapServer()), mNetif(aThreadNetif) { @@ -75,11 +77,15 @@ void Leader::Reset(void) void Leader::Start(void) { mCoapServer.AddResource(mServerData); + mCoapServer.AddResource(mCommissioningDataGet); + mCoapServer.AddResource(mCommissioningDataSet); } void Leader::Stop(void) { mCoapServer.RemoveResource(mServerData); + mCoapServer.RemoveResource(mCommissioningDataGet); + mCoapServer.RemoveResource(mCommissioningDataSet); } uint8_t Leader::GetVersion(void) const @@ -551,6 +557,106 @@ void Leader::HandleServerData(Coap::Header &aHeader, Message &aMessage, SendServerDataResponse(aHeader, aMessageInfo, NULL, 0); } +void Leader::HandleCommissioningSet(void *aContext, Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo) +{ + Leader *obj = static_cast(aContext); + obj->HandleCommissioningSet(aHeader, aMessage, aMessageInfo); +} + +void Leader::HandleCommissioningSet(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + uint16_t offset = aMessage.GetOffset(); + uint8_t length = static_cast(aMessage.GetLength() - aMessage.GetOffset()); + uint8_t tlvs[NetworkData::kMaxSize]; + MeshCoP::StateTlv::State state = MeshCoP::StateTlv::kAccept; + bool hasSessionId = false; + uint16_t sessionId = 0; + + VerifyOrExit(mMle.GetDeviceState() == Mle::kDeviceStateLeader, state = MeshCoP::StateTlv::kReject); + + aMessage.Read(offset, length, tlvs); + + // Session Id and Border Router Locator MUST NOT be set, and only includes commissioning data tlvs + for (MeshCoP::Tlv *cur = reinterpret_cast(tlvs); + cur < reinterpret_cast(tlvs + length); + cur = cur->GetNext()) + { + MeshCoP::Tlv::Type type = cur->GetType(); + + VerifyOrExit(type == MeshCoP::Tlv::kCommissionerSessionId || + type == MeshCoP::Tlv::kJoinerUdpPort || type == MeshCoP::Tlv::kSteeringData, + state = MeshCoP::StateTlv::kReject); + + if (type == MeshCoP::Tlv::kCommissionerSessionId) + { + hasSessionId = true; + sessionId = static_cast(cur)->GetCommissionerSessionId(); + } + } + + VerifyOrExit(hasSessionId, state = MeshCoP::StateTlv::kReject); + + for (MeshCoP::Tlv *cur = reinterpret_cast(mTlvs + sizeof(CommissioningDataTlv)); + cur < reinterpret_cast(mTlvs + mLength); + cur = cur->GetNext()) + { + if (cur->GetType() == MeshCoP::Tlv::kCommissionerSessionId) + { + VerifyOrExit(sessionId == + static_cast(cur)->GetCommissionerSessionId(), + state = MeshCoP::StateTlv::kReject); + } + else if (cur->GetType() == MeshCoP::Tlv::kBorderAgentLocator) + { + memcpy(tlvs + length, reinterpret_cast(cur), cur->GetLength() + sizeof(MeshCoP::Tlv)); + length += (cur->GetLength() + sizeof(MeshCoP::Tlv)); + } + } + + SetCommissioningData(tlvs, length); + +exit: + + if (mMle.GetDeviceState() == Mle::kDeviceStateLeader) + { + SendCommissioningSetResponse(aHeader, aMessageInfo, state); + } + + return; +} + +void Leader::HandleCommissioningGet(void *aContext, Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo) +{ + Leader *obj = static_cast(aContext); + obj->HandleCommissioningGet(aHeader, aMessage, aMessageInfo); +} + +void Leader::HandleCommissioningGet(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + MeshCoP::Tlv tlv; + uint16_t offset = aMessage.GetOffset(); + uint8_t tlvs[NetworkData::kMaxSize]; + uint8_t length = 0; + + while (offset < aMessage.GetLength()) + { + aMessage.Read(offset, sizeof(tlv), &tlv); + + if (tlv.GetType() == MeshCoP::Tlv::kGet) + { + length = tlv.GetLength(); + aMessage.Read(offset + sizeof(MeshCoP::Tlv), length, tlvs); + break; + } + + offset += sizeof(tlv) + tlv.GetLength(); + } + + SendCommissioningGetResponse(aHeader, aMessageInfo, tlvs, length); +} + void Leader::SendServerDataResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, const uint8_t *aTlvs, uint8_t aTlvsLength) { @@ -581,6 +687,109 @@ exit: } } +void Leader::SendCommissioningGetResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, + uint8_t *aTlvs, uint8_t aLength) +{ + ThreadError error = kThreadError_None; + Coap::Header responseHeader; + Message *message; + uint8_t index; + uint8_t *data = NULL; + uint8_t length = 0; + + VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + responseHeader.Init(); + responseHeader.SetVersion(1); + responseHeader.SetType(Coap::Header::kTypeAcknowledgment); + responseHeader.SetCode(Coap::Header::kCodeChanged); + responseHeader.SetMessageId(aRequestHeader.GetMessageId()); + responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength()); + responseHeader.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + responseHeader.Finalize(); + SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength())); + + for (NetworkDataTlv *cur = reinterpret_cast(mTlvs); + cur < reinterpret_cast(mTlvs + mLength); + cur = cur->GetNext()) + { + if (cur->GetType() == NetworkDataTlv::kTypeCommissioningData) + { + data = cur->GetValue(); + length = cur->GetLength(); + break; + } + } + + VerifyOrExit(data && length, error = kThreadError_Drop); + + if (aLength == 0) + { + SuccessOrExit(error = message->Append(data, length)); + } + else + { + for (index = 0; index < aLength; index++) + { + for (MeshCoP::Tlv *cur = reinterpret_cast(data); + cur < reinterpret_cast(data + length); + cur = cur->GetNext()) + { + if (cur->GetType() == aTlvs[index]) + { + SuccessOrExit(error = message->Append(cur, sizeof(NetworkDataTlv) + cur->GetLength())); + break; + } + } + } + } + + SuccessOrExit(error = mCoapServer.SendMessage(*message, aMessageInfo)); + + otLogInfoMeshCoP("sent commissioning dataset get response\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } +} + +void Leader::SendCommissioningSetResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, + MeshCoP::StateTlv::State aState) +{ + ThreadError error = kThreadError_None; + Coap::Header responseHeader; + Message *message; + MeshCoP::StateTlv state; + + VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + responseHeader.Init(); + responseHeader.SetVersion(1); + responseHeader.SetType(Coap::Header::kTypeAcknowledgment); + responseHeader.SetCode(Coap::Header::kCodeChanged); + responseHeader.SetMessageId(aRequestHeader.GetMessageId()); + responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength()); + responseHeader.AppendContentFormatOption(Coap::Header::kApplicationOctetStream); + responseHeader.Finalize(); + SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength())); + + state.Init(); + state.SetState(aState); + SuccessOrExit(error = message->Append(&state, sizeof(state))); + + SuccessOrExit(error = mCoapServer.SendMessage(*message, aMessageInfo)); + + otLogInfoMeshCoP("sent commissioning dataset set response\n"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } +} + void Leader::RlocLookup(uint16_t aRloc16, bool &aIn, bool &aStable, uint8_t *aTlvs, uint8_t aTlvsLength) { NetworkDataTlv *cur = reinterpret_cast(aTlvs); diff --git a/src/core/thread/network_data_leader.hpp b/src/core/thread/network_data_leader.hpp index eae071195..175bd1408 100644 --- a/src/core/thread/network_data_leader.hpp +++ b/src/core/thread/network_data_leader.hpp @@ -281,6 +281,18 @@ private: bool IsStableUpdated(uint16_t aRloc16, uint8_t *aTlvs, uint8_t aTlvsLength, uint8_t *aTlvsBase, uint8_t aTlvsBaseLength); + static void HandleCommissioningSet(void *aContext, Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo); + void HandleCommissioningSet(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + static void HandleCommissioningGet(void *aContext, Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo); + void HandleCommissioningGet(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + void SendCommissioningGetResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, + uint8_t *aTlvs, uint8_t aLength); + void SendCommissioningSetResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo, + MeshCoP::StateTlv::State aState); /** * Thread Specification Constants @@ -302,6 +314,9 @@ private: uint8_t mStableVersion; uint8_t mVersion; + Coap::Resource mCommissioningDataGet; + Coap::Resource mCommissioningDataSet; + Coap::Server &mCoapServer; ThreadNetif &mNetif; }; diff --git a/src/core/thread/thread_uris.hpp b/src/core/thread/thread_uris.hpp index 436fce377..e9f2c9e81 100644 --- a/src/core/thread/thread_uris.hpp +++ b/src/core/thread/thread_uris.hpp @@ -194,6 +194,22 @@ namespace Thread { */ #define OPENTHREAD_URI_PANID_QUERY "c/pq" +/** + * @def OPENTHREAD_URI_COMMISSIONER_GET + * + * The URI Path for MGMT_COMMISSIONER_GET + * + */ +#define OPENTHREAD_URI_COMMISSIONER_GET "c/cg" + +/** + * @def OPENTHREAD_URI_COMMISSIONER_SET + * + * The URI Path for MGMT_COMMISSIONER_SET + * + */ +#define OPENTHREAD_URI_COMMISSIONER_SET "c/cs" + } // namespace Thread #endif // THREAD_URIS_HPP_