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