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