mirror of
https://github.com/espressif/openthread.git
synced 2026-08-24 19:29:52 +00:00
Introduce mechanism for delaying MLE Parent Request and MLE Link Accept. (#674)
This commit is contained in:
committed by
Jonathan Hui
parent
ef4ebfaf39
commit
537f0fdac8
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user