diff --git a/doc/spinel-protocol-src/spinel-prop-ipv6.md b/doc/spinel-protocol-src/spinel-prop-ipv6.md index 88438761b..ddf4b246c 100644 --- a/doc/spinel-protocol-src/spinel-prop-ipv6.md +++ b/doc/spinel-protocol-src/spinel-prop-ipv6.md @@ -47,3 +47,23 @@ Default value is `false`. Array of structures containing: * `6`: Multicast IPv6 Address + +### PROP 103: PROP_IPv6_ICMP_PING_OFFLOAD_MODE +* Type: Read-Write +* Packed-Encoding: `C` +* Unit: Enumeration + +Allow the NCP to directly respond to ICMP ping requests. If this is +turned on, ping request ICMP packets will not be passed to the host. + +This property allows enabling responses sent to unicast only, multicast +only, or both. + +Values: + +* 0: `IPV6_ICMP_PING_OFFLOAD_DISABLED` +* 1: `IPV6_ICMP_PING_OFFLOAD_UNICAST_ONLY` +* 2: `IPV6_ICMP_PING_OFFLOAD_MULTICAST_ONLY` +* 3: `IPV6_ICMP_PING_OFFLOAD_ALL` + +Default value is `IPV6_ICMP_PING_OFFLOAD_DISABLED`. diff --git a/examples/drivers/windows/otLwf/eventprocessing.c b/examples/drivers/windows/otLwf/eventprocessing.c index c5e0361a1..7ba75f2e8 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 - otIcmp6SetEchoEnabled(pFilter->otCtx, FALSE); + otIcmp6SetEchoMode(pFilter->otCtx, OT_ICMP6_ECHO_HANDLER_DISABLED); // Register callbacks with OpenThread otSetStateChangedCallback(pFilter->otCtx, otLwfStateChangedCallback, pFilter); diff --git a/examples/drivers/windows/otLwf/radio.c b/examples/drivers/windows/otLwf/radio.c index ea88f5931..03eb8b9b6 100644 --- a/examples/drivers/windows/otLwf/radio.c +++ b/examples/drivers/windows/otLwf/radio.c @@ -82,7 +82,7 @@ otPlatReset( NT_ASSERT(otCtxToFilter(pFilter->otCtx) == pFilter); // Disable Icmp (ping) handling - otIcmp6SetEchoEnabled(pFilter->otCtx, FALSE); + otIcmp6SetEchoMode(pFilter->otCtx, OT_ICMP6_ECHO_HANDLER_DISABLED); // Register callbacks with OpenThread otSetStateChangedCallback(pFilter->otCtx, otLwfStateChangedCallback, pFilter); diff --git a/include/openthread/icmp6.h b/include/openthread/icmp6.h index fefd3a168..3c991e8b4 100644 --- a/include/openthread/icmp6.h +++ b/include/openthread/icmp6.h @@ -123,25 +123,38 @@ typedef struct otIcmp6Handler struct otIcmp6Handler *mNext; ///< A pointer to the next handler in the list. } otIcmp6Handler; +/** + * ICMPv6 Echo Reply Modes + * + */ +typedef enum otIcmp6EchoMode { + OT_ICMP6_ECHO_HANDLER_DISABLED = 0, ///< ICMPv6 Echo processing disabled + OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY = 1, ///< ICMPv6 Echo processing enabled only for unicast requests only + OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY = 2, ///< ICMPv6 Echo processing enabled only for multicast requests only + OT_ICMP6_ECHO_HANDLER_ALL = 3, ///< ICMPv6 Echo processing enabled for unicast and multicast requests +} otIcmp6EchoMode; + /** * 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. + * @retval OT_ICMP6_ECHO_HANDLER_DISABLED ICMPv6 Echo processing is disabled. + * @retval OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY ICMPv6 Echo processing enabled for unicast requests only + * @retval OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY ICMPv6 Echo processing enabled for multicast requests only + * @retval OT_ICMP6_ECHO_HANDLER_ALL ICMPv6 Echo processing enabled for unicast and multicast requests * */ -bool otIcmp6IsEchoEnabled(otInstance *aInstance); +otIcmp6EchoMode otIcmp6GetEchoMode(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. + * @param[in] aMode The ICMPv6 Echo processing mode. * */ -void otIcmp6SetEchoEnabled(otInstance *aInstance, bool aEnabled); +void otIcmp6SetEchoMode(otInstance *aInstance, otIcmp6EchoMode aMode); /** * This function registers a handler to provide received ICMPv6 messages. @@ -150,7 +163,7 @@ void otIcmp6SetEchoEnabled(otInstance *aInstance, bool aEnabled); * 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 + * @param[in] aHandler A pointer to a handler containing callback that is called when * an ICMPv6 message is received. * */ diff --git a/src/core/api/icmp6_api.cpp b/src/core/api/icmp6_api.cpp index 20887524c..78ed9ce2d 100644 --- a/src/core/api/icmp6_api.cpp +++ b/src/core/api/icmp6_api.cpp @@ -39,18 +39,18 @@ using namespace ot; -bool otIcmp6IsEchoEnabled(otInstance *aInstance) +otIcmp6EchoMode otIcmp6GetEchoMode(otInstance *aInstance) { Instance &instance = *static_cast(aInstance); - return instance.GetIp6().GetIcmp().IsEchoEnabled(); + return instance.GetIp6().GetIcmp().GetEchoMode(); } -void otIcmp6SetEchoEnabled(otInstance *aInstance, bool aEnabled) +void otIcmp6SetEchoMode(otInstance *aInstance, otIcmp6EchoMode aMode) { Instance &instance = *static_cast(aInstance); - instance.GetIp6().GetIcmp().SetEchoEnabled(aEnabled); + instance.GetIp6().GetIcmp().SetEchoMode(aMode); } otError otIcmp6RegisterHandler(otInstance *aInstance, otIcmp6Handler *aHandler) diff --git a/src/core/net/icmp6.cpp b/src/core/net/icmp6.cpp index 47d885b90..0b77cb06b 100644 --- a/src/core/net/icmp6.cpp +++ b/src/core/net/icmp6.cpp @@ -53,7 +53,7 @@ Icmp::Icmp(Instance &aInstance) : InstanceLocator(aInstance) , mHandlers(NULL) , mEchoSequence(1) - , mIsEchoEnabled(true) + , mEchoMode(OT_ICMP6_ECHO_HANDLER_ALL) { } @@ -157,7 +157,7 @@ otError Icmp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo) checksum = aMessage.UpdateChecksum(checksum, aMessage.GetOffset(), payloadLength); VerifyOrExit(checksum == 0xffff, error = OT_ERROR_PARSE); - if (mIsEchoEnabled && (icmp6Header.GetType() == IcmpHeader::kTypeEchoRequest)) + if (icmp6Header.GetType() == IcmpHeader::kTypeEchoRequest) { HandleEchoRequest(aMessage, aMessageInfo); } @@ -173,6 +173,29 @@ exit: return error; } +bool Icmp::ShouldHandleEchoRequest(const MessageInfo &aMessageInfo) +{ + bool rval = false; + + switch (mEchoMode) + { + case OT_ICMP6_ECHO_HANDLER_DISABLED: + rval = false; + break; + case OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY: + rval = !aMessageInfo.GetSockAddr().IsMulticast(); + break; + case OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY: + rval = aMessageInfo.GetSockAddr().IsMulticast(); + break; + case OT_ICMP6_ECHO_HANDLER_ALL: + rval = true; + break; + } + + return rval; +} + otError Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMessageInfo) { otError error = OT_ERROR_NONE; @@ -181,6 +204,8 @@ otError Icmp::HandleEchoRequest(Message &aRequestMessage, const MessageInfo &aMe MessageInfo replyMessageInfo; uint16_t payloadLength; + VerifyOrExit(ShouldHandleEchoRequest(aMessageInfo)); + otLogInfoIcmp(GetInstance(), "Received Echo Request"); icmp6Header.Init(); diff --git a/src/core/net/icmp6.hpp b/src/core/net/icmp6.hpp index 7a87bdd85..116121f07 100644 --- a/src/core/net/icmp6.hpp +++ b/src/core/net/icmp6.hpp @@ -325,7 +325,7 @@ public: * @retval FALSE ICMPv6 Echo processing is disabled. * */ - bool IsEchoEnabled(void) { return mIsEchoEnabled; } + otIcmp6EchoMode GetEchoMode(void) const { return mEchoMode; } /** * This method sets whether or not ICMPv6 Echo processing is enabled. @@ -333,15 +333,24 @@ public: * @param[in] aEnabled TRUE to enable ICMPv6 Echo processing, FALSE otherwise. * */ - void SetEchoEnabled(bool aEnabled) { mIsEchoEnabled = aEnabled; } + void SetEchoMode(otIcmp6EchoMode aMode) { mEchoMode = aMode; } + + /** + * This method indicates whether or not the ICMPv6 Echo Request should be handled. + * + * @retval TRUE if OpenThread should respond with an ICMPv6 Echo Reply. + * @retval FALSE if OpenThread should not respond with an ICMPv6 Echo Reply. + * + */ + bool ShouldHandleEchoRequest(const MessageInfo &aMessageInfo); private: otError HandleEchoRequest(Message &aMessage, const MessageInfo &aMessageInfo); IcmpHandler *mHandlers; - uint16_t mEchoSequence; - bool mIsEchoEnabled; + uint16_t mEchoSequence; + otIcmp6EchoMode mEchoMode; }; /** diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 1184f65f4..30648a195 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -616,7 +616,7 @@ otError Ip6::ProcessReceiveCallback(const Message & aMessage, switch (aIpProto) { case kProtoIcmp6: - if (mIcmp.IsEchoEnabled()) + if (mIcmp.ShouldHandleEchoRequest(aMessageInfo)) { IcmpHeader icmp; aMessage.Read(aMessage.GetOffset(), sizeof(icmp), &icmp); diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 87267e3d7..be9e4c2b7 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -145,6 +145,7 @@ const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = NCP_GET_PROP_HANDLER_ENTRY(THREAD_PENDING_DATASET), NCP_GET_PROP_HANDLER_ENTRY(IPV6_ADDRESS_TABLE), NCP_GET_PROP_HANDLER_ENTRY(IPV6_ICMP_PING_OFFLOAD), + NCP_GET_PROP_HANDLER_ENTRY(IPV6_ICMP_PING_OFFLOAD_MODE), NCP_GET_PROP_HANDLER_ENTRY(IPV6_LL_ADDR), NCP_GET_PROP_HANDLER_ENTRY(IPV6_ML_PREFIX), NCP_GET_PROP_HANDLER_ENTRY(IPV6_ML_ADDR), @@ -292,6 +293,7 @@ const NcpBase::PropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = NCP_SET_PROP_HANDLER_ENTRY(STREAM_NET), NCP_SET_PROP_HANDLER_ENTRY(IPV6_ML_PREFIX), NCP_SET_PROP_HANDLER_ENTRY(IPV6_ICMP_PING_OFFLOAD), + NCP_SET_PROP_HANDLER_ENTRY(IPV6_ICMP_PING_OFFLOAD_MODE), NCP_SET_PROP_HANDLER_ENTRY(THREAD_RLOC16_DEBUG_PASSTHRU), #if OPENTHREAD_ENABLE_MAC_FILTER NCP_SET_PROP_HANDLER_ENTRY(MAC_WHITELIST), @@ -604,7 +606,7 @@ NcpBase::NcpBase(Instance *aInstance): otIp6SetReceiveCallback(mInstance, &NcpBase::HandleDatagramFromStack, this); otIp6SetReceiveFilterEnabled(mInstance, true); otLinkSetPcapCallback(mInstance, &NcpBase::HandleRawFrame, static_cast(this)); - otIcmp6SetEchoEnabled(mInstance, false); + otIcmp6SetEchoMode(mInstance, OT_ICMP6_ECHO_HANDLER_DISABLED); #if OPENTHREAD_FTD otThreadSetChildTableCallback(mInstance, &NcpBase::HandleChildTableChanged); #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index bd56e1ab6..23e22a074 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -481,6 +481,8 @@ protected: NCP_GET_PROP_HANDLER(IPV6_MULTICAST_ADDRESS_TABLE); NCP_INSERT_PROP_HANDLER(IPV6_MULTICAST_ADDRESS_TABLE); NCP_REMOVE_PROP_HANDLER(IPV6_MULTICAST_ADDRESS_TABLE); + NCP_GET_PROP_HANDLER(IPV6_ICMP_PING_OFFLOAD_MODE); + NCP_SET_PROP_HANDLER(IPV6_ICMP_PING_OFFLOAD_MODE); NCP_GET_PROP_HANDLER(THREAD_LEADER); NCP_GET_PROP_HANDLER(THREAD_RLOC16_DEBUG_PASSTHRU); diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 719c2c486..6c372b04c 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -1136,7 +1136,7 @@ otError NcpBase::GetPropertyHandler_IPV6_ROUTE_TABLE(void) otError NcpBase::GetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(void) { - return mEncoder.WriteBool(otIcmp6IsEchoEnabled(mInstance)); + return mEncoder.WriteBool(otIcmp6GetEchoMode(mInstance) != OT_ICMP6_ECHO_HANDLER_DISABLED); } otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(void) @@ -1146,7 +1146,7 @@ otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(void) SuccessOrExit(error = mDecoder.ReadBool(enabled)); - otIcmp6SetEchoEnabled(mInstance, enabled); + otIcmp6SetEchoMode(mInstance, enabled ? OT_ICMP6_ECHO_HANDLER_ALL : OT_ICMP6_ECHO_HANDLER_DISABLED); exit: return error; @@ -1206,6 +1206,59 @@ exit: return error; } +otError NcpBase::GetPropertyHandler_IPV6_ICMP_PING_OFFLOAD_MODE(void) +{ + spinel_ipv6_icmp_ping_offload_mode_t mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED; + + switch (otIcmp6GetEchoMode(mInstance)) + { + case OT_ICMP6_ECHO_HANDLER_DISABLED: + mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED; + break; + case OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY: + mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_UNICAST_ONLY; + break; + case OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY: + mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_MULTICAST_ONLY; + break; + case OT_ICMP6_ECHO_HANDLER_ALL: + mode = SPINEL_IPV6_ICMP_PING_OFFLOAD_ALL; + break; + }; + + return mEncoder.WriteUint8(mode); +} + +otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD_MODE(void) +{ + otError error = OT_ERROR_NONE; + otIcmp6EchoMode mode = OT_ICMP6_ECHO_HANDLER_DISABLED; + uint8_t spinelMode; + + SuccessOrExit(error = mDecoder.ReadUint8(spinelMode)); + + switch (spinelMode) + { + case SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED: + mode = OT_ICMP6_ECHO_HANDLER_DISABLED; + break; + case SPINEL_IPV6_ICMP_PING_OFFLOAD_UNICAST_ONLY: + mode = OT_ICMP6_ECHO_HANDLER_UNICAST_ONLY; + break; + case SPINEL_IPV6_ICMP_PING_OFFLOAD_MULTICAST_ONLY: + mode = OT_ICMP6_ECHO_HANDLER_MULTICAST_ONLY; + break; + case SPINEL_IPV6_ICMP_PING_OFFLOAD_ALL: + mode = OT_ICMP6_ECHO_HANDLER_ALL; + break; + }; + + otIcmp6SetEchoMode(mInstance, mode); + +exit: + return error; +} + otError NcpBase::GetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(void) { // Note reverse logic: passthru enabled = filter disabled diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c index 4f4cc1751..bc81ed0ba 100644 --- a/src/ncp/spinel.c +++ b/src/ncp/spinel.c @@ -1569,6 +1569,10 @@ spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "PROP_IPV6_MULTICAST_ADDRESS_TABLE"; break; + case SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD_MODE: + ret = "PROP_IPV6_ICMP_PING_OFFLOAD_MODE"; + break; + case SPINEL_PROP_STREAM_DEBUG: ret = "PROP_STREAM_DEBUG"; break; diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index 611fc7670..2a33820b5 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -200,6 +200,14 @@ typedef enum SPINEL_NET_ROLE_LEADER = 3, } spinel_net_role_t; +typedef enum +{ + SPINEL_IPV6_ICMP_PING_OFFLOAD_DISABLED = 0, + SPINEL_IPV6_ICMP_PING_OFFLOAD_UNICAST_ONLY = 1, + SPINEL_IPV6_ICMP_PING_OFFLOAD_MULTICAST_ONLY = 2, + SPINEL_IPV6_ICMP_PING_OFFLOAD_ALL = 3, +} spinel_ipv6_icmp_ping_offload_mode_t; + typedef enum { SPINEL_SCAN_STATE_IDLE = 0, @@ -1412,6 +1420,20 @@ typedef enum SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE = SPINEL_PROP_IPV6__BEGIN + 6, ///< [A(t(6))] + /// IPv6 ICMP Ping Offload + /** Format: `C` + * + * Allow the NCP to directly respond to ICMP ping requests. If this is + * turned on, ping request ICMP packets will not be passed to the host. + * + * This property allows enabling responses sent to unicast only, multicast + * only, or both. + * + * Default value is `NET_IPV6_ICMP_PING_OFFLOAD_DISABLED`. + */ + SPINEL_PROP_IPV6_ICMP_PING_OFFLOAD_MODE + = SPINEL_PROP_IPV6__BEGIN + 7, ///< [b] + SPINEL_PROP_IPV6__END = 0x70, SPINEL_PROP_STREAM__BEGIN = 0x70,