diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj
index 725d0d277..6c705b71a 100644
--- a/etc/visual-studio/libopenthread.vcxproj
+++ b/etc/visual-studio/libopenthread.vcxproj
@@ -129,6 +129,8 @@
+
+
diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters
index 0d2db8dbd..d11a2c08f 100644
--- a/etc/visual-studio/libopenthread.vcxproj.filters
+++ b/etc/visual-studio/libopenthread.vcxproj.filters
@@ -219,6 +219,12 @@
Source Files\thread
+
+ Source Files\thread
+
+
+ Source Files\thread
+
Source Files\thread
diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj
index d8cb5e0cd..633ab275a 100644
--- a/etc/visual-studio/libopenthread_k.vcxproj
+++ b/etc/visual-studio/libopenthread_k.vcxproj
@@ -137,6 +137,8 @@
+
+
diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters
index fa03ea8d8..9a8231810 100644
--- a/etc/visual-studio/libopenthread_k.vcxproj.filters
+++ b/etc/visual-studio/libopenthread_k.vcxproj.filters
@@ -219,6 +219,12 @@
Source Files\thread
+
+ Source Files\thread
+
+
+ Source Files\thread
+
Source Files\thread
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 1c1ef2e8a..6311521f0 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -171,6 +171,8 @@ SOURCES_COMMON = \
thread/link_quality.cpp \
thread/lowpan.cpp \
thread/mesh_forwarder.cpp \
+ thread/mesh_forwarder_ftd.cpp \
+ thread/mesh_forwarder_mtd.cpp \
thread/mle.cpp \
thread/mle_router.cpp \
thread/network_data.cpp \
diff --git a/src/core/api/message_api.cpp b/src/core/api/message_api.cpp
index 258546a1d..c4acfa5e2 100644
--- a/src/core/api/message_api.cpp
+++ b/src/core/api/message_api.cpp
@@ -177,8 +177,13 @@ void otMessageGetBufferInfo(otInstance *aInstance, otBufferInfo *aBufferInfo)
instance.GetThreadNetif().GetMeshForwarder().GetReassemblyQueue().GetInfo(aBufferInfo->m6loReassemblyMessages,
aBufferInfo->m6loReassemblyBuffers);
+#if OPENTHREAD_FTD
instance.GetThreadNetif().GetMeshForwarder().GetResolvingQueue().GetInfo(aBufferInfo->mArpMessages,
aBufferInfo->mArpBuffers);
+#else
+ aBufferInfo->mArpMessages = 0;
+ aBufferInfo->mArpBuffers = 0;
+#endif
instance.GetThreadNetif().GetIp6().GetSendQueue().GetInfo(aBufferInfo->mIp6Messages,
aBufferInfo->mIp6Buffers);
diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp
index db0df4f0e..e95f38fbd 100644
--- a/src/core/thread/mesh_forwarder.cpp
+++ b/src/core/thread/mesh_forwarder.cpp
@@ -64,13 +64,9 @@ MeshForwarder::MeshForwarder(Instance &aInstance):
mDiscoverTimer(aInstance, &MeshForwarder::HandleDiscoverTimer, this),
mReassemblyTimer(aInstance, &MeshForwarder::HandleReassemblyTimer, this),
mMessageNextOffset(0),
- mSendMessageFrameCounter(0),
mSendMessage(NULL),
mSendMessageIsARetransmission(false),
mSendMessageMaxMacTxAttempts(Mac::kDirectFrameMacTxAttempts),
- mSendMessageKeyId(0),
- mSendMessageDataSequenceNumber(0),
- mStartChildIndex(0),
mMeshSource(Mac::kShortAddrInvalid),
mMeshDest(Mac::kShortAddrInvalid),
mAddMeshHeader(false),
@@ -82,8 +78,14 @@ MeshForwarder::MeshForwarder(Instance &aInstance):
mRestoreChannel(0),
mRestorePanId(Mac::kPanIdBroadcast),
mScanning(false),
- mDataPollManager(aInstance),
- mSourceMatchController(aInstance)
+#if OPENTHREAD_FTD
+ mSourceMatchController(aInstance),
+ mSendMessageFrameCounter(0),
+ mSendMessageKeyId(0),
+ mSendMessageDataSequenceNumber(0),
+ mStartChildIndex(0),
+#endif
+ mDataPollManager(aInstance)
{
mFragTag = static_cast(otPlatRandomGet());
GetNetif().GetMac().RegisterReceiver(mMacReceiver);
@@ -147,135 +149,6 @@ exit:
return error;
}
-void MeshForwarder::HandleResolved(const Ip6::Address &aEid, otError aError)
-{
- Message *cur, *next;
- Ip6::Address ip6Dst;
- bool enqueuedMessage = false;
-
- for (cur = mResolvingQueue.GetHead(); cur; cur = next)
- {
- next = cur->GetNext();
-
- if (cur->GetType() != Message::kTypeIp6)
- {
- continue;
- }
-
- cur->Read(Ip6::Header::GetDestinationOffset(), sizeof(ip6Dst), &ip6Dst);
-
- if (ip6Dst == aEid)
- {
- mResolvingQueue.Dequeue(*cur);
-
- if (aError == OT_ERROR_NONE)
- {
- mSendQueue.Enqueue(*cur);
- enqueuedMessage = true;
- }
- else
- {
- LogIp6Message(kMessageDrop, *cur, NULL, aError);
- cur->Free();
- }
- }
- }
-
- if (enqueuedMessage)
- {
- mScheduleTransmissionTask.Post();
- }
-}
-
-void MeshForwarder::ClearChildIndirectMessages(Child &aChild)
-{
- Message *nextMessage;
-
- VerifyOrExit(aChild.GetIndirectMessageCount() > 0);
-
- for (Message *message = mSendQueue.GetHead(); message; message = nextMessage)
- {
- nextMessage = message->GetNext();
-
- message->ClearChildMask(GetNetif().GetMle().GetChildIndex(aChild));
-
- if (!message->IsChildPending() && !message->GetDirectTransmission())
- {
- if (mSendMessage == message)
- {
- mSendMessage = NULL;
- }
-
- mSendQueue.Dequeue(*message);
- message->Free();
- }
- }
-
- aChild.SetIndirectMessage(NULL);
- mSourceMatchController.ResetMessageCount(aChild);
-
-exit:
- return;
-}
-
-void MeshForwarder::UpdateIndirectMessages(void)
-{
- Child *children;
- uint8_t numChildren;
-
- children = GetNetif().GetMle().GetChildren(&numChildren);
-
- for (uint8_t i = 0; i < numChildren; i++)
- {
- Child *child = &children[i];
-
- if (child->IsStateValidOrRestoring() || (child->GetIndirectMessageCount() == 0))
- {
- continue;
- }
-
- ClearChildIndirectMessages(*child);
- }
-}
-
-otError MeshForwarder::EvictIndirectMessage(void)
-{
- otError error = OT_ERROR_NOT_FOUND;
-
- for (Message *message = mSendQueue.GetHead(); message; message = message->GetNext())
- {
- if (!message->IsChildPending())
- {
- continue;
- }
-
- RemoveMessage(*message);
- ExitNow(error = OT_ERROR_NONE);
- }
-
-exit:
- return error;
-}
-
-otError MeshForwarder::RemoveMessageFromSleepyChild(Message &aMessage, Child &aChild)
-{
- otError error = OT_ERROR_NONE;
- uint8_t childIndex = GetNetif().GetMle().GetChildIndex(aChild);
-
- VerifyOrExit(aMessage.GetChildMask(childIndex) == true, error = OT_ERROR_NOT_FOUND);
-
- aMessage.ClearChildMask(childIndex);
- mSourceMatchController.DecrementMessageCount(aChild);
-
- if (aChild.GetIndirectMessage() == &aMessage)
- {
- aChild.SetIndirectMessage(NULL);
- }
-
-exit:
- return error;
-}
-
void MeshForwarder::RemoveMessage(Message &aMessage)
{
Child *children;
@@ -298,70 +171,6 @@ void MeshForwarder::RemoveMessage(Message &aMessage)
aMessage.Free();
}
-void MeshForwarder::RemoveMessages(Child &aChild, uint8_t aSubType)
-{
- ThreadNetif &netif = GetNetif();
- Message *nextMessage;
-
- for (Message *message = mSendQueue.GetHead(); message; message = nextMessage)
- {
- nextMessage = message->GetNext();
-
- if ((aSubType != Message::kSubTypeNone) && (aSubType != message->GetSubType()))
- {
- continue;
- }
-
- if (RemoveMessageFromSleepyChild(*message, aChild) != OT_ERROR_NONE)
- {
- switch (message->GetType())
- {
- case Message::kTypeIp6:
- {
- Ip6::Header ip6header;
-
- IgnoreReturnValue(message->Read(0, sizeof(ip6header), &ip6header));
-
- if (&aChild == static_cast(netif.GetMle().GetNeighbor(ip6header.GetDestination())))
- {
- message->ClearDirectTransmission();
- }
-
- break;
- }
-
- case Message::kType6lowpan:
- {
- Lowpan::MeshHeader meshHeader;
-
- IgnoreReturnValue(meshHeader.Init(*message));
-
- if (&aChild == static_cast(netif.GetMle().GetNeighbor(meshHeader.GetDestination())))
- {
- message->ClearDirectTransmission();
- }
-
- break;
- }
-
- default:
- break;
- }
- }
-
- if (!message->IsChildPending() && !message->GetDirectTransmission())
- {
- if (mSendMessage == message)
- {
- mSendMessage = NULL;
- }
-
- mSendQueue.Dequeue(*message);
- message->Free();
- }
- }
-}
-
void MeshForwarder::ScheduleTransmissionTask(Tasklet &aTasklet)
{
aTasklet.GetOwner().ScheduleTransmissionTask();
@@ -369,83 +178,19 @@ void MeshForwarder::ScheduleTransmissionTask(Tasklet &aTasklet)
void MeshForwarder::ScheduleTransmissionTask(void)
{
- ThreadNetif &netif = GetNetif();
- uint8_t numChildren;
- uint8_t childIndex;
- uint8_t nextIndex;
- Child *children;
-
VerifyOrExit(mSendBusy == false);
- UpdateIndirectMessages();
-
mSendMessageIsARetransmission = false;
- children = netif.GetMle().GetChildren(&numChildren);
-
- if (mStartChildIndex >= numChildren)
+ if (GetIndirectTransmission() == OT_ERROR_NONE)
{
- mStartChildIndex = 0;
- }
-
- childIndex = mStartChildIndex;
-
- for (uint8_t iterations = numChildren; iterations > 0; iterations--, childIndex = nextIndex)
- {
- Child &child = children[childIndex];
-
- if ((nextIndex = childIndex + 1) == numChildren)
- {
- nextIndex = 0;
- }
-
- if (!child.IsStateValidOrRestoring() || !child.IsDataRequestPending())
- {
- continue;
- }
-
- mSendMessage = child.GetIndirectMessage();
- mSendMessageMaxMacTxAttempts = Mac::kIndirectFrameMacTxAttempts;
-
- if (mSendMessage == NULL)
- {
- mSendMessage = GetIndirectTransmission(child);
- }
-
- if (mSendMessage != NULL)
- {
- PrepareIndirectTransmission(*mSendMessage, child);
- }
- else
- {
- // A NULL `mSendMessage` triggers an empty frame to be sent to the child.
-
- if (child.IsIndirectSourceMatchShort())
- {
- mMacSource.mLength = sizeof(mMacSource.mShortAddress);
- mMacSource.mShortAddress = netif.GetMac().GetShortAddress();
- }
- else
- {
- mMacSource.mLength = sizeof(mMacSource.mExtAddress);
- mMacSource.mExtAddress = netif.GetMac().GetExtAddress();
- }
-
- child.GetMacAddress(mMacDest);
- }
-
- // Record current child index, and move it to next index after this indirect transmission has completed.
-
- mStartChildIndex = childIndex;
-
- netif.GetMac().SendFrameRequest(mMacSender);
ExitNow();
}
if ((mSendMessage = GetDirectTransmission()) != NULL)
{
mSendMessageMaxMacTxAttempts = Mac::kDirectFrameMacTxAttempts;
- netif.GetMac().SendFrameRequest(mMacSender);
+ GetNetif().GetMac().SendFrameRequest(mMacSender);
ExitNow();
}
@@ -453,108 +198,6 @@ exit:
return;
}
-otError MeshForwarder::SendMessage(Message &aMessage)
-{
- ThreadNetif &netif = GetNetif();
- otError error = OT_ERROR_NONE;
- Neighbor *neighbor;
-
- uint8_t numChildren;
- Child *child;
-
- switch (aMessage.GetType())
- {
- case Message::kTypeIp6:
- {
- Ip6::Header ip6Header;
-
- aMessage.Read(0, sizeof(ip6Header), &ip6Header);
-
- if (ip6Header.GetDestination() == netif.GetMle().GetLinkLocalAllThreadNodesAddress() ||
- ip6Header.GetDestination() == netif.GetMle().GetRealmLocalAllThreadNodesAddress())
- {
- // schedule direct transmission
- aMessage.SetDirectTransmission();
-
- if (aMessage.GetSubType() != Message::kSubTypeMplRetransmission)
- {
- // destined for all sleepy children
- child = netif.GetMle().GetChildren(&numChildren);
-
- for (uint8_t i = 0; i < numChildren; i++, child++)
- {
- if (child->IsStateValidOrRestoring() && !child->IsRxOnWhenIdle())
- {
- aMessage.SetChildMask(i);
- mSourceMatchController.IncrementMessageCount(*child);
- }
- }
- }
- }
- else if ((neighbor = netif.GetMle().GetNeighbor(ip6Header.GetDestination())) != NULL &&
- !neighbor->IsRxOnWhenIdle() &&
- !aMessage.GetDirectTransmission())
- {
- // destined for a sleepy child
- child = static_cast(neighbor);
- aMessage.SetChildMask(netif.GetMle().GetChildIndex(*child));
- mSourceMatchController.IncrementMessageCount(*child);
- }
- else
- {
- // schedule direct transmission
- aMessage.SetDirectTransmission();
- }
-
- break;
- }
-
- case Message::kType6lowpan:
- {
- Lowpan::MeshHeader meshHeader;
-
- IgnoreReturnValue(meshHeader.Init(aMessage));
-
- if ((neighbor = netif.GetMle().GetNeighbor(meshHeader.GetDestination())) != NULL &&
- !neighbor->IsRxOnWhenIdle())
- {
- // destined for a sleepy child
- child = static_cast(neighbor);
- aMessage.SetChildMask(netif.GetMle().GetChildIndex(*child));
- mSourceMatchController.IncrementMessageCount(*child);
- }
- else
- {
- // not destined for a sleepy child
- aMessage.SetDirectTransmission();
- }
-
- break;
- }
-
- case Message::kTypeMacDataPoll:
- aMessage.SetDirectTransmission();
- break;
-
- case Message::kTypeSupervision:
- child = netif.GetChildSupervisor().GetDestination(aMessage);
- VerifyOrExit(child != NULL, error = OT_ERROR_DROP);
- VerifyOrExit(!child->IsRxOnWhenIdle(), error = OT_ERROR_DROP);
-
- aMessage.SetChildMask(netif.GetMle().GetChildIndex(*child));
- mSourceMatchController.IncrementMessageCount(*child);
- break;
- }
-
- aMessage.SetOffset(0);
- aMessage.SetDatagramTag(0);
- SuccessOrExit(error = mSendQueue.Enqueue(aMessage));
- mScheduleTransmissionTask.Post();
-
-exit:
- return error;
-}
-
otError MeshForwarder::PrepareDiscoverRequest(void)
{
ThreadNetif &netif = GetNetif();
@@ -611,15 +254,19 @@ Message *MeshForwarder::GetDirectTransmission(void)
break;
- case Message::kType6lowpan:
- error = UpdateMeshRoute(*curMessage);
- break;
-
case Message::kTypeMacDataPoll:
error = PrepareDataPoll();
break;
- case Message::kTypeSupervision:
+#if OPENTHREAD_FTD
+
+ case Message::kType6lowpan:
+ error = UpdateMeshRoute(*curMessage);
+ break;
+
+#endif
+
+ default:
error = OT_ERROR_DROP;
break;
}
@@ -629,11 +276,15 @@ Message *MeshForwarder::GetDirectTransmission(void)
case OT_ERROR_NONE:
ExitNow();
+#if OPENTHREAD_FTD
+
case OT_ERROR_ADDRESS_QUERY:
mSendQueue.Dequeue(*curMessage);
mResolvingQueue.Enqueue(*curMessage);
continue;
+#endif
+
case OT_ERROR_DROP:
case OT_ERROR_NO_BUFS:
mSendQueue.Dequeue(*curMessage);
@@ -651,107 +302,6 @@ exit:
return curMessage;
}
-Message *MeshForwarder::GetIndirectTransmission(Child &aChild)
-{
- Message *message = NULL;
- Message *next;
- uint8_t childIndex = GetNetif().GetMle().GetChildIndex(aChild);
-
- for (message = mSendQueue.GetHead(); message; message = next)
- {
- next = message->GetNext();
-
- if (message->GetChildMask(childIndex))
- {
- // Skip and remove the supervision message if there are other messages queued for the child.
-
- if ((message->GetType() == Message::kTypeSupervision) && (aChild.GetIndirectMessageCount() > 1))
- {
- message->ClearChildMask(childIndex);
- mSourceMatchController.DecrementMessageCount(aChild);
- mSendQueue.Dequeue(*message);
- message->Free();
- continue;
- }
-
- break;
- }
- }
-
- aChild.SetIndirectMessage(message);
- aChild.SetIndirectFragmentOffset(0);
- aChild.ResetIndirectTxAttempts();
-
- if (message != NULL)
- {
- Mac::Address macAddr;
-
- LogIp6Message(kMessagePrepareIndirect, *message, &aChild.GetMacAddress(macAddr), OT_ERROR_NONE);
- }
-
- return message;
-}
-
-void MeshForwarder::PrepareIndirectTransmission(Message &aMessage, const Child &aChild)
-{
- if (aChild.GetIndirectTxAttempts() > 0)
- {
- mSendMessageIsARetransmission = true;
- mSendMessageFrameCounter = aChild.GetIndirectFrameCounter();
- mSendMessageKeyId = aChild.GetIndirectKeyId();
- mSendMessageDataSequenceNumber = aChild.GetIndirectDataSequenceNumber();
- }
-
- aMessage.SetOffset(aChild.GetIndirectFragmentOffset());
-
- switch (aMessage.GetType())
- {
- case Message::kTypeIp6:
- {
- Ip6::Header ip6Header;
-
- aMessage.Read(0, sizeof(ip6Header), &ip6Header);
-
- mAddMeshHeader = false;
- GetMacSourceAddress(ip6Header.GetSource(), mMacSource);
-
- if (ip6Header.GetDestination().IsLinkLocal())
- {
- GetMacDestinationAddress(ip6Header.GetDestination(), mMacDest);
- }
- else
- {
- aChild.GetMacAddress(mMacDest);
- }
-
- break;
- }
-
- case Message::kType6lowpan:
- {
- Lowpan::MeshHeader meshHeader;
-
- IgnoreReturnValue(meshHeader.Init(aMessage));
- mAddMeshHeader = true;
- mMeshDest = meshHeader.GetDestination();
- mMeshSource = meshHeader.GetSource();
- mMacSource.mLength = sizeof(mMacSource.mShortAddress);
- mMacSource.mShortAddress = GetNetif().GetMac().GetShortAddress();
- mMacDest.mLength = sizeof(mMacDest.mShortAddress);
- mMacDest.mShortAddress = meshHeader.GetDestination();
- break;
- }
-
- case Message::kTypeSupervision:
- aChild.GetMacAddress(mMacDest);
- break;
-
- default:
- assert(false);
- break;
- }
-}
-
otError MeshForwarder::PrepareDataPoll(void)
{
otError error = OT_ERROR_NONE;
@@ -782,45 +332,6 @@ exit:
return error;
}
-otError MeshForwarder::UpdateMeshRoute(Message &aMessage)
-{
- ThreadNetif &netif = GetNetif();
- otError error = OT_ERROR_NONE;
- Lowpan::MeshHeader meshHeader;
- Neighbor *neighbor;
- uint16_t nextHop;
-
- IgnoreReturnValue(meshHeader.Init(aMessage));
-
- nextHop = netif.GetMle().GetNextHop(meshHeader.GetDestination());
-
- if (nextHop != Mac::kShortAddrInvalid)
- {
- neighbor = netif.GetMle().GetNeighbor(nextHop);
- }
- else
- {
- neighbor = netif.GetMle().GetNeighbor(meshHeader.GetDestination());
- }
-
- if (neighbor == NULL)
- {
- ExitNow(error = OT_ERROR_DROP);
- }
-
- mMacDest.mLength = sizeof(mMacDest.mShortAddress);
- mMacDest.mShortAddress = neighbor->GetRloc16();
- mMacSource.mLength = sizeof(mMacSource.mShortAddress);
- mMacSource.mShortAddress = netif.GetMac().GetShortAddress();
-
- mAddMeshHeader = true;
- mMeshDest = meshHeader.GetDestination();
- mMeshSource = meshHeader.GetSource();
-
-exit:
- return error;
-}
-
otError MeshForwarder::UpdateIp6Route(Message &aMessage)
{
ThreadNetif &netif = GetNetif();
@@ -877,176 +388,18 @@ otError MeshForwarder::UpdateIp6Route(Message &aMessage)
mMacDest.mLength = sizeof(mMacDest.mShortAddress);
mMacDest.mShortAddress = netif.GetMle().GetNextHop(Mac::kShortAddrBroadcast);
}
-
+ else
+ {
#if OPENTHREAD_FTD
- else
- {
- Neighbor *neighbor;
-
- if (netif.GetMle().IsRoutingLocator(ip6Header.GetDestination()))
- {
- uint16_t rloc16 = HostSwap16(ip6Header.GetDestination().mFields.m16[7]);
- VerifyOrExit(netif.GetMle().IsRouterIdValid(netif.GetMle().GetRouterId(rloc16)),
- error = OT_ERROR_DROP);
- mMeshDest = rloc16;
- }
- else if (netif.GetMle().IsAnycastLocator(ip6Header.GetDestination()))
- {
- uint16_t aloc16 = HostSwap16(ip6Header.GetDestination().mFields.m16[7]);
-
- if (aloc16 == Mle::kAloc16Leader)
- {
- mMeshDest = netif.GetMle().GetRloc16(netif.GetMle().GetLeaderId());
- }
-
-#if OPENTHREAD_ENABLE_DHCP6_SERVER || OPENTHREAD_ENABLE_DHCP6_CLIENT
- else if (aloc16 <= Mle::kAloc16DhcpAgentEnd)
- {
- uint16_t agentRloc16;
- uint8_t routerId;
- VerifyOrExit((netif.GetNetworkDataLeader().GetRlocByContextId(
- static_cast(aloc16 & Mle::kAloc16DhcpAgentMask),
- agentRloc16) == OT_ERROR_NONE),
- error = OT_ERROR_DROP);
-
- routerId = netif.GetMle().GetRouterId(agentRloc16);
-
- // if agent is active router or the child of the device
- if ((netif.GetMle().IsActiveRouter(agentRloc16)) ||
- (netif.GetMle().GetRloc16(routerId) == netif.GetMle().GetRloc16()))
- {
- mMeshDest = agentRloc16;
- }
- else
- {
- // use the parent of the ED Agent as Dest
- mMeshDest = netif.GetMle().GetRloc16(routerId);
- }
- }
-
-#endif // OPENTHREAD_ENABLE_DHCP6_SERVER || OPENTHREAD_ENABLE_DHCP6_CLIENT
-#if OPENTHREAD_ENABLE_SERVICE
- else if ((aloc16 >= Mle::kAloc16ServiceStart) && (aloc16 <= Mle::kAloc16ServiceEnd))
- {
- SuccessOrExit(error = GetDestinationRlocByServiceAloc(aloc16, mMeshDest));
- }
-
-#endif
- else
- {
- // TODO: support ALOC for Commissioner, Neighbor Discovery Agent
- ExitNow(error = OT_ERROR_DROP);
- }
- }
- else if ((neighbor = netif.GetMle().GetNeighbor(ip6Header.GetDestination())) != NULL)
- {
- mMeshDest = neighbor->GetRloc16();
- }
- else if (netif.GetNetworkDataLeader().IsOnMesh(ip6Header.GetDestination()))
- {
- SuccessOrExit(error = netif.GetAddressResolver().Resolve(ip6Header.GetDestination(), mMeshDest));
- }
- else
- {
- netif.GetNetworkDataLeader().RouteLookup(
- ip6Header.GetSource(),
- ip6Header.GetDestination(),
- NULL,
- &mMeshDest
- );
- }
-
- VerifyOrExit(mMeshDest != Mac::kShortAddrInvalid, error = OT_ERROR_DROP);
-
- mMeshSource = netif.GetMac().GetShortAddress();
- mMacDest.mLength = sizeof(mMacDest.mShortAddress);
-
- SuccessOrExit(error = netif.GetMle().CheckReachability(mMeshSource, mMeshDest, ip6Header));
- mMacDest.mShortAddress = netif.GetMle().GetNextHop(mMeshDest);
-
- if (mMacDest.mShortAddress != mMeshDest)
- {
- // destination is not neighbor
- mMacSource.mLength = sizeof(mMacSource.mShortAddress);
- mMacSource.mShortAddress = mMeshSource;
- mAddMeshHeader = true;
- }
- }
-
-#else // OPENTHREAD_FTD
- else
- {
+ error = UpdateIp6RouteFtd(ip6Header);
+#else
assert(false);
- }
-
-#endif // OPENTHREAD_FTD
-
-exit:
- return error;
-}
-
-#if OPENTHREAD_FTD
-#if OPENTHREAD_ENABLE_SERVICE
-otError MeshForwarder::GetDestinationRlocByServiceAloc(uint16_t aServiceAloc, uint16_t &aMeshDest)
-{
- otError error = OT_ERROR_NONE;
- ThreadNetif &netif = GetNetif();
- uint8_t serviceId = netif.GetMle().GetServiceIdFromAloc(aServiceAloc);
- NetworkData::ServiceTlv *serviceTlv = netif.GetNetworkDataLeader().FindServiceById(serviceId);
-
- if (serviceTlv != NULL)
- {
- NetworkData::NetworkDataTlv *cur = serviceTlv->GetSubTlvs();
- NetworkData::NetworkDataTlv *end = serviceTlv->GetNext();
- NetworkData::ServerTlv *server;
- uint8_t bestCost = Mle::kMaxRouteCost;
- uint8_t curCost = 0x00;
- uint16_t bestDest = Mac::kShortAddrInvalid;
-
- while (cur < end)
- {
- switch (cur->GetType())
- {
- case NetworkData::NetworkDataTlv::kTypeServer:
- server = static_cast(cur);
- curCost = netif.GetMle().GetCost(server->GetServer16());
-
- if ((bestDest == Mac::kShortAddrInvalid) || (curCost < bestCost))
- {
- bestDest = server->GetServer16();
- bestCost = curCost;
- }
-
- break;
-
- default:
- break;
- }
-
- cur = cur->GetNext();
- }
-
- if (bestDest != Mac::kShortAddrInvalid)
- {
- aMeshDest = bestDest;
- }
- else
- {
- // ServiceTLV without ServerTLV? Can't forward packet anywhere.
- ExitNow(error = OT_ERROR_DROP);
- }
- }
- else
- {
- // Unknown service, can't forward
- ExitNow(error = OT_ERROR_DROP);
+#endif
}
exit:
return error;
}
-#endif // OPENTHREAD_ENABLE_SERVICE
-#endif // OPENTHREAD_FTD
void MeshForwarder::SetRxOff(void)
{
@@ -1140,8 +493,6 @@ otError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame)
{
ThreadNetif &netif = GetNetif();
otError error = OT_ERROR_NONE;
- Mac::Address macDest;
- Child *child = NULL;
VerifyOrExit(mEnabled, error = OT_ERROR_ABORT);
@@ -1196,54 +547,67 @@ otError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame)
assert(aFrame.GetLength() != 7);
break;
- case Message::kType6lowpan:
- error = SendMesh(*mSendMessage, aFrame);
- break;
-
case Message::kTypeMacDataPoll:
error = SendPoll(*mSendMessage, aFrame);
break;
+#if OPENTHREAD_FTD
+
+ case Message::kType6lowpan:
+ error = SendMesh(*mSendMessage, aFrame);
+ break;
+
case Message::kTypeSupervision:
error = SendEmptyFrame(aFrame, kSupervisionMsgAckRequest);
mMessageNextOffset = mSendMessage->GetLength();
break;
+
+#endif
}
assert(error == OT_ERROR_NONE);
- aFrame.GetDstAddr(macDest);
-
- // Set `FramePending` if there are more queued messages (excluding
- // the current one being sent out) for the child (note `> 1` check).
- // The case where the current message requires fragmentation is
- // already checked and handled in `SendFragment()` method.
-
- if (((child = netif.GetMle().GetChild(macDest)) != NULL)
- && !child->IsRxOnWhenIdle()
- && (child->GetIndirectMessageCount() > 1))
- {
- aFrame.SetFramePending(true);
- }
-
aFrame.SetIsARetransmission(mSendMessageIsARetransmission);
aFrame.SetMaxTxAttempts(mSendMessageMaxMacTxAttempts);
- if (mSendMessageIsARetransmission)
+#if OPENTHREAD_FTD
+
{
- // If this is the re-transmission of an indirect frame to a sleepy child, we
- // ensure to use the same frame counter, key id, and data sequence number as
- // the last attempt.
+ Mac::Address macDest;
+ Child *child = NULL;
- aFrame.SetSequence(mSendMessageDataSequenceNumber);
-
- if (aFrame.GetSecurityEnabled())
+ if (mSendMessageIsARetransmission)
{
- aFrame.SetFrameCounter(mSendMessageFrameCounter);
- aFrame.SetKeyId(mSendMessageKeyId);
+ // If this is the re-transmission of an indirect frame to a sleepy child, we
+ // ensure to use the same frame counter, key id, and data sequence number as
+ // the last attempt.
+
+ aFrame.SetSequence(mSendMessageDataSequenceNumber);
+
+ if (aFrame.GetSecurityEnabled())
+ {
+ aFrame.SetFrameCounter(mSendMessageFrameCounter);
+ aFrame.SetKeyId(mSendMessageKeyId);
+ }
+ }
+
+ aFrame.GetDstAddr(macDest);
+
+ // Set `FramePending` if there are more queued messages (excluding
+ // the current one being sent out) for the child (note `> 1` check).
+ // The case where the current message requires fragmentation is
+ // already checked and handled in `SendFragment()` method.
+
+ if (((child = netif.GetMle().GetChild(macDest)) != NULL)
+ && !child->IsRxOnWhenIdle()
+ && (child->GetIndirectMessageCount() > 1))
+ {
+ aFrame.SetFramePending(true);
}
}
+#endif
+
exit:
return error;
}
@@ -1278,41 +642,14 @@ otError MeshForwarder::SendPoll(Message &aMessage, Mac::Frame &aFrame)
return OT_ERROR_NONE;
}
-otError MeshForwarder::SendMesh(Message &aMessage, Mac::Frame &aFrame)
-{
- ThreadNetif &netif = GetNetif();
- uint16_t fcf;
-
- // initialize MAC header
- fcf = Mac::Frame::kFcfFrameData | Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfFrameVersion2006 |
- Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort |
- Mac::Frame::kFcfAckRequest | Mac::Frame::kFcfSecurityEnabled;
-
- aFrame.InitMacHeader(fcf, Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32);
- aFrame.SetDstPanId(netif.GetMac().GetPanId());
- aFrame.SetDstAddr(mMacDest.mShortAddress);
- aFrame.SetSrcAddr(mMacSource.mShortAddress);
-
- // write payload
- assert(aMessage.GetLength() <= aFrame.GetMaxPayloadLength());
- aMessage.Read(0, aMessage.GetLength(), aFrame.GetPayload());
- aFrame.SetPayloadLength(static_cast(aMessage.GetLength()));
-
- mMessageNextOffset = aMessage.GetLength();
-
- return OT_ERROR_NONE;
-}
-
otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
{
ThreadNetif &netif = GetNetif();
Mac::Address meshDest, meshSource;
uint16_t fcf;
Lowpan::FragmentHeader *fragmentHeader;
- Lowpan::MeshHeader meshHeader;
uint8_t *payload;
uint8_t headerLength;
- uint8_t hopsLeft;
uint16_t payloadLength;
int hcLength;
uint16_t fragmentLength;
@@ -1399,9 +736,14 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
headerLength = 0;
+#if OPENTHREAD_FTD
+
// initialize Mesh header
if (mAddMeshHeader)
{
+ Lowpan::MeshHeader meshHeader;
+ uint8_t hopsLeft;
+
if (netif.GetMle().GetRole() == OT_DEVICE_ROLE_CHILD)
{
// REED sets hopsLeft to max (16) + 1. It does not know the route cost.
@@ -1441,6 +783,8 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
headerLength += meshHeader.GetHeaderLength();
}
+#endif
+
// copy IPv6 Header
if (aMessage.GetOffset() == 0)
{
@@ -1588,9 +932,7 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, otError aError)
{
ThreadNetif &netif = GetNetif();
Mac::Address macDest;
- Child *child;
Neighbor *neighbor;
- uint8_t childIndex;
mSendBusy = false;
@@ -1638,107 +980,7 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, otError aError)
}
}
- if ((child = netif.GetMle().GetChild(macDest)) != NULL)
- {
- child->SetDataRequestPending(false);
-
- VerifyOrExit(mSendMessage != NULL);
-
- if (mSendMessage == child->GetIndirectMessage())
- {
- // To ensure fairness in handling of data requests from sleepy
- // children, once a message is completed for indirect transmission to a
- // child (no matter succeed or failed), the `mStartChildIndex` is updated to
- // the next index after the current child. Subsequent call to
- // `ScheduleTransmissionTask()` will begin the iteration through
- // the children list from this index.
-
- mStartChildIndex++;
-
- if (aError == OT_ERROR_NONE)
- {
- child->ResetIndirectTxAttempts();
- }
- else
- {
- child->IncrementIndirectTxAttempts();
-
- if (child->GetIndirectTxAttempts() < kMaxPollTriggeredTxAttempts)
- {
- // We save the frame counter, key id, and data sequence number of
- // current frame so we use the same values for the retransmission
- // of the frame following the receipt of a data request command (data
- // poll) from the sleepy child.
-
- child->SetIndirectDataSequenceNumber(aFrame.GetSequence());
-
- if (aFrame.GetSecurityEnabled())
- {
- uint32_t frameCounter;
- uint8_t keyId;
-
- aFrame.GetFrameCounter(frameCounter);
- child->SetIndirectFrameCounter(frameCounter);
-
- aFrame.GetKeyId(keyId);
- child->SetIndirectKeyId(keyId);
- }
-
- ExitNow();
- }
-
- child->ResetIndirectTxAttempts();
-
-#if OPENTHREAD_CONFIG_DROP_MESSAGE_ON_FRAGMENT_TX_FAILURE
- // We set the NextOffset to end of message, since there is no need to
- // send any remaining fragments in the message to the child, if all tx
- // attempts of current frame already failed.
-
- mMessageNextOffset = mSendMessage->GetLength();
-#endif
- }
- }
-
- if (mMessageNextOffset < mSendMessage->GetLength())
- {
- if (mSendMessage == child->GetIndirectMessage())
- {
- child->SetIndirectFragmentOffset(mMessageNextOffset);
- }
- }
- else
- {
- if (mSendMessage == child->GetIndirectMessage())
- {
- child->SetIndirectFragmentOffset(0);
- child->SetIndirectMessage(NULL);
-
- // Enable short source address matching after the first indirect
- // message transmission attempt to the child. We intentionally do
- // not check for successful tx here to address the scenario where
- // the child does receive "Child ID Response" but parent misses the
- // 15.4 ack from child. If the "Child ID Response" does not make it
- // to the child, then the child will need to send a new "Child ID
- // Request" which will cause the parent to switch to using long
- // address mode for source address matching.
-
- mSourceMatchController.SetSrcMatchAsShort(*child, true);
- }
-
- childIndex = netif.GetMle().GetChildIndex(*child);
-
- if (mSendMessage->GetChildMask(childIndex))
- {
- mSendMessage->ClearChildMask(childIndex);
- mSourceMatchController.DecrementMessageCount(*child);
- }
- }
-
- if (aError == OT_ERROR_NONE)
- {
- netif.GetChildSupervisor().UpdateOnSend(*child);
- }
- }
+ HandleSentFrameToChild(aFrame, aError, macDest);
VerifyOrExit(mSendMessage != NULL);
@@ -1873,7 +1115,6 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame)
Mac::Address macSource;
uint8_t *payload;
uint8_t payloadLength;
- uint8_t commandId;
otError error = OT_ERROR_NONE;
char stringBuffer[Mac::Frame::kInfoStringSize];
@@ -1925,7 +1166,12 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame)
break;
+#if OPENTHREAD_FTD
+
case Mac::Frame::kFcfFrameMacCmd:
+ {
+ uint8_t commandId;
+
aFrame.GetCommandId(commandId);
if (commandId == Mac::Frame::kMacCmdDataRequest)
@@ -1938,6 +1184,9 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame)
}
break;
+ }
+
+#endif
default:
error = OT_ERROR_DROP;
@@ -1956,176 +1205,6 @@ exit:
OT_UNUSED_VARIABLE(stringBuffer);
}
-void MeshForwarder::HandleMesh(uint8_t *aFrame, uint8_t aFrameLength, const Mac::Address &aMacSource,
- const otThreadLinkInfo &aLinkInfo)
-{
- ThreadNetif &netif = GetNetif();
- otError error = OT_ERROR_NONE;
- Message *message = NULL;
- Mac::Address meshDest;
- Mac::Address meshSource;
- Lowpan::MeshHeader meshHeader;
-
- // Check the mesh header
- VerifyOrExit(meshHeader.Init(aFrame, aFrameLength) == OT_ERROR_NONE, error = OT_ERROR_DROP);
-
- // Security Check: only process Mesh Header frames that had security enabled.
- VerifyOrExit(aLinkInfo.mLinkSecurity && meshHeader.IsValid(), error = OT_ERROR_SECURITY);
-
- meshSource.mLength = sizeof(meshSource.mShortAddress);
- meshSource.mShortAddress = meshHeader.GetSource();
- meshDest.mLength = sizeof(meshDest.mShortAddress);
- meshDest.mShortAddress = meshHeader.GetDestination();
-
-#if OPENTHREAD_FTD
- UpdateRoutes(aFrame, aFrameLength, meshSource, meshDest);
-#endif // OPENTHREAD_FTD
-
- if (meshDest.mShortAddress == netif.GetMac().GetShortAddress() ||
- netif.GetMle().IsMinimalChild(meshDest.mShortAddress))
- {
- aFrame += meshHeader.GetHeaderLength();
- aFrameLength -= meshHeader.GetHeaderLength();
-
- if (reinterpret_cast(aFrame)->IsFragmentHeader())
- {
- HandleFragment(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
- }
- else if (Lowpan::Lowpan::IsLowpanHc(aFrame))
- {
- HandleLowpanHC(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
- }
- else
- {
- ExitNow(error = OT_ERROR_PARSE);
- }
- }
- else if (meshHeader.GetHopsLeft() > 0)
- {
- netif.GetMle().ResolveRoutingLoops(aMacSource.mShortAddress, meshDest.mShortAddress);
-
- SuccessOrExit(error = CheckReachability(aFrame, aFrameLength, meshSource, meshDest));
-
- meshHeader.SetHopsLeft(meshHeader.GetHopsLeft() - 1);
- meshHeader.AppendTo(aFrame);
-
- VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kType6lowpan, 0)) != NULL,
- error = OT_ERROR_NO_BUFS);
- SuccessOrExit(error = message->SetLength(aFrameLength));
- message->Write(0, aFrameLength, aFrame);
- message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
- message->SetPanId(aLinkInfo.mPanId);
-
- SendMessage(*message);
- }
-
-exit:
-
- if (error != OT_ERROR_NONE)
- {
- char srcStringBuffer[Mac::Address::kAddressStringSize];
-
- otLogInfoMac(
- GetInstance(),
- "Dropping rx mesh frame, error:%s, len:%d, src:%s, sec:%s",
- otThreadErrorToString(error),
- aFrameLength,
- aMacSource.ToString(srcStringBuffer, sizeof(srcStringBuffer)),
- aLinkInfo.mLinkSecurity ? "yes" : "no"
- );
-
- OT_UNUSED_VARIABLE(srcStringBuffer);
-
- if (message != NULL)
- {
- message->Free();
- }
- }
-}
-
-#if OPENTHREAD_FTD
-void MeshForwarder::UpdateRoutes(uint8_t *aFrame, uint8_t aFrameLength,
- const Mac::Address &aMeshSource, const Mac::Address &aMeshDest)
-{
- ThreadNetif &netif = GetNetif();
- Lowpan::MeshHeader meshHeader;
- Ip6::Header ip6Header;
- Neighbor *neighbor;
-
- VerifyOrExit(meshHeader.Init(aFrame, aFrameLength) == OT_ERROR_NONE);
-
- // skip mesh header
- aFrame += meshHeader.GetHeaderLength();
- aFrameLength -= meshHeader.GetHeaderLength();
-
- // skip fragment header
- if (aFrameLength >= 1 &&
- reinterpret_cast(aFrame)->IsFragmentHeader())
- {
- VerifyOrExit(sizeof(Lowpan::FragmentHeader) <= aFrameLength);
- VerifyOrExit(reinterpret_cast(aFrame)->GetDatagramOffset() == 0);
-
- aFrame += reinterpret_cast(aFrame)->GetHeaderLength();
- aFrameLength -= reinterpret_cast(aFrame)->GetHeaderLength();
- }
-
- // only process IPv6 packets
- VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame));
-
- VerifyOrExit(netif.GetLowpan().DecompressBaseHeader(ip6Header, aMeshSource, aMeshDest, aFrame, aFrameLength) > 0);
-
- neighbor = netif.GetMle().GetNeighbor(ip6Header.GetSource());
- VerifyOrExit(neighbor != NULL && !neighbor->IsFullThreadDevice());
-
- netif.GetAddressResolver().UpdateCacheEntry(ip6Header.GetSource(), meshHeader.GetSource());
-
- if (Mle::Mle::GetRouterId(meshHeader.GetSource()) != Mle::Mle::GetRouterId(GetNetif().GetMac().GetShortAddress()))
- {
- netif.GetMle().RemoveNeighbor(*neighbor);
- }
-
-exit:
- return;
-}
-#endif // OPENTHREAD_FTD
-
-otError MeshForwarder::CheckReachability(uint8_t *aFrame, uint8_t aFrameLength,
- const Mac::Address &aMeshSource, const Mac::Address &aMeshDest)
-{
- ThreadNetif &netif = GetNetif();
- otError error = OT_ERROR_NONE;
- Ip6::Header ip6Header;
- Lowpan::MeshHeader meshHeader;
-
- VerifyOrExit(meshHeader.Init(aFrame, aFrameLength) == OT_ERROR_NONE, error = OT_ERROR_DROP);
-
- // skip mesh header
- aFrame += meshHeader.GetHeaderLength();
- aFrameLength -= meshHeader.GetHeaderLength();
-
- // skip fragment header
- if (aFrameLength >= 1 &&
- reinterpret_cast(aFrame)->IsFragmentHeader())
- {
- VerifyOrExit(sizeof(Lowpan::FragmentHeader) <= aFrameLength, error = OT_ERROR_DROP);
- VerifyOrExit(reinterpret_cast(aFrame)->GetDatagramOffset() == 0);
-
- aFrame += reinterpret_cast(aFrame)->GetHeaderLength();
- aFrameLength -= reinterpret_cast(aFrame)->GetHeaderLength();
- }
-
- // only process IPv6 packets
- VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame));
-
- VerifyOrExit(netif.GetLowpan().DecompressBaseHeader(ip6Header, aMeshSource, aMeshDest, aFrame, aFrameLength) > 0,
- error = OT_ERROR_DROP);
-
- error = netif.GetMle().CheckReachability(aMeshSource.mShortAddress, aMeshDest.mShortAddress, ip6Header);
-
-exit:
- return error;
-}
-
void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
const Mac::Address &aMacSource, const Mac::Address &aMacDest,
const otThreadLinkInfo &aLinkInfo)
@@ -2382,36 +1461,6 @@ otError MeshForwarder::HandleDatagram(Message &aMessage, const otThreadLinkInfo
return netif.GetIp6().HandleDatagram(aMessage, &netif, netif.GetInterfaceId(), &aLinkInfo, false);
}
-void MeshForwarder::HandleDataRequest(const Mac::Address &aMacSource, const otThreadLinkInfo &aLinkInfo)
-{
- ThreadNetif &netif = GetNetif();
- Child *child;
- uint16_t indirectMsgCount;
-
- // Security Check: only process secure Data Poll frames.
- VerifyOrExit(aLinkInfo.mLinkSecurity);
-
- VerifyOrExit(netif.GetMle().GetRole() != OT_DEVICE_ROLE_DETACHED);
-
- VerifyOrExit((child = netif.GetMle().GetChild(aMacSource)) != NULL);
- child->SetLastHeard(TimerMilli::GetNow());
- child->ResetLinkFailures();
- indirectMsgCount = child->GetIndirectMessageCount();
-
- if (!mSourceMatchController.IsEnabled() || (indirectMsgCount > 0))
- {
- child->SetDataRequestPending(true);
- }
-
- mScheduleTransmissionTask.Post();
-
- otLogInfoMac(GetInstance(), "Rx data poll, src:0x%04x, qed_msgs:%d, rss:%d", child->GetRloc16(), indirectMsgCount,
- aLinkInfo.mRss);
-
-exit:
- return;
-}
-
void MeshForwarder::HandleDataPollTimeout(Mac::Receiver &aReceiver)
{
aReceiver.GetOwner().GetDataPollManager().HandlePollTimeout();
diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp
index e08b290cc..a6810fa02 100644
--- a/src/core/thread/mesh_forwarder.hpp
+++ b/src/core/thread/mesh_forwarder.hpp
@@ -199,14 +199,6 @@ public:
*/
const MessageQueue &GetReassemblyQueue(void) const { return mReassemblyList; }
- /**
- * This method returns a reference to the resolving queue.
- *
- * @returns A reference to the resolving queue.
- *
- */
- const MessageQueue &GetResolvingQueue(void) const { return mResolvingQueue; }
-
/**
* This method returns a reference to the data poll manager.
*
@@ -215,14 +207,6 @@ public:
*/
DataPollManager &GetDataPollManager(void) { return mDataPollManager; }
- /**
- * This method returns a reference to the source match controller.
- *
- * @returns A reference to the source match controller.
- *
- */
- SourceMatchController &GetSourceMatchController(void) { return mSourceMatchController; }
-
/**
* This method returns a reference to the IP level counters.
*
@@ -231,6 +215,24 @@ public:
*/
const otIpCounters &GetCounters(void) const { return mIpCounters; }
+#if OPENTHREAD_FTD
+ /**
+ * This method returns a reference to the resolving queue.
+ *
+ * @returns A reference to the resolving queue.
+ *
+ */
+ const MessageQueue &GetResolvingQueue(void) const { return mResolvingQueue; }
+
+ /**
+ * This method returns a reference to the source match controller.
+ *
+ * @returns A reference to the source match controller.
+ *
+ */
+ SourceMatchController &GetSourceMatchController(void) { return mSourceMatchController; }
+#endif
+
private:
enum
{
@@ -272,6 +274,7 @@ private:
otError GetMacDestinationAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
otError GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr);
Message *GetDirectTransmission(void);
+ otError GetIndirectTransmission(void);
Message *GetIndirectTransmission(Child &aChild);
otError PrepareDiscoverRequest(void);
void PrepareIndirectTransmission(Message &aMessage, const Child &aChild);
@@ -290,6 +293,7 @@ private:
otError SendFragment(Message &aMessage, Mac::Frame &aFrame);
otError SendEmptyFrame(Mac::Frame &aFrame, bool aAckRequest);
otError UpdateIp6Route(Message &aMessage);
+ otError UpdateIp6RouteFtd(Ip6::Header &ip6Header);
otError UpdateMeshRoute(Message &aMessage);
otError HandleDatagram(Message &aMessage, const otThreadLinkInfo &aLinkInfo,
const Mac::Address &aMacSource);
@@ -303,6 +307,7 @@ private:
otError HandleFrameRequest(Mac::Frame &aFrame);
static void HandleSentFrame(Mac::Sender &aSender, Mac::Frame &aFrame, otError aError);
void HandleSentFrame(Mac::Frame &aFrame, otError aError);
+ void HandleSentFrameToChild(const Mac::Frame &aFrame, otError aError, const Mac::Address &macDest);
static void HandleDiscoverTimer(Timer &aTimer);
void HandleDiscoverTimer(void);
static void HandleReassemblyTimer(Timer &aTimer);
@@ -311,11 +316,7 @@ private:
void ScheduleTransmissionTask(void);
static void HandleDataPollTimeout(Mac::Receiver &aReceiver);
-#if OPENTHREAD_FTD
-#if OPENTHREAD_ENABLE_SERVICE
otError GetDestinationRlocByServiceAloc(uint16_t aServiceAloc, uint16_t &aMeshDest);
-#endif // OPENTHREAD_ENABLE_SERVICE
-#endif // OPENTHREAD_FTD
void LogIp6Message(MessageAction aAction, const Message &aMessage, const Mac::Address *aMacAddress,
otError aError);
@@ -327,17 +328,12 @@ private:
PriorityQueue mSendQueue;
MessageQueue mReassemblyList;
- MessageQueue mResolvingQueue;
uint16_t mFragTag;
uint16_t mMessageNextOffset;
- uint32_t mSendMessageFrameCounter;
- Message *mSendMessage;
+ Message *mSendMessage;
bool mSendMessageIsARetransmission;
uint8_t mSendMessageMaxMacTxAttempts;
- uint8_t mSendMessageKeyId;
- uint8_t mSendMessageDataSequenceNumber;
- uint8_t mStartChildIndex;
Mac::Address mMacSource;
Mac::Address mMacDest;
@@ -356,10 +352,18 @@ private:
uint16_t mRestorePanId;
bool mScanning;
- DataPollManager mDataPollManager;
- SourceMatchController mSourceMatchController;
-
otIpCounters mIpCounters;
+
+#if OPENTHREAD_FTD
+ MessageQueue mResolvingQueue;
+ SourceMatchController mSourceMatchController;
+ uint32_t mSendMessageFrameCounter;
+ uint8_t mSendMessageKeyId;
+ uint8_t mSendMessageDataSequenceNumber;
+ uint8_t mStartChildIndex;
+#endif
+
+ DataPollManager mDataPollManager;
};
/**
diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp
new file mode 100644
index 000000000..1bd0fa140
--- /dev/null
+++ b/src/core/thread/mesh_forwarder_ftd.cpp
@@ -0,0 +1,1014 @@
+/*
+ * Copyright (c) 2018, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file implements FTD-specific mesh forwarding of IPv6/6LoWPAN messages.
+ */
+
+#if OPENTHREAD_FTD
+
+#define WPP_NAME "mesh_forwarder_ftd.tmh"
+
+#include "mesh_forwarder.hpp"
+
+#include "common/logging.hpp"
+#include "common/owner-locator.hpp"
+
+namespace ot {
+
+otError MeshForwarder::SendMessage(Message &aMessage)
+{
+ ThreadNetif &netif = GetNetif();
+ otError error = OT_ERROR_NONE;
+ Neighbor *neighbor;
+
+ uint8_t numChildren;
+ Child *child;
+
+ switch (aMessage.GetType())
+ {
+ case Message::kTypeIp6:
+ {
+ Ip6::Header ip6Header;
+
+ aMessage.Read(0, sizeof(ip6Header), &ip6Header);
+
+ if (ip6Header.GetDestination() == netif.GetMle().GetLinkLocalAllThreadNodesAddress() ||
+ ip6Header.GetDestination() == netif.GetMle().GetRealmLocalAllThreadNodesAddress())
+ {
+ // schedule direct transmission
+ aMessage.SetDirectTransmission();
+
+ if (aMessage.GetSubType() != Message::kSubTypeMplRetransmission)
+ {
+ // destined for all sleepy children
+ child = netif.GetMle().GetChildren(&numChildren);
+
+ for (uint8_t i = 0; i < numChildren; i++, child++)
+ {
+ if (child->IsStateValidOrRestoring() && !child->IsRxOnWhenIdle())
+ {
+ aMessage.SetChildMask(i);
+ mSourceMatchController.IncrementMessageCount(*child);
+ }
+ }
+ }
+ }
+ else if ((neighbor = netif.GetMle().GetNeighbor(ip6Header.GetDestination())) != NULL &&
+ !neighbor->IsRxOnWhenIdle() &&
+ !aMessage.GetDirectTransmission())
+ {
+ // destined for a sleepy child
+ child = static_cast(neighbor);
+ aMessage.SetChildMask(netif.GetMle().GetChildIndex(*child));
+ mSourceMatchController.IncrementMessageCount(*child);
+ }
+ else
+ {
+ // schedule direct transmission
+ aMessage.SetDirectTransmission();
+ }
+
+ break;
+ }
+
+ case Message::kTypeSupervision:
+ child = netif.GetChildSupervisor().GetDestination(aMessage);
+ VerifyOrExit(child != NULL, error = OT_ERROR_DROP);
+ VerifyOrExit(!child->IsRxOnWhenIdle(), error = OT_ERROR_DROP);
+
+ aMessage.SetChildMask(netif.GetMle().GetChildIndex(*child));
+ mSourceMatchController.IncrementMessageCount(*child);
+ break;
+
+ default:
+ aMessage.SetDirectTransmission();
+ break;
+ }
+
+ aMessage.SetOffset(0);
+ aMessage.SetDatagramTag(0);
+ SuccessOrExit(error = mSendQueue.Enqueue(aMessage));
+ mScheduleTransmissionTask.Post();
+
+exit:
+ return error;
+}
+
+void MeshForwarder::HandleResolved(const Ip6::Address &aEid, otError aError)
+{
+ Message *cur, *next;
+ Ip6::Address ip6Dst;
+ bool enqueuedMessage = false;
+
+ for (cur = mResolvingQueue.GetHead(); cur; cur = next)
+ {
+ next = cur->GetNext();
+
+ if (cur->GetType() != Message::kTypeIp6)
+ {
+ continue;
+ }
+
+ cur->Read(Ip6::Header::GetDestinationOffset(), sizeof(ip6Dst), &ip6Dst);
+
+ if (ip6Dst == aEid)
+ {
+ mResolvingQueue.Dequeue(*cur);
+
+ if (aError == OT_ERROR_NONE)
+ {
+ mSendQueue.Enqueue(*cur);
+ enqueuedMessage = true;
+ }
+ else
+ {
+ LogIp6Message(kMessageDrop, *cur, NULL, aError);
+ cur->Free();
+ }
+ }
+ }
+
+ if (enqueuedMessage)
+ {
+ mScheduleTransmissionTask.Post();
+ }
+}
+
+void MeshForwarder::ClearChildIndirectMessages(Child &aChild)
+{
+ Message *nextMessage;
+
+ VerifyOrExit(aChild.GetIndirectMessageCount() > 0);
+
+ for (Message *message = mSendQueue.GetHead(); message; message = nextMessage)
+ {
+ nextMessage = message->GetNext();
+
+ message->ClearChildMask(GetNetif().GetMle().GetChildIndex(aChild));
+
+ if (!message->IsChildPending() && !message->GetDirectTransmission())
+ {
+ if (mSendMessage == message)
+ {
+ mSendMessage = NULL;
+ }
+
+ mSendQueue.Dequeue(*message);
+ message->Free();
+ }
+ }
+
+ aChild.SetIndirectMessage(NULL);
+ mSourceMatchController.ResetMessageCount(aChild);
+
+exit:
+ return;
+}
+
+void MeshForwarder::UpdateIndirectMessages(void)
+{
+ Child *children;
+ uint8_t numChildren;
+
+ children = GetNetif().GetMle().GetChildren(&numChildren);
+
+ for (uint8_t i = 0; i < numChildren; i++)
+ {
+ Child *child = &children[i];
+
+ if (child->IsStateValidOrRestoring() || (child->GetIndirectMessageCount() == 0))
+ {
+ continue;
+ }
+
+ ClearChildIndirectMessages(*child);
+ }
+}
+
+otError MeshForwarder::EvictIndirectMessage(void)
+{
+ otError error = OT_ERROR_NOT_FOUND;
+
+ for (Message *message = mSendQueue.GetHead(); message; message = message->GetNext())
+ {
+ if (!message->IsChildPending())
+ {
+ continue;
+ }
+
+ RemoveMessage(*message);
+ ExitNow(error = OT_ERROR_NONE);
+ }
+
+exit:
+ return error;
+}
+
+otError MeshForwarder::RemoveMessageFromSleepyChild(Message &aMessage, Child &aChild)
+{
+ otError error = OT_ERROR_NONE;
+ uint8_t childIndex = GetNetif().GetMle().GetChildIndex(aChild);
+
+ VerifyOrExit(aMessage.GetChildMask(childIndex) == true, error = OT_ERROR_NOT_FOUND);
+
+ aMessage.ClearChildMask(childIndex);
+ mSourceMatchController.DecrementMessageCount(aChild);
+
+ if (aChild.GetIndirectMessage() == &aMessage)
+ {
+ aChild.SetIndirectMessage(NULL);
+ }
+
+exit:
+ return error;
+}
+
+void MeshForwarder::RemoveMessages(Child &aChild, uint8_t aSubType)
+{
+ ThreadNetif &netif = GetNetif();
+ Message *nextMessage;
+
+ for (Message *message = mSendQueue.GetHead(); message; message = nextMessage)
+ {
+ nextMessage = message->GetNext();
+
+ if ((aSubType != Message::kSubTypeNone) && (aSubType != message->GetSubType()))
+ {
+ continue;
+ }
+
+ if (RemoveMessageFromSleepyChild(*message, aChild) != OT_ERROR_NONE)
+ {
+ switch (message->GetType())
+ {
+ case Message::kTypeIp6:
+ {
+ Ip6::Header ip6header;
+
+ IgnoreReturnValue(message->Read(0, sizeof(ip6header), &ip6header));
+
+ if (&aChild == static_cast(netif.GetMle().GetNeighbor(ip6header.GetDestination())))
+ {
+ message->ClearDirectTransmission();
+ }
+
+ break;
+ }
+
+ case Message::kType6lowpan:
+ {
+ Lowpan::MeshHeader meshHeader;
+
+ IgnoreReturnValue(meshHeader.Init(*message));
+
+ if (&aChild == static_cast(netif.GetMle().GetNeighbor(meshHeader.GetDestination())))
+ {
+ message->ClearDirectTransmission();
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ if (!message->IsChildPending() && !message->GetDirectTransmission())
+ {
+ if (mSendMessage == message)
+ {
+ mSendMessage = NULL;
+ }
+
+ mSendQueue.Dequeue(*message);
+ message->Free();
+ }
+ }
+}
+
+otError MeshForwarder::GetIndirectTransmission(void)
+{
+ otError error = OT_ERROR_NOT_FOUND;
+ ThreadNetif &netif = GetNetif();
+ uint8_t numChildren;
+ uint8_t childIndex;
+ uint8_t nextIndex;
+ Child *children;
+
+ UpdateIndirectMessages();
+
+ children = netif.GetMle().GetChildren(&numChildren);
+
+ if (mStartChildIndex >= numChildren)
+ {
+ mStartChildIndex = 0;
+ }
+
+ childIndex = mStartChildIndex;
+
+ for (uint8_t iterations = numChildren; iterations > 0; iterations--, childIndex = nextIndex)
+ {
+ Child &child = children[childIndex];
+
+ if ((nextIndex = childIndex + 1) == numChildren)
+ {
+ nextIndex = 0;
+ }
+
+ if (!child.IsStateValidOrRestoring() || !child.IsDataRequestPending())
+ {
+ continue;
+ }
+
+ mSendMessage = child.GetIndirectMessage();
+ mSendMessageMaxMacTxAttempts = Mac::kIndirectFrameMacTxAttempts;
+
+ if (mSendMessage == NULL)
+ {
+ mSendMessage = GetIndirectTransmission(child);
+ }
+
+ if (mSendMessage != NULL)
+ {
+ PrepareIndirectTransmission(*mSendMessage, child);
+ }
+ else
+ {
+ // A NULL `mSendMessage` triggers an empty frame to be sent to the child.
+
+ if (child.IsIndirectSourceMatchShort())
+ {
+ mMacSource.mLength = sizeof(mMacSource.mShortAddress);
+ mMacSource.mShortAddress = netif.GetMac().GetShortAddress();
+ }
+ else
+ {
+ mMacSource.mLength = sizeof(mMacSource.mExtAddress);
+ mMacSource.mExtAddress = netif.GetMac().GetExtAddress();
+ }
+
+ child.GetMacAddress(mMacDest);
+ }
+
+ // Record current child index, and move it to next index after this indirect transmission has completed.
+
+ mStartChildIndex = childIndex;
+
+ netif.GetMac().SendFrameRequest(mMacSender);
+ ExitNow(error = OT_ERROR_NONE);
+ }
+
+exit:
+ return error;
+}
+
+Message *MeshForwarder::GetIndirectTransmission(Child &aChild)
+{
+ Message *message = NULL;
+ Message *next;
+ uint8_t childIndex = GetNetif().GetMle().GetChildIndex(aChild);
+
+ for (message = mSendQueue.GetHead(); message; message = next)
+ {
+ next = message->GetNext();
+
+ if (message->GetChildMask(childIndex))
+ {
+ // Skip and remove the supervision message if there are other messages queued for the child.
+
+ if ((message->GetType() == Message::kTypeSupervision) && (aChild.GetIndirectMessageCount() > 1))
+ {
+ message->ClearChildMask(childIndex);
+ mSourceMatchController.DecrementMessageCount(aChild);
+ mSendQueue.Dequeue(*message);
+ message->Free();
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ aChild.SetIndirectMessage(message);
+ aChild.SetIndirectFragmentOffset(0);
+ aChild.ResetIndirectTxAttempts();
+
+ if (message != NULL)
+ {
+ Mac::Address macAddr;
+
+ LogIp6Message(kMessagePrepareIndirect, *message, &aChild.GetMacAddress(macAddr), OT_ERROR_NONE);
+ }
+
+ return message;
+}
+
+void MeshForwarder::PrepareIndirectTransmission(Message &aMessage, const Child &aChild)
+{
+ if (aChild.GetIndirectTxAttempts() > 0)
+ {
+ mSendMessageIsARetransmission = true;
+ mSendMessageFrameCounter = aChild.GetIndirectFrameCounter();
+ mSendMessageKeyId = aChild.GetIndirectKeyId();
+ mSendMessageDataSequenceNumber = aChild.GetIndirectDataSequenceNumber();
+ }
+
+ aMessage.SetOffset(aChild.GetIndirectFragmentOffset());
+
+ switch (aMessage.GetType())
+ {
+ case Message::kTypeIp6:
+ {
+ Ip6::Header ip6Header;
+
+ aMessage.Read(0, sizeof(ip6Header), &ip6Header);
+
+ mAddMeshHeader = false;
+ GetMacSourceAddress(ip6Header.GetSource(), mMacSource);
+
+ if (ip6Header.GetDestination().IsLinkLocal())
+ {
+ GetMacDestinationAddress(ip6Header.GetDestination(), mMacDest);
+ }
+ else
+ {
+ aChild.GetMacAddress(mMacDest);
+ }
+
+ break;
+ }
+
+ case Message::kTypeSupervision:
+ aChild.GetMacAddress(mMacDest);
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
+
+otError MeshForwarder::SendMesh(Message &aMessage, Mac::Frame &aFrame)
+{
+ ThreadNetif &netif = GetNetif();
+ uint16_t fcf;
+
+ // initialize MAC header
+ fcf = Mac::Frame::kFcfFrameData | Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfFrameVersion2006 |
+ Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort |
+ Mac::Frame::kFcfAckRequest | Mac::Frame::kFcfSecurityEnabled;
+
+ aFrame.InitMacHeader(fcf, Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32);
+ aFrame.SetDstPanId(netif.GetMac().GetPanId());
+ aFrame.SetDstAddr(mMacDest.mShortAddress);
+ aFrame.SetSrcAddr(mMacSource.mShortAddress);
+
+ // write payload
+ assert(aMessage.GetLength() <= aFrame.GetMaxPayloadLength());
+ aMessage.Read(0, aMessage.GetLength(), aFrame.GetPayload());
+ aFrame.SetPayloadLength(static_cast(aMessage.GetLength()));
+
+ mMessageNextOffset = aMessage.GetLength();
+
+ return OT_ERROR_NONE;
+}
+
+void MeshForwarder::HandleDataRequest(const Mac::Address &aMacSource, const otThreadLinkInfo &aLinkInfo)
+{
+ ThreadNetif &netif = GetNetif();
+ Child *child;
+ uint16_t indirectMsgCount;
+
+ // Security Check: only process secure Data Poll frames.
+ VerifyOrExit(aLinkInfo.mLinkSecurity);
+
+ VerifyOrExit(netif.GetMle().GetRole() != OT_DEVICE_ROLE_DETACHED);
+
+ VerifyOrExit((child = netif.GetMle().GetChild(aMacSource)) != NULL);
+ child->SetLastHeard(TimerMilli::GetNow());
+ child->ResetLinkFailures();
+ indirectMsgCount = child->GetIndirectMessageCount();
+
+ if (!mSourceMatchController.IsEnabled() || (indirectMsgCount > 0))
+ {
+ child->SetDataRequestPending(true);
+ }
+
+ mScheduleTransmissionTask.Post();
+
+ otLogInfoMac(GetInstance(), "Rx data poll, src:0x%04x, qed_msgs:%d, rss:%d", child->GetRloc16(), indirectMsgCount,
+ aLinkInfo.mRss);
+
+exit:
+ return;
+}
+
+void MeshForwarder::HandleSentFrameToChild(const Mac::Frame &aFrame, otError aError, const Mac::Address &aMacDest)
+{
+ ThreadNetif &netif = GetNetif();
+ Child *child;
+
+ child = netif.GetMle().GetChild(aMacDest);
+ VerifyOrExit(child != NULL);
+
+ child->SetDataRequestPending(false);
+
+ VerifyOrExit(mSendMessage != NULL);
+
+ if (mSendMessage == child->GetIndirectMessage())
+ {
+ // To ensure fairness in handling of data requests from sleepy
+ // children, once a message is completed for indirect transmission to a
+ // child (no matter succeed or failed), the `mStartChildIndex` is updated to
+ // the next index after the current child. Subsequent call to
+ // `ScheduleTransmissionTask()` will begin the iteration through
+ // the children list from this index.
+
+ mStartChildIndex++;
+
+ if (aError == OT_ERROR_NONE)
+ {
+ child->ResetIndirectTxAttempts();
+ }
+ else
+ {
+ child->IncrementIndirectTxAttempts();
+
+ if (child->GetIndirectTxAttempts() < kMaxPollTriggeredTxAttempts)
+ {
+ // We save the frame counter, key id, and data sequence number of
+ // current frame so we use the same values for the retransmission
+ // of the frame following the receipt of a data request command (data
+ // poll) from the sleepy child.
+
+ child->SetIndirectDataSequenceNumber(aFrame.GetSequence());
+
+ if (aFrame.GetSecurityEnabled())
+ {
+ uint32_t frameCounter;
+ uint8_t keyId;
+
+ aFrame.GetFrameCounter(frameCounter);
+ child->SetIndirectFrameCounter(frameCounter);
+
+ aFrame.GetKeyId(keyId);
+ child->SetIndirectKeyId(keyId);
+ }
+
+ ExitNow();
+ }
+
+ child->ResetIndirectTxAttempts();
+
+#if OPENTHREAD_CONFIG_DROP_MESSAGE_ON_FRAGMENT_TX_FAILURE
+ // We set the NextOffset to end of message, since there is no need to
+ // send any remaining fragments in the message to the child, if all tx
+ // attempts of current frame already failed.
+
+ mMessageNextOffset = mSendMessage->GetLength();
+#endif
+ }
+ }
+
+ if (mMessageNextOffset < mSendMessage->GetLength())
+ {
+ if (mSendMessage == child->GetIndirectMessage())
+ {
+ child->SetIndirectFragmentOffset(mMessageNextOffset);
+ }
+ }
+ else
+ {
+ uint8_t childIndex;
+
+ if (mSendMessage == child->GetIndirectMessage())
+ {
+ child->SetIndirectFragmentOffset(0);
+ child->SetIndirectMessage(NULL);
+
+ // Enable short source address matching after the first indirect
+ // message transmission attempt to the child. We intentionally do
+ // not check for successful tx here to address the scenario where
+ // the child does receive "Child ID Response" but parent misses the
+ // 15.4 ack from child. If the "Child ID Response" does not make it
+ // to the child, then the child will need to send a new "Child ID
+ // Request" which will cause the parent to switch to using long
+ // address mode for source address matching.
+
+ mSourceMatchController.SetSrcMatchAsShort(*child, true);
+ }
+
+ childIndex = netif.GetMle().GetChildIndex(*child);
+
+ if (mSendMessage->GetChildMask(childIndex))
+ {
+ mSendMessage->ClearChildMask(childIndex);
+ mSourceMatchController.DecrementMessageCount(*child);
+ }
+ }
+
+ if (aError == OT_ERROR_NONE)
+ {
+ netif.GetChildSupervisor().UpdateOnSend(*child);
+ }
+
+exit:
+ return;
+}
+
+otError MeshForwarder::UpdateMeshRoute(Message &aMessage)
+{
+ ThreadNetif &netif = GetNetif();
+ otError error = OT_ERROR_NONE;
+ Lowpan::MeshHeader meshHeader;
+ Neighbor *neighbor;
+ uint16_t nextHop;
+
+ IgnoreReturnValue(meshHeader.Init(aMessage));
+
+ nextHop = netif.GetMle().GetNextHop(meshHeader.GetDestination());
+
+ if (nextHop != Mac::kShortAddrInvalid)
+ {
+ neighbor = netif.GetMle().GetNeighbor(nextHop);
+ }
+ else
+ {
+ neighbor = netif.GetMle().GetNeighbor(meshHeader.GetDestination());
+ }
+
+ if (neighbor == NULL)
+ {
+ ExitNow(error = OT_ERROR_DROP);
+ }
+
+ mMacDest.mLength = sizeof(mMacDest.mShortAddress);
+ mMacDest.mShortAddress = neighbor->GetRloc16();
+ mMacSource.mLength = sizeof(mMacSource.mShortAddress);
+ mMacSource.mShortAddress = netif.GetMac().GetShortAddress();
+
+ mAddMeshHeader = true;
+ mMeshDest = meshHeader.GetDestination();
+ mMeshSource = meshHeader.GetSource();
+
+exit:
+ return error;
+}
+
+otError MeshForwarder::UpdateIp6RouteFtd(Ip6::Header &ip6Header)
+{
+ otError error = OT_ERROR_NONE;
+ ThreadNetif &netif = GetNetif();
+ Neighbor *neighbor;
+
+ if (netif.GetMle().IsRoutingLocator(ip6Header.GetDestination()))
+ {
+ uint16_t rloc16 = HostSwap16(ip6Header.GetDestination().mFields.m16[7]);
+ VerifyOrExit(netif.GetMle().IsRouterIdValid(netif.GetMle().GetRouterId(rloc16)),
+ error = OT_ERROR_DROP);
+ mMeshDest = rloc16;
+ }
+ else if (netif.GetMle().IsAnycastLocator(ip6Header.GetDestination()))
+ {
+ uint16_t aloc16 = HostSwap16(ip6Header.GetDestination().mFields.m16[7]);
+
+ if (aloc16 == Mle::kAloc16Leader)
+ {
+ mMeshDest = netif.GetMle().GetRloc16(netif.GetMle().GetLeaderId());
+ }
+
+#if OPENTHREAD_ENABLE_DHCP6_SERVER || OPENTHREAD_ENABLE_DHCP6_CLIENT
+ else if (aloc16 <= Mle::kAloc16DhcpAgentEnd)
+ {
+ uint16_t agentRloc16;
+ uint8_t routerId;
+ VerifyOrExit((netif.GetNetworkDataLeader().GetRlocByContextId(
+ static_cast(aloc16 & Mle::kAloc16DhcpAgentMask),
+ agentRloc16) == OT_ERROR_NONE),
+ error = OT_ERROR_DROP);
+
+ routerId = netif.GetMle().GetRouterId(agentRloc16);
+
+ // if agent is active router or the child of the device
+ if ((netif.GetMle().IsActiveRouter(agentRloc16)) ||
+ (netif.GetMle().GetRloc16(routerId) == netif.GetMle().GetRloc16()))
+ {
+ mMeshDest = agentRloc16;
+ }
+ else
+ {
+ // use the parent of the ED Agent as Dest
+ mMeshDest = netif.GetMle().GetRloc16(routerId);
+ }
+ }
+
+#endif // OPENTHREAD_ENABLE_DHCP6_SERVER || OPENTHREAD_ENABLE_DHCP6_CLIENT
+#if OPENTHREAD_ENABLE_SERVICE
+ else if ((aloc16 >= Mle::kAloc16ServiceStart) && (aloc16 <= Mle::kAloc16ServiceEnd))
+ {
+ SuccessOrExit(error = GetDestinationRlocByServiceAloc(aloc16, mMeshDest));
+ }
+
+#endif
+ else
+ {
+ // TODO: support ALOC for Commissioner, Neighbor Discovery Agent
+ ExitNow(error = OT_ERROR_DROP);
+ }
+ }
+ else if ((neighbor = netif.GetMle().GetNeighbor(ip6Header.GetDestination())) != NULL)
+ {
+ mMeshDest = neighbor->GetRloc16();
+ }
+ else if (netif.GetNetworkDataLeader().IsOnMesh(ip6Header.GetDestination()))
+ {
+ SuccessOrExit(error = netif.GetAddressResolver().Resolve(ip6Header.GetDestination(), mMeshDest));
+ }
+ else
+ {
+ netif.GetNetworkDataLeader().RouteLookup(
+ ip6Header.GetSource(),
+ ip6Header.GetDestination(),
+ NULL,
+ &mMeshDest
+ );
+ }
+
+ VerifyOrExit(mMeshDest != Mac::kShortAddrInvalid, error = OT_ERROR_DROP);
+
+ mMeshSource = netif.GetMac().GetShortAddress();
+ mMacDest.mLength = sizeof(mMacDest.mShortAddress);
+
+ SuccessOrExit(error = netif.GetMle().CheckReachability(mMeshSource, mMeshDest, ip6Header));
+ mMacDest.mShortAddress = netif.GetMle().GetNextHop(mMeshDest);
+
+ if (mMacDest.mShortAddress != mMeshDest)
+ {
+ // destination is not neighbor
+ mMacSource.mLength = sizeof(mMacSource.mShortAddress);
+ mMacSource.mShortAddress = mMeshSource;
+ mAddMeshHeader = true;
+ }
+
+exit:
+ return error;
+}
+
+otError MeshForwarder::CheckReachability(uint8_t *aFrame, uint8_t aFrameLength,
+ const Mac::Address &aMeshSource, const Mac::Address &aMeshDest)
+{
+ ThreadNetif &netif = GetNetif();
+ otError error = OT_ERROR_NONE;
+ Ip6::Header ip6Header;
+ Lowpan::MeshHeader meshHeader;
+
+ VerifyOrExit(meshHeader.Init(aFrame, aFrameLength) == OT_ERROR_NONE, error = OT_ERROR_DROP);
+
+ // skip mesh header
+ aFrame += meshHeader.GetHeaderLength();
+ aFrameLength -= meshHeader.GetHeaderLength();
+
+ // skip fragment header
+ if (aFrameLength >= 1 &&
+ reinterpret_cast(aFrame)->IsFragmentHeader())
+ {
+ VerifyOrExit(sizeof(Lowpan::FragmentHeader) <= aFrameLength, error = OT_ERROR_DROP);
+ VerifyOrExit(reinterpret_cast(aFrame)->GetDatagramOffset() == 0);
+
+ aFrame += reinterpret_cast(aFrame)->GetHeaderLength();
+ aFrameLength -= reinterpret_cast(aFrame)->GetHeaderLength();
+ }
+
+ // only process IPv6 packets
+ VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame));
+
+ VerifyOrExit(netif.GetLowpan().DecompressBaseHeader(ip6Header, aMeshSource, aMeshDest, aFrame, aFrameLength) > 0,
+ error = OT_ERROR_DROP);
+
+ error = netif.GetMle().CheckReachability(aMeshSource.mShortAddress, aMeshDest.mShortAddress, ip6Header);
+
+exit:
+ return error;
+}
+
+void MeshForwarder::HandleMesh(uint8_t *aFrame, uint8_t aFrameLength, const Mac::Address &aMacSource,
+ const otThreadLinkInfo &aLinkInfo)
+{
+ ThreadNetif &netif = GetNetif();
+ otError error = OT_ERROR_NONE;
+ Message *message = NULL;
+ Mac::Address meshDest;
+ Mac::Address meshSource;
+ Lowpan::MeshHeader meshHeader;
+
+ // Check the mesh header
+ VerifyOrExit(meshHeader.Init(aFrame, aFrameLength) == OT_ERROR_NONE, error = OT_ERROR_DROP);
+
+ // Security Check: only process Mesh Header frames that had security enabled.
+ VerifyOrExit(aLinkInfo.mLinkSecurity && meshHeader.IsValid(), error = OT_ERROR_SECURITY);
+
+ meshSource.mLength = sizeof(meshSource.mShortAddress);
+ meshSource.mShortAddress = meshHeader.GetSource();
+ meshDest.mLength = sizeof(meshDest.mShortAddress);
+ meshDest.mShortAddress = meshHeader.GetDestination();
+
+ UpdateRoutes(aFrame, aFrameLength, meshSource, meshDest);
+
+ if (meshDest.mShortAddress == netif.GetMac().GetShortAddress() ||
+ netif.GetMle().IsMinimalChild(meshDest.mShortAddress))
+ {
+ aFrame += meshHeader.GetHeaderLength();
+ aFrameLength -= meshHeader.GetHeaderLength();
+
+ if (reinterpret_cast(aFrame)->IsFragmentHeader())
+ {
+ HandleFragment(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
+ }
+ else if (Lowpan::Lowpan::IsLowpanHc(aFrame))
+ {
+ HandleLowpanHC(aFrame, aFrameLength, meshSource, meshDest, aLinkInfo);
+ }
+ else
+ {
+ ExitNow(error = OT_ERROR_PARSE);
+ }
+ }
+ else if (meshHeader.GetHopsLeft() > 0)
+ {
+ netif.GetMle().ResolveRoutingLoops(aMacSource.mShortAddress, meshDest.mShortAddress);
+
+ SuccessOrExit(error = CheckReachability(aFrame, aFrameLength, meshSource, meshDest));
+
+ meshHeader.SetHopsLeft(meshHeader.GetHopsLeft() - 1);
+ meshHeader.AppendTo(aFrame);
+
+ VerifyOrExit((message = GetInstance().GetMessagePool().New(Message::kType6lowpan, 0)) != NULL,
+ error = OT_ERROR_NO_BUFS);
+ SuccessOrExit(error = message->SetLength(aFrameLength));
+ message->Write(0, aFrameLength, aFrame);
+ message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
+ message->SetPanId(aLinkInfo.mPanId);
+
+ SendMessage(*message);
+ }
+
+exit:
+
+ if (error != OT_ERROR_NONE)
+ {
+ char srcStringBuffer[Mac::Address::kAddressStringSize];
+
+ otLogInfoMac(
+ GetInstance(),
+ "Dropping rx mesh frame, error:%s, len:%d, src:%s, sec:%s",
+ otThreadErrorToString(error),
+ aFrameLength,
+ aMacSource.ToString(srcStringBuffer, sizeof(srcStringBuffer)),
+ aLinkInfo.mLinkSecurity ? "yes" : "no"
+ );
+
+ OT_UNUSED_VARIABLE(srcStringBuffer);
+
+ if (message != NULL)
+ {
+ message->Free();
+ }
+ }
+}
+
+void MeshForwarder::UpdateRoutes(uint8_t *aFrame, uint8_t aFrameLength,
+ const Mac::Address &aMeshSource, const Mac::Address &aMeshDest)
+{
+ ThreadNetif &netif = GetNetif();
+ Lowpan::MeshHeader meshHeader;
+ Ip6::Header ip6Header;
+ Neighbor *neighbor;
+
+ VerifyOrExit(meshHeader.Init(aFrame, aFrameLength) == OT_ERROR_NONE);
+
+ // skip mesh header
+ aFrame += meshHeader.GetHeaderLength();
+ aFrameLength -= meshHeader.GetHeaderLength();
+
+ // skip fragment header
+ if (aFrameLength >= 1 &&
+ reinterpret_cast(aFrame)->IsFragmentHeader())
+ {
+ VerifyOrExit(sizeof(Lowpan::FragmentHeader) <= aFrameLength);
+ VerifyOrExit(reinterpret_cast(aFrame)->GetDatagramOffset() == 0);
+
+ aFrame += reinterpret_cast(aFrame)->GetHeaderLength();
+ aFrameLength -= reinterpret_cast(aFrame)->GetHeaderLength();
+ }
+
+ // only process IPv6 packets
+ VerifyOrExit(aFrameLength >= 1 && Lowpan::Lowpan::IsLowpanHc(aFrame));
+
+ VerifyOrExit(netif.GetLowpan().DecompressBaseHeader(ip6Header, aMeshSource, aMeshDest, aFrame, aFrameLength) > 0);
+
+ neighbor = netif.GetMle().GetNeighbor(ip6Header.GetSource());
+ VerifyOrExit(neighbor != NULL && !neighbor->IsFullThreadDevice());
+
+ netif.GetAddressResolver().UpdateCacheEntry(ip6Header.GetSource(), meshHeader.GetSource());
+
+ if (Mle::Mle::GetRouterId(meshHeader.GetSource()) != Mle::Mle::GetRouterId(GetNetif().GetMac().GetShortAddress()))
+ {
+ netif.GetMle().RemoveNeighbor(*neighbor);
+ }
+
+exit:
+ return;
+}
+
+#if OPENTHREAD_ENABLE_SERVICE
+otError MeshForwarder::GetDestinationRlocByServiceAloc(uint16_t aServiceAloc, uint16_t &aMeshDest)
+{
+ otError error = OT_ERROR_NONE;
+ ThreadNetif &netif = GetNetif();
+ uint8_t serviceId = netif.GetMle().GetServiceIdFromAloc(aServiceAloc);
+ NetworkData::ServiceTlv *serviceTlv = netif.GetNetworkDataLeader().FindServiceById(serviceId);
+
+ if (serviceTlv != NULL)
+ {
+ NetworkData::NetworkDataTlv *cur = serviceTlv->GetSubTlvs();
+ NetworkData::NetworkDataTlv *end = serviceTlv->GetNext();
+ NetworkData::ServerTlv *server;
+ uint8_t bestCost = Mle::kMaxRouteCost;
+ uint8_t curCost = 0x00;
+ uint16_t bestDest = Mac::kShortAddrInvalid;
+
+ while (cur < end)
+ {
+ switch (cur->GetType())
+ {
+ case NetworkData::NetworkDataTlv::kTypeServer:
+ server = static_cast(cur);
+ curCost = netif.GetMle().GetCost(server->GetServer16());
+
+ if ((bestDest == Mac::kShortAddrInvalid) || (curCost < bestCost))
+ {
+ bestDest = server->GetServer16();
+ bestCost = curCost;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ cur = cur->GetNext();
+ }
+
+ if (bestDest != Mac::kShortAddrInvalid)
+ {
+ aMeshDest = bestDest;
+ }
+ else
+ {
+ // ServiceTLV without ServerTLV? Can't forward packet anywhere.
+ ExitNow(error = OT_ERROR_DROP);
+ }
+ }
+ else
+ {
+ // Unknown service, can't forward
+ ExitNow(error = OT_ERROR_DROP);
+ }
+
+exit:
+ return error;
+}
+#endif // OPENTHREAD_ENABLE_SERVICE
+
+} // namespace ot
+
+#endif // OPENTHREAD_FTD
diff --git a/src/core/thread/mesh_forwarder_mtd.cpp b/src/core/thread/mesh_forwarder_mtd.cpp
new file mode 100644
index 000000000..882b5a8c8
--- /dev/null
+++ b/src/core/thread/mesh_forwarder_mtd.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file implements MTD-specific mesh forwarding of IPv6/6LoWPAN messages.
+ */
+
+#if OPENTHREAD_MTD
+
+#define WPP_NAME "mesh_forwarder_mtd.tmh"
+
+#include "mesh_forwarder.hpp"
+
+namespace ot {
+
+otError MeshForwarder::SendMessage(Message &aMessage)
+{
+ otError error;
+
+ aMessage.SetDirectTransmission();
+ aMessage.SetOffset(0);
+ aMessage.SetDatagramTag(0);
+
+ SuccessOrExit(error = mSendQueue.Enqueue(aMessage));
+ mScheduleTransmissionTask.Post();
+
+exit:
+ return error;
+}
+
+otError MeshForwarder::EvictIndirectMessage(void)
+{
+ return OT_ERROR_NOT_FOUND;
+}
+
+otError MeshForwarder::GetIndirectTransmission(void)
+{
+ return OT_ERROR_NOT_FOUND;
+}
+
+otError MeshForwarder::RemoveMessageFromSleepyChild(Message &aMessage, Child &aChild)
+{
+ OT_UNUSED_VARIABLE(aMessage);
+ OT_UNUSED_VARIABLE(aChild);
+ return OT_ERROR_NOT_FOUND;
+}
+
+void MeshForwarder::HandleSentFrameToChild(const Mac::Frame &aFrame, otError aError, const Mac::Address &aMacDest)
+{
+ OT_UNUSED_VARIABLE(aFrame);
+ OT_UNUSED_VARIABLE(aError);
+ OT_UNUSED_VARIABLE(aMacDest);
+}
+
+void MeshForwarder::HandleMesh(uint8_t *aFrame, uint8_t aFrameLength, const Mac::Address &aMacSource,
+ const otThreadLinkInfo &aLinkInfo)
+{
+ OT_UNUSED_VARIABLE(aFrame);
+ OT_UNUSED_VARIABLE(aFrameLength);
+ OT_UNUSED_VARIABLE(aMacSource);
+ OT_UNUSED_VARIABLE(aLinkInfo);
+}
+
+} // namespace ot
+
+#endif // OPENTHREAD_MTD