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)
};