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/as_core_type.hpp"
44 #include "common/code_utils.hpp"
45 #include "common/locator.hpp"
46 #include "common/message.hpp"
47 #include "common/non_copyable.hpp"
48 #include "common/numeric_limits.hpp"
49 #include "common/time.hpp"
50 #include "common/timer.hpp"
51 #include "net/icmp6.hpp"
52 #include "net/ip6_address.hpp"
53 
54 namespace ot {
55 namespace Utils {
56 
57 /**
58  * Implements sending ICMPv6 Echo Request messages and processing ICMPv6 Echo Reply messages.
59  *
60  */
61 class PingSender : public InstanceLocator, private NonCopyable
62 {
63 public:
64     /**
65      * Represents a ping reply.
66      *
67      */
68     typedef otPingSenderReply Reply;
69 
70     /**
71      * Represents the statistics of several ping requests.
72      *
73      */
74     struct Statistics : public otPingSenderStatistics
75     {
Statisticsot::Utils::PingSender::Statistics76         Statistics(void) { Clear(); }
77 
Clearot::Utils::PingSender::Statistics78         void Clear(void)
79         {
80             mSentCount          = 0;
81             mReceivedCount      = 0;
82             mTotalRoundTripTime = 0;
83             mMinRoundTripTime   = NumericLimits<uint16_t>::kMax;
84             mMaxRoundTripTime   = NumericLimits<uint16_t>::kMin;
85             mIsMulticast        = false;
86         }
87     };
88 
89     /**
90      * Represents a ping request configuration.
91      *
92      */
93     class Config : public otPingSenderConfig
94     {
95         friend class PingSender;
96 
97     public:
98         /**
99          * Gets the source IPv6 address of the ping.
100          *
101          * @returns The ping source IPv6 address.
102          *
103          */
GetSource(void)104         Ip6::Address &GetSource(void) { return AsCoreType(&mSource); }
105 
106         /**
107          * Gets the source IPv6 address of the ping.
108          *
109          * @returns The ping source IPv6 address.
110          *
111          */
GetSource(void) const112         const Ip6::Address &GetSource(void) const { return AsCoreType(&mSource); }
113 
114         /**
115          * Gets the destination IPv6 address to ping.
116          *
117          * @returns The ping destination IPv6 address.
118          *
119          */
GetDestination(void)120         Ip6::Address &GetDestination(void) { return AsCoreType(&mDestination); }
121 
122         /**
123          * Gets the destination IPv6 address to ping.
124          *
125          * @returns The ping destination IPv6 address.
126          *
127          */
GetDestination(void) const128         const Ip6::Address &GetDestination(void) const { return AsCoreType(&mDestination); }
129 
130     private:
131         static constexpr uint16_t kDefaultSize     = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_SIZE;
132         static constexpr uint16_t kDefaultCount    = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_COUNT;
133         static constexpr uint32_t kDefaultInterval = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_INTERVAL;
134         static constexpr uint32_t kDefaultTimeout  = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_TIMEOUT;
135 
136         void SetUnspecifiedToDefault(void);
137         void InvokeReplyCallback(const Reply &aReply) const;
138         void InvokeStatisticsCallback(const Statistics &aStatistics) const;
139     };
140 
141     /**
142      * Initializes the `PingSender` object.
143      *
144      * @param[in]  aInstance     A reference to the OpenThread instance.
145      *
146      */
147     explicit PingSender(Instance &aInstance);
148 
149     /**
150      * Starts a ping.
151      *
152      * @param[in] aConfig          The ping config to use.
153      *
154      * @retval kErrorNone          The ping started successfully.
155      * @retval kErrorBusy          Could not start since busy with a previous ongoing ping request.
156      * @retval kErrorInvalidArgs   The @p aConfig contains invalid parameters (e.g., ping interval is too long).
157      *
158      */
159     Error Ping(const Config &aConfig);
160 
161     /**
162      * Stops an ongoing ping.
163      *
164      */
165     void Stop(void);
166 
167 private:
168     void        SendPing(void);
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     using PingTimer = TimerMilliIn<PingSender, &PingSender::HandleTimer>;
179 
180     Config             mConfig;
181     Statistics         mStatistics;
182     uint16_t           mIdentifier;
183     uint16_t           mTargetEchoSequence;
184     PingTimer          mTimer;
185     Ip6::Icmp::Handler mIcmpHandler;
186 };
187 
188 } // namespace Utils
189 
190 DefineCoreType(otPingSenderReply, Utils::PingSender::Reply);
191 DefineCoreType(otPingSenderConfig, Utils::PingSender::Config);
192 DefineCoreType(otPingSenderStatistics, Utils::PingSender::Statistics);
193 
194 } // namespace ot
195 
196 #endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE
197 
198 #endif // PING_SENDER_HPP_
199