diff --git a/doc/spinel-protocol-src/spinel-tech-thread.md b/doc/spinel-protocol-src/spinel-tech-thread.md index 02af2fc15..4b5772751 100644 --- a/doc/spinel-protocol-src/spinel-tech-thread.md +++ b/doc/spinel-protocol-src/spinel-tech-thread.md @@ -335,3 +335,20 @@ Response messages. * All zeros to clear the steering data (indicating no steering data). * All 0xFFs to set the steering data (bloom filter) to accept/allow all. * A specific EUI64 which is then added to steering data/bloom filter. + +### PROP 5399: SPINEL_PROP_THREAD_ROUTER_TABLE {#prop-thread-router-table} + +* Type: Read-Only +* Packed-Encoding: `A(t(ESCCCCCCb)` + +Data per item is: + +* `E`: IEEE 802.15.4 Extended Address +* `S`: RLOC16 +* `C`: Router ID +* `C`: Next hop to router +* `C`: Path cost to router +* `C`: Link Quality In +* `C`: Link Quality Out +* `C`: Age (seconds since last heard) +* `b`: Link established with Router ID or not. diff --git a/include/openthread/thread_ftd.h b/include/openthread/thread_ftd.h index 7aecdee6e..b1f59159f 100644 --- a/include/openthread/thread_ftd.h +++ b/include/openthread/thread_ftd.h @@ -372,9 +372,20 @@ OTAPI otError OTCALL otThreadGetChildInfoByIndex(otInstance *aInstance, uint8_t * @param[in] aInstance A pointer to an OpenThread instance. * * @returns The Router ID Sequence. + * */ OTAPI uint8_t OTCALL otThreadGetRouterIdSequence(otInstance *aInstance); +/** + * The function returns the maximum allowed router ID + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The maximum allowed router ID. + * + */ +uint8_t otThreadGetMaxRouterId(otInstance *aInstance); + /** * The function retains diagnostic information for a given Thread Router. * @@ -382,6 +393,10 @@ OTAPI uint8_t OTCALL otThreadGetRouterIdSequence(otInstance *aInstance); * @param[in] aRouterId The router ID or RLOC16 for a given router. * @param[out] aRouterInfo A pointer to where the router information is placed. * + * @retval OT_ERROR_NONE Successfully retrieved the router info for given id. + * @retval OT_ERROR_NOT_FOUND No router entry with the given id. + * @retval OT_ERROR_INVALID_ARGS @p aRouterInfo is NULL. + * */ OTAPI otError OTCALL otThreadGetRouterInfo(otInstance *aInstance, uint16_t aRouterId, otRouterInfo *aRouterInfo); diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index c05e292bc..f43bf68c5 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -38,8 +38,8 @@ #if OPENTHREAD_FTD #include -#include "openthread-core-config.h" #include "openthread-instance.h" +#include "thread/mle_constants.hpp" using namespace ot; @@ -214,6 +214,12 @@ uint8_t otThreadGetRouterIdSequence(otInstance *aInstance) return aInstance->mThreadNetif.GetMle().GetRouterIdSequence(); } +uint8_t otThreadGetMaxRouterId(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + return Mle::kMaxRouterId; +} + otError otThreadGetRouterInfo(otInstance *aInstance, uint16_t aRouterId, otRouterInfo *aRouterInfo) { otError error = OT_ERROR_NONE; diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 26989835d..0bafc4807 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3773,7 +3773,7 @@ otError MleRouter::GetRouterInfo(uint16_t aRouterId, otRouterInfo &aRouterInfo) } router = GetRouter(routerId); - VerifyOrExit(router != NULL, error = OT_ERROR_INVALID_ARGS); + VerifyOrExit(router != NULL, error = OT_ERROR_NOT_FOUND); memcpy(&aRouterInfo.mExtAddress, &router->GetExtAddress(), sizeof(aRouterInfo.mExtAddress)); diff --git a/src/core/thread/mle_router_ftd.hpp b/src/core/thread/mle_router_ftd.hpp index 2e450f8ae..c7b763320 100644 --- a/src/core/thread/mle_router_ftd.hpp +++ b/src/core/thread/mle_router_ftd.hpp @@ -583,6 +583,9 @@ public: * @param[in] aRouterId The router ID or RLOC16 for a given router. * @param[out] aRouterInfo The router information. * + * @retval OT_ERROR_NONE Successfully retrieved the router info for given id. + * @retval OT_ERROR_NOT_FOUND No router entry with the given id. + * */ otError GetRouterInfo(uint16_t aRouterId, otRouterInfo &aRouterInfo); diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 0d0fc5730..c9d0b89b4 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -208,6 +208,7 @@ const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = NCP_GET_PROP_HANDLER_ENTRY(NET_PSKC), NCP_GET_PROP_HANDLER_ENTRY(THREAD_LEADER_WEIGHT), NCP_GET_PROP_HANDLER_ENTRY(THREAD_CHILD_TABLE), + NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_TABLE), NCP_GET_PROP_HANDLER_ENTRY(THREAD_LOCAL_LEADER_WEIGHT), NCP_GET_PROP_HANDLER_ENTRY(THREAD_ROUTER_ROLE_ENABLED), NCP_GET_PROP_HANDLER_ENTRY(THREAD_CHILD_COUNT_MAX), diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 8715025a5..2beb56829 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -552,6 +552,7 @@ private: NCP_SET_PROP_HANDLER(NET_PSKC); NCP_GET_PROP_HANDLER(THREAD_CHILD_TABLE); + NCP_GET_PROP_HANDLER(THREAD_ROUTER_TABLE); NCP_GET_PROP_HANDLER(THREAD_CHILD_COUNT_MAX); NCP_SET_PROP_HANDLER(THREAD_CHILD_COUNT_MAX); NCP_SET_PROP_HANDLER(THREAD_CHILD_TIMEOUT); diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 8d8a5a82b..c9bded262 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -107,6 +107,40 @@ exit: return error; } +otError NcpBase::GetPropertyHandler_THREAD_ROUTER_TABLE(void) +{ + otError error = OT_ERROR_NONE; + otRouterInfo routerInfo; + uint8_t maxRouterId; + + maxRouterId = otThreadGetMaxRouterId(mInstance); + + for (uint8_t routerId = 0; routerId <= maxRouterId; routerId++) + { + if ((otThreadGetRouterInfo(mInstance, routerId, &routerInfo) != OT_ERROR_NONE) || !routerInfo.mAllocated) + { + continue; + } + + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteEui64(routerInfo.mExtAddress)); + SuccessOrExit(error = mEncoder.WriteUint16(routerInfo.mRloc16)); + SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mRouterId)); + SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mNextHop)); + SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mPathCost)); + SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mLinkQualityIn)); + SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mLinkQualityOut)); + SuccessOrExit(error = mEncoder.WriteUint8(routerInfo.mAge)); + SuccessOrExit(error = mEncoder.WriteBool(routerInfo.mLinkEstablished)); + + SuccessOrExit(error = mEncoder.CloseStruct()); + } + +exit: + return error; +} + otError NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(void) { return mEncoder.WriteBool(otThreadIsRouterRoleEnabled(mInstance)); diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c index 9803c3113..92f0f5b53 100644 --- a/src/ncp/spinel.c +++ b/src/ncp/spinel.c @@ -1421,6 +1421,10 @@ spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "PROP_THREAD_STEERING_DATA"; break; + case SPINEL_PROP_THREAD_ROUTER_TABLE: + ret = "PROP_THREAD_ROUTER_TABLE"; + break; + case SPINEL_PROP_IPV6_LL_ADDR: ret = "PROP_IPV6_LL_ADDR"; break; diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index 46ba06eb9..96d0b092a 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -1010,6 +1010,24 @@ typedef enum */ SPINEL_PROP_THREAD_STEERING_DATA = SPINEL_PROP_THREAD_EXT__BEGIN + 22, + /// Thread Router Table. + /** Format: `A(t(ESCCCCCCb)`. + * + * Data per item is: + * + * `E`: IEEE 802.15.4 Extended Address + * `S`: RLOC16 + * `C`: Router ID + * `C`: Next hop to router + * `C`: Path cost to router + * `C`: Link Quality In + * `C`: Link Quality Out + * `C`: Age (seconds since last heard) + * `b`: Link established with Router ID or not. + * + */ + SPINEL_PROP_THREAD_ROUTER_TABLE = SPINEL_PROP_THREAD_EXT__BEGIN + 23, + SPINEL_PROP_THREAD_EXT__END = 0x1600, SPINEL_PROP_IPV6__BEGIN = 0x60,