1 /*
2  *  Copyright (c) 2021, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions to support ping functionality.
32  */
33 
34 #ifndef PING_SENDER_HPP_
35 #define PING_SENDER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
40 
41 #include <openthread/ping_sender.h>
42 
43 #include "common/code_utils.hpp"
44 #include "common/locator.hpp"
45 #include "common/message.hpp"
46 #include "common/non_copyable.hpp"
47 #include "common/numeric_limits.hpp"
48 #include "common/time.hpp"
49 #include "common/timer.hpp"
50 #include "net/icmp6.hpp"
51 #include "net/ip6_address.hpp"
52 
53 namespace ot {
54 namespace Utils {
55 
56 /**
57  * This class implements sending ICMPv6 Echo Request messages and processing ICMPv6 Echo Reply messages.
58  *
59  */
60 class PingSender : public InstanceLocator, private NonCopyable
61 {
62 public:
63     /**
64      * This class represents a ping reply.
65      *
66      */
67     typedef otPingSenderReply Reply;
68 
69     /**
70      * This class represents the statistics of several ping requests.
71      *
72      */
73     struct Statistics : public otPingSenderStatistics
74     {
Statisticsot::Utils::PingSender::Statistics75         Statistics(void) { Clear(); }
76 
Clearot::Utils::PingSender::Statistics77         void Clear(void)
78         {
79             mSentCount          = 0;
80             mReceivedCount      = 0;
81             mTotalRoundTripTime = 0;
82             mMinRoundTripTime   = NumericLimits<uint16_t>::kMax;
83             mMaxRoundTripTime   = NumericLimits<uint16_t>::kMin;
84             mIsMulticast        = false;
85         }
86     };
87 
88     /**
89      * This class represents a ping request configuration.
90      *
91      */
92     class Config : public otPingSenderConfig
93     {
94         friend class PingSender;
95 
96     public:
97         /**
98          * This method gets the source IPv6 address of the ping.
99          *
100          * @returns The ping source IPv6 address.
101          *
102          */
GetSource(void)103         Ip6::Address &GetSource(void) { return static_cast<Ip6::Address &>(mSource); }
104 
105         /**
106          * This method gets the source IPv6 address of the ping.
107          *
108          * @returns The ping source IPv6 address.
109          *
110          */
GetSource(void) const111         const Ip6::Address &GetSource(void) const { return static_cast<const Ip6::Address &>(mSource); }
112 
113         /**
114          * This method gets the destination IPv6 address to ping.
115          *
116          * @returns The ping destination IPv6 address.
117          *
118          */
GetDestination(void)119         Ip6::Address &GetDestination(void) { return static_cast<Ip6::Address &>(mDestination); }
120 
121         /**
122          * This method gets the destination IPv6 address to ping.
123          *
124          * @returns The ping destination IPv6 address.
125          *
126          */
GetDestination(void) const127         const Ip6::Address &GetDestination(void) const { return static_cast<const Ip6::Address &>(mDestination); }
128 
129     private:
130         static constexpr uint16_t kDefaultSize     = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_SIZE;
131         static constexpr uint16_t kDefaultCount    = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_COUNT;
132         static constexpr uint32_t kDefaultInterval = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_INTEVRAL;
133         static constexpr uint32_t kDefaultTimeout  = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_TIMEOUT;
134 
135         void SetUnspecifiedToDefault(void);
136         void InvokeReplyCallback(const Reply &aReply) const;
137         void InvokeStatisticsCallback(const Statistics &aStatistics) const;
138     };
139 
140     /**
141      * This constructor initializes the `PingSender` object.
142      *
143      * @param[in]  aInstance     A reference to the OpenThread instance.
144      *
145      */
146     explicit PingSender(Instance &aInstance);
147 
148     /**
149      * This method starts a ping.
150      *
151      * @param[in] aConfig          The ping config to use.
152      *
153      * @retval kErrorNone          The ping started successfully.
154      * @retval kErrorBusy          Could not start since busy with a previous ongoing ping request.
155      * @retval kErrorInvalidArgs   The @p aConfig contains invalid parameters (e.g., ping interval is too long).
156      *
157      */
158     Error Ping(const Config &aConfig);
159 
160     /**
161      * This method stops an ongoing ping.
162      *
163      */
164     void Stop(void);
165 
166 private:
167     void        SendPing(void);
168     static void HandleTimer(Timer &aTimer);
169     void        HandleTimer(void);
170     static void HandleIcmpReceive(void *               aContext,
171                                   otMessage *          aMessage,
172                                   const otMessageInfo *aMessageInfo,
173                                   const otIcmp6Header *aIcmpHeader);
174     void        HandleIcmpReceive(const Message &          aMessage,
175                                   const Ip6::MessageInfo & aMessageInfo,
176                                   const Ip6::Icmp::Header &aIcmpHeader);
177 
178     Config             mConfig;
179     Statistics         mStatistics;
180     uint16_t           mIdentifier;
181     uint16_t           mTargetEchoSequence;
182     TimerMilli         mTimer;
183     Ip6::Icmp::Handler mIcmpHandler;
184 };
185 
186 } // namespace Utils
187 } // namespace ot
188 
189 #endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE
190 
191 #endif // PING_SENDER_HPP_
192