1 /*
2  *  Copyright (c) 2016, 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 for handle network diagnostic.
32  */
33 
34 #ifndef NETWORK_DIAGNOSTIC_HPP_
35 #define NETWORK_DIAGNOSTIC_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/netdiag.h>
40 
41 #include "common/callback.hpp"
42 #include "common/locator.hpp"
43 #include "common/non_copyable.hpp"
44 #include "net/udp6.hpp"
45 #include "thread/network_diagnostic_tlvs.hpp"
46 #include "thread/tmf.hpp"
47 #include "thread/uri_paths.hpp"
48 
49 namespace ot {
50 
51 namespace Utils {
52 class MeshDiag;
53 }
54 
55 namespace NetworkDiagnostic {
56 
57 /**
58  * @addtogroup core-netdiag
59  *
60  * @brief
61  *   This module includes definitions for sending and handling Network Diagnostic Commands.
62  *
63  * @{
64  */
65 
66 class Client;
67 
68 /**
69  * Implements the Network Diagnostic server responding to requests.
70  *
71  */
72 class Server : public InstanceLocator, private NonCopyable
73 {
74     friend class Tmf::Agent;
75     friend class Client;
76 
77 public:
78     /**
79      * Initializes the Server.
80      *
81      * @param[in] aInstance   The OpenThread instance.
82      *
83      */
84     explicit Server(Instance &aInstance);
85 
86 #if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
87     /**
88      * Returns the vendor name string.
89      *
90      * @returns The vendor name string.
91      *
92      */
GetVendorName(void) const93     const char *GetVendorName(void) const { return mVendorName; }
94 
95     /**
96      * Sets the vendor name string.
97      *
98      * @param[in] aVendorName     The vendor name string.
99      *
100      * @retval kErrorNone         Successfully set the vendor name.
101      * @retval kErrorInvalidArgs  @p aVendorName is not valid (too long or not UTF8).
102      *
103      */
104     Error SetVendorName(const char *aVendorName);
105 
106     /**
107      * Returns the vendor model string.
108      *
109      * @returns The vendor model string.
110      *
111      */
GetVendorModel(void) const112     const char *GetVendorModel(void) const { return mVendorModel; }
113 
114     /**
115      * Sets the vendor model string.
116      *
117      * @param[in] aVendorModel     The vendor model string.
118      *
119      * @retval kErrorNone         Successfully set the vendor model.
120      * @retval kErrorInvalidArgs  @p aVendorModel is not valid (too long or not UTF8).
121      *
122      */
123     Error SetVendorModel(const char *aVendorModel);
124 
125     /**
126      * Returns the vendor software version string.
127      *
128      * @returns The vendor software version string.
129      *
130      */
GetVendorSwVersion(void) const131     const char *GetVendorSwVersion(void) const { return mVendorSwVersion; }
132 
133     /**
134      * Sets the vendor sw version string
135      *
136      * @param[in] aVendorSwVersion     The vendor sw version string.
137      *
138      * @retval kErrorNone         Successfully set the vendor sw version.
139      * @retval kErrorInvalidArgs  @p aVendorSwVersion is not valid (too long or not UTF8).
140      *
141      */
142     Error SetVendorSwVersion(const char *aVendorSwVersion);
143 
144     /**
145      * Returns the vendor app URL string.
146      *
147      * @returns the vendor app URL string.
148      *
149      */
GetVendorAppUrl(void) const150     const char *GetVendorAppUrl(void) const { return mVendorAppUrl; }
151 
152     /**
153      * Sets the vendor app URL string.
154      *
155      * @param[in] aVendorAppUrl     The vendor app URL string
156      *
157      * @retval kErrorNone         Successfully set the vendor app URL.
158      * @retval kErrorInvalidArgs  @p aVendorAppUrl is not valid (too long or not UTF8).
159      *
160      */
161     Error SetVendorAppUrl(const char *aVendorAppUrl);
162 
163 #else
GetVendorName(void) const164     const char *GetVendorName(void) const { return kVendorName; }
GetVendorModel(void) const165     const char *GetVendorModel(void) const { return kVendorModel; }
GetVendorSwVersion(void) const166     const char *GetVendorSwVersion(void) const { return kVendorSwVersion; }
GetVendorAppUrl(void) const167     const char *GetVendorAppUrl(void) const { return kVendorAppUrl; }
168 #endif // OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
169 
170 private:
171     static constexpr uint16_t kMaxChildEntries              = 398;
172     static constexpr uint16_t kAnswerMessageLengthThreshold = 800;
173 
174 #if OPENTHREAD_FTD
175     struct AnswerInfo
176     {
AnswerInfoot::NetworkDiagnostic::Server::AnswerInfo177         AnswerInfo(void)
178             : mAnswerIndex(0)
179             , mQueryId(0)
180             , mHasQueryId(false)
181             , mFirstAnswer(nullptr)
182         {
183         }
184 
185         uint16_t          mAnswerIndex;
186         uint16_t          mQueryId;
187         bool              mHasQueryId;
188         Message::Priority mPriority;
189         Coap::Message    *mFirstAnswer;
190     };
191 #endif
192 
193     static const char kVendorName[];
194     static const char kVendorModel[];
195     static const char kVendorSwVersion[];
196     static const char kVendorAppUrl[];
197 
198     Error AppendDiagTlv(uint8_t aTlvType, Message &aMessage);
199     Error AppendIp6AddressList(Message &aMessage);
200     Error AppendMacCounters(Message &aMessage);
201     Error AppendRequestedTlvs(const Message &aRequest, Message &aResponse);
202     void  PrepareMessageInfoForDest(const Ip6::Address &aDestination, Tmf::MessageInfo &aMessageInfo) const;
203 
204 #if OPENTHREAD_MTD
205     void SendAnswer(const Ip6::Address &aDestination, const Message &aRequest);
206 #elif OPENTHREAD_FTD
207     Error       AllocateAnswer(Coap::Message *&aAnswer, AnswerInfo &aInfo);
208     Error       CheckAnswerLength(Coap::Message *&aAnswer, AnswerInfo &aInfo);
209     bool        IsLastAnswer(const Coap::Message &aAnswer) const;
210     void        FreeAllRelatedAnswers(Coap::Message &aFirstAnswer);
211     void        PrepareAndSendAnswers(const Ip6::Address &aDestination, const Message &aRequest);
212     void        SendNextAnswer(Coap::Message &aAnswer, const Ip6::Address &aDestination);
213     Error       AppendChildTable(Message &aMessage);
214     Error       AppendChildTableAsChildTlvs(Coap::Message *&aAnswer, AnswerInfo &aInfo);
215     Error       AppendRouterNeighborTlvs(Coap::Message *&aAnswer, AnswerInfo &aInfo);
216     Error       AppendChildTableIp6AddressList(Coap::Message *&aAnswer, AnswerInfo &aInfo);
217     Error       AppendChildIp6AddressListTlv(Coap::Message &aAnswer, const Child &aChild);
218 
219     static void HandleAnswerResponse(void                *aContext,
220                                      otMessage           *aMessage,
221                                      const otMessageInfo *aMessageInfo,
222                                      Error                aResult);
223     void        HandleAnswerResponse(Coap::Message          &aNextAnswer,
224                                      Coap::Message          *aResponse,
225                                      const Ip6::MessageInfo *aMessageInfo,
226                                      Error                   aResult);
227 #endif
228 
229     template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
230 
231 #if OPENTHREAD_CONFIG_NET_DIAG_VENDOR_INFO_SET_API_ENABLE
232     VendorNameTlv::StringType      mVendorName;
233     VendorModelTlv::StringType     mVendorModel;
234     VendorSwVersionTlv::StringType mVendorSwVersion;
235     VendorAppUrlTlv::StringType    mVendorAppUrl;
236 #endif
237 
238 #if OPENTHREAD_FTD
239     Coap::MessageQueue mAnswerQueue;
240 #endif
241 };
242 
243 DeclareTmfHandler(Server, kUriDiagnosticGetRequest);
244 DeclareTmfHandler(Server, kUriDiagnosticGetQuery);
245 DeclareTmfHandler(Server, kUriDiagnosticGetAnswer);
246 
247 #if OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
248 
249 /**
250  * Implements the Network Diagnostic client sending requests and queries.
251  *
252  */
253 class Client : public InstanceLocator, private NonCopyable
254 {
255     friend class Tmf::Agent;
256     friend class Utils::MeshDiag;
257 
258 public:
259     typedef otNetworkDiagIterator          Iterator;    ///< Iterator to go through TLVs in `GetNextDiagTlv()`.
260     typedef otNetworkDiagTlv               TlvInfo;     ///< Parse info from a Network Diagnostic TLV.
261     typedef otNetworkDiagChildEntry        ChildInfo;   ///< Parsed info for child table entry.
262     typedef otReceiveDiagnosticGetCallback GetCallback; ///< Diagnostic Get callback function pointer type.
263 
264     static constexpr Iterator kIteratorInit = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT; ///< Initializer for Iterator.
265 
266     /**
267      * Initializes the Client.
268      *
269      * @param[in] aInstance   The OpenThread instance.
270      *
271      */
272     explicit Client(Instance &aInstance);
273 
274     /**
275      * Sends Diagnostic Get request. If the @p aDestination is of multicast type, the DIAG_GET.qry
276      * message is sent or the DIAG_GET.req otherwise.
277      *
278      * @param[in]  aDestination      The destination address.
279      * @param[in]  aTlvTypes         An array of Network Diagnostic TLV types.
280      * @param[in]  aCount            Number of types in @p aTlvTypes.
281      * @param[in]  aCallback         Callback when Network Diagnostic Get response is received (can be NULL).
282      * @param[in]  Context           Application-specific context used with @p aCallback.
283      *
284      */
285     Error SendDiagnosticGet(const Ip6::Address &aDestination,
286                             const uint8_t       aTlvTypes[],
287                             uint8_t             aCount,
288                             GetCallback         aCallback,
289                             void               *Context);
290 
291     /**
292      * Sends Diagnostic Reset request.
293      *
294      * @param[in] aDestination  The destination address.
295      * @param[in] aTlvTypes     An array of Network Diagnostic TLV types.
296      * @param[in] aCount        Number of types in aTlvTypes
297      *
298      */
299     Error SendDiagnosticReset(const Ip6::Address &aDestination, const uint8_t aTlvTypes[], uint8_t aCount);
300 
301     /**
302      * Gets the next Network Diagnostic TLV in a given message.
303      *
304      * @param[in]      aMessage    Message to read TLVs from.
305      * @param[in,out]  aIterator   The Network Diagnostic iterator. To get the first TLV set it to `kIteratorInit`.
306      * @param[out]     aTlvInfo    A reference to a `TlvInfo` to output the next TLV data.
307      *
308      * @retval kErrorNone       Successfully found the next Network Diagnostic TLV.
309      * @retval kErrorNotFound   No subsequent Network Diagnostic TLV exists in the message.
310      * @retval kErrorParse      Parsing the next Network Diagnostic failed.
311      *
312      */
313     static Error GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator, TlvInfo &aTlvInfo);
314 
315     /**
316      * This method returns the query ID used for the last Network Diagnostic Query command.
317      *
318      * @returns The query ID used for last query.
319      *
320      */
GetLastQueryId(void) const321     uint16_t GetLastQueryId(void) const { return mQueryId; }
322 
323 private:
324     Error SendCommand(Uri                   aUri,
325                       Message::Priority     aPriority,
326                       const Ip6::Address   &aDestination,
327                       const uint8_t         aTlvTypes[],
328                       uint8_t               aCount,
329                       Coap::ResponseHandler aHandler = nullptr,
330                       void                 *aContext = nullptr);
331 
332     static void HandleGetResponse(void                *aContext,
333                                   otMessage           *aMessage,
334                                   const otMessageInfo *aMessageInfo,
335                                   Error                aResult);
336     void        HandleGetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult);
337 
338     template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
339 
340 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
341     static const char *UriToString(Uri aUri);
342 #endif
343 
344     uint16_t              mQueryId;
345     Callback<GetCallback> mGetCallback;
346 };
347 
348 DeclareTmfHandler(Client, kUriDiagnosticReset);
349 
350 #endif // OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
351 
352 /**
353  * @}
354  */
355 } // namespace NetworkDiagnostic
356 
357 } // namespace ot
358 
359 #endif // NETWORK_DIAGNOSTIC_HPP_
360