diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 0d33a3ea2..475609b8c 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -1487,7 +1487,7 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame) if (payloadLength >= sizeof(Lowpan::MeshHeader) && reinterpret_cast(payload)->IsMeshHeader()) { - HandleMesh(payload, payloadLength, messageInfo); + HandleMesh(payload, payloadLength, macSource, messageInfo); } else if (payloadLength >= sizeof(Lowpan::FragmentHeader) && reinterpret_cast(payload)->IsFragmentHeader()) @@ -1521,7 +1521,8 @@ exit: } } -void MeshForwarder::HandleMesh(uint8_t *aFrame, uint8_t aFrameLength, const ThreadMessageInfo &aMessageInfo) +void MeshForwarder::HandleMesh(uint8_t *aFrame, uint8_t aFrameLength, const Mac::Address &aMacSource, + const ThreadMessageInfo &aMessageInfo) { ThreadError error = kThreadError_None; Message *message = NULL; @@ -1560,6 +1561,8 @@ void MeshForwarder::HandleMesh(uint8_t *aFrame, uint8_t aFrameLength, const Thre } else if (meshHeader.GetHopsLeft() > 0) { + mMle.ResolveRoutingLoops(aMacSource.mShortAddress, meshDest.mShortAddress); + SuccessOrExit(error = CheckReachability(aFrame, aFrameLength, meshSource, meshDest)); meshHeader.SetHopsLeft(meshHeader.GetHopsLeft() - 1); diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 06ccc592f..2a4bbaa8a 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -225,7 +225,8 @@ private: ThreadError GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr); Message *GetDirectTransmission(void); Message *GetIndirectTransmission(const Child &aChild); - void HandleMesh(uint8_t *aFrame, uint8_t aPayloadLength, const ThreadMessageInfo &aMessageInfo); + void HandleMesh(uint8_t *aFrame, uint8_t aPayloadLength, const Mac::Address &aMacSource, + const ThreadMessageInfo &aMessageInfo); void HandleFragment(uint8_t *aFrame, uint8_t aPayloadLength, const Mac::Address &aMacSource, const Mac::Address &aMacDest, const ThreadMessageInfo &aMessageInfo); diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index bda6020e7..090e41fe7 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -3530,6 +3530,20 @@ exit: return error; } +void MleRouter::ResolveRoutingLoops(uint16_t aSourceMac, uint16_t aDestRloc16) +{ + if (aSourceMac == GetNextHop(aDestRloc16)) + { + // loop detected + Router *router = GetRouter(GetRouterId(aDestRloc16)); + assert(router != NULL); + + // invalidate next hop + router->mNextHop = kInvalidRouterId; + ResetAdvertiseInterval(); + } +} + ThreadError MleRouter::CheckReachability(uint16_t aMeshSource, uint16_t aMeshDest, Ip6::Header &aIp6Header) { Ip6::Address destination; diff --git a/src/core/thread/mle_router_ftd.hpp b/src/core/thread/mle_router_ftd.hpp index a4b57374e..b557cc233 100644 --- a/src/core/thread/mle_router_ftd.hpp +++ b/src/core/thread/mle_router_ftd.hpp @@ -665,6 +665,15 @@ public: */ ThreadError CheckReachability(uint16_t aMeshSource, uint16_t aMeshDest, Ip6::Header &aIp6Header); + /** + * This method resolves 2-hop routing loops. + * + * @param[in] aSourceMac The RLOC16 of the previous hop. + * @param[in] aDestRloc16 The RLOC16 of the final destination. + * + */ + void ResolveRoutingLoops(uint16_t aSourceMac, uint16_t aDestRloc16); + /** * This method checks if a given Router ID has correct value. * diff --git a/src/core/thread/mle_router_mtd.hpp b/src/core/thread/mle_router_mtd.hpp index b722fe65d..5345dca7d 100644 --- a/src/core/thread/mle_router_mtd.hpp +++ b/src/core/thread/mle_router_mtd.hpp @@ -135,6 +135,8 @@ public: static int ComparePartitions(bool, const LeaderDataTlv &, bool, const LeaderDataTlv &) { return 0; } + void ResolveRoutingLoops(uint16_t, uint16_t) { } + ThreadError CheckReachability(uint16_t aMeshSource, uint16_t aMeshDest, Ip6::Header &aIp6Header) { return Mle::CheckReachability(aMeshSource, aMeshDest, aIp6Header); }