[icmp6] allow config of echo handling for unicast/multicast separately (#2609)

Previously, ICMPv6 Echo Request handling was either enabled or disabled.
This commit allows enabling/disabling the handler for ICMPv6 Echo Requests
sent to unicast and multicast destinations separately.

This commit also adds an associated spinel property and NCP implementation.
This commit is contained in:
Jonathan Hui
2018-03-13 18:10:28 +00:00
committed by GitHub
parent 0dd689752c
commit f602dcd5e7
13 changed files with 172 additions and 22 deletions
@@ -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`.
@@ -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);
+1 -1
View File
@@ -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);
+19 -6
View File
@@ -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.
*
*/
+4 -4
View File
@@ -39,18 +39,18 @@
using namespace ot;
bool otIcmp6IsEchoEnabled(otInstance *aInstance)
otIcmp6EchoMode otIcmp6GetEchoMode(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(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<Instance *>(aInstance);
instance.GetIp6().GetIcmp().SetEchoEnabled(aEnabled);
instance.GetIp6().GetIcmp().SetEchoMode(aMode);
}
otError otIcmp6RegisterHandler(otInstance *aInstance, otIcmp6Handler *aHandler)
+27 -2
View File
@@ -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();
+13 -4
View File
@@ -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;
};
/**
+1 -1
View File
@@ -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);
+3 -1
View File
@@ -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<void *>(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
+2
View File
@@ -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);
+55 -2
View File
@@ -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
+4
View File
@@ -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;
+22
View File
@@ -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,