[mle] work around MLE Link Accept messages that are too large

This commit addresses an issue where the MLE Link Accept message may
be too large to fit within a single IEEE 802.15.4 frame. Thread
requires any MLE message transported using 6LoWPAN fragmentation to
also enable IEEE 802.15.4 MAC frame security. However, the purpose of
MLE Link Accept messages is to establish a secure link and cannot
itself be transported with IEEE 802.15.4 MAC frame security enabled.

An MLE Link Accept message may carry a Route64 TLV that has a length
dependent on the number of active routers in the network. When there
are many active routers, the Route64 TLV is large and the MLE Link
Accept message can no longer fit within a single IEEE 802.15.4
frame. The side effect is that a router coming out of reset will not
be able to diretly restore its router role and must first attach as an
end device.

This commit limits the size of a Route64 TLV when included in MLE Link
Accept messages. When the number of active routers is above a
threshold, some routers will be elided from the Route64 TLV and the
Router ID Sequence value is decremented. This allows the device coming
out of reset to restore its router role and retrieve the current
Route64 TLV in a subsequent message exchange.
This commit is contained in:
Jonathan Hui
2020-08-11 13:22:01 -07:00
parent b5e17e07ee
commit a6865e03e4
3 changed files with 66 additions and 9 deletions
+54 -7
View File
@@ -725,7 +725,7 @@ otError MleRouter::SendLinkAccept(const Ip6::MessageInfo &aMessageInfo,
switch (aRequestedTlvs.mTlvs[i])
{
case Tlv::kRoute:
SuccessOrExit(error = AppendRoute(*message));
SuccessOrExit(error = AppendRoute(*message, aNeighbor));
break;
case Tlv::kAddress16:
@@ -4139,15 +4139,62 @@ exit:
return error;
}
void MleRouter::FillRouteTlv(RouteTlv &aTlv)
void MleRouter::FillRouteTlv(RouteTlv &aTlv, Neighbor *aNeighbor)
{
uint8_t routerCount = 0;
uint8_t routerIdSequence = mRouterTable.GetRouterIdSequence();
RouterIdSet routerIdSet = mRouterTable.GetRouterIdSet();
uint8_t routerCount;
aTlv.SetRouterIdSequence(mRouterTable.GetRouterIdSequence());
aTlv.SetRouterIdMask(mRouterTable.GetRouterIdSet());
if (aNeighbor && IsActiveRouter(aNeighbor->GetRloc16()))
{
// Sending a Link Accept message that may require truncation
// of Route64 TLV
routerCount = mRouterTable.GetActiveRouterCount();
if (routerCount > RouteTlv::kLinkAcceptMaxRouters)
{
for (uint8_t routerId = 0; routerId <= kMaxRouterId; routerId++)
{
if (routerCount <= RouteTlv::kLinkAcceptMaxRouters)
{
break;
}
if ((routerId == RouterIdFromRloc16(GetRloc16())) || (routerId == aNeighbor->GetRouterId()) ||
(routerId == GetLeaderId()))
{
// Route64 TLV must contain this device and the
// neighboring router to ensure that at least this
// link can be established.
continue;
}
if (routerIdSet.Contains(routerId))
{
routerIdSet.Remove(routerId);
routerCount--;
}
}
// Ensure that the neighbor will process the current
// Route64 TLV in a subsequent message exchange
routerIdSequence -= RouteTlv::kLinkAcceptSequenceRollback;
}
}
aTlv.SetRouterIdSequence(routerIdSequence);
aTlv.SetRouterIdMask(routerIdSet);
routerCount = 0;
for (Router &router : Get<RouterTable>().Iterate())
{
if (!routerIdSet.Contains(router.GetRouterId()))
{
continue;
}
if (router.GetRloc16() == GetRloc16())
{
aTlv.SetLinkQualityIn(routerCount, 0);
@@ -4193,12 +4240,12 @@ void MleRouter::FillRouteTlv(RouteTlv &aTlv)
aTlv.SetRouteDataLength(routerCount);
}
otError MleRouter::AppendRoute(Message &aMessage)
otError MleRouter::AppendRoute(Message &aMessage, Neighbor *aNeighbor)
{
RouteTlv tlv;
tlv.Init();
FillRouteTlv(tlv);
FillRouteTlv(tlv, aNeighbor);
return tlv.AppendTo(aMessage);
}
+2 -2
View File
@@ -419,7 +419,7 @@ public:
* @param[out] aTlv A reference to the tlv to be filled.
*
*/
void FillRouteTlv(RouteTlv &aTlv);
void FillRouteTlv(RouteTlv &aTlv, Neighbor *aNeighbor = nullptr);
/**
* This method generates an MLE Child Update Request message to be sent to the parent.
@@ -582,7 +582,7 @@ private:
otError AppendConnectivity(Message &aMessage);
otError AppendChildAddresses(Message &aMessage, Child &aChild);
otError AppendRoute(Message &aMessage);
otError AppendRoute(Message &aMessage, Neighbor *aNeighbor = nullptr);
otError AppendActiveDataset(Message &aMessage);
otError AppendPendingDataset(Message &aMessage);
void HandleDetachStart(void);
+10
View File
@@ -142,6 +142,16 @@ OT_TOOL_PACKED_BEGIN
class RouteTlv : public Tlv
{
public:
enum
{
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
kLinkAcceptMaxRouters = 3,
#else
kLinkAcceptMaxRouters = 20,
#endif
kLinkAcceptSequenceRollback = 64,
};
/**
* This method initializes the TLV.
*