diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c index 3e435ae46..2bfe208c5 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(uint16_t) && - *OutBufferLength >= sizeof(uint16_t) + sizeof(otBorderRouterConfig)) + if (InBufferLength >= sizeof(BOOLEAN) + sizeof(uint32_t) && + *OutBufferLength >= sizeof(uint32_t) + sizeof(otBorderRouterConfig)) { BOOLEAN aLocal = *(BOOLEAN*)InBuffer; - uint16_t aIterator = *(uint16_t*)(InBuffer + sizeof(BOOLEAN)); - otBorderRouterConfig* aConfig = (otBorderRouterConfig*)((PUCHAR)OutBuffer + sizeof(uint16_t)); + uint32_t aIterator = *(uint32_t*)(InBuffer + sizeof(BOOLEAN)); + otBorderRouterConfig* aConfig = (otBorderRouterConfig*)((PUCHAR)OutBuffer + sizeof(uint32_t)); if (aLocal) { status = ThreadErrorToNtstatus( @@ -4860,7 +4860,7 @@ otLwfIoCtl_otNextOnMeshPrefix( *OutBufferLength = sizeof(uint8_t) + sizeof(otBorderRouterConfig); if (status == STATUS_SUCCESS) { - *(uint16_t*)OutBuffer = aIterator; + *(uint32_t*)OutBuffer = aIterator; } } else diff --git a/include/openthread/types.h b/include/openthread/types.h index 9a8eb98c7..f6e5628a5 100644 --- a/include/openthread/types.h +++ b/include/openthread/types.h @@ -696,9 +696,9 @@ typedef struct otIp6Prefix uint8_t mLength; ///< The IPv6 prefix length. } otIp6Prefix; -#define OT_NETWORK_DATA_ITERATOR_INIT 0 ///< Initializer for otNetworkDataIterator. +#define OT_NETWORK_DATA_ITERATOR_INIT 0 ///< Initializer for otNetworkDataIterator. -typedef uint16_t otNetworkDataIterator; ///< Used to iterate through Network Data information. +typedef uint32_t otNetworkDataIterator; ///< Used to iterate through Network Data information. /** * This structure represents a Border Router configuration. diff --git a/src/core/thread/network_data.cpp b/src/core/thread/network_data.cpp index 1cb7e4f04..dc890deb2 100644 --- a/src/core/thread/network_data.cpp +++ b/src/core/thread/network_data.cpp @@ -95,14 +95,14 @@ otError NetworkData::GetNextOnMeshPrefix(otNetworkDataIterator *aIterator, uint1 { otError error = OT_ERROR_NOT_FOUND; NetworkDataIterator iterator(aIterator); - NetworkDataTlv *cur = reinterpret_cast(mTlvs + iterator.GetTlvsIndex()); + NetworkDataTlv *cur = reinterpret_cast(mTlvs + iterator.GetTlvOffset()); NetworkDataTlv *end = reinterpret_cast(mTlvs + mLength); - for (; cur < end; cur = cur->GetNext(), iterator.SetEntryIndex(0)) + for (; cur < end; cur = cur->GetNext(), iterator.SetSubTlvOffset(0), iterator.SetEntryIndex(0)) { PrefixTlv *prefix; - BorderRouterTlv *borderRouter; - BorderRouterEntry *borderRouterEntry = NULL; + NetworkDataTlv *subCur; + NetworkDataTlv *subEnd; VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end, error = OT_ERROR_PARSE); @@ -112,43 +112,50 @@ otError NetworkData::GetNextOnMeshPrefix(otNetworkDataIterator *aIterator, uint1 } prefix = static_cast(cur); + subCur = reinterpret_cast(reinterpret_cast(prefix->GetSubTlvs()) + + iterator.GetSubTlvOffset()); + subEnd = cur->GetNext(); - if ((borderRouter = FindBorderRouter(*prefix)) == NULL) + for (; subCur < subEnd; subCur = subCur->GetNext(), iterator.SetEntryIndex(0)) { - continue; - } + BorderRouterTlv *borderRouter; - for (uint8_t i = iterator.GetEntryIndex(); i < borderRouter->GetNumEntries(); i++) - { - if (aRloc16 == Mac::kShortAddrBroadcast || borderRouter->GetEntry(i)->GetRloc() == aRloc16) + VerifyOrExit((subCur + 1) <= subEnd && subCur->GetNext() <= subEnd, error = OT_ERROR_PARSE); + + if (subCur->GetType() != NetworkDataTlv::kTypeBorderRouter) { - borderRouterEntry = borderRouter->GetEntry(i); - iterator.SetEntryIndex(i + 1); - break; + continue; + } + + borderRouter = static_cast(subCur); + + for (uint8_t index = iterator.GetEntryIndex(); index < borderRouter->GetNumEntries(); index++) + { + if (aRloc16 == Mac::kShortAddrBroadcast || borderRouter->GetEntry(index)->GetRloc() == aRloc16) + { + BorderRouterEntry *borderRouterEntry = borderRouter->GetEntry(index); + + memset(aConfig, 0, sizeof(*aConfig)); + memcpy(&aConfig->mPrefix.mPrefix, prefix->GetPrefix(), BitVectorBytes(prefix->GetPrefixLength())); + aConfig->mPrefix.mLength = prefix->GetPrefixLength(); + aConfig->mPreference = borderRouterEntry->GetPreference(); + aConfig->mPreferred = borderRouterEntry->IsPreferred(); + aConfig->mSlaac = borderRouterEntry->IsSlaac(); + aConfig->mDhcp = borderRouterEntry->IsDhcp(); + aConfig->mConfigure = borderRouterEntry->IsConfigure(); + aConfig->mDefaultRoute = borderRouterEntry->IsDefaultRoute(); + aConfig->mOnMesh = borderRouterEntry->IsOnMesh(); + aConfig->mStable = borderRouter->IsStable(); + aConfig->mRloc16 = borderRouterEntry->GetRloc(); + + iterator.SaveTlvOffset(cur, mTlvs); + iterator.SaveSubTlvOffset(subCur, prefix->GetSubTlvs()); + iterator.SetEntryIndex(index + 1); + + ExitNow(error = OT_ERROR_NONE); + } } } - - if (borderRouterEntry == NULL) - { - continue; - } - - memset(aConfig, 0, sizeof(*aConfig)); - memcpy(&aConfig->mPrefix.mPrefix, prefix->GetPrefix(), BitVectorBytes(prefix->GetPrefixLength())); - aConfig->mPrefix.mLength = prefix->GetPrefixLength(); - aConfig->mPreference = borderRouterEntry->GetPreference(); - aConfig->mPreferred = borderRouterEntry->IsPreferred(); - aConfig->mSlaac = borderRouterEntry->IsSlaac(); - aConfig->mDhcp = borderRouterEntry->IsDhcp(); - aConfig->mConfigure = borderRouterEntry->IsConfigure(); - aConfig->mDefaultRoute = borderRouterEntry->IsDefaultRoute(); - aConfig->mOnMesh = borderRouterEntry->IsOnMesh(); - aConfig->mStable = borderRouter->IsStable(); - aConfig->mRloc16 = borderRouterEntry->GetRloc(); - - iterator.SetTlvsIndex(static_cast(reinterpret_cast(cur) - mTlvs)); - - ExitNow(error = OT_ERROR_NONE); } exit: @@ -165,14 +172,14 @@ otError NetworkData::GetNextExternalRoute(otNetworkDataIterator *aIterator, uint { otError error = OT_ERROR_NOT_FOUND; NetworkDataIterator iterator(aIterator); - NetworkDataTlv *cur = reinterpret_cast(mTlvs + iterator.GetTlvsIndex()); + NetworkDataTlv *cur = reinterpret_cast(mTlvs + iterator.GetTlvOffset()); NetworkDataTlv *end = reinterpret_cast(mTlvs + mLength); - for (; cur < end; cur = cur->GetNext(), iterator.SetEntryIndex(0)) + for (; cur < end; cur = cur->GetNext(), iterator.SetSubTlvOffset(0), iterator.SetEntryIndex(0)) { PrefixTlv *prefix; - HasRouteTlv *hasRoute; - HasRouteEntry *hasRouteEntry = NULL; + NetworkDataTlv *subCur; + NetworkDataTlv *subEnd; VerifyOrExit((cur + 1) <= end && cur->GetNext() <= end, error = OT_ERROR_PARSE); @@ -183,37 +190,46 @@ otError NetworkData::GetNextExternalRoute(otNetworkDataIterator *aIterator, uint prefix = static_cast(cur); - if ((hasRoute = FindHasRoute(*prefix)) == NULL) - { - continue; - } + subCur = reinterpret_cast(reinterpret_cast(prefix->GetSubTlvs()) + + iterator.GetSubTlvOffset()); + subEnd = cur->GetNext(); - for (uint8_t i = iterator.GetEntryIndex(); i < hasRoute->GetNumEntries(); i++) + for (; subCur < subEnd; subCur = subCur->GetNext(), iterator.SetEntryIndex(0)) { - if (aRloc16 == Mac::kShortAddrBroadcast || hasRoute->GetEntry(i)->GetRloc() == aRloc16) + HasRouteTlv *hasRoute; + + VerifyOrExit((subCur + 1) <= subEnd && subCur->GetNext() <= subEnd, error = OT_ERROR_PARSE); + + if (subCur->GetType() != NetworkDataTlv::kTypeHasRoute) { - hasRouteEntry = hasRoute->GetEntry(i); - iterator.SetEntryIndex(i + 1); - break; + continue; + } + + hasRoute = static_cast(subCur); + + for (uint8_t index = iterator.GetEntryIndex(); index < hasRoute->GetNumEntries(); index++) + { + if (aRloc16 == Mac::kShortAddrBroadcast || hasRoute->GetEntry(index)->GetRloc() == aRloc16) + { + HasRouteEntry *hasRouteEntry = hasRoute->GetEntry(index); + + memset(aConfig, 0, sizeof(*aConfig)); + memcpy(&aConfig->mPrefix.mPrefix, prefix->GetPrefix(), + BitVectorBytes(prefix->GetPrefixLength())); + aConfig->mPrefix.mLength = prefix->GetPrefixLength(); + aConfig->mPreference = hasRouteEntry->GetPreference(); + aConfig->mStable = hasRoute->IsStable(); + aConfig->mRloc16 = hasRouteEntry->GetRloc(); + aConfig->mNextHopIsThisDevice = (hasRouteEntry->GetRloc() == GetNetif().GetMle().GetRloc16()); + + iterator.SaveTlvOffset(cur, mTlvs); + iterator.SaveSubTlvOffset(subCur, prefix->GetSubTlvs()); + iterator.SetEntryIndex(index + 1); + + ExitNow(error = OT_ERROR_NONE); + } } } - - if (hasRouteEntry == NULL) - { - continue; - } - - memset(aConfig, 0, sizeof(*aConfig)); - memcpy(&aConfig->mPrefix.mPrefix, prefix->GetPrefix(), BitVectorBytes(prefix->GetPrefixLength())); - aConfig->mPrefix.mLength = prefix->GetPrefixLength(); - aConfig->mPreference = hasRouteEntry->GetPreference(); - aConfig->mStable = hasRoute->IsStable(); - aConfig->mRloc16 = hasRouteEntry->GetRloc(); - aConfig->mNextHopIsThisDevice = (hasRouteEntry->GetRloc() == GetNetif().GetMle().GetRloc16()); - - iterator.SetTlvsIndex(static_cast(reinterpret_cast(cur) - mTlvs)); - - ExitNow(error = OT_ERROR_NONE); } exit: diff --git a/src/core/thread/network_data.hpp b/src/core/thread/network_data.hpp index 972a76f56..0e1427266 100644 --- a/src/core/thread/network_data.hpp +++ b/src/core/thread/network_data.hpp @@ -354,19 +354,38 @@ protected: private: enum { - kDataResubmitDelay = 300000, ///< DATA_RESUBMIT_DELAY (miliseconds) + kDataResubmitDelay = 300000, ///< DATA_RESUBMIT_DELAY (milliseconds) }; class NetworkDataIterator { + private: + enum + { + kTlvPoistion = 0, + kSubTlvPosition = 1, + kEntryPosition = 2, + }; + 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; } + uint8_t GetTlvOffset(void) const { return mIteratorBuffer[kTlvPoistion]; } + uint8_t GetSubTlvOffset(void) const { return mIteratorBuffer[kSubTlvPosition]; } + uint8_t GetEntryIndex(void) const { return mIteratorBuffer[kEntryPosition]; } + void SetTlvOffset(uint8_t aOffset) { mIteratorBuffer[kTlvPoistion] = aOffset; } + void SetSubTlvOffset(uint8_t aOffset) { mIteratorBuffer[kSubTlvPosition] = aOffset; } + void SetEntryIndex(uint8_t aIndex) { mIteratorBuffer[kEntryPosition] = aIndex; } + + void SaveTlvOffset(const NetworkDataTlv *aTlv, const uint8_t *aTlvs) { + SetTlvOffset(static_cast(reinterpret_cast(aTlv) - aTlvs)); + } + + void SaveSubTlvOffset(const NetworkDataTlv *aSubTlv, const NetworkDataTlv *aSubTlvs) { + SetSubTlvOffset(static_cast(reinterpret_cast(aSubTlv) - + reinterpret_cast(aSubTlvs))); + } private: uint8_t *mIteratorBuffer; diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index d9b4b75e3..ba17b2556 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -88,6 +88,7 @@ check_PROGRAMS = \ test-hmac-sha256 \ test-lowpan \ test-link-quality \ + test-network-data \ test-mac-frame \ test-message \ test-message-queue \ @@ -155,6 +156,9 @@ test_link_quality_SOURCES = test_platform.cpp test_link_quality.cpp test_lowpan_LDADD = $(COMMON_LDADD) test_lowpan_SOURCES = test_platform.cpp test_lowpan.cpp test_util.cpp +test_network_data_LDADD = $(COMMON_LDADD) +test_network_data_SOURCES = test_platform.cpp test_network_data.cpp + test_mac_frame_LDADD = $(COMMON_LDADD) test_mac_frame_SOURCES = test_platform.cpp test_mac_frame.cpp diff --git a/tests/unit/test_network_data.cpp b/tests/unit/test_network_data.cpp new file mode 100644 index 000000000..5a777d370 --- /dev/null +++ b/tests/unit/test_network_data.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2017, 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. + */ + +#include + +#include "openthread-instance.h" +#include "thread/network_data_local.hpp" + +#include "test_platform.h" +#include "test_util.hpp" + +namespace ot { + +class TestNetworkData: public NetworkData::NetworkData +{ +public: + TestNetworkData(otInstance *aInstance, const uint8_t *aTlvs, uint8_t aTlvsLength): + NetworkData::NetworkData(aInstance->mThreadNetif, false) { + memcpy(mTlvs, aTlvs, aTlvsLength); + mLength = aTlvsLength; + } +}; + +void PrintExternalRouteConfig(const otExternalRouteConfig &aConfig) +{ + printf("\nprefix:"); + + for (uint8_t i = 0; i < 16; i++) + { + printf("%02x", aConfig.mPrefix.mPrefix.mFields.m8[i]); + } + + printf(", length:%d, rloc16:%04x, preference:%d, stable:%d, nexthop:%d", aConfig.mPrefix.mLength, + aConfig.mRloc16, aConfig.mPreference, aConfig.mStable, aConfig.mNextHopIsThisDevice); +} + +// Returns true if the two given otExternalRouteConfig match (intentionally ignoring mNextHopIsThisDevice). +bool CompareExternalRouteConfig(const otExternalRouteConfig &aConfig1, const otExternalRouteConfig &aConfig2) +{ + return (memcmp(aConfig1.mPrefix.mPrefix.mFields.m8, aConfig2.mPrefix.mPrefix.mFields.m8, + sizeof(aConfig1.mPrefix.mPrefix)) == 0) && + (aConfig1.mPrefix.mLength == aConfig2.mPrefix.mLength) && + (aConfig1.mRloc16 == aConfig2.mRloc16) && + (aConfig1.mPreference == aConfig2.mPreference) && + (aConfig1.mStable == aConfig2.mStable); +} + +void TestNetworkDataIterator(void) +{ + otInstance *instance; + otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT; + otExternalRouteConfig config; + + instance = testInitInstance(); + VerifyOrQuit(instance != NULL, "Null OpenThread instance\n"); + + { + const uint8_t kNetworkData[] = + { + 0x08, 0x04, 0x0B, 0x02, 0x00, 0x00, 0x03, 0x14, 0x00, 0x40, 0xFD, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xC8, 0x00, 0x40, 0x01, 0x03, 0x54, 0x00, 0x00 + }; + + otExternalRouteConfig routes[] = + { + { + { + {{{ 0xfd, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}, + 64 + }, + 0xc800, + 1, + false, + false, + }, + { + { + {{{ 0xfd, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}, + 64 + }, + 0x5400, + 0, + true, + false, + } + }; + + TestNetworkData netData(instance, kNetworkData, sizeof(kNetworkData)); + + iter = OT_NETWORK_DATA_ITERATOR_INIT; + + printf("\nTest #1: Network data 1"); + printf("\n-------------------------------------------------"); + + for (uint8_t i = 0; i < sizeof(routes) / sizeof(routes[0]); i++) + { + SuccessOrQuit(netData.GetNextExternalRoute(&iter, &config), "GetNextExternalRoute() failed\n"); + PrintExternalRouteConfig(config); + VerifyOrQuit(CompareExternalRouteConfig(config, routes[i]) == true, + "external route config does not match expectation"); + } + } + + { + const uint8_t kNetworkData[] = + { + 0x08, 0x04, 0x0B, 0x02, 0x00, 0x00, 0x03, 0x1E, 0x00, 0x40, 0xFD, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, + 0x07, 0x02, 0x11, 0x40, 0x00, 0x03, 0x10, 0x00, 0x40, 0x01, 0x03, 0x54, 0x00, 0x00, 0x05, 0x04, 0x54, 0x00, + 0x31, 0x00, 0x02, 0x0F, 0x00, 0x40, 0xFD, 0x00, 0xAB, 0xBA, 0xCD, 0xDC, 0x00, 0x00, 0x00, 0x03, 0x10, 0x00, + 0x00, 0x03, 0x0E, 0x00, 0x20, 0xFD, 0x00, 0xAB, 0xBA, 0x01, 0x06, 0x54, 0x00, 0x00, 0x04, 0x00, 0x00 + }; + + otExternalRouteConfig routes[] = + { + { + { + {{{ 0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}, + 64 + }, + 0x1000, + 1, + false, + false + }, + { + { + {{{ 0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}, + 64 + }, + 0x5400, + 0, + true, + false + }, + { + { + {{{ 0xfd, 0x00, 0xab, 0xba, 0xcd, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}, + 64 + }, + 0x1000, + 0, + false, + false + }, + { + { + {{{ 0xfd, 0x00, 0xab, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}, + 32 + }, + 0x5400, + 0, + true, + false + }, + { + { + {{{ 0xfd, 0x00, 0xab, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}, + 32 + }, + 0x0400, + 0, + true, + false + } + }; + + TestNetworkData netData(instance, kNetworkData, sizeof(kNetworkData)); + + iter = OT_NETWORK_DATA_ITERATOR_INIT; + + printf("\nTest #2: Network data 2"); + printf("\n-------------------------------------------------"); + + for (uint8_t i = 0; i < sizeof(routes) / sizeof(routes[0]); i++) + { + SuccessOrQuit(netData.GetNextExternalRoute(&iter, &config), "GetNextExternalRoute() failed\n"); + PrintExternalRouteConfig(config); + VerifyOrQuit(CompareExternalRouteConfig(config, routes[i]) == true, + "external route config does not match expectation"); + } + } + + testFreeInstance(instance); +} + +} // namespace ot + +#ifdef ENABLE_TEST_MAIN +int main(void) +{ + ot::TestNetworkDataIterator(); + + printf("\nAll tests passed\n"); + return 0; +} +#endif