mirror of
https://github.com/espressif/openthread.git
synced 2026-07-11 06:40:19 +00:00
MPL: Introduce multicast forwarding. (#827)
* Message: Add a new optional parameter to Clone method. * MPL: Introduce MPL Forwarding This commit introduces MPL Forwarding for Routers. All references to MPL Seed have been replaced with MPL Seed Id.
This commit is contained in:
committed by
Jonathan Hui
parent
ad39a59ff9
commit
78d4b678e3
@@ -474,14 +474,14 @@ int Message::CopyTo(uint16_t aSourceOffset, uint16_t aDestinationOffset, uint16_
|
||||
return bytesCopied;
|
||||
}
|
||||
|
||||
Message *Message::Clone(void) const
|
||||
Message *Message::Clone(uint16_t aLength) const
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
Message *messageCopy;
|
||||
|
||||
VerifyOrExit((messageCopy = GetMessagePool()->New(GetType(), GetReserved())) != NULL, error = kThreadError_NoBufs);
|
||||
SuccessOrExit(error = messageCopy->SetLength(GetLength()));
|
||||
CopyTo(0, 0, GetLength(), *messageCopy);
|
||||
SuccessOrExit(error = messageCopy->SetLength(aLength));
|
||||
CopyTo(0, 0, aLength, *messageCopy);
|
||||
|
||||
// Copy selected message information.
|
||||
messageCopy->SetOffset(GetOffset());
|
||||
|
||||
@@ -386,11 +386,21 @@ public:
|
||||
|
||||
/**
|
||||
* This method creates a copy of the current Message. It allocates the new one
|
||||
* from the same Message Poll as the original Message.
|
||||
* from the same Message Poll as the original Message and copies @p aLength octets of a payload.
|
||||
*
|
||||
* @param[in] aLength Number of payload bytes to copy.
|
||||
*
|
||||
* @returns A pointer to the message or NULL if insufficient message buffers are available.
|
||||
*/
|
||||
Message *Clone(void) const;
|
||||
Message *Clone(uint16_t aLength) const;
|
||||
|
||||
/**
|
||||
* This method creates a copy of the current Message. It allocates the new one
|
||||
* from the same Message Poll as the original Message and copies a full payload.
|
||||
*
|
||||
* @returns A pointer to the message or NULL if insufficient message buffers are available.
|
||||
*/
|
||||
Message *Clone(void) const { return Clone(GetLength()); };
|
||||
|
||||
/**
|
||||
* This method returns the datagram tag used for 6LoWPAN fragmentation.
|
||||
|
||||
@@ -151,6 +151,12 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Ip6::EnqueueDatagram(Message &aMessage)
|
||||
{
|
||||
mSendQueue.Enqueue(aMessage);
|
||||
mSendQueueTask.Post();
|
||||
}
|
||||
|
||||
ThreadError Ip6::SendDatagram(Message &message, MessageInfo &messageInfo, IpProto ipproto)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
@@ -211,8 +217,7 @@ exit:
|
||||
if (error == kThreadError_None)
|
||||
{
|
||||
message.SetInterfaceId(messageInfo.mInterfaceId);
|
||||
mSendQueue.Enqueue(message);
|
||||
mSendQueueTask.Post();
|
||||
EnqueueDatagram(message);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -308,7 +313,7 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
ThreadError Ip6::HandleExtensionHeaders(Message &message, Header &header, uint8_t &nextHeader, bool &forward,
|
||||
ThreadError Ip6::HandleExtensionHeaders(Message &message, Header &header, uint8_t &nextHeader, bool forward,
|
||||
bool receive)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
@@ -488,6 +493,7 @@ ThreadError Ip6::HandleDatagram(Message &message, Netif *netif, int8_t interface
|
||||
}
|
||||
}
|
||||
|
||||
message.SetInterfaceId(interfaceId);
|
||||
message.SetOffset(sizeof(header));
|
||||
|
||||
// process IPv6 Extension Headers
|
||||
|
||||
@@ -146,6 +146,14 @@ public:
|
||||
ThreadError HandleDatagram(Message &aMessage, Netif *aNetif, int8_t aInterfaceId,
|
||||
const void *aLinkMessageInfo, bool aFromNcpHost);
|
||||
|
||||
|
||||
/**
|
||||
* This methods adds a full IPv6 packet to the transmit queue.
|
||||
*
|
||||
* @param aMessage A reference to the message.
|
||||
*/
|
||||
void EnqueueDatagram(Message &aMessage);
|
||||
|
||||
/**
|
||||
* This static method updates a checksum.
|
||||
*
|
||||
@@ -335,7 +343,7 @@ private:
|
||||
void HandleSendQueue(void);
|
||||
|
||||
ThreadError ProcessReceiveCallback(const Message &aMessage, const MessageInfo &aMessageInfo, uint8_t aIpProto);
|
||||
ThreadError HandleExtensionHeaders(Message &message, Header &header, uint8_t &nextHeader, bool &forward,
|
||||
ThreadError HandleExtensionHeaders(Message &message, Header &header, uint8_t &nextHeader, bool forward,
|
||||
bool receive);
|
||||
ThreadError HandleFragment(Message &message);
|
||||
ThreadError AddMplOption(Message &message, Header &header, IpProto nextHeader, uint16_t payloadLength);
|
||||
|
||||
+250
-42
@@ -35,17 +35,31 @@
|
||||
#include <common/message.hpp>
|
||||
#include <net/ip6.hpp>
|
||||
#include <net/ip6_mpl.hpp>
|
||||
#include <platform/random.h>
|
||||
|
||||
namespace Thread {
|
||||
namespace Ip6 {
|
||||
|
||||
void MplBufferedMessageMetadata::GenerateNextTransmissionTime(uint32_t aCurrentTime, uint8_t aInterval)
|
||||
{
|
||||
// Emulate Trickle timer behavior and set up the next retransmission within [0,I) range.
|
||||
uint8_t t = otPlatRandomGet() % aInterval;
|
||||
|
||||
// Set transmission time at the beginning of the next interval.
|
||||
SetTransmissionTime(aCurrentTime + GetIntervalOffset() + t);
|
||||
SetIntervalOffset(aInterval - t);
|
||||
}
|
||||
|
||||
Mpl::Mpl(Ip6 &aIp6):
|
||||
mTimer(aIp6.mTimerScheduler, &Mpl::HandleTimer, this),
|
||||
mIp6(aIp6),
|
||||
mSeedSetTimer(aIp6.mTimerScheduler, &Mpl::HandleSeedSetTimer, this),
|
||||
mRetransmissionTimer(aIp6.mTimerScheduler, &Mpl::HandleRetransmissionTimer, this),
|
||||
mTimerExpirations(0),
|
||||
mSequence(0),
|
||||
mSeedId(0),
|
||||
mMatchingAddress(NULL)
|
||||
{
|
||||
memset(mEntries, 0, sizeof(mEntries));
|
||||
mSequence = 0;
|
||||
mSeed = 0;
|
||||
memset(mSeedSet, 0, sizeof(mSeedSet));
|
||||
}
|
||||
|
||||
void Mpl::InitOption(OptionMpl &aOption, const Address &aAddress)
|
||||
@@ -53,49 +67,41 @@ void Mpl::InitOption(OptionMpl &aOption, const Address &aAddress)
|
||||
aOption.Init();
|
||||
aOption.SetSequence(mSequence++);
|
||||
|
||||
// Check if Seed can be elided.
|
||||
// Check if Seed Id can be elided.
|
||||
if (mMatchingAddress && aAddress == *mMatchingAddress)
|
||||
{
|
||||
aOption.SetSeedLength(OptionMpl::kSeedLength0);
|
||||
aOption.SetSeedIdLength(OptionMpl::kSeedIdLength0);
|
||||
|
||||
// Decrease default option length.
|
||||
aOption.SetLength(aOption.GetLength() - sizeof(mSeed));
|
||||
aOption.SetLength(aOption.GetLength() - sizeof(mSeedId));
|
||||
}
|
||||
else
|
||||
{
|
||||
aOption.SetSeedLength(OptionMpl::kSeedLength2);
|
||||
aOption.SetSeed(mSeed);
|
||||
aOption.SetSeedIdLength(OptionMpl::kSeedIdLength2);
|
||||
aOption.SetSeedId(mSeedId);
|
||||
}
|
||||
}
|
||||
|
||||
ThreadError Mpl::ProcessOption(const Message &aMessage, const Address &aAddress, bool &aForward)
|
||||
ThreadError Mpl::UpdateSeedSet(uint16_t aSeedId, uint8_t aSequence)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
OptionMpl option;
|
||||
MplEntry *entry = NULL;
|
||||
MplSeedEntry *entry = NULL;
|
||||
int8_t diff;
|
||||
|
||||
VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(option), &option) >= OptionMpl::kMinLength &&
|
||||
(option.GetSeedLength() == OptionMpl::kSeedLength0 ||
|
||||
option.GetSeedLength() == OptionMpl::kSeedLength2),
|
||||
error = kThreadError_Drop);
|
||||
|
||||
if (option.GetSeedLength() == OptionMpl::kSeedLength0)
|
||||
for (uint32_t i = 0; i < kNumSeedEntries; i++)
|
||||
{
|
||||
// Retrieve Seed from the IPv6 Source Address.
|
||||
option.SetSeed(HostSwap16(aAddress.mFields.m16[7]));
|
||||
}
|
||||
|
||||
for (int i = 0; i < kNumEntries; i++)
|
||||
{
|
||||
if (mEntries[i].mLifetime == 0)
|
||||
if (mSeedSet[i].GetLifetime() == 0)
|
||||
{
|
||||
entry = &mEntries[i];
|
||||
// Start allocating from the first possible entry to speed up process of searching.
|
||||
if (entry == NULL)
|
||||
{
|
||||
entry = &mSeedSet[i];
|
||||
}
|
||||
}
|
||||
else if (mEntries[i].mSeed == option.GetSeed())
|
||||
else if (mSeedSet[i].GetSeedId() == aSeedId)
|
||||
{
|
||||
entry = &mEntries[i];
|
||||
diff = static_cast<int8_t>(option.GetSequence() - entry->mSequence);
|
||||
entry = &mSeedSet[i];
|
||||
diff = static_cast<int8_t>(aSequence - entry->GetSequence());
|
||||
|
||||
VerifyOrExit(diff > 0, error = kThreadError_Drop);
|
||||
|
||||
@@ -105,38 +111,240 @@ ThreadError Mpl::ProcessOption(const Message &aMessage, const Address &aAddress,
|
||||
|
||||
VerifyOrExit(entry != NULL, error = kThreadError_Drop);
|
||||
|
||||
aForward = true;
|
||||
|
||||
entry->mSeed = option.GetSeed();
|
||||
entry->mSequence = option.GetSequence();
|
||||
entry->mLifetime = kLifetime;
|
||||
mTimer.Start(1000);
|
||||
entry->SetSeedId(aSeedId);
|
||||
entry->SetSequence(aSequence);
|
||||
entry->SetLifetime(kSeedEntryLifetime);
|
||||
mSeedSetTimer.Start(kSeedEntryLifetimeDt);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mpl::HandleTimer(void *aContext)
|
||||
void Mpl::UpdateBufferedSet(uint16_t aSeedId, uint8_t aSequence)
|
||||
{
|
||||
static_cast<Mpl *>(aContext)->HandleTimer();
|
||||
int8_t diff;
|
||||
MplBufferedMessageMetadata messageMetadata;
|
||||
|
||||
Message *message = mBufferedMessageSet.GetHead();
|
||||
Message *nextMessage = NULL;
|
||||
|
||||
// Check if multicast forwarding is enabled.
|
||||
VerifyOrExit(GetTimerExpirations() > 0, ;);
|
||||
|
||||
while (message != NULL)
|
||||
{
|
||||
nextMessage = message->GetNext();
|
||||
messageMetadata.ReadFrom(*message);
|
||||
|
||||
if (messageMetadata.GetSeedId() == aSeedId)
|
||||
{
|
||||
diff = static_cast<int8_t>(aSequence - messageMetadata.GetSequence());
|
||||
|
||||
if (diff > 0)
|
||||
{
|
||||
// Stop retransmitting MPL Data Message that is consider to be old.
|
||||
mBufferedMessageSet.Dequeue(*message);
|
||||
message->Free();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
message = nextMessage;
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Mpl::HandleTimer()
|
||||
void Mpl::AddBufferedMessage(Message &aMessage, uint16_t aSeedId, uint8_t aSequence, bool aIsOutbound)
|
||||
{
|
||||
uint32_t now = Timer::GetNow();
|
||||
ThreadError error = kThreadError_None;
|
||||
Message *messageCopy = NULL;
|
||||
MplBufferedMessageMetadata messageMetadata;
|
||||
uint32_t nextTransmissionTime;
|
||||
uint8_t hopLimit;
|
||||
|
||||
VerifyOrExit((messageCopy = aMessage.Clone()) != NULL, error = kThreadError_NoBufs);
|
||||
|
||||
if (!aIsOutbound)
|
||||
{
|
||||
aMessage.Read(Header::GetHopLimitOffset(), Header::GetHopLimitSize(), &hopLimit);
|
||||
VerifyOrExit(--hopLimit > 0, error = kThreadError_Drop);
|
||||
messageCopy->Write(Header::GetHopLimitOffset(), Header::GetHopLimitSize(), &hopLimit);
|
||||
}
|
||||
|
||||
messageMetadata.SetSeedId(aSeedId);
|
||||
messageMetadata.SetSequence(aSequence);
|
||||
messageMetadata.SetTransmissionCount(aIsOutbound ? 1 : 0);
|
||||
messageMetadata.GenerateNextTransmissionTime(now, kDataMessageInterval);
|
||||
|
||||
// Append the message with MplBufferedMessageMetadata and add it to the queue.
|
||||
SuccessOrExit(error = messageMetadata.AppendTo(*messageCopy));
|
||||
mBufferedMessageSet.Enqueue(*messageCopy);
|
||||
|
||||
if (mRetransmissionTimer.IsRunning())
|
||||
{
|
||||
// If timer is already running, check if it should be restarted with earlier fire time.
|
||||
nextTransmissionTime = mRetransmissionTimer.Gett0() + mRetransmissionTimer.Getdt();
|
||||
|
||||
if (messageMetadata.IsEarlier(nextTransmissionTime))
|
||||
{
|
||||
mRetransmissionTimer.Start(messageMetadata.GetTransmissionTime() - now);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise just set the timer.
|
||||
mRetransmissionTimer.Start(messageMetadata.GetTransmissionTime() - now);
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kThreadError_None && messageCopy != NULL)
|
||||
{
|
||||
messageCopy->Free();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadError Mpl::ProcessOption(Message &aMessage, const Address &aAddress, bool aIsOutbound)
|
||||
{
|
||||
ThreadError error;
|
||||
OptionMpl option;
|
||||
|
||||
VerifyOrExit(aMessage.Read(aMessage.GetOffset(), sizeof(option), &option) >= OptionMpl::kMinLength &&
|
||||
(option.GetSeedIdLength() == OptionMpl::kSeedIdLength0 ||
|
||||
option.GetSeedIdLength() == OptionMpl::kSeedIdLength2),
|
||||
error = kThreadError_Drop);
|
||||
|
||||
if (option.GetSeedIdLength() == OptionMpl::kSeedIdLength0)
|
||||
{
|
||||
// Retrieve MPL Seed Id from the IPv6 Source Address.
|
||||
option.SetSeedId(HostSwap16(aAddress.mFields.m16[7]));
|
||||
}
|
||||
|
||||
// Check MPL Data Messages in the MPL Buffered Set against sequence number.
|
||||
UpdateBufferedSet(option.GetSeedId(), option.GetSequence());
|
||||
|
||||
// Check if the MPL Data Message is new.
|
||||
error = UpdateSeedSet(option.GetSeedId(), option.GetSequence());
|
||||
|
||||
if (error == kThreadError_None)
|
||||
{
|
||||
AddBufferedMessage(aMessage, option.GetSeedId(), option.GetSequence(), aIsOutbound);
|
||||
}
|
||||
else if (aIsOutbound)
|
||||
{
|
||||
// In case MPL Data Message is generated locally, ignore potential error of the MPL Seed Set
|
||||
// to allow subsequent retransmissions with the same sequence number.
|
||||
ExitNow(error = kThreadError_None);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Mpl::HandleRetransmissionTimer(void *aContext)
|
||||
{
|
||||
static_cast<Mpl *>(aContext)->HandleRetransmissionTimer();
|
||||
}
|
||||
|
||||
void Mpl::HandleRetransmissionTimer()
|
||||
{
|
||||
uint32_t now = Timer::GetNow();
|
||||
uint32_t nextDelta = 0xffffffff;
|
||||
MplBufferedMessageMetadata messageMetadata;
|
||||
|
||||
Message *message = mBufferedMessageSet.GetHead();
|
||||
Message *nextMessage = NULL;
|
||||
|
||||
while (message != NULL)
|
||||
{
|
||||
nextMessage = message->GetNext();
|
||||
messageMetadata.ReadFrom(*message);
|
||||
|
||||
if (messageMetadata.IsLater(now))
|
||||
{
|
||||
// Calculate the next retransmission time and choose the lowest.
|
||||
if (messageMetadata.GetTransmissionTime() - now < nextDelta)
|
||||
{
|
||||
nextDelta = messageMetadata.GetTransmissionTime() - now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update the number of transmission timer expirations.
|
||||
messageMetadata.SetTransmissionCount(messageMetadata.GetTransmissionCount() + 1);
|
||||
|
||||
if (messageMetadata.GetTransmissionCount() < GetTimerExpirations())
|
||||
{
|
||||
Message *messageCopy = message->Clone(message->GetLength() - sizeof(MplBufferedMessageMetadata));
|
||||
|
||||
if (messageCopy != NULL)
|
||||
{
|
||||
mIp6.EnqueueDatagram(*messageCopy);
|
||||
}
|
||||
|
||||
messageMetadata.GenerateNextTransmissionTime(now, kDataMessageInterval);
|
||||
messageMetadata.UpdateIn(*message);
|
||||
|
||||
// Check if retransmission time is lower than the current lowest one.
|
||||
if (messageMetadata.GetTransmissionTime() - now < nextDelta)
|
||||
{
|
||||
nextDelta = messageMetadata.GetTransmissionTime() - now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mBufferedMessageSet.Dequeue(*message);
|
||||
|
||||
if (messageMetadata.GetTransmissionCount() == GetTimerExpirations())
|
||||
{
|
||||
// Remove the extra metadata from the MPL Data Message.
|
||||
messageMetadata.RemoveFrom(*message);
|
||||
mIp6.EnqueueDatagram(*message);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stop retransmitting if the number of timer expirations is already exceeded.
|
||||
message->Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message = nextMessage;
|
||||
}
|
||||
|
||||
if (nextDelta != 0xffffffff)
|
||||
{
|
||||
mRetransmissionTimer.Start(nextDelta);
|
||||
}
|
||||
}
|
||||
|
||||
void Mpl::HandleSeedSetTimer(void *aContext)
|
||||
{
|
||||
static_cast<Mpl *>(aContext)->HandleSeedSetTimer();
|
||||
}
|
||||
|
||||
void Mpl::HandleSeedSetTimer()
|
||||
{
|
||||
bool startTimer = false;
|
||||
|
||||
for (int i = 0; i < kNumEntries; i++)
|
||||
for (int i = 0; i < kNumSeedEntries; i++)
|
||||
{
|
||||
if (mEntries[i].mLifetime > 0)
|
||||
if (mSeedSet[i].GetLifetime() > 0)
|
||||
{
|
||||
mEntries[i].mLifetime--;
|
||||
mSeedSet[i].SetLifetime(mSeedSet[i].GetLifetime() - 1);
|
||||
startTimer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (startTimer)
|
||||
{
|
||||
mTimer.Start(1000);
|
||||
mSeedSetTimer.Start(kSeedEntryLifetimeDt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+327
-47
@@ -86,31 +86,31 @@ public:
|
||||
uint8_t GetTotalLength() const { return OptionHeader::GetLength() + sizeof(OptionHeader); }
|
||||
|
||||
/**
|
||||
* MPL Seed lengths.
|
||||
* MPL Seed Id lengths.
|
||||
*/
|
||||
enum SeedLength
|
||||
enum SeedIdLength
|
||||
{
|
||||
kSeedLength0 = 0 << 6, ///< 0-byte MPL Seed Length.
|
||||
kSeedLength2 = 1 << 6, ///< 2-byte MPL Seed Length.
|
||||
kSeedLength8 = 2 << 6, ///< 8-byte MPL Seed Length.
|
||||
kSeedLength16 = 3 << 6, ///< 16-byte MPL Seed Length.
|
||||
kSeedIdLength0 = 0 << 6, ///< 0-byte MPL Seed Id Length.
|
||||
kSeedIdLength2 = 1 << 6, ///< 2-byte MPL Seed Id Length.
|
||||
kSeedIdLength8 = 2 << 6, ///< 8-byte MPL Seed Id Length.
|
||||
kSeedIdLength16 = 3 << 6, ///< 16-byte MPL Seed Id Length.
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the MPL Seed Length value.
|
||||
* This method returns the MPL Seed Id Length value.
|
||||
*
|
||||
* @returns The MPL Seed Length value.
|
||||
* @returns The MPL Seed Id Length value.
|
||||
*
|
||||
*/
|
||||
SeedLength GetSeedLength() { return static_cast<SeedLength>(mControl & kSeedLengthMask); }
|
||||
SeedIdLength GetSeedIdLength() { return static_cast<SeedIdLength>(mControl & kSeedIdLengthMask); }
|
||||
|
||||
/**
|
||||
* This method sets the MPL Seed Length value.
|
||||
* This method sets the MPL Seed Id Length value.
|
||||
*
|
||||
* @param[in] aSeedLength The MPL Seed Length.
|
||||
* @param[in] aSeedIdLength The MPL Seed Length.
|
||||
*
|
||||
*/
|
||||
void SetSeedLength(SeedLength aSeedLength) { mControl = static_cast<uint8_t>((mControl & ~kSeedLengthMask) | aSeedLength); }
|
||||
void SetSeedIdLength(SeedIdLength aSeedIdLength) { mControl = static_cast<uint8_t>((mControl & ~kSeedIdLengthMask) | aSeedIdLength); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the MPL M flag is set.
|
||||
@@ -145,33 +145,281 @@ public:
|
||||
* This method sets the MPL Sequence value.
|
||||
*
|
||||
* @param[in] aSequence The MPL Sequence value.
|
||||
*
|
||||
*/
|
||||
void SetSequence(uint8_t aSequence) { mSequence = aSequence; }
|
||||
|
||||
/**
|
||||
* This method returns the MPL Seed value.
|
||||
* This method returns the MPL Seed Id value.
|
||||
*
|
||||
* @returns The MPL Seed value.
|
||||
* @returns The MPL Seed Id value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSeed() const { return HostSwap16(mSeed); }
|
||||
uint16_t GetSeedId() const { return HostSwap16(mSeedId); }
|
||||
|
||||
/**
|
||||
* This method sets the MPL Seed value.
|
||||
* This method sets the MPL Seed Id value.
|
||||
*
|
||||
* @param[in] aSeedId The MPL Seed Id value.
|
||||
*
|
||||
* @param[in] aSeed The MPL Seed value.
|
||||
*/
|
||||
void SetSeed(uint16_t aSeed) { mSeed = HostSwap16(aSeed); }
|
||||
void SetSeedId(uint16_t aSeedId) { mSeedId = HostSwap16(aSeedId); }
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kSeedLengthMask = 3 << 6,
|
||||
kSeedIdLengthMask = 3 << 6,
|
||||
kMaxFlag = 1 << 5
|
||||
};
|
||||
uint8_t mControl;
|
||||
uint8_t mSequence;
|
||||
uint16_t mSeed;
|
||||
uint16_t mSeedId;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class represents an MPL's Seed Set entry.
|
||||
*
|
||||
*/
|
||||
class MplSeedEntry
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method returns the MPL Seed Id value.
|
||||
*
|
||||
* @returns The MPL Seed Id value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSeedId() const { return mSeedId; }
|
||||
|
||||
/**
|
||||
* This method sets the MPL Seed Id value.
|
||||
*
|
||||
* @param[in] aSeedId The MPL Seed Id value.
|
||||
*
|
||||
*/
|
||||
void SetSeedId(uint16_t aSeedId) { mSeedId = aSeedId; }
|
||||
|
||||
/**
|
||||
* This method returns the MPL Sequence value.
|
||||
*
|
||||
* @returns The MPL Sequence value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetSequence() const { return mSequence; }
|
||||
|
||||
/**
|
||||
* This method sets the MPL Sequence value.
|
||||
*
|
||||
* @param[in] aSequence The MPL Sequence value.
|
||||
*
|
||||
*/
|
||||
void SetSequence(uint8_t aSequence) { mSequence = aSequence; }
|
||||
|
||||
/**
|
||||
* This method returns the MPL Seed Set entry's remaining lifetime.
|
||||
*
|
||||
* @returns The MPL Seed Set entry's remaining lifetime.
|
||||
*
|
||||
*/
|
||||
uint8_t GetLifetime() const { return mLifetime; }
|
||||
|
||||
/**
|
||||
* This method sets the remaining lifetime of the Seed Set entry.
|
||||
*
|
||||
* @param[in] aLifetime The remaining lifetime of the Seed Set entry.
|
||||
*
|
||||
*/
|
||||
void SetLifetime(uint8_t aLifetime) { mLifetime = aLifetime; }
|
||||
|
||||
private:
|
||||
uint16_t mSeedId;
|
||||
uint8_t mSequence;
|
||||
uint8_t mLifetime;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class represents metadata required for MPL retransmissions.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class MplBufferedMessageMetadata
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default constructor for the object.
|
||||
*
|
||||
*/
|
||||
MplBufferedMessageMetadata(void):
|
||||
mSeedId(0),
|
||||
mSequence(0),
|
||||
mTransmissionCount(0),
|
||||
mTransmissionTime(0),
|
||||
mIntervalOffset(0) {
|
||||
};
|
||||
|
||||
/**
|
||||
* This method appends MPL Buffered Message metadata 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) const {
|
||||
return aMessage.Append(this, sizeof(*this));
|
||||
};
|
||||
|
||||
/**
|
||||
* This method reads request data from the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @returns The number of bytes that have been read.
|
||||
*
|
||||
*/
|
||||
uint16_t ReadFrom(const Message &aMessage) {
|
||||
return aMessage.Read(aMessage.GetLength() - sizeof(*this), sizeof(*this), this);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method removes MPL Buffered Messsage metadata from the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @retval kThreadError_None Successfully removed the header.
|
||||
*
|
||||
*/
|
||||
ThreadError RemoveFrom(Message &aMessage) {
|
||||
return aMessage.SetLength(aMessage.GetLength() - sizeof(*this));
|
||||
};
|
||||
|
||||
/**
|
||||
* This method updates MPL Buffered Messsage metadata in the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
*
|
||||
* @returns The number of bytes that have been updated.
|
||||
*
|
||||
*/
|
||||
int UpdateIn(Message &aMessage) const {
|
||||
return aMessage.Write(aMessage.GetLength() - sizeof(*this), sizeof(*this), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) const { return (static_cast<int32_t>(aTime - mTransmissionTime) > 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) const { return (static_cast<int32_t>(aTime - mTransmissionTime) < 0); };
|
||||
|
||||
/**
|
||||
* This method returns the MPL Seed Id value.
|
||||
*
|
||||
* @returns The MPL Seed Id value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSeedId() const { return mSeedId; }
|
||||
|
||||
/**
|
||||
* This method sets the MPL Seed Id value.
|
||||
*
|
||||
* @param[in] aSeedId The MPL Seed Id value.
|
||||
*
|
||||
*/
|
||||
void SetSeedId(uint16_t aSeedId) { mSeedId = aSeedId; }
|
||||
|
||||
/**
|
||||
* This method returns the MPL Sequence value.
|
||||
*
|
||||
* @returns The MPL Sequence value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetSequence() const { return mSequence; }
|
||||
|
||||
/**
|
||||
* This method sets the MPL Sequence value.
|
||||
*
|
||||
* @param[in] aSequence The MPL Sequence value.
|
||||
*
|
||||
*/
|
||||
void SetSequence(uint8_t aSequence) { mSequence = aSequence; }
|
||||
|
||||
/**
|
||||
* This method returns the number of already preformed transmissions.
|
||||
*
|
||||
* @returns The number of already preformed transmissions.
|
||||
*
|
||||
*/
|
||||
uint8_t GetTransmissionCount() const { return mTransmissionCount; }
|
||||
|
||||
/**
|
||||
* This method sets the number of already performed transmissions.
|
||||
*
|
||||
* @param[in] aTransmissionCount The number of already performed transmissions.
|
||||
*
|
||||
*/
|
||||
void SetTransmissionCount(uint8_t aTransmissionCount) { mTransmissionCount = aTransmissionCount; }
|
||||
|
||||
/**
|
||||
* This method returns the transmission timestamp of the message.
|
||||
*
|
||||
* @returns The transmission timestamp of the message.
|
||||
*
|
||||
*/
|
||||
uint32_t GetTransmissionTime() const { return mTransmissionTime; }
|
||||
|
||||
/**
|
||||
* This method sets the transmission timestamp of the message.
|
||||
*
|
||||
* @param[in] aTransmissionTime The transmission timestamp of the message.
|
||||
*
|
||||
*/
|
||||
void SetTransmissionTime(uint32_t aTransmissionTime) { mTransmissionTime = aTransmissionTime; }
|
||||
|
||||
/**
|
||||
* This method returns the offset from the transmission time to the end of trickle interval.
|
||||
*
|
||||
* @returns The offset from the the transmission time to the end of trickle interval.
|
||||
*
|
||||
*/
|
||||
uint32_t GetIntervalOffset() const { return mIntervalOffset; }
|
||||
|
||||
/**
|
||||
* This method sets the offset from the transmission time to the end of trickle interval.
|
||||
*
|
||||
* @param[in] aIntervalOffset The offset from the the transmission time to the end of trickle interval.
|
||||
*
|
||||
*/
|
||||
void SetIntervalOffset(uint8_t aIntervalOffset) { mIntervalOffset = aIntervalOffset; }
|
||||
|
||||
/**
|
||||
* This method generates the next transmission time for the MPL Data Message.
|
||||
*
|
||||
* @param[in] aCurrentTime Current time (in milliseconds).
|
||||
* @param[in] aInterval The current interval size (in milliseconds).
|
||||
*/
|
||||
void GenerateNextTransmissionTime(uint32_t aCurrentTime, uint8_t aInterval);
|
||||
|
||||
private:
|
||||
uint16_t mSeedId;
|
||||
uint8_t mSequence;
|
||||
uint8_t mTransmissionCount;
|
||||
uint32_t mTransmissionTime;
|
||||
uint8_t mIntervalOffset;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
@@ -199,65 +447,97 @@ public:
|
||||
void InitOption(OptionMpl &aOption, const Address &aAddress);
|
||||
|
||||
/**
|
||||
* This method processes an MPL option.
|
||||
* This method processes an MPL option. When the MPL module acts as an MPL Forwarder
|
||||
* it disseminates MPL Data Message using Trickle timer expirations. When acts as an
|
||||
* MPL Seed it allows to send the first MPL Data Message directly, then sets up Trickle
|
||||
* timer expirations for subsequent retransmissions.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aAddress A reference to the IPv6 Source Address.
|
||||
* @param[out] aForward TRUE if this message should be forwarded, FALSE otherwise.
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aAddress A reference to the IPv6 Source Address.
|
||||
* @param[in] aIsOutbound TRUE if this message was locally generated, FALSE otherwise.
|
||||
*
|
||||
* @retval kThreadError_None Successfully processed the MPL option.
|
||||
* @retval kThreadError_Drop The MPL message is a duplicate and should be dropped.
|
||||
*
|
||||
*/
|
||||
ThreadError ProcessOption(const Message &aMessage, const Address &aAddress, bool &aForward);
|
||||
ThreadError ProcessOption(Message &aMessage, const Address &aAddress, bool aIsOutbound);
|
||||
|
||||
/**
|
||||
* This method returns the MPL Seed value.
|
||||
* This method returns the MPL Seed Id value.
|
||||
*
|
||||
* @returns The MPL Seed value.
|
||||
* @returns The MPL Seed Id value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetSeed() const { return mSeed; }
|
||||
uint16_t GetSeedId() const { return mSeedId; }
|
||||
|
||||
/**
|
||||
* This method sets the MPL Seed value.
|
||||
* This method sets the MPL Seed Id value.
|
||||
*
|
||||
* @param[in] aSeedId The MPL Seed Id value.
|
||||
*
|
||||
* @param[in] aSeed The MPL Seed value.
|
||||
*/
|
||||
void SetSeed(uint16_t aSeed) { mSeed = aSeed; }
|
||||
void SetSeedId(uint16_t aSeedId) { mSeedId = aSeedId; }
|
||||
|
||||
/**
|
||||
* This method sets IPv6 matching address, that allows to elide seed-id.
|
||||
* This method gets the MPL number of Trickle timer expirations that occur before
|
||||
* terminating the Trickle algorithm's retransmission of a given MPL Data Message.
|
||||
*
|
||||
* @returns The MPL number of Trickle timer expirations.
|
||||
*
|
||||
*/
|
||||
uint8_t GetTimerExpirations() const { return mTimerExpirations; }
|
||||
|
||||
/**
|
||||
* This method sets the MPL number of Trickle timer expirations that occur before
|
||||
* terminating the Trickle algorithm's retransmission of a given MPL Data Message.
|
||||
*
|
||||
* @param[in] aTimerExpirations The number of Trickle timer expirations.
|
||||
*
|
||||
*/
|
||||
void SetTimerExpirations(uint8_t aTimerExpirations) { mTimerExpirations = aTimerExpirations; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 matching address, that allows to elide MPL Seed Id.
|
||||
*
|
||||
* @param[in] aAddress The reference to the IPv6 matching address.
|
||||
*
|
||||
* @param[in] aAddress The reference to IPv6 matching address.
|
||||
*/
|
||||
void SetMatchingAddress(const Address &aAddress) { mMatchingAddress = &aAddress; }
|
||||
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kNumEntries = OPENTHREAD_CONFIG_MPL_CACHE_ENTRIES,
|
||||
kLifetime = OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME,
|
||||
kNumSeedEntries = OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRIES,
|
||||
kSeedEntryLifetime = OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRY_LIFETIME,
|
||||
kSeedEntryLifetimeDt = 1000,
|
||||
kDataMessageInterval = 64
|
||||
};
|
||||
|
||||
static void HandleTimer(void *context);
|
||||
void HandleTimer();
|
||||
ThreadError UpdateSeedSet(uint16_t aSeedId, uint8_t aSequence);
|
||||
void UpdateBufferedSet(uint16_t aSeedId, uint8_t aSequence);
|
||||
void AddBufferedMessage(Message &aMessage, uint16_t aSeedId, uint8_t aSequence, bool aIsOutbound);
|
||||
|
||||
Timer mTimer;
|
||||
static void HandleSeedSetTimer(void *aContext);
|
||||
void HandleSeedSetTimer();
|
||||
|
||||
static void HandleRetransmissionTimer(void *aContext);
|
||||
void HandleRetransmissionTimer();
|
||||
|
||||
Ip6 &mIp6;
|
||||
|
||||
Timer mSeedSetTimer;
|
||||
Timer mRetransmissionTimer;
|
||||
|
||||
uint8_t mTimerExpirations;
|
||||
uint8_t mSequence;
|
||||
uint16_t mSeed;
|
||||
uint16_t mSeedId;
|
||||
const Address *mMatchingAddress;
|
||||
|
||||
struct MplEntry
|
||||
{
|
||||
uint16_t mSeed;
|
||||
uint8_t mSequence;
|
||||
uint8_t mLifetime;
|
||||
};
|
||||
MplEntry mEntries[kNumEntries];
|
||||
MplSeedEntry mSeedSet[kNumSeedEntries];
|
||||
MessageQueue mBufferedMessageSet;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -136,24 +136,24 @@
|
||||
#endif // OPENTHREAD_CONFIG_6LOWPAN_REASSEMBLY_TIMEOUT
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MPL_CACHE_ENTRIES
|
||||
* @def OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRIES
|
||||
*
|
||||
* The number of MPL cache entries for duplicate detection.
|
||||
* The number of MPL Seed Set entries for duplicate detection.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MPL_CACHE_ENTRIES
|
||||
#define OPENTHREAD_CONFIG_MPL_CACHE_ENTRIES 32
|
||||
#endif // OPENTHREAD_CONFIG_MPL_CACHE_ENTRIES
|
||||
#ifndef OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRIES
|
||||
#define OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRIES 32
|
||||
#endif // OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRIES
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME
|
||||
* @def OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRY_LIFETIME
|
||||
*
|
||||
* The MPL cache entry lifetime in seconds.
|
||||
* The MPL Seed Set entry lifetime in seconds.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME
|
||||
#define OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME 5
|
||||
#endif // OPENTHREAD_CONFIG_MPL_CACHE_ENTRY_LIFETIME
|
||||
#ifndef OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRY_LIFETIME
|
||||
#define OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRY_LIFETIME 5
|
||||
#endif // OPENTHREAD_CONFIG_MPL_SEED_SET_ENTRY_LIFETIME
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_JOINER_UDP_PORT
|
||||
@@ -360,4 +360,3 @@
|
||||
#endif // OPENTHREAD_CONFIG_SETTINGS_PAGE_NUM
|
||||
|
||||
#endif // OPENTHREAD_CORE_DEFAULT_CONFIG_H_
|
||||
|
||||
|
||||
@@ -390,6 +390,7 @@ ThreadError Mle::SetStateDetached(void)
|
||||
mMesh.SetRxOnWhenIdle(true);
|
||||
mMleRouter.HandleDetachStart();
|
||||
mNetif.GetIp6().SetForwardingEnabled(false);
|
||||
mNetif.GetIp6().mMpl.SetTimerExpirations(0);
|
||||
|
||||
otLogInfoMle("Mode -> Detached");
|
||||
return kThreadError_None;
|
||||
@@ -423,6 +424,7 @@ ThreadError Mle::SetStateChild(uint16_t aRloc16)
|
||||
|
||||
mNetif.GetNetworkDataLocal().ClearResubmitDelayTimer();
|
||||
mNetif.GetIp6().SetForwardingEnabled(false);
|
||||
mNetif.GetIp6().mMpl.SetTimerExpirations(kMplChildDataMessageTimerExpirations);
|
||||
|
||||
if (mPreviousPanId != Mac::kPanIdBroadcast && (mDeviceMode & ModeTlv::kModeFFD))
|
||||
{
|
||||
@@ -589,7 +591,7 @@ ThreadError Mle::SetRloc16(uint16_t aRloc16)
|
||||
}
|
||||
|
||||
mMac.SetShortAddress(aRloc16);
|
||||
mNetif.GetIp6().mMpl.SetSeed(aRloc16);
|
||||
mNetif.GetIp6().mMpl.SetSeedId(aRloc16);
|
||||
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
@@ -118,6 +118,16 @@ enum
|
||||
kMinAssignedLinkMargin0 = 0x00, ///< minimal link margin for LQI 0 (0 - 2)
|
||||
};
|
||||
|
||||
/**
|
||||
* Multicast Forwarding Constants
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kMplChildDataMessageTimerExpirations = 0, ///< Number of MPL retransmissions for Children.
|
||||
kMplRouterDataMessageTimerExpirations = 2, ///< Number of MPL retransmissions for Routers.
|
||||
};
|
||||
|
||||
} // namespace Mle
|
||||
|
||||
/**
|
||||
|
||||
@@ -359,6 +359,7 @@ ThreadError MleRouter::SetStateRouter(uint16_t aRloc16)
|
||||
mNetworkData.Stop();
|
||||
mStateUpdateTimer.Start(kStateUpdatePeriod);
|
||||
mNetif.GetIp6().SetForwardingEnabled(true);
|
||||
mNetif.GetIp6().mMpl.SetTimerExpirations(kMplRouterDataMessageTimerExpirations);
|
||||
|
||||
otLogInfoMle("Mode -> Router");
|
||||
return kThreadError_None;
|
||||
@@ -386,6 +387,7 @@ ThreadError MleRouter::SetStateLeader(uint16_t aRloc16)
|
||||
mCoapServer.AddResource(mAddressSolicit);
|
||||
mCoapServer.AddResource(mAddressRelease);
|
||||
mNetif.GetIp6().SetForwardingEnabled(true);
|
||||
mNetif.GetIp6().mMpl.SetTimerExpirations(kMplRouterDataMessageTimerExpirations);
|
||||
|
||||
otLogInfoMle("Mode -> Leader %d", mLeaderData.GetPartitionId());
|
||||
return kThreadError_None;
|
||||
|
||||
Reference in New Issue
Block a user