[mac] adds the wake-up identifier to the Connection IE (#11907)

The P2P peer can be woken up using the wake-up identifier. The wake-up identifier
is included in the Connection IE. This commit implements methods to the Connection IE
and Frame to process wake-up identifier.
This commit is contained in:
Zhanglong Xia
2025-10-29 02:01:19 +08:00
committed by GitHub
parent ce17d9e6a9
commit 4cced2e81e
8 changed files with 238 additions and 23 deletions
+27 -12
View File
@@ -299,11 +299,12 @@ exit:
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
bool Frame::IsWakeupFrame(void) const
{
const uint16_t fcf = GetFrameControlField();
bool result = false;
uint8_t keyIdMode;
uint8_t firstIeIndex;
Address srcAddress;
const uint16_t fcf = GetFrameControlField();
bool result = false;
uint8_t keyIdMode;
uint8_t firstIeIndex;
Address srcAddress;
const ConnectionIe *connectionIe;
// Wake-up frame is a Multipurpose frame without Ack Request...
VerifyOrExit((fcf & kFcfFrameTypeMask) == kTypeMultipurpose);
@@ -319,12 +320,12 @@ bool Frame::IsWakeupFrame(void) const
// ... that has Rendezvous Time IE and Connection IE...
VerifyOrExit(GetRendezvousTimeIe() != nullptr);
VerifyOrExit(GetConnectionIe() != nullptr);
VerifyOrExit((connectionIe = GetConnectionIe()) != nullptr);
// ... but no other IEs nor payload.
firstIeIndex = FindHeaderIeIndex();
VerifyOrExit(mPsdu + firstIeIndex + sizeof(HeaderIe) + RendezvousTimeIe::kIeContentSize + sizeof(HeaderIe) +
ConnectionIe::kIeContentSize ==
connectionIe->GetHeaderIe()->GetLength() ==
GetFooter());
result = true;
@@ -1505,26 +1506,39 @@ exit:
#endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
Error TxFrame::GenerateWakeupFrame(PanId aPanId, const Address &aDest, const Address &aSource)
Error TxFrame::GenerateWakeupFrame(PanId aPanId, const WakeupRequest &aWakeupRequest, const Address &aSource)
{
Error error = kErrorNone;
uint16_t fcf;
uint8_t secCtl;
uint8_t wakeupIdLength;
FrameBuilder builder;
Address dest;
fcf = kTypeMultipurpose | kMpFcfLongFrame | kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression |
kMpFcfIePresent;
VerifyOrExit(!aDest.IsNone() && !aSource.IsNone(), error = kErrorInvalidArgs);
VerifyOrExit(!aSource.IsNone(), error = kErrorInvalidArgs);
fcf |= DetermineFcfAddrType(aDest, kMpFcfDstAddrShift);
if (aWakeupRequest.IsWakeupByExtAddress())
{
wakeupIdLength = 0;
dest.SetExtended(aWakeupRequest.GetExtAddress());
}
else
{
wakeupIdLength = GetWakeupIdLength(aWakeupRequest.GetWakeupId());
dest.SetNone();
}
fcf |= DetermineFcfAddrType(dest, kMpFcfDstAddrShift);
fcf |= DetermineFcfAddrType(aSource, kMpFcfSrcAddrShift);
builder.Init(mPsdu, GetMtu());
IgnoreError(builder.AppendLittleEndianUint16(fcf));
IgnoreError(builder.AppendLittleEndianUint16(aPanId));
IgnoreError(builder.AppendMacAddress(aDest));
IgnoreError(builder.AppendMacAddress(dest));
IgnoreError(builder.AppendMacAddress(aSource));
secCtl = kKeyIdMode2 | kSecurityEncMic32;
@@ -1534,8 +1548,9 @@ Error TxFrame::GenerateWakeupFrame(PanId aPanId, const Address &aDest, const Add
builder.Append<HeaderIe>()->Init(RendezvousTimeIe::kHeaderIeId, sizeof(RendezvousTimeIe));
builder.Append<RendezvousTimeIe>();
builder.Append<HeaderIe>()->Init(ConnectionIe::kHeaderIeId, sizeof(ConnectionIe));
builder.Append<HeaderIe>()->Init(ConnectionIe::kHeaderIeId, sizeof(ConnectionIe) + wakeupIdLength);
builder.Append<ConnectionIe>()->Init();
builder.AppendLength(wakeupIdLength);
builder.AppendLength(CalculateMicSize(secCtl) + GetFcsSize());
+4 -4
View File
@@ -1322,14 +1322,14 @@ public:
/**
* Generate IEE 802.15.4 Wake-up frame.
*
* @param[in] aPanId A destination PAN identifier
* @param[in] aDest A destination address (short or extended)
* @param[in] aSource A source address (short or extended)
* @param[in] aPanId A destination PAN identifier
* @param[in] aWakeupRequest A const reference to the wake-up request.
* @param[in] aSource A source address (short or extended)
*
* @retval kErrorNone Successfully generated Wake-up frame.
* @retval kErrorInvalidArgs @p aDest or @p aSource have incorrect type.
*/
Error GenerateWakeupFrame(PanId aPanId, const Address &aDest, const Address &aSource);
Error GenerateWakeupFrame(PanId aPanId, const WakeupRequest &aWakeupRequest, const Address &aSource);
#endif
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
+36
View File
@@ -43,5 +43,41 @@ void HeaderIe::Init(uint16_t aId, uint8_t aLen)
SetLength(aLen);
}
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
Error ConnectionIe::SetWakeupId(WakeupId aWakeupId)
{
Error error = kErrorNone;
const HeaderIe *headerIe = GetHeaderIe();
uint8_t wakeupIdLength = GetWakeupIdLength(aWakeupId);
VerifyOrExit(headerIe->GetLength() > sizeof(ConnectionIe), error = kErrorParse);
VerifyOrExit(headerIe->GetLength() - sizeof(ConnectionIe) == wakeupIdLength, error = kErrorParse);
aWakeupId = LittleEndian::HostSwap64(aWakeupId);
memcpy(GetWakeupIdData(), reinterpret_cast<uint8_t *>(&aWakeupId), wakeupIdLength);
exit:
return error;
}
Error ConnectionIe::GetWakeupId(WakeupId &aWakeupId) const
{
Error error = kErrorNone;
const HeaderIe *headerIe = GetHeaderIe();
uint8_t wakeupIdLength;
VerifyOrExit(headerIe->GetLength() > sizeof(ConnectionIe), error = kErrorParse);
wakeupIdLength = headerIe->GetLength() - sizeof(ConnectionIe);
VerifyOrExit(wakeupIdLength <= sizeof(WakeupId), error = kErrorParse);
aWakeupId = 0;
memcpy(reinterpret_cast<uint8_t *>(&aWakeupId), GetWakeupIdData(), wakeupIdLength);
aWakeupId = LittleEndian::HostSwap64(aWakeupId);
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
} // namespace Mac
} // namespace ot
+33
View File
@@ -377,11 +377,44 @@ public:
*/
void SetRetryCount(uint8_t aRetryCount) { WriteBits<uint8_t, kRetryCountMask>(mConnectionWindow, aRetryCount); }
/**
* Sets the Wake-up Identifier.
*
* @param[in] aWakeupId The Wake-up Identifier.
*
* @retval kErrorNone Successfully set the Wake-up Identifier.
* @retval kErrorParse The length of the given Wake-up Identifier didn't match the reserved length.
*/
Error SetWakeupId(WakeupId aWakeupId);
/**
* Gets the Wake-up Identifier.
*
* @param[out] aWakeupId A reference to the Wake-up Identifier.
*
* @retval kErrorNone Successfully got the Wake-up Identifier.
* @retval kErrorParse Failed to parse the Wake-up Identifier from the Connection IE.
*/
Error GetWakeupId(WakeupId &aWakeupId) const;
/**
* Gets the pointer to the HeaderIe of this ConnectionIe.
*
* @returns A pointer to the HeaderIe.
*/
const HeaderIe *GetHeaderIe(void) const
{
return reinterpret_cast<const HeaderIe *>(reinterpret_cast<const uint8_t *>(this) - sizeof(HeaderIe));
}
private:
static constexpr uint8_t kRetryIntervalOffset = 4;
static constexpr uint8_t kRetryIntervalMask = 0x3 << kRetryIntervalOffset;
static constexpr uint8_t kRetryCountMask = 0xf;
const uint8_t *GetWakeupIdData(void) const { return reinterpret_cast<const uint8_t *>(this) + sizeof(*this); }
uint8_t *GetWakeupIdData(void) { return reinterpret_cast<uint8_t *>(this) + sizeof(*this); }
uint8_t mConnectionWindow;
} OT_TOOL_PACKED_END;
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
+22
View File
@@ -35,6 +35,7 @@
#include <stdio.h>
#include "common/bit_utils.hpp"
#include "common/code_utils.hpp"
#include "common/random.hpp"
#include "common/string.hpp"
@@ -404,6 +405,27 @@ bool KeyMaterial::operator==(const KeyMaterial &aOther) const
#endif
}
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
uint8_t GetWakeupIdLength(WakeupId aWakeupId)
{
uint8_t zeroBytesCount = 0;
for (int i = static_cast<int>(sizeof(WakeupId)) - 1; i >= 1; --i)
{
if (((aWakeupId >> (i * kBitsPerByte)) & 0xFF) == 0)
{
zeroBytesCount++;
}
else
{
break;
}
}
return sizeof(WakeupId) - zeroBytesCount;
}
#endif
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
void WakeupRequest::SetExtAddress(const ExtAddress &aExtAddress)
{
+40
View File
@@ -81,6 +81,11 @@ typedef otShortAddress ShortAddress;
constexpr ShortAddress kShortAddrBroadcast = OT_RADIO_BROADCAST_SHORT_ADDR; ///< Broadcast Short Address.
constexpr ShortAddress kShortAddrInvalid = OT_RADIO_INVALID_SHORT_ADDR; ///< Invalid Short Address.
/**
* Represents the wake-up identifier.
*/
typedef otWakeupId WakeupId;
/**
* Generates a random IEEE 802.15.4 PAN ID.
*
@@ -960,6 +965,19 @@ private:
uint8_t mUncertainty;
};
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
/**
* Gets the length of the wake-up identifier.
*
* The length is the number of bytes remaining after removing the most significant zero bytes.
*
* @param[in] aWakeupId The wake-up identifier.
*
* @returns The length of the @p aWakeupId.
*/
uint8_t GetWakeupIdLength(WakeupId aWakeupId);
#endif
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
/**
* Represents a wake-up request.
@@ -1004,6 +1022,28 @@ public:
*/
ExtAddress &GetExtAddress(void);
/**
* Gets the Wake-up Identifier of the wake-up request.
*
* MUST be used only if the wake-up request type is `kTypeWakeupId` or `kTypeGroupWakeupId`.
*
* @returns The Wake-up Identifier.
*/
WakeupId GetWakeupId(void) const { return mShared.mWakeupId; }
/**
* Sets the wake-up request with the Wake-up Identifier.
*
* The type is also updated to indicate that the wake-up request type is `kTypeWakeupId`.
*
* @param[in] aWakeupId A Wake-up Identifier.
*/
void SetWakeupId(WakeupId aWakeupId)
{
SetType(kTypeWakeupId);
mShared.mWakeupId = aWakeupId;
}
/**
* Sets the wake-up request type.
*
+2 -3
View File
@@ -80,7 +80,6 @@ void WakeupTxScheduler::RequestWakeupFrameTransmission(void) { Get<Mac::Mac>().R
Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
{
Mac::TxFrame *frame = nullptr;
Mac::Address target;
Mac::Address source;
uint32_t radioTxDelay;
uint32_t rendezvousTimeUs;
@@ -89,7 +88,6 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
VerifyOrExit(mIsRunning);
target.SetExtended(mWakeupRequest.GetExtAddress());
source.SetExtended(Get<Mac::Mac>().GetExtAddress());
VerifyOrExit(mTxTimeUs >= nowUs);
radioTxDelay = mTxTimeUs - nowUs;
@@ -100,7 +98,8 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
frame = &aTxFrames.GetTxFrame();
#endif
VerifyOrExit(frame->GenerateWakeupFrame(Get<Mac::Mac>().GetPanId(), target, source) == kErrorNone, frame = nullptr);
VerifyOrExit(frame->GenerateWakeupFrame(Get<Mac::Mac>().GetPanId(), mWakeupRequest, source) == kErrorNone,
frame = nullptr);
frame->SetTxDelayBaseTime(static_cast<uint32_t>(Get<Radio>().GetNow()));
frame->SetTxDelay(radioTxDelay);
frame->SetCsmaCaEnabled(kWakeupFrameTxCca);
+74 -4
View File
@@ -785,6 +785,7 @@ void TestMacFrameAckGeneration(void)
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
constexpr uint16_t kMpFcfLongFrame = 1 << 3;
constexpr uint16_t kMpFcfDstAddrShift = 4;
constexpr uint16_t kMpFcfDstAddrNone = 0 << kMpFcfDstAddrShift;
constexpr uint16_t kMpFcfDstAddrExt = 3 << kMpFcfDstAddrShift;
constexpr uint16_t kMpFcfSrcAddrShift = 6;
constexpr uint16_t kMpFcfSrcAddrShort = 2 << kMpFcfSrcAddrShift;
@@ -797,9 +798,10 @@ constexpr uint16_t kMpFcfIePresent = 1 << 15;
void TestMacWakeupFrameGeneration(void)
{
constexpr static uint8_t kSrcExtaddr[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
constexpr static uint8_t kDstExtaddr[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87};
constexpr static uint8_t kKeySource[] = {0, 0, 0, 0x1c};
constexpr static Mac::WakeupId kWakeupId = 0x1020;
constexpr static uint8_t kSrcExtaddr[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
constexpr static uint8_t kDstExtaddr[] = {0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87};
constexpr static uint8_t kKeySource[] = {0, 0, 0, 0x1c};
constexpr static uint8_t kWakeupPsdu[] = {
// Frame Control
@@ -818,10 +820,28 @@ void TestMacWakeupFrameGeneration(void)
// Connection IE
0x05, 0x00, 0x9b, 0xb8, 0xea, 0x01, 0x1c};
constexpr static uint8_t kWakeupPsdu2[] = {
// Frame Control
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrNone | kMpFcfSrcAddrExt,
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
// PAN ID
0xce, 0xfa,
// No Destination Address
// Source Address
0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
// Security Header
Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xfc, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x1c, 0x1d,
// Rendezvous Time IE
0x82, 0x0e, 0xcd, 0xab,
// Connection IE
0x07, 0x00, 0x9b, 0xb8, 0xea, 0x01, 0x1c, 0x20, 0x10};
uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE];
Mac::Address src;
Mac::Address dst;
Mac::Address addr;
Mac::WakeupId wakeupId;
Mac::WakeupRequest wakeupRequest;
Mac::TxFrame txFrame;
Mac::Frame rxFrame;
Mac::ConnectionIe *connectionIe;
@@ -830,11 +850,12 @@ void TestMacWakeupFrameGeneration(void)
src.SetExtended(kSrcExtaddr);
dst.SetExtended(kDstExtaddr);
wakeupRequest.SetExtAddress(dst.GetExtended());
txFrame.mPsdu = psdu;
txFrame.mLength = 0;
txFrame.mRadioType = 0;
SuccessOrQuit(txFrame.GenerateWakeupFrame(0xface, dst, src));
SuccessOrQuit(txFrame.GenerateWakeupFrame(0xface, wakeupRequest, src));
// Validate that the frame satisfies the wake-up frame definition
VerifyOrQuit(txFrame.GetType() == Mac::Frame::kTypeMultipurpose);
@@ -855,10 +876,12 @@ void TestMacWakeupFrameGeneration(void)
connectionIe = txFrame.GetConnectionIe();
connectionIe->SetRetryInterval(1);
connectionIe->SetRetryCount(12);
VerifyOrQuit(connectionIe->SetWakeupId(kWakeupId) == kErrorParse);
VerifyOrQuit(txFrame.GetRendezvousTimeIe()->GetRendezvousTime() == 0xabcd);
VerifyOrQuit(connectionIe->GetRetryInterval() == 1);
VerifyOrQuit(connectionIe->GetRetryCount() == 12);
VerifyOrQuit(connectionIe->GetWakeupId(wakeupId) == kErrorParse);
VerifyOrQuit(txFrame.GetLength() == sizeof(kWakeupPsdu) + txFrame.GetFooterLength());
VerifyOrQuit(memcmp(psdu, kWakeupPsdu, sizeof(kWakeupPsdu)) == 0);
@@ -869,6 +892,53 @@ void TestMacWakeupFrameGeneration(void)
SuccessOrQuit(rxFrame.ValidatePsdu());
VerifyOrQuit(rxFrame.IsWakeupFrame());
// Validate the wake-up frame using the wake-up identifier.
src.SetExtended(kSrcExtaddr);
wakeupRequest.SetWakeupId(kWakeupId);
txFrame.mPsdu = psdu;
txFrame.mLength = 0;
txFrame.mRadioType = 0;
SuccessOrQuit(txFrame.GenerateWakeupFrame(0xface, wakeupRequest, src));
// Validate that the frame satisfies the wake-up frame definition
VerifyOrQuit(txFrame.GetType() == Mac::Frame::kTypeMultipurpose);
VerifyOrQuit(!txFrame.GetAckRequest());
VerifyOrQuit(txFrame.GetRendezvousTimeIe() != nullptr);
VerifyOrQuit(txFrame.GetConnectionIe() != nullptr);
VerifyOrQuit(txFrame.GetPayloadLength() == 0);
SuccessOrQuit(txFrame.GetSrcAddr(addr));
VerifyOrQuit(CompareAddresses(src, addr));
SuccessOrQuit(txFrame.GetDstAddr(addr));
VerifyOrQuit(addr.IsNone());
// Initialize remaining fields and check if the frame has the expected contents
txFrame.SetFrameCounter(0xfcfcfcfc);
txFrame.SetKeySource(kKeySource);
txFrame.SetKeyId(0x1d);
txFrame.GetRendezvousTimeIe()->SetRendezvousTime(0xabcd);
connectionIe = txFrame.GetConnectionIe();
connectionIe->SetRetryInterval(1);
connectionIe->SetRetryCount(12);
SuccessOrQuit(connectionIe->SetWakeupId(kWakeupId));
VerifyOrQuit(txFrame.GetRendezvousTimeIe()->GetRendezvousTime() == 0xabcd);
VerifyOrQuit(connectionIe->GetRetryInterval() == 1);
VerifyOrQuit(connectionIe->GetRetryCount() == 12);
SuccessOrQuit(connectionIe->GetWakeupId(wakeupId));
VerifyOrQuit(wakeupId == kWakeupId);
VerifyOrQuit(wakeupRequest.GetWakeupId() == kWakeupId);
VerifyOrQuit(txFrame.GetLength() == sizeof(kWakeupPsdu2) + txFrame.GetFooterLength());
VerifyOrQuit(memcmp(psdu, kWakeupPsdu2, sizeof(kWakeupPsdu2)) == 0);
// Initialize RX Frame with the same PSDU and check if it's recognized as wake-up frame
rxFrame.mPsdu = psdu;
rxFrame.mLength = txFrame.GetLength();
rxFrame.mRadioType = 0;
SuccessOrQuit(rxFrame.ValidatePsdu());
VerifyOrQuit(rxFrame.IsWakeupFrame());
}
void TestMacWakeupFrameDetectionNegative(void)