mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 03:37:46 +00:00
[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:
committed by
Jonathan Hui
parent
3a6cefd48c
commit
e9e900a5dc
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user