Introduce mechanism for delaying MLE Parent Request and MLE Link Accept. (#674)

This commit is contained in:
Robert Lubos
2016-09-28 23:55:34 -07:00
committed by Jonathan Hui
parent ef4ebfaf39
commit 537f0fdac8
3 changed files with 234 additions and 12 deletions
+7 -5
View File
@@ -55,11 +55,13 @@ enum
*/
enum
{
kVersion = 2, ///< MLE Version
kUdpPort = 19788, ///< MLE UDP Port
kParentRequestRouterTimeout = 1000, ///< Router Request timeout
kParentRequestChildTimeout = 2000, ///< End Device Request timeout
kMaxResponseDelay = 1000, ///< Maximum delay before responding to a multicast request
kVersion = 2, ///< MLE Version
kUdpPort = 19788, ///< MLE UDP Port
kParentRequestRouterTimeout = 1000, ///< Router Request timeout
kParentRequestChildTimeout = 2000, ///< End Device Request timeout
kParentResponseMaxDelayRouters = 500, ///< Maximum delay for response for Parent Request sent to routers only
kParentResponseMaxDelayAll = 1000, ///< Maximum delay for response for Parent Request sent to all devices
kMaxResponseDelay = 1000, ///< Maximum delay before responding to a multicast request
};
enum
+113 -6
View File
@@ -52,6 +52,7 @@ MleRouter::MleRouter(ThreadNetif &aThreadNetif):
Mle(aThreadNetif),
mAdvertiseTimer(aThreadNetif.GetIp6().mTimerScheduler, &MleRouter::HandleAdvertiseTimer, NULL, this),
mStateUpdateTimer(aThreadNetif.GetIp6().mTimerScheduler, &MleRouter::HandleStateUpdateTimer, this),
mDelayedResponseTimer(aThreadNetif.GetIp6().mTimerScheduler, &MleRouter::HandleDelayedResponseTimer, this),
mSocket(aThreadNetif.GetIp6().mUdp),
mAddressSolicit(OPENTHREAD_URI_ADDRESS_SOLICIT, &MleRouter::HandleAddressSolicit, this),
mAddressRelease(OPENTHREAD_URI_ADDRESS_RELEASE, &MleRouter::HandleAddressRelease, this),
@@ -750,9 +751,19 @@ ThreadError MleRouter::SendLinkAccept(const Ip6::MessageInfo &aMessageInfo, Neig
aNeighbor->mState = Neighbor::kStateLinkRequest;
}
SuccessOrExit(error = SendMessage(*message, aMessageInfo.GetPeerAddr()));
if (aMessageInfo.GetSockAddr().IsMulticast())
{
SuccessOrExit(error = AddDelayedResponse(*message, aMessageInfo.GetPeerAddr(),
(otPlatRandomGet() % kMaxResponseDelay) + 1));
otLogInfoMle("Sent link accept\n");
otLogInfoMle("Delayed link accept\n");
}
else
{
SuccessOrExit(error = SendMessage(*message, aMessageInfo.GetPeerAddr()));
otLogInfoMle("Sent link accept\n");
}
exit:
@@ -1638,8 +1649,9 @@ ThreadError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::M
child->mState = Neighbor::kStateParentRequest;
child->mDataRequest = false;
child->mLastHeard = Timer::GetNow();
child->mTimeout = Timer::SecToMsec(2 * kParentRequestChildTimeout);
SuccessOrExit(error = SendParentResponse(child, challenge));
SuccessOrExit(error = SendParentResponse(child, challenge, !scanMask.IsEndDeviceFlagSet()));
exit:
return error;
@@ -1767,11 +1779,96 @@ exit:
{}
}
ThreadError MleRouter::SendParentResponse(Child *aChild, const ChallengeTlv &challenge)
void MleRouter::HandleDelayedResponseTimer(void *aContext)
{
static_cast<MleRouter *>(aContext)->HandleDelayedResponseTimer();
}
void MleRouter::HandleDelayedResponseTimer(void)
{
DelayedResponseHeader delayedResponse;
uint32_t now = otPlatAlarmGetNow();
uint32_t nextDelay = 0xffffffff;
Message *message = mDelayedResponses.GetHead();
Message *nextMessage = NULL;
while (message != NULL)
{
nextMessage = message->GetNext();
delayedResponse.ReadFrom(*message);
if (delayedResponse.IsLater(now))
{
// Calculate the next delay and choose the lowest.
if (delayedResponse.GetSendTime() - now < nextDelay)
{
nextDelay = delayedResponse.GetSendTime() - now;
}
}
else
{
mDelayedResponses.Dequeue(*message);
// Remove the DelayedResponseHeader from the message.
DelayedResponseHeader::RemoveFrom(*message);
// Send the message.
if (SendMessage(*message, delayedResponse.GetDestination()) == kThreadError_None)
{
otLogInfoMle("Sent delayed response\n");
}
else
{
message->Free();
}
}
message = nextMessage;
}
if (nextDelay != 0xffffffff)
{
mDelayedResponseTimer.Start(nextDelay);
}
}
ThreadError MleRouter::AddDelayedResponse(Message &aMessage, const Ip6::Address &aDestination, uint16_t aDelay)
{
ThreadError error = kThreadError_None;
uint32_t alarmFireTime;
uint32_t sendTime = otPlatAlarmGetNow() + aDelay;
// Append the message with DelayedRespnoseHeader and add to the list.
DelayedResponseHeader delayedResponse(sendTime, aDestination);
SuccessOrExit(error = delayedResponse.AppendTo(aMessage));
mDelayedResponses.Enqueue(aMessage);
if (mDelayedResponseTimer.IsRunning())
{
// If timer is already running, check if it should be restarted with earlier fire time.
alarmFireTime = mDelayedResponseTimer.Gett0() + mDelayedResponseTimer.Getdt();
if (delayedResponse.IsEarlier(alarmFireTime))
{
mDelayedResponseTimer.Start(aDelay);
}
}
else
{
// Otherwise just set the timer.
mDelayedResponseTimer.Start(aDelay);
}
exit:
return error;
}
ThreadError MleRouter::SendParentResponse(Child *aChild, const ChallengeTlv &challenge, bool aRoutersOnlyRequest)
{
ThreadError error = kThreadError_None;
Ip6::Address destination;
Message *message;
uint16_t delay;
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
message->SetLinkSecurityEnabled(false);
@@ -1806,9 +1903,19 @@ ThreadError MleRouter::SendParentResponse(Child *aChild, const ChallengeTlv &cha
memset(&destination, 0, sizeof(destination));
destination.mFields.m16[0] = HostSwap16(0xfe80);
destination.SetIid(aChild->mMacAddr);
SuccessOrExit(error = SendMessage(*message, destination));
otLogInfoMle("Sent Parent Response\n");
if (aRoutersOnlyRequest)
{
delay = (otPlatRandomGet() % kParentResponseMaxDelayRouters) + 1;
}
else
{
delay = (otPlatRandomGet() % kParentResponseMaxDelayAll) + 1;
}
SuccessOrExit(error = AddDelayedResponse(*message, destination, delay));
otLogInfoMle("Delayed Parent Response\n");
exit:
+114 -1
View File
@@ -34,6 +34,8 @@
#ifndef MLE_ROUTER_HPP_
#define MLE_ROUTER_HPP_
#include <string.h>
#include <coap/coap_header.hpp>
#include <coap/coap_server.hpp>
#include <common/timer.hpp>
@@ -61,6 +63,110 @@ class NetworkDataLeader;
* @{
*/
/**
* This class implements functionality required for delaying MLE responses.
*
*/
OT_TOOL_PACKED_BEGIN
class DelayedResponseHeader
{
public:
/**
* Default constructor for the object.
*
*/
DelayedResponseHeader(void) { memset(this, 0, sizeof(*this)); };
/**
* This constructor initializes the object with specific values.
*
* @param[in] aSendTime Time when the message shall be sent.
* @param[in] aDestination IPv6 address of the message destination.
*
*/
DelayedResponseHeader(uint32_t aSendTime, const Ip6::Address &aDestination) {
mSendTime = aSendTime;
mDestination = aDestination;
};
/**
* This method appends delayed response header to the message.
*
* @param[in] aMessage A reference to the message.
*
* @retval kThreadError_None Successfully appended the bytes.
* @retval kThreadError_NoBufs Insufficient available buffers to grow the message.
*
*/
ThreadError AppendTo(Message &aMessage) {
return aMessage.Append(this, sizeof(*this));
};
/**
* This method reads delayed response header from the message.
*
* @param[in] aMessage A reference to the message.
*
* @returns The number of bytes read.
*
*/
uint16_t ReadFrom(Message &aMessage) {
return aMessage.Read(aMessage.GetLength() - sizeof(*this), sizeof(*this), this);
};
/**
* This method removes delayed response header from the message.
*
* @param[in] aMessage A reference to the message.
*
* @retval kThreadError_None Successfully removed the header.
*
*/
static ThreadError RemoveFrom(Message &aMessage) {
return aMessage.SetLength(aMessage.GetLength() - sizeof(DelayedResponseHeader));
};
/**
* This method returns a time when the message shall be sent.
*
* @returns A time when the message shall be sent.
*
*/
uint32_t GetSendTime(void) const { return mSendTime; };
/**
* This method returns a destination of the delayed message.
*
* @returns A destination of the delayed message.
*
*/
const Ip6::Address &GetDestination(void) const { return mDestination; };
/**
* This method checks if the message shall be sent before the given time.
*
* @param[in] aTime A time to compare.
*
* @retval TRUE If the message shall be sent before the given time.
* @retval FALSE Otherwise.
*/
bool IsEarlier(uint32_t aTime) { return (static_cast<int32_t>(aTime - mSendTime) > 0); };
/**
* This method checks if the message shall be sent after the given time.
*
* @param[in] aTime A time to compare.
*
* @retval TRUE If the message shall be sent after the given time.
* @retval FALSE Otherwise.
*/
bool IsLater(uint32_t aTime) { return (static_cast<int32_t>(aTime - mSendTime) < 0); };
private:
Ip6::Address mDestination; ///< IPv6 address of the message destination.
uint32_t mSendTime; ///< Time when the message shall be sent.
} OT_TOOL_PACKED_END;
/**
* This class implements MLE functionality required by the Thread Router and Leader roles.
*
@@ -552,7 +658,7 @@ private:
ThreadError SendLinkRequest(Neighbor *aNeighbor);
ThreadError SendLinkAccept(const Ip6::MessageInfo &aMessageInfo, Neighbor *aNeighbor,
const TlvRequestTlv &aTlvRequest, const ChallengeTlv &aChallenge);
ThreadError SendParentResponse(Child *aChild, const ChallengeTlv &aChallenge);
ThreadError SendParentResponse(Child *aChild, const ChallengeTlv &aChallenge, bool aRoutersOnlyRequest);
ThreadError SendChildIdResponse(Child *aChild);
ThreadError SendChildUpdateResponse(Child *aChild, const Ip6::MessageInfo &aMessageInfo,
const uint8_t *aTlvs, uint8_t aTlvsLength, const ChallengeTlv *challenge);
@@ -593,9 +699,16 @@ private:
bool HandleAdvertiseTimer(void);
static void HandleStateUpdateTimer(void *aContext);
void HandleStateUpdateTimer(void);
static void HandleDelayedResponseTimer(void *aContext);
void HandleDelayedResponseTimer(void);
ThreadError AddDelayedResponse(Message &aMessage, const Ip6::Address &aDestination, uint16_t aDelay);
MessageQueue mDelayedResponses;
TrickleTimer mAdvertiseTimer;
Timer mStateUpdateTimer;
Timer mDelayedResponseTimer;
Ip6::UdpSocket mSocket;
Coap::Resource mAddressSolicit;