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:
Łukasz Duda
2016-10-24 20:34:15 +02:00
committed by Jonathan Hui
parent ad39a59ff9
commit 78d4b678e3
10 changed files with 635 additions and 110 deletions
+3 -3
View File
@@ -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());
+12 -2
View File
@@ -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.
+9 -3
View File
@@ -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
+9 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
};
/**
* @}
*
+10 -11
View File
@@ -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_
+3 -1
View File
@@ -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;
}
+10
View File
@@ -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
/**
+2
View File
@@ -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;