[indirect-sender] convert queued child messages when mode changes (#4001)

This commit ensures all queued messages for a child are accordingly
converted (indirect to direct transmission) when a child switches its
mode from sleepy to non-sleepy.
This commit is contained in:
Abtin Keshavarzian
2019-07-22 09:45:33 -07:00
committed by Jonathan Hui
parent 3a6cefd48c
commit e9e900a5dc
3 changed files with 71 additions and 17 deletions
+40
View File
@@ -41,6 +41,7 @@
#include "common/logging.hpp"
#include "common/message.hpp"
#include "thread/mesh_forwarder.hpp"
#include "thread/mle_tlvs.hpp"
#include "thread/topology.hpp"
namespace ot {
@@ -163,6 +164,45 @@ exit:
return;
}
void IndirectSender::HandleChildModeChange(Child &aChild, uint8_t aOldMode)
{
bool wasRxOnWhenIdle = ((aOldMode & Mle::ModeTlv::kModeRxOnWhenIdle) != 0);
if (!aChild.IsRxOnWhenIdle() && (aChild.GetState() == Neighbor::kStateValid))
{
SetChildUseShortAddress(aChild, true);
}
// On sleepy to non-sleepy mode change, convert indirect messages in
// the send queue destined to the child to direct.
if (!wasRxOnWhenIdle && aChild.IsRxOnWhenIdle() && (aChild.GetIndirectMessageCount() > 0))
{
uint8_t childIndex = Get<ChildTable>().GetChildIndex(aChild);
for (Message *message = Get<MeshForwarder>().mSendQueue.GetHead(); message; message = message->GetNext())
{
if (message->GetChildMask(childIndex))
{
message->ClearChildMask(childIndex);
message->SetDirectTransmission();
}
}
aChild.SetIndirectMessage(NULL);
mSourceMatchController.ResetMessageCount(aChild);
mDataPollHandler.RequestFrameChange(DataPollHandler::kPurgeFrame, aChild);
}
// Since the queuing delays for direct transmissions are expected to
// be relatively small especially when compared to indirect, for a
// non-sleepy to sleepy mode change, we allow any direct message
// (for the child) already in the send queue to remain as is. This
// is equivalent to dropping the already queued messages in this
// case.
}
Message *IndirectSender::FindIndirectMessage(Child &aChild)
{
Message *message;
+9
View File
@@ -186,6 +186,15 @@ public:
*/
void SetChildUseShortAddress(Child &aChild, bool aUseShortAddress);
/**
* This method handles a child mode change and updates any queued messages for the child accordingly.
*
* @param[in] aChild The child whose device mode was changed.
* @param[in] aOldMode The old device mode of the child.
*
*/
void HandleChildModeChange(Child &aChild, uint8_t aOldMode);
private:
enum
{
+22 -17
View File
@@ -2225,6 +2225,7 @@ otError MleRouter::HandleChildUpdateRequest(const Message & aMessage,
LeaderDataTlv leaderData;
TimeoutTlv timeout;
Child * child;
uint8_t oldMode;
TlvRequestTlv tlvRequest;
uint8_t tlvs[kMaxResponseTlvs];
uint8_t tlvslength = 0;
@@ -2257,23 +2258,8 @@ otError MleRouter::HandleChildUpdateRequest(const Message & aMessage,
ExitNow();
}
if (child->GetDeviceMode() != mode.GetMode())
{
otLogNoteMle("Child 0x%04x mode change 0x%02x -> 0x%02x [rx-on:%s, sec-data-req:%s, ftd:%s, full-netdata:%s]",
child->GetRloc16(), child->GetDeviceMode(), mode.GetMode(),
(mode.GetMode() & ModeTlv::kModeRxOnWhenIdle) ? "yes" : " no",
(mode.GetMode() & ModeTlv::kModeSecureDataRequest) ? "yes" : " no",
(mode.GetMode() & ModeTlv::kModeFullThreadDevice) ? "yes" : "no",
(mode.GetMode() & ModeTlv::kModeFullNetworkData) ? "yes" : "no");
child->SetDeviceMode(mode.GetMode());
childDidChange = true;
if (!(mode.GetMode() & ModeTlv::kModeRxOnWhenIdle) && (child->GetState() == Neighbor::kStateValid))
{
Get<IndirectSender>().SetChildUseShortAddress(*child, true);
}
}
oldMode = child->GetDeviceMode();
child->SetDeviceMode(mode.GetMode());
tlvs[tlvslength++] = Tlv::kMode;
@@ -2337,6 +2323,25 @@ otError MleRouter::HandleChildUpdateRequest(const Message & aMessage,
child->SetLastHeard(TimerMilli::GetNow());
if (oldMode != child->GetDeviceMode())
{
otLogNoteMle("Child 0x%04x mode change 0x%02x -> 0x%02x [rx-on:%s, sec-data-req:%s, ftd:%s, full-netdata:%s]",
child->GetRloc16(), oldMode, mode.GetMode(),
(mode.GetMode() & ModeTlv::kModeRxOnWhenIdle) ? "yes" : "no",
(mode.GetMode() & ModeTlv::kModeSecureDataRequest) ? "yes" : "no",
(mode.GetMode() & ModeTlv::kModeFullThreadDevice) ? "yes" : "no",
(mode.GetMode() & ModeTlv::kModeFullNetworkData) ? "yes" : "no");
childDidChange = true;
// The `IndirectSender::HandleChildModeChange()` needs to happen
// after "Child Update" message is fully parsed to ensure that
// any registered IPv6 addresses included in the "Child Update"
// are added to the child.
Get<IndirectSender>().HandleChildModeChange(*child, oldMode);
}
if (child->IsStateRestoring())
{
SetChildStateToValid(*child);