| /* |
| * Copyright (c) 2023, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** |
| * @file |
| * This file includes definitions for Mesh Diagnostic module. |
| */ |
| |
| #ifndef MESH_DIAG_HPP_ |
| #define MESH_DIAG_HPP_ |
| |
| #include "openthread-core-config.h" |
| |
| #if OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD |
| |
| #if !OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE |
| #error "OPENTHREAD_CONFIG_MESH_DIAG_ENABLE requires OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE" |
| #endif |
| |
| #include <openthread/mesh_diag.h> |
| |
| #include "coap/coap.hpp" |
| #include "common/callback.hpp" |
| #include "common/locator.hpp" |
| #include "common/message.hpp" |
| #include "common/timer.hpp" |
| #include "net/ip6_address.hpp" |
| #include "thread/network_diagnostic.hpp" |
| #include "thread/network_diagnostic_tlvs.hpp" |
| |
| struct otMeshDiagIp6AddrIterator |
| { |
| }; |
| |
| struct otMeshDiagChildIterator |
| { |
| }; |
| |
| namespace ot { |
| namespace Utils { |
| |
| /** |
| * Implements the Mesh Diagnostics. |
| * |
| */ |
| class MeshDiag : public InstanceLocator |
| { |
| friend class ot::NetworkDiagnostic::Client; |
| |
| public: |
| static constexpr uint16_t kVersionUnknown = OT_MESH_DIAG_VERSION_UNKNOWN; ///< Unknown version. |
| |
| typedef otMeshDiagDiscoverConfig DiscoverConfig; ///< Discovery configuration. |
| typedef otMeshDiagDiscoverCallback DiscoverCallback; ///< Discovery callback. |
| typedef otMeshDiagQueryChildTableCallback QueryChildTableCallback; ///< Query Child Table callback. |
| typedef otMeshDiagChildIp6AddrsCallback ChildIp6AddrsCallback; ///< Child IPv6 addresses callback. |
| typedef otMeshDiagQueryRouterNeighborTableCallback RouterNeighborTableCallback; ///< Neighbor table callback. |
| |
| /** |
| * Represents an iterator to go over list of IPv6 addresses of a router or an MTD child. |
| * |
| */ |
| class Ip6AddrIterator : public otMeshDiagIp6AddrIterator |
| { |
| friend class MeshDiag; |
| |
| public: |
| /** |
| * Iterates through the discovered IPv6 address of a router. |
| * |
| * @param[out] aAddress A reference to return the next IPv6 address (if any). |
| * |
| * @retval kErrorNone Successfully retrieved the next address. @p aAddress is updated. |
| * @retval kErrorNotFound No more address. Reached the end of the list. |
| * |
| */ |
| Error GetNextAddress(Ip6::Address &aAddress); |
| |
| private: |
| Error InitFrom(const Message &aMessage); |
| |
| const Message *mMessage; |
| uint16_t mCurOffset; |
| uint16_t mEndOffset; |
| }; |
| |
| /** |
| * Represents information about a router in Thread mesh. |
| * |
| */ |
| class RouterInfo : public otMeshDiagRouterInfo, public Clearable<RouterInfo> |
| { |
| friend class MeshDiag; |
| |
| private: |
| Error ParseFrom(const Message &aMessage); |
| }; |
| |
| /** |
| * Represents information about a child in Thread mesh. |
| * |
| */ |
| class ChildInfo : public otMeshDiagChildInfo, public Clearable<ChildInfo> |
| { |
| }; |
| |
| /** |
| * Represents an iterator to go over list of IPv6 addresses of a router. |
| * |
| */ |
| class ChildIterator : public otMeshDiagChildIterator |
| { |
| friend class MeshDiag; |
| |
| public: |
| /** |
| * Iterates through the discovered children of a router. |
| * |
| * @param[out] aChildInfo A reference to return the info for the next child (if any). |
| * |
| * @retval kErrorNone Successfully retrieved the next child info. @p aChildInfo is updated. |
| * @retval kErrorNotFound No more child entry. Reached the end of the list. |
| * |
| */ |
| Error GetNextChildInfo(ChildInfo &aChildInfo); |
| |
| private: |
| Error InitFrom(const Message &aMessage, uint16_t aParentRloc16); |
| |
| const Message *mMessage; |
| uint16_t mCurOffset; |
| uint16_t mEndOffset; |
| uint16_t mParentRloc16; |
| }; |
| |
| /** |
| * Initializes the `MeshDiag` instance. |
| * |
| * @param[in] aInstance The OpenThread instance. |
| * |
| */ |
| explicit MeshDiag(Instance &aInstance); |
| |
| /** |
| * Starts network topology discovery. |
| * |
| * @param[in] aConfig The configuration to use for discovery (e.g., which items to discover). |
| * @param[in] aCallback The callback to report the discovered routers. |
| * @param[in] aContext A context to pass in @p aCallback. |
| * |
| * @retval kErrorNone The network topology discovery started successfully. |
| * @retval kErrorBusy A previous discovery or query request is still ongoing. |
| * @retval kErrorInvalidState Device is not attached. |
| * @retval kErrorNoBufs Could not allocate buffer to send discovery messages. |
| * |
| */ |
| Error DiscoverTopology(const DiscoverConfig &aConfig, DiscoverCallback aCallback, void *aContext); |
| |
| /** |
| * Starts query for child table for a given router. |
| * |
| * @param[in] aRloc16 The RLOC16 of router to query. |
| * @param[in] aCallback The callback to report the queried child table. |
| * @param[in] aContext A context to pass in @p aCallback. |
| * |
| * @retval kErrorNone The query started successfully. |
| * @retval kErrorBusy A previous discovery or query request is still ongoing. |
| * @retval kErrorInvalidArgs The @p aRloc16 is not a valid router RLOC16. |
| * @retval kErrorInvalidState Device is not attached. |
| * @retval kErrorNoBufs Could not allocate buffer to send query messages. |
| * |
| */ |
| Error QueryChildTable(uint16_t aRloc16, QueryChildTableCallback aCallback, void *aContext); |
| |
| /** |
| * Sends a query to a parent to retrieve the IPv6 addresses of all its MTD children. |
| * |
| * @param[in] aRloc16 The RLOC16 of parent to query. |
| * @param[in] aCallback The callback to report the queried child IPv6 address list. |
| * @param[in] aContext A context to pass in @p aCallback. |
| * |
| * @retval kErrorNone The query started successfully. |
| * @retval kErrorBusy A previous discovery or query request is still ongoing. |
| * @retval kErrorInvalidArgs The @p aRloc16 is not a valid RLOC16. |
| * @retval kErrorInvalidState Device is not attached. |
| * @retval kErrorNoBufs Could not allocate buffer to send query messages. |
| * |
| */ |
| Error QueryChildrenIp6Addrs(uint16_t aRloc16, ChildIp6AddrsCallback aCallback, void *aContext); |
| |
| /** |
| * Starts query for router neighbor table for a given router. |
| * |
| * @param[in] aRloc16 The RLOC16 of router to query. |
| * @param[in] aCallback The callback to report the queried table. |
| * @param[in] aContext A context to pass in @p aCallback. |
| * |
| * @retval kErrorNone The query started successfully. |
| * @retval kErrorBusy A previous discovery or query request is still ongoing. |
| * @retval kErrorInvalidArgs The @p aRloc16 is not a valid router RLOC16. |
| * @retval kErrorInvalidState Device is not attached. |
| * @retval kErrorNoBufs Could not allocate buffer to send query messages. |
| * |
| */ |
| Error QueryRouterNeighborTable(uint16_t aRloc16, RouterNeighborTableCallback aCallback, void *aContext); |
| |
| /** |
| * Cancels an ongoing discovery or query operation if there one, otherwise no action. |
| * |
| * When ongoing discovery is cancelled, the callback from `DiscoverTopology()` or `QueryChildTable()` will not be |
| * called anymore. |
| * |
| */ |
| void Cancel(void); |
| |
| private: |
| typedef ot::NetworkDiagnostic::Tlv Tlv; |
| |
| static constexpr uint32_t kResponseTimeout = OPENTHREAD_CONFIG_MESH_DIAG_RESPONSE_TIMEOUT; |
| |
| enum State : uint8_t |
| { |
| kStateIdle, |
| kStateDicoverTopology, |
| kStateQueryChildTable, |
| kStateQueryChildrenIp6Addrs, |
| kStateQueryRouterNeighborTable, |
| }; |
| |
| struct DiscoverInfo |
| { |
| Callback<DiscoverCallback> mCallback; |
| Mle::RouterIdSet mExpectedRouterIdSet; |
| }; |
| |
| struct QueryChildTableInfo |
| { |
| Callback<QueryChildTableCallback> mCallback; |
| uint16_t mRouterRloc16; |
| }; |
| |
| struct QueryChildrenIp6AddrsInfo |
| { |
| Callback<ChildIp6AddrsCallback> mCallback; |
| uint16_t mParentRloc16; |
| }; |
| |
| struct QueryRouterNeighborTableInfo |
| { |
| Callback<RouterNeighborTableCallback> mCallback; |
| uint16_t mRouterRloc16; |
| }; |
| |
| class ChildEntry : public otMeshDiagChildEntry |
| { |
| friend class MeshDiag; |
| |
| private: |
| void SetFrom(const NetworkDiagnostic::ChildTlv &aChildTlv); |
| }; |
| |
| class RouterNeighborEntry : public otMeshDiagRouterNeighborEntry |
| { |
| friend class MeshDiag; |
| |
| private: |
| void SetFrom(const NetworkDiagnostic::RouterNeighborTlv &aTlv); |
| }; |
| |
| Error SendQuery(uint16_t aRloc16, const uint8_t *aTlvs, uint8_t aTlvsLength); |
| void Finalize(Error aError); |
| void HandleTimer(void); |
| bool HandleDiagnosticGetAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); |
| Error ProcessMessage(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint16_t aSenderRloc16); |
| bool ProcessChildTableAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); |
| bool ProcessChildrenIp6AddrsAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); |
| bool ProcessRouterNeighborTableAnswer(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); |
| |
| void HandleDiagGetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult); |
| |
| static void HandleDiagGetResponse(void *aContext, |
| otMessage *aMessage, |
| const otMessageInfo *aMessageInfo, |
| Error aResult); |
| |
| using TimeoutTimer = TimerMilliIn<MeshDiag, &MeshDiag::HandleTimer>; |
| |
| State mState; |
| uint16_t mExpectedQueryId; |
| uint16_t mExpectedAnswerIndex; |
| TimeoutTimer mTimer; |
| |
| union |
| { |
| DiscoverInfo mDiscover; |
| QueryChildTableInfo mQueryChildTable; |
| QueryChildrenIp6AddrsInfo mQueryChildrenIp6Addrs; |
| QueryRouterNeighborTableInfo mQueryRouterNeighborTable; |
| }; |
| }; |
| |
| } // namespace Utils |
| |
| DefineCoreType(otMeshDiagIp6AddrIterator, Utils::MeshDiag::Ip6AddrIterator); |
| DefineCoreType(otMeshDiagRouterInfo, Utils::MeshDiag::RouterInfo); |
| DefineCoreType(otMeshDiagChildInfo, Utils::MeshDiag::ChildInfo); |
| DefineCoreType(otMeshDiagChildIterator, Utils::MeshDiag::ChildIterator); |
| |
| } // namespace ot |
| |
| #endif // OPENTHREAD_CONFIG_MESH_DIAG_ENABLE && OPENTHREAD_FTD |
| |
| #endif // MESH_DIAG_HPP_ |