From 1e61811e70f396271f57113d22c0a39f4e008ea1 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 9 Aug 2017 21:48:57 -0700 Subject: [PATCH] [network-data] iterate over all external routes or on-mesh prefix entries (#2073) The same external route or on-mesh prefix can be registered by different devices with different flags (e.g., different preference level). This info is stored in network data as part of the BorderRouterEntry TLV. This commit changes the methods `GetNextOnMeshPrefix()` and `GetNextExternalRoute()` to ensure that different entries corresponding to the same prefix are provided separately when iterating over all entries (i.e., without giving a specific RLOC16). To implement this the `otNetworkDataIterator` is changed to track both the index into the `mTlvs` buffer and the entry index. This commit also appends an RLOC16 field to the struct packing format of `SPINEL_PROP_THREAD_ON_MESH_NETS and `OFF_MESH_ROUTES` spinel properties and updates the implementation and documentation accordingly. --- doc/spinel-protocol-src/spinel-tech-thread.md | 4 ++++ examples/drivers/windows/otLwf/iocontrol.c | 10 +++++----- include/openthread/types.h | 9 ++++++++- src/core/thread/network_data.cpp | 19 ++++++++++++------- src/core/thread/network_data.hpp | 15 +++++++++++++++ src/ncp/ncp_base_mtd.cpp | 16 ++++++++++++---- src/ncp/spinel.h | 4 +++- 7 files changed, 59 insertions(+), 18 deletions(-) diff --git a/doc/spinel-protocol-src/spinel-tech-thread.md b/doc/spinel-protocol-src/spinel-tech-thread.md index f410fd02f..02af2fc15 100644 --- a/doc/spinel-protocol-src/spinel-tech-thread.md +++ b/doc/spinel-protocol-src/spinel-tech-thread.md @@ -95,6 +95,8 @@ Data per item is: * `b`: "Is defined locally" flag. Set if this network was locally defined. Assumed to be true for set, insert and replace. Clear if the on mesh network was defined by another node. +* `S`: The RLOC16 of the device that registered this on-mesh prefix entry. + This value is not used and ignored when adding an on-mesh prefix. ### PROP 91: PROP_THREAD_OFF_MESH_ROUTES * Type: Read-Write @@ -114,6 +116,8 @@ Data per item is: route is this device itself (i.e., route was added by this device) This value is ignored when adding an external route. For any added route the next hop is this device. +* `S`: The RLOC16 of the device that registered this route entry. + This value is not used and ignored when adding a route. ### PROP 92: PROP_THREAD_ASSISTING_PORTS * Type: Read-Write diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c index c26c2e80c..3e435ae46 100644 --- a/examples/drivers/windows/otLwf/iocontrol.c +++ b/examples/drivers/windows/otLwf/iocontrol.c @@ -4833,12 +4833,12 @@ otLwfIoCtl_otNextOnMeshPrefix( { NTSTATUS status = STATUS_INVALID_PARAMETER; - if (InBufferLength >= sizeof(BOOLEAN) + sizeof(uint8_t) && - *OutBufferLength >= sizeof(uint8_t) + sizeof(otBorderRouterConfig)) + if (InBufferLength >= sizeof(BOOLEAN) + sizeof(uint16_t) && + *OutBufferLength >= sizeof(uint16_t) + sizeof(otBorderRouterConfig)) { BOOLEAN aLocal = *(BOOLEAN*)InBuffer; - uint8_t aIterator = *(uint8_t*)(InBuffer + sizeof(BOOLEAN)); - otBorderRouterConfig* aConfig = (otBorderRouterConfig*)((PUCHAR)OutBuffer + sizeof(uint8_t)); + uint16_t aIterator = *(uint16_t*)(InBuffer + sizeof(BOOLEAN)); + otBorderRouterConfig* aConfig = (otBorderRouterConfig*)((PUCHAR)OutBuffer + sizeof(uint16_t)); if (aLocal) { status = ThreadErrorToNtstatus( @@ -4860,7 +4860,7 @@ otLwfIoCtl_otNextOnMeshPrefix( *OutBufferLength = sizeof(uint8_t) + sizeof(otBorderRouterConfig); if (status == STATUS_SUCCESS) { - *(uint8_t*)OutBuffer = aIterator; + *(uint16_t*)OutBuffer = aIterator; } } else diff --git a/include/openthread/types.h b/include/openthread/types.h index e1606a4cd..37a414df8 100644 --- a/include/openthread/types.h +++ b/include/openthread/types.h @@ -696,7 +696,7 @@ typedef struct otIp6Prefix #define OT_NETWORK_DATA_ITERATOR_INIT 0 ///< Initializer for otNetworkDataIterator. -typedef uint8_t otNetworkDataIterator; ///< Used to iterate through Network Data information. +typedef uint16_t otNetworkDataIterator; ///< Used to iterate through Network Data information. /** * This structure represents a Border Router configuration. @@ -764,6 +764,13 @@ typedef struct otExternalRouteConfig */ otIp6Prefix mPrefix; + /** + * The Rloc associated with the external route entry. + * + * This value is ignored when adding an external route. For any added route the device's Rloc will be used. + */ + uint16_t mRloc16; + /** * A 2-bit signed integer indicating router preference as defined in RFC 4291. */ diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp index e0a824efe..5f11d7170 100644 --- a/src/core/thread/network_data.cpp +++ b/src/core/thread/network_data.cpp @@ -88,10 +88,11 @@ otError NetworkData::GetNextOnMeshPrefix(otNetworkDataIterator *aIterator, uint1 otBorderRouterConfig *aConfig) { otError error = OT_ERROR_NOT_FOUND; - NetworkDataTlv *cur = reinterpret_cast(mTlvs + *aIterator); + NetworkDataIterator iterator(aIterator); + NetworkDataTlv *cur = reinterpret_cast(mTlvs + iterator.GetTlvsIndex()); NetworkDataTlv *end = reinterpret_cast(mTlvs + mLength); - for (; cur < end; cur = cur->GetNext()) + for (; cur < end; cur = cur->GetNext(), iterator.SetEntryIndex(0)) { PrefixTlv *prefix; BorderRouterTlv *borderRouter; @@ -109,11 +110,12 @@ otError NetworkData::GetNextOnMeshPrefix(otNetworkDataIterator *aIterator, uint1 continue; } - for (uint8_t i = 0; i < borderRouter->GetNumEntries(); i++) + for (uint8_t i = iterator.GetEntryIndex(); i < borderRouter->GetNumEntries(); i++) { if (aRloc16 == Mac::kShortAddrBroadcast || borderRouter->GetEntry(i)->GetRloc() == aRloc16) { borderRouterEntry = borderRouter->GetEntry(i); + iterator.SetEntryIndex(i + 1); break; } } @@ -136,7 +138,7 @@ otError NetworkData::GetNextOnMeshPrefix(otNetworkDataIterator *aIterator, uint1 aConfig->mStable = cur->IsStable(); aConfig->mRloc16 = borderRouterEntry->GetRloc(); - *aIterator = static_cast(reinterpret_cast(cur->GetNext()) - mTlvs); + iterator.SetTlvsIndex(static_cast(reinterpret_cast(cur) - mTlvs)); ExitNow(error = OT_ERROR_NONE); } @@ -154,10 +156,11 @@ otError NetworkData::GetNextExternalRoute(otNetworkDataIterator *aIterator, uint otExternalRouteConfig *aConfig) { otError error = OT_ERROR_NOT_FOUND; - NetworkDataTlv *cur = reinterpret_cast(mTlvs + *aIterator); + NetworkDataIterator iterator(aIterator); + NetworkDataTlv *cur = reinterpret_cast(mTlvs + iterator.GetTlvsIndex()); NetworkDataTlv *end = reinterpret_cast(mTlvs + mLength); - for (; cur < end; cur = cur->GetNext()) + for (; cur < end; cur = cur->GetNext(), iterator.SetEntryIndex(0)) { PrefixTlv *prefix; HasRouteTlv *hasRoute; @@ -175,11 +178,12 @@ otError NetworkData::GetNextExternalRoute(otNetworkDataIterator *aIterator, uint continue; } - for (uint8_t i = 0; i < hasRoute->GetNumEntries(); i++) + for (uint8_t i = iterator.GetEntryIndex(); i < hasRoute->GetNumEntries(); i++) { if (aRloc16 == Mac::kShortAddrBroadcast || hasRoute->GetEntry(i)->GetRloc() == aRloc16) { hasRouteEntry = hasRoute->GetEntry(i); + iterator.SetEntryIndex(i + 1); break; } } @@ -194,6 +198,7 @@ otError NetworkData::GetNextExternalRoute(otNetworkDataIterator *aIterator, uint aConfig->mPrefix.mLength = prefix->GetPrefixLength(); aConfig->mPreference = hasRouteEntry->GetPreference(); aConfig->mStable = cur->IsStable(); + aConfig->mRloc16 = hasRouteEntry->GetRloc(); aConfig->mNextHopIsThisDevice = (hasRouteEntry->GetRloc() == GetNetif().GetMle().GetRloc16()); *aIterator = static_cast(reinterpret_cast(cur->GetNext()) - mTlvs); diff --git a/src/core/thread/network_data.hpp b/src/core/thread/network_data.hpp index b045747d3..8df508143 100644 --- a/src/core/thread/network_data.hpp +++ b/src/core/thread/network_data.hpp @@ -353,6 +353,21 @@ private: kDataResubmitDelay = 300000, ///< DATA_RESUBMIT_DELAY (miliseconds) }; + class NetworkDataIterator + { + public: + NetworkDataIterator(otNetworkDataIterator *aIterator): + mIteratorBuffer(reinterpret_cast(aIterator)) { } + + uint8_t GetTlvsIndex(void) const { return mIteratorBuffer[0]; } + uint8_t GetEntryIndex(void) const { return mIteratorBuffer[1]; } + void SetTlvsIndex(uint8_t aIndex) { mIteratorBuffer[0] = aIndex; } + void SetEntryIndex(uint8_t aIndex) { mIteratorBuffer[1] = aIndex; } + + private: + uint8_t *mIteratorBuffer; + }; + const bool mLocal; bool mLastAttemptWait; uint32_t mLastAttempt; diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index f846d1d3a..d98c43e2e 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -1078,12 +1078,14 @@ otError NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_ SPINEL_DATATYPE_BOOL_S // isStable SPINEL_DATATYPE_UINT8_S // Flags SPINEL_DATATYPE_BOOL_S // isLocal + SPINEL_DATATYPE_UINT16_S // RLOC16 ), &borderRouterConfig.mPrefix, 64, borderRouterConfig.mStable, flags, - false + false, + borderRouterConfig.mRloc16 )); } @@ -1108,12 +1110,14 @@ otError NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_ SPINEL_DATATYPE_BOOL_S // isStable SPINEL_DATATYPE_UINT8_S // Flags SPINEL_DATATYPE_BOOL_S // isLocal + SPINEL_DATATYPE_UINT16_S // RLOC16 ), &borderRouterConfig.mPrefix, 64, borderRouterConfig.mStable, flags, - true + true, + borderRouterConfig.mRloc16 )); } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER @@ -1801,13 +1805,15 @@ otError NcpBase::GetPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spin SPINEL_DATATYPE_UINT8_S // Route Preference Flags SPINEL_DATATYPE_BOOL_S // IsLocal SPINEL_DATATYPE_BOOL_S // NextHopIsThisDevice + SPINEL_DATATYPE_UINT16_S // RLOC16 ), &external_route_config.mPrefix.mPrefix, external_route_config.mPrefix.mLength, external_route_config.mStable, ExternalRoutePreferenceToFlagByte(external_route_config.mPreference), false, - external_route_config.mNextHopIsThisDevice + external_route_config.mNextHopIsThisDevice, + external_route_config.mRloc16 )); } @@ -1823,13 +1829,15 @@ otError NcpBase::GetPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spin SPINEL_DATATYPE_UINT8_S // Route Preference Flags SPINEL_DATATYPE_BOOL_S // IsLocal SPINEL_DATATYPE_BOOL_S // NextHopIsThisDevice + SPINEL_DATATYPE_UINT16_S // RLOC16 ), &external_route_config.mPrefix.mPrefix, external_route_config.mPrefix.mLength, external_route_config.mStable, ExternalRoutePreferenceToFlagByte(external_route_config.mPreference), true, - external_route_config.mNextHopIsThisDevice + external_route_config.mNextHopIsThisDevice, + external_route_config.mRloc16 )); } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index a28234121..e431cea7c 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -807,7 +807,7 @@ typedef enum = SPINEL_PROP_THREAD__BEGIN + 8, ///< [D] SPINEL_PROP_THREAD_STABLE_NETWORK_DATA_VERSION = SPINEL_PROP_THREAD__BEGIN + 9, ///< [S] - SPINEL_PROP_THREAD_ON_MESH_NETS = SPINEL_PROP_THREAD__BEGIN + 10, ///< array(ipv6prefix,prefixlen,stable,flags,isLocal) [A(t(6CbCb))] + SPINEL_PROP_THREAD_ON_MESH_NETS = SPINEL_PROP_THREAD__BEGIN + 10, ///< array(ipv6prefix,prefixlen,stable,flags,isLocal,rloc6) [A(t(6CbCbS))] /// Off-mesh routes /** Format: [A(t(6CbCbb))] @@ -826,6 +826,8 @@ typedef enum * route is this device itself (i.e., route was added by this device) * This value is ignored when adding an external route. For any added * route the next hop is this device. + * `S`: The RLOC16 of the device that registered this route entry. + * This value is not used and ignored when adding a route. * */ SPINEL_PROP_THREAD_OFF_MESH_ROUTES = SPINEL_PROP_THREAD__BEGIN + 11,