[discover-scan] simplify and enhance discovery response parsing (#12293)

This commit enhances the parsing of discovery response messages in
`DiscoverScanner::HandleDiscoveryResponse()`.

The parsing logic is updated to first restrict the message to the
content of the `Discovery` TLV. This allows for a simpler and more
robust processing of the nested MeshCoP sub-TLVs. Instead of looping
through all sub-TLVs, the new approach directly looks for each expected
sub-TLV.

This change provides a clearer distinction between required TLVs
(`DiscoveryResponseTlv`, `ExtendedPanIdTlv`, `NetworkNameTlv`) and
optional ones. The handling of optional TLVs like `JoinerUdpPortTlv`
and `SteeringDataTlv` is improved to explicitly manage the case where
they are not found.

Additionally, this commit includes minor cleanups to `SteeringDataTlv`
to simplify its implementation.
This commit is contained in:
Abtin Keshavarzian
2026-01-14 10:20:20 -08:00
committed by GitHub
parent f4816375c0
commit 41ecb75b83
2 changed files with 56 additions and 70 deletions
+2 -5
View File
@@ -349,15 +349,12 @@ public:
*
* @returns The Steering Data length.
*/
uint8_t GetSteeringDataLength(void) const
{
return GetLength() <= sizeof(mSteeringData) ? GetLength() : sizeof(mSteeringData);
}
uint8_t GetSteeringDataLength(void) const { return Min<uint8_t>(GetLength(), SteeringData::kMaxLength); }
/**
* Sets all bits in the Bloom Filter to zero.
*/
void Clear(void) { memset(mSteeringData, 0, GetSteeringDataLength()); }
void Clear(void) { ClearAllBytes(mSteeringData); }
/**
* Copies the Steering Data from the TLV into a given `SteeringData` variable.
+54 -65
View File
@@ -317,19 +317,24 @@ exit:
void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const
{
Error error = kErrorNone;
ScanResult result;
OffsetRange offsetRange;
Tlv::ParsedInfo tlvInfo;
bool didCheckSteeringData = false;
Error error = kErrorNone;
ScanResult result;
OffsetRange offsetRange;
MeshCoP::DiscoveryResponseTlvValue respTlvValue;
MeshCoP::SteeringDataTlv steeringDataTlv;
Mle::Log(Mle::kMessageReceive, Mle::kTypeDiscoveryResponse, aRxInfo.mMessageInfo.GetPeerAddr());
VerifyOrExit(mState == kStateScanning, error = kErrorDrop);
// Find MLE Discovery TLV
// Find MLE Discovery TLV and restrict the message to this TLV value,
// so we can parse all the included MeshCoP sub-TLVs within this TLV.
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aRxInfo.mMessage, Tlv::kDiscovery, offsetRange));
aRxInfo.mMessage.SetOffset(offsetRange.GetOffset());
IgnoreError(aRxInfo.mMessage.SetLength(offsetRange.GetEndOffset()));
ClearAllBytes(result);
result.mDiscover = true;
result.mPanId = aRxInfo.mMessage.GetPanId();
@@ -339,68 +344,52 @@ void DiscoverScanner::HandleDiscoveryResponse(Mle::RxInfo &aRxInfo) const
AsCoreType(&result.mExtAddress).SetFromIid(aRxInfo.mMessageInfo.GetPeerAddr().GetIid());
for (; !offsetRange.IsEmpty(); offsetRange.AdvanceOffset(tlvInfo.GetSize()))
// Required TLVs
SuccessOrExit(error = Tlv::Find<MeshCoP::DiscoveryResponseTlv>(aRxInfo.mMessage, respTlvValue));
result.mVersion = respTlvValue.GetVersion();
result.mIsNative = respTlvValue.GetNativeCommissionerFlag();
SuccessOrExit(error = Tlv::Find<MeshCoP::ExtendedPanIdTlv>(aRxInfo.mMessage, AsCoreType(&result.mExtendedPanId)));
SuccessOrExit(error = Tlv::Find<MeshCoP::NetworkNameTlv>(aRxInfo.mMessage, result.mNetworkName.m8));
// Optional TLVs
switch (Tlv::Find<MeshCoP::JoinerUdpPortTlv>(aRxInfo.mMessage, result.mJoinerUdpPort))
{
SuccessOrExit(error = tlvInfo.ParseFrom(aRxInfo.mMessage, offsetRange));
if (tlvInfo.mIsExtended)
{
continue;
}
switch (tlvInfo.mType)
{
case MeshCoP::Tlv::kDiscoveryResponse:
{
MeshCoP::DiscoveryResponseTlvValue respTlvValue;
SuccessOrExit(error = Tlv::Read<MeshCoP::DiscoveryResponseTlv>(aRxInfo.mMessage, offsetRange.GetOffset(),
respTlvValue));
result.mVersion = respTlvValue.GetVersion();
result.mIsNative = respTlvValue.GetNativeCommissionerFlag();
break;
}
case MeshCoP::Tlv::kExtendedPanId:
SuccessOrExit(error = Tlv::Read<MeshCoP::ExtendedPanIdTlv>(aRxInfo.mMessage, offsetRange.GetOffset(),
AsCoreType(&result.mExtendedPanId)));
break;
case MeshCoP::Tlv::kNetworkName:
SuccessOrExit(error = Tlv::Read<MeshCoP::NetworkNameTlv>(aRxInfo.mMessage, offsetRange.GetOffset(),
result.mNetworkName.m8));
break;
case MeshCoP::Tlv::kSteeringData:
if (!tlvInfo.mValueOffsetRange.IsEmpty())
{
MeshCoP::SteeringData &steeringData = AsCoreType(&result.mSteeringData);
OffsetRange valueOffsetRange = tlvInfo.mValueOffsetRange;
valueOffsetRange.ShrinkLength(MeshCoP::SteeringData::kMaxLength);
IgnoreError(steeringData.Init(static_cast<uint8_t>(valueOffsetRange.GetLength())));
aRxInfo.mMessage.ReadBytes(valueOffsetRange, steeringData.GetData());
if (mEnableFiltering)
{
VerifyOrExit(steeringData.Contains(mFilterIndexes));
}
didCheckSteeringData = true;
}
break;
case MeshCoP::Tlv::kJoinerUdpPort:
SuccessOrExit(error = Tlv::Read<MeshCoP::JoinerUdpPortTlv>(aRxInfo.mMessage, offsetRange.GetOffset(),
result.mJoinerUdpPort));
break;
default:
break;
}
case kErrorNone:
break;
case kErrorNotFound:
result.mJoinerUdpPort = 0;
break;
default:
ExitNow(error = kErrorParse);
}
VerifyOrExit(!mEnableFiltering || didCheckSteeringData);
switch (Tlv::FindTlv(aRxInfo.mMessage, steeringDataTlv))
{
case kErrorNone:
if (steeringDataTlv.IsValid())
{
MeshCoP::SteeringData &steeringData = AsCoreType(&result.mSteeringData);
IgnoreError(steeringDataTlv.CopyTo(steeringData));
if (mEnableFiltering)
{
VerifyOrExit(steeringData.Contains(mFilterIndexes));
}
}
break;
case kErrorNotFound:
VerifyOrExit(!mEnableFiltering);
break;
default:
ExitNow(error = kErrorParse);
}
mCallback.InvokeIfSet(&result);