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 class PingSender : public InstanceLocator, private NonCopyable
61 {
62 public:
63     /**
64      * Represents a ping reply.
65      */
66     typedef otPingSenderReply Reply;
67 
68     /**
69      * Represents the statistics of several ping requests.
70      */
71     struct Statistics : public otPingSenderStatistics
72     {
Statisticsot::Utils::PingSender::Statistics73         Statistics(void) { Clear(); }
74 
Clearot::Utils::PingSender::Statistics75         void Clear(void)
76         {
77             mSentCount          = 0;
78             mReceivedCount      = 0;
79             mTotalRoundTripTime = 0;
80             mMinRoundTripTime   = NumericLimits<uint16_t>::kMax;
81             mMaxRoundTripTime   = NumericLimits<uint16_t>::kMin;
82             mIsMulticast        = false;
83         }
84     };
85 
86     /**
87      * Represents a ping request configuration.
88      */
89     class Config : public otPingSenderConfig
90     {
91         friend class PingSender;
92 
93     public:
94         /**
95          * Gets the source IPv6 address of the ping.
96          *
97          * @returns The ping source IPv6 address.
98          */
GetSource(void)99         Ip6::Address &GetSource(void) { return AsCoreType(&mSource); }
100 
101         /**
102          * Gets the source IPv6 address of the ping.
103          *
104          * @returns The ping source IPv6 address.
105          */
GetSource(void) const106         const Ip6::Address &GetSource(void) const { return AsCoreType(&mSource); }
107 
108         /**
109          * Gets the destination IPv6 address to ping.
110          *
111          * @returns The ping destination IPv6 address.
112          */
GetDestination(void)113         Ip6::Address &GetDestination(void) { return AsCoreType(&mDestination); }
114 
115         /**
116          * Gets the destination IPv6 address to ping.
117          *
118          * @returns The ping destination IPv6 address.
119          */
GetDestination(void) const120         const Ip6::Address &GetDestination(void) const { return AsCoreType(&mDestination); }
121 
122     private:
123         static constexpr uint16_t kDefaultSize     = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_SIZE;
124         static constexpr uint16_t kDefaultCount    = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_COUNT;
125         static constexpr uint32_t kDefaultInterval = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_INTERVAL;
126         static constexpr uint32_t kDefaultTimeout  = OPENTHREAD_CONFIG_PING_SENDER_DEFAULT_TIMEOUT;
127 
128         void SetUnspecifiedToDefault(void);
129         void InvokeReplyCallback(const Reply &aReply) const;
130         void InvokeStatisticsCallback(const Statistics &aStatistics) const;
131     };
132 
133     /**
134      * Initializes the `PingSender` object.
135      *
136      * @param[in]  aInstance     A reference to the OpenThread instance.
137      */
138     explicit PingSender(Instance &aInstance);
139 
140     /**
141      * Starts a ping.
142      *
143      * @param[in] aConfig          The ping config to use.
144      *
145      * @retval kErrorNone          The ping started successfully.
146      * @retval kErrorBusy          Could not start since busy with a previous ongoing ping request.
147      * @retval kErrorInvalidArgs   The @p aConfig contains invalid parameters (e.g., ping interval is too long).
148      */
149     Error Ping(const Config &aConfig);
150 
151     /**
152      * Stops an ongoing ping.
153      */
154     void Stop(void);
155 
156 private:
157     void        SendPing(void);
158     void        HandleTimer(void);
159     static void HandleIcmpReceive(void                *aContext,
160                                   otMessage           *aMessage,
161                                   const otMessageInfo *aMessageInfo,
162                                   const otIcmp6Header *aIcmpHeader);
163     void        HandleIcmpReceive(const Message           &aMessage,
164                                   const Ip6::MessageInfo  &aMessageInfo,
165                                   const Ip6::Icmp::Header &aIcmpHeader);
166 
167     using PingTimer = TimerMilliIn<PingSender, &PingSender::HandleTimer>;
168 
169     Config             mConfig;
170     Statistics         mStatistics;
171     uint16_t           mIdentifier;
172     uint16_t           mTargetEchoSequence;
173     PingTimer          mTimer;
174     Ip6::Icmp::Handler mIcmpHandler;
175 };
176 
177 } // namespace Utils
178 
179 DefineCoreType(otPingSenderReply, Utils::PingSender::Reply);
180 DefineCoreType(otPingSenderConfig, Utils::PingSender::Config);
181 DefineCoreType(otPingSenderStatistics, Utils::PingSender::Statistics);
182 
183 } // namespace ot
184 
185 #endif // OPENTHREAD_CONFIG_PING_SENDER_ENABLE
186 
187 #endif // PING_SENDER_HPP_
188