[mle] validate peer extended address in Link Accept (#13207)

This commit ensures that the peer's extended address matches the stored
extended address when receiving a Link Accept for an already valid link,
preventing unintended frame counter resets and neighbor table updates.

To achieve this:
- We validate that the peer's extended address (extracted from the
  IPv6 peer address IID) matches the router's stored extended address
  when processing Link Accepts for a neighbor that is already in the
  kStateValid state. If there is a mismatch, the packet is rejected
  with kErrorSecurity.
- We gate InitNeighbor() and the resetting of MLE frame counters
  so they only execute if the neighbor is not already kStateValid.
  For valid neighbors, we only update link statistics (RSS, last
  heard, link quality, key sequence) and clear the Link Accept
  timeout without modifying the frame counters or average RSS history.
This commit is contained in:
Jonathan Hui
2026-06-04 13:33:07 -07:00
committed by GitHub
parent b72d7144ee
commit c4a85578f5
+26 -11
View File
@@ -903,6 +903,7 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
LeaderData leaderData;
uint8_t linkMargin;
bool shouldUpdateRoutes = false;
Mac::ExtAddress extAddress;
SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
@@ -928,6 +929,8 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
break;
case Neighbor::kStateValid:
extAddress.SetFromIid(aRxInfo.mMessageInfo.GetPeerAddr().GetIid());
VerifyOrExit(router->GetExtAddress() == extAddress, error = kErrorSecurity);
break;
default:
@@ -1042,20 +1045,32 @@ void Mle::HandleLinkAcceptVariant(RxInfo &aRxInfo, MessageType aMessageType)
OT_ASSERT(false);
}
InitNeighbor(*router, aRxInfo);
router->SetRloc16(sourceAddress);
router->GetLinkFrameCounters().SetAll(linkFrameCounter);
router->SetLinkAckFrameCounter(linkFrameCounter);
router->SetMleFrameCounter(mleFrameCounter);
router->SetVersion(version);
router->SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
DeviceMode::kModeFullNetworkData));
if (neighborState != Neighbor::kStateValid)
{
InitNeighbor(*router, aRxInfo);
router->SetRloc16(sourceAddress);
router->GetLinkFrameCounters().SetAll(linkFrameCounter);
router->SetLinkAckFrameCounter(linkFrameCounter);
router->SetMleFrameCounter(mleFrameCounter);
router->SetDeviceMode(DeviceMode(DeviceMode::kModeFullThreadDevice | DeviceMode::kModeRxOnWhenIdle |
DeviceMode::kModeFullNetworkData));
router->SetKeySequence(aRxInfo.mKeySequence);
router->SetState(Neighbor::kStateValid);
}
else
{
router->GetLinkInfo().AddRss(aRxInfo.mMessage.GetAverageRss());
router->SetLastHeard(TimerMilli::GetNow());
}
router->SetLinkQualityOut(LinkQualityForLinkMargin(linkMargin));
router->SetState(Neighbor::kStateValid);
router->SetKeySequence(aRxInfo.mKeySequence);
router->SetVersion(version);
router->ClearLinkAcceptTimeout();
mNeighborTable.Signal(NeighborTable::kRouterAdded, *router);
if (neighborState != Neighbor::kStateValid)
{
mNeighborTable.Signal(NeighborTable::kRouterAdded, *router);
}
mDelayedSender.RemoveScheduledLinkRequest(*router);