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