diff --git a/src/core/diags/README.md b/src/core/diags/README.md
index 9ec39c2cfed..b2fbd6f36a6 100644
--- a/src/core/diags/README.md
+++ b/src/core/diags/README.md
@@ -80,13 +80,14 @@ Done
### diag frame
-Usage: `diag frame [-c] [-p TX_POWER] [-s] `
+Usage: `diag frame [-c] [-p TX_POWER] [-s] [-u] `
Set the frame (hex encoded) to be used by `diag send` and `diag repeat`. The frame may be overwritten by `diag send` and `diag repeat`.
-- Specify `-s` to indicate that tx security is already processed so that it should be skipped in the radio layer.
- Specify `-c` to enable CSMA/CA for this frame in the radio layer.
- Specify `-p` to specify the tx power in dBm for this frame.
+- Specify `-s` to indicate that tx security is already processed so that it should be skipped in the radio layer.
+- Specify `-u` to specify the `mInfo.mTxInfo.mIsHeaderUpdated` filed for this frame.
```bash
> diag frame 11223344
diff --git a/src/core/diags/factory_diags.cpp b/src/core/diags/factory_diags.cpp
index ab88579f34d..6a42c7b619f 100644
--- a/src/core/diags/factory_diags.cpp
+++ b/src/core/diags/factory_diags.cpp
@@ -213,6 +213,7 @@ Diags::Diags(Instance &aInstance)
void Diags::ResetTxPacket(void)
{
+ mIsHeaderUpdated = false;
mTxPacket->mInfo.mTxInfo.mTxDelayBaseTime = 0;
mTxPacket->mInfo.mTxInfo.mTxDelay = 0;
mTxPacket->mInfo.mTxInfo.mMaxCsmaBackoffs = 0;
@@ -232,6 +233,7 @@ Error Diags::ProcessFrame(uint8_t aArgsLength, char *aArgs[])
uint16_t size = OT_RADIO_FRAME_MAX_SIZE;
bool securityProcessed = false;
bool csmaCaEnabled = false;
+ bool isHeaderUpdated = false;
int8_t txPower = OT_RADIO_POWER_INVALID;
while (aArgsLength > 1)
@@ -239,6 +241,7 @@ Error Diags::ProcessFrame(uint8_t aArgsLength, char *aArgs[])
if (StringMatch(aArgs[0], "-s"))
{
securityProcessed = true;
+ isHeaderUpdated = true;
}
else if (StringMatch(aArgs[0], "-p"))
{
@@ -255,6 +258,10 @@ Error Diags::ProcessFrame(uint8_t aArgsLength, char *aArgs[])
{
csmaCaEnabled = true;
}
+ else if (StringMatch(aArgs[0], "-u"))
+ {
+ isHeaderUpdated = true;
+ }
else
{
ExitNow(error = kErrorInvalidArgs);
@@ -276,6 +283,7 @@ Error Diags::ProcessFrame(uint8_t aArgsLength, char *aArgs[])
mTxPacket->mInfo.mTxInfo.mTxPower = txPower;
mTxPacket->mLength = size;
mIsTxPacketSet = true;
+ mIsHeaderUpdated = isHeaderUpdated;
exit:
AppendErrorResult(error);
@@ -514,7 +522,13 @@ void Diags::TransmitPacket(void)
{
mTxPacket->mChannel = mChannel;
- if (!mIsTxPacketSet)
+ if (mIsTxPacketSet)
+ {
+ // The `mInfo.mTxInfo.mIsHeaderUpdated` field may be updated by the radio driver after the frame is sent,
+ // set the `mInfo.mTxInfo.mIsHeaderUpdated` field before transmitting the frame.
+ mTxPacket->mInfo.mTxInfo.mIsHeaderUpdated = mIsHeaderUpdated;
+ }
+ else
{
ResetTxPacket();
mTxPacket->mLength = mTxLen;
diff --git a/src/core/diags/factory_diags.hpp b/src/core/diags/factory_diags.hpp
index a3f87042c2c..6d6ac6bc302 100644
--- a/src/core/diags/factory_diags.hpp
+++ b/src/core/diags/factory_diags.hpp
@@ -218,9 +218,10 @@ class Diags : public InstanceLocator, private NonCopyable
uint8_t mChannel;
int8_t mTxPower;
uint8_t mTxLen;
- bool mIsTxPacketSet;
- bool mRepeatActive;
- bool mDiagSendOn;
+ bool mIsHeaderUpdated : 1;
+ bool mIsTxPacketSet : 1;
+ bool mRepeatActive : 1;
+ bool mDiagSendOn : 1;
#endif
otDiagOutputCallback mOutputCallback;
diff --git a/src/lib/spinel/radio_spinel.cpp b/src/lib/spinel/radio_spinel.cpp
index 36b8dfb3f88..d7606ff6aff 100644
--- a/src/lib/spinel/radio_spinel.cpp
+++ b/src/lib/spinel/radio_spinel.cpp
@@ -1582,10 +1582,8 @@ void RadioSpinel::HandleTransmitDone(uint32_t aCommand,
error = SpinelStatusToOtError(status);
}
- static_cast(mTransmitFrame)->SetIsHeaderUpdated(headerUpdated);
-
- if ((sRadioCaps & OT_RADIO_CAPS_TRANSMIT_SEC) && headerUpdated &&
- static_cast(mTransmitFrame)->GetSecurityEnabled())
+ if ((sRadioCaps & OT_RADIO_CAPS_TRANSMIT_SEC) && (!mTransmitFrame->mInfo.mTxInfo.mIsHeaderUpdated) &&
+ headerUpdated && static_cast(mTransmitFrame)->GetSecurityEnabled())
{
uint8_t keyId;
uint32_t frameCounter;
@@ -1602,6 +1600,8 @@ void RadioSpinel::HandleTransmitDone(uint32_t aCommand,
#endif
}
+ static_cast(mTransmitFrame)->SetIsHeaderUpdated(headerUpdated);
+
exit:
// A parse error indicates an RCP misbehavior, so recover the RCP immediately.
mState = kStateTransmitDone;