From 4f35cdb854f925100f7089f9fe6e699c6a21c0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Duda?= Date: Fri, 24 Feb 2017 21:13:59 +0100 Subject: [PATCH] [ICMPv6] Allow application to register ICMPv6 handler. (#1380) --- .../drivers/windows/otLwf/eventprocessing.c | 2 +- examples/drivers/windows/otLwf/precomp.h | 1 + examples/drivers/windows/otLwf/radio.c | 2 +- include/Makefile.am | 1 + include/openthread-icmp6.h | 111 ++++++++++++++++ include/openthread-ip6.h | 20 --- include/openthread-types.h | 109 ++++++++++++++-- src/cli/cli.cpp | 40 ++++-- src/cli/cli.hpp | 8 +- src/core/net/icmp6.cpp | 62 +++------ src/core/net/icmp6.hpp | 122 ++++-------------- src/core/net/ip6.cpp | 2 +- src/core/openthread.cpp | 17 ++- src/core/thread/address_resolver.cpp | 19 +-- src/core/thread/address_resolver_ftd.hpp | 6 +- src/core/thread/mle.cpp | 4 +- src/core/thread/mle_router.cpp | 4 +- src/ncp/ncp_base.cpp | 7 +- 18 files changed, 323 insertions(+), 214 deletions(-) create mode 100644 include/openthread-icmp6.h diff --git a/examples/drivers/windows/otLwf/eventprocessing.c b/examples/drivers/windows/otLwf/eventprocessing.c index b2be230ee..917fc6b45 100644 --- a/examples/drivers/windows/otLwf/eventprocessing.c +++ b/examples/drivers/windows/otLwf/eventprocessing.c @@ -786,7 +786,7 @@ otLwfEventWorkerThread( NT_ASSERT(otCtxToFilter(pFilter->otCtx) == pFilter); // Disable Icmp (ping) handling - otSetIcmpEchoEnabled(pFilter->otCtx, FALSE); + otIcmp6SetEchoEnabled(pFilter->otCtx, FALSE); // Register callbacks with OpenThread otSetStateChangedCallback(pFilter->otCtx, otLwfStateChangedCallback, pFilter); diff --git a/examples/drivers/windows/otLwf/precomp.h b/examples/drivers/windows/otLwf/precomp.h index 25b8fa7d3..d1ba9c86f 100644 --- a/examples/drivers/windows/otLwf/precomp.h +++ b/examples/drivers/windows/otLwf/precomp.h @@ -62,6 +62,7 @@ RtlCopyBufferToMdl( #include #include #include +#include #include #include #include diff --git a/examples/drivers/windows/otLwf/radio.c b/examples/drivers/windows/otLwf/radio.c index d00ddbe2e..cbdebaaba 100644 --- a/examples/drivers/windows/otLwf/radio.c +++ b/examples/drivers/windows/otLwf/radio.c @@ -85,7 +85,7 @@ otPlatReset( NT_ASSERT(otCtxToFilter(pFilter->otCtx) == pFilter); // Disable Icmp (ping) handling - otSetIcmpEchoEnabled(pFilter->otCtx, FALSE); + otIcmp6SetEchoEnabled(pFilter->otCtx, FALSE); // Register callbacks with OpenThread otSetStateChangedCallback(pFilter->otCtx, otLwfStateChangedCallback, pFilter); diff --git a/include/Makefile.am b/include/Makefile.am index aa4bd5fbf..17d04ff95 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -64,6 +64,7 @@ include_HEADERS = \ openthread-coap.h \ openthread-crypto.h \ openthread-diag.h \ + openthread-icmp6.h \ openthread-ip6.h \ openthread-jam-detection.h \ openthread-message.h \ diff --git a/include/openthread-icmp6.h b/include/openthread-icmp6.h new file mode 100644 index 000000000..64b69c338 --- /dev/null +++ b/include/openthread-icmp6.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief + * This file defines the top-level icmp6 functions for the OpenThread library. + */ + +#ifndef OPENTHREAD_ICMP6_H_ +#define OPENTHREAD_ICMP6_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @addtogroup icmp6 ICMPv6 + * + * @brief + * This module includes functions that control ICMPv6 communication. + * + * @{ + * + */ + +/** + * This function indicates whether or not ICMPv6 Echo processing is enabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval TRUE ICMPv6 Echo processing is enabled. + * @retval FALSE ICMPv6 Echo processing is disabled. + * + */ +bool otIcmp6IsEchoEnabled(otInstance *aInstance); + +/** + * This function sets whether or not ICMPv6 Echo processing is enabled. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aEnabled TRUE to enable ICMPv6 Echo processing, FALSE otherwise. + * + */ +void otIcmp6SetEchoEnabled(otInstance *aInstance, bool aEnabled); + +/** + * This function registers a handler to provide received ICMPv6 messages. + * + * @note A handler structure @p aHandler has to be stored in persistant (static) memory. + * OpenThread does not make a copy of handler structure. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aHandler A pointer to a handler conitaining callback that is called when + * an ICMPv6 message is received. + * + */ +ThreadError otIcmp6RegisterHandler(otInstance *aInstance, otIcmp6Handler *aHandler); + +/** + * This function sends an ICMPv6 Echo Request via the Thread interface. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aMessage A pointer to the message buffer containing the ICMPv6 payload. + * @param[in] aMessageInfo A reference to message information associated with @p aMessage. + * @param[in] aIdentifier An identifier to aid in matching Echo Replies to this Echo Request. + * May be zero. + * + */ +ThreadError otIcmp6SendEchoRequest(otInstance *aInstance, otMessage aMessage, + const otMessageInfo *aMessageInfo, uint16_t aIdentifier); + +/** + * @} + * + */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // OPENTHREAD_ICMP6_H_ diff --git a/include/openthread-ip6.h b/include/openthread-ip6.h index c7fba834e..0d9030286 100644 --- a/include/openthread-ip6.h +++ b/include/openthread-ip6.h @@ -342,26 +342,6 @@ void otSetReceiveIp6DatagramFilterEnabled(otInstance *aInstance, bool aEnabled); */ ThreadError otSendIp6Datagram(otInstance *aInstance, otMessage aMessage); -/** - * This function indicates whether or not ICMPv6 Echo processing is enabled. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * - * @retval TRUE ICMPv6 Echo processing is enabled. - * @retval FALSE ICMPv6 Echo processing is disabled. - * - */ -bool otIsIcmpEchoEnabled(otInstance *aInstance); - -/** - * This function sets whether or not ICMPv6 Echo processing is enabled. - * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aEnabled TRUE to enable ICMPv6 Echo processing, FALSE otherwise. - * - */ -void otSetIcmpEchoEnabled(otInstance *aInstance, bool aEnabled); - /** * @} * diff --git a/include/openthread-types.h b/include/openthread-types.h index b7e599f24..d87aeb3b1 100644 --- a/include/openthread-types.h +++ b/include/openthread-types.h @@ -329,6 +329,21 @@ struct otIp6Address typedef struct otIp6Address otIp6Address; + +/** + * This structure represents the local and peer IPv6 socket addresses. + */ +typedef struct otMessageInfo +{ + otIp6Address mSockAddr; ///< The local IPv6 address. + otIp6Address mPeerAddr; ///< The peer IPv6 address. + uint16_t mSockPort; ///< The local transport-layer port. + uint16_t mPeerPort; ///< The peer transport-layer port. + int8_t mInterfaceId; ///< An IPv6 interface identifier. + uint8_t mHopLimit; ///< The IPv6 Hop Limit. + const void *mLinkInfo; ///< A pointer to link-specific information. +} otMessageInfo; + /** * @addtogroup commands Commands * @@ -982,6 +997,86 @@ typedef struct void *mData; ///< Opaque data used by the implementation. } otMessageQueue; +/** + * @} + * + */ + +/** + * @addtogroup icmp6 ICMPv6 + * + * @brief + * This module includes functions that control ICMPv6 communication. + * + * @{ + * + */ + +/** + * ICMPv6 Message Types + * +*/ +typedef enum otIcmp6Type +{ + kIcmp6TypeDstUnreach = 1, ///< Destination Unreachable + kIcmp6TypeEchoRequest = 128, ///< Echo Request + kIcmp6TypeEchoReply = 129, ///< Echo Reply +} otIcmp6Type; + +/** + * ICMPv6 Message Codes + * + */ +typedef enum otIcmp6Code +{ + kIcmp6CodeDstUnreachNoRoute = 0, ///< Destination Unreachable No Route +} otIcmp6Code; + +#define OT_ICMP6_HEADER_DATA_SIZE 4 ///< Size of an message specific data of ICMPv6 Header. + +/** + * This structure represents an ICMPv6 header. + * + */ +OT_TOOL_PACKED_BEGIN +struct otIcmp6Header +{ + uint8_t mType; ///< Type + uint8_t mCode; ///< Code + uint16_t mChecksum; ///< Checksum + union + { + uint8_t m8[OT_ICMP6_HEADER_DATA_SIZE / sizeof(uint8_t)]; + uint16_t m16[OT_ICMP6_HEADER_DATA_SIZE / sizeof(uint16_t)]; + uint32_t m32[OT_ICMP6_HEADER_DATA_SIZE / sizeof(uint32_t)]; + } mData; ///< Message-specific data +} OT_TOOL_PACKED_END; + +typedef struct otIcmp6Header otIcmp6Header; + +/** + * This callback allows OpenThread to inform the application of a received ICMPv6 message. + * + * @param[in] aContext A pointer to arbitrary context information. + * @param[in] aMessage A pointer to the received message. + * @param[in] aMessageInfo A pointer to message information associated with @p aMessage. + * @param[in] aIcmpHeader A pointer to the received ICMPv6 header. + * + */ +typedef void (*otIcmp6ReceiveCallback)(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo, + const otIcmp6Header *aIcmpHeader); + +/** + * This structure implements ICMPv6 message handler. + * + */ +typedef struct otIcmp6Handler +{ + otIcmp6ReceiveCallback mReceiveCallback; + void *mContext; + struct otIcmp6Handler *mNext; +} otIcmp6Handler; + /** * @} * @@ -1007,20 +1102,6 @@ typedef struct otSockAddr int8_t mScopeId; ///< An IPv6 scope identifier. } otSockAddr; -/** - * This structure represents the local and peer IPv6 socket addresses. - */ -typedef struct otMessageInfo -{ - otIp6Address mSockAddr; ///< The local IPv6 address. - otIp6Address mPeerAddr; ///< The peer IPv6 address. - uint16_t mSockPort; ///< The local transport-layer port. - uint16_t mPeerPort; ///< The peer transport-layer port. - int8_t mInterfaceId; ///< An IPv6 interface identifier. - uint8_t mHopLimit; ///< The IPv6 Hop Limit. - const void *mLinkInfo; ///< A pointer to link-specific information. -} otMessageInfo; - /** * This callback allows OpenThread to inform the application of a received UDP message. */ diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 356929aa0..46f99c2da 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -144,10 +145,13 @@ Interpreter::Interpreter(otInstance *aInstance): mInstance(aInstance) { memset(mSlaacAddresses, 0, sizeof(mSlaacAddresses)); - mInstance->mIp6.mIcmp.SetEchoReplyHandler(&s_HandleEchoResponse, this); otSetStateChangedCallback(mInstance, &Interpreter::s_HandleNetifStateChanged, this); otSetReceiveDiagnosticGetCallback(mInstance, &Interpreter::s_HandleDiagnosticGetResponse, this); + mIcmpHandler.mReceiveCallback = Interpreter::s_HandleIcmpReceive; + mIcmpHandler.mContext = this; + otIcmp6RegisterHandler(mInstance, &mIcmpHandler); + #if OPENTHREAD_ENABLE_DHCP6_CLIENT memset(mDhcpAddresses, 0, sizeof(mDhcpAddresses)); #endif // OPENTHREAD_ENABLE_DHCP6_CLIENT @@ -1270,17 +1274,20 @@ exit: AppendResult(error); } -void Interpreter::s_HandleEchoResponse(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +void Interpreter::s_HandleIcmpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo, + const otIcmp6Header *aIcmpHeader) { - static_cast(aContext)->HandleEchoResponse(aMessage, aMessageInfo); + static_cast(aContext)->HandleIcmpReceive(*static_cast(aMessage), + *static_cast(aMessageInfo), + *static_cast(aIcmpHeader)); } -void Interpreter::HandleEchoResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +void Interpreter::HandleIcmpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, + const Ip6::IcmpHeader &aIcmpHeader) { - Ip6::IcmpHeader icmp6Header; uint32_t timestamp = 0; - aMessage.Read(aMessage.GetOffset(), sizeof(icmp6Header), &icmp6Header); + VerifyOrExit(aIcmpHeader.GetType() == kIcmp6TypeEchoReply, ;); sServer->OutputFormat("%d bytes from ", aMessage.GetLength() - aMessage.GetOffset()); sServer->OutputFormat("%x:%x:%x:%x:%x:%x:%x:%x", @@ -1292,15 +1299,18 @@ void Interpreter::HandleEchoResponse(Message &aMessage, const Ip6::MessageInfo & HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[5]), HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[6]), HostSwap16(aMessageInfo.GetPeerAddr().mFields.m16[7])); - sServer->OutputFormat(": icmp_seq=%d hlim=%d", icmp6Header.GetSequence(), aMessageInfo.mHopLimit); + sServer->OutputFormat(": icmp_seq=%d hlim=%d", aIcmpHeader.GetSequence(), aMessageInfo.mHopLimit); - if (aMessage.Read(aMessage.GetOffset() + sizeof(icmp6Header), sizeof(uint32_t), ×tamp) >= + if (aMessage.Read(aMessage.GetOffset(), sizeof(uint32_t), ×tamp) >= static_cast(sizeof(uint32_t))) { sServer->OutputFormat(" time=%dms", Timer::GetNow() - HostSwap32(timestamp)); } sServer->OutputFormat("\r\n"); + +exit: + return; } void Interpreter::ProcessPing(int argc, char *argv[]) @@ -1363,20 +1373,22 @@ void Interpreter::HandlePingTimer() { ThreadError error = kThreadError_None; uint32_t timestamp = HostSwap32(Timer::GetNow()); - Message *message; - VerifyOrExit((message = mInstance->mIp6.mIcmp.NewMessage(0)) != NULL, error = kThreadError_NoBufs); - SuccessOrExit(error = message->Append(×tamp, sizeof(timestamp))); - SuccessOrExit(error = message->SetLength(sLength)); + otMessage message; + const otMessageInfo *messageInfo = static_cast(&sMessageInfo); + + VerifyOrExit((message = otNewIp6Message(mInstance, true)) != NULL, error = kThreadError_NoBufs); + SuccessOrExit(error = otAppendMessage(message, ×tamp, sizeof(timestamp))); + SuccessOrExit(error = otSetMessageLength(message, sLength)); + SuccessOrExit(error = otIcmp6SendEchoRequest(mInstance, message, messageInfo, 1)); - SuccessOrExit(error = mInstance->mIp6.mIcmp.SendEchoRequest(*message, sMessageInfo)); sCount--; exit: if (error != kThreadError_None && message != NULL) { - message->Free(); + otFreeMessage(message); } if (sCount) diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 2bee59c15..d94af2ee3 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -218,7 +218,8 @@ private: void ProcessVersion(int argc, char *argv[]); void ProcessWhitelist(int argc, char *argv[]); - static void s_HandleEchoResponse(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + static void s_HandleIcmpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo, + const otIcmp6Header *aIcmpHeader); static void s_HandlePingTimer(void *aContext); static void s_HandleActiveScanResult(otActiveScanResult *aResult, void *aContext); static void s_HandleNetifStateChanged(uint32_t aFlags, void *aContext); @@ -229,7 +230,8 @@ private: 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 HandleIcmpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, + const Ip6::IcmpHeader &aIcmpHeader); void HandlePingTimer(); void HandleActiveScanResult(otActiveScanResult *aResult); void HandleNetifStateChanged(uint32_t aFlags); @@ -242,6 +244,7 @@ private: static const struct Command sCommands[]; Ip6::MessageInfo sMessageInfo; + Server *sServer; uint16_t sLength; uint16_t sCount; @@ -253,6 +256,7 @@ private: otDhcpAddress mDhcpAddresses[OPENTHREAD_CONFIG_NUM_DHCP_PREFIXES]; #endif // OPENTHREAD_ENABLE_DHCP6_CLIENT + otIcmp6Handler mIcmpHandler; otInstance *mInstance; }; diff --git a/src/core/net/icmp6.cpp b/src/core/net/icmp6.cpp index 65a5ad90d..9ad8fb42f 100644 --- a/src/core/net/icmp6.cpp +++ b/src/core/net/icmp6.cpp @@ -50,8 +50,6 @@ namespace Ip6 { Icmp::Icmp(Ip6 &aIp6): mHandlers(NULL), mEchoSequence(1), - mEchoReplyHandler(NULL), - mEchoReplyContext(NULL), mIsEchoEnabled(true), mIp6(aIp6) { @@ -62,11 +60,11 @@ Message *Icmp::NewMessage(uint16_t aReserved) return mIp6.NewMessage(sizeof(IcmpHeader) + aReserved); } -ThreadError Icmp::RegisterCallbacks(IcmpHandler &aHandler) +ThreadError Icmp::RegisterHandler(IcmpHandler &aHandler) { ThreadError error = kThreadError_None; - for (IcmpHandler *cur = mHandlers; cur; cur = cur->mNext) + for (IcmpHandler *cur = mHandlers; cur; cur = cur->GetNext()) { if (cur == &aHandler) { @@ -81,13 +79,8 @@ exit: return error; } -void Icmp::SetEchoReplyHandler(EchoReplyHandler aHandler, void *aContext) -{ - mEchoReplyHandler = aHandler; - mEchoReplyContext = aContext; -} - -ThreadError Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo) +ThreadError Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, + uint16_t aIdentifier) { ThreadError error = kThreadError_None; MessageInfo messageInfoLocal; @@ -96,8 +89,8 @@ ThreadError Icmp::SendEchoRequest(Message &aMessage, const MessageInfo &aMessage messageInfoLocal = aMessageInfo; icmpHeader.Init(); - icmpHeader.SetType(IcmpHeader::kTypeEchoRequest); - icmpHeader.SetId(1); + icmpHeader.SetType(kIcmp6TypeEchoRequest); + icmpHeader.SetId(aIdentifier); icmpHeader.SetSequence(mEchoSequence++); SuccessOrExit(error = aMessage.Prepend(&icmpHeader, sizeof(icmpHeader))); @@ -160,35 +153,22 @@ ThreadError Icmp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo) checksum = aMessage.UpdateChecksum(checksum, aMessage.GetOffset(), payloadLength); VerifyOrExit(checksum == 0xffff, ;); - switch (icmp6Header.GetType()) + if (mIsEchoEnabled && (icmp6Header.GetType() == kIcmp6TypeEchoRequest)) { - case IcmpHeader::kTypeEchoRequest: - return HandleEchoRequest(aMessage, aMessageInfo); + HandleEchoRequest(aMessage, aMessageInfo); + } - case IcmpHeader::kTypeEchoReply: - return HandleEchoReply(aMessage, aMessageInfo); + aMessage.MoveOffset(sizeof(icmp6Header)); - case IcmpHeader::kTypeDstUnreach: - return HandleDstUnreach(aMessage, aMessageInfo, icmp6Header); + for (IcmpHandler *handler = mHandlers; handler; handler = handler->GetNext()) + { + handler->HandleReceiveMessage(aMessage, aMessageInfo, icmp6Header); } exit: return error; } -ThreadError Icmp::HandleDstUnreach(Message &aMessage, const MessageInfo &aMessageInfo, - const IcmpHeader &aIcmpheader) -{ - aMessage.MoveOffset(sizeof(aIcmpheader)); - - for (IcmpHandler *handler = mHandlers; handler; handler = handler->mNext) - { - handler->HandleDstUnreach(aMessage, aMessageInfo, aIcmpheader); - } - - return kThreadError_None; -} - ThreadError Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo) { ThreadError error = kThreadError_None; @@ -197,16 +177,14 @@ ThreadError Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo MessageInfo replyMessageInfo; uint16_t payloadLength; - VerifyOrExit(mIsEchoEnabled, ;); - otLogInfoIcmp("Received Echo Request"); icmp6Header.Init(); - icmp6Header.SetType(IcmpHeader::kTypeEchoReply); + icmp6Header.SetType(kIcmp6TypeEchoReply); if ((replyMessage = mIp6.NewMessage(0)) == NULL) { - otLogDebgIcmp("icmp fail"); + otLogDebgIcmp("Failed to allocate a new message"); ExitNow(); } @@ -241,16 +219,6 @@ exit: return error; } -ThreadError Icmp::HandleEchoReply(Message &aMessage, const MessageInfo &aMessageInfo) -{ - VerifyOrExit(mIsEchoEnabled && mEchoReplyHandler, ;); - - mEchoReplyHandler(mEchoReplyContext, aMessage, aMessageInfo); - -exit: - return kThreadError_None; -} - ThreadError Icmp::UpdateChecksum(Message &aMessage, uint16_t aChecksum) { aChecksum = aMessage.UpdateChecksum(aChecksum, aMessage.GetOffset(), diff --git a/src/core/net/icmp6.hpp b/src/core/net/icmp6.hpp index e7515f62d..44c92a5ab 100644 --- a/src/core/net/icmp6.hpp +++ b/src/core/net/icmp6.hpp @@ -34,6 +34,7 @@ #ifndef ICMP6_HPP_ #define ICMP6_HPP_ +#include #include #include @@ -52,35 +53,12 @@ namespace Ip6 { * */ -enum -{ - kIcmp6DataSize = 4, -}; - -/** - * This structure represents an ICMPv6 header. - * - */ -OT_TOOL_PACKED_BEGIN -struct IcmpHeaderPoD -{ - uint8_t mType; ///< Type - uint8_t mCode; ///< Code - uint16_t mChecksum; ///< Checksum - union - { - uint8_t m8[kIcmp6DataSize / sizeof(uint8_t)]; - uint16_t m16[kIcmp6DataSize / sizeof(uint16_t)]; - uint32_t m32[kIcmp6DataSize / sizeof(uint32_t)]; - } mData; ///< Message-specific data -} OT_TOOL_PACKED_END; - -/** +/* * This class implements ICMPv6 header generation and parsing. * */ OT_TOOL_PACKED_BEGIN -class IcmpHeader: private IcmpHeaderPoD +class IcmpHeader: public otIcmp6Header { public: /** @@ -93,12 +71,13 @@ public: * ICMPv6 Message Types * */ - enum Type - { - kTypeDstUnreach = 1, ///< Destination Unreachable - kTypeEchoRequest = 128, ///< Echo Request - kTypeEchoReply = 129, ///< Echo Reply - }; + typedef otIcmp6Type Type; + + /** + * ICMPv6 Message Codes + * + */ + typedef otIcmp6Code Code; /** * This method returns the ICMPv6 message type. @@ -116,15 +95,6 @@ public: */ void SetType(Type aType) { mType = static_cast(aType); } - /** - * ICMPv6 Message Codes - * - */ - enum Code - { - kCodeDstUnreachNoRoute = 0, ///< Destination Unreachable No Route - }; - /** * This method returns the ICMPv6 message code. * @@ -194,7 +164,7 @@ public: * @returns The byte offset of the Checksum field. * */ - static uint8_t GetChecksumOffset(void) { return offsetof(IcmpHeaderPoD, mChecksum); } + static uint8_t GetChecksumOffset(void) { return offsetof(otIcmp6Header, mChecksum); } /** * This static method returns the byte offset of the ICMPv6 payload. @@ -202,7 +172,7 @@ public: * @returns The Byte offset of the ICMPv6 payload. * */ - static uint8_t GetDataOffset(void) { return offsetof(IcmpHeaderPoD, mData); } + static uint8_t GetDataOffset(void) { return offsetof(otIcmp6Header, mData); } } OT_TOOL_PACKED_END; @@ -210,45 +180,30 @@ public: * This class implements ICMPv6 message handlers. * */ -class IcmpHandler +class IcmpHandler : public otIcmp6Handler { friend class Icmp; public: - /** - * This function pointer is called when receiving an ICMPv6 Destination Unreachable message. - * - * @param[in] aContext A pointer to arbitrary context information. - * @param[in] aMessage A reference to the received message. - * @param[in] aMessageInfo A reference to message information associated with @p aMessage. - * @param[in] aIcmpHeader A reference to the received ICMPv6 header. - * - */ - typedef void (*DstUnreachHandler)(void *aContext, Message &aMesage, const MessageInfo &aMessageInfo, - const IcmpHeader &aIcmpHeader); - /** * This constructor creates an ICMPv6 message handler. * - * @param[in] aDstUnreachHandler A pointer to the function that is called when receiving a Destination - * Unreachable message. - * @param[in] aContext A pointer to arbitrary context information. + * @param[in] aCallback A pointer to the function that is called when receiving an ICMPv6 message. + * @param[in] aContext A pointer to arbitrary context information. * */ - IcmpHandler(DstUnreachHandler aDstUnreachHandler, void *aContext) { - mDstUnreachHandler = aDstUnreachHandler; - mContext = aContext; - mNext = NULL; + IcmpHandler(otIcmp6ReceiveCallback aCallback, void *aContext) { + mReceiveCallback = aCallback; + mContext = aContext; + mNext = NULL; } private: - void HandleDstUnreach(Message &message, const MessageInfo &messageInfo, const IcmpHeader &icmp6Header) { - mDstUnreachHandler(mContext, message, messageInfo, icmp6Header); + void HandleReceiveMessage(Message &message, const MessageInfo &messageInfo, const IcmpHeader &icmp6Header) { + mReceiveCallback(mContext, &message, &messageInfo, &icmp6Header); } - DstUnreachHandler mDstUnreachHandler; - void *mContext; - IcmpHandler *mNext; + IcmpHandler *GetNext(void) { return static_cast(mNext); } }; /** @@ -277,46 +232,29 @@ public: Message *NewMessage(uint16_t aReserved); /** - * This method registers ICMPv6 handlers. + * This method registers ICMPv6 handler. * * @param[in] aHandler A reference to the ICMPv6 handler. * - * @retval kThreadError_None Successfully registered the ICMPv6 handler. + * @retval kThreadError_None Successfully registered the ICMPv6 handler. * @retval kThreadError_Already The ICMPv6 handler is already registered. * */ - ThreadError RegisterCallbacks(IcmpHandler &aHandler); - - /** - * This function pointer is called when receiving an ICMPv6 Echo Reply in response to an Echo Request. - * - * @param[in] aContext A pointer to arbitrary context information. - * @param[in] aMessage A reference to the received message. - * @param[in] aMessageInfo A reference to message information associated with @p aMessage. - * - */ - typedef void (*EchoReplyHandler)(void *aContext, Message &aMessage, const MessageInfo &aMessageInfo); - - /** - * This method sets the Echo Reply handler. - * - * @param[in] aHandler A pointer to a function that is called when receiving an ICMPv6 Echo Reply. - * @param[in] aContext A pointer to arbitrary context information. - * - */ - void SetEchoReplyHandler(EchoReplyHandler aHandler, void *aContext); + ThreadError RegisterHandler(IcmpHandler &aHandler); /** * This method sends an ICMPv6 Echo Request message. * * @param[in] aMessage A reference to the Echo Request payload. * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. + * @param[in] aIdentifier An identifier to aid in matching Echo Replies to this Echo Request. + * May be zero. * * @retval kThreadError_None Successfully enqueued the ICMPv6 Echo Request message. * @retval kThreadError_NoBufs Insufficient buffers available to generate an ICMPv6 Echo Request message. * */ - ThreadError SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo); + ThreadError SendEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo, uint16_t aIdentifier); /** * This method sends an ICMPv6 error message. @@ -376,15 +314,11 @@ public: void SetEchoEnabled(bool aEnabled); private: - ThreadError HandleDstUnreach(Message &aMessage, const MessageInfo &aMessageInfo, const IcmpHeader &aIcmpHeader); ThreadError HandleEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo); - ThreadError HandleEchoReply(Message &aMessage, const MessageInfo &aMessageInfo); IcmpHandler *mHandlers; uint16_t mEchoSequence; - EchoReplyHandler mEchoReplyHandler; - void *mEchoReplyContext; bool mIsEchoEnabled; Ip6 &mIp6; diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 57b18cad6..0bcc36a41 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -617,7 +617,7 @@ ThreadError Ip6::ProcessReceiveCallback(const Message &aMessage, const MessageIn aMessage.Read(aMessage.GetOffset(), sizeof(icmp), &icmp); // do not pass ICMP Echo Request messages - VerifyOrExit(icmp.GetType() != IcmpHeader::kTypeEchoRequest, error = kThreadError_NoRoute); + VerifyOrExit(icmp.GetType() != kIcmp6TypeEchoRequest, error = kThreadError_NoRoute); } break; diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index 559af5a57..a22b1555f 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -1752,16 +1752,29 @@ ThreadError otSendUdp(otUdpSocket *aSocket, otMessage aMessage, const otMessageI *static_cast(aMessageInfo)); } -bool otIsIcmpEchoEnabled(otInstance *aInstance) +bool otIcmp6IsEchoEnabled(otInstance *aInstance) { return aInstance->mIp6.mIcmp.IsEchoEnabled(); } -void otSetIcmpEchoEnabled(otInstance *aInstance, bool aEnabled) +void otIcmp6SetEchoEnabled(otInstance *aInstance, bool aEnabled) { aInstance->mIp6.mIcmp.SetEchoEnabled(aEnabled); } +ThreadError otIcmp6RegisterHandler(otInstance *aInstance, otIcmp6Handler *aHandler) +{ + return aInstance->mIp6.mIcmp.RegisterHandler(*static_cast(aHandler)); +} + +ThreadError otIcmp6SendEchoRequest(otInstance *aInstance, otMessage aMessage, + const otMessageInfo *aMessageInfo, uint16_t aIdentifier) +{ + return aInstance->mIp6.mIcmp.SendEchoRequest(*static_cast(aMessage), + *static_cast(aMessageInfo), + aIdentifier); +} + uint8_t otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond) { uint8_t rval; diff --git a/src/core/thread/address_resolver.cpp b/src/core/thread/address_resolver.cpp index 7905dcce8..74daa5cf2 100644 --- a/src/core/thread/address_resolver.cpp +++ b/src/core/thread/address_resolver.cpp @@ -55,7 +55,7 @@ AddressResolver::AddressResolver(ThreadNetif &aThreadNetif) : mAddressError(OPENTHREAD_URI_ADDRESS_ERROR, &AddressResolver::HandleAddressError, this), mAddressQuery(OPENTHREAD_URI_ADDRESS_QUERY, &AddressResolver::HandleAddressQuery, this), mAddressNotification(OPENTHREAD_URI_ADDRESS_NOTIFY, &AddressResolver::HandleAddressNotification, this), - mIcmpHandler(&AddressResolver::HandleDstUnreach, this), + mIcmpHandler(&AddressResolver::HandleIcmpReceive, this), mTimer(aThreadNetif.GetIp6().mTimerScheduler, &AddressResolver::HandleTimer, this), mNetif(aThreadNetif) { @@ -65,7 +65,7 @@ AddressResolver::AddressResolver(ThreadNetif &aThreadNetif) : mNetif.GetCoapServer().AddResource(mAddressQuery); mNetif.GetCoapServer().AddResource(mAddressNotification); - mNetif.GetIp6().mIcmp.RegisterCallbacks(mIcmpHandler); + mNetif.GetIp6().mIcmp.RegisterHandler(mIcmpHandler); } void AddressResolver::Clear() @@ -645,20 +645,23 @@ void AddressResolver::HandleTimer() } } -void AddressResolver::HandleDstUnreach(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo, - const Ip6::IcmpHeader &aIcmpHeader) +void AddressResolver::HandleIcmpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo, + const otIcmp6Header *aIcmpHeader) { - static_cast(aContext)->HandleDstUnreach(aMessage, aMessageInfo, aIcmpHeader); + static_cast(aContext)->HandleIcmpReceive(*static_cast(aMessage), + *static_cast(aMessageInfo), + *static_cast(aIcmpHeader)); (void)aMessageInfo; } -void AddressResolver::HandleDstUnreach(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, - const Ip6::IcmpHeader &aIcmpHeader) +void AddressResolver::HandleIcmpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, + const Ip6::IcmpHeader &aIcmpHeader) { Ip6::Header ip6Header; - VerifyOrExit(aIcmpHeader.GetCode() == Ip6::IcmpHeader::kCodeDstUnreachNoRoute, ;); + VerifyOrExit(aIcmpHeader.GetType() == kIcmp6TypeDstUnreach, ;); + VerifyOrExit(aIcmpHeader.GetCode() == kIcmp6CodeDstUnreachNoRoute, ;); VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(ip6Header), &ip6Header) == sizeof(ip6Header), ;); for (int i = 0; i < kCacheEntries; i++) diff --git a/src/core/thread/address_resolver_ftd.hpp b/src/core/thread/address_resolver_ftd.hpp index 25ebc694d..79a0e605a 100644 --- a/src/core/thread/address_resolver_ftd.hpp +++ b/src/core/thread/address_resolver_ftd.hpp @@ -174,9 +174,9 @@ private: const otMessageInfo *aMessageInfo); void HandleAddressNotification(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - static void HandleDstUnreach(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo, - const Ip6::IcmpHeader &aIcmpHeader); - void HandleDstUnreach(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Ip6::IcmpHeader &aIcmpHeader); + static void HandleIcmpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo, + const otIcmp6Header *aIcmpHeader); + void HandleIcmpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo, const Ip6::IcmpHeader &aIcmpHeader); static void HandleTimer(void *aContext); void HandleTimer(void); diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index f49b12631..dce229260 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -3203,8 +3203,8 @@ ThreadError Mle::CheckReachability(uint16_t aMeshSource, uint16_t aMeshDest, Ip6 messageInfo.GetPeerAddr().mFields.m16[7] = HostSwap16(aMeshSource); messageInfo.SetInterfaceId(mNetif.GetInterfaceId()); - mNetif.GetIp6().mIcmp.SendError(Ip6::IcmpHeader::kTypeDstUnreach, - Ip6::IcmpHeader::kCodeDstUnreachNoRoute, + mNetif.GetIp6().mIcmp.SendError(kIcmp6TypeDstUnreach, + kIcmp6CodeDstUnreachNoRoute, messageInfo, aIp6Header); exit: diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 29e6c31f2..acdddad76 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3632,8 +3632,8 @@ ThreadError MleRouter::CheckReachability(uint16_t aMeshSource, uint16_t aMeshDes messageInfo.GetPeerAddr().mFields.m16[7] = HostSwap16(aMeshSource); messageInfo.SetInterfaceId(mNetif.GetInterfaceId()); - mNetif.GetIp6().mIcmp.SendError(Ip6::IcmpHeader::kTypeDstUnreach, - Ip6::IcmpHeader::kCodeDstUnreachNoRoute, + mNetif.GetIp6().mIcmp.SendError(kIcmp6TypeDstUnreach, + kIcmp6CodeDstUnreachNoRoute, messageInfo, aIp6Header); return kThreadError_Drop; diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index f265676db..da8c7498a 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #if OPENTHREAD_ENABLE_JAM_DETECTION #include #endif @@ -515,7 +516,7 @@ NcpBase::NcpBase(otInstance *aInstance): otSetStateChangedCallback(mInstance, &NcpBase::HandleNetifStateChanged, this); otSetReceiveIp6DatagramCallback(mInstance, &NcpBase::HandleDatagramFromStack, this); otSetLinkPcapCallback(mInstance, &NcpBase::HandleRawFrame, static_cast(this)); - otSetIcmpEchoEnabled(mInstance, false); + otIcmp6SetEchoEnabled(mInstance, false); otSetReceiveIp6DatagramFilterEnabled(mInstance, true); mUpdateChangedPropsTask.Post(); @@ -2711,7 +2712,7 @@ ThreadError NcpBase::GetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t header, s SPINEL_CMD_PROP_VALUE_IS, key, SPINEL_DATATYPE_BOOL_S, - otIsIcmpEchoEnabled(mInstance) + otIcmp6IsEchoEnabled(mInstance) ); } @@ -4379,7 +4380,7 @@ ThreadError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t header, s if (parsedLength > 0) { - otSetIcmpEchoEnabled(mInstance, isEnabled); + otIcmp6SetEchoEnabled(mInstance, isEnabled); errorCode = HandleCommandPropertyGet(header, key); }