[mle] simplify parsing of Address Registration TLV entries (#8963)

This commit adds `ProcessAddressRegistrationTlv()` method which
finds an Address Registration TLV in a received MLE messages from
a child and processes its entries updating the child's registered
addresses.
This commit is contained in:
Abtin Keshavarzian
2023-04-17 10:00:14 -07:00
committed by GitHub
parent e63c5d321a
commit 25fe46d8dd
3 changed files with 77 additions and 133 deletions
+55 -41
View File
@@ -1785,26 +1785,28 @@ exit:
}
#endif
Error MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, uint16_t aLength, Child &aChild)
Error MleRouter::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild)
{
Error error = kErrorNone;
AddressRegistrationEntry entry;
Ip6::Address address;
Lowpan::Context context;
uint8_t registeredCount = 0;
uint8_t storedCount = 0;
uint16_t end = aOffset + aLength;
Error error;
uint16_t offset;
uint16_t length;
uint16_t endOffset;
uint8_t count = 0;
uint8_t storedCount = 0;
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
Ip6::Address oldDua;
const Ip6::Address *oldDuaPtr = nullptr;
bool hasDua = false;
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
Ip6::Address oldMlrRegisteredAddresses[kMaxChildIpAddresses - 1];
uint16_t oldMlrRegisteredAddressNum = 0;
#endif
SuccessOrExit(error = Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, offset, length));
endOffset = offset + length;
#if OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
if ((oldDuaPtr = aChild.GetDomainUnicastAddress()) != nullptr)
{
@@ -1831,36 +1833,47 @@ Error MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffset,
aChild.ClearIp6Addresses();
while (aOffset < end)
while (offset < endOffset)
{
uint8_t len;
uint8_t controlByte;
Ip6::Address address;
// read out the control field
SuccessOrExit(error = aMessage.Read(aOffset, &entry, sizeof(uint8_t)));
// Read out the control byte (first byte in entry)
SuccessOrExit(error = aRxInfo.mMessage.Read(offset, controlByte));
offset++;
count++;
len = entry.GetLength();
address.Clear();
SuccessOrExit(error = aMessage.Read(aOffset, &entry, len));
aOffset += len;
registeredCount++;
if (entry.IsCompressed())
if (AddressRegistrationTlv::IsEntryCompressed(controlByte))
{
if (Get<NetworkData::Leader>().GetContext(entry.GetContextId(), context) != kErrorNone)
// Compressed entry contains IID with the 64-bit prefix
// determined from 6LoWPAN context identifier (from
// the control byte).
uint8_t contextId = AddressRegistrationTlv::GetContextId(controlByte);
Lowpan::Context context;
VerifyOrExit(offset + sizeof(Ip6::InterfaceIdentifier) <= endOffset, error = kErrorParse);
IgnoreError(aRxInfo.mMessage.Read(offset, address.GetIid()));
offset += sizeof(Ip6::InterfaceIdentifier);
if (Get<NetworkData::Leader>().GetContext(contextId, context) != kErrorNone)
{
LogWarn("Failed to get context %u for compressed address from child 0x%04x", entry.GetContextId(),
LogWarn("Failed to get context %u for compressed address from child 0x%04x", contextId,
aChild.GetRloc16());
continue;
}
address.Clear();
address.SetPrefix(context.mPrefix);
address.SetIid(entry.GetIid());
}
else
{
address = entry.GetIp6Address();
// Uncompressed entry contains the full IPv6 address.
VerifyOrExit(offset + sizeof(Ip6::Address) <= endOffset, error = kErrorParse);
IgnoreError(aRxInfo.mMessage.Read(offset, address));
offset += sizeof(Ip6::Address);
}
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
@@ -1956,14 +1969,14 @@ Error MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffset,
Get<MlrManager>().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses, oldMlrRegisteredAddressNum);
#endif
if (registeredCount == 0)
if (count == 0)
{
LogInfo("Child 0x%04x has no registered IPv6 address", aChild.GetRloc16());
}
else
{
LogInfo("Child 0x%04x has %u registered IPv6 address%s, %u address%s stored", aChild.GetRloc16(),
registeredCount, (registeredCount == 1) ? "" : "es", storedCount, (storedCount == 1) ? "" : "es");
LogInfo("Child 0x%04x has %u registered IPv6 address%s, %u address%s stored", aChild.GetRloc16(), count,
(count == 1) ? "" : "es", storedCount, (storedCount == 1) ? "" : "es");
}
error = kErrorNone;
@@ -2088,11 +2101,7 @@ void MleRouter::HandleChildIdRequest(RxInfo &aRxInfo)
if (!mode.IsFullThreadDevice())
{
uint16_t offset;
uint16_t length;
SuccessOrExit(error = Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, offset, length));
SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, offset, length, *child));
SuccessOrExit(error = ProcessAddressRegistrationTlv(aRxInfo, *child));
}
// Remove from router table
@@ -2182,8 +2191,6 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
DeviceMode oldMode;
TlvList requestedTlvList;
TlvList tlvList;
uint16_t addrOffset;
uint16_t addrLength;
bool childDidChange = false;
Log(kMessageReceive, kTypeChildUpdateRequestOfChild, aRxInfo.mMessageInfo.GetPeerAddr());
@@ -2246,10 +2253,15 @@ void MleRouter::HandleChildUpdateRequest(RxInfo &aRxInfo)
}
// IPv6 Address TLV
if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, addrOffset, addrLength) == kErrorNone)
switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
{
SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, addrOffset, addrLength, *child));
case kErrorNone:
tlvList.Add(Tlv::kAddressRegistration);
break;
case kErrorNotFound:
break;
default:
ExitNow(error = kErrorParse);
}
// Leader Data
@@ -2404,8 +2416,6 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
uint32_t mleFrameCounter;
LeaderData leaderData;
Child *child;
uint16_t addrOffset;
uint16_t addrLength;
if ((aRxInfo.mNeighbor == nullptr) || IsActiveRouter(aRxInfo.mNeighbor->GetRloc16()) ||
!Get<ChildTable>().Contains(*aRxInfo.mNeighbor))
@@ -2517,9 +2527,13 @@ void MleRouter::HandleChildUpdateResponse(RxInfo &aRxInfo)
}
// IPv6 Address
if (Tlv::FindTlvValueOffset(aRxInfo.mMessage, Tlv::kAddressRegistration, addrOffset, addrLength) == kErrorNone)
switch (ProcessAddressRegistrationTlv(aRxInfo, *child))
{
SuccessOrExit(error = UpdateChildAddresses(aRxInfo.mMessage, addrOffset, addrLength, *child));
case kErrorNone:
case kErrorNotFound:
break;
default:
ExitNow(error = kErrorParse);
}
// Leader Data
+1
View File
@@ -630,6 +630,7 @@ private:
void SetStateRouterOrLeader(DeviceRole aRole, uint16_t aRloc16, LeaderStartMode aStartMode);
void StopLeader(void);
void SynchronizeChildNetworkData(void);
Error ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild);
Error UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, uint16_t aLength, Child &aChild);
bool HasNeighborWithGoodLinkQuality(void) const;
+21 -92
View File
@@ -999,6 +999,27 @@ public:
*/
static uint8_t ControlByteFor(uint8_t aContextId) { return kCompressed | (aContextId & kContextIdMask); }
/**
* This static method indicates whether or not an address entry is using compressed format.
*
* @param[in] aControlByte The control byte (the first byte in the entry).
*
* @retval TRUE If the entry uses compressed format.
* @retval FALSE If the entry uses uncompressed format.
*
*/
static bool IsEntryCompressed(uint8_t aControlByte) { return (aControlByte & kCompressed); }
/**
* This static method gets the context ID in a compressed entry.
*
* @param[in] aControlByte The control byte (the first byte in the entry).
*
* @returns The 6LoWPAN context ID.
*
*/
static uint8_t GetContextId(uint8_t aControlByte) { return (aControlByte & kContextIdMask); }
AddressRegistrationTlv(void) = delete;
private:
@@ -1006,98 +1027,6 @@ private:
static constexpr uint8_t kContextIdMask = 0xf;
};
/**
* This class implements Address Registration Entry generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class AddressRegistrationEntry
{
public:
/**
* This method returns the IPv6 address or IID length.
*
* @returns The IPv6 address length if the Compressed bit is clear, or the IID length if the Compressed bit is
* set.
*
*/
uint8_t GetLength(void) const { return sizeof(mControl) + (IsCompressed() ? sizeof(mIid) : sizeof(mIp6Address)); }
/**
* This method indicates whether or not the Compressed flag is set.
*
* @retval TRUE If the Compressed flag is set.
* @retval FALSE If the Compressed flag is not set.
*
*/
bool IsCompressed(void) const { return (mControl & kCompressed) != 0; }
/**
* This method sets the Uncompressed flag.
*
*/
void SetUncompressed(void) { mControl = 0; }
/**
* This method returns the Context ID for the compressed form.
*
* @returns The Context ID value.
*
*/
uint8_t GetContextId(void) const { return mControl & kCidMask; }
/**
* This method sets the Context ID value.
*
* @param[in] aContextId The Context ID value.
*
*/
void SetContextId(uint8_t aContextId) { mControl = kCompressed | aContextId; }
/**
* This method returns the IID value.
*
* @returns The IID value.
*
*/
const Ip6::InterfaceIdentifier &GetIid(void) const { return mIid; }
/**
* This method sets the IID value.
*
* @param[in] aIid The IID value.
*
*/
void SetIid(const Ip6::InterfaceIdentifier &aIid) { mIid = aIid; }
/**
* This method returns the IPv6 Address value.
*
* @returns The IPv6 Address value.
*
*/
const Ip6::Address &GetIp6Address(void) const { return mIp6Address; }
/**
* This method sets the IPv6 Address value.
*
* @param[in] aAddress A reference to the IPv6 Address value.
*
*/
void SetIp6Address(const Ip6::Address &aAddress) { mIp6Address = aAddress; }
private:
static constexpr uint8_t kCompressed = 1 << 7;
static constexpr uint8_t kCidMask = 0xf;
uint8_t mControl;
union
{
Ip6::InterfaceIdentifier mIid;
Ip6::Address mIp6Address;
} OT_TOOL_PACKED_FIELD;
} OT_TOOL_PACKED_END;
/**
* This class implements Channel TLV generation and parsing.
*