mirror of
https://github.com/espressif/openthread.git
synced 2026-08-30 22:09:54 +00:00
[mac-frame] update GenerateEnhAck() to use InitMacHeader() (#9338)
This commit updates the `GenerateEnhAck()` method to add checks to validate the received frame before preparing the ACK. These checks are added as a safeguard in case the caller (radio platform implementation) does not validate the received frame before calling this method to generate the ACK. Specifically, the checks verify that the received frame is using the 2015 version, has the "Ack Request" flag, has a valid source address (which is used as the destination in the generated ACK), and has a valid destination address that is not broadcast. The checks also verify that if the received frame is secured, it uses security level `kSecurityEncMic32`. The commit also simplifies the code by using `InitMacHeader()` to prepare the header and addresses. Enhanced ACK frames always have a destination address and no source address (to keep the frame shorter). If the received frame has a source PAN ID, it is used in the ACK frame. If it does not, the code checks if the received frame has a destination PAN ID and uses that in the ACK frame.
This commit is contained in:
+76
-93
@@ -239,6 +239,8 @@ void Frame::InitMacHeader(Type aType,
|
||||
|
||||
uint16_t Frame::GetFrameControlField(void) const { return ReadUint16(mPsdu); }
|
||||
|
||||
void Frame::SetFrameControlField(uint16_t aFcf) { WriteUint16(aFcf, mPsdu); }
|
||||
|
||||
Error Frame::ValidatePsdu(void) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
@@ -275,6 +277,22 @@ void Frame::SetFramePending(bool aFramePending)
|
||||
}
|
||||
}
|
||||
|
||||
void Frame::SetIePresent(bool aIePresent)
|
||||
{
|
||||
uint16_t fcf = GetFrameControlField();
|
||||
|
||||
if (aIePresent)
|
||||
{
|
||||
fcf |= kFcfIePresent;
|
||||
}
|
||||
else
|
||||
{
|
||||
fcf &= ~kFcfIePresent;
|
||||
}
|
||||
|
||||
SetFrameControlField(fcf);
|
||||
}
|
||||
|
||||
uint8_t Frame::FindDstPanIdIndex(void) const
|
||||
{
|
||||
uint8_t index;
|
||||
@@ -1090,7 +1108,7 @@ Error Frame::InitIeHeaderAt(uint8_t &aIndex, uint8_t ieId, uint8_t ieContentSize
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
WriteUint16(GetFrameControlField() | kFcfIePresent, mPsdu);
|
||||
SetIePresent(true);
|
||||
|
||||
if (aIndex == 0)
|
||||
{
|
||||
@@ -1386,115 +1404,80 @@ void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending)
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
Error TxFrame::GenerateEnhAck(const RxFrame &aFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength)
|
||||
Error TxFrame::GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
Address address;
|
||||
PanId panId;
|
||||
Addresses addrs;
|
||||
PanIds panIds;
|
||||
uint8_t securityLevel = kSecurityNone;
|
||||
uint8_t keyIdMode = kKeyIdMode0;
|
||||
|
||||
uint16_t fcf;
|
||||
Address address;
|
||||
PanId panId;
|
||||
uint8_t footerLength;
|
||||
uint8_t securityControlField;
|
||||
uint8_t keyId;
|
||||
// Validate the received frame.
|
||||
|
||||
fcf = static_cast<uint16_t>(kTypeAck) | static_cast<uint16_t>(kVersion2015) | kFcfSrcAddrNone;
|
||||
VerifyOrExit(aRxFrame.IsVersion2015(), error = kErrorParse);
|
||||
VerifyOrExit(aRxFrame.GetAckRequest(), error = kErrorParse);
|
||||
|
||||
mChannel = aFrame.mChannel;
|
||||
// Check `aRxFrame` has a valid destination address. The ack frame
|
||||
// will not use this as its source though and will always use no
|
||||
// source address.
|
||||
|
||||
SuccessOrExit(error = aRxFrame.GetDstAddr(address));
|
||||
VerifyOrExit(!address.IsNone() && !address.IsBroadcast(), error = kErrorParse);
|
||||
|
||||
// Check `aRxFrame` has a valid source, which is then used as
|
||||
// ack frames destination.
|
||||
|
||||
SuccessOrExit(error = aRxFrame.GetSrcAddr(addrs.mDestination));
|
||||
VerifyOrExit(!addrs.mDestination.IsNone(), error = kErrorParse);
|
||||
|
||||
if (aRxFrame.GetSecurityEnabled())
|
||||
{
|
||||
SuccessOrExit(error = aRxFrame.GetSecurityLevel(securityLevel));
|
||||
VerifyOrExit(securityLevel == kSecurityEncMic32, error = kErrorParse);
|
||||
|
||||
SuccessOrExit(error = aRxFrame.GetKeyIdMode(keyIdMode));
|
||||
}
|
||||
|
||||
if (aRxFrame.IsSrcPanIdPresent())
|
||||
{
|
||||
SuccessOrExit(error = aRxFrame.GetSrcPanId(panId));
|
||||
panIds.SetDestination(panId);
|
||||
}
|
||||
else if (aRxFrame.IsDstPanIdPresent())
|
||||
{
|
||||
SuccessOrExit(error = aRxFrame.GetDstPanId(panId));
|
||||
panIds.SetDestination(panId);
|
||||
}
|
||||
|
||||
// Prepare the ack frame
|
||||
|
||||
mChannel = aRxFrame.mChannel;
|
||||
memset(&mInfo.mTxInfo, 0, sizeof(mInfo.mTxInfo));
|
||||
|
||||
// Set frame control field
|
||||
if (aIsFramePending)
|
||||
InitMacHeader(kTypeAck, kVersion2015, addrs, panIds, static_cast<SecurityLevel>(securityLevel),
|
||||
static_cast<KeyIdMode>(keyIdMode));
|
||||
|
||||
SetFramePending(aIsFramePending);
|
||||
SetIePresent(aIeLength != 0);
|
||||
SetSequence(aRxFrame.GetSequence());
|
||||
|
||||
if (aRxFrame.GetSecurityEnabled())
|
||||
{
|
||||
fcf |= kFcfFramePending;
|
||||
}
|
||||
uint8_t keyId;
|
||||
|
||||
if (aFrame.GetSecurityEnabled())
|
||||
{
|
||||
fcf |= kFcfSecurityEnabled;
|
||||
}
|
||||
|
||||
if (aFrame.IsPanIdCompressed())
|
||||
{
|
||||
fcf |= kFcfPanidCompression;
|
||||
}
|
||||
|
||||
// Destination address mode
|
||||
if ((aFrame.GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrExt)
|
||||
{
|
||||
fcf |= kFcfDstAddrExt;
|
||||
}
|
||||
else if ((aFrame.GetFrameControlField() & kFcfSrcAddrMask) == kFcfSrcAddrShort)
|
||||
{
|
||||
fcf |= kFcfDstAddrShort;
|
||||
}
|
||||
else
|
||||
{
|
||||
fcf |= kFcfDstAddrNone;
|
||||
}
|
||||
|
||||
if (aIeLength > 0)
|
||||
{
|
||||
fcf |= kFcfIePresent;
|
||||
}
|
||||
|
||||
WriteUint16(fcf, mPsdu);
|
||||
|
||||
// Set sequence number
|
||||
mPsdu[kSequenceIndex] = aFrame.GetSequence();
|
||||
|
||||
if (IsDstPanIdPresent())
|
||||
{
|
||||
// Set address field
|
||||
if (aFrame.IsSrcPanIdPresent())
|
||||
{
|
||||
SuccessOrExit(error = aFrame.GetSrcPanId(panId));
|
||||
}
|
||||
else if (aFrame.IsDstPanIdPresent())
|
||||
{
|
||||
SuccessOrExit(error = aFrame.GetDstPanId(panId));
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = kErrorParse);
|
||||
}
|
||||
|
||||
SetDstPanId(panId);
|
||||
}
|
||||
|
||||
if (aFrame.IsSrcAddrPresent())
|
||||
{
|
||||
SuccessOrExit(error = aFrame.GetSrcAddr(address));
|
||||
SetDstAddr(address);
|
||||
}
|
||||
|
||||
// At this time the length of ACK hasn't been determined, set it to
|
||||
// `kMaxPsduSize` to call methods that check frame length
|
||||
mLength = kMaxPsduSize;
|
||||
|
||||
// Set security header
|
||||
if (aFrame.GetSecurityEnabled())
|
||||
{
|
||||
SuccessOrExit(error = aFrame.GetSecurityControlField(securityControlField));
|
||||
SuccessOrExit(error = aFrame.GetKeyId(keyId));
|
||||
|
||||
VerifyOrExit((securityControlField & kSecLevelMask) == kSecurityEncMic32, error = kErrorParse);
|
||||
|
||||
SetSecurityControlField(securityControlField);
|
||||
SuccessOrExit(error = aRxFrame.GetKeyId(keyId));
|
||||
SetKeyId(keyId);
|
||||
}
|
||||
|
||||
// Set header IE
|
||||
if (aIeLength > 0)
|
||||
{
|
||||
OT_ASSERT(aIeData != nullptr);
|
||||
memcpy(&mPsdu[FindHeaderIeIndex()], aIeData, aIeLength);
|
||||
mLength += aIeLength;
|
||||
}
|
||||
|
||||
// Set frame length
|
||||
footerLength = GetFooterLength();
|
||||
OT_ASSERT(footerLength != kInvalidIndex);
|
||||
mLength = SkipSecurityHeaderIndex() + aIeLength + footerLength;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -504,6 +504,14 @@ public:
|
||||
*/
|
||||
bool IsIePresent(void) const { return (GetFrameControlField() & kFcfIePresent) != 0; }
|
||||
|
||||
/**
|
||||
* Sets the IE Present bit.
|
||||
*
|
||||
* @param[in] aIePresent The IE Present bit.
|
||||
*
|
||||
*/
|
||||
void SetIePresent(bool aIePresent);
|
||||
|
||||
/**
|
||||
* Returns the Sequence Number value.
|
||||
*
|
||||
@@ -1122,6 +1130,7 @@ protected:
|
||||
static constexpr uint8_t kMaxPsduSize = kInvalidSize - 1;
|
||||
static constexpr uint8_t kSequenceIndex = kFcfSize;
|
||||
|
||||
void SetFrameControlField(uint16_t aFcf);
|
||||
uint8_t FindDstPanIdIndex(void) const;
|
||||
uint8_t FindDstAddrIndex(void) const;
|
||||
uint8_t FindSrcPanIdIndex(void) const;
|
||||
@@ -1148,8 +1157,6 @@ protected:
|
||||
static uint8_t CalculateAddrFieldSize(uint16_t aFcf);
|
||||
static uint8_t CalculateSecurityHeaderSize(uint8_t aSecurityControl);
|
||||
static uint8_t CalculateMicSize(uint8_t aSecurityControl);
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1502,16 +1509,16 @@ public:
|
||||
/**
|
||||
* Generate Enh-Ack in this frame object.
|
||||
*
|
||||
* @param[in] aFrame A reference to the frame received.
|
||||
* @param[in] aRxFrame A reference to the received frame.
|
||||
* @param[in] aIsFramePending Value of the ACK's frame pending bit.
|
||||
* @param[in] aIeData A pointer to the IE data portion of the ACK to be sent.
|
||||
* @param[in] aIeLength The length of IE data portion of the ACK to be sent.
|
||||
*
|
||||
* @retval kErrorNone Successfully generated Enh Ack.
|
||||
* @retval kErrorParse @p aFrame has incorrect format.
|
||||
* @retval kErrorParse @p aRxFrame has incorrect format.
|
||||
*
|
||||
*/
|
||||
Error GenerateEnhAck(const RxFrame &aFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength);
|
||||
Error GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength);
|
||||
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
|
||||
/**
|
||||
|
||||
@@ -747,13 +747,14 @@ void TestMacFrameAckGeneration(void)
|
||||
uint8_t ie_data[6] = {0x04, 0x0d, 0x21, 0x0c, 0x35, 0x0c};
|
||||
Mac::CslIe *csl;
|
||||
|
||||
IgnoreError(ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data)));
|
||||
SuccessOrQuit(ackFrame.GenerateEnhAck(receivedFrame, false, ie_data, sizeof(ie_data)));
|
||||
|
||||
csl = reinterpret_cast<Mac::CslIe *>(ackFrame.GetHeaderIe(Mac::CslIe::kHeaderIeId) + sizeof(Mac::HeaderIe));
|
||||
VerifyOrQuit(ackFrame.mLength == 23);
|
||||
VerifyOrQuit(ackFrame.mLength == 25);
|
||||
VerifyOrQuit(ackFrame.GetType() == Mac::Frame::kTypeAck);
|
||||
VerifyOrQuit(ackFrame.GetSecurityEnabled());
|
||||
VerifyOrQuit(ackFrame.IsIePresent());
|
||||
VerifyOrQuit(!ackFrame.IsDstPanIdPresent());
|
||||
VerifyOrQuit(ackFrame.IsDstPanIdPresent());
|
||||
VerifyOrQuit(ackFrame.IsDstAddrPresent());
|
||||
VerifyOrQuit(!ackFrame.IsSrcAddrPresent());
|
||||
VerifyOrQuit(ackFrame.GetVersion() == Mac::Frame::kVersion2015);
|
||||
|
||||
Reference in New Issue
Block a user