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.
This commit is contained in:
Abtin Keshavarzian
2017-04-07 10:45:36 -07:00
committed by Jonathan Hui
parent 2b40187d3e
commit fbdb812f6a
14 changed files with 530 additions and 290 deletions
+2
View File
@@ -133,6 +133,7 @@
<ClCompile Include="..\..\src\core\thread\network_data_local.cpp" />
<ClCompile Include="..\..\src\core\thread\network_diagnostic.cpp" />
<ClCompile Include="..\..\src\core\thread\panid_query_server.cpp" />
<ClCompile Include="..\..\src\core\thread\src_match_controller.cpp" />
<ClCompile Include="..\..\src\core\thread\thread_netif.cpp" />
<ClCompile Include="..\..\src\core\utils\slaac_address.cpp" />
<ClCompile Include="..\..\src\core\utils\jam_detector.cpp" />
@@ -215,6 +216,7 @@
<ClInclude Include="..\..\src\core\thread\network_diagnostic.hpp" />
<ClInclude Include="..\..\src\core\thread\network_diagnostic_tlvs.hpp" />
<ClInclude Include="..\..\src\core\thread\panid_query_server.hpp" />
<ClInclude Include="..\..\src\core\thread\src_match_controller.hpp" />
<ClInclude Include="..\..\src\core\thread\thread_netif.hpp" />
<ClInclude Include="..\..\src\core\thread\thread_tlvs.hpp" />
<ClInclude Include="..\..\src\core\thread\thread_uris.hpp" />
@@ -225,6 +225,9 @@
<ClCompile Include="..\..\src\core\thread\panid_query_server.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\thread\src_match_controller.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\thread\thread_netif.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
@@ -461,6 +464,9 @@
<ClInclude Include="..\..\src\core\thread\panid_query_server.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\thread\src_match_controller.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\thread\thread_netif.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
@@ -138,6 +138,7 @@
<ClCompile Include="..\..\src\core\thread\network_data_local.cpp" />
<ClCompile Include="..\..\src\core\thread\network_diagnostic.cpp" />
<ClCompile Include="..\..\src\core\thread\panid_query_server.cpp" />
<ClCompile Include="..\..\src\core\thread\src_match_controller.cpp" />
<ClCompile Include="..\..\src\core\thread\thread_netif.cpp" />
<ClCompile Include="..\..\src\core\utils\slaac_address.cpp" />
<ClCompile Include="..\..\src\core\utils\jam_detector.cpp" />
@@ -244,6 +245,7 @@
<ClInclude Include="..\..\src\core\thread\network_diagnostic.hpp" />
<ClInclude Include="..\..\src\core\thread\network_diagnostic_tlvs.hpp" />
<ClInclude Include="..\..\src\core\thread\panid_query_server.hpp" />
<ClInclude Include="..\..\src\core\thread\src_match_controller.hpp" />
<ClInclude Include="..\..\src\core\thread\thread_netif.hpp" />
<ClInclude Include="..\..\src\core\thread\thread_tlvs.hpp" />
<ClInclude Include="..\..\src\core\thread\thread_uris.hpp" />
@@ -228,6 +228,9 @@
<ClCompile Include="..\..\src\core\thread\panid_query_server.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\thread\src_match_controller.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\thread\thread_netif.cpp">
<Filter>Source Files\thread</Filter>
</ClCompile>
@@ -464,6 +467,9 @@
<ClInclude Include="..\..\src\core\thread\panid_query_server.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\thread\src_match_controller.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\thread\thread_netif.hpp">
<Filter>Header Files\thread</Filter>
</ClInclude>
+1
View File
@@ -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
+2
View File
@@ -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 \
-72
View File
@@ -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
-36
View File
@@ -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.
*
+29 -172
View File
@@ -79,7 +79,7 @@ MeshForwarder::MeshForwarder(ThreadNetif &aThreadNetif):
mRestorePanId(Mac::kPanIdBroadcast),
mScanning(false),
mDataPollManager(*this),
mSrcMatchEnabled(false)
mSourceMatchController(*this)
{
mFragTag = static_cast<uint16_t>(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<Child *>(neighbor);
children->mQueuedIndirectMessageCnt++;
AddSrcMatchEntry(*children);
aMessage.SetChildMask(mNetif.GetMle().GetChildIndex(*children));
child = static_cast<Child *>(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<Child *>(neighbor);
children->mQueuedIndirectMessageCnt++;
AddSrcMatchEntry(*children);
aMessage.SetChildMask(mNetif.GetMle().GetChildIndex(*children));
child = static_cast<Child *>(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;
}
+11 -1
View File
@@ -43,6 +43,7 @@
#include <net/ip6.hpp>
#include <thread/address_resolver.hpp>
#include <thread/data_poll_manager.hpp>
#include <thread/src_match_controller.hpp>
#include <thread/lowpan.hpp>
#include <thread/network_data_leader.hpp>
#include <thread/topology.hpp>
@@ -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;
};
/**
+4 -4
View File
@@ -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:
+238
View File
@@ -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 <common/code_utils.hpp>
#include <common/debug.hpp>
#include <common/logging.hpp>
#include <thread/mesh_forwarder.hpp>
#include <thread/src_match_controller.hpp>
#include <thread/thread_netif.hpp>
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
+205
View File
@@ -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 <openthread-core-config.h>
#include "openthread/types.h"
#include <thread/topology.hpp>
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_
+24 -5
View File
@@ -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.
};
/**