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. }; /**