From 5028d2f71b3d1c7a9e712ad933e75b5bdb871379 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Wed, 17 Jan 2018 20:18:09 +0000 Subject: [PATCH] [mesh-forwarder] MTD code size optimizations (#2469) --- etc/visual-studio/libopenthread.vcxproj | 2 + .../libopenthread.vcxproj.filters | 6 + etc/visual-studio/libopenthread_k.vcxproj | 2 + .../libopenthread_k.vcxproj.filters | 6 + src/core/Makefile.am | 2 + src/core/api/message_api.cpp | 5 + src/core/thread/mesh_forwarder.cpp | 1119 ++--------------- src/core/thread/mesh_forwarder.hpp | 62 +- src/core/thread/mesh_forwarder_ftd.cpp | 1014 +++++++++++++++ src/core/thread/mesh_forwarder_mtd.cpp | 92 ++ 10 files changed, 1246 insertions(+), 1064 deletions(-) create mode 100644 src/core/thread/mesh_forwarder_ftd.cpp create mode 100644 src/core/thread/mesh_forwarder_mtd.cpp 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