From fbdb812f6aab8e54d2acfeef0fad1a020fc61027 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 7 Apr 2017 10:45:36 -0700 Subject: [PATCH] Adding `SourceMatchController` class. (#1559) This commit adds a new class `SourceMatchController` which contains all (existing) logic to maintain the source match table and control when/how to enable or disable the source matching feature. It also updates `Child` class by changing the access level of member variables related to the source matching feature (e.g., number of indirect queued messages) to private to ensure that they are only modified by the new `SourceMatchController` class while providing simple getter methods for use by other classes. The changes in this commit also address two corner-case issues related to source address matching feature: - First issue where we could possibly enable the source address matching after successfully adding a short address while still having remaining pending entries. - Second issue where an entry would not be added properly from a `SetSrcMatchAsShort()` call for a child, if there were more than one message queued for the child. --- etc/visual-studio/libopenthread.vcxproj | 2 + .../libopenthread.vcxproj.filters | 6 + etc/visual-studio/libopenthread_k.vcxproj | 2 + .../libopenthread_k.vcxproj.filters | 6 + include/openthread/openthread.h | 1 + src/core/Makefile.am | 2 + src/core/mac/mac.cpp | 72 ------ src/core/mac/mac.hpp | 36 --- src/core/thread/mesh_forwarder.cpp | 201 +++------------ src/core/thread/mesh_forwarder.hpp | 12 +- src/core/thread/mle_router.cpp | 8 +- src/core/thread/src_match_controller.cpp | 238 ++++++++++++++++++ src/core/thread/src_match_controller.hpp | 205 +++++++++++++++ src/core/thread/topology.hpp | 29 ++- 14 files changed, 530 insertions(+), 290 deletions(-) create mode 100644 src/core/thread/src_match_controller.cpp create mode 100644 src/core/thread/src_match_controller.hpp diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj index d55f272a6..d97eada37 100644 --- a/etc/visual-studio/libopenthread.vcxproj +++ b/etc/visual-studio/libopenthread.vcxproj @@ -133,6 +133,7 @@ + @@ -215,6 +216,7 @@ + diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters index 0547019bf..8c708a406 100644 --- a/etc/visual-studio/libopenthread.vcxproj.filters +++ b/etc/visual-studio/libopenthread.vcxproj.filters @@ -225,6 +225,9 @@ Source Files\thread + + Source Files\thread + Source Files\thread @@ -461,6 +464,9 @@ Header Files\thread + + Header Files\thread + Header Files\thread diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj index d488c7aee..2b747e36d 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj +++ b/etc/visual-studio/libopenthread_k.vcxproj @@ -138,6 +138,7 @@ + @@ -244,6 +245,7 @@ + diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters index 2c901adf5..61a06ad17 100644 --- a/etc/visual-studio/libopenthread_k.vcxproj.filters +++ b/etc/visual-studio/libopenthread_k.vcxproj.filters @@ -228,6 +228,9 @@ Source Files\thread + + Source Files\thread + Source Files\thread @@ -464,6 +467,9 @@ Header Files\thread + + Header Files\thread + Header Files\thread diff --git a/include/openthread/openthread.h b/include/openthread/openthread.h index 56b77324f..e55ed572e 100644 --- a/include/openthread/openthread.h +++ b/include/openthread/openthread.h @@ -95,6 +95,7 @@ extern "C" { * @defgroup core-mac MAC * @defgroup core-mesh-forwarding Mesh Forwarding * @defgroup core-data-poll-manager Data Poll Manager + * @defgroup core-source-match-controller Source Address Match Controller * @defgroup core-message Message * @defgroup core-mle MLE * @defgroup core-netdata Network Data diff --git a/src/core/Makefile.am b/src/core/Makefile.am index d73356f65..44509dc83 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -92,6 +92,7 @@ SOURCES_COMMON = \ thread/network_data_leader.cpp \ thread/panid_query_server.cpp \ thread/network_diagnostic.cpp \ + thread/src_match_controller.cpp \ thread/thread_netif.cpp \ utils/slaac_address.cpp \ $(NULL) @@ -344,6 +345,7 @@ noinst_HEADERS = \ thread/panid_query_server.hpp \ thread/network_diagnostic.hpp \ thread/network_diagnostic_tlvs.hpp \ + thread/src_match_controller.hpp \ thread/thread_netif.hpp \ thread/thread_tlvs.hpp \ thread/thread_uris.hpp \ diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index ec657233b..ae111c055 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -1614,77 +1614,5 @@ void Mac::ResetCounters(void) memset(&mCounters, 0, sizeof(mCounters)); } -void Mac::EnableSrcMatch(bool aEnable) -{ - otPlatRadioEnableSrcMatch(GetInstance(), aEnable); - otLogDebgMac(GetInstance(), "SrcAddrMatch - %s", aEnable ? "Enabling" : "Disabling"); -} - -ThreadError Mac::AddSrcMatchEntry(Address &aAddr) -{ - ThreadError error = kThreadError_None; - char stringBuffer[Address::kAddressStringSize]; - - if (aAddr.mLength == 2) - { - error = otPlatRadioAddSrcMatchShortEntry(GetInstance(), aAddr.mShortAddress); - } - else - { - uint8_t buf[8]; - - for (uint8_t i = 0; i < sizeof(buf); i++) - { - buf[i] = aAddr.mExtAddress.m8[7 - i]; - } - - error = otPlatRadioAddSrcMatchExtEntry(GetInstance(), buf); - } - - otLogDebgMac(GetInstance(), "SrcAddrMatch - Adding address: %s -- %s (%d)", - aAddr.ToString(stringBuffer, sizeof(stringBuffer)), otThreadErrorToString(error), error); - - (void)stringBuffer; - - return error; -} - -ThreadError Mac::ClearSrcMatchEntry(Address &aAddr) -{ - ThreadError error = kThreadError_None; - char stringBuffer[Address::kAddressStringSize]; - - if (aAddr.mLength == 2) - { - error = otPlatRadioClearSrcMatchShortEntry(GetInstance(), aAddr.mShortAddress); - } - else - { - uint8_t buf[8]; - - for (uint8_t i = 0; i < sizeof(buf); i++) - { - buf[i] = aAddr.mExtAddress.m8[7 - i]; - } - - error = otPlatRadioClearSrcMatchExtEntry(GetInstance(), buf); - } - - otLogDebgMac(GetInstance(), "SrcAddrMatch - Clearing address: %s -- %s (%d)", - aAddr.ToString(stringBuffer, sizeof(stringBuffer)), otThreadErrorToString(error), error); - - (void)stringBuffer; - - return error; -} - -void Mac::ClearSrcMatchEntries() -{ - otPlatRadioClearSrcMatchShortEntries(GetInstance()); - otPlatRadioClearSrcMatchExtEntries(GetInstance()); - - otLogDebgMac(GetInstance(), "SrcAddrMatch - Cleared all entries"); -} - } // namespace Mac } // namespace Thread diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 16c9f52b6..92f8458b4 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -571,42 +571,6 @@ public: */ LinkQualityInfo &GetNoiseFloor(void) { return mNoiseFloor; } - /** - * This method enables/disables source match feature. - * - * @param[in] aEnable Enable/disable source match for automatical pending. - * - */ - void EnableSrcMatch(bool aEnable); - - /** - * This method adds the address into the source match table. - * - * @param[in] aAddr The address to be added into the source match table. - * - * @retval ::kThreadError_None Successfully added the address into the source match table. - * @retval ::kThreadError_NoBufs No available entry in the source match table - * - */ - ThreadError AddSrcMatchEntry(Address &aAddr); - - /** - * This method removes the address from the source match table. - * - * @param[in] aAddr The address to be removed from the source match table. - * - * @retval ::kThreadError_None Successfully removed the address from the source match table. - * @retval ::kThreadError_NoAddress The address is not in the source match table. - * - */ - ThreadError ClearSrcMatchEntry(Address &aAddr); - - /** - * This method clears the source match table. - * - */ - void ClearSrcMatchEntries(void); - /** * This method indicates whether or not CSMA backoff is supported by the radio layer. * diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 89f20f434..e087b04d6 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -79,7 +79,7 @@ MeshForwarder::MeshForwarder(ThreadNetif &aThreadNetif): mRestorePanId(Mac::kPanIdBroadcast), mScanning(false), mDataPollManager(*this), - mSrcMatchEnabled(false) + mSourceMatchController(*this) { mFragTag = static_cast(otPlatRandomGet()); mNetif.GetMac().RegisterReceiver(mMacReceiver); @@ -185,7 +185,7 @@ void MeshForwarder::ClearChildIndirectMessages(Child &aChild) { Message *nextMessage; - VerifyOrExit(aChild.mQueuedIndirectMessageCnt > 0); + VerifyOrExit(aChild.GetQueuedMessageCount() > 0); for (Message *message = mSendQueue.GetHead(); message; message = nextMessage) { @@ -205,8 +205,7 @@ void MeshForwarder::ClearChildIndirectMessages(Child &aChild) } } - aChild.mQueuedIndirectMessageCnt = 0; - ClearSrcMatchEntry(aChild); + mSourceMatchController.ResetMessageCount(aChild); exit: return; @@ -223,7 +222,7 @@ void MeshForwarder::UpdateIndirectMessages(void) { Child *child = &children[i]; - if (child->IsStateValidOrRestoring() || child->mQueuedIndirectMessageCnt == 0) + if (child->IsStateValidOrRestoring() || (child->GetQueuedMessageCount() == 0)) { continue; } @@ -276,7 +275,7 @@ void MeshForwarder::ScheduleTransmissionTask(void) { // A NULL `mSendMessage` triggers an empty frame to be sent to the child. - if (child.mAddSrcMatchEntryShort) + if (child.ShouldUseShortAddress()) { mMacSource.mLength = sizeof(mMacSource.mShortAddress); mMacSource.mShortAddress = mNetif.GetMac().GetShortAddress(); @@ -309,147 +308,13 @@ exit: (void) error; } -ThreadError MeshForwarder::AddPendingSrcMatchEntries(void) -{ - uint8_t numChildren; - Child *children = NULL; - ThreadError error = kThreadError_NoBufs; - - children = mNetif.GetMle().GetChildren(&numChildren); - - // Add pending short address first - for (uint8_t i = 0; i < numChildren; i++) - { - if (children[i].IsStateValidOrRestoring() && - children[i].mAddSrcMatchEntryPending && - children[i].mAddSrcMatchEntryShort) - { - VerifyOrExit(((error = AddSrcMatchEntry(children[i])) == kThreadError_None)); - } - } - - // Add pending extended address - for (uint8_t i = 0; i < numChildren; i++) - { - if (children[i].IsStateValidOrRestoring() && - children[i].mAddSrcMatchEntryPending && - !children[i].mAddSrcMatchEntryShort) - { - VerifyOrExit(((error = AddSrcMatchEntry(children[i])) == kThreadError_None)); - } - } - -exit: - return error; -} - -ThreadError MeshForwarder::AddSrcMatchEntry(Child &aChild) -{ - ThreadError error = kThreadError_NoBufs; - Mac::Address macAddr; - - otLogDebgMac(GetInstance(), "Queuing for child (0x%x)", aChild.mValid.mRloc16); - otLogDebgMac(GetInstance(), "SrcMatch %d (0:Dis, 1:En))", mSrcMatchEnabled); - - // first queued message, to be added into source match table - if (aChild.mQueuedIndirectMessageCnt == 1) - { - aChild.mAddSrcMatchEntryPending = true; - } - - VerifyOrExit(aChild.mAddSrcMatchEntryPending); - - if (aChild.mAddSrcMatchEntryShort) - { - macAddr.mLength = sizeof(macAddr.mShortAddress); - macAddr.mShortAddress = aChild.mValid.mRloc16; - } - else - { - macAddr.mLength = sizeof(macAddr.mExtAddress); - memcpy(macAddr.mExtAddress.m8, aChild.mMacAddr.m8, sizeof(macAddr.mExtAddress)); - } - - if ((error = mNetif.GetMac().AddSrcMatchEntry(macAddr)) == kThreadError_None) - { - // succeed in adding to source match table - aChild.mAddSrcMatchEntryPending = false; - - if (!mSrcMatchEnabled) - { - mNetif.GetMac().EnableSrcMatch(true); - mSrcMatchEnabled = true; - } - } - else - { - if (mSrcMatchEnabled) - { - mNetif.GetMac().EnableSrcMatch(false); - mSrcMatchEnabled = false; - } - } - -exit: - return error; -} - -void MeshForwarder::ClearSrcMatchEntry(Child &aChild) -{ - Mac::Address macAddr; - - if (aChild.mAddSrcMatchEntryShort) - { - macAddr.mLength = sizeof(macAddr.mShortAddress); - macAddr.mShortAddress = aChild.mValid.mRloc16; - } - else - { - macAddr.mLength = sizeof(macAddr.mExtAddress); - memcpy(macAddr.mExtAddress.m8, aChild.mMacAddr.m8, sizeof(macAddr.mExtAddress)); - } - - if (mNetif.GetMac().ClearSrcMatchEntry(macAddr) == kThreadError_None) - { - if (!mSrcMatchEnabled && (AddPendingSrcMatchEntries() == kThreadError_None)) - { - mNetif.GetMac().EnableSrcMatch(true); - mSrcMatchEnabled = true; - } - } - else - { - // if finished queued messages for SED which is not added into the source match table - aChild.mAddSrcMatchEntryPending = false; - } -} - -void MeshForwarder::SetSrcMatchAsShort(Child &aChild, bool aShortSource) -{ - VerifyOrExit(aChild.mAddSrcMatchEntryShort != aShortSource); - - if (aChild.mQueuedIndirectMessageCnt > 0) - { - ClearSrcMatchEntry(aChild); - aChild.mAddSrcMatchEntryShort = aShortSource; - AddSrcMatchEntry(aChild); - } - else - { - aChild.mAddSrcMatchEntryShort = aShortSource; - } - -exit: - return; -} - ThreadError MeshForwarder::SendMessage(Message &aMessage) { ThreadError error = kThreadError_None; Neighbor *neighbor; uint8_t numChildren; - Child *children; + Child *child; switch (aMessage.GetType()) { @@ -470,15 +335,15 @@ ThreadError MeshForwarder::SendMessage(Message &aMessage) if (aMessage.GetSubType() != Message::kSubTypeMplRetransmission) { // destined for all sleepy children - children = mNetif.GetMle().GetChildren(&numChildren); + child = mNetif.GetMle().GetChildren(&numChildren); - for (uint8_t i = 0; i < numChildren; i++) + for (uint8_t i = 0; i < numChildren; i++, child++) { - if (children[i].IsStateValidOrRestoring() && (children[i].mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) + if (child->IsStateValidOrRestoring() && + (child->mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) { - children[i].mQueuedIndirectMessageCnt++; - AddSrcMatchEntry(children[i]); aMessage.SetChildMask(i); + mSourceMatchController.IncrementMessageCount(*child); } } } @@ -488,11 +353,9 @@ ThreadError MeshForwarder::SendMessage(Message &aMessage) !aMessage.GetDirectTransmission()) { // destined for a sleepy child - children = static_cast(neighbor); - children->mQueuedIndirectMessageCnt++; - - AddSrcMatchEntry(*children); - aMessage.SetChildMask(mNetif.GetMle().GetChildIndex(*children)); + child = static_cast(neighbor); + aMessage.SetChildMask(mNetif.GetMle().GetChildIndex(*child)); + mSourceMatchController.IncrementMessageCount(*child); } else { @@ -513,11 +376,9 @@ ThreadError MeshForwarder::SendMessage(Message &aMessage) (neighbor->mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) { // destined for a sleepy child - children = static_cast(neighbor); - children->mQueuedIndirectMessageCnt++; - - AddSrcMatchEntry(*children); - aMessage.SetChildMask(mNetif.GetMle().GetChildIndex(*children)); + child = static_cast(neighbor); + aMessage.SetChildMask(mNetif.GetMle().GetChildIndex(*child)); + mSourceMatchController.IncrementMessageCount(*child); } else { @@ -542,7 +403,7 @@ exit: return error; } -Message *MeshForwarder::GetDirectTransmission() +Message *MeshForwarder::GetDirectTransmission(void) { Message *curMessage, *nextMessage; ThreadError error = kThreadError_None; @@ -645,7 +506,7 @@ void MeshForwarder::PrepareIndirectTransmission(Message &aMessage, const Child & } else { - if (aChild.mAddSrcMatchEntryShort) + if (aChild.ShouldUseShortAddress()) { mMacDest.mLength = sizeof(mMacDest.mShortAddress); mMacDest.mShortAddress = aChild.mValid.mRloc16; @@ -888,7 +749,7 @@ void MeshForwarder::SetRxOff(void) mDataPollManager.StopPolling(); } -bool MeshForwarder::GetRxOnWhenIdle() +bool MeshForwarder::GetRxOnWhenIdle(void) { return mNetif.GetMac().GetRxOnWhenIdle(); } @@ -1042,12 +903,16 @@ ThreadError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame) assert(error == kThreadError_None); - // set FramePending if there are more queued messages for the child aFrame.GetDstAddr(macDest); + // Set `FramePending` if there are more queued messages (excluding + // the current one being sent out) for the child (note `> 1` check). + // The case where the current message requires fragmentation is + // already checked and handled in `SendFragment()` method. + if (((child = mNetif.GetMle().GetChild(macDest)) != NULL) && ((child->mMode & Mle::ModeTlv::kModeRxOnWhenIdle) == 0) - && (child->mQueuedIndirectMessageCnt > 1)) + && (child->GetQueuedMessageCount() > 1)) { aFrame.SetFramePending(true); } @@ -1580,7 +1445,7 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, ThreadError aError) // one indirect message to valid sleepy devices is sent out successfully if (aError == kThreadError_None) { - SetSrcMatchAsShort(*child, true); + mSourceMatchController.SetSrcMatchAsShort(*child, true); } } @@ -1589,15 +1454,7 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, ThreadError aError) if (mSendMessage->GetChildMask(childIndex)) { mSendMessage->ClearChildMask(childIndex); - - child->mQueuedIndirectMessageCnt--; - otLogDebgMac(GetInstance(), "Sent to child (0x%x), still queued message (%d)", - child->mValid.mRloc16, child->mQueuedIndirectMessageCnt); - - if (child->mQueuedIndirectMessageCnt == 0) - { - ClearSrcMatchEntry(*child); - } + mSourceMatchController.DecrementMessageCount(*child); } } } @@ -2103,7 +1960,7 @@ void MeshForwarder::HandleDataRequest(const Mac::Address &aMacSource, const Thre child->mLastHeard = Timer::GetNow(); child->mLinkFailures = 0; - if (!mSrcMatchEnabled || child->mQueuedIndirectMessageCnt > 0) + if (!mSourceMatchController.IsEnabled() || (child->GetQueuedMessageCount() > 0)) { child->mDataRequest = true; } diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 97d36c56b..7ee5cacc1 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -217,6 +218,14 @@ public: */ DataPollManager &GetDataPollManager(void) { return mDataPollManager; } + /** + * This method returns a reference to the source match controller. + * + * @returns A reference to the source match controller. + * + */ + SourceMatchController &GetSourceMatchController(void) { return mSourceMatchController; } + private: enum { @@ -327,7 +336,8 @@ private: DataPollManager mDataPollManager; - bool mSrcMatchEnabled; + + SourceMatchController mSourceMatchController; }; /** diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 5c348c5e6..76c1f5868 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -2655,13 +2655,13 @@ ThreadError MleRouter::SendChildIdResponse(Child *aChild) SuccessOrExit(error = AppendChildAddresses(*message, *aChild)); } + SetChildStateToValid(aChild); + if ((aChild->mMode & ModeTlv::kModeRxOnWhenIdle) == 0) { - mNetif.GetMeshForwarder().SetSrcMatchAsShort(*aChild, false); + mNetif.GetMeshForwarder().GetSourceMatchController().SetSrcMatchAsShort(*aChild, false); } - SetChildStateToValid(aChild); - memset(&destination, 0, sizeof(destination)); destination.mFields.m16[0] = HostSwap16(0xfe80); destination.SetIid(aChild->mMacAddr); @@ -3354,7 +3354,7 @@ ThreadError MleRouter::RestoreChildren(void) (childInfo.mFullNetworkData ? ModeTlv::kModeFullNetworkData : 0); child->mState = Neighbor::kStateRestored; child->mLastHeard = Timer::GetNow(); - mNetif.GetMeshForwarder().SetSrcMatchAsShort(*child, true); + mNetif.GetMeshForwarder().GetSourceMatchController().SetSrcMatchAsShort(*child, true); } exit: diff --git a/src/core/thread/src_match_controller.cpp b/src/core/thread/src_match_controller.cpp new file mode 100644 index 000000000..a92db6af2 --- /dev/null +++ b/src/core/thread/src_match_controller.cpp @@ -0,0 +1,238 @@ +/* + * 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. + */ + +/** + * @file + * This file implements source address match controller. + */ + +#define WPP_NAME "src_match_controller.tmh" + +#include +#include +#include +#include +#include +#include + +namespace Thread { + +SourceMatchController::SourceMatchController(MeshForwarder &aMeshForwarder) : + mMeshForwarder(aMeshForwarder), + mEnabled(false) +{ + ClearTable(); +} + +otInstance *SourceMatchController::GetInstance(void) +{ + return mMeshForwarder.GetInstance(); +} + +void SourceMatchController::IncrementMessageCount(Child &aChild) +{ + if (aChild.mQueuedMessageCount++ == 0) + { + AddEntry(aChild); + } +} + +void SourceMatchController::DecrementMessageCount(Child &aChild) +{ + if (aChild.mQueuedMessageCount == 0) + { + otLogWarnMac(GetInstance(), "DecrementMessageCount(child 0x%04x) called when already at zero count.", + aChild.mValid.mRloc16); + ExitNow(); + } + + if (--aChild.mQueuedMessageCount == 0) + { + ClearEntry(aChild); + } + +exit: + return; +} + +void SourceMatchController::ResetMessageCount(Child &aChild) +{ + aChild.mQueuedMessageCount = 0; + ClearEntry(aChild); +} + +void SourceMatchController::SetSrcMatchAsShort(Child &aChild, bool aUseShortAddress) +{ + VerifyOrExit(aChild.mUseShortAddress != aUseShortAddress); + + if (aChild.mQueuedMessageCount > 0) + { + ClearEntry(aChild); + aChild.mUseShortAddress = aUseShortAddress; + AddEntry(aChild); + } + else + { + aChild.mUseShortAddress = aUseShortAddress; + } + +exit: + return; +} + +void SourceMatchController::ClearTable(void) +{ + otPlatRadioClearSrcMatchShortEntries(GetInstance()); + otPlatRadioClearSrcMatchExtEntries(GetInstance()); + otLogDebgMac(GetInstance(), "SrcAddrMatch - Cleared all entries"); +} + +void SourceMatchController::Enable(bool aEnable) +{ + mEnabled = aEnable; + otPlatRadioEnableSrcMatch(GetInstance(), mEnabled); + otLogDebgMac(GetInstance(), "SrcAddrMatch - %sabling", mEnabled ? "En" : "Dis"); +} + +void SourceMatchController::AddEntry(Child &aChild) +{ + aChild.mSourceMatchPending = true; + + if (!IsEnabled()) + { + SuccessOrExit(AddPendingEntries()); + Enable(true); + } + else + { + VerifyOrExit(AddAddress(aChild) == kThreadError_None, Enable(false)); + aChild.mSourceMatchPending = false; + } + +exit: + return; +} + +ThreadError SourceMatchController::AddAddress(const Child &aChild) +{ + ThreadError error = kThreadError_None; + + if (aChild.mUseShortAddress) + { + error = otPlatRadioAddSrcMatchShortEntry(GetInstance(), aChild.mValid.mRloc16); + + otLogDebgMac(GetInstance(), "SrcAddrMatch - Adding short addr: 0x%04x -- %s (%d)", + aChild.mValid.mRloc16, otThreadErrorToString(error), error); + } + else + { + uint8_t addr[sizeof(aChild.mMacAddr)]; + + for (uint8_t i = 0; i < sizeof(addr); i++) + { + addr[i] = aChild.mMacAddr.m8[sizeof(addr) - 1 - i]; + } + + error = otPlatRadioAddSrcMatchExtEntry(GetInstance(), addr); + + otLogDebgMac(GetInstance(), "SrcAddrMatch - Adding addr: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x -- %s (%d)", + addr[7], addr[6], addr[5], addr[4], addr[3], addr[2], addr[1], addr[0], + otThreadErrorToString(error), error); + } + + return error; +} + +void SourceMatchController::ClearEntry(Child &aChild) +{ + ThreadError error = kThreadError_None; + + if (aChild.mSourceMatchPending) + { + otLogDebgMac(GetInstance(), "SrcAddrMatch - Clearing pending flag for 0x%04x", aChild.mValid.mRloc16); + aChild.mSourceMatchPending = false; + ExitNow(); + } + + if (aChild.mUseShortAddress) + { + error = otPlatRadioClearSrcMatchShortEntry(GetInstance(), aChild.mValid.mRloc16); + + otLogDebgMac(GetInstance(), "SrcAddrMatch - Clearing short address: 0x%04x -- %s (%d)", + aChild.mValid.mRloc16, otThreadErrorToString(error), error); + } + else + { + uint8_t addr[sizeof(aChild.mMacAddr)]; + + for (uint8_t i = 0; i < sizeof(addr); i++) + { + addr[i] = aChild.mMacAddr.m8[sizeof(aChild.mMacAddr) - 1 - i]; + } + + error = otPlatRadioClearSrcMatchExtEntry(GetInstance(), addr); + + otLogDebgMac(GetInstance(), "SrcAddrMatch - Clearing addr: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x -- %s (%d)", + addr[7], addr[6], addr[5], addr[4], addr[3], addr[2], addr[1], addr[0], + otThreadErrorToString(error), error); + } + + SuccessOrExit(error); + + if (!IsEnabled()) + { + SuccessOrExit(AddPendingEntries()); + Enable(true); + } + +exit: + return; +} + +ThreadError SourceMatchController::AddPendingEntries(void) +{ + ThreadError error = kThreadError_None; + uint8_t numChildren; + Child *child; + + child = mMeshForwarder.GetNetif().GetMle().GetChildren(&numChildren); + + for (uint8_t i = 0; i < numChildren; i++, child++) + { + if (child->IsStateValidOrRestoring() && child->mSourceMatchPending) + { + SuccessOrExit(AddAddress(*child)); + child->mSourceMatchPending = false; + } + } + +exit: + return error; +} + +} // namespace Thread diff --git a/src/core/thread/src_match_controller.hpp b/src/core/thread/src_match_controller.hpp new file mode 100644 index 000000000..80eebcd1c --- /dev/null +++ b/src/core/thread/src_match_controller.hpp @@ -0,0 +1,205 @@ +/* + * 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. + */ + +/** + * @file + * This file includes definitions for source address match controller. + */ + +#ifndef SOURCE_MATCH_CONTROLLER_HPP_ +#define SOURCE_MATCH_CONTROLLER_HPP_ + +#include + +#include "openthread/types.h" +#include + +namespace Thread { + +class MeshForwarder; + +/** + * @addtogroup core-source-match-controller + * + * @brief + * This module includes definition for source address match controller. + * + * @{ + */ + +/** + * This class implements the "source address match" controller. + * + * The source address match feature controls how the radio layer decides the "frame pending" bit for acks sent in + * response to data request commands from sleepy children. + * + * This class updates the source match table and also controls when to enable or disable the source matching + * feature. + * + * The source address match table provides the list of children for which there is a pending frame. Either a short + * address or an extended/long address can be added to the source address match table. + * + */ +class SourceMatchController +{ +public: + /** + * This constructor initializes the object. + * + * @param[in] aMeshForwarder A reference to the Mesh Forwarder. + * + */ + explicit SourceMatchController(MeshForwarder &aMeshForwarder); + + /** + * This method returns the pointer to the parent otInstance structure. + * + * @returns The pointer to the parent otInstance structure. + * + */ + otInstance *GetInstance(void); + + /** + * This method returns the current state of source address matching. + * + * @returns `true` if source address matching is enabled, `false` otherwise. + * + */ + bool IsEnabled(void) const { return mEnabled; } + + /** + * This method increments the message count for a child and updates the source match table. + * + * @param[in] aChild A reference to the child. + * + */ + void IncrementMessageCount(Child &aChild); + + /** + * This method decrements the message count for a child and updates the source match table. + * + * @param[in] aChild A reference to the child. + * + */ + void DecrementMessageCount(Child &aChild); + + /** + * This method resets the message count for a child to zero and updates the source match table. + * + * @param[in] aChild A reference to the child. + * + */ + void ResetMessageCount(Child &aChild); + + /** + * This method sets whether or not to perform source address matching on the extended or short address for + * a child. + * + * @param[in] aChild A reference to the child. + * @param[in] aUseShortAddress `true` to match on short source address, `false` otherwise. + * + */ + void SetSrcMatchAsShort(Child &aChild, bool aUseShortAddress); + +private: + /** + * This method clears the source match table. + * + */ + void ClearTable(void); + + /** + * This method enables or disables the source matching. + * + * If enabled, the radio uses the source match table to determine whether to set or clear the "frame pending" bit + * in an acknowledgment to a MAC Data Request command. If disabled, the radio layer sets the "frame pending" on all + * acknowledgment frames in response to MAC Data Request commands. + * + * @param[in] aEnable `true` to enable, `false` to disable. + * + */ + void Enable(bool aEnable); + + /** + * This method adds an entry to source match table for a given child and updates the state of source matching + * feature accordingly. + * + * If the entry is added successfully, source matching feature is enabled (if not already enabled) after ensuring + * that there are no remaining pending entries. If the entry cannot be added (no space in source match table), + * the child is marked to remember the pending entry and source matching is disabled. + * + * @param[in] aChild A reference to the child. + * + */ + void AddEntry(Child &aChild); + + /** + * This method clears an entry in source match table for a given child and updates the state of source matching + * feature accordingly. + * + * If the entry is removed successfully and frees up space in the source match table, any remaining pending + * entries are added. If all pending entries are successfully added, source matching is enabled. + * + * @param[in] aChild A reference to the child. + * + */ + void ClearEntry(Child &aChild); + + /** + * This method adds a given child's address (short or extended address depending on child's setting) to the source + * source match table (@sa SetSrcMatchAsShort. + * + * @param[in] aChild A reference to the child + * + * @retval kThreadError_None Child's address was added successfully to the source match table. + * @retval kThreadError_NoBufs No available space in the source match table. + * + */ + ThreadError AddAddress(const Child &aChild); + + /** + * This method adds all pending entries to the source match table. + * + * @retval kThreadError_None All pending entries were successfully added. + * @retval kThreadError_NoBufs No available space in the source match table. + * + */ + ThreadError AddPendingEntries(void); + + MeshForwarder &mMeshForwarder; + bool mEnabled; +}; + +/** + * @} + * + */ + +} // namespace Thread + +#endif // SOURCE_MATCH_CONTROLLER_HPP_ diff --git a/src/core/thread/topology.hpp b/src/core/thread/topology.hpp index cc119e979..9ce6d89bf 100644 --- a/src/core/thread/topology.hpp +++ b/src/core/thread/topology.hpp @@ -93,8 +93,7 @@ public: uint8_t mLinkFailures; ///< Consecutive link failure count LinkQualityInfo mLinkInfo; ///< Link quality info (contains average RSS, link margin and link quality) -public: - /* + /** * Check if the neighbor/child is in valid state or if it is being restored. * When in these states messages can be sent to and/or received from the neighbor/child. * @@ -121,6 +120,8 @@ public: */ class Child : public Neighbor { + friend class SourceMatchController; + public: enum { @@ -145,9 +146,27 @@ public: uint8_t mAttachChallenge[Mle::ChallengeTlv::kMaxSize]; ///< The challenge value }; uint8_t mNetworkDataVersion; ///< Current Network Data version - uint16_t mQueuedIndirectMessageCnt; ///< Count of queued messages - bool mAddSrcMatchEntryShort : 1; ///< Indicates whether or not to force add short address - bool mAddSrcMatchEntryPending : 1; ///< Indicates whether or not pending to add + + /** + * This method checks if a short or extended address should be used. + * + * @returns `true` if a short address should be used, `false` for extended address. + * + */ + bool ShouldUseShortAddress(void) const { return mUseShortAddress; } + + /** + * This method returns the number of queued message(s) for the child + * + * @returns Number of queues message(s). + * + */ + uint16_t GetQueuedMessageCount(void) const { return mQueuedMessageCount; } + +private: + uint16_t mQueuedMessageCount : 13; ///< Number of queued indirect messages for the child. + bool mUseShortAddress : 1; ///< Indicates whether to use short or extended address. + bool mSourceMatchPending : 1; ///< Indicates whether or not pending to add to src match table. }; /**