diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index f5ccea48d..448efa8b8 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -697,7 +697,7 @@ void Mac::TransmitDoneTask(bool aRxPending, ThreadError aError) case kStateActiveScan: case kStateTransmitBeacon: - SentFrame(aError == kThreadError_None); + SentFrame(aError); break; default: @@ -770,7 +770,7 @@ void Mac::HandleMacTimer(void) case kStateTransmitData: otLogDebgMac("ack timer fired\n"); mCounters.mTxTotal++; - SentFrame(false); + SentFrame(kThreadError_NoAck); break; default: @@ -793,14 +793,20 @@ void Mac::HandleReceiveTimer(void) NextOperation(); } -void Mac::SentFrame(bool aAcked) +void Mac::SentFrame(ThreadError aError) { Frame &sendFrame(*static_cast(otPlatRadioGetTransmitBuffer(NULL))); - Address destination; Sender *sender; - if (sendFrame.GetAckRequest() && !aAcked) + switch (aError) { + case kThreadError_None: + break; + + case kThreadError_ChannelAccessFailure: + break; + + case kThreadError_NoAck: otDumpDebgMac("NO ACK", sendFrame.GetHeader(), 16); if (mTransmitAttempts < kMaxFrameAttempts) @@ -813,8 +819,11 @@ void Mac::SentFrame(bool aAcked) ExitNow(); } - sendFrame.GetDstAddr(destination); - mMle.RemoveNeighbor(destination); + break; + + default: + assert(false); + break; } mTransmitAttempts = 0; @@ -823,7 +832,7 @@ void Mac::SentFrame(bool aAcked) { mCounters.mTxAckRequested++; - if (aAcked) + if (aError == kThreadError_None) { mCounters.mTxAcked++; } @@ -866,7 +875,7 @@ void Mac::SentFrame(bool aAcked) sender->mNext = NULL; mDataSequence++; - sender->HandleSentFrame(sendFrame); + sender->HandleSentFrame(sendFrame, aError); ScheduleNextTransmission(); break; diff --git a/src/core/mac/mac.hpp b/src/core/mac/mac.hpp index 5e8553130..800b76053 100644 --- a/src/core/mac/mac.hpp +++ b/src/core/mac/mac.hpp @@ -69,7 +69,7 @@ enum kMinBE = 3, ///< macMinBE (IEEE 802.15.4-2006) kMaxBE = 6, ///< macMaxBE (IEEE 802.15.4-2006) kMaxCSMABackoffs = 4, ///< macMaxCSMABackoffs (IEEE 802.15.4-2006) - kMaxFrameRetries = 15, ///< macMaxFrameRetries (IEEE 802.15.4-2006) + kMaxFrameRetries = 3, ///< macMaxFrameRetries (IEEE 802.15.4-2006) kUnitBackoffPeriod = 20, ///< Number of symbols (IEEE 802.15.4-2006) kMinBackoff = 16, ///< Minimum backoff (milliseconds). @@ -146,9 +146,10 @@ public: * * @param[in] aContext A pointer to arbitrary context information. * @param[in] aFrame A reference to the MAC frame buffer that was sent. + * @param[in] aError The status of the last MSDU transmission. * */ - typedef void (*SentFrameHandler)(void *aContext, Frame &aFrame); + typedef void (*SentFrameHandler)(void *aContext, Frame &aFrame, ThreadError aError); /** * This constructor creates a MAC sender client. @@ -167,7 +168,7 @@ public: private: ThreadError HandleFrameRequest(Frame &frame) { return mFrameRequestHandler(mContext, frame); } - void HandleSentFrame(Frame &frame) { mSentFrameHandler(mContext, frame); } + void HandleSentFrame(Frame &frame, ThreadError error) { mSentFrameHandler(mContext, frame, error); } FrameRequestHandler mFrameRequestHandler; SentFrameHandler mSentFrameHandler; @@ -556,7 +557,7 @@ private: void ProcessTransmitSecurity(Frame &aFrame); ThreadError ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr, Neighbor *aNeighbor); void ScheduleNextTransmission(void); - void SentFrame(bool aAcked); + void SentFrame(ThreadError aError); void SendBeaconRequest(Frame &aFrame); void SendBeacon(Frame &aFrame); void StartBackoff(void); diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 53293c115..22951b833 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -1119,12 +1119,12 @@ ThreadError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame) return kThreadError_None; } -void MeshForwarder::HandleSentFrame(void *aContext, Mac::Frame &aFrame) +void MeshForwarder::HandleSentFrame(void *aContext, Mac::Frame &aFrame, ThreadError aError) { - static_cast(aContext)->HandleSentFrame(aFrame); + static_cast(aContext)->HandleSentFrame(aFrame, aError); } -void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame) +void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, ThreadError aError) { Mac::Address macDest; Child *child; @@ -1141,6 +1141,43 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame) aFrame.GetDstAddr(macDest); + if ((neighbor = mMle.GetNeighbor(macDest)) != NULL) + { + switch (aError) + { + case kThreadError_None: + neighbor->mLinkFailures = 0; + break; + + case kThreadError_ChannelAccessFailure: + break; + + case kThreadError_NoAck: + neighbor->mLinkFailures++; + + if (mMle.IsActiveRouter(neighbor->mValid.mRloc16)) + { + if (neighbor->mLinkFailures >= Mle::kFailedRouterTransmissions) + { + mMle.RemoveNeighbor(*neighbor); + } + } + else + { + if (neighbor->mLinkFailures >= Mle::kFailedChildTransmissions) + { + mMle.RemoveNeighbor(*neighbor); + } + } + + break; + + default: + assert(false); + break; + } + } + if ((child = mMle.GetChild(macDest)) != NULL) { child->mDataRequest = false; diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 779f55c3e..0aada1813 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -208,8 +208,8 @@ private: static ThreadError HandleFrameRequest(void *aContext, Mac::Frame &aFrame); ThreadError HandleFrameRequest(Mac::Frame &aFrame); - static void HandleSentFrame(void *aContext, Mac::Frame &aFrame); - void HandleSentFrame(Mac::Frame &aFrame); + static void HandleSentFrame(void *aContext, Mac::Frame &aFrame, ThreadError aError); + void HandleSentFrame(Mac::Frame &aFrame, ThreadError aError); static void HandleDiscoverTimer(void *aContext); void HandleDiscoverTimer(void); diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 2b4aee310..b07b9ba7e 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -1913,6 +1913,7 @@ ThreadError Mle::HandleParentResponse(const Message &aMessage, const Ip6::Messag mParent.mMode = ModeTlv::kModeFFD | ModeTlv::kModeRxOnWhenIdle | ModeTlv::kModeFullNetworkData; mParent.mLinkInfo.Clear(); mParent.mLinkInfo.AddRss(mMac.GetNoiseFloor(), threadMessageInfo->mRss); + mParent.mLinkFailures = 0; mParent.mState = Neighbor::kStateValid; mParent.mKeySequence = aKeySequence; diff --git a/src/core/thread/mle_constants.hpp b/src/core/thread/mle_constants.hpp index 7e7e5d984..12ee698a8 100644 --- a/src/core/thread/mle_constants.hpp +++ b/src/core/thread/mle_constants.hpp @@ -46,6 +46,7 @@ enum { kMaxChildren = OPENTHREAD_CONFIG_MAX_CHILDREN, kMaxChildKeepAliveAttempts = 4, ///< Maximum keep alive attempts before attempting to reattach to a new Parent + kFailedChildTransmissions = 4, ///< FAILED_CHILD_TRANSMISSIONS }; /** @@ -77,6 +78,7 @@ enum { kAdvertiseIntervalMin = 1, ///< ADVERTISEMENT_I_MIN (seconds) kAdvertiseIntervalMax = 32, ///< ADVERTISEMENT_I_MAX (seconds) + kFailedRouterTransmissions = 4, ///< FAILED_ROUTER_TRANSMISSIONS kRouterIdReuseDelay = 100, ///< ID_REUSE_DELAY (seconds) kRouterIdSequencePeriod = 10, ///< ID_SEQUENCE_PERIOD (seconds) kMaxNeighborAge = 100, ///< MAX_NEIGHBOR_AGE (seconds) diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index b50b62af0..8142b8d14 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -630,6 +630,7 @@ ThreadError MleRouter::HandleLinkRequest(const Message &aMessage, const Ip6::Mes memcpy(&neighbor->mMacAddr, &macAddr, sizeof(neighbor->mMacAddr)); neighbor->mLinkInfo.Clear(); neighbor->mLinkInfo.AddRss(mMac.GetNoiseFloor(), threadMessageInfo->mRss); + neighbor->mLinkFailures = 0; neighbor->mState = Neighbor::kStateLinkRequest; } else @@ -932,6 +933,7 @@ ThreadError MleRouter::HandleLinkAccept(const Message &aMessage, const Ip6::Mess neighbor->mMode = ModeTlv::kModeFFD | ModeTlv::kModeRxOnWhenIdle | ModeTlv::kModeFullNetworkData; neighbor->mLinkInfo.Clear(); neighbor->mLinkInfo.AddRss(mMac.GetNoiseFloor(), threadMessageInfo->mRss); + neighbor->mLinkFailures = 0; neighbor->mState = Neighbor::kStateValid; neighbor->mKeySequence = aKeySequence; @@ -1365,6 +1367,7 @@ ThreadError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::M memcpy(&router->mMacAddr, &macAddr, sizeof(router->mMacAddr)); router->mLinkInfo.Clear(); router->mLinkInfo.AddRss(mMac.GetNoiseFloor(), threadMessageInfo->mRss); + router->mLinkFailures = 0; router->mState = Neighbor::kStateLinkRequest; SendLinkRequest(router); ExitNow(error = kThreadError_NoRoute); @@ -1413,6 +1416,7 @@ ThreadError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::M memcpy(&router->mMacAddr, &macAddr, sizeof(router->mMacAddr)); router->mLinkInfo.Clear(); router->mLinkInfo.AddRss(mMac.GetNoiseFloor(), threadMessageInfo->mRss); + router->mLinkFailures = 0; router->mState = Neighbor::kStateLinkRequest; router->mDataRequest = false; SendLinkRequest(router); @@ -1619,6 +1623,7 @@ ThreadError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::M memcpy(&child->mMacAddr, &macAddr, sizeof(child->mMacAddr)); child->mLinkInfo.Clear(); child->mLinkInfo.AddRss(mMac.GetNoiseFloor(), threadMessageInfo->mRss); + child->mLinkFailures = 0; child->mState = Neighbor::kStateParentRequest; child->mDataRequest = false; diff --git a/src/core/thread/topology.hpp b/src/core/thread/topology.hpp index e8b709da3..60f97d4b2 100644 --- a/src/core/thread/topology.hpp +++ b/src/core/thread/topology.hpp @@ -87,6 +87,7 @@ public: State mState : 3; ///< The link state uint8_t mMode : 4; ///< The MLE device mode bool mDataRequest : 1; ///< Indicates whether or not a Data Poll was received + uint8_t mLinkFailures; ///< Consecutive link failure count LinkQualityInfo mLinkInfo; ///< Link quality info (contains average RSS, link margin and link quality) };