diff --git a/include/openthread.h b/include/openthread.h index 5ea43a184..323905afa 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -1908,9 +1908,10 @@ OTAPI ThreadError OTCALL otGetParentInfo(otInstance *aInstance, otRouterInfo *aP OTAPI uint8_t OTCALL otGetStableNetworkDataVersion(otInstance *aInstance); /** - * This function pointer is called when an DIAG_GET.rsp is received. + * This function pointer is called when Network Diagnostic Get response is received. * - * @param[in] aMessage A pointer to the message buffer containing the received DIAG_GET.rsp payload. + * @param[in] aMessage A pointer to the message buffer containing the received Network Diagnostic + * Get response payload. * @param[in] aMessageInfo A pointer to the message info for @p aMessage. * @param[in] aContext A pointer to application-specific context. * @@ -1919,11 +1920,11 @@ typedef void (*otReceiveDiagnosticGetCallback)(otMessage aMessage, const otMessa void *aContext); /** - * This function registers a callback to provide received raw DIAG_GET.rsp payload. + * This function registers a callback to provide received raw Network Diagnostic Get response payload. * * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aCallback A pointer to a function that is called when an DIAG_GET.rsp is received or - * NULL to disable the callback. + * @param[in] aCallback A pointer to a function that is called when Network Diagnostic Get response + * is received or NULL to disable the callback. * @param[in] aCallbackContext A pointer to application-specific context. * */ @@ -1931,7 +1932,7 @@ void otSetReceiveDiagnosticGetCallback(otInstance *aInstance, otReceiveDiagnosti void *aCallbackContext); /** - * Send a Network Diagnostic Get request + * Send a Network Diagnostic Get request. * * @param[in] aDestination A pointer to destination address. * @param[in] aTlvTypes An array of Network Diagnostic TLV types. @@ -1941,7 +1942,7 @@ OTAPI ThreadError OTCALL otSendDiagnosticGet(otInstance *aInstance, const otIp6A const uint8_t aTlvTypes[], uint8_t aCount); /** - * Send a Network Diagnostic Reset request + * Send a Network Diagnostic Reset request. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aDestination A pointer to destination address. diff --git a/src/core/thread/network_diagnostic.cpp b/src/core/thread/network_diagnostic.cpp index 6906978f9..681aaa7f3 100644 --- a/src/core/thread/network_diagnostic.cpp +++ b/src/core/thread/network_diagnostic.cpp @@ -56,7 +56,9 @@ namespace Thread { namespace NetworkDiagnostic { NetworkDiagnostic::NetworkDiagnostic(ThreadNetif &aThreadNetif) : - mDiagnosticGet(OPENTHREAD_URI_DIAGNOSTIC_GET, &NetworkDiagnostic::HandleDiagnosticGet, this), + mDiagnosticGetRequest(OPENTHREAD_URI_DIAGNOSTIC_GET_REQUEST, &NetworkDiagnostic::HandleDiagnosticGetRequest, this), + mDiagnosticGetQuery(OPENTHREAD_URI_DIAGNOSTIC_GET_QUERY, &NetworkDiagnostic::HandleDiagnosticGetQuery, this), + mDiagnosticGetAnswer(OPENTHREAD_URI_DIAGNOSTIC_GET_ANSWER, &NetworkDiagnostic::HandleDiagnosticGetAnswer, this), mDiagnosticReset(OPENTHREAD_URI_DIAGNOSTIC_RESET, &NetworkDiagnostic::HandleDiagnosticReset, this), mCoapServer(aThreadNetif.GetCoapServer()), mCoapClient(aThreadNetif.GetCoapClient()), @@ -66,7 +68,9 @@ NetworkDiagnostic::NetworkDiagnostic(ThreadNetif &aThreadNetif) : mReceiveDiagnosticGetCallback(NULL), mReceiveDiagnosticGetCallbackContext(NULL) { - mCoapServer.AddResource(mDiagnosticGet); + mCoapServer.AddResource(mDiagnosticGetRequest); + mCoapServer.AddResource(mDiagnosticGetQuery); + mCoapServer.AddResource(mDiagnosticGetAnswer); mCoapServer.AddResource(mDiagnosticReset); } @@ -77,20 +81,54 @@ void NetworkDiagnostic::SetReceiveDiagnosticGetCallback(otReceiveDiagnosticGetCa mReceiveDiagnosticGetCallbackContext = aCallbackContext; } +ThreadError NetworkDiagnostic::SendEmptyAck(Coap::Header &aHeader, const Ip6::MessageInfo &aMessageInfo) +{ + ThreadError error = kThreadError_None; + Message *message = NULL; + Coap::Header header; + Ip6::MessageInfo messageInfo(aMessageInfo); + + VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs); + + header.SetDefaultResponseHeader(aHeader); + + SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); + + SuccessOrExit(error = mCoapServer.SendMessage(*message, messageInfo)); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } + + return error; +} + ThreadError NetworkDiagnostic::SendDiagnosticGet(const Ip6::Address &aDestination, const uint8_t aTlvTypes[], uint8_t aCount) { ThreadError error; - Ip6::SockAddr sockaddr; Message *message; Coap::Header header; Ip6::MessageInfo messageInfo; + otCoapResponseHandler handler = NULL; - sockaddr.mPort = kCoapUdpPort; + if (aDestination.IsMulticast()) + { + header.Init(kCoapTypeNonConfirmable, kCoapRequestGet); + header.SetToken(Coap::Header::kDefaultTokenLength); + header.AppendUriPathOptions(OPENTHREAD_URI_DIAGNOSTIC_GET_QUERY); + } + else + { + handler = &NetworkDiagnostic::HandleDiagnosticGetResponse; + header.Init(kCoapTypeConfirmable, kCoapRequestGet); + header.SetToken(Coap::Header::kDefaultTokenLength); + header.AppendUriPathOptions(OPENTHREAD_URI_DIAGNOSTIC_GET_REQUEST); + } - header.Init(kCoapTypeConfirmable, kCoapRequestGet); - header.SetToken(Coap::Header::kDefaultTokenLength); - header.AppendUriPathOptions(OPENTHREAD_URI_DIAGNOSTIC_GET); header.SetPayloadMarker(); VerifyOrExit((message = mCoapClient.NewMessage(header)) != NULL, error = kThreadError_NoBufs); @@ -102,8 +140,7 @@ ThreadError NetworkDiagnostic::SendDiagnosticGet(const Ip6::Address &aDestinatio messageInfo.SetPeerPort(kCoapUdpPort); messageInfo.SetInterfaceId(mNetif.GetInterfaceId()); - SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo, - &NetworkDiagnostic::HandleDiagnosticGetResponse, this)); + SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo, handler, this)); otLogInfoNetDiag("Sent diagnostic get"); @@ -120,72 +157,59 @@ exit: void NetworkDiagnostic::HandleDiagnosticGetResponse(void *aContext, otCoapHeader *aHeader, otMessage aMessage, const otMessageInfo *aMessageInfo, ThreadError aResult) { - static_cast(aContext)->HandleDiagnosticGetResponse(static_cast(aHeader), - static_cast(aMessage), - static_cast(aMessageInfo), + static_cast(aContext)->HandleDiagnosticGetResponse(*static_cast(aHeader), + *static_cast(aMessage), + *static_cast(aMessageInfo), aResult); } -void NetworkDiagnostic::HandleDiagnosticGetResponse(Coap::Header *aHeader, Message *aMessage, - const Ip6::MessageInfo *aMessageInfo, ThreadError aResult) +void NetworkDiagnostic::HandleDiagnosticGetResponse(Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo, + ThreadError aResult) { VerifyOrExit(aResult == kThreadError_None, ;); - VerifyOrExit(aHeader->GetCode() == kCoapResponseChanged, ;); + VerifyOrExit(aHeader.GetCode() == kCoapResponseChanged, ;); - otLogInfoNetDiag("Network Diagnostic get response received"); + otLogInfoNetDiag("Received diagnostic get response"); - VerifyOrExit(mReceiveDiagnosticGetCallback != NULL, ;); - - // Call application defined callback. - mReceiveDiagnosticGetCallback(aMessage, aMessageInfo, mReceiveDiagnosticGetCallbackContext); + if (mReceiveDiagnosticGetCallback) + { + mReceiveDiagnosticGetCallback(&aMessage, &aMessageInfo, mReceiveDiagnosticGetCallbackContext); + } exit: return; } -ThreadError NetworkDiagnostic::SendDiagnosticReset(const Ip6::Address &aDestination, const uint8_t aTlvTypes[], - uint8_t aCount) +void NetworkDiagnostic::HandleDiagnosticGetAnswer(void *aContext, otCoapHeader *aHeader, otMessage aMessage, + const otMessageInfo *aMessageInfo) { - ThreadError error; - Ip6::SockAddr sockaddr; - Message *message; - Coap::Header header; - Ip6::MessageInfo messageInfo; - - header.Init(kCoapTypeConfirmable, kCoapRequestPost); - header.SetToken(Coap::Header::kDefaultTokenLength); - header.AppendUriPathOptions(OPENTHREAD_URI_DIAGNOSTIC_RESET); - header.SetPayloadMarker(); - - VerifyOrExit((message = mCoapClient.NewMessage(header)) != NULL, error = kThreadError_NoBufs); - - SuccessOrExit(error = message->Append(aTlvTypes, aCount)); - - messageInfo.SetPeerAddr(aDestination); - messageInfo.SetSockAddr(mMle.GetMeshLocal16()); - messageInfo.SetPeerPort(kCoapUdpPort); - messageInfo.SetInterfaceId(mNetif.GetInterfaceId()); - - SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo)); - - otLogInfoNetDiag("Sent network diagnostic reset"); - -exit: - - if (error != kThreadError_None && message != NULL) - { - message->Free(); - } - - return error; + static_cast(aContext)->HandleDiagnosticGetAnswer(*static_cast(aHeader), + *static_cast(aMessage), + *static_cast(aMessageInfo)); } -void NetworkDiagnostic::HandleDiagnosticGet(void *aContext, otCoapHeader *aHeader, otMessage aMessage, - const otMessageInfo *aMessageInfo) +void NetworkDiagnostic::HandleDiagnosticGetAnswer(Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo) { - static_cast(aContext)->HandleDiagnosticGet( - *static_cast(aHeader), *static_cast(aMessage), - *static_cast(aMessageInfo)); + ThreadError error = kThreadError_None; + + VerifyOrExit(aHeader.GetType() == kCoapTypeConfirmable && + aHeader.GetCode() == kCoapRequestPost, ;); + + otLogInfoNetDiag("Diagnostic get answer received"); + + if (mReceiveDiagnosticGetCallback) + { + mReceiveDiagnosticGetCallback(&aMessage, &aMessageInfo, mReceiveDiagnosticGetCallbackContext); + } + + SuccessOrExit(error = SendEmptyAck(aHeader, aMessageInfo)); + + otLogInfoNetDiag("Sent diagnostic answer acknowledgment"); + +exit: + return; } ThreadError NetworkDiagnostic::AppendIPv6AddressList(Message &aMessage) @@ -260,13 +284,241 @@ exit: return error; } -void NetworkDiagnostic::HandleDiagnosticGet(Coap::Header &aHeader, Message &aMessage, - const Ip6::MessageInfo &aMessageInfo) +ThreadError NetworkDiagnostic::FillRequestedTlvs(Message &aRequest, Message &aResponse, + NetworkDiagnosticTlv &aNetworkDiagnosticTlv) +{ + ThreadError error = kThreadError_None; + uint16_t offset = 0; + uint8_t type; + + offset = aRequest.GetOffset() + sizeof(NetworkDiagnosticTlv); + + for (uint32_t i = 0; i < aNetworkDiagnosticTlv.GetLength(); i++) + { + VerifyOrExit(aRequest.Read(offset, sizeof(type), &type) == sizeof(type), error = kThreadError_Drop); + + otLogInfoNetDiag("Received diagnostic get type %d", type); + + switch (type) + { + case NetworkDiagnosticTlv::kExtMacAddress: + { + ExtMacAddressTlv tlv; + tlv.Init(); + tlv.SetMacAddr(*mNetif.GetMac().GetExtAddress()); + SuccessOrExit(error = aResponse.Append(&tlv, sizeof(tlv))); + break; + } + + case NetworkDiagnosticTlv::kAddress16: + { + Address16Tlv tlv; + tlv.Init(); + tlv.SetRloc16(mMle.GetRloc16()); + SuccessOrExit(error = aResponse.Append(&tlv, sizeof(tlv))); + break; + } + + case NetworkDiagnosticTlv::kMode: + { + ModeTlv tlv; + tlv.Init(); + tlv.SetMode(mMle.GetDeviceMode()); + SuccessOrExit(error = aResponse.Append(&tlv, sizeof(tlv))); + break; + } + + case NetworkDiagnosticTlv::kTimeout: + { + if ((mMle.GetDeviceMode() & ModeTlv::kModeRxOnWhenIdle) == 0) + { + TimeoutTlv tlv; + tlv.Init(); + tlv.SetTimeout(mMle.GetTimeout()); + SuccessOrExit(error = aResponse.Append(&tlv, sizeof(tlv))); + } + + break; + } + + case NetworkDiagnosticTlv::kConnectivity: + { + ConnectivityTlv tlv; + tlv.Init(); + mMle.FillConnectivityTlv(*reinterpret_cast(&tlv)); + SuccessOrExit(error = aResponse.Append(&tlv, sizeof(tlv))); + break; + } + + case NetworkDiagnosticTlv::kRoute: + { + RouteTlv tlv; + tlv.Init(); + mMle.FillRouteTlv(*reinterpret_cast(&tlv)); + SuccessOrExit(error = aResponse.Append(&tlv, tlv.GetSize())); + break; + } + + case NetworkDiagnosticTlv::kLeaderData: + { + LeaderDataTlv tlv; + memcpy(&tlv, &mMle.GetLeaderDataTlv(), sizeof(tlv)); + tlv.Init(); + SuccessOrExit(error = aResponse.Append(&tlv, tlv.GetSize())); + break; + } + + case NetworkDiagnosticTlv::kNetworkData: + { + NetworkDataTlv tlv; + tlv.Init(); + mMle.FillNetworkDataTlv((*reinterpret_cast(&tlv)), true); + SuccessOrExit(error = aResponse.Append(&tlv, tlv.GetSize())); + break; + } + + case NetworkDiagnosticTlv::kIPv6AddressList: + { + SuccessOrExit(error = AppendIPv6AddressList(aResponse)); + break; + } + + case NetworkDiagnosticTlv::kMacCounters: + { + MacCountersTlv tlv; + memset(&tlv, 0, sizeof(tlv)); + tlv.Init(); + mMac.FillMacCountersTlv(tlv); + SuccessOrExit(error = aResponse.Append(&tlv, tlv.GetSize())); + break; + } + + case NetworkDiagnosticTlv::kBatteryLevel: + { + // TODO Need more api from driver + BatteryLevelTlv tlv; + tlv.Init(); + tlv.SetBatteryLevel(100); + SuccessOrExit(error = aResponse.Append(&tlv, tlv.GetSize())); + break; + } + + case NetworkDiagnosticTlv::kSupplyVoltage: + { + // TODO Need more api from driver + SupplyVoltageTlv tlv; + tlv.Init(); + tlv.SetSupplyVoltage(0); + SuccessOrExit(error = aResponse.Append(&tlv, tlv.GetSize())); + break; + } + + case NetworkDiagnosticTlv::kChildTable: + { + SuccessOrExit(error = AppendChildTable(aResponse)); + break; + } + + case NetworkDiagnosticTlv::kChannelPages: + { + ChannelPagesTlv tlv; + tlv.Init(); + tlv.GetChannelPages()[0] = 0; + tlv.SetLength(1); + SuccessOrExit(error = aResponse.Append(&tlv, tlv.GetSize())); + break; + } + + default: + ExitNow(error = kThreadError_Drop); + } + + offset += sizeof(type); + } + +exit: + return error; +} + +void NetworkDiagnostic::HandleDiagnosticGetQuery(void *aContext, otCoapHeader *aHeader, otMessage aMessage, + const otMessageInfo *aMessageInfo) +{ + static_cast(aContext)->HandleDiagnosticGetQuery( + *static_cast(aHeader), *static_cast(aMessage), + *static_cast(aMessageInfo)); +} + +void NetworkDiagnostic::HandleDiagnosticGetQuery(Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo) +{ + ThreadError error = kThreadError_None; + Message *message = NULL; + NetworkDiagnosticTlv networkDiagnosticTlv; + Coap::Header header; + Ip6::MessageInfo messageInfo; + + VerifyOrExit(aHeader.GetCode() == kCoapRequestGet, error = kThreadError_Drop); + + otLogInfoNetDiag("Received diagnostic get query"); + + VerifyOrExit((aMessage.Read(aMessage.GetOffset(), sizeof(NetworkDiagnosticTlv), + &networkDiagnosticTlv) == sizeof(NetworkDiagnosticTlv)), error = kThreadError_Drop); + + VerifyOrExit(networkDiagnosticTlv.GetType() == NetworkDiagnosticTlv::kTypeList, error = kThreadError_Drop); + + VerifyOrExit((static_cast(&networkDiagnosticTlv)->IsValid()), error = kThreadError_Drop); + + // DIAG_GET.qry may be sent as a confirmable message. + if (aHeader.GetType() == kCoapTypeConfirmable) + { + SuccessOrExit(error = SendEmptyAck(aHeader, aMessageInfo)); + + otLogInfoNetDiag("Sent diagnostic get query acknowledgment"); + } + + header.Init(kCoapTypeConfirmable, kCoapRequestPost); + header.SetToken(Coap::Header::kDefaultTokenLength); + header.AppendUriPathOptions(OPENTHREAD_URI_DIAGNOSTIC_GET_ANSWER); + + if (networkDiagnosticTlv.GetLength() > 0) + { + header.SetPayloadMarker(); + } + + VerifyOrExit((message = mCoapClient.NewMessage(header)) != NULL, error = kThreadError_NoBufs); + + messageInfo.SetPeerAddr(aMessageInfo.GetPeerAddr()); + messageInfo.SetSockAddr(mMle.GetMeshLocal16()); + messageInfo.SetPeerPort(kCoapUdpPort); + messageInfo.SetInterfaceId(mNetif.GetInterfaceId()); + + SuccessOrExit(error = FillRequestedTlvs(aMessage, *message, networkDiagnosticTlv)); + + SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo, NULL, this)); + + otLogInfoNetDiag("Sent diagnostic get answer"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } +} + +void NetworkDiagnostic::HandleDiagnosticGetRequest(void *aContext, otCoapHeader *aHeader, otMessage aMessage, + const otMessageInfo *aMessageInfo) +{ + static_cast(aContext)->HandleDiagnosticGetRequest( + *static_cast(aHeader), *static_cast(aMessage), + *static_cast(aMessageInfo)); +} + +void NetworkDiagnostic::HandleDiagnosticGetRequest(Coap::Header &aHeader, Message &aMessage, + const Ip6::MessageInfo &aMessageInfo) { ThreadError error = kThreadError_None; Message *message = NULL; - uint16_t offset = 0; - uint8_t type; NetworkDiagnosticTlv networkDiagnosticTlv; Coap::Header header; Ip6::MessageInfo messageInfo(aMessageInfo); @@ -294,155 +546,11 @@ void NetworkDiagnostic::HandleDiagnosticGet(Coap::Header &aHeader, Message &aMes SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); - offset = aMessage.GetOffset() + sizeof(NetworkDiagnosticTlv); - - for (uint8_t i = 0; i < networkDiagnosticTlv.GetLength(); i++) - { - - VerifyOrExit(aMessage.Read(offset, sizeof(type), &type) == sizeof(type), error = kThreadError_Drop); - - otLogInfoNetDiag("Received diagnostic get type %d", type); - - switch (type) - { - case NetworkDiagnosticTlv::kExtMacAddress: - { - ExtMacAddressTlv tlv; - tlv.Init(); - tlv.SetMacAddr(*mNetif.GetMac().GetExtAddress()); - SuccessOrExit(error = message->Append(&tlv, sizeof(tlv))); - break; - } - - case NetworkDiagnosticTlv::kAddress16: - { - Address16Tlv tlv; - tlv.Init(); - tlv.SetRloc16(mMle.GetRloc16()); - SuccessOrExit(error = message->Append(&tlv, sizeof(tlv))); - break; - } - - case NetworkDiagnosticTlv::kMode: - { - ModeTlv tlv; - tlv.Init(); - tlv.SetMode(mMle.GetDeviceMode()); - SuccessOrExit(error = message->Append(&tlv, sizeof(tlv))); - break; - } - - case NetworkDiagnosticTlv::kTimeout: - { - if ((mMle.GetDeviceMode() & ModeTlv::kModeRxOnWhenIdle) == 0) - { - TimeoutTlv tlv; - tlv.Init(); - tlv.SetTimeout(mMle.GetTimeout()); - SuccessOrExit(error = message->Append(&tlv, sizeof(tlv))); - } - - break; - } - - case NetworkDiagnosticTlv::kConnectivity: - { - ConnectivityTlv tlv; - tlv.Init(); - mMle.FillConnectivityTlv(*reinterpret_cast(&tlv)); - SuccessOrExit(error = message->Append(&tlv, sizeof(tlv))); - break; - } - - case NetworkDiagnosticTlv::kRoute: - { - RouteTlv tlv; - tlv.Init(); - mMle.FillRouteTlv(*reinterpret_cast(&tlv)); - SuccessOrExit(error = message->Append(&tlv, tlv.GetSize())); - break; - } - - case NetworkDiagnosticTlv::kLeaderData: - { - LeaderDataTlv tlv; - memcpy(&tlv, &mMle.GetLeaderDataTlv(), sizeof(tlv)); - tlv.Init(); - SuccessOrExit(error = message->Append(&tlv, tlv.GetSize())); - break; - } - - case NetworkDiagnosticTlv::kNetworkData: - { - NetworkDataTlv tlv; - tlv.Init(); - mMle.FillNetworkDataTlv((*reinterpret_cast(&tlv)), true); - SuccessOrExit(error = message->Append(&tlv, tlv.GetSize())); - break; - } - - case NetworkDiagnosticTlv::kIPv6AddressList: - { - SuccessOrExit(error = AppendIPv6AddressList(*message)); - break; - } - - case NetworkDiagnosticTlv::kMacCounters: - { - MacCountersTlv tlv; - memset(&tlv, 0, sizeof(tlv)); - tlv.Init(); - mMac.FillMacCountersTlv(tlv); - SuccessOrExit(error = message->Append(&tlv, tlv.GetSize())); - break; - } - - case NetworkDiagnosticTlv::kBatteryLevel: - { - // TODO Need more api from driver - BatteryLevelTlv tlv; - tlv.Init(); - tlv.SetBatteryLevel(100); - SuccessOrExit(error = message->Append(&tlv, tlv.GetSize())); - break; - } - - case NetworkDiagnosticTlv::kSupplyVoltage: - { - // TODO Need more api from driver - SupplyVoltageTlv tlv; - tlv.Init(); - tlv.SetSupplyVoltage(0); - SuccessOrExit(error = message->Append(&tlv, tlv.GetSize())); - break; - } - - case NetworkDiagnosticTlv::kChildTable: - { - SuccessOrExit(error = AppendChildTable(*message)); - break; - } - - case NetworkDiagnosticTlv::kChannelPages: - { - ChannelPagesTlv tlv; - tlv.Init(); - tlv.GetChannelPages()[0] = 0; - tlv.SetLength(1); - SuccessOrExit(error = message->Append(&tlv, tlv.GetSize())); - break; - } - - default: - ExitNow(); - } - - offset += sizeof(type); - } + SuccessOrExit(error = FillRequestedTlvs(aMessage, *message, networkDiagnosticTlv)); SuccessOrExit(error = mCoapServer.SendMessage(*message, messageInfo)); - otLogInfoNetDiag("Sent diagnostic get acknowledgment"); + otLogInfoNetDiag("Sent diagnostic get response"); exit: @@ -452,6 +560,42 @@ exit: } } +ThreadError NetworkDiagnostic::SendDiagnosticReset(const Ip6::Address &aDestination, const uint8_t aTlvTypes[], + uint8_t aCount) +{ + ThreadError error; + Message *message; + Coap::Header header; + Ip6::MessageInfo messageInfo; + + header.Init(kCoapTypeConfirmable, kCoapRequestPost); + header.SetToken(Coap::Header::kDefaultTokenLength); + header.AppendUriPathOptions(OPENTHREAD_URI_DIAGNOSTIC_RESET); + header.SetPayloadMarker(); + + VerifyOrExit((message = mCoapClient.NewMessage(header)) != NULL, error = kThreadError_NoBufs); + + SuccessOrExit(error = message->Append(aTlvTypes, aCount)); + + messageInfo.SetPeerAddr(aDestination); + messageInfo.SetSockAddr(mMle.GetMeshLocal16()); + messageInfo.SetPeerPort(kCoapUdpPort); + messageInfo.SetInterfaceId(mNetif.GetInterfaceId()); + + SuccessOrExit(error = mCoapClient.SendMessage(*message, messageInfo)); + + otLogInfoNetDiag("Sent network diagnostic reset"); + +exit: + + if (error != kThreadError_None && message != NULL) + { + message->Free(); + } + + return error; +} + void NetworkDiagnostic::HandleDiagnosticReset(void *aContext, otCoapHeader *aHeader, otMessage aMessage, const otMessageInfo *aMessageInfo) { @@ -468,8 +612,6 @@ void NetworkDiagnostic::HandleDiagnosticReset(Coap::Header &aHeader, Message &aM uint16_t offset = 0; uint8_t type; NetworkDiagnosticTlv networkDiagnosticTlv; - Coap::Header header; - Ip6::MessageInfo messageInfo(aMessageInfo); otLogInfoNetDiag("Received diagnostic reset request"); @@ -483,12 +625,6 @@ void NetworkDiagnostic::HandleDiagnosticReset(Coap::Header &aHeader, Message &aM VerifyOrExit((static_cast(&networkDiagnosticTlv)->IsValid()), error = kThreadError_Drop); - VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs); - - header.SetDefaultResponseHeader(aHeader); - - SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength())); - offset = aMessage.GetOffset() + sizeof(NetworkDiagnosticTlv); for (uint8_t i = 0; i < networkDiagnosticTlv.GetLength(); i++) @@ -508,7 +644,7 @@ void NetworkDiagnostic::HandleDiagnosticReset(Coap::Header &aHeader, Message &aM } } - SuccessOrExit(error = mCoapServer.SendMessage(*message, messageInfo)); + SuccessOrExit(error = SendEmptyAck(aHeader, aMessageInfo)); otLogInfoNetDiag("Sent diagnostic reset acknowledgment"); diff --git a/src/core/thread/network_diagnostic.hpp b/src/core/thread/network_diagnostic.hpp index dd05b89e1..ee4698813 100644 --- a/src/core/thread/network_diagnostic.hpp +++ b/src/core/thread/network_diagnostic.hpp @@ -49,6 +49,7 @@ namespace NetworkDiagnostic { class IPv6AddressListTlv; class ChildTableTlv; +class NetworkDiagnosticTlv; /** * @addtogroup core-netdiag @@ -73,17 +74,18 @@ public: explicit NetworkDiagnostic(ThreadNetif &aThreadNetif); /** - * This method registers a callback to provide received raw DIAG_GET.rsp payload. + * This method registers a callback to provide received raw DIAG_GET.rsp or an DIAG_GET.ans payload. * - * @param[in] aCallback A pointer to a function that is called when an DIAG_GET.rsp is received or - * NULL to disable the callback. + * @param[in] aCallback A pointer to a function that is called when an DIAG_GET.rsp or an DIAG_GET.ans + * is received or NULL to disable the callback. * @param[in] aCallbackContext A pointer to application-specific context. * */ void SetReceiveDiagnosticGetCallback(otReceiveDiagnosticGetCallback aCallback, void *aCallbackContext); /** - * This method sends Diagnostic Get request. + * This method sends Diagnostic Get request. If the @p aDestination is of multicast type, the DIAG_GET.qry + * message is sent or the DIAG_GET.req otherwise. * * @param[in] aDestination A reference to the destination address. * @param[in] aTlvTypes An array of Network Diagnostic TLV types. @@ -102,39 +104,37 @@ public: */ ThreadError SendDiagnosticReset(const Ip6::Address &aDestination, const uint8_t aTlvTypes[], uint8_t aCount); - /** - * This method fills IPv6AddressListTlv. - * - * @param[out] aTlv A reference to the tlv. - * - */ - ThreadError AppendIPv6AddressList(Message &aMessage); - - /** - * This method fills ChildTableTlv. - * - * @param[out] aTlv A reference to the tlv. - * - */ - ThreadError AppendChildTable(Message &aMessage); - private: + + ThreadError AppendIPv6AddressList(Message &aMessage); + ThreadError AppendChildTable(Message &aMessage); + ThreadError FillRequestedTlvs(Message &aRequest, Message &aResponse, NetworkDiagnosticTlv &aNetworkDiagnosticTlv); + ThreadError SendEmptyAck(Coap::Header &aHeader, const Ip6::MessageInfo &aMessageInfo); + + static void HandleDiagnosticGetRequest(void *aContext, otCoapHeader *aHeader, otMessage aMessage, + const otMessageInfo *aMessageInfo); + void HandleDiagnosticGetRequest(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + static void HandleDiagnosticGetQuery(void *aContext, otCoapHeader *aHeader, otMessage aMessage, + const otMessageInfo *aMessageInfo); + void HandleDiagnosticGetQuery(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + static void HandleDiagnosticGetResponse(void *aContext, otCoapHeader *aHeader, otMessage aMessage, const otMessageInfo *aMessageInfo, ThreadError aResult); - void HandleDiagnosticGetResponse(Coap::Header *aHeader, Message *aMessage, - const Ip6::MessageInfo *aMessageInfo, ThreadError aResult); + void HandleDiagnosticGetResponse(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo, + ThreadError aResult); - static void HandleDiagnosticGet(void *aContext, otCoapHeader *aHeader, otMessage aMessage, - const otMessageInfo *aMessageInfo); - void HandleDiagnosticGet(Thread::Coap::Header &aHeader, Thread::Message &aMessage, - const Thread::Ip6::MessageInfo &aMessageInfo); + static void HandleDiagnosticGetAnswer(void *aContext, otCoapHeader *aHeader, otMessage aMessage, + const otMessageInfo *aMessageInfo); + void HandleDiagnosticGetAnswer(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); static void HandleDiagnosticReset(void *aContext, otCoapHeader *aHeader, otMessage aMessage, const otMessageInfo *aMessageInfo); - void HandleDiagnosticReset(Coap::Header &aHeader, Message &aMessage, - const Ip6::MessageInfo &aMessageInfo); + void HandleDiagnosticReset(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - Coap::Resource mDiagnosticGet; + Coap::Resource mDiagnosticGetRequest; + Coap::Resource mDiagnosticGetQuery; + Coap::Resource mDiagnosticGetAnswer; Coap::Resource mDiagnosticReset; Coap::Server &mCoapServer; Coap::Client &mCoapClient; diff --git a/src/core/thread/thread_uris.hpp b/src/core/thread/thread_uris.hpp index af466d412..5a86b2e2e 100644 --- a/src/core/thread/thread_uris.hpp +++ b/src/core/thread/thread_uris.hpp @@ -40,7 +40,7 @@ namespace Thread { * The URI Path for Address Query. * */ -#define OPENTHREAD_URI_ADDRESS_QUERY "a/aq" +#define OPENTHREAD_URI_ADDRESS_QUERY "a/aq" /** * @def OPENTHREAD_URI_ADDRESS_NOTIFY @@ -48,7 +48,7 @@ namespace Thread { * The URI Path for Address Notify. * */ -#define OPENTHREAD_URI_ADDRESS_NOTIFY "a/an" +#define OPENTHREAD_URI_ADDRESS_NOTIFY "a/an" /** * @def OPENTHREAD_URI_ADDRESS_ERROR @@ -56,7 +56,7 @@ namespace Thread { * The URI Path for Address Error. * */ -#define OPENTHREAD_URI_ADDRESS_ERROR "a/ae" +#define OPENTHREAD_URI_ADDRESS_ERROR "a/ae" /** * @def OPENTHREAD_URI_ADDRESS_RELEASE @@ -64,7 +64,7 @@ namespace Thread { * The URI Path for Address Release. * */ -#define OPENTHREAD_URI_ADDRESS_RELEASE "a/ar" +#define OPENTHREAD_URI_ADDRESS_RELEASE "a/ar" /** * @def OPENTHREAD_URI_ADDRESS_SOLICIT @@ -72,7 +72,7 @@ namespace Thread { * The URI Path for Address Solicit. * */ -#define OPENTHREAD_URI_ADDRESS_SOLICIT "a/as" +#define OPENTHREAD_URI_ADDRESS_SOLICIT "a/as" /** * @def OPENTHREAD_URI_ACTIVE_GET @@ -80,7 +80,7 @@ namespace Thread { * The URI Path for MGMT_ACTIVE_GET * */ -#define OPENTHREAD_URI_ACTIVE_GET "c/ag" +#define OPENTHREAD_URI_ACTIVE_GET "c/ag" /** * @def OPENTHREAD_URI_ACTIVE_SET @@ -88,7 +88,7 @@ namespace Thread { * The URI Path for MGMT_ACTIVE_SET * */ -#define OPENTHREAD_URI_ACTIVE_SET "c/as" +#define OPENTHREAD_URI_ACTIVE_SET "c/as" /** * @def OPENTHREAD_URI_DATASET_CHANGED @@ -96,7 +96,7 @@ namespace Thread { * The URI Path for MGMT_DATASET_CHANGED * */ -#define OPENTHREAD_URI_DATASET_CHANGED "c/dc" +#define OPENTHREAD_URI_DATASET_CHANGED "c/dc" /** * @def OPENTHREAD_URI_ENERGY_SCAN @@ -104,7 +104,7 @@ namespace Thread { * The URI Path for Energy Scan * */ -#define OPENTHREAD_URI_ENERGY_SCAN "c/es" +#define OPENTHREAD_URI_ENERGY_SCAN "c/es" /** * @def OPENTHREAD_URI_ENERGY_REPORT @@ -112,7 +112,7 @@ namespace Thread { * The URI Path for Energy Report * */ -#define OPENTHREAD_URI_ENERGY_REPORT "c/er" +#define OPENTHREAD_URI_ENERGY_REPORT "c/er" /** * @def OPENTHREAD_URI_PENDING_GET @@ -120,7 +120,7 @@ namespace Thread { * The URI Path for MGMT_PENDING_GET * */ -#define OPENTHREAD_URI_PENDING_GET "c/pg" +#define OPENTHREAD_URI_PENDING_GET "c/pg" /** * @def OPENTHREAD_URI_PENDING_SET @@ -128,7 +128,7 @@ namespace Thread { * The URI Path for MGMT_PENDING_SET * */ -#define OPENTHREAD_URI_PENDING_SET "c/ps" +#define OPENTHREAD_URI_PENDING_SET "c/ps" /** * @def OPENTHREAD_URI_SERVER_DATA @@ -136,7 +136,7 @@ namespace Thread { * The URI Path for Server Data Registration. * */ -#define OPENTHREAD_URI_SERVER_DATA "a/sd" +#define OPENTHREAD_URI_SERVER_DATA "a/sd" /** * @def OPENTHREAD_URI_ANNOUNCE_BEGIN @@ -144,7 +144,7 @@ namespace Thread { * The URI Path for Announce Begin. * */ -#define OPENTHREAD_URI_ANNOUNCE_BEGIN "c/ab" +#define OPENTHREAD_URI_ANNOUNCE_BEGIN "c/ab" /** * @def OPENTHREAD_URI_RELAY_RX @@ -152,7 +152,7 @@ namespace Thread { * The URI Path for Relay RX. * */ -#define OPENTHREAD_URI_RELAY_RX "c/rx" +#define OPENTHREAD_URI_RELAY_RX "c/rx" /** * @def OPENTHREAD_URI_RELAY_TX @@ -160,7 +160,7 @@ namespace Thread { * The URI Path for Relay TX. * */ -#define OPENTHREAD_URI_RELAY_TX "c/tx" +#define OPENTHREAD_URI_RELAY_TX "c/tx" /** * @def OPENTHREAD_URI_JOINER_FINALIZE @@ -168,7 +168,7 @@ namespace Thread { * The URI Path for Joiner Finalize * */ -#define OPENTHREAD_URI_JOINER_FINALIZE "c/jf" +#define OPENTHREAD_URI_JOINER_FINALIZE "c/jf" /** * @def OPENTHREAD_URI_JOINER_ENTRUST @@ -176,7 +176,7 @@ namespace Thread { * The URI Path for Joiner Entrust * */ -#define OPENTHREAD_URI_JOINER_ENTRUST "c/je" +#define OPENTHREAD_URI_JOINER_ENTRUST "c/je" /** * @def OPENTHREAD_URI_LEADER_PETITION @@ -184,7 +184,7 @@ namespace Thread { * The URI Path for Leader Petition * */ -#define OPENTHREAD_URI_LEADER_PETITION "c/lp" +#define OPENTHREAD_URI_LEADER_PETITION "c/lp" /** * @def OPENTHREAD_URI_LEADER_KEEP_ALIVE @@ -192,7 +192,7 @@ namespace Thread { * The URI Path for Leader Keep Alive * */ -#define OPENTHREAD_URI_LEADER_KEEP_ALIVE "c/la" +#define OPENTHREAD_URI_LEADER_KEEP_ALIVE "c/la" /** * @def OPENTHREAD_URI_PANID_CONFLICT @@ -200,7 +200,7 @@ namespace Thread { * The URI Path for PAN ID Conflict * */ -#define OPENTHREAD_URI_PANID_CONFLICT "c/pc" +#define OPENTHREAD_URI_PANID_CONFLICT "c/pc" /** * @def OPENTHREAD_URI_PANID_QUERY @@ -208,7 +208,7 @@ namespace Thread { * The URI Path for PAN ID Query * */ -#define OPENTHREAD_URI_PANID_QUERY "c/pq" +#define OPENTHREAD_URI_PANID_QUERY "c/pq" /** * @def OPENTHREAD_URI_COMMISSIONER_GET @@ -216,7 +216,7 @@ namespace Thread { * The URI Path for MGMT_COMMISSIONER_GET * */ -#define OPENTHREAD_URI_COMMISSIONER_GET "c/cg" +#define OPENTHREAD_URI_COMMISSIONER_GET "c/cg" /** * @def OPENTHREAD_URI_COMMISSIONER_SET @@ -224,15 +224,31 @@ namespace Thread { * The URI Path for MGMT_COMMISSIONER_SET * */ -#define OPENTHREAD_URI_COMMISSIONER_SET "c/cs" +#define OPENTHREAD_URI_COMMISSIONER_SET "c/cs" /** - * @def OPENTHREAD_URI_DIAGNOSTIC_GET + * @def OPENTHREAD_URI_DIAGNOSTIC_GET_REQUEST * - * The URI Path for Network Diagnostic Get. + * The URI Path for Network Diagnostic Get Request. * */ -#define OPENTHREAD_URI_DIAGNOSTIC_GET "d/dg" +#define OPENTHREAD_URI_DIAGNOSTIC_GET_REQUEST "d/dg" + +/** + * @def OPENTHREAD_URI_DIAGNOSTIC_GET_QUERY + * + * The URI Path for Network Diagnostic Get Query. + * + */ +#define OPENTHREAD_URI_DIAGNOSTIC_GET_QUERY "d/dq" + +/** + * @def OPENTHREAD_URI_DIAGNOSTIC_GET_ANSWER + * + * The URI Path for Network Diagnostic Get Answer. + * + */ +#define OPENTHREAD_URI_DIAGNOSTIC_GET_ANSWER "d/da" /** * @def OPENTHREAD_URI_DIAG_RST @@ -240,7 +256,7 @@ namespace Thread { * The URI Path for Network Diagnostic Reset. * */ -#define OPENTHREAD_URI_DIAGNOSTIC_RESET "d/dr" +#define OPENTHREAD_URI_DIAGNOSTIC_RESET "d/dr" } // namespace Thread