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