• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2023, 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 Mesh Diagnostic module.
32  */
33 
34 #ifndef MESH_DIAG_HPP_
35 #define MESH_DIAG_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
40 
41 #if !OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE
42 #error "OPENTHREAD_CONFIG_MESH_DIAG_ENABLE requires OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE"
43 #endif
44 
45 #include <openthread/mesh_diag.h>
46 
47 #include "coap/coap.hpp"
48 #include "common/callback.hpp"
49 #include "common/locator.hpp"
50 #include "common/message.hpp"
51 #include "common/timer.hpp"
52 #include "net/ip6_address.hpp"
53 #include "thread/network_diagnostic.hpp"
54 #include "thread/network_diagnostic_tlvs.hpp"
55 
56 struct otMeshDiagIp6AddrIterator
57 {
58 };
59 
60 struct otMeshDiagChildIterator
61 {
62 };
63 
64 namespace ot {
65 namespace Utils {
66 
67 /**
68  * Implements the Mesh Diagnostics.
69  */
70 class MeshDiag : public InstanceLocator
71 {
72     friend class ot::NetworkDiagnostic::Client;
73 
74 public:
75     static constexpr uint16_t kVersionUnknown = OT_MESH_DIAG_VERSION_UNKNOWN; ///< Unknown version.
76 
77     typedef otMeshDiagDiscoverConfig                   DiscoverConfig;              ///< Discovery configuration.
78     typedef otMeshDiagDiscoverCallback                 DiscoverCallback;            ///< Discovery callback.
79     typedef otMeshDiagQueryChildTableCallback          QueryChildTableCallback;     ///< Query Child Table callback.
80     typedef otMeshDiagChildIp6AddrsCallback            ChildIp6AddrsCallback;       ///< Child IPv6 addresses callback.
81     typedef otMeshDiagQueryRouterNeighborTableCallback RouterNeighborTableCallback; ///< Neighbor table callback.
82 
83     /**
84      * Represents an iterator to go over list of IPv6 addresses of a router or an MTD child.
85      */
86     class Ip6AddrIterator : public otMeshDiagIp6AddrIterator
87     {
88         friend class MeshDiag;
89 
90     public:
91         /**
92          * Iterates through the discovered IPv6 address of a router.
93          *
94          * @param[out]     aAddress  A reference to return the next IPv6 address (if any).
95          *
96          * @retval kErrorNone      Successfully retrieved the next address. @p aAddress is updated.
97          * @retval kErrorNotFound  No more address. Reached the end of the list.
98          */
99         Error GetNextAddress(Ip6::Address &aAddress);
100 
101     private:
102         Error InitFrom(const Message &aMessage);
103 
104         const Message *mMessage;
105         OffsetRange    mOffsetRange;
106     };
107 
108     /**
109      * Represents information about a router in Thread mesh.
110      */
111     class RouterInfo : public otMeshDiagRouterInfo, public Clearable<RouterInfo>
112     {
113         friend class MeshDiag;
114 
115     private:
116         Error ParseFrom(const Message &aMessage);
117     };
118 
119     /**
120      * Represents information about a child in Thread mesh.
121      */
122     class ChildInfo : public otMeshDiagChildInfo, public Clearable<ChildInfo>
123     {
124     };
125 
126     /**
127      * Represents an iterator to go over list of IPv6 addresses of a router.
128      */
129     class ChildIterator : public otMeshDiagChildIterator
130     {
131         friend class MeshDiag;
132 
133     public:
134         /**
135          * Iterates through the discovered children of a router.
136          *
137          * @param[out]     aChildInfo  A reference to return the info for the next child (if any).
138          *
139          * @retval kErrorNone      Successfully retrieved the next child info. @p aChildInfo is updated.
140          * @retval kErrorNotFound  No more child entry. Reached the end of the list.
141          */
142         Error GetNextChildInfo(ChildInfo &aChildInfo);
143 
144     private:
145         Error InitFrom(const Message &aMessage, uint16_t aParentRloc16);
146 
147         const Message *mMessage;
148         OffsetRange    mOffsetRange;
149         uint16_t       mParentRloc16;
150     };
151 
152     /**
153      * Initializes the `MeshDiag` instance.
154      *
155      * @param[in] aInstance   The OpenThread instance.
156      */
157     explicit MeshDiag(Instance &aInstance);
158 
159     /**
160      * Starts network topology discovery.
161      *
162      * @param[in] aConfig          The configuration to use for discovery (e.g., which items to discover).
163      * @param[in] aCallback        The callback to report the discovered routers.
164      * @param[in] aContext         A context to pass in @p aCallback.
165      *
166      * @retval kErrorNone          The network topology discovery started successfully.
167      * @retval kErrorBusy          A previous discovery or query request is still ongoing.
168      * @retval kErrorInvalidState  Device is not attached.
169      * @retval kErrorNoBufs        Could not allocate buffer to send discovery messages.
170      */
171     Error DiscoverTopology(const DiscoverConfig &aConfig, DiscoverCallback aCallback, void *aContext);
172 
173     /**
174      * Starts query for child table for a given router.
175      *
176      * @param[in] aRloc16          The RLOC16 of router to query.
177      * @param[in] aCallback        The callback to report the queried child table.
178      * @param[in] aContext         A context to pass in @p aCallback.
179      *
180      * @retval kErrorNone          The query started successfully.
181      * @retval kErrorBusy          A previous discovery or query request is still ongoing.
182      * @retval kErrorInvalidArgs   The @p aRloc16 is not a valid router RLOC16.
183      * @retval kErrorInvalidState  Device is not attached.
184      * @retval kErrorNoBufs        Could not allocate buffer to send query messages.
185      */
186     Error QueryChildTable(uint16_t aRloc16, QueryChildTableCallback aCallback, void *aContext);
187 
188     /**
189      * Sends a query to a parent to retrieve the IPv6 addresses of all its MTD children.
190      *
191      * @param[in] aRloc16          The RLOC16 of parent to query.
192      * @param[in] aCallback        The callback to report the queried child IPv6 address list.
193      * @param[in] aContext         A context to pass in @p aCallback.
194      *
195      * @retval kErrorNone          The query started successfully.
196      * @retval kErrorBusy          A previous discovery or query request is still ongoing.
197      * @retval kErrorInvalidArgs   The @p aRloc16 is not a valid  RLOC16.
198      * @retval kErrorInvalidState  Device is not attached.
199      * @retval kErrorNoBufs        Could not allocate buffer to send query messages.
200      */
201     Error QueryChildrenIp6Addrs(uint16_t aRloc16, ChildIp6AddrsCallback aCallback, void *aContext);
202 
203     /**
204      * Starts query for router neighbor table for a given router.
205      *
206      * @param[in] aRloc16          The RLOC16 of router to query.
207      * @param[in] aCallback        The callback to report the queried table.
208      * @param[in] aContext         A context to pass in @p aCallback.
209      *
210      * @retval kErrorNone          The query started successfully.
211      * @retval kErrorBusy          A previous discovery or query request is still ongoing.
212      * @retval kErrorInvalidArgs   The @p aRloc16 is not a valid router RLOC16.
213      * @retval kErrorInvalidState  Device is not attached.
214      * @retval kErrorNoBufs        Could not allocate buffer to send query messages.
215      */
216     Error QueryRouterNeighborTable(uint16_t aRloc16, RouterNeighborTableCallback aCallback, void *aContext);
217 
218     /**
219      * Cancels an ongoing discovery or query operation if there one, otherwise no action.
220      *
221      * When ongoing discovery is cancelled, the callback from `DiscoverTopology()` or  `QueryChildTable()` will not be
222      * called anymore.
223      */
224     void Cancel(void);
225 
226 private:
227     typedef ot::NetworkDiagnostic::Tlv Tlv;
228 
229     static constexpr uint32_t kResponseTimeout = OPENTHREAD_CONFIG_MESH_DIAG_RESPONSE_TIMEOUT;
230 
231     enum State : uint8_t
232     {
233         kStateIdle,
234         kStateDiscoverTopology,
235         kStateQueryChildTable,
236         kStateQueryChildrenIp6Addrs,
237         kStateQueryRouterNeighborTable,
238     };
239 
240     struct DiscoverInfo
241     {
242         Callback<DiscoverCallback> mCallback;
243         Mle::RouterIdSet           mExpectedRouterIdSet;
244     };
245 
246     struct QueryChildTableInfo
247     {
248         Callback<QueryChildTableCallback> mCallback;
249         uint16_t                          mRouterRloc16;
250     };
251 
252     struct QueryChildrenIp6AddrsInfo
253     {
254         Callback<ChildIp6AddrsCallback> mCallback;
255         uint16_t                        mParentRloc16;
256     };
257 
258     struct QueryRouterNeighborTableInfo
259     {
260         Callback<RouterNeighborTableCallback> mCallback;
261         uint16_t                              mRouterRloc16;
262     };
263 
264     class ChildEntry : public otMeshDiagChildEntry
265     {
266         friend class MeshDiag;
267 
268     private:
269         void SetFrom(const NetworkDiagnostic::ChildTlv &aChildTlv);
270     };
271 
272     class RouterNeighborEntry : public otMeshDiagRouterNeighborEntry
273     {
274         friend class MeshDiag;
275 
276     private:
277         void SetFrom(const NetworkDiagnostic::RouterNeighborTlv &aTlv);
278     };
279 
280     Error SendQuery(uint16_t aRloc16, const uint8_t *aTlvs, uint8_t aTlvsLength);
281     void  Finalize(Error aError);
282     void  HandleTimer(void);
283     bool  HandleDiagnosticGetAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
284     Error ProcessMessage(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint16_t aSenderRloc16);
285     bool  ProcessChildTableAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
286     bool  ProcessChildrenIp6AddrsAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
287     bool  ProcessRouterNeighborTableAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
288 
289     void HandleDiagGetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult);
290 
291     static void HandleDiagGetResponse(void                *aContext,
292                                       otMessage           *aMessage,
293                                       const otMessageInfo *aMessageInfo,
294                                       otError              aResult);
295 
296     using TimeoutTimer = TimerMilliIn<MeshDiag, &MeshDiag::HandleTimer>;
297 
298     State        mState;
299     uint16_t     mExpectedQueryId;
300     uint16_t     mExpectedAnswerIndex;
301     TimeoutTimer mTimer;
302 
303     union
304     {
305         DiscoverInfo                 mDiscover;
306         QueryChildTableInfo          mQueryChildTable;
307         QueryChildrenIp6AddrsInfo    mQueryChildrenIp6Addrs;
308         QueryRouterNeighborTableInfo mQueryRouterNeighborTable;
309     };
310 };
311 
312 } // namespace Utils
313 
314 DefineCoreType(otMeshDiagIp6AddrIterator, Utils::MeshDiag::Ip6AddrIterator);
315 DefineCoreType(otMeshDiagRouterInfo, Utils::MeshDiag::RouterInfo);
316 DefineCoreType(otMeshDiagChildInfo, Utils::MeshDiag::ChildInfo);
317 DefineCoreType(otMeshDiagChildIterator, Utils::MeshDiag::ChildIterator);
318 
319 } // namespace ot
320 
321 #endif // OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD
322 
323 #endif // MESH_DIAG_HPP_
324