[cli] use ICMPv6 Echo Request ID to match Responses (#4534)

This commit updates/enhances the CLI `ping` command. It adds the
feature to track and match the ICMPv6 echo requests and responses
using an identifier. Each `ping` command will use a new value as the
identifier. A received ICMPv6 echo response not matching the current
identifier is ignored. This commit also makes the following (smaller)
changes:
- renames the ping related member variables as `mPing{Name}`,
- defines  constants for default ping parameters,
- changes `ping` to use public OT APIs/definition (instead of core
  methods).
This commit is contained in:
Abtin Keshavarzian
2020-02-09 15:13:33 -08:00
committed by Jonathan Hui
parent aa78b2688e
commit 253e99ba17
2 changed files with 76 additions and 61 deletions
+63 -55
View File
@@ -225,9 +225,12 @@ Interpreter::Interpreter(Instance *aInstance)
: mUserCommands(NULL)
, mUserCommandsLength(0)
, mServer(NULL)
, mLength(8)
, mCount(1)
, mInterval(1000)
, mPingLength(kDefaultPingLength)
, mPingCount(kDefaultPingCount)
, mPingInterval(kDefaultPingInterval)
, mPingHopLimit(0)
, mPingAllowZeroHopLimit(false)
, mPingIdentifier(0)
, mPingTimer(*aInstance, &Interpreter::HandlePingTimer, this)
#if OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE
, mResolvingInProgress(0)
@@ -1983,27 +1986,26 @@ void Interpreter::HandleIcmpReceive(void * aContext,
const otMessageInfo *aMessageInfo,
const otIcmp6Header *aIcmpHeader)
{
static_cast<Interpreter *>(aContext)->HandleIcmpReceive(*static_cast<Message *>(aMessage),
*static_cast<const Ip6::MessageInfo *>(aMessageInfo),
*static_cast<const Ip6::IcmpHeader *>(aIcmpHeader));
static_cast<Interpreter *>(aContext)->HandleIcmpReceive(aMessage, aMessageInfo, aIcmpHeader);
}
void Interpreter::HandleIcmpReceive(Message & aMessage,
const Ip6::MessageInfo &aMessageInfo,
const otIcmp6Header & aIcmpHeader)
void Interpreter::HandleIcmpReceive(otMessage * aMessage,
const otMessageInfo *aMessageInfo,
const otIcmp6Header *aIcmpHeader)
{
uint32_t timestamp = 0;
uint32_t timestamp;
VerifyOrExit(aIcmpHeader.mType == OT_ICMP6_TYPE_ECHO_REPLY);
VerifyOrExit(aIcmpHeader->mType == OT_ICMP6_TYPE_ECHO_REPLY);
VerifyOrExit((mPingIdentifier != 0) && (mPingIdentifier == HostSwap16(aIcmpHeader->mData.m16[0])));
mServer->OutputFormat("%u bytes from ",
aMessage.GetLength() - aMessage.GetOffset() + static_cast<uint16_t>(sizeof(otIcmp6Header)));
mServer->OutputFormat("%u bytes from ", otMessageGetLength(aMessage) - otMessageGetOffset(aMessage) +
static_cast<uint16_t>(sizeof(otIcmp6Header)));
OutputIp6Address(aMessageInfo.GetPeerAddr());
OutputIp6Address(aMessageInfo->mPeerAddr);
mServer->OutputFormat(": icmp_seq=%d hlim=%d", HostSwap16(aIcmpHeader.mData.m16[1]), aMessageInfo.mHopLimit);
mServer->OutputFormat(": icmp_seq=%d hlim=%d", HostSwap16(aIcmpHeader->mData.m16[1]), aMessageInfo->mHopLimit);
if (aMessage.Read(aMessage.GetOffset(), sizeof(uint32_t), &timestamp) >= static_cast<int>(sizeof(uint32_t)))
if (otMessageRead(aMessage, otMessageGetOffset(aMessage), &timestamp, sizeof(uint32_t)) == sizeof(uint32_t))
{
mServer->OutputFormat(" time=%dms", TimerMilli::GetNow().GetValue() - HostSwap32(timestamp));
}
@@ -2025,26 +2027,21 @@ void Interpreter::ProcessPing(int argc, char *argv[])
if (strcmp(argv[0], "stop") == 0)
{
if (!mPingTimer.IsRunning())
{
error = OT_ERROR_INVALID_STATE;
}
else
{
mPingTimer.Stop();
}
mPingIdentifier = 0;
VerifyOrExit(mPingTimer.IsRunning(), error = OT_ERROR_INVALID_STATE);
mPingTimer.Stop();
ExitNow();
}
VerifyOrExit(!mPingTimer.IsRunning(), error = OT_ERROR_BUSY);
mMessageInfo = Ip6::MessageInfo();
SuccessOrExit(error = mMessageInfo.GetPeerAddr().FromString(argv[0]));
SuccessOrExit(error = otIp6AddressFromString(argv[0], &mPingDestAddress));
mLength = 8;
mCount = 1;
mInterval = 1000;
mPingLength = kDefaultPingLength;
mPingCount = kDefaultPingCount;
mPingInterval = kDefaultPingInterval;
mPingHopLimit = 0;
mPingAllowZeroHopLimit = false;
while (index < argc)
{
@@ -2052,28 +2049,25 @@ void Interpreter::ProcessPing(int argc, char *argv[])
{
case 1:
SuccessOrExit(error = ParseLong(argv[index], value));
mLength = static_cast<uint16_t>(value);
mPingLength = static_cast<uint16_t>(value);
break;
case 2:
SuccessOrExit(error = ParseLong(argv[index], value));
mCount = static_cast<uint16_t>(value);
mPingCount = static_cast<uint16_t>(value);
break;
case 3:
SuccessOrExit(error = ParsePingInterval(argv[index], interval));
VerifyOrExit(0 < interval && interval <= Timer::kMaxDelay, error = OT_ERROR_INVALID_ARGS);
mInterval = interval;
mPingInterval = interval;
break;
case 4:
SuccessOrExit(error = ParseLong(argv[index], value));
VerifyOrExit(0 <= value && value <= 255, error = OT_ERROR_INVALID_ARGS);
mMessageInfo.mHopLimit = static_cast<uint8_t>(value);
if (value == 0)
{
mMessageInfo.mAllowZeroHopLimit = true;
}
mPingHopLimit = static_cast<uint8_t>(value);
mPingAllowZeroHopLimit = (mPingHopLimit == 0);
break;
default:
@@ -2083,42 +2077,56 @@ void Interpreter::ProcessPing(int argc, char *argv[])
index++;
}
HandlePingTimer();
mPingIdentifier++;
return;
if (mPingIdentifier == 0)
{
mPingIdentifier++;
}
SendPing();
exit:
AppendResult(error);
if (error != OT_ERROR_NONE)
{
AppendResult(error);
}
}
void Interpreter::HandlePingTimer(Timer &aTimer)
{
GetOwner(aTimer).HandlePingTimer();
GetOwner(aTimer).SendPing();
}
void Interpreter::HandlePingTimer()
void Interpreter::SendPing(void)
{
otError error = OT_ERROR_NONE;
uint32_t timestamp = HostSwap32(TimerMilli::GetNow().GetValue());
uint32_t timestamp = HostSwap32(TimerMilli::GetNow().GetValue());
otMessage * message = NULL;
otMessageInfo messageInfo;
otMessage * message;
const otMessageInfo *messageInfo = static_cast<const otMessageInfo *>(&mMessageInfo);
memset(&messageInfo, 0, sizeof(messageInfo));
messageInfo.mPeerAddr = mPingDestAddress;
messageInfo.mHopLimit = mPingHopLimit;
messageInfo.mAllowZeroHopLimit = mPingAllowZeroHopLimit;
VerifyOrExit((message = otIp6NewMessage(mInstance, NULL)) != NULL, error = OT_ERROR_NO_BUFS);
SuccessOrExit(error = otMessageAppend(message, &timestamp, sizeof(timestamp)));
SuccessOrExit(error = otMessageSetLength(message, mLength));
SuccessOrExit(error = otIcmp6SendEchoRequest(mInstance, message, messageInfo, 1));
message = otIp6NewMessage(mInstance, NULL);
VerifyOrExit(message != NULL);
SuccessOrExit(otMessageAppend(message, &timestamp, sizeof(timestamp)));
SuccessOrExit(otMessageSetLength(message, mPingLength));
SuccessOrExit(otIcmp6SendEchoRequest(mInstance, message, &messageInfo, mPingIdentifier));
message = NULL;
exit:
if (error != OT_ERROR_NONE && message != NULL)
if (message != NULL)
{
otMessageFree(message);
}
if (--mCount)
if (--mPingCount)
{
mPingTimer.Start(mInterval);
mPingTimer.Start(mPingInterval);
}
}