[mac] multipurpose wake-up frame support (#10728)

1. Add OT_WAKEUP_COORDINATOR and OT_WAKEUP_END_DEVICE build
   options.
2. Add support for parsing and constructing 802.15.4
   Multipurpose frames.
3. Add support for parsing and constructing wake-up
   frames.
This commit is contained in:
Damian Królik
2024-09-23 09:02:15 -07:00
committed by GitHub
parent b605bb993e
commit bc50521cfa
11 changed files with 887 additions and 148 deletions
+216
View File
@@ -787,6 +787,218 @@ void TestMacFrameAckGeneration(void)
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
}
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
constexpr uint16_t kMpFcfLongFrame = 1 << 3;
constexpr uint16_t kMpFcfDstAddrShift = 4;
constexpr uint16_t kMpFcfDstAddrExt = 3 << kMpFcfDstAddrShift;
constexpr uint16_t kMpFcfSrcAddrShift = 6;
constexpr uint16_t kMpFcfSrcAddrShort = 2 << kMpFcfSrcAddrShift;
constexpr uint16_t kMpFcfSrcAddrExt = 3 << kMpFcfSrcAddrShift;
constexpr uint16_t kMpFcfPanidPresent = 1 << 8;
constexpr uint16_t kMpFcfSecurityEnabled = 1 << 9;
constexpr uint16_t kMpFcfSequenceSuppression = 1 << 10;
constexpr uint16_t kMpFcfAckRequest = 1 << 14;
constexpr uint16_t kMpFcfIePresent = 1 << 15;
void TestMacWakeupFrameGeneration(void)
{
constexpr static uint8_t srcExtaddr[] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
constexpr static uint8_t dstExtaddr[] = {0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD};
constexpr static uint8_t keySource[] = {0, 0, 0, 0x1C};
constexpr static uint8_t wakeupPsdu[] = {
// Frame Control
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
// PAN ID
0xCE, 0xFA,
// Destination Address
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
// Source Address
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
// 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
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C};
uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE];
Mac::Address src;
Mac::Address dst;
Mac::Address addr;
Mac::TxFrame txFrame;
Mac::Frame rxFrame;
Mac::ConnectionIe *connectionIe;
printf("TestMacWakeupFrameGeneration\n");
src.SetExtended(srcExtaddr);
dst.SetExtended(dstExtaddr);
txFrame.mPsdu = psdu;
txFrame.mLength = 0;
txFrame.mRadioType = 0;
SuccessOrQuit(txFrame.GenerateWakeupFrame(0xface, dst, 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(CompareAddresses(dst, addr));
// Initialize remaining fields and check if the frame has the expected contents
txFrame.SetFrameCounter(0xFCFCFCFC);
txFrame.SetKeySource(keySource);
txFrame.SetKeyId(0x1D);
txFrame.GetRendezvousTimeIe()->SetRendezvousTime(0xABCD);
connectionIe = txFrame.GetConnectionIe();
connectionIe->SetRetryInterval(1);
connectionIe->SetRetryCount(12);
VerifyOrQuit(txFrame.GetRendezvousTimeIe()->GetRendezvousTime() == 0xABCD);
VerifyOrQuit(connectionIe->GetRetryInterval() == 1);
VerifyOrQuit(connectionIe->GetRetryCount() == 12);
VerifyOrQuit(txFrame.GetLength() == sizeof(wakeupPsdu) + txFrame.GetFooterLength());
VerifyOrQuit(memcmp(psdu, wakeupPsdu, sizeof(wakeupPsdu)) == 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)
{
struct TestCase
{
uint8_t *mPsdu;
uint8_t mLength;
};
uint8_t ackRequestedPsdu[] = {
// Frame Control
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfAckRequest | kMpFcfIePresent) >>
8,
// PAN ID
0xCE, 0xFA,
// Destination Address
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
// Source Address
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
// 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
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
// Footer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t shortAddressPsdu[] = {
// Frame Control
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrShort,
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
// PAN ID
0xCE, 0xFA,
// Destination Address
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
// Source Address
0x55, 0x55,
// 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
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
// Footer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t noRendezvousIePsdu[] = {
// Frame Control
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
// PAN ID
0xCE, 0xFA,
// Destination Address
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
// Source Address
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
// Security Header
Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x1C, 0x1D,
// Connection IE
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
// Footer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t noConnectionIePsdu[] = {
// Frame Control
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
// PAN ID
0xCE, 0xFA,
// Destination Address
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
// Source Address
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
// 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
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x02, 0x1C,
// Footer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t keyIdMode1Psdu[] = {
// Frame Control
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
// PAN ID
0xCE, 0xFA,
// Destination Address
0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
// Source Address
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
// Security Header
Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecurityEncMic32, 0xFC, 0xFC, 0xFC, 0xFC, 0x1D,
// Rendezvous Time IE
0x82, 0x0E, 0xCD, 0xAB,
// Connection IE
0x05, 0x00, 0x9B, 0xB8, 0xEA, 0x01, 0x1C,
// Footer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const TestCase testCases[] = {
{ackRequestedPsdu, sizeof(ackRequestedPsdu)}, {shortAddressPsdu, sizeof(shortAddressPsdu)},
{noRendezvousIePsdu, sizeof(noRendezvousIePsdu)}, {noConnectionIePsdu, sizeof(noConnectionIePsdu)},
{keyIdMode1Psdu, sizeof(keyIdMode1Psdu)},
};
Mac::Frame rxFrame;
printf("TestMacWakeupFrameDetectionNegative\n");
for (const TestCase &testCase : testCases)
{
rxFrame.mPsdu = testCase.mPsdu;
rxFrame.mLength = testCase.mLength;
rxFrame.mRadioType = 0;
SuccessOrQuit(rxFrame.ValidatePsdu());
VerifyOrQuit(!rxFrame.IsWakeupFrame());
}
}
#endif
} // namespace ot
int main(void)
@@ -796,6 +1008,10 @@ int main(void)
ot::TestMacChannelMask();
ot::TestMacFrameApi();
ot::TestMacFrameAckGeneration();
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
ot::TestMacWakeupFrameGeneration();
ot::TestMacWakeupFrameDetectionNegative();
#endif
printf("All tests passed\n");
return 0;
}