xref: /aosp_15_r20/external/openthread/src/cli/cli_ping.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker  *  Copyright (c) 2024, The OpenThread Authors.
3*cfb92d14SAndroid Build Coastguard Worker  *  All rights reserved.
4*cfb92d14SAndroid Build Coastguard Worker  *
5*cfb92d14SAndroid Build Coastguard Worker  *  Redistribution and use in source and binary forms, with or without
6*cfb92d14SAndroid Build Coastguard Worker  *  modification, are permitted provided that the following conditions are met:
7*cfb92d14SAndroid Build Coastguard Worker  *  1. Redistributions of source code must retain the above copyright
8*cfb92d14SAndroid Build Coastguard Worker  *     notice, this list of conditions and the following disclaimer.
9*cfb92d14SAndroid Build Coastguard Worker  *  2. Redistributions in binary form must reproduce the above copyright
10*cfb92d14SAndroid Build Coastguard Worker  *     notice, this list of conditions and the following disclaimer in the
11*cfb92d14SAndroid Build Coastguard Worker  *     documentation and/or other materials provided with the distribution.
12*cfb92d14SAndroid Build Coastguard Worker  *  3. Neither the name of the copyright holder nor the
13*cfb92d14SAndroid Build Coastguard Worker  *     names of its contributors may be used to endorse or promote products
14*cfb92d14SAndroid Build Coastguard Worker  *     derived from this software without specific prior written permission.
15*cfb92d14SAndroid Build Coastguard Worker  *
16*cfb92d14SAndroid Build Coastguard Worker  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*cfb92d14SAndroid Build Coastguard Worker  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*cfb92d14SAndroid Build Coastguard Worker  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*cfb92d14SAndroid Build Coastguard Worker  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*cfb92d14SAndroid Build Coastguard Worker  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*cfb92d14SAndroid Build Coastguard Worker  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*cfb92d14SAndroid Build Coastguard Worker  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*cfb92d14SAndroid Build Coastguard Worker  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*cfb92d14SAndroid Build Coastguard Worker  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*cfb92d14SAndroid Build Coastguard Worker  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*cfb92d14SAndroid Build Coastguard Worker  *  POSSIBILITY OF SUCH DAMAGE.
27*cfb92d14SAndroid Build Coastguard Worker  */
28*cfb92d14SAndroid Build Coastguard Worker 
29*cfb92d14SAndroid Build Coastguard Worker /**
30*cfb92d14SAndroid Build Coastguard Worker  * @file
31*cfb92d14SAndroid Build Coastguard Worker  *   This file implements the CLI interpreter for Ping Sender function.
32*cfb92d14SAndroid Build Coastguard Worker  */
33*cfb92d14SAndroid Build Coastguard Worker 
34*cfb92d14SAndroid Build Coastguard Worker #include "cli_ping.hpp"
35*cfb92d14SAndroid Build Coastguard Worker 
36*cfb92d14SAndroid Build Coastguard Worker #include <openthread/ping_sender.h>
37*cfb92d14SAndroid Build Coastguard Worker 
38*cfb92d14SAndroid Build Coastguard Worker #include "cli/cli.hpp"
39*cfb92d14SAndroid Build Coastguard Worker #include "cli/cli_utils.hpp"
40*cfb92d14SAndroid Build Coastguard Worker #include "common/code_utils.hpp"
41*cfb92d14SAndroid Build Coastguard Worker 
42*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
43*cfb92d14SAndroid Build Coastguard Worker 
44*cfb92d14SAndroid Build Coastguard Worker namespace ot {
45*cfb92d14SAndroid Build Coastguard Worker namespace Cli {
46*cfb92d14SAndroid Build Coastguard Worker 
PingSender(otInstance * aInstance,OutputImplementer & aOutputImplementer)47*cfb92d14SAndroid Build Coastguard Worker PingSender::PingSender(otInstance *aInstance, OutputImplementer &aOutputImplementer)
48*cfb92d14SAndroid Build Coastguard Worker     : Utils(aInstance, aOutputImplementer)
49*cfb92d14SAndroid Build Coastguard Worker     , mPingIsAsync(false)
50*cfb92d14SAndroid Build Coastguard Worker {
51*cfb92d14SAndroid Build Coastguard Worker }
52*cfb92d14SAndroid Build Coastguard Worker 
Process(Arg aArgs[])53*cfb92d14SAndroid Build Coastguard Worker otError PingSender::Process(Arg aArgs[])
54*cfb92d14SAndroid Build Coastguard Worker {
55*cfb92d14SAndroid Build Coastguard Worker     otError            error = OT_ERROR_NONE;
56*cfb92d14SAndroid Build Coastguard Worker     otPingSenderConfig config;
57*cfb92d14SAndroid Build Coastguard Worker     bool               async = false;
58*cfb92d14SAndroid Build Coastguard Worker     bool               nat64Synth;
59*cfb92d14SAndroid Build Coastguard Worker 
60*cfb92d14SAndroid Build Coastguard Worker     /**
61*cfb92d14SAndroid Build Coastguard Worker      * @cli ping stop
62*cfb92d14SAndroid Build Coastguard Worker      * @code
63*cfb92d14SAndroid Build Coastguard Worker      * ping stop
64*cfb92d14SAndroid Build Coastguard Worker      * Done
65*cfb92d14SAndroid Build Coastguard Worker      * @endcode
66*cfb92d14SAndroid Build Coastguard Worker      * @par
67*cfb92d14SAndroid Build Coastguard Worker      * Stop sending ICMPv6 Echo Requests.
68*cfb92d14SAndroid Build Coastguard Worker      * @sa otPingSenderStop
69*cfb92d14SAndroid Build Coastguard Worker      */
70*cfb92d14SAndroid Build Coastguard Worker     if (aArgs[0] == "stop")
71*cfb92d14SAndroid Build Coastguard Worker     {
72*cfb92d14SAndroid Build Coastguard Worker         otPingSenderStop(GetInstancePtr());
73*cfb92d14SAndroid Build Coastguard Worker         ExitNow();
74*cfb92d14SAndroid Build Coastguard Worker     }
75*cfb92d14SAndroid Build Coastguard Worker     else if (aArgs[0] == "async")
76*cfb92d14SAndroid Build Coastguard Worker     {
77*cfb92d14SAndroid Build Coastguard Worker         async = true;
78*cfb92d14SAndroid Build Coastguard Worker         aArgs++;
79*cfb92d14SAndroid Build Coastguard Worker     }
80*cfb92d14SAndroid Build Coastguard Worker 
81*cfb92d14SAndroid Build Coastguard Worker     ClearAllBytes(config);
82*cfb92d14SAndroid Build Coastguard Worker 
83*cfb92d14SAndroid Build Coastguard Worker     if (aArgs[0] == "-I")
84*cfb92d14SAndroid Build Coastguard Worker     {
85*cfb92d14SAndroid Build Coastguard Worker         SuccessOrExit(error = aArgs[1].ParseAsIp6Address(config.mSource));
86*cfb92d14SAndroid Build Coastguard Worker 
87*cfb92d14SAndroid Build Coastguard Worker #if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
88*cfb92d14SAndroid Build Coastguard Worker         VerifyOrExit(otIp6HasUnicastAddress(GetInstancePtr(), &config.mSource), error = OT_ERROR_INVALID_ARGS);
89*cfb92d14SAndroid Build Coastguard Worker #endif
90*cfb92d14SAndroid Build Coastguard Worker         aArgs += 2;
91*cfb92d14SAndroid Build Coastguard Worker     }
92*cfb92d14SAndroid Build Coastguard Worker 
93*cfb92d14SAndroid Build Coastguard Worker     if (aArgs[0] == "-m")
94*cfb92d14SAndroid Build Coastguard Worker     {
95*cfb92d14SAndroid Build Coastguard Worker         config.mMulticastLoop = true;
96*cfb92d14SAndroid Build Coastguard Worker         aArgs++;
97*cfb92d14SAndroid Build Coastguard Worker     }
98*cfb92d14SAndroid Build Coastguard Worker 
99*cfb92d14SAndroid Build Coastguard Worker     SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], config.mDestination, nat64Synth));
100*cfb92d14SAndroid Build Coastguard Worker 
101*cfb92d14SAndroid Build Coastguard Worker     if (nat64Synth)
102*cfb92d14SAndroid Build Coastguard Worker     {
103*cfb92d14SAndroid Build Coastguard Worker         OutputFormat("Pinging synthesized IPv6 address: ");
104*cfb92d14SAndroid Build Coastguard Worker         OutputIp6AddressLine(config.mDestination);
105*cfb92d14SAndroid Build Coastguard Worker     }
106*cfb92d14SAndroid Build Coastguard Worker 
107*cfb92d14SAndroid Build Coastguard Worker     if (!aArgs[1].IsEmpty())
108*cfb92d14SAndroid Build Coastguard Worker     {
109*cfb92d14SAndroid Build Coastguard Worker         SuccessOrExit(error = aArgs[1].ParseAsUint16(config.mSize));
110*cfb92d14SAndroid Build Coastguard Worker     }
111*cfb92d14SAndroid Build Coastguard Worker 
112*cfb92d14SAndroid Build Coastguard Worker     if (!aArgs[2].IsEmpty())
113*cfb92d14SAndroid Build Coastguard Worker     {
114*cfb92d14SAndroid Build Coastguard Worker         SuccessOrExit(error = aArgs[2].ParseAsUint16(config.mCount));
115*cfb92d14SAndroid Build Coastguard Worker     }
116*cfb92d14SAndroid Build Coastguard Worker 
117*cfb92d14SAndroid Build Coastguard Worker     if (!aArgs[3].IsEmpty())
118*cfb92d14SAndroid Build Coastguard Worker     {
119*cfb92d14SAndroid Build Coastguard Worker         SuccessOrExit(error = ParsePingInterval(aArgs[3], config.mInterval));
120*cfb92d14SAndroid Build Coastguard Worker     }
121*cfb92d14SAndroid Build Coastguard Worker 
122*cfb92d14SAndroid Build Coastguard Worker     if (!aArgs[4].IsEmpty())
123*cfb92d14SAndroid Build Coastguard Worker     {
124*cfb92d14SAndroid Build Coastguard Worker         SuccessOrExit(error = aArgs[4].ParseAsUint8(config.mHopLimit));
125*cfb92d14SAndroid Build Coastguard Worker         config.mAllowZeroHopLimit = (config.mHopLimit == 0);
126*cfb92d14SAndroid Build Coastguard Worker     }
127*cfb92d14SAndroid Build Coastguard Worker 
128*cfb92d14SAndroid Build Coastguard Worker     if (!aArgs[5].IsEmpty())
129*cfb92d14SAndroid Build Coastguard Worker     {
130*cfb92d14SAndroid Build Coastguard Worker         uint32_t timeout;
131*cfb92d14SAndroid Build Coastguard Worker 
132*cfb92d14SAndroid Build Coastguard Worker         SuccessOrExit(error = ParsePingInterval(aArgs[5], timeout));
133*cfb92d14SAndroid Build Coastguard Worker         VerifyOrExit(timeout <= NumericLimits<uint16_t>::kMax, error = OT_ERROR_INVALID_ARGS);
134*cfb92d14SAndroid Build Coastguard Worker         config.mTimeout = static_cast<uint16_t>(timeout);
135*cfb92d14SAndroid Build Coastguard Worker     }
136*cfb92d14SAndroid Build Coastguard Worker 
137*cfb92d14SAndroid Build Coastguard Worker     VerifyOrExit(aArgs[6].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
138*cfb92d14SAndroid Build Coastguard Worker 
139*cfb92d14SAndroid Build Coastguard Worker     config.mReplyCallback      = PingSender::HandlePingReply;
140*cfb92d14SAndroid Build Coastguard Worker     config.mStatisticsCallback = PingSender::HandlePingStatistics;
141*cfb92d14SAndroid Build Coastguard Worker     config.mCallbackContext    = this;
142*cfb92d14SAndroid Build Coastguard Worker 
143*cfb92d14SAndroid Build Coastguard Worker     SuccessOrExit(error = otPingSenderPing(GetInstancePtr(), &config));
144*cfb92d14SAndroid Build Coastguard Worker 
145*cfb92d14SAndroid Build Coastguard Worker     mPingIsAsync = async;
146*cfb92d14SAndroid Build Coastguard Worker 
147*cfb92d14SAndroid Build Coastguard Worker     if (!async)
148*cfb92d14SAndroid Build Coastguard Worker     {
149*cfb92d14SAndroid Build Coastguard Worker         error = OT_ERROR_PENDING;
150*cfb92d14SAndroid Build Coastguard Worker     }
151*cfb92d14SAndroid Build Coastguard Worker 
152*cfb92d14SAndroid Build Coastguard Worker exit:
153*cfb92d14SAndroid Build Coastguard Worker     return error;
154*cfb92d14SAndroid Build Coastguard Worker }
155*cfb92d14SAndroid Build Coastguard Worker 
ParsePingInterval(const Arg & aArg,uint32_t & aInterval)156*cfb92d14SAndroid Build Coastguard Worker otError PingSender::ParsePingInterval(const Arg &aArg, uint32_t &aInterval)
157*cfb92d14SAndroid Build Coastguard Worker {
158*cfb92d14SAndroid Build Coastguard Worker     otError        error    = OT_ERROR_NONE;
159*cfb92d14SAndroid Build Coastguard Worker     const char    *string   = aArg.GetCString();
160*cfb92d14SAndroid Build Coastguard Worker     const uint32_t msFactor = 1000;
161*cfb92d14SAndroid Build Coastguard Worker     uint32_t       factor   = msFactor;
162*cfb92d14SAndroid Build Coastguard Worker 
163*cfb92d14SAndroid Build Coastguard Worker     aInterval = 0;
164*cfb92d14SAndroid Build Coastguard Worker 
165*cfb92d14SAndroid Build Coastguard Worker     while (*string)
166*cfb92d14SAndroid Build Coastguard Worker     {
167*cfb92d14SAndroid Build Coastguard Worker         if ('0' <= *string && *string <= '9')
168*cfb92d14SAndroid Build Coastguard Worker         {
169*cfb92d14SAndroid Build Coastguard Worker             // In the case of seconds, change the base of already calculated value.
170*cfb92d14SAndroid Build Coastguard Worker             if (factor == msFactor)
171*cfb92d14SAndroid Build Coastguard Worker             {
172*cfb92d14SAndroid Build Coastguard Worker                 aInterval *= 10;
173*cfb92d14SAndroid Build Coastguard Worker             }
174*cfb92d14SAndroid Build Coastguard Worker 
175*cfb92d14SAndroid Build Coastguard Worker             aInterval += static_cast<uint32_t>(*string - '0') * factor;
176*cfb92d14SAndroid Build Coastguard Worker 
177*cfb92d14SAndroid Build Coastguard Worker             // In the case of milliseconds, change the multiplier factor.
178*cfb92d14SAndroid Build Coastguard Worker             if (factor != msFactor)
179*cfb92d14SAndroid Build Coastguard Worker             {
180*cfb92d14SAndroid Build Coastguard Worker                 factor /= 10;
181*cfb92d14SAndroid Build Coastguard Worker             }
182*cfb92d14SAndroid Build Coastguard Worker         }
183*cfb92d14SAndroid Build Coastguard Worker         else if (*string == '.')
184*cfb92d14SAndroid Build Coastguard Worker         {
185*cfb92d14SAndroid Build Coastguard Worker             // Accept only one dot character.
186*cfb92d14SAndroid Build Coastguard Worker             VerifyOrExit(factor == msFactor, error = OT_ERROR_INVALID_ARGS);
187*cfb92d14SAndroid Build Coastguard Worker 
188*cfb92d14SAndroid Build Coastguard Worker             // Start analyzing hundreds of milliseconds.
189*cfb92d14SAndroid Build Coastguard Worker             factor /= 10;
190*cfb92d14SAndroid Build Coastguard Worker         }
191*cfb92d14SAndroid Build Coastguard Worker         else
192*cfb92d14SAndroid Build Coastguard Worker         {
193*cfb92d14SAndroid Build Coastguard Worker             ExitNow(error = OT_ERROR_INVALID_ARGS);
194*cfb92d14SAndroid Build Coastguard Worker         }
195*cfb92d14SAndroid Build Coastguard Worker 
196*cfb92d14SAndroid Build Coastguard Worker         string++;
197*cfb92d14SAndroid Build Coastguard Worker     }
198*cfb92d14SAndroid Build Coastguard Worker 
199*cfb92d14SAndroid Build Coastguard Worker exit:
200*cfb92d14SAndroid Build Coastguard Worker     return error;
201*cfb92d14SAndroid Build Coastguard Worker }
202*cfb92d14SAndroid Build Coastguard Worker 
HandlePingReply(const otPingSenderReply * aReply,void * aContext)203*cfb92d14SAndroid Build Coastguard Worker void PingSender::HandlePingReply(const otPingSenderReply *aReply, void *aContext)
204*cfb92d14SAndroid Build Coastguard Worker {
205*cfb92d14SAndroid Build Coastguard Worker     static_cast<PingSender *>(aContext)->HandlePingReply(aReply);
206*cfb92d14SAndroid Build Coastguard Worker }
207*cfb92d14SAndroid Build Coastguard Worker 
HandlePingReply(const otPingSenderReply * aReply)208*cfb92d14SAndroid Build Coastguard Worker void PingSender::HandlePingReply(const otPingSenderReply *aReply)
209*cfb92d14SAndroid Build Coastguard Worker {
210*cfb92d14SAndroid Build Coastguard Worker     OutputFormat("%u bytes from ", static_cast<uint16_t>(aReply->mSize + sizeof(otIcmp6Header)));
211*cfb92d14SAndroid Build Coastguard Worker     OutputIp6Address(aReply->mSenderAddress);
212*cfb92d14SAndroid Build Coastguard Worker     OutputLine(": icmp_seq=%u hlim=%u time=%ums", aReply->mSequenceNumber, aReply->mHopLimit, aReply->mRoundTripTime);
213*cfb92d14SAndroid Build Coastguard Worker }
214*cfb92d14SAndroid Build Coastguard Worker 
HandlePingStatistics(const otPingSenderStatistics * aStatistics,void * aContext)215*cfb92d14SAndroid Build Coastguard Worker void PingSender::HandlePingStatistics(const otPingSenderStatistics *aStatistics, void *aContext)
216*cfb92d14SAndroid Build Coastguard Worker {
217*cfb92d14SAndroid Build Coastguard Worker     static_cast<PingSender *>(aContext)->HandlePingStatistics(aStatistics);
218*cfb92d14SAndroid Build Coastguard Worker }
219*cfb92d14SAndroid Build Coastguard Worker 
HandlePingStatistics(const otPingSenderStatistics * aStatistics)220*cfb92d14SAndroid Build Coastguard Worker void PingSender::HandlePingStatistics(const otPingSenderStatistics *aStatistics)
221*cfb92d14SAndroid Build Coastguard Worker {
222*cfb92d14SAndroid Build Coastguard Worker     OutputFormat("%u packets transmitted, %u packets received.", aStatistics->mSentCount, aStatistics->mReceivedCount);
223*cfb92d14SAndroid Build Coastguard Worker 
224*cfb92d14SAndroid Build Coastguard Worker     if ((aStatistics->mSentCount != 0) && !aStatistics->mIsMulticast &&
225*cfb92d14SAndroid Build Coastguard Worker         aStatistics->mReceivedCount <= aStatistics->mSentCount)
226*cfb92d14SAndroid Build Coastguard Worker     {
227*cfb92d14SAndroid Build Coastguard Worker         uint32_t packetLossRate =
228*cfb92d14SAndroid Build Coastguard Worker             1000 * (aStatistics->mSentCount - aStatistics->mReceivedCount) / aStatistics->mSentCount;
229*cfb92d14SAndroid Build Coastguard Worker 
230*cfb92d14SAndroid Build Coastguard Worker         OutputFormat(" Packet loss = %lu.%u%%.", ToUlong(packetLossRate / 10),
231*cfb92d14SAndroid Build Coastguard Worker                      static_cast<uint16_t>(packetLossRate % 10));
232*cfb92d14SAndroid Build Coastguard Worker     }
233*cfb92d14SAndroid Build Coastguard Worker 
234*cfb92d14SAndroid Build Coastguard Worker     if (aStatistics->mReceivedCount != 0)
235*cfb92d14SAndroid Build Coastguard Worker     {
236*cfb92d14SAndroid Build Coastguard Worker         uint32_t avgRoundTripTime = 1000 * aStatistics->mTotalRoundTripTime / aStatistics->mReceivedCount;
237*cfb92d14SAndroid Build Coastguard Worker 
238*cfb92d14SAndroid Build Coastguard Worker         OutputFormat(" Round-trip min/avg/max = %u/%u.%u/%u ms.", aStatistics->mMinRoundTripTime,
239*cfb92d14SAndroid Build Coastguard Worker                      static_cast<uint16_t>(avgRoundTripTime / 1000), static_cast<uint16_t>(avgRoundTripTime % 1000),
240*cfb92d14SAndroid Build Coastguard Worker                      aStatistics->mMaxRoundTripTime);
241*cfb92d14SAndroid Build Coastguard Worker     }
242*cfb92d14SAndroid Build Coastguard Worker 
243*cfb92d14SAndroid Build Coastguard Worker     OutputNewLine();
244*cfb92d14SAndroid Build Coastguard Worker 
245*cfb92d14SAndroid Build Coastguard Worker     if (!mPingIsAsync)
246*cfb92d14SAndroid Build Coastguard Worker     {
247*cfb92d14SAndroid Build Coastguard Worker         OutputResult(OT_ERROR_NONE);
248*cfb92d14SAndroid Build Coastguard Worker     }
249*cfb92d14SAndroid Build Coastguard Worker }
250*cfb92d14SAndroid Build Coastguard Worker 
OutputResult(otError aError)251*cfb92d14SAndroid Build Coastguard Worker void PingSender::OutputResult(otError aError) { Interpreter::GetInterpreter().OutputResult(aError); }
252*cfb92d14SAndroid Build Coastguard Worker 
253*cfb92d14SAndroid Build Coastguard Worker } // namespace Cli
254*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
255*cfb92d14SAndroid Build Coastguard Worker 
256*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE
257