[mle] send shorter "Child ID Request" if needed to avoid frag (#3813)

This commit addresses the attach failure issue by an SED child trying
to register multiple IPv6 addresses in MLE "Child ID Request" message.
If the MLE "Child ID Request" requires fragmentation at 6LoWPAN layer,
this commit changes the code to abort the transmission and drop the
message and instead signal to MLE layer to prepare a shorter "Child ID
Request" by only including the mesh-local address in the `Address
Registration TLV`. After the child attaches, the new code will ensure
to trigger a "Child Update Request" exchange for the child to register
the remaining IPv6 addresses with its parents.
This commit is contained in:
Abtin Keshavarzian
2019-05-16 12:23:52 -07:00
committed by Jonathan Hui
parent 06197eb7f5
commit 0b396918c1
6 changed files with 122 additions and 23 deletions
+14 -6
View File
@@ -393,15 +393,23 @@ exit:
bool Message::IsSubTypeMle(void) const
{
bool rval = false;
bool rval;
if (mBuffer.mHead.mInfo.mSubType == kSubTypeMleAnnounce ||
mBuffer.mHead.mInfo.mSubType == kSubTypeMleDiscoverRequest ||
mBuffer.mHead.mInfo.mSubType == kSubTypeMleDiscoverResponse ||
mBuffer.mHead.mInfo.mSubType == kSubTypeMleChildUpdateRequest ||
mBuffer.mHead.mInfo.mSubType == kSubTypeMleDataResponse || mBuffer.mHead.mInfo.mSubType == kSubTypeMleGeneral)
switch (mBuffer.mHead.mInfo.mSubType)
{
case kSubTypeMleGeneral:
case kSubTypeMleAnnounce:
case kSubTypeMleDiscoverRequest:
case kSubTypeMleDiscoverResponse:
case kSubTypeMleChildUpdateRequest:
case kSubTypeMleDataResponse:
case kSubTypeMleChildIdRequest:
rval = true;
break;
default:
rval = false;
break;
}
return rval;
+11 -10
View File
@@ -218,16 +218,17 @@ public:
enum
{
kSubTypeNone = 0, ///< None
kSubTypeMleAnnounce = 1, ///< MLE Announce
kSubTypeMleDiscoverRequest = 2, ///< MLE Discover Request
kSubTypeMleDiscoverResponse = 3, ///< MLE Discover Response
kSubTypeJoinerEntrust = 4, ///< Joiner Entrust
kSubTypeMplRetransmission = 5, ///< MPL next retransmission message
kSubTypeMleGeneral = 6, ///< General MLE
kSubTypeJoinerFinalizeResponse = 7, ///< Joiner Finalize Response
kSubTypeMleChildUpdateRequest = 8, ///< MLE Child Update Request
kSubTypeMleDataResponse = 9, ///< MLE Data Response
kSubTypeNone = 0, ///< None
kSubTypeMleAnnounce = 1, ///< MLE Announce
kSubTypeMleDiscoverRequest = 2, ///< MLE Discover Request
kSubTypeMleDiscoverResponse = 3, ///< MLE Discover Response
kSubTypeJoinerEntrust = 4, ///< Joiner Entrust
kSubTypeMplRetransmission = 5, ///< MPL next retransmission message
kSubTypeMleGeneral = 6, ///< General MLE
kSubTypeJoinerFinalizeResponse = 7, ///< Joiner Finalize Response
kSubTypeMleChildUpdateRequest = 8, ///< MLE Child Update Request
kSubTypeMleDataResponse = 9, ///< MLE Data Response
kSubTypeMleChildIdRequest = 10, ///< MLE Child ID Request
};
enum
+21
View File
@@ -568,6 +568,15 @@ otError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame)
{
// Enable security and try again.
mSendMessage->SetLinkSecurityEnabled(true);
if (mSendMessage->GetSubType() == Message::kSubTypeMleChildIdRequest)
{
otLogNoteMac("Child ID Request requires fragmentation, aborting tx");
mMessageNextOffset = mSendMessage->GetLength();
error = OT_ERROR_ABORT;
ExitNow();
}
error = SendFragment(*mSendMessage, aFrame);
}
@@ -1136,6 +1145,18 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, otError aError)
if (mSendMessage->GetDirectTransmission() == false && mSendMessage->IsChildPending() == false)
{
if (mSendMessage->GetSubType() == Message::kSubTypeMleChildIdRequest && mSendMessage->IsLinkSecurityEnabled())
{
// If the Child ID Request requires fragmentation and therefore
// link layer security, the frame transmission will be aborted.
// When the message is being freed, we signal to MLE to prepare a
// shorter Child ID Request message (by only including mesh-local
// address in the Address Registration TLV).
otLogInfoMac("Requesting shorter `Child ID Request`");
Get<Mle::Mle>().RequestShorterChildIdRequest();
}
mSendQueue.Dequeue(*mSendMessage);
mSendMessage->Free();
mSendMessage = NULL;
+50 -6
View File
@@ -85,6 +85,7 @@ Mle::Mle(Instance &aInstance)
, mChildUpdateRequestState(kChildUpdateRequestNone)
, mDataRequestAttempts(0)
, mDataRequestState(kDataRequestNone)
, mAddressRegistrationMode(kAppendAllAddresses)
, mParentLinkMargin(0)
, mParentIsSingleton(false)
, mReceivedResponseFromParent(false)
@@ -1302,12 +1303,13 @@ otError Mle::AppendVersion(Message &aMessage)
return aMessage.AppendTlv(tlv);
}
otError Mle::AppendAddressRegistration(Message &aMessage)
otError Mle::AppendAddressRegistration(Message &aMessage, AddressRegistrationMode aMode)
{
otError error = OT_ERROR_NONE;
Tlv tlv;
AddressRegistrationEntry entry;
Lowpan::Context context;
bool done = false;
uint8_t length = 0;
uint8_t counter = 0;
uint16_t startOffset = aMessage.GetLength();
@@ -1315,7 +1317,6 @@ otError Mle::AppendAddressRegistration(Message &aMessage)
tlv.SetType(Tlv::kAddressRegistration);
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(tlv)));
// write entries to message
for (const Ip6::NetifUnicastAddress *addr = Get<ThreadNetif>().GetUnicastAddresses(); addr; addr = addr->GetNext())
{
if (addr->GetAddress().IsLinkLocal() || IsRoutingLocator(addr->GetAddress()) ||
@@ -1324,6 +1325,17 @@ otError Mle::AppendAddressRegistration(Message &aMessage)
continue;
}
if (aMode == kAppendMeshLocalOnly)
{
if (addr->GetAddress() != GetMeshLocal64())
{
continue;
}
// Set `done` to `true` to exit after the address is appended.
done = true;
}
if (Get<NetworkData::Leader>().GetContext(addr->GetAddress(), context) == OT_ERROR_NONE)
{
// compressed entry
@@ -1341,7 +1353,7 @@ otError Mle::AppendAddressRegistration(Message &aMessage)
length += entry.GetLength();
counter++;
// only continue to append if there is available entry.
VerifyOrExit(counter < OPENTHREAD_CONFIG_IP_ADDRS_TO_REGISTER);
VerifyOrExit(!done && (counter < OPENTHREAD_CONFIG_IP_ADDRS_TO_REGISTER));
}
// For sleepy end device, register external multicast addresses to the parent for indirect transmission
@@ -1450,6 +1462,21 @@ void Mle::HandleStateChanged(otChangedFlags aFlags)
{
VerifyOrExit(mRole != OT_DEVICE_ROLE_DISABLED);
if (aFlags & OT_CHANGED_THREAD_ROLE)
{
if (mRole == OT_DEVICE_ROLE_CHILD && !IsFullThreadDevice() && mAddressRegistrationMode == kAppendMeshLocalOnly)
{
// If only mesh-local address was registered in the "Child
// ID Request" message, after device is attached, trigger a
// "Child Update Request" to register the remaining
// addresses.
mAddressRegistrationMode = kAppendAllAddresses;
mChildUpdateRequestState = kChildUpdateRequestPending;
ScheduleMessageTransmissionTimer();
}
}
if ((aFlags & (OT_CHANGED_IP6_ADDRESS_ADDED | OT_CHANGED_IP6_ADDRESS_REMOVED)) != 0)
{
if (!Get<ThreadNetif>().IsUnicastAddress(mMeshLocal64.GetAddress()))
@@ -1954,6 +1981,15 @@ exit:
return error;
}
void Mle::RequestShorterChildIdRequest(void)
{
if (mAttachState == kAttachStateChildIdRequest)
{
mAddressRegistrationMode = kAppendMeshLocalOnly;
SendChildIdRequest();
}
}
otError Mle::SendChildIdRequest(void)
{
otError error = OT_ERROR_NONE;
@@ -1981,6 +2017,7 @@ otError Mle::SendChildIdRequest(void)
}
VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS);
message->SetSubType(Message::kSubTypeMleChildIdRequest);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandChildIdRequest));
SuccessOrExit(error = AppendResponse(*message, mChildIdRequest.mChallenge, mChildIdRequest.mChallengeLength));
SuccessOrExit(error = AppendLinkFrameCounter(*message));
@@ -1991,7 +2028,7 @@ otError Mle::SendChildIdRequest(void)
if (!IsFullThreadDevice())
{
SuccessOrExit(error = AppendAddressRegistration(*message));
SuccessOrExit(error = AppendAddressRegistration(*message, mAddressRegistrationMode));
// no need to request the last Route64 TLV for MTD
tlvsLen -= 1;
@@ -2007,8 +2044,15 @@ otError Mle::SendChildIdRequest(void)
destination.mFields.m16[0] = HostSwap16(0xfe80);
destination.SetIid(mParentCandidate.GetExtAddress());
SuccessOrExit(error = SendMessage(*message, destination));
LogMleMessage("Send Child ID Request", destination);
;
if (mAddressRegistrationMode == kAppendMeshLocalOnly)
{
LogMleMessage("Send Child ID Request - short", destination);
}
else
{
LogMleMessage("Send Child ID Request", destination);
}
if (!IsRxOnWhenIdle())
{
+25 -1
View File
@@ -1072,6 +1072,16 @@ public:
*/
void RegisterParentResponseStatsCallback(otThreadParentResponseCallback aCallback, void *aContext);
/**
* This method requests MLE layer to prepare and send a shorter version of Child ID Request message by only
* including the mesh-local IPv6 address in the Address Registration TLV.
*
* This method should be called when a previous MLE Child ID Request message would require fragmentation at 6LoWPAN
* layer.
*
*/
void RequestShorterChildIdRequest(void);
protected:
/**
* States during attach (when searching for a parent).
@@ -1105,6 +1115,17 @@ protected:
kMleMaxResponseDelay = 1000u, ///< Maximum delay before responding to a multicast request.
};
/**
* This enumeration type is used in `AppendAddressRegistration()` to determine which addresses to include in the
* appended Address Registration TLV.
*
*/
enum AddressRegistrationMode
{
kAppendAllAddresses, ///< Append all addresses (unicast/multicast) in Address Registration TLV.
kAppendMeshLocalOnly, ///< Only append the Mesh Local (ML-EID) address in Address Registration TLV.
};
/**
* This method allocates a new message buffer for preparing an MLE message.
*
@@ -1323,12 +1344,13 @@ protected:
* This method appends an Address Registration TLV to a message.
*
* @param[in] aMessage A reference to the message.
* @param[in] aMode Determines which addresses to include in the TLV (see `AddressRegistrationMode`).
*
* @retval OT_ERROR_NONE Successfully appended the Address Registration TLV.
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to append the Address Registration TLV.
*
*/
otError AppendAddressRegistration(Message &aMessage);
otError AppendAddressRegistration(Message &aMessage, AddressRegistrationMode aMode = kAppendAllAddresses);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
@@ -1755,6 +1777,8 @@ private:
uint8_t mDataRequestAttempts;
DataRequestState mDataRequestState;
AddressRegistrationMode mAddressRegistrationMode;
uint8_t mParentLinkMargin;
bool mParentIsSingleton;
bool mReceivedResponseFromParent;
+1
View File
@@ -2089,6 +2089,7 @@ otError MleRouter::HandleChildIdRequest(const Message & aMessage,
// Remove existing MLE messages
Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleGeneral);
Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleChildIdRequest);
Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleChildUpdateRequest);
Get<MeshForwarder>().RemoveMessages(*child, Message::kSubTypeMleDataResponse);