Compare commits

...

12 Commits

Author SHA1 Message Date
Jonathan Hui b678a4f63b [lowpan] check datagramSize in Decompress and DecompressUdpHeader (#13276)
This commit adds robust bounds validation checks inside the lowpan
decompression routines to prevent potential integer underflows.

Specifically:
- In Lowpan::Decompress, we ensure that the declared datagramSize is
  large enough to contain the IPv6 header being decompressed at the
  current offset. This prevents underflow during recursive calls
  (e.g., for tunneled packets) when the datagram size is smaller
  than the combined headers.
- In Lowpan::DecompressUdpHeader, we verify that the remaining
  datagram length is sufficient to fit a UDP header, preventing
  underflow when calculating the UDP length from the offset.
2026-07-03 22:49:06 -07:00
Abtin Keshavarzian 3481946bfa [mac-frame] simplify FCF flag changes using UpdateFcfFlag (#13282)
This commit introduces a private helper method `UpdateFcfFlag()` in
`Mac::Frame` to consolidate repetitive Frame Control Field (FCF)
flag modification logic across MAC frame setters.
2026-07-03 21:16:45 -07:00
Abtin Keshavarzian 471460c610 [radio] define OT_CONFIG_RADIO_TIME_ENABLE derived configuration (#13280)
This commit defines `OT_CONFIG_RADIO_TIME_ENABLE` as a derived internal
configuration macro in `radio.hpp`. It consolidates conditional checks
for features that depend on radio clock time (CSL receiver/transmitter,
wakeup, and time synchronization).
2026-07-03 21:06:16 -07:00
Abtin Keshavarzian a4bf4f9899 [mac] add dynamic HeaderIe building with StartIe() and EndIe() (#13291)
This commit introduces dynamic Header IE generation in `HeaderIe`
using `StartIe()`, `EndIe()`, and `Bookmark`. It allows appending
variable-length Header IEs directly into a `FrameBuilder` without
pre-computing the IE length.

It also adds unit test case `TestMacHeaderIeStartEnd()` in
`test_mac_frame.cpp` covering normal usage, empty IEs, max length
(127 bytes), and error cases for the new methods.
2026-07-03 21:03:22 -07:00
Abtin Keshavarzian ef9c8de3cd [bit-utils] un-inline CountBitsInMask helper method (#13286)
This commit replaces the template function `CountBitsInMask<UintType>`
with a non-template function `CountBitsInMask(uint32_t)` in `bit_utils.hpp`
and moves its implementation to `bit_utils.cpp`.

Un-inlining this helper function avoids template instantiation overhead
and reduces binary size across translation units. Small integer arguments
(`uint8_t`, `uint16_t`) automatically promote to `uint32_t`, preserving
existing functionality.
2026-07-03 21:00:06 -07:00
Chenfan Zhang e4930db19d [dns] fix otDnsEncodeTxtData parameter type mismatch (#13288)
This commit fixes a parameter type mismatch between declaration and
implementation of function `otDnsEncodeTxtData()`.

`include/openthread/dns.h` provides an API `otDnsEncodeTxtData()` for
encoding TXT record entries list into TXT data, which is implemented
in `src/core/api/dns_api.cpp`. The problem is, `otDnsEncodeTxtData()`
is declared with `uint16_t aNumTxtEntries` in the public header, but
defined with `uint8_t aNumTxtEntries` in the implementation. This
mismatch can lead to symbol/ABI inconsistency for C callers and causes
link failure in downstream integrations.

This commit changes the type of parameter `aNumTxtEntries` in cpp
implementation from `uint8_t` to `uint16_t`, to follow up type
definitions in the declaration and later called
`Dns::TxtEntry::AppendEntries()`. So that downstream integrations will
not run into link failure when using `otDnsEncodeTxtData()`.
2026-07-03 16:05:21 -07:00
Suvesh Pratapa 63f325229b [crypto] add platform AES-CCM* one-shot hook (#13190)
When OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE is set,
AesCcm::Engine::ProcessOneShot() calls the new weak platform hook:

  otPlatCryptoAesCcmProcessOneShot()

The hook operates in-place on a contiguous [payload|tag] buffer,
mapping to a one-shot PSA AEAD call or a packet-oriented hardware engine.

Default weak implementations:
- PSA path: psa_aead_encrypt / psa_aead_decrypt (one-shot).
- mbedTLS path: mbedtls_ccm_encrypt_and_tag / mbedtls_ccm_auth_decrypt,
  both support in-place (input == output).
2026-07-03 16:02:01 -07:00
xusiyu adac57a6e8 [crypto] align LinkRaw MAC key exportability with KeyManager (#13277)
This change completes a previously unfinished part of the "MAC keys
must be exportable" fix. `KeyManager` already applies an explicit
exportable policy (`kExportableMacKeys`) when updating MAC keys, but
`LinkRaw::SetMacKey()` still relied on `SetFrom(...,
aIsExportable=false)` by default, which made key import permissions
inconsistent across code paths.

On RCP paths with `OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE`,
MAC key bytes from host spinel are re-imported on RCP as key
references before being passed to the platform radio. If those key
references are not created with export permission as required by
`OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE`, the platform
can fail to retrieve key material when setting MAC keys, which can
break subsequent 802.15.4 security processing.

This patch introduces a shared `Mac::kDefaultMacKeysExportable` policy
(derived from `OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE`)
and uses it in both `KeyManager` and `LinkRaw`, so MAC key import
behavior stays consistent whenever
`OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE` is enabled.
2026-07-03 13:33:54 -07:00
Abtin Keshavarzian e299ad29e4 [mac] rename TxFrame::Info to TxFrame::BuildInfo (#13289)
This commit renames `TxFrame::Info` to `TxFrame::BuildInfo` across the
MAC module, message framer, and related tests.

Renaming this structure to `BuildInfo` explicitly conveys its purpose
as the specification used to construct/build headers for transmission,
distinguishing it from parsed frame header metadata.
2026-07-03 13:17:47 -07:00
Abtin Keshavarzian 1d4900609d [bit-utils] add DetermineMinBitSizeFor helper method (#13287)
This commit adds `DetermineMinBitSizeFor(uint32_t)` to calculate and
return the minimum number of bits required to represent a given
32-bit unsigned integer value.

It also adds unit tests for this in `test_bit_utils.cpp`.
2026-07-03 13:13:42 -07:00
Abtin Keshavarzian a56a79bcb7 [mac-frame] remove Multipurpose frame format support (#13281)
This commit removes the Multipurpose (MP) frame format support
(`OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME`) and associated
wake-up frame handling.

Multipurpose frame support was originally added as a provisional and
experimental solution for the Wakeup Coordinator / Wake-up End Device
(WED) wake mechanism. However, updated Thread specification designs
decided against using the Multipurpose frame format for wake frames.
Removing this now obsolete MP frame logic cleans up and simplifies
MAC frame parsing and generation ahead of implementing the updated
wake mechanism.

Key changes:
- Removes `OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME` from `mac.h` and
  adds an `#error` check in `openthread-core-config-check.h`.
- Simplifies `Mac::Frame` control field (FCF) parsing and helper methods
  by removing MP-specific frame handling and template helpers.
- Replaces legacy MP wake-up frame helpers in `mac_frame.cpp` with
  temporary placeholder stubs.
- Cleans up unit tests in `test_mac_frame.cpp` related to MP frame
  format.
- Removes the now obsolete `v1_5-cli-p2p-link.exp` test.
2026-07-03 12:53:32 -07:00
Abtin Keshavarzian 4c44ff1edb [radio] introduce dedicated RadioTime types to clarify clock domain (#13268)
This commit introduces dedicated type definitions `otRadioTime64`
(`RadioTime64`) and `otRadioTime32` (`RadioTime32`) to represent radio
hardware microsecond timestamps.

Key benefits and changes:
- Self-Documenting Clock Domain: Transceiver hardware clocks operate in a
  distinct clock domain (`otPlatRadioGetNow()`) from core system timers
  (`TimerMilli::GetNow()`, `TimerMicro::GetNow()`). Using dedicated
  types prevents developers from accidentally passing core system time
  into radio scheduling APIs.
- Explicit Rollover Handling: Introduced `IsRadioTimeStrictlyBefore()` to
  compare 32-bit radio timestamps using modulo serial arithmetic, cleanly
  accounting for `uint32_t` microsecond counter wrap-around.
- Core Module Adoption: Updated `otRadioFrame::mTxInfo` / `mRxInfo`,
  `otPlatRadioGetNow()`, `otPlatRadioReceiveAt()`, `SubMac`, and
  `CslTxScheduler` to adopt the new radio time types.
2026-07-03 12:32:11 -07:00
57 changed files with 1097 additions and 1135 deletions
+19
View File
@@ -107,6 +107,25 @@ jobs:
cmake --build --preset simulation
ctest --preset simulation
cmake-presets-ccm-one-shot:
runs-on: ubuntu-24.04
steps:
- name: Harden Runner
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
submodules: recursive
- name: Bootstrap
run: |
sudo apt-get --no-install-recommends install -y build-essential ninja-build libreadline-dev libncurses-dev
- name: Build and test with platform CCM one-shot enabled
run: |
cmake --preset simulation -DOT_CRYPTO_CCM_ONE_SHOT=ON
cmake --build --preset simulation
ctest --preset simulation
cmake-version:
runs-on: ubuntu-24.04
steps:
+1
View File
@@ -307,6 +307,7 @@ endif()
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
set(OT_CRYPTO_LIB_VALUES "MBEDTLS" "PSA" "PLATFORM")
ot_multi_option(OT_CRYPTO_LIB OT_CRYPTO_LIB_VALUES OPENTHREAD_CONFIG_CRYPTO_LIB OPENTHREAD_CONFIG_CRYPTO_LIB_ "set Crypto backend library")
ot_option(OT_CRYPTO_CCM_ONE_SHOT OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE "platform one-shot AES-CCM* hook")
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
set(OT_THREAD_VERSION_VALUES "1.1" "1.2" "1.3" "1.3.1" "1.4")
+2 -2
View File
@@ -1041,7 +1041,7 @@ exit:
}
#endif
uint64_t otPlatRadioGetNow(otInstance *aInstance)
otRadioTime64 otPlatRadioGetNow(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
@@ -1109,7 +1109,7 @@ otError otPlatRadioResetCsl(otInstance *aInstance)
return OT_ERROR_NONE;
}
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, otRadioTime32 aCslSampleTime)
{
OT_UNUSED_VARIABLE(aInstance);
+1 -1
View File
@@ -345,7 +345,7 @@ typedef struct otRadioContext
otExtAddress mExtAddress; ///< In little-endian byte order.
uint32_t mMacFrameCounter;
uint32_t mPrevMacFrameCounter;
uint32_t mCslSampleTime; ///< The sample time based on the microsecond timer.
otRadioTime32 mCslSampleTime; ///< The sample time based on the microsecond timer.
uint16_t mCslPeriod; ///< In unit of 10 symbols.
otShortAddress mCslShortAddress; ///< The short address of the CSL receiver's peer.
otExtAddress mCslExtAddress; ///< The extended address of the CSL receiver's peer.
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (609)
#define OPENTHREAD_API_VERSION (610)
/**
* @addtogroup api-instance
+45
View File
@@ -749,6 +749,51 @@ otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword,
uint16_t aKeyLen,
uint8_t *aKey);
/**
* @struct otPlatCryptoAesCcmConfig
*
* Holds the parameters for a one-shot AES-CCM* operation passed to `otPlatCryptoAesCcmProcessOneShot`.
*/
typedef struct otPlatCryptoAesCcmConfig
{
otCryptoKey mKey; ///< The encryption key.
const uint8_t *mNonce; ///< Pointer to the nonce buffer (IEEE 802.15.4 CCM* format, 13 bytes).
uint8_t mNonceLength; ///< Length of @p mNonce in bytes.
uint8_t mTagLength; ///< Authentication tag length in bytes (even)
uint32_t mHeaderLength; ///< Length of the additional authenticated data (header) in bytes.
uint32_t mPlainTextLength; ///< Payload length in bytes (excluding tag).
} otPlatCryptoAesCcmConfig;
/**
* Performs in-place AES-CCM* authenticated encryption or decryption in a single call.
*
* For encryption (@p aEncrypt == true):
* - Plaintext at @p aData is replaced with ciphertext in-place.
* - The authentication tag is written to @p aData + @p aConfig->mPlainTextLength.
*
* For decryption (@p aEncrypt == false):
* - Ciphertext at @p aData is replaced with plaintext in-place.
* - The tag to verify must be at @p aData + @p aConfig->mPlainTextLength.
*
* Requires `OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE`.
*
* Default weak mbedTLS and PSA implementations are provided.
*
* @param[in] aEncrypt True to encrypt and generate tag; false to decrypt and verify tag.
* @param[in] aConfig CCM* parameters (key, nonce, lengths).
* @param[in] aHeader Additional authenticated data (not encrypted). May be NULL if header length is 0.
* @param[in,out] aData Payload buffer (plaintext on encrypt entry, ciphertext on decrypt entry).
* The buffer must hold @p aConfig->mPlainTextLength + @p aConfig->mTagLength bytes.
*
* @retval OT_ERROR_NONE Success.
* @retval OT_ERROR_SECURITY Tag mismatch (decrypt only).
* @retval OT_ERROR_FAILED Operation failed.
*/
otError otPlatCryptoAesCcmProcessOneShot(bool aEncrypt,
const otPlatCryptoAesCcmConfig *aConfig,
const uint8_t *aHeader,
uint8_t *aData);
/**
* @}
*/
+25 -6
View File
@@ -183,6 +183,25 @@ struct otExtAddress
*/
typedef struct otExtAddress otExtAddress;
/**
* Represents a 64-bit radio time in microseconds referenced to a continuous monotonic local radio clock.
*
* This type is returned by `otPlatRadioGetNow()` and is used as the timestamp field (`mTimestamp`) in radio frames
* (`otRadioFrame`).
*/
typedef uint64_t otRadioTime64;
/**
* Represents a 32-bit radio time in microseconds.
*
* This type holds the lower 32 bits (least significant bits) of a full 64-bit radio time (`otRadioTime64`).
*
* It is used in APIs such as `otPlatRadioReceiveAt()` and `otPlatRadioUpdateCslSampleTime()` and as the transmission
* delay base time (`mTxDelayBaseTime`) in `otRadioFrame`. It is important for radio platform implementations to
* correctly account for its roll-over.
*/
typedef uint32_t otRadioTime32;
#define OT_MAC_KEY_SIZE 16 ///< Size of the MAC Key in bytes.
/**
@@ -273,7 +292,7 @@ typedef struct otRadioFrame
*
* This field does not affect CCA behavior which is controlled by `mCsmaCaEnabled`.
*/
uint32_t mTxDelayBaseTime;
otRadioTime32 mTxDelayBaseTime;
/**
* The delay time in microseconds for this transmission referenced
@@ -381,7 +400,7 @@ typedef struct otRadioFrame
*
* The platform should update this field before otPlatRadioTxStarted() is fired for each transmit attempt.
*/
uint64_t mTimestamp;
otRadioTime64 mTimestamp;
} mTxInfo;
/**
@@ -393,7 +412,7 @@ typedef struct otRadioFrame
* The time of the local radio clock in microseconds when the end of
* the SFD was present at the local antenna.
*/
uint64_t mTimestamp;
otRadioTime64 mTimestamp;
uint32_t mAckFrameCounter; ///< ACK security frame counter (applicable when `mAckedWithSecEnhAck` is set).
uint8_t mAckKeyId; ///< ACK security key index (applicable when `mAckedWithSecEnhAck` is set).
@@ -765,7 +784,7 @@ void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacF
* @returns The current time in microseconds. UINT64_MAX when platform does not
* support or radio time is not ready.
*/
uint64_t otPlatRadioGetNow(otInstance *aInstance);
otRadioTime64 otPlatRadioGetNow(otInstance *aInstance);
/**
* Get the bus speed in bits/second between the host and the radio chip.
@@ -894,7 +913,7 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel);
* @retval OT_ERROR_NONE Successfully scheduled receive window.
* @retval OT_ERROR_FAILED The receive window could not be scheduled. For example, if @p aStart is in the past.
*/
otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration);
otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, otRadioTime32 aStart, uint32_t aDuration);
/**
* The radio driver calls this function to notify OpenThread of a received frame.
@@ -1225,7 +1244,7 @@ otError otPlatRadioResetCsl(otInstance *aInstance);
* the time when the first symbol of the MHR of
* the frame is expected.
*/
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime);
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, otRadioTime32 aCslSampleTime);
/**
* Get the current estimated worst case accuracy (maximum ± deviation from the
+4
View File
@@ -196,6 +196,10 @@ build_all_features()
reset_source
"$(dirname "$0")"/cmake-build simulation -DOT_BLE_TCAT=ON
# Build with platform CCM one-shot enabled
reset_source
"$(dirname "$0")"/cmake-build simulation -DOT_CRYPTO_CCM_ONE_SHOT=ON
}
build_nest_common()
+3
View File
@@ -663,6 +663,8 @@ openthread_core_files = [
"radio/radio.hpp",
"radio/radio_callbacks.cpp",
"radio/radio_platform.cpp",
"radio/radio_types.cpp",
"radio/radio_types.hpp",
"radio/trel_interface.cpp",
"radio/trel_interface.hpp",
"radio/trel_link.cpp",
@@ -857,6 +859,7 @@ openthread_radio_sources = [
"radio/radio.cpp",
"radio/radio_callbacks.cpp",
"radio/radio_platform.cpp",
"radio/radio_types.cpp",
"thread/link_quality.cpp",
"utils/parse_cmdline.cpp",
"utils/power_calibration.cpp",
+2
View File
@@ -224,6 +224,7 @@ set(COMMON_SOURCES
radio/radio.cpp
radio/radio_callbacks.cpp
radio/radio_platform.cpp
radio/radio_types.cpp
radio/trel_interface.cpp
radio/trel_link.cpp
radio/trel_packet.cpp
@@ -339,6 +340,7 @@ set(RADIO_COMMON_SOURCES
radio/radio.cpp
radio/radio_callbacks.cpp
radio/radio_platform.cpp
radio/radio_types.cpp
thread/link_quality.cpp
utils/otns.cpp
utils/parse_cmdline.cpp
+1 -1
View File
@@ -49,7 +49,7 @@ otError otDnsGetNextTxtEntry(otDnsTxtEntryIterator *aIterator, otDnsTxtEntry *aE
}
otError otDnsEncodeTxtData(const otDnsTxtEntry *aTxtEntries,
uint8_t aNumTxtEntries,
uint16_t aNumTxtEntries,
uint8_t *aTxtData,
uint16_t *aTxtDataLength)
{
+26
View File
@@ -38,6 +38,19 @@
namespace ot {
uint8_t CountBitsInMask(uint32_t aMask)
{
uint8_t count = 0;
while (aMask != 0)
{
aMask &= aMask - 1;
count++;
}
return count;
}
uint16_t CountMatchingBits(const uint8_t *aFirst, const uint8_t *aSecond, uint16_t aMaxBitLength)
{
uint16_t remainingLen = aMaxBitLength;
@@ -79,4 +92,17 @@ exit:
return matchedLen;
}
uint8_t DetermineMinBitSizeFor(uint32_t aValue)
{
uint8_t bitSize = 0;
do
{
bitSize++;
aValue >>= 1;
} while (aValue != 0);
return bitSize;
}
} // namespace ot
+13 -17
View File
@@ -61,28 +61,13 @@ static constexpr uint8_t kBitsPerByte = 8; ///< Number of bits in a byte.
#define BytesForBitSize(aBitSize) static_cast<uint8_t>(((aBitSize) + (kBitsPerByte - 1)) / kBitsPerByte)
/**
* Counts the number of `1` bits in the binary representation of a given unsigned int bit-mask value.
*
* @tparam UintType The unsigned int type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
* Counts the number of `1` bits in the binary representation of a given `uint32_t` bit-mask value.
*
* @param[in] aMask A bit mask.
*
* @returns The number of `1` bits in @p aMask.
*/
template <typename UintType> uint8_t CountBitsInMask(UintType aMask)
{
static_assert(TypeTraits::IsUint<UintType>::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)");
uint8_t count = 0;
while (aMask != 0)
{
aMask &= aMask - 1;
count++;
}
return count;
}
uint8_t CountBitsInMask(uint32_t aMask);
/**
* Counts the number of consecutive matching bits between two byte arrays.
@@ -102,6 +87,17 @@ template <typename UintType> uint8_t CountBitsInMask(UintType aMask)
*/
uint16_t CountMatchingBits(const uint8_t *aFirst, const uint8_t *aSecond, uint16_t aMaxBitLength);
/**
* Determines the minimum number of bits required to represent a given integer value.
*
* @note For a value of `0`, this function returns `1`.
*
* @param[in] aValue The 32-bit unsigned integer value.
*
* @returns The minimum number of bits required to represent @p aValue.
*/
uint8_t DetermineMinBitSizeFor(uint32_t aValue);
/**
* Sets the specified bit in a given integer to 1.
*
+19
View File
@@ -297,6 +297,25 @@ public:
*/
void RemoveBytes(uint16_t aOffset, uint16_t aLength);
/**
* Reads a pointer to a previously appended object in the `FrameBuilder` at a given byte offset.
*
* This method does not perform any bounds checking. The caller MUST ensure the object of type `ObjectType`
* fits within the previously appended content.
*
* @tparam ObjectType The object type to read.
*
* @param[in] aOffset The byte offset where the object starts.
*
* @returns A pointer to the `ObjectType` at @p aOffset.
*/
template <typename ObjectType> ObjectType *Read(uint16_t aOffset)
{
static_assert(!TypeTraits::IsPointer<ObjectType>::kValue, "ObjectType must not be a pointer");
return reinterpret_cast<ObjectType *>(mBuffer + aOffset);
}
private:
uint8_t *mBuffer;
uint16_t mLength;
+13
View File
@@ -68,6 +68,19 @@
#define OPENTHREAD_CONFIG_CRYPTO_PLATFORM_ALLOCS_CONTEXT 0
#endif
/**
* @def OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
*
* Define to 1 to enable platform one-shot AES-CCM* acceleration.
*
* When enabled, `AesCcm::Engine::ProcessOneShot()` calls
* `otPlatCryptoAesCcmProcessOneShot()` instead of the built-in
* software CCM engine.
*/
#ifndef OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
#define OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE 0
#endif
#if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PLATFORM
/**
-10
View File
@@ -409,16 +409,6 @@
#define OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE 0
#endif
/**
* @def OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
*
* Define to 1 to enable support for IEEE 802.15.4 MAC Multipurpose frame format.
*/
#ifndef OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
#define OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME \
(OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE)
#endif
/**
* @def OPENTHREAD_CONFIG_MAC_CSL_AUTO_SYNC_ENABLE
*
@@ -702,4 +702,9 @@
#error "OPENTHREAD_CONFIG_MLE_IP_ADDRS_TO_REGISTER is removed. All addresses are now registered."
#endif
#ifdef OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
#error "OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME was removed and is no longer supported. " \
"It was originally implemented as a provisional solution for the wake mechanism."
#endif
#endif // OT_CORE_CONFIG_OPENTHREAD_CORE_CONFIG_CHECK_H_
+6 -7
View File
@@ -212,13 +212,11 @@ Error AesCcm::Engine::ProcessOneShot(Operation aOperation,
const uint8_t *aHeader,
uint8_t *aData)
{
// This method performs one-shot (single-part) AES-CCM processing.
// Currently, it is implemented by calling the multi-part
// streaming APIs sequentially. In the future, this can be
// optimized to directly call platform-specific one-shot hardware
// acceleration APIs if supported by the platform.
Error error = kErrorNone;
Error error = kErrorNone;
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
error = otPlatCryptoAesCcmProcessOneShot(aOperation == kEncrypt, &aConfig, aHeader, aData);
#else
uint8_t tag[kMaxTagLength];
Start(aConfig);
@@ -236,6 +234,7 @@ Error AesCcm::Engine::ProcessOneShot(Operation aOperation,
error = (memcmp(aData + aConfig.mPlainTextLength, tag, aConfig.mTagLength) == 0) ? kErrorNone : kErrorSecurity;
break;
}
#endif
return error;
}
@@ -249,7 +248,7 @@ void AesCcm::Engine::Start(const Config &aConfig)
OT_ASSERT(aConfig.IsValid());
mEcb.SetKey(aConfig.mKey);
mEcb.SetKey(aConfig.GetKey());
mNonceLength = aConfig.mNonceLength;
mTagLength = aConfig.mTagLength;
+6 -11
View File
@@ -119,7 +119,7 @@ public:
* @param[in] aKey A pointer to the key.
* @param[in] aKeyLength Length of the key in bytes.
*/
void SetKey(const uint8_t *aKey, uint16_t aKeyLength) { mConfig.mKey.Set(aKey, aKeyLength); }
void SetKey(const uint8_t *aKey, uint16_t aKeyLength) { mConfig.GetKey().Set(aKey, aKeyLength); }
/**
* Sets the key.
@@ -128,7 +128,7 @@ public:
*
* @param[in] aMacKey Key Material for AES operation.
*/
void SetKey(const Mac::KeyMaterial &aMacKey) { aMacKey.ConvertToCryptoKey(mConfig.mKey); }
void SetKey(const Mac::KeyMaterial &aMacKey) { aMacKey.ConvertToCryptoKey(mConfig.GetKey()); }
/**
* Sets the Nonce.
@@ -245,16 +245,11 @@ public:
void *aTag);
private:
struct Config : public Clearable<Config>
struct Config : public otPlatCryptoAesCcmConfig, public Clearable<Config>
{
bool IsValid(void) const;
Key mKey;
uint8_t mNonceLength;
uint8_t mTagLength;
uint32_t mHeaderLength;
uint32_t mPlainTextLength;
const uint8_t *mNonce;
bool IsValid(void) const;
Key &GetKey(void) { return AsCoreType(&mKey); }
const Key &GetKey(void) const { return AsCoreType(&mKey); }
};
class Engine
@@ -37,6 +37,7 @@
#include <string.h>
#include <mbedtls/aes.h>
#include <mbedtls/ccm.h>
#include <mbedtls/cmac.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecdsa.h>
@@ -152,6 +153,59 @@ exit:
return error;
}
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
OT_TOOL_WEAK otError otPlatCryptoAesCcmProcessOneShot(bool aEncrypt,
const otPlatCryptoAesCcmConfig *aConfig,
const uint8_t *aHeader,
uint8_t *aData)
{
Error error = kErrorNone;
mbedtls_ccm_context ctx;
int ret;
mbedtls_ccm_init(&ctx);
VerifyOrExit(aConfig != nullptr && aConfig->mNonce != nullptr && aData != nullptr, error = kErrorInvalidArgs);
{
const LiteralKey key(*static_cast<const Key *>(&aConfig->mKey));
ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key.GetBytes(), key.GetLength() * kBitsPerByte);
VerifyOrExit(ret == 0, error = kErrorFailed);
if (aEncrypt)
{
ret = mbedtls_ccm_encrypt_and_tag(&ctx, aConfig->mPlainTextLength, aConfig->mNonce, aConfig->mNonceLength,
aHeader, aConfig->mHeaderLength, aData, aData,
aData + aConfig->mPlainTextLength, aConfig->mTagLength);
VerifyOrExit(ret == 0, error = kErrorFailed);
}
else
{
// MBEDTLS_ERR_CCM_AUTH_FAILED is the expected return on tag mismatch; map to kErrorSecurity.
ret = mbedtls_ccm_auth_decrypt(&ctx, aConfig->mPlainTextLength, aConfig->mNonce, aConfig->mNonceLength,
aHeader, aConfig->mHeaderLength, aData, aData,
aData + aConfig->mPlainTextLength, aConfig->mTagLength);
if (ret == MBEDTLS_ERR_CCM_AUTH_FAILED)
{
error = kErrorSecurity;
}
else
{
VerifyOrExit(ret == 0, error = kErrorFailed);
}
}
}
exit:
mbedtls_ccm_free(&ctx);
return error;
}
#endif // OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
#if OPENTHREAD_FTD || OPENTHREAD_MTD
// HMAC implementations
+43
View File
@@ -389,6 +389,49 @@ OT_TOOL_WEAK otError otPlatCryptoAesFree(otCryptoContext *aContext)
return kErrorNone;
}
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
OT_TOOL_WEAK otError otPlatCryptoAesCcmProcessOneShot(bool aEncrypt,
const otPlatCryptoAesCcmConfig *aConfig,
const uint8_t *aHeader,
uint8_t *aData)
{
Error error = kErrorNone;
psa_status_t status;
psa_algorithm_t algorithm;
size_t outputLen = 0;
VerifyOrExit(aConfig != nullptr && aConfig->mNonce != nullptr && aData != nullptr, error = kErrorInvalidArgs);
VerifyOrExit(aConfig->mKey.mKey == nullptr, error = kErrorInvalidArgs);
algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, aConfig->mTagLength);
if (aEncrypt)
{
// Output layout: ciphertext || tag, written in-place over the plaintext buffer.
status = psa_aead_encrypt(aConfig->mKey.mKeyRef, algorithm, aConfig->mNonce, aConfig->mNonceLength, aHeader,
aConfig->mHeaderLength, aData, aConfig->mPlainTextLength, aData,
aConfig->mPlainTextLength + aConfig->mTagLength, &outputLen);
SuccessOrExit(error = PsaToOtError(status));
VerifyOrExit(outputLen == aConfig->mPlainTextLength + aConfig->mTagLength, error = kErrorFailed);
}
else
{
// Input layout: ciphertext || tag contiguous at aData. Output plaintext written in-place.
status = psa_aead_decrypt(aConfig->mKey.mKeyRef, algorithm, aConfig->mNonce, aConfig->mNonceLength, aHeader,
aConfig->mHeaderLength, aData, aConfig->mPlainTextLength + aConfig->mTagLength, aData,
aConfig->mPlainTextLength, &outputLen);
error = (status == PSA_ERROR_INVALID_SIGNATURE) ? kErrorSecurity : PsaToOtError(status);
SuccessOrExit(error);
VerifyOrExit(outputLen == aConfig->mPlainTextLength, error = kErrorFailed);
}
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
#if OPENTHREAD_FTD || OPENTHREAD_MTD
OT_TOOL_WEAK otError otPlatCryptoHmacSha256Init(otCryptoContext *aContext)
+13 -13
View File
@@ -539,36 +539,36 @@ uint32_t DataPollSender::GetDefaultPollPeriod(void) const
Mac::TxFrame *DataPollSender::PrepareDataRequest(Mac::TxFrames &aTxFrames)
{
Mac::TxFrame *frame = nullptr;
Mac::TxFrame::Info frameInfo;
Mac::TxFrame *frame = nullptr;
Mac::TxFrame::BuildInfo buildInfo;
#if OPENTHREAD_CONFIG_MULTI_RADIO
Mac::RadioType radio;
SuccessOrExit(GetPollDestinationAddress(frameInfo.mAddrs.mDestination, radio));
SuccessOrExit(GetPollDestinationAddress(buildInfo.mAddrs.mDestination, radio));
frame = &aTxFrames.GetTxFrame(radio);
#else
SuccessOrExit(GetPollDestinationAddress(frameInfo.mAddrs.mDestination));
SuccessOrExit(GetPollDestinationAddress(buildInfo.mAddrs.mDestination));
frame = &aTxFrames.GetTxFrame();
#endif
if (frameInfo.mAddrs.mDestination.IsExtended())
if (buildInfo.mAddrs.mDestination.IsExtended())
{
frameInfo.mAddrs.mSource.SetExtended(Get<Mac::Mac>().GetExtAddress());
buildInfo.mAddrs.mSource.SetExtended(Get<Mac::Mac>().GetExtAddress());
}
else
{
frameInfo.mAddrs.mSource.SetShort(Get<Mac::Mac>().GetShortAddress());
buildInfo.mAddrs.mSource.SetShort(Get<Mac::Mac>().GetShortAddress());
}
frameInfo.mPanIds.SetBothSourceDestination(Get<Mac::Mac>().GetPanId());
buildInfo.mPanIds.SetBothSourceDestination(Get<Mac::Mac>().GetPanId());
frameInfo.mType = Mac::Frame::kTypeMacCmd;
frameInfo.mCommandId = Mac::Frame::kMacCmdDataRequest;
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
frameInfo.mKeyIdMode = Mac::Frame::kKeyIdMode1;
buildInfo.mType = Mac::Frame::kTypeMacCmd;
buildInfo.mCommandId = Mac::Frame::kMacCmdDataRequest;
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mKeyIdMode = Mac::Frame::kKeyIdMode1;
Get<MessageFramer>().PrepareMacHeaders(*frame, frameInfo, nullptr);
Get<MessageFramer>().PrepareMacHeaders(*frame, buildInfo, nullptr);
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (frame->Has<Mac::CslIe>())
+3 -3
View File
@@ -253,9 +253,9 @@ Error LinkRaw::SetMacKey(uint8_t aKeyIdMode,
VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
prevKey.SetFrom(aPrevKey);
currKey.SetFrom(aCurrKey);
nextKey.SetFrom(aNextKey);
prevKey.SetFrom(aPrevKey, kDefaultMacKeysExportable);
currKey.SetFrom(aCurrKey, kDefaultMacKeysExportable);
nextKey.SetFrom(aNextKey, kDefaultMacKeysExportable);
mSubMac.SetMacKey(aKeyIdMode, aKeyId, prevKey, currKey, nextKey);
+24 -24
View File
@@ -705,18 +705,18 @@ void Mac::FinishOperation(void)
TxFrame *Mac::PrepareBeaconRequest(TxFrames &aTxFrames)
{
TxFrame &frame = aTxFrames.GetBroadcastTxFrame();
TxFrame::Info frameInfo;
TxFrame &frame = aTxFrames.GetBroadcastTxFrame();
TxFrame::BuildInfo buildInfo;
frameInfo.mAddrs.mSource.SetNone();
frameInfo.mAddrs.mDestination.SetShort(kShortAddrBroadcast);
frameInfo.mPanIds.SetDestination(kShortAddrBroadcast);
buildInfo.mAddrs.mSource.SetNone();
buildInfo.mAddrs.mDestination.SetShort(kShortAddrBroadcast);
buildInfo.mPanIds.SetDestination(kShortAddrBroadcast);
frameInfo.mType = Frame::kTypeMacCmd;
frameInfo.mCommandId = Frame::kMacCmdBeaconRequest;
frameInfo.mVersion = Frame::kVersion2003;
buildInfo.mType = Frame::kTypeMacCmd;
buildInfo.mCommandId = Frame::kMacCmdBeaconRequest;
buildInfo.mVersion = Frame::kVersion2003;
frameInfo.PrepareHeadersIn(frame);
buildInfo.PrepareHeadersIn(frame);
LogInfo("Sending Beacon Request");
@@ -725,9 +725,9 @@ TxFrame *Mac::PrepareBeaconRequest(TxFrames &aTxFrames)
TxFrame *Mac::PrepareBeacon(TxFrames &aTxFrames)
{
TxFrame *frame;
TxFrame::Info frameInfo;
Beacon *beacon = nullptr;
TxFrame *frame;
TxFrame::BuildInfo buildInfo;
Beacon *beacon = nullptr;
#if OPENTHREAD_CONFIG_MAC_OUTGOING_BEACON_PAYLOAD_ENABLE
uint8_t beaconLength;
BeaconPayload *beaconPayload = nullptr;
@@ -741,14 +741,14 @@ TxFrame *Mac::PrepareBeacon(TxFrames &aTxFrames)
frame = &aTxFrames.GetBroadcastTxFrame();
#endif
frameInfo.mAddrs.mSource.SetExtended(GetExtAddress());
frameInfo.mPanIds.SetSource(mPanId);
frameInfo.mAddrs.mDestination.SetNone();
buildInfo.mAddrs.mSource.SetExtended(GetExtAddress());
buildInfo.mPanIds.SetSource(mPanId);
buildInfo.mAddrs.mDestination.SetNone();
frameInfo.mType = Frame::kTypeBeacon;
frameInfo.mVersion = Frame::kVersion2003;
buildInfo.mType = Frame::kTypeBeacon;
buildInfo.mVersion = Frame::kVersion2003;
frameInfo.PrepareHeadersIn(*frame);
buildInfo.PrepareHeadersIn(*frame);
beacon = reinterpret_cast<Beacon *>(frame->GetPayload());
beacon->Init();
@@ -2498,7 +2498,7 @@ void Mac::ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr)
neighbor->SetCslLastHeard(TimerMilli::GetNow());
neighbor->SetLastRxTimestamp(aFrame.GetTimestamp());
LogDebg("Timestamp=%lu Sequence=%u CslPeriod=%u CslPhase=%u TransmitPhase=%u",
ToUlong(static_cast<uint32_t>(aFrame.GetTimestamp())), aFrame.GetSequence(), csl->GetPeriod(),
ToUlong(ConvertRadioTime64To32(aFrame.GetTimestamp())), aFrame.GetSequence(), csl->GetPeriod(),
csl->GetPhase(), neighbor->GetCslPhase());
#if OPENTHREAD_FTD
@@ -2622,9 +2622,9 @@ Error Mac::HandleWakeupFrame(const RxFrame &aFrame)
const ConnectionIe *connectionIe;
Address srcAddress;
WakeupInfo wakeupInfo;
uint32_t rvTimeUs;
uint64_t rvTimestampUs;
uint64_t radioNowUs;
RadioTime32 rvTimeUs;
RadioTime64 rvTimestampUs;
RadioTime64 radioNowUs;
VerifyOrExit(mWakeupListenEnabled && aFrame.IsWakeupFrame());
@@ -2637,13 +2637,13 @@ Error Mac::HandleWakeupFrame(const RxFrame &aFrame)
wakeupInfo.mRetryCount = connectionIe->GetRetryCount();
VerifyOrExit(wakeupInfo.mRetryInterval > 0 && wakeupInfo.mRetryCount > 0, error = kErrorInvalidArgs);
radioNowUs = otPlatRadioGetNow(&GetInstance());
radioNowUs = Get<Radio>().GetNow();
rvTimeUs = aFrame.Find<RendezvousTimeIe>()->GetRendezvousTime() * kUsPerTenSymbols;
rvTimestampUs = aFrame.GetTimestamp() + kRadioHeaderPhrDuration + aFrame.GetLength() * kOctetDuration + rvTimeUs;
if (rvTimestampUs > radioNowUs + kCslRequestAhead)
{
wakeupInfo.mAttachDelayMs = static_cast<uint32_t>(rvTimestampUs - radioNowUs - kCslRequestAhead);
wakeupInfo.mAttachDelayMs = ConvertRadioTime64To32(rvTimestampUs - radioNowUs - kCslRequestAhead);
wakeupInfo.mAttachDelayMs = wakeupInfo.mAttachDelayMs / Time::kOneMsecInUsec;
}
else
+36 -178
View File
@@ -49,7 +49,7 @@
namespace ot {
namespace Mac {
void TxFrame::Info::PrepareHeadersIn(TxFrame &aTxFrame) const
void TxFrame::BuildInfo::PrepareHeadersIn(TxFrame &aTxFrame) const
{
uint16_t fcf;
FrameBuilder builder;
@@ -252,21 +252,6 @@ void TxFrame::Info::PrepareHeadersIn(TxFrame &aTxFrame) const
aTxFrame.mLength = builder.GetLength();
}
void Frame::SetFrameControlField(uint16_t aFcf)
{
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
if (IsShortFcf(aFcf))
{
OT_ASSERT((aFcf >> 8) == 0);
mPsdu[0] = static_cast<uint8_t>(aFcf);
}
else
#endif
{
LittleEndian::WriteUint16(aFcf, mPsdu);
}
}
Error Frame::ValidatePsdu(void) const
{
Error error = kErrorNone;
@@ -298,86 +283,22 @@ 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 ConnectionIe *connectionIe;
// Wake-up frame is a Multipurpose frame without Ack Request...
VerifyOrExit((fcf & kFcfFrameTypeMask) == kTypeMultipurpose);
VerifyOrExit((fcf & kMpFcfAckRequest) == 0);
// ... with extended source address...
SuccessOrExit(GetSrcAddr(srcAddress));
VerifyOrExit(srcAddress.IsExtended());
// ... secured with Key Id Mode 2...
SuccessOrExit(GetKeyIdMode(keyIdMode));
VerifyOrExit(keyIdMode == kKeyIdMode2);
// ... that has Rendezvous Time IE and Connection IE...
VerifyOrExit(Has<RendezvousTimeIe>());
VerifyOrExit((connectionIe = Find<ConnectionIe>()) != nullptr);
// ... but no other IEs nor payload.
firstIeIndex = FindHeaderIeIndex();
VerifyOrExit(mPsdu + firstIeIndex + sizeof(RendezvousTimeIe) + connectionIe->GetSize() == GetFooter());
result = true;
exit:
return result;
// Placeholder implementation following removal of legacy Multipurpose frame format.
return false;
}
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
#endif
void Frame::SetAckRequest(bool aAckRequest)
void Frame::UpdateFcfFlag(bool aSet, uint16_t aBitFlag)
{
uint16_t fcf = GetFrameControlField();
uint16_t mask = Select<kFcfAckRequest, kMpFcfAckRequest>(fcf);
uint16_t fcf = GetFrameControlField();
if (aAckRequest)
if (aSet)
{
fcf |= mask;
fcf |= aBitFlag;
}
else
{
fcf &= ~mask;
}
SetFrameControlField(fcf);
}
void Frame::SetFramePending(bool aFramePending)
{
uint16_t fcf = GetFrameControlField();
uint16_t mask = Select<kFcfFramePending, kMpFcfFramePending>(fcf);
if (aFramePending)
{
fcf |= mask;
}
else
{
fcf &= ~mask;
}
SetFrameControlField(fcf);
}
void Frame::SetIePresent(bool aIePresent)
{
uint16_t fcf = GetFrameControlField();
uint16_t mask = Select<kFcfIePresent, kMpFcfIePresent>(fcf);
if (aIePresent)
{
fcf |= mask;
}
else
{
fcf &= ~mask;
fcf &= ~aBitFlag;
}
SetFrameControlField(fcf);
@@ -386,7 +307,7 @@ void Frame::SetIePresent(bool aIePresent)
uint8_t Frame::SkipSequenceIndex(void) const
{
uint16_t fcf = GetFrameControlField();
uint8_t index = GetFcfSize(fcf);
uint8_t index = kFcfSize;
if (IsSequencePresent(fcf))
{
@@ -412,14 +333,7 @@ bool Frame::IsDstPanIdPresent(uint16_t aFcf)
{
bool present;
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
if (IsMultipurpose(aFcf))
{
present = (aFcf & kMpFcfPanidPresent) != 0;
}
else
#endif
if (IsVersion2015(aFcf))
if (IsVersion2015(aFcf))
{
// Original table at `InitMacHeader()`
//
@@ -485,14 +399,14 @@ uint8_t Frame::GetSequence(void) const
{
OT_ASSERT(IsSequencePresent());
return GetPsdu()[GetFcfSize(GetFrameControlField())];
return GetPsdu()[kFcfSize];
}
void Frame::SetSequence(uint8_t aSequence)
{
OT_ASSERT(IsSequencePresent());
GetPsdu()[GetFcfSize(GetFrameControlField())] = aSequence;
GetPsdu()[kFcfSize] = aSequence;
}
uint8_t Frame::FindDstAddrIndex(void) const { return SkipSequenceIndex() + (IsDstPanIdPresent() ? sizeof(PanId) : 0); }
@@ -556,15 +470,7 @@ bool Frame::IsSrcPanIdPresent(uint16_t aFcf)
{
bool present;
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
if (IsMultipurpose(aFcf))
{
// Sources PAN ID is implicitly equal to Destination PAN ID in Multipurpose frames
present = false;
}
else
#endif
if (IsVersion2015(aFcf) && ((aFcf & (kFcfDstAddrMask | kFcfSrcAddrMask)) == (kFcfDstAddrExt | kFcfSrcAddrExt)))
if (IsVersion2015(aFcf) && ((aFcf & (kFcfDstAddrMask | kFcfSrcAddrMask)) == (kFcfDstAddrExt | kFcfSrcAddrExt)))
{
// Special case for a IEEE 802.15.4-2015 frame: When both
// addresses are extended, then the source PAN iD is not present
@@ -1004,7 +910,7 @@ exit:
uint8_t Frame::CalculateAddrFieldSize(uint16_t aFcf)
{
uint8_t size = GetFcfSize(aFcf) + (IsSequencePresent(aFcf) ? kDsnSize : 0);
uint8_t size = kFcfSize + (IsSequencePresent(aFcf) ? kDsnSize : 0);
// This static method calculates the size (number of bytes) of
// Address header field for a given Frame Control `aFcf` value.
@@ -1384,12 +1290,12 @@ void TxFrame::GenerateImmAck(const RxFrame &aFrame, bool aIsFramePending)
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
Error TxFrame::GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, const uint8_t *aIeData, uint8_t aIeLength)
{
Error error = kErrorNone;
Info frameInfo;
Address address;
PanId panId;
uint8_t securityLevel = kSecurityNone;
uint8_t keyIdMode = kKeyIdMode0;
Error error = kErrorNone;
BuildInfo buildInfo;
Address address;
PanId panId;
uint8_t securityLevel = kSecurityNone;
uint8_t keyIdMode = kKeyIdMode0;
// Validate the received frame.
@@ -1406,8 +1312,8 @@ Error TxFrame::GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, con
// Check `aRxFrame` has a valid source, which is then used as
// ack frames destination.
SuccessOrExit(error = aRxFrame.GetSrcAddr(frameInfo.mAddrs.mDestination));
VerifyOrExit(!frameInfo.mAddrs.mDestination.IsNone(), error = kErrorParse);
SuccessOrExit(error = aRxFrame.GetSrcAddr(buildInfo.mAddrs.mDestination));
VerifyOrExit(!buildInfo.mAddrs.mDestination.IsNone(), error = kErrorParse);
if (aRxFrame.GetSecurityEnabled())
{
@@ -1420,12 +1326,12 @@ Error TxFrame::GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, con
if (aRxFrame.IsSrcPanIdPresent())
{
SuccessOrExit(error = aRxFrame.GetSrcPanId(panId));
frameInfo.mPanIds.SetDestination(panId);
buildInfo.mPanIds.SetDestination(panId);
}
else if (aRxFrame.IsDstPanIdPresent())
{
SuccessOrExit(error = aRxFrame.GetDstPanId(panId));
frameInfo.mPanIds.SetDestination(panId);
buildInfo.mPanIds.SetDestination(panId);
}
// Prepare the ack frame
@@ -1433,12 +1339,12 @@ Error TxFrame::GenerateEnhAck(const RxFrame &aRxFrame, bool aIsFramePending, con
mChannel = aRxFrame.mChannel;
ClearAllBytes(mInfo.mTxInfo);
frameInfo.mType = kTypeAck;
frameInfo.mVersion = kVersion2015;
frameInfo.mSecurityLevel = static_cast<SecurityLevel>(securityLevel);
frameInfo.mKeyIdMode = static_cast<KeyIdMode>(keyIdMode);
buildInfo.mType = kTypeAck;
buildInfo.mVersion = kVersion2015;
buildInfo.mSecurityLevel = static_cast<SecurityLevel>(securityLevel);
buildInfo.mKeyIdMode = static_cast<KeyIdMode>(keyIdMode);
frameInfo.PrepareHeadersIn(*this);
buildInfo.PrepareHeadersIn(*this);
SetFramePending(aIsFramePending);
SetIePresent(aIeLength != 0);
@@ -1467,56 +1373,14 @@ exit:
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
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;
// Placeholder implementation following removal of legacy Multipurpose frame format.
OT_UNUSED_VARIABLE(aPanId);
OT_UNUSED_VARIABLE(aWakeupRequest);
OT_UNUSED_VARIABLE(aSource);
fcf = kTypeMultipurpose | kMpFcfLongFrame | kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression |
kMpFcfIePresent;
VerifyOrExit(!aSource.IsNone(), error = kErrorInvalidArgs);
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.AppendUint<kLittleEndian>(fcf));
IgnoreError(builder.AppendUint<kLittleEndian>(aPanId));
IgnoreError(builder.AppendMacAddress(dest));
IgnoreError(builder.AppendMacAddress(aSource));
secCtl = kKeyIdMode2 | kSecurityEncMic32;
IgnoreError(builder.AppendUint8(secCtl));
builder.AppendLength(CalculateSecurityHeaderSize(secCtl) - sizeof(secCtl));
builder.Append<RendezvousTimeIe>()->Init();
builder.Append<ConnectionIe>()->Init(wakeupIdLength);
builder.AppendLength(wakeupIdLength);
builder.AppendLength(CalculateMicSize(secCtl) + GetFcsSize());
mLength = builder.GetLength();
exit:
return error;
return kErrorFailed;
}
#endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
#endif
bool RxFrame::IsSecuredWith(KeyIdModeFlags aFlags) const
{
@@ -1644,12 +1508,6 @@ Frame::InfoString Frame::ToInfoString(void) const
break;
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
case kTypeMultipurpose:
string.Append("MP");
break;
#endif
default:
string.Append("%d", type);
break;
+47 -110
View File
@@ -37,12 +37,14 @@
#include "openthread-core-config.h"
#include "common/as_core_type.hpp"
#include "common/bit_utils.hpp"
#include "common/const_cast.hpp"
#include "common/encoding.hpp"
#include "common/numeric_limits.hpp"
#include "mac/mac_header_ie.hpp"
#include "mac/mac_types.hpp"
#include "meshcop/network_name.hpp"
#include "radio/radio_types.hpp"
namespace ot {
namespace Mac {
@@ -229,11 +231,9 @@ public:
/**
* Sets the Frame Pending bit.
*
* @note This method must not be called on a Multipurpose frame with short Frame Control field.
*
* @param[in] aFramePending The Frame Pending bit.
*/
void SetFramePending(bool aFramePending);
void SetFramePending(bool aFramePending) { UpdateFcfFlag(aFramePending, kFcfFramePending); }
/**
* Indicates whether or not the Ack Request bit is set.
@@ -246,17 +246,13 @@ public:
/**
* Sets the Ack Request bit.
*
* @note This method must not be called on a Multipurpose frame with short Frame Control field.
*
* @param[in] aAckRequest The Ack Request bit.
*/
void SetAckRequest(bool aAckRequest);
void SetAckRequest(bool aAckRequest) { UpdateFcfFlag(aAckRequest, kFcfAckRequest); }
/**
* Indicates whether or not the PanId Compression bit is set.
*
* @note This method must not be called on a Multipurpose frame, which lacks this flag.
*
* @retval TRUE If the PanId Compression bit is set.
* @retval FALSE If the PanId Compression bit is not set.
*/
@@ -273,11 +269,9 @@ public:
/**
* Sets the IE Present bit.
*
* @note This method must not be called on a Multipurpose frame with short Frame Control field.
*
* @param[in] aIePresent The IE Present bit.
*/
void SetIePresent(bool aIePresent);
void SetIePresent(bool aIePresent) { UpdateFcfFlag(aIePresent, kFcfIePresent); }
/**
* Returns the Sequence Number value.
@@ -697,22 +691,9 @@ public:
*
* @returns The Frame Control field.
*/
uint16_t GetFrameControlField(void) const
{
uint16_t fcf = mPsdu[0];
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
if (!IsShortFcf(fcf))
#endif
{
fcf |= (mPsdu[1] << 8);
}
return fcf;
}
uint16_t GetFrameControlField(void) const { return LittleEndian::ReadUint16(mPsdu); }
protected:
static constexpr uint8_t kShortFcfSize = sizeof(uint8_t);
static constexpr uint8_t kSecurityControlSize = sizeof(uint8_t);
static constexpr uint8_t kFrameCounterSize = sizeof(uint32_t);
static constexpr uint8_t kCommandIdSize = sizeof(uint8_t);
@@ -744,25 +725,6 @@ protected:
static constexpr uint16_t kFcfSrcAddrExt = kFcfAddrExt << kFcfSrcAddrShift;
static constexpr uint16_t kFcfSrcAddrMask = kFcfAddrMask << kFcfSrcAddrShift;
// Frame Control field format for MAC Multipurpose frame
static constexpr uint16_t kMpFcfLongFrame = 1 << 3;
static constexpr uint16_t kMpFcfDstAddrShift = 4;
static constexpr uint16_t kMpFcfDstAddrNone = kFcfAddrNone << kMpFcfDstAddrShift;
static constexpr uint16_t kMpFcfDstAddrShort = kFcfAddrShort << kMpFcfDstAddrShift;
static constexpr uint16_t kMpFcfDstAddrExt = kFcfAddrExt << kMpFcfDstAddrShift;
static constexpr uint16_t kMpFcfDstAddrMask = kFcfAddrMask << kMpFcfDstAddrShift;
static constexpr uint16_t kMpFcfSrcAddrShift = 6;
static constexpr uint16_t kMpFcfSrcAddrNone = kFcfAddrNone << kMpFcfSrcAddrShift;
static constexpr uint16_t kMpFcfSrcAddrShort = kFcfAddrShort << kMpFcfSrcAddrShift;
static constexpr uint16_t kMpFcfSrcAddrExt = kFcfAddrExt << kMpFcfSrcAddrShift;
static constexpr uint16_t kMpFcfSrcAddrMask = kFcfAddrMask << kMpFcfSrcAddrShift;
static constexpr uint16_t kMpFcfPanidPresent = 1 << 8;
static constexpr uint16_t kMpFcfSecurityEnabled = 1 << 9;
static constexpr uint16_t kMpFcfSequenceSuppression = 1 << 10;
static constexpr uint16_t kMpFcfFramePending = 1 << 11;
static constexpr uint16_t kMpFcfAckRequest = 1 << 14;
static constexpr uint16_t kMpFcfIePresent = 1 << 15;
static constexpr uint8_t kSecLevelMask = 7 << 0;
static constexpr uint8_t kKeyIdModeMask = 3 << 3;
@@ -781,7 +743,8 @@ protected:
static constexpr uint8_t kInvalidSize = kInvalidIndex;
static constexpr uint8_t kMaxPsduSize = kInvalidSize - 1;
void SetFrameControlField(uint16_t aFcf);
void SetFrameControlField(uint16_t aFcf) { LittleEndian::WriteUint16(aFcf, mPsdu); }
void UpdateFcfFlag(bool aSet, uint16_t aBitFlag);
uint8_t SkipSequenceIndex(void) const;
uint8_t FindDstPanIdIndex(void) const;
uint8_t FindDstAddrIndex(void) const;
@@ -795,63 +758,23 @@ protected:
uint8_t FindHeaderIeIndex(void) const;
#endif
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
static uint8_t GetFcfSize(uint16_t aFcf) { return IsShortFcf(aFcf) ? kShortFcfSize : kFcfSize; }
#else
// clang-format off
static uint8_t GetFcfSize(uint16_t /* aFcf */) { return kFcfSize; }
// clang-format on
#endif
#if OPENTHREAD_CONFIG_MAC_MULTIPURPOSE_FRAME
template <uint16_t kValue, uint16_t kMpValue> static uint16_t Select(uint16_t aFcf)
{
return IsMultipurpose(aFcf) ? kMpValue : kValue;
}
#else
template <uint16_t kValue, uint16_t kMpValue> static uint16_t Select(uint16_t /* aFcf */) { return kValue; }
#endif
template <uint16_t kValue, uint16_t kMpValue> static uint16_t MaskFcf(uint16_t aFcf)
{
return aFcf & Select<kValue, kMpValue>(aFcf);
}
static uint16_t GetFcfDstAddr(uint16_t aFcf)
{
return MaskFcf<kFcfDstAddrMask, kMpFcfDstAddrMask>(aFcf) >> Select<kFcfDstAddrShift, kMpFcfDstAddrShift>(aFcf);
}
static uint16_t GetFcfSrcAddr(uint16_t aFcf)
{
return MaskFcf<kFcfSrcAddrMask, kMpFcfSrcAddrMask>(aFcf) >> Select<kFcfSrcAddrShift, kMpFcfSrcAddrShift>(aFcf);
}
static bool IsMultipurpose(uint16_t aFcf) { return (aFcf & kFcfFrameTypeMask) == kTypeMultipurpose; }
static bool IsShortFcf(uint16_t aFcf)
{
return (aFcf & (kFcfFrameTypeMask | kMpFcfLongFrame)) == (kTypeMultipurpose | 0);
}
static bool IsSequencePresent(uint16_t aFcf)
{
return !MaskFcf<kFcfSequenceSuppression, kMpFcfSequenceSuppression>(aFcf);
}
static bool IsDstAddrPresent(uint16_t aFcf) { return MaskFcf<kFcfDstAddrMask, kMpFcfDstAddrMask>(aFcf); }
static bool IsDstPanIdPresent(uint16_t aFcf);
static bool IsSrcAddrPresent(uint16_t aFcf) { return MaskFcf<kFcfSrcAddrMask, kMpFcfSrcAddrMask>(aFcf); }
static bool IsSrcPanIdPresent(uint16_t aFcf);
static bool IsSecurityEnabled(uint16_t aFcf) { return MaskFcf<kFcfSecurityEnabled, kMpFcfSecurityEnabled>(aFcf); }
static bool IsFramePending(uint16_t aFcf) { return MaskFcf<kFcfFramePending, kMpFcfFramePending>(aFcf); }
static bool IsIePresent(uint16_t aFcf) { return MaskFcf<kFcfIePresent, kMpFcfIePresent>(aFcf); }
static bool IsAckRequest(uint16_t aFcf) { return MaskFcf<kFcfAckRequest, kMpFcfAckRequest>(aFcf); }
static bool IsVersion2015(uint16_t aFcf) { return (aFcf & kFcfFrameVersionMask) == kVersion2015; }
static uint16_t GetFcfDstAddr(uint16_t aFcf) { return ReadBits<uint16_t, kFcfDstAddrMask>(aFcf); }
static uint16_t GetFcfSrcAddr(uint16_t aFcf) { return ReadBits<uint16_t, kFcfSrcAddrMask>(aFcf); }
static bool IsSequencePresent(uint16_t aFcf) { return (aFcf & kFcfSequenceSuppression) == 0; }
static bool IsDstAddrPresent(uint16_t aFcf) { return (aFcf & kFcfDstAddrMask) != 0; }
static bool IsSrcAddrPresent(uint16_t aFcf) { return (aFcf & kFcfSrcAddrMask) != 0; }
static bool IsSecurityEnabled(uint16_t aFcf) { return (aFcf & kFcfSecurityEnabled) != 0; }
static bool IsFramePending(uint16_t aFcf) { return (aFcf & kFcfFramePending) != 0; }
static bool IsIePresent(uint16_t aFcf) { return (aFcf & kFcfIePresent) != 0; }
static bool IsAckRequest(uint16_t aFcf) { return (aFcf & kFcfAckRequest) != 0; }
static bool IsVersion2015(uint16_t aFcf) { return (aFcf & kFcfFrameVersionMask) == kVersion2015; }
static bool IsDstPanIdPresent(uint16_t aFcf);
static bool IsSrcPanIdPresent(uint16_t aFcf);
static uint16_t DetermineFcfAddrType(const Address &aAddress, uint16_t aBitShift);
static uint8_t CalculateAddrFieldSize(uint16_t aFcf);
static uint8_t CalculateSecurityHeaderSize(uint8_t aSecurityControl);
static uint8_t CalculateKeySourceSize(uint8_t aSecurityControl);
static uint8_t CalculateMicSize(uint8_t aSecurityControl);
static uint8_t CalculateAddrFieldSize(uint16_t aFcf);
static uint8_t CalculateSecurityHeaderSize(uint8_t aSecurityControl);
static uint8_t CalculateKeySourceSize(uint8_t aSecurityControl);
static uint8_t CalculateMicSize(uint8_t aSecurityControl);
private:
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
@@ -945,7 +868,7 @@ public:
*
* @returns The timestamp in microseconds.
*/
const uint64_t &GetTimestamp(void) const { return mInfo.mRxInfo.mTimestamp; }
const RadioTime64 &GetTimestamp(void) const { return mInfo.mRxInfo.mTimestamp; }
/**
* Performs AES CCM on the frame which is received.
@@ -967,22 +890,22 @@ class TxFrame : public Frame
{
public:
/**
* Represents header information.
* Represents the information to use to build the frame.
*/
struct Info : public Clearable<Info>
struct BuildInfo : public Clearable<BuildInfo>
{
/**
* Initializes the `Info` by clearing all its fields (setting all bytes to zero).
* Initializes the `BuildInfo` by clearing all its fields (setting all bytes to zero).
*/
Info(void) { Clear(); }
BuildInfo(void) { Clear(); }
/**
* Prepares MAC headers based on `Info` fields in a given `TxFrame`.
* Prepares MAC headers based on `BuildInfo` fields in a given `TxFrame`.
*
* This method uses the `Info` structure to construct the MAC address and security headers in @p aTxFrame.
* This method uses the `BuildInfo` structure to construct the MAC address and security headers in @p aTxFrame.
* It determines the Frame Control Field (FCF), including setting the appropriate frame type, security level,
* and addressing mode flags. It populates the source and destination addresses and PAN IDs within the MAC
* header based on the information provided in the `Info` structure.
* header based on the information provided in the `BuildInfo` structure.
*
* It sets the Ack Request bit in the FCF if the following criteria are met:
* - A destination address is present
@@ -1283,6 +1206,13 @@ public:
#endif
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
/**
* Gets the TX delay field for the frame.
*
* @returns The delay time for the TX frame in microseconds.
*/
uint32_t GetTxDelay(void) const { return mInfo.mTxInfo.mTxDelay; }
/**
* Set TX delay field for the frame.
*
@@ -1290,12 +1220,19 @@ public:
*/
void SetTxDelay(uint32_t aTxDelay) { mInfo.mTxInfo.mTxDelay = aTxDelay; }
/**
* Gets the TX delay base time field for the frame.
*
* @returns The delay base time for the TX frame as a `RadioTime32`.
*/
RadioTime32 GetTxDelayBaseTime(void) const { return mInfo.mTxInfo.mTxDelayBaseTime; }
/**
* Set TX delay base time field for the frame.
*
* @param[in] aTxDelayBaseTime The delay base time for the TX frame.
*/
void SetTxDelayBaseTime(uint32_t aTxDelayBaseTime) { mInfo.mTxInfo.mTxDelayBaseTime = aTxDelayBaseTime; }
void SetTxDelayBaseTime(RadioTime32 aTxDelayBaseTime) { mInfo.mTxInfo.mTxDelayBaseTime = aTxDelayBaseTime; }
#endif
};
+36
View File
@@ -43,6 +43,42 @@ void HeaderIe::Init(uint8_t aId, uint8_t aLen)
SetId(aId);
}
Error HeaderIe::StartIe(FrameBuilder &aBuilder, uint8_t aId, Bookmark &aBookmark)
{
Error error = kErrorNone;
HeaderIe *ie;
aBookmark = aBuilder.GetLength();
ie = aBuilder.Append<HeaderIe>();
VerifyOrExit(ie != nullptr, error = kErrorNoBufs);
ie->Init(aId, 0);
exit:
return error;
}
Error HeaderIe::EndIe(FrameBuilder &aBuilder, const Bookmark &aBookmark)
{
Error error = kErrorNone;
uint16_t offset = aBookmark;
uint16_t length;
HeaderIe *ie;
VerifyOrExit(offset + sizeof(HeaderIe) <= aBuilder.GetLength(), error = kErrorInvalidArgs);
ie = aBuilder.Read<HeaderIe>(offset);
length = aBuilder.GetLength() - offset - sizeof(HeaderIe);
VerifyOrExit(length <= kMaxLength, error = kErrorInvalidArgs);
ie->SetLength(static_cast<uint8_t>(length));
exit:
return error;
}
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
Error ConnectionIe::SetWakeupId(WakeupId aWakeupId)
+38
View File
@@ -40,6 +40,7 @@
#include "common/bit_utils.hpp"
#include "common/const_cast.hpp"
#include "common/encoding.hpp"
#include "common/frame_builder.hpp"
#include "common/num_utils.hpp"
#include "common/numeric_limits.hpp"
#include "mac/mac_types.hpp"
@@ -60,6 +61,8 @@ OT_TOOL_PACKED_BEGIN
class HeaderIe
{
public:
static constexpr uint8_t kMaxLength = 127; ///< Maximum Header IE length in bytes.
/**
* Returns the IE Element ID.
*
@@ -115,6 +118,41 @@ public:
return (aIe.GetId() == IeType::kId) && static_cast<const IeType *>(&aIe)->IsValid();
}
/**
* Represents the opaque type for a bookmark used by `StartIe()/EndIe()`.
*/
typedef uint16_t Bookmark;
/**
* Starts appending a (variable-length) `HeaderIe` in a `FrameBuilder`.
*
* On success, this method appends a `HeaderIe` descriptor (with length initialized to zero) to @p aBuilder and
* saves the current byte offset as @p aBookmark. The caller can then append the IE content bytes to @p aBuilder,
* and finally call `EndIe()` to update the IE length field automatically.
*
* @param[in,out] aBuilder The `FrameBuilder` instance to append to.
* @param[in] aId The IE Element ID.
* @param[out] aBookmark A reference to a `Bookmark` to save the start offset.
*
* @retval kErrorNone Successfully started the `HeaderIe`.
* @retval kErrorNoBufs Insufficient space in @p aBuilder to append the `HeaderIe` header.
*/
static Error StartIe(FrameBuilder &aBuilder, uint8_t aId, Bookmark &aBookmark);
/**
* Finishes appending a `HeaderIe` in a `FrameBuilder`.
*
* This method updates the length field of the `HeaderIe` previously started using `StartIe()`. It determines the
* IE length based on the number of bytes appended to @p aBuilder since `StartIe()` was called.
*
* @param[in,out] aBuilder The `FrameBuilder` instance.
* @param[in] aBookmark The `Bookmark` used when calling `StartIe()`.
*
* @retval kErrorNone Successfully finalized the `HeaderIe` length.
* @retval kErrorInvalidArgs The @p aBookmark is invalid or the appended IE length exceeds `kMaxLength`.
*/
static Error EndIe(FrameBuilder &aBuilder, const Bookmark &aBookmark);
protected:
void Init(uint8_t aId, uint8_t aLen);
uint8_t *GetBytes(void) { return reinterpret_cast<uint8_t *>(this); }
+2
View File
@@ -80,6 +80,8 @@ 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.
constexpr bool kDefaultMacKeysExportable =
OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE; ///< Default exportability policy for MAC key refs.
/**
* Represents the wake-up identifier.
+9 -12
View File
@@ -427,32 +427,29 @@ void SubMac::StartCsmaBackoff(void)
uint8_t backoffExponent = kCsmaMinBe + mCsmaBackoffs;
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
if (mTransmitFrame.mInfo.mTxInfo.mTxDelay != 0 || mTransmitFrame.mInfo.mTxInfo.mTxDelayBaseTime != 0)
if (mTransmitFrame.GetTxDelay() != 0 || mTransmitFrame.GetTxDelayBaseTime() != 0)
{
SetState(kStateCslTransmit);
if (ShouldHandleTransmitTargetTime())
{
static constexpr uint32_t kAheadTime = kCcaSampleInterval + kCslTransmitTimeAhead + kRadioHeaderShrDuration;
Time txStartTime = Time(mTransmitFrame.mInfo.mTxInfo.mTxDelayBaseTime);
Time radioNow = Time(static_cast<uint32_t>(Get<Radio>().GetNow()));
RadioTime32 radioNow = Get<Radio>().GetNowAsRadioTime32();
RadioTime32 txStartTime = mTransmitFrame.GetTxDelayBaseTime();
txStartTime += (mTransmitFrame.mInfo.mTxInfo.mTxDelay - kAheadTime);
if (radioNow < txStartTime)
if (IsRadioTimeStrictlyBefore(radioNow, txStartTime))
{
StartTimer(txStartTime - radioNow);
ExitNow();
}
else // Transmit without delay
{
BeginTransmit();
}
}
else
{
BeginTransmit();
// Transmit without delay
}
BeginTransmit();
ExitNow();
}
#endif // !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
+10 -10
View File
@@ -677,7 +677,7 @@ private:
bool mIsCslSampling : 1; // Indicates that the current time is in CSL sample window
// for platforms not supporting `Radio::ReceiveAt()`.
uint16_t mCslPeerShort; // The CSL peer short address.
uint32_t mCslSampleTimeRadio; // The CSL sample time of the current period based on radio time (lower 32-bit).
RadioTime32 mCslSampleTimeRadio; // The CSL sample time of the current period based on radio time (lower 32-bit).
TimeMicro mCslSampleTimeLocal; // The CSL sample time of the current period based on local time.
TimeMicro mCslLastSync; // The timestamp of the last successful CSL synchronization.
CslAccuracy mCslParentAccuracy; // The parent's CSL accuracy (clock accuracy and uncertainty).
@@ -685,15 +685,15 @@ private:
#endif
#if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
bool mIsWedSampling : 1; // Indicates that the current time is in WED's sample window
// for platforms not supporting `Radio::ReceiveAt()`.
bool mIsWedEnabled : 1; // Indicates if the WED is enabled.
uint32_t mWakeupListenInterval; // The wake-up listen interval, in microseconds.
uint32_t mWakeupListenDuration; // The wake-up listen duration, in microseconds.
uint8_t mWakeupChannel; // The wake-up sample channel.
TimeMicro mWedSampleTime; // The WED sample time of the current interval in local time.
uint64_t mWedSampleTimeRadio; // The WED sample time of the current interval in radio time.
TimerMicro mWedTimer;
bool mIsWedSampling : 1; // Indicates that the current time is in WED's sample window
// for platforms not supporting `Radio::ReceiveAt()`.
bool mIsWedEnabled : 1; // Indicates if the WED is enabled.
uint32_t mWakeupListenInterval; // The wake-up listen interval, in microseconds.
uint32_t mWakeupListenDuration; // The wake-up listen duration, in microseconds.
uint8_t mWakeupChannel; // The wake-up sample channel.
TimeMicro mWedSampleTime; // The WED sample time of the current interval in local time.
RadioTime64 mWedSampleTimeRadio; // The WED sample time of the current interval in radio time.
TimerMicro mWedTimer;
#endif
};
+8 -9
View File
@@ -99,7 +99,7 @@ void SubMac::UpdateCslLastSyncTimestamp(RxFrame *aFrame, Error aError)
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_LOCAL_TIME_SYNC
mCslLastSync = TimerMicro::GetNow();
#else
mCslLastSync = TimeMicro(static_cast<uint32_t>(aFrame->mInfo.mRxInfo.mTimestamp));
mCslLastSync = TimeMicro(ConvertRadioTime64To32(aFrame->GetTimestamp()));
#endif
}
@@ -129,7 +129,7 @@ void SubMac::SetCslParams(uint16_t aPeriod, uint8_t aChannel, ShortAddress aShor
mCslTimer.Stop();
if (mCslPeriod > 0)
{
mCslSampleTimeRadio = static_cast<uint32_t>(Get<Radio>().GetNow());
mCslSampleTimeRadio = Get<Radio>().GetNowAsRadioTime32();
mCslSampleTimeLocal = TimerMicro::GetNow();
// Update CSL sync time whenever CSL parameters are re-initialized.
mCslLastSync = mCslSampleTimeLocal;
@@ -180,9 +180,9 @@ void SubMac::HandleCslReceiveAt(uint32_t aTimeAhead, uint32_t aTimeAfter)
* x-|------------|-------------------------------------x-|------------|---------------------------------------|
* sample sleep sample sleep
*/
uint32_t periodUs = mCslPeriod * kUsPerTenSymbols;
uint32_t winStart;
uint32_t winDuration;
uint32_t periodUs = mCslPeriod * kUsPerTenSymbols;
RadioTime32 winStart;
uint32_t winDuration;
mCslTimer.FireAt(mCslSampleTimeLocal + periodUs - aTimeAhead - GetNextCycleDrift());
aTimeAhead -= kCslReceiveTimeAhead;
@@ -290,7 +290,7 @@ uint32_t SubMac::GetLocalTime(void)
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_LOCAL_TIME_SYNC
now = TimerMicro::GetNow().GetValue();
#else
now = static_cast<uint32_t>(Get<Radio>().GetNow());
now = Get<Radio>().GetNowAsRadioTime32();
#endif
return now;
@@ -321,8 +321,7 @@ void SubMac::LogReceived(RxFrame *aFrame)
(dst.GetType() == Address::kTypeExtended && dst.GetExtended() == GetExtAddress()));
LogDebg("Received frame in state (SubMac %s, CSL %s), timestamp %lu", StateToString(mState),
mIsCslSampling ? "CslSample" : "CslSleep",
ToUlong(static_cast<uint32_t>(aFrame->mInfo.mRxInfo.mTimestamp)));
mIsCslSampling ? "CslSample" : "CslSleep", ToUlong(ConvertRadioTime64To32(aFrame->GetTimestamp())));
VerifyOrExit(mState == kStateRadioSample);
@@ -330,7 +329,7 @@ void SubMac::LogReceived(RxFrame *aFrame)
ahead -= kMinReceiveOnAhead + kCslReceiveTimeAhead;
sampleTime = mCslSampleTimeRadio - mCslPeriod * kUsPerTenSymbols;
deviation = static_cast<uint32_t>(aFrame->mInfo.mRxInfo.mTimestamp) + kRadioHeaderPhrDuration - sampleTime;
deviation = ConvertRadioTime64To32(aFrame->GetTimestamp()) + kRadioHeaderPhrDuration - sampleTime;
// This logs three values (all in microseconds):
// - Absolute sample time in which the CSL receiver expected the MHR of the received frame.
+1 -1
View File
@@ -96,7 +96,7 @@ void SubMac::HandleWedReceiveAt(void)
if (mState != kStateDisabled)
{
IgnoreError(
Get<Radio>().ReceiveAt(mWakeupChannel, static_cast<uint32_t>(mWedSampleTimeRadio), mWakeupListenDuration));
Get<Radio>().ReceiveAt(mWakeupChannel, ConvertRadioTime64To32(mWedSampleTimeRadio), mWakeupListenDuration));
}
}
+1 -1
View File
@@ -100,7 +100,7 @@ Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
VerifyOrExit(frame->GenerateWakeupFrame(Get<Mac::Mac>().GetPanId(), mWakeupRequest, source) == kErrorNone,
frame = nullptr);
frame->SetTxDelayBaseTime(static_cast<uint32_t>(Get<Radio>().GetNow()));
frame->SetTxDelayBaseTime(Get<Radio>().GetNowAsRadioTime32());
frame->SetTxDelay(radioTxDelay);
frame->SetCsmaCaEnabled(kWakeupFrameTxCca);
frame->SetMaxCsmaBackoffs(0);
+2
View File
@@ -128,6 +128,8 @@ Error Radio::Transmit(Mac::TxFrame &aFrame)
}
#endif // OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
//---------------------------------------------------------------------------------------------------------------------
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
inline uint64_t UintSafeMinus(uint64_t aLhs, uint64_t aRhs) { return aLhs > aRhs ? (aLhs - aRhs) : 0; }
+20 -15
View File
@@ -46,6 +46,7 @@
#include "common/numeric_limits.hpp"
#include "common/time.hpp"
#include "mac/mac_frame.hpp"
#include "radio/radio_types.hpp"
namespace ot {
@@ -523,7 +524,7 @@ public:
* @retval kErrorNone Successfully scheduled receive window.
* @retval kErrorFailed The receive window could not be scheduled.
*/
Error ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDuration);
Error ReceiveAt(uint8_t aChannel, RadioTime32 aStart, uint32_t aDuration);
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -532,7 +533,7 @@ public:
*
* @param[in] aCslSampleTime The CSL sample time.
*/
void UpdateCslSampleTime(uint32_t aCslSampleTime);
void UpdateCslSampleTime(RadioTime32 aCslSampleTime);
/**
* Enables CSL sampling in radio.
@@ -559,15 +560,21 @@ public:
Error ResetCsl(void);
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE || \
OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
#if OT_CONFIG_RADIO_TIME_ENABLE
/**
* Get the current radio time in microseconds referenced to a continuous monotonic local radio clock (64 bits
* width).
*
* @returns The current radio clock time.
*/
uint64_t GetNow(void);
RadioTime64 GetNow(void);
/**
* Get the current radio time in microseconds as a 32-bit value (lower 32 bits of the full radio time).
*
* @returns The current radio clock time as a `RadioTime32`.
*/
RadioTime32 GetNowAsRadioTime32(void) { return ConvertRadioTime64To32(GetNow()); }
/**
* Get the current accuracy, in units of ± ppm, of the clock used for scheduling CSL operations.
@@ -584,7 +591,7 @@ public:
* @returns The CSL Uncertainty in units of 10 us.
*/
uint8_t GetCslUncertainty(void);
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#endif // OT_CONFIG_RADIO_TIME_ENABLE
/**
* Gets the radio transmit frame buffer.
@@ -984,7 +991,7 @@ inline Error Radio::Receive(uint8_t aChannel)
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
inline Error Radio::ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
inline Error Radio::ReceiveAt(uint8_t aChannel, RadioTime32 aStart, uint32_t aDuration)
{
Error error = otPlatRadioReceiveAt(GetInstancePtr(), aChannel, aStart, aDuration);
#if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
@@ -998,7 +1005,7 @@ inline Error Radio::ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDurat
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
inline void Radio::UpdateCslSampleTime(uint32_t aCslSampleTime)
inline void Radio::UpdateCslSampleTime(RadioTime32 aCslSampleTime)
{
otPlatRadioUpdateCslSampleTime(GetInstancePtr(), aCslSampleTime);
}
@@ -1011,9 +1018,8 @@ inline Error Radio::EnableCsl(uint32_t aCslPeriod, Mac::ShortAddress aShortAddr,
inline Error Radio::ResetCsl(void) { return otPlatRadioResetCsl(GetInstancePtr()); }
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE || \
OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
inline uint64_t Radio::GetNow(void) { return otPlatRadioGetNow(GetInstancePtr()); }
#if OT_CONFIG_RADIO_TIME_ENABLE
inline RadioTime64 Radio::GetNow(void) { return otPlatRadioGetNow(GetInstancePtr()); }
inline uint8_t Radio::GetCslAccuracy(void) { return otPlatRadioGetCslAccuracy(GetInstancePtr()); }
@@ -1112,16 +1118,15 @@ inline Error Radio::ReceiveAt(uint8_t, uint32_t, uint32_t) { return kErrorNone;
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
inline void Radio::UpdateCslSampleTime(uint32_t) {}
inline void Radio::UpdateCslSampleTime(RadioTime32) {}
inline Error Radio::EnableCsl(uint32_t, Mac::ShortAddress, const Mac::ExtAddress &) { return kErrorNotImplemented; }
inline Error Radio::ResetCsl(void) { return kErrorNotImplemented; }
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE || \
OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
inline uint64_t Radio::GetNow(void) { return NumericLimits<uint64_t>::kMax; }
#if OT_CONFIG_RADIO_TIME_ENABLE
inline RadioTime64 Radio::GetNow(void) { return NumericLimits<uint64_t>::kMax; }
inline uint8_t Radio::GetCslAccuracy(void) { return NumericLimits<uint8_t>::kMax; }
+5 -5
View File
@@ -281,7 +281,7 @@ extern "C" OT_TOOL_WEAK void otPlatRadioSetMacFrameCounterIfLarger(otInstance *a
extern "C" OT_TOOL_WEAK uint64_t otPlatTimeGet(void) { return UINT64_MAX; }
extern "C" OT_TOOL_WEAK uint64_t otPlatRadioGetNow(otInstance *aInstance)
extern "C" OT_TOOL_WEAK otRadioTime64 otPlatRadioGetNow(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
@@ -366,10 +366,10 @@ extern "C" OT_TOOL_WEAK otError otPlatRadioGetRegion(otInstance *aInstance, uint
return kErrorNotImplemented;
}
extern "C" OT_TOOL_WEAK otError otPlatRadioReceiveAt(otInstance *aInstance,
uint8_t aChannel,
uint32_t aStart,
uint32_t aDuration)
extern "C" OT_TOOL_WEAK otError otPlatRadioReceiveAt(otInstance *aInstance,
uint8_t aChannel,
otRadioTime32 aStart,
uint32_t aDuration)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aChannel);
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2026, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes implementation of OpenThread radio types.
*/
#include "radio_types.hpp"
#include "common/time.hpp"
namespace ot {
bool IsRadioTimeStrictlyBefore(RadioTime32 aFirstTime, RadioTime32 aSecondTime)
{
Time firstTime(aFirstTime);
Time secondTime(aSecondTime);
return (firstTime < secondTime);
}
} // namespace ot
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2026, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file includes definitions for OpenThread radio types.
*/
#ifndef OT_CORE_RADIO_RADIO_TYPES_HPP_
#define OT_CORE_RADIO_RADIO_TYPES_HPP_
#include "openthread-core-config.h"
#include <openthread/platform/radio.h>
namespace ot {
#ifdef OT_CONFIG_RADIO_TIME_ENABLE
#error "OT_CONFIG_RADIO_TIME_ENABLE MUST NOT be defined directly. It is derived from other configs"
#endif
#define OT_CONFIG_RADIO_TIME_ENABLE \
(OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE || \
OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE || OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE || \
OPENTHREAD_CONFIG_TIME_SYNC_ENABLE)
/**
* Represents a 64-bit radio time in microseconds referenced to a continuous monotonic local radio clock.
*/
typedef otRadioTime64 RadioTime64;
/**
* Represents a 32-bit radio time in microseconds (holds the lower 32 bits of a `RadioTime64`).
*/
typedef otRadioTime32 RadioTime32;
/**
* Converts a 64-bit radio time to a 32-bit radio time.
*
* @param[in] aRadioTime64 The 64-bit radio time to convert.
*
* @returns The converted 32-bit radio time (lower 32 bits of @p aRadioTime64).
*/
inline RadioTime32 ConvertRadioTime64To32(RadioTime64 aRadioTime64) { return static_cast<RadioTime32>(aRadioTime64); }
/**
* Indicates whether a given 32-bit radio time is strictly before another 32-bit radio time.
*
* This function correctly accounts for 32-bit microsecond counter roll-over.
*
* @param[in] aFirstTime The first 32-bit radio time to compare.
* @param[in] aSecondTime The second 32-bit radio time to compare.
*
* @retval TRUE @p aFirstTime is strictly before @p aSecondTime.
* @retval FALSE @p aFirstTime is not strictly before @p aSecondTime.
*/
bool IsRadioTimeStrictlyBefore(RadioTime32 aFirstTime, RadioTime32 aSecondTime);
} // namespace ot
#endif // OT_CORE_RADIO_RADIO_TYPES_HPP_
+6 -7
View File
@@ -135,12 +135,12 @@ uint32_t CslTxScheduler::GetNextCslTransmissionDelay(const CslNeighbor &aCslNeig
uint32_t &aDelayFromLastRx,
uint32_t aAheadUs) const
{
uint64_t radioNow = Get<Radio>().GetNow();
uint32_t periodInUs = aCslNeighbor.GetCslPeriod() * kUsPerTenSymbols;
// See CslTxScheduler::NeighborInfo::mCslPhase
/* see CslTxScheduler::NeighborInfo::mCslPhase */
uint64_t firstTxWindow = aCslNeighbor.GetLastRxTimestamp() + aCslNeighbor.GetCslPhase() * kUsPerTenSymbols;
uint64_t nextTxWindow = radioNow - (radioNow % periodInUs) + (firstTxWindow % periodInUs);
RadioTime64 radioNow = Get<Radio>().GetNow();
uint32_t periodInUs = aCslNeighbor.GetCslPeriod() * kUsPerTenSymbols;
RadioTime64 firstTxWindow = aCslNeighbor.GetLastRxTimestamp() + aCslNeighbor.GetCslPhase() * kUsPerTenSymbols;
RadioTime64 nextTxWindow = radioNow - (radioNow % periodInUs) + (firstTxWindow % periodInUs);
while (nextTxWindow < radioNow + aAheadUs)
{
@@ -222,8 +222,7 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
VerifyOrExit(delay <= mCslFrameRequestAheadUs + kFramePreparationGuardInterval, frame = nullptr);
frame->SetTxDelay(txDelay);
frame->SetTxDelayBaseTime(
static_cast<uint32_t>(mCslTxNeighbor->GetLastRxTimestamp())); // Only LSB part of the time is required.
frame->SetTxDelayBaseTime(ConvertRadioTime64To32(mCslTxNeighbor->GetLastRxTimestamp()));
frame->SetCsmaCaEnabled(true);
exit:
+2 -2
View File
@@ -95,8 +95,8 @@ public:
TimeMilli GetCslLastHeard(void) const { return mCslLastHeard; }
void SetCslLastHeard(TimeMilli aCslLastHeard) { mCslLastHeard = aCslLastHeard; }
uint64_t GetLastRxTimestamp(void) const { return mLastRxTimestamp; }
void SetLastRxTimestamp(uint64_t aLastRxTimestamp) { mLastRxTimestamp = aLastRxTimestamp; }
RadioTime64 GetLastRxTimestamp(void) const { return mLastRxTimestamp; }
void SetLastRxTimestamp(RadioTime64 aLastRxTimestamp) { mLastRxTimestamp = aLastRxTimestamp; }
private:
uint8_t mCslTxAttempts : 7; ///< Number of CSL triggered tx attempts.
+3 -3
View File
@@ -344,13 +344,13 @@ void KeyManager::UpdateKeyMaterial(void)
Mac::KeyMaterial prevKey;
Mac::KeyMaterial nextKey;
curKey.SetFrom(hashKeys.GetMacKey(), kExportableMacKeys);
curKey.SetFrom(hashKeys.GetMacKey(), Mac::kDefaultMacKeysExportable);
ComputeKeys(mKeySequence - 1, hashKeys);
prevKey.SetFrom(hashKeys.GetMacKey(), kExportableMacKeys);
prevKey.SetFrom(hashKeys.GetMacKey(), Mac::kDefaultMacKeysExportable);
ComputeKeys(mKeySequence + 1, hashKeys);
nextKey.SetFrom(hashKeys.GetMacKey(), kExportableMacKeys);
nextKey.SetFrom(hashKeys.GetMacKey(), Mac::kDefaultMacKeysExportable);
Get<Mac::SubMac>().SetMacKey(Mac::Frame::kKeyIdMode1, (mKeySequence & 0x7f) + 1, prevKey, curKey, nextKey);
}
-1
View File
@@ -571,7 +571,6 @@ public:
private:
static constexpr uint16_t kDefaultKeySwitchGuardTime = 624; // ~ 93% of 672 (default key rotation time)
static constexpr uint32_t kKeySwitchGuardTimePercentage = 93; // Percentage of key rotation time.
static constexpr bool kExportableMacKeys = OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE;
static_assert(kDefaultKeySwitchGuardTime ==
SecurityPolicy::kDefaultKeyRotationTime * kKeySwitchGuardTimePercentage / 100,
+2
View File
@@ -970,6 +970,7 @@ Error Lowpan::DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint
}
else
{
VerifyOrExit(aDatagramLength >= aMessage.GetOffset() + sizeof(Ip6::UdpHeader), error = kErrorParse);
udpHeader.SetLength(aDatagramLength - aMessage.GetOffset());
}
@@ -1035,6 +1036,7 @@ Error Lowpan::Decompress(Message &aMessage,
if (aDatagramLength)
{
VerifyOrExit(aDatagramLength >= currentOffset + sizeof(Ip6::Header), error = kErrorParse);
ip6PayloadLength = BigEndian::HostSwap16(aDatagramLength - currentOffset - sizeof(Ip6::Header));
}
else
+46 -44
View File
@@ -53,11 +53,13 @@ void MessageFramer::DetermineMacSourceAddress(const Ip6::Address &aIp6Addr, Mac:
}
}
void MessageFramer::PrepareMacHeaders(Mac::TxFrame &aTxFrame, Mac::TxFrame::Info &aTxFrameInfo, const Message *aMessage)
void MessageFramer::PrepareMacHeaders(Mac::TxFrame &aTxFrame,
Mac::TxFrame::BuildInfo &aBuildInfo,
const Message *aMessage)
{
const Neighbor *neighbor;
aTxFrameInfo.mVersion = Mac::Frame::kVersion2006;
aBuildInfo.mVersion = Mac::Frame::kVersion2006;
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
@@ -67,7 +69,7 @@ void MessageFramer::PrepareMacHeaders(Mac::TxFrame &aTxFrame, Mac::TxFrame::Info
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Determine frame version and Header IE entries
neighbor = Get<NeighborTable>().FindNeighbor(aTxFrameInfo.mAddrs.mDestination);
neighbor = Get<NeighborTable>().FindNeighbor(aBuildInfo.mAddrs.mDestination);
if (neighbor == nullptr)
{
@@ -75,20 +77,20 @@ void MessageFramer::PrepareMacHeaders(Mac::TxFrame &aTxFrame, Mac::TxFrame::Info
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
else if (Get<Mac::Mac>().IsCslEnabled())
{
aTxFrameInfo.mAppendCslIe = true;
aTxFrameInfo.mVersion = Mac::Frame::kVersion2015;
aBuildInfo.mAppendCslIe = true;
aBuildInfo.mVersion = Mac::Frame::kVersion2015;
}
#endif
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
else if ((Get<ChildTable>().Contains(*neighbor) && static_cast<const Child *>(neighbor)->IsCslSynchronized()))
{
aTxFrameInfo.mVersion = Mac::Frame::kVersion2015;
aBuildInfo.mVersion = Mac::Frame::kVersion2015;
}
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
else if (neighbor->IsEnhAckProbingActive())
{
aTxFrameInfo.mVersion = Mac::Frame::kVersion2015;
aBuildInfo.mVersion = Mac::Frame::kVersion2015;
}
#endif
@@ -98,19 +100,19 @@ void MessageFramer::PrepareMacHeaders(Mac::TxFrame &aTxFrame, Mac::TxFrame::Info
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
if ((aMessage != nullptr) && aMessage->IsTimeSync())
{
aTxFrameInfo.mAppendTimeIe = true;
aTxFrameInfo.mVersion = Mac::Frame::kVersion2015;
aBuildInfo.mAppendTimeIe = true;
aBuildInfo.mVersion = Mac::Frame::kVersion2015;
}
#endif
aTxFrameInfo.mEmptyPayload = (aMessage == nullptr) || (aMessage->GetLength() == 0);
aBuildInfo.mEmptyPayload = (aMessage == nullptr) || (aMessage->GetLength() == 0);
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Prepare MAC headers
aTxFrameInfo.PrepareHeadersIn(aTxFrame);
aBuildInfo.PrepareHeadersIn(aTxFrame);
OT_UNUSED_VARIABLE(aMessage);
OT_UNUSED_VARIABLE(neighbor);
@@ -118,23 +120,23 @@ void MessageFramer::PrepareMacHeaders(Mac::TxFrame &aTxFrame, Mac::TxFrame::Info
void MessageFramer::PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address &aMacDest, bool aAckRequest)
{
Mac::TxFrame::Info frameInfo;
Mac::TxFrame::BuildInfo buildInfo;
frameInfo.mAddrs.mSource.SetShort(Get<Mac::Mac>().GetShortAddress());
buildInfo.mAddrs.mSource.SetShort(Get<Mac::Mac>().GetShortAddress());
if (frameInfo.mAddrs.mSource.IsShortAddrInvalid() || aMacDest.IsExtended())
if (buildInfo.mAddrs.mSource.IsShortAddrInvalid() || aMacDest.IsExtended())
{
frameInfo.mAddrs.mSource.SetExtended(Get<Mac::Mac>().GetExtAddress());
buildInfo.mAddrs.mSource.SetExtended(Get<Mac::Mac>().GetExtAddress());
}
frameInfo.mAddrs.mDestination = aMacDest;
frameInfo.mPanIds.SetBothSourceDestination(Get<Mac::Mac>().GetPanId());
buildInfo.mAddrs.mDestination = aMacDest;
buildInfo.mPanIds.SetBothSourceDestination(Get<Mac::Mac>().GetPanId());
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
frameInfo.mKeyIdMode = Mac::Frame::kKeyIdMode1;
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mKeyIdMode = Mac::Frame::kKeyIdMode1;
PrepareMacHeaders(aFrame, frameInfo, nullptr);
PrepareMacHeaders(aFrame, buildInfo, nullptr);
aFrame.SetAckRequest(aAckRequest);
aFrame.SetPayloadLength(0);
@@ -148,34 +150,34 @@ uint16_t MessageFramer::PrepareFrame(Mac::TxFrame &aFrame,
uint16_t aMeshDest,
bool aAddFragHeader)
{
Mac::TxFrame::Info frameInfo;
uint16_t payloadLength;
uint16_t origMsgOffset;
uint16_t nextOffset;
FrameBuilder frameBuilder;
Mac::TxFrame::BuildInfo buildInfo;
uint16_t payloadLength;
uint16_t origMsgOffset;
uint16_t nextOffset;
FrameBuilder frameBuilder;
start:
frameInfo.Clear();
buildInfo.Clear();
if (aMessage.IsLinkSecurityEnabled())
{
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
if (aMessage.GetSubType() == Message::kSubTypeJoinerEntrust)
{
frameInfo.mKeyIdMode = Mac::Frame::kKeyIdMode0;
buildInfo.mKeyIdMode = Mac::Frame::kKeyIdMode0;
}
else if (aMessage.IsMleCommand(Mle::kCommandAnnounce))
{
frameInfo.mKeyIdMode = Mac::Frame::kKeyIdMode2;
buildInfo.mKeyIdMode = Mac::Frame::kKeyIdMode2;
}
else
{
frameInfo.mKeyIdMode = Mac::Frame::kKeyIdMode1;
buildInfo.mKeyIdMode = Mac::Frame::kKeyIdMode1;
}
}
frameInfo.mPanIds.SetBothSourceDestination(Get<Mac::Mac>().GetPanId());
buildInfo.mPanIds.SetBothSourceDestination(Get<Mac::Mac>().GetPanId());
if (aMessage.IsSubTypeMle())
{
@@ -184,12 +186,12 @@ start:
case Mle::kCommandAnnounce:
aFrame.SetChannel(aMessage.GetChannel());
aFrame.SetRxChannelAfterTxDone(Get<Mac::Mac>().GetPanChannel());
frameInfo.mPanIds.SetDestination(Mac::kPanIdBroadcast);
buildInfo.mPanIds.SetDestination(Mac::kPanIdBroadcast);
break;
case Mle::kCommandDiscoveryRequest:
case Mle::kCommandDiscoveryResponse:
frameInfo.mPanIds.SetDestination(aMessage.GetPanId());
buildInfo.mPanIds.SetDestination(aMessage.GetPanId());
break;
default:
@@ -197,10 +199,10 @@ start:
}
}
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mAddrs = aMacAddrs;
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mAddrs = aMacAddrs;
PrepareMacHeaders(aFrame, frameInfo, &aMessage);
PrepareMacHeaders(aFrame, buildInfo, &aMessage);
frameBuilder.Init(aFrame.GetPayload(), aFrame.GetMaxPayloadLength());
@@ -350,15 +352,15 @@ start:
uint16_t MessageFramer::PrepareMeshFrame(Mac::TxFrame &aFrame, Message &aMessage, const Mac::Addresses &aMacAddrs)
{
Mac::TxFrame::Info frameInfo;
Mac::TxFrame::BuildInfo buildInfo;
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mAddrs = aMacAddrs;
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
frameInfo.mKeyIdMode = Mac::Frame::kKeyIdMode1;
frameInfo.mPanIds.SetBothSourceDestination(Get<Mac::Mac>().GetPanId());
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mAddrs = aMacAddrs;
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mKeyIdMode = Mac::Frame::kKeyIdMode1;
buildInfo.mPanIds.SetBothSourceDestination(Get<Mac::Mac>().GetPanId());
PrepareMacHeaders(aFrame, frameInfo, &aMessage);
PrepareMacHeaders(aFrame, buildInfo, &aMessage);
// write payload
OT_ASSERT(aMessage.GetLength() <= aFrame.GetMaxPayloadLength());
+1 -1
View File
@@ -131,7 +131,7 @@ private:
// (requiring one hop) and one as additional guard increment.
static constexpr uint8_t kMeshHeaderHopsLeft = Mle::kMaxRouteCost + 3;
void PrepareMacHeaders(Mac::TxFrame &aTxFrame, Mac::TxFrame::Info &aTxFrameInfo, const Message *aMessage);
void PrepareMacHeaders(Mac::TxFrame &aTxFrame, Mac::TxFrame::BuildInfo &aBuildInfo, const Message *aMessage);
uint16_t mFragTag;
};
+9 -9
View File
@@ -1627,15 +1627,15 @@ otError RadioSpinel::Transmit(otRadioFrame &aFrame)
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
if (mTransmitFrame->mInfo.mTxInfo.mIeInfo->mTimeIeOffset != 0)
{
uint64_t netRadioTime = otPlatRadioGetNow(mInstance);
uint64_t netSyncTime;
uint8_t *timeIe = mTransmitFrame->mPsdu + mTransmitFrame->mInfo.mTxInfo.mIeInfo->mTimeIeOffset;
otRadioTime64 netRadioTime = otPlatRadioGetNow(mInstance);
otRadioTime64 netSyncTime;
uint8_t *timeIe = mTransmitFrame->mPsdu + mTransmitFrame->mInfo.mTxInfo.mIeInfo->mTimeIeOffset;
if (netRadioTime == UINT64_MAX)
{
// If we can't get the radio time, get the platform time
netSyncTime = static_cast<uint64_t>(static_cast<int64_t>(otPlatTimeGet()) +
mTransmitFrame->mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset);
netSyncTime = static_cast<otRadioTime64>(static_cast<int64_t>(otPlatTimeGet()) +
mTransmitFrame->mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset);
}
else
{
@@ -1644,16 +1644,16 @@ otError RadioSpinel::Transmit(otRadioFrame &aFrame)
// If supported, add a delay and transmit the network time at a precise moment
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
transmitDelay = kTxWaitUs / 10;
mTransmitFrame->mInfo.mTxInfo.mTxDelayBaseTime = static_cast<uint32_t>(netRadioTime);
mTransmitFrame->mInfo.mTxInfo.mTxDelayBaseTime = static_cast<otRadioTime32>(netRadioTime);
mTransmitFrame->mInfo.mTxInfo.mTxDelay = transmitDelay;
#endif
netSyncTime = static_cast<uint64_t>(static_cast<int64_t>(netRadioTime) + transmitDelay +
mTransmitFrame->mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset);
netSyncTime = static_cast<otRadioTime64>(static_cast<int64_t>(netRadioTime) + transmitDelay +
mTransmitFrame->mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset);
}
*(timeIe++) = mTransmitFrame->mInfo.mTxInfo.mIeInfo->mTimeSyncSeq;
for (uint8_t i = 0; i < sizeof(uint64_t); i++)
for (uint8_t i = 0; i < sizeof(otRadioTime64); i++)
{
*(timeIe++) = static_cast<uint8_t>(netSyncTime & 0xff);
netSyncTime = netSyncTime >> 8;
+2 -2
View File
@@ -1709,8 +1709,8 @@ template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_RX_AT>(void)
SuccessOrExit(error = mDecoder.ReadUint8(channel));
{
uint64_t now = otPlatRadioGetNow(mInstance);
uint32_t start;
otRadioTime64 now = otPlatRadioGetNow(mInstance);
uint32_t start;
VerifyOrExit(when > now && (when - now) < UINT32_MAX, error = OT_ERROR_INVALID_ARGS);
+2 -2
View File
@@ -978,7 +978,7 @@ void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacF
OT_UNUSED_VARIABLE(aInstance);
}
uint64_t otPlatRadioGetNow(otInstance *aInstance)
otRadioTime64 otPlatRadioGetNow(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return GetRadioSpinel().GetNow();
@@ -1097,7 +1097,7 @@ otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance,
}
#endif
otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, otRadioTime32 aStart, uint32_t aDuration)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aChannel);
+1 -1
View File
@@ -385,7 +385,7 @@ otError otPlatRadioSleep(otInstance *) { return OT_ERROR_NONE; }
otError otPlatRadioReceive(otInstance *, uint8_t aChannel) { return FakePlatform::CurrentPlatform().Receive(aChannel); }
otError otPlatRadioReceiveAt(otInstance *, uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
otError otPlatRadioReceiveAt(otInstance *, uint8_t aChannel, otRadioTime32 aStart, uint32_t aDuration)
{
return FakePlatform::CurrentPlatform().ReceiveAt(aChannel, aStart, aDuration);
}
+54 -54
View File
@@ -66,17 +66,17 @@ TEST(RadioSpinelTransmit, shouldPassDesiredTxPowerToRadioPlatform)
txFrame.mPsdu = frameBuffer;
{
Mac::TxFrame::Info frameInfo;
Mac::TxFrame::BuildInfo buildInfo;
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mVersion = Mac::Frame::kVersion2006;
frameInfo.mAddrs.mSource.SetShort(kSrcAddr);
frameInfo.mAddrs.mDestination.SetExtended(kDstAddr);
frameInfo.mPanIds.SetSource(kSrcPanId);
frameInfo.mPanIds.SetDestination(kDstPanId);
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mVersion = Mac::Frame::kVersion2006;
buildInfo.mAddrs.mSource.SetShort(kSrcAddr);
buildInfo.mAddrs.mDestination.SetExtended(kDstAddr);
buildInfo.mPanIds.SetSource(kSrcPanId);
buildInfo.mPanIds.SetDestination(kDstPanId);
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
frameInfo.PrepareHeadersIn(txFrame);
buildInfo.PrepareHeadersIn(txFrame);
}
txFrame.mInfo.mTxInfo.mTxPower = kTxPower;
@@ -110,17 +110,17 @@ TEST(RadioSpinelTransmit, shouldCauseSwitchingToRxChannelAfterTxDone)
txFrame.mPsdu = frameBuffer;
{
Mac::TxFrame::Info frameInfo;
Mac::TxFrame::BuildInfo buildInfo;
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mVersion = Mac::Frame::kVersion2006;
frameInfo.mAddrs.mSource.SetShort(kSrcAddr);
frameInfo.mAddrs.mDestination.SetExtended(kDstAddr);
frameInfo.mPanIds.SetSource(kSrcPanId);
frameInfo.mPanIds.SetDestination(kDstPanId);
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mVersion = Mac::Frame::kVersion2006;
buildInfo.mAddrs.mSource.SetShort(kSrcAddr);
buildInfo.mAddrs.mDestination.SetExtended(kDstAddr);
buildInfo.mPanIds.SetSource(kSrcPanId);
buildInfo.mPanIds.SetDestination(kDstPanId);
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
frameInfo.PrepareHeadersIn(txFrame);
buildInfo.PrepareHeadersIn(txFrame);
}
txFrame.mInfo.mTxInfo.mTxPower = kTxPower;
@@ -156,17 +156,17 @@ TEST(RadioSpinelTransmit, shouldSkipCsmaCaWhenDisabled)
txFrame.mPsdu = frameBuffer;
{
Mac::TxFrame::Info frameInfo;
Mac::TxFrame::BuildInfo buildInfo;
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mVersion = Mac::Frame::kVersion2006;
frameInfo.mAddrs.mSource.SetShort(kSrcAddr);
frameInfo.mAddrs.mDestination.SetExtended(kDstAddr);
frameInfo.mPanIds.SetSource(kSrcPanId);
frameInfo.mPanIds.SetDestination(kDstPanId);
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mVersion = Mac::Frame::kVersion2006;
buildInfo.mAddrs.mSource.SetShort(kSrcAddr);
buildInfo.mAddrs.mDestination.SetExtended(kDstAddr);
buildInfo.mPanIds.SetSource(kSrcPanId);
buildInfo.mPanIds.SetDestination(kDstPanId);
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
frameInfo.PrepareHeadersIn(txFrame);
buildInfo.PrepareHeadersIn(txFrame);
}
txFrame.mInfo.mTxInfo.mCsmaCaEnabled = false;
@@ -212,17 +212,17 @@ TEST(RadioSpinelTransmit, shouldPerformCsmaCaWhenEnabled)
txFrame.mPsdu = frameBuffer;
{
Mac::TxFrame::Info frameInfo;
Mac::TxFrame::BuildInfo buildInfo;
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mVersion = Mac::Frame::kVersion2006;
frameInfo.mAddrs.mSource.SetShort(kSrcAddr);
frameInfo.mAddrs.mDestination.SetExtended(kDstAddr);
frameInfo.mPanIds.SetSource(kSrcPanId);
frameInfo.mPanIds.SetDestination(kDstPanId);
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mVersion = Mac::Frame::kVersion2006;
buildInfo.mAddrs.mSource.SetShort(kSrcAddr);
buildInfo.mAddrs.mDestination.SetExtended(kDstAddr);
buildInfo.mPanIds.SetSource(kSrcPanId);
buildInfo.mPanIds.SetDestination(kDstPanId);
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
frameInfo.PrepareHeadersIn(txFrame);
buildInfo.PrepareHeadersIn(txFrame);
}
txFrame.mInfo.mTxInfo.mCsmaCaEnabled = true;
@@ -262,17 +262,17 @@ TEST(RadioSpinelTransmit, shouldNotCauseSwitchingToRxAfterTxDoneIfNotRxOnWhenIdl
txFrame.mPsdu = frameBuffer;
{
Mac::TxFrame::Info frameInfo;
Mac::TxFrame::BuildInfo buildInfo;
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mVersion = Mac::Frame::kVersion2006;
frameInfo.mAddrs.mSource.SetShort(kSrcAddr);
frameInfo.mAddrs.mDestination.SetExtended(kDstAddr);
frameInfo.mPanIds.SetSource(kSrcPanId);
frameInfo.mPanIds.SetDestination(kDstPanId);
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mVersion = Mac::Frame::kVersion2006;
buildInfo.mAddrs.mSource.SetShort(kSrcAddr);
buildInfo.mAddrs.mDestination.SetExtended(kDstAddr);
buildInfo.mPanIds.SetSource(kSrcPanId);
buildInfo.mPanIds.SetDestination(kDstPanId);
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
frameInfo.PrepareHeadersIn(txFrame);
buildInfo.PrepareHeadersIn(txFrame);
}
txFrame.mInfo.mTxInfo.mTxPower = kTxPower;
@@ -338,17 +338,17 @@ TEST(RadioSpinelTransmit, shouldSkipCsmaBackoffWhenCsmaCaIsEnabledAndMaxBackoffs
txFrame.mPsdu = frameBuffer;
{
Mac::TxFrame::Info frameInfo;
Mac::TxFrame::BuildInfo buildInfo;
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mVersion = Mac::Frame::kVersion2006;
frameInfo.mAddrs.mSource.SetShort(kSrcAddr);
frameInfo.mAddrs.mDestination.SetExtended(kDstAddr);
frameInfo.mPanIds.SetSource(kSrcPanId);
frameInfo.mPanIds.SetDestination(kDstPanId);
frameInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mVersion = Mac::Frame::kVersion2006;
buildInfo.mAddrs.mSource.SetShort(kSrcAddr);
buildInfo.mAddrs.mDestination.SetExtended(kDstAddr);
buildInfo.mPanIds.SetSource(kSrcPanId);
buildInfo.mPanIds.SetDestination(kDstPanId);
buildInfo.mSecurityLevel = Mac::Frame::kSecurityEncMic32;
frameInfo.PrepareHeadersIn(txFrame);
buildInfo.PrepareHeadersIn(txFrame);
}
txFrame.mInfo.mTxInfo.mCsmaCaEnabled = true;
+2 -2
View File
@@ -156,7 +156,7 @@ exit:
return error;
}
uint64_t otPlatRadioGetNow(otInstance *aInstance)
otRadioTime64 otPlatRadioGetNow(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
@@ -332,7 +332,7 @@ otError otPlatRadioResetCsl(otInstance *aInstance)
return kErrorNone;
}
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, otRadioTime32 aCslSampleTime)
{
AsNode(aInstance).mRadio.mRadioContext.mCslSampleTime = aCslSampleTime;
}
-237
View File
@@ -1,237 +0,0 @@
#!/usr/bin/expect -f
#
# Copyright (c) 2025, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
source "tests/scripts/expect/_common.exp"
source "tests/scripts/expect/_multinode.exp"
set WL1 1
set WL2 2
set WC1 3
set WC2 4
set WL1_EXT_ADDRESS "deadbeefcafe0001"
set WL2_EXT_ADDRESS "deadbeefcafe0002"
set WC1_EXT_ADDRESS "deadbeefcafe0003"
set WC2_EXT_ADDRESS "deadbeefcafe0004"
send_user "\n\n>>> Setup WL1\n"
spawn_node $WL1
setup_default_network
send "mode rdn\n"
expect_line "Done"
send "extaddr $WL1_EXT_ADDRESS\n"
expect_line "Done"
send "wakeup channel 11\n"
expect_line "Done"
send "routerupgradethreshold 0\n"
expect_line "Done"
send "ifconfig up\n"
expect_line "Done"
send "thread start\n"
expect_line "Done"
send "wakeup listen enable\n"
expect_line "Done"
set wl1_link_local_addr [get_ipaddr linklocal]
send_user "\n\n>>> Setup WL2\n"
spawn_node $WL2
setup_default_network
send "mode rdn\n"
expect_line "Done"
send "extaddr $WL2_EXT_ADDRESS\n"
expect_line "Done"
send "wakeup channel 11\n"
expect_line "Done"
send "routerupgradethreshold 0\n"
expect_line "Done"
send "ifconfig up\n"
expect_line "Done"
send "thread start\n"
expect_line "Done"
send "wakeup listen enable\n"
expect_line "Done"
set wl2_link_local_addr [get_ipaddr linklocal]
send_user "\n\n>>> Setup WC1\n"
spawn_node $WC1
setup_default_network
send "mode rdn\n"
expect_line "Done"
send "extaddr $WC1_EXT_ADDRESS\n"
expect_line "Done"
send "wakeup channel 11\n"
expect_line "Done"
send "routerupgradethreshold 0\n"
expect_line "Done"
send "ifconfig up\n"
expect_line "Done"
send "thread start\n"
expect_line "Done"
set wc1_link_local_addr [get_ipaddr linklocal]
send_user "\n\n>>> Setup WC2\n"
spawn_node $WC2
setup_default_network
send "mode rdn\n"
expect_line "Done"
send "extaddr $WC2_EXT_ADDRESS\n"
expect_line "Done"
send "wakeup channel 11\n"
expect_line "Done"
send "routerupgradethreshold 0\n"
expect_line "Done"
send "ifconfig up\n"
expect_line "Done"
send "thread start\n"
expect_line "Done"
set wc2_link_local_addr [get_ipaddr linklocal]
send_user "\n\n>>> WC1 establishes a P2P link with WL1\n"
switch_node $WC1
send "p2p link extaddr $WL1_EXT_ADDRESS\n"
expect_line "Done"
send_user "\n\n>>> WC1 pings WL1\n"
send "ping $wl1_link_local_addr 20 5\n"
for {set i 1} {$i <= 5} {incr i} {
expect "28 bytes from $wl1_link_local_addr: icmp_seq=$i"
}
sleep 1
send_user "\n\n>>> WC1 establishes a P2P link with WL2\n"
send "p2p link extaddr $WL2_EXT_ADDRESS\n"
expect_line "Done"
sleep 1
send_user "\n\n>>> WC1 pings WL2\n"
send "ping $wl2_link_local_addr 20 5\n"
for {set i 6} {$i <= 10} {incr i} {
expect "28 bytes from $wl2_link_local_addr: icmp_seq=$i"
}
send_user "\n\n>>> WC2 establishes a P2P link with WL1\n"
switch_node $WC2
send "p2p link extaddr $WL1_EXT_ADDRESS\n"
expect_line "Done"
sleep 1
send_user "\n\n>>> WC2 pings WL1\n"
send "ping $wl1_link_local_addr 20 5\n"
for {set i 1} {$i <= 5} {incr i} {
expect "28 bytes from $wl1_link_local_addr: icmp_seq=$i"
}
send_user "\n\n>>> WL1 pings WC1\n"
switch_node $WL1
send "ping $wc1_link_local_addr 20 5\n"
for {set i 1} {$i <= 5} {incr i} {
expect "28 bytes from $wc1_link_local_addr: icmp_seq=$i"
}
send_user "\n\n>>> WL1 pings WC2\n"
send "ping $wc2_link_local_addr 20 5\n"
for {set i 6} {$i <= 10} {incr i} {
expect "28 bytes from $wc2_link_local_addr: icmp_seq=$i"
}
send_user "\n\n>>> WL2 pings WC1\n"
switch_node $WL2
send "ping $wc1_link_local_addr 20 5\n"
for {set i 1} {$i <= 5} {incr i} {
expect "28 bytes from $wc1_link_local_addr: icmp_seq=$i"
}
send_user "\n\n>>> WC1 tears down the P2P link with WL1\n"
switch_node $WC1
send "p2p unlink $WL1_EXT_ADDRESS\n"
expect_line "Done"
send_user "\n\n>>> WC2 tears down the P2P link with WL1\n"
switch_node $WC2
send "p2p unlink $WL1_EXT_ADDRESS\n"
expect_line "Done"
send_user "\n\n>>> WL2 tears down the P2P link with WC1\n"
switch_node $WL2
send "p2p unlink $WC1_EXT_ADDRESS\n"
expect_line "Done"
sleep 1
dispose_all
+112
View File
@@ -339,6 +339,115 @@ void TestAesCcmMessageProcessing(void)
printf("\nTestAesCcmMessageProcessing PASSED\n\n");
}
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
/**
* Verifies `otPlatCryptoAesCcmProcessOneShot` directly and via `AesCcm::Process`,
* using IEEE 802.15.4-2006 Annex C Section C.2.3
* (MAC command frame: 29-byte header, 1-byte payload, 8-byte MIC).
*/
void TestPlatformCcmSinglePart(void)
{
static const uint8_t kKey[] = {
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
};
static const uint8_t kNonce[] = {
0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x06,
};
static constexpr uint32_t kHeaderLength = 29;
static constexpr uint32_t kPayloadLength = 1;
static constexpr uint8_t kTagLength = 8;
static constexpr uint32_t kFrameLength = kHeaderLength + kPayloadLength + kTagLength;
static const uint8_t kPlainFrame[kHeaderLength + kPayloadLength] = {
0x2B, 0xDC, 0x84, 0x21, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0xFF, 0xFF,
0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x06, 0x05, 0x00, 0x00, 0x00, 0x01, 0xCE,
};
static const uint8_t kEncryptedFrame[kFrameLength] = {
0x2B, 0xDC, 0x84, 0x21, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC,
0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x06, 0x05, 0x00,
0x00, 0x00, 0x01, 0xD8, 0x4F, 0xDE, 0x52, 0x90, 0x61, 0xF9, 0xC6, 0xF1,
};
otInstance *instance = testInitInstance();
uint8_t frame[kFrameLength];
otPlatCryptoAesCcmConfig config;
printf("TestPlatformCcmSinglePart\n");
VerifyOrQuit(instance != nullptr);
config.mKey.mKey = kKey;
config.mKey.mKeyLength = sizeof(kKey);
config.mKey.mKeyRef = 0;
config.mNonce = kNonce;
config.mNonceLength = sizeof(kNonce);
config.mTagLength = kTagLength;
config.mHeaderLength = kHeaderLength;
config.mPlainTextLength = kPayloadLength;
// Direct encrypt/decrypt round-trip through the platform hook.
memcpy(frame, kPlainFrame, sizeof(kPlainFrame));
memset(frame + kHeaderLength + kPayloadLength, 0, kTagLength);
SuccessOrQuit(otPlatCryptoAesCcmProcessOneShot(true, &config, frame, frame + kHeaderLength));
DumpBuffer("encrypted", frame, sizeof(frame));
VerifyOrQuit(memcmp(frame, kEncryptedFrame, kFrameLength) == 0);
SuccessOrQuit(otPlatCryptoAesCcmProcessOneShot(false, &config, frame, frame + kHeaderLength));
DumpBuffer("decrypted", frame, kHeaderLength + kPayloadLength);
VerifyOrQuit(memcmp(frame, kPlainFrame, kHeaderLength + kPayloadLength) == 0);
// Tag corruption must be rejected.
memcpy(frame, kPlainFrame, sizeof(kPlainFrame));
memset(frame + kHeaderLength + kPayloadLength, 0, kTagLength);
SuccessOrQuit(otPlatCryptoAesCcmProcessOneShot(true, &config, frame, frame + kHeaderLength));
frame[kHeaderLength + kPayloadLength] ^= 0xFF;
VerifyOrQuit(otPlatCryptoAesCcmProcessOneShot(false, &config, frame, frame + kHeaderLength) == kErrorSecurity);
memcpy(frame, kPlainFrame, sizeof(kPlainFrame));
memset(frame + kHeaderLength + kPayloadLength, 0, kTagLength);
SuccessOrQuit(otPlatCryptoAesCcmProcessOneShot(true, &config, frame, frame + kHeaderLength));
frame[kFrameLength - 1] ^= 0x01;
VerifyOrQuit(otPlatCryptoAesCcmProcessOneShot(false, &config, frame, frame + kHeaderLength) == kErrorSecurity);
// AesCcm::Process must produce the same result as the direct platform call.
{
uint8_t directResult[kFrameLength];
uint8_t aesCcmResult[kFrameLength];
Crypto::AesCcm aesCcm;
memcpy(directResult, kPlainFrame, sizeof(kPlainFrame));
memset(directResult + kHeaderLength + kPayloadLength, 0, kTagLength);
SuccessOrQuit(otPlatCryptoAesCcmProcessOneShot(true, &config, directResult, directResult + kHeaderLength));
memcpy(aesCcmResult, kPlainFrame, sizeof(kPlainFrame));
memset(aesCcmResult + kHeaderLength + kPayloadLength, 0, kTagLength);
aesCcm.SetKey(kKey, sizeof(kKey));
aesCcm.SetNonce(kNonce, sizeof(kNonce));
aesCcm.SetAuthData(aesCcmResult, kHeaderLength);
aesCcm.SetTagLength(kTagLength);
SuccessOrQuit(aesCcm.Process(Crypto::AesCcm::kEncrypt, aesCcmResult + kHeaderLength, kPayloadLength));
VerifyOrQuit(memcmp(directResult, aesCcmResult, kFrameLength) == 0);
VerifyOrQuit(memcmp(aesCcmResult, kEncryptedFrame, kFrameLength) == 0);
aesCcm.SetKey(kKey, sizeof(kKey));
aesCcm.SetNonce(kNonce, sizeof(kNonce));
aesCcm.SetAuthData(aesCcmResult, kHeaderLength);
aesCcm.SetTagLength(kTagLength);
SuccessOrQuit(aesCcm.Process(Crypto::AesCcm::kDecrypt, aesCcmResult + kHeaderLength, kPayloadLength));
VerifyOrQuit(memcmp(aesCcmResult, kPlainFrame, kHeaderLength + kPayloadLength) == 0);
}
testFreeInstance(instance);
printf("\nTestPlatformCcmSinglePart PASSED\n\n");
}
#endif // OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
} // namespace ot
int main(void)
@@ -346,6 +455,9 @@ int main(void)
ot::TestMacBeaconFrame();
ot::TestMacCommandFrame();
ot::TestAesCcmMessageProcessing();
#if OPENTHREAD_CONFIG_CRYPTO_PLATFORM_CCM_ONE_SHOT_ENABLE
ot::TestPlatformCcmSinglePart();
#endif
printf("All tests passed\n");
return 0;
}
+63 -16
View File
@@ -37,23 +37,28 @@ namespace ot {
void TestCountBitsInMask(void)
{
VerifyOrQuit(CountBitsInMask<uint8_t>(0) == 0);
VerifyOrQuit(CountBitsInMask<uint8_t>(1) == 1);
VerifyOrQuit(CountBitsInMask<uint8_t>(2) == 1);
VerifyOrQuit(CountBitsInMask<uint8_t>(3) == 2);
VerifyOrQuit(CountBitsInMask<uint8_t>(4) == 1);
VerifyOrQuit(CountBitsInMask<uint8_t>(7) == 3);
VerifyOrQuit(CountBitsInMask<uint8_t>(11) == 3);
VerifyOrQuit(CountBitsInMask<uint8_t>(15) == 4);
VerifyOrQuit(CountBitsInMask<uint8_t>(0x11) == 2);
VerifyOrQuit(CountBitsInMask<uint8_t>(0xef) == 7);
VerifyOrQuit(CountBitsInMask<uint8_t>(0xff) == 8);
VerifyOrQuit(CountBitsInMask(0) == 0);
VerifyOrQuit(CountBitsInMask(1) == 1);
VerifyOrQuit(CountBitsInMask(2) == 1);
VerifyOrQuit(CountBitsInMask(3) == 2);
VerifyOrQuit(CountBitsInMask(4) == 1);
VerifyOrQuit(CountBitsInMask(7) == 3);
VerifyOrQuit(CountBitsInMask(11) == 3);
VerifyOrQuit(CountBitsInMask(15) == 4);
VerifyOrQuit(CountBitsInMask(0x11) == 2);
VerifyOrQuit(CountBitsInMask(0xef) == 7);
VerifyOrQuit(CountBitsInMask(0xff) == 8);
VerifyOrQuit(CountBitsInMask<uint16_t>(0) == 0);
VerifyOrQuit(CountBitsInMask<uint16_t>(0xff00) == 8);
VerifyOrQuit(CountBitsInMask<uint16_t>(0xff) == 8);
VerifyOrQuit(CountBitsInMask<uint16_t>(0xaa55) == 8);
VerifyOrQuit(CountBitsInMask<uint16_t>(0xffff) == 16);
VerifyOrQuit(CountBitsInMask(0xff00) == 8);
VerifyOrQuit(CountBitsInMask(0xaa55) == 8);
VerifyOrQuit(CountBitsInMask(0xffff) == 16);
VerifyOrQuit(CountBitsInMask(0x10000) == 1);
VerifyOrQuit(CountBitsInMask(0xff0055) == 12);
VerifyOrQuit(CountBitsInMask(0xaa0055) == 8);
VerifyOrQuit(CountBitsInMask(0xaa007700) == 10);
VerifyOrQuit(CountBitsInMask(0xffff0000) == 16);
VerifyOrQuit(CountBitsInMask(0xffffffff) == 32);
printf("TestCountBitsInMask() passed\n");
}
@@ -130,6 +135,47 @@ void TestCountMatchingBitsExamples(void)
printf("TestCountMatchingBitsExamples() passed\n");
}
void TestDetermineMinBitSize(void)
{
VerifyOrQuit(DetermineMinBitSizeFor(0) == 1);
VerifyOrQuit(DetermineMinBitSizeFor(1) == 1);
VerifyOrQuit(DetermineMinBitSizeFor(2) == 2);
VerifyOrQuit(DetermineMinBitSizeFor(3) == 2);
VerifyOrQuit(DetermineMinBitSizeFor(4) == 3);
VerifyOrQuit(DetermineMinBitSizeFor(6) == 3);
VerifyOrQuit(DetermineMinBitSizeFor(7) == 3);
VerifyOrQuit(DetermineMinBitSizeFor(8) == 4);
VerifyOrQuit(DetermineMinBitSizeFor(11) == 4);
VerifyOrQuit(DetermineMinBitSizeFor(15) == 4);
VerifyOrQuit(DetermineMinBitSizeFor(16) == 5);
VerifyOrQuit(DetermineMinBitSizeFor(30) == 5);
VerifyOrQuit(DetermineMinBitSizeFor(32) == 6);
VerifyOrQuit(DetermineMinBitSizeFor(127) == 7);
VerifyOrQuit(DetermineMinBitSizeFor(128) == 8);
VerifyOrQuit(DetermineMinBitSizeFor(255) == 8);
VerifyOrQuit(DetermineMinBitSizeFor(256) == 9);
VerifyOrQuit(DetermineMinBitSizeFor(500) == 9);
VerifyOrQuit(DetermineMinBitSizeFor(1000) == 10);
VerifyOrQuit(DetermineMinBitSizeFor(1023) == 10);
VerifyOrQuit(DetermineMinBitSizeFor(1024) == 11);
VerifyOrQuit(DetermineMinBitSizeFor(2000) == 11);
VerifyOrQuit(DetermineMinBitSizeFor(0xffff) == 16);
VerifyOrQuit(DetermineMinBitSizeFor(0x10000) == 17);
VerifyOrQuit(DetermineMinBitSizeFor(0x7fffffff) == 31);
VerifyOrQuit(DetermineMinBitSizeFor(0x80000000) == 32);
VerifyOrQuit(DetermineMinBitSizeFor(0xffffffff) == 32);
printf("TestDetermineMinBitSize() passed\n");
}
} // namespace ot
int main(void)
@@ -137,6 +183,7 @@ int main(void)
ot::TestCountBitsInMask();
ot::TestCountMatchingBitsAllCombinations();
ot::TestCountMatchingBitsExamples();
ot::TestDetermineMinBitSize();
printf("All tests passed\n");
return 0;
+113 -316
View File
@@ -290,43 +290,43 @@ void TestMacHeader(void)
uint8_t psdu[OT_RADIO_FRAME_MAX_SIZE];
uint8_t offset;
Mac::TxFrame frame;
Mac::TxFrame::Info frameInfo;
Mac::Address address;
Mac::PanId panId;
Mac::TxFrame frame;
Mac::TxFrame::BuildInfo buildInfo;
Mac::Address address;
Mac::PanId panId;
frame.mPsdu = psdu;
frame.mLength = 0;
frame.mRadioType = 0;
VerifyOrQuit(frameInfo.mAddrs.mSource.IsNone());
VerifyOrQuit(frameInfo.mAddrs.mDestination.IsNone());
VerifyOrQuit(!frameInfo.mPanIds.IsSourcePresent());
VerifyOrQuit(!frameInfo.mPanIds.IsDestinationPresent());
VerifyOrQuit(buildInfo.mAddrs.mSource.IsNone());
VerifyOrQuit(buildInfo.mAddrs.mDestination.IsNone());
VerifyOrQuit(!buildInfo.mPanIds.IsSourcePresent());
VerifyOrQuit(!buildInfo.mPanIds.IsDestinationPresent());
switch (testCase.mSrcAddrType)
{
case kNoneAddr:
frameInfo.mAddrs.mSource.SetNone();
buildInfo.mAddrs.mSource.SetNone();
break;
case kShrtAddr:
frameInfo.mAddrs.mSource.SetShort(kShortAddr1);
buildInfo.mAddrs.mSource.SetShort(kShortAddr1);
break;
case kExtdAddr:
frameInfo.mAddrs.mSource.SetExtended(extAddr1);
buildInfo.mAddrs.mSource.SetExtended(extAddr1);
break;
}
switch (testCase.mDstAddrType)
{
case kNoneAddr:
frameInfo.mAddrs.mDestination.SetNone();
buildInfo.mAddrs.mDestination.SetNone();
break;
case kShrtAddr:
frameInfo.mAddrs.mDestination.SetShort(kShortAddr2);
buildInfo.mAddrs.mDestination.SetShort(kShortAddr2);
break;
case kExtdAddr:
frameInfo.mAddrs.mDestination.SetExtended(extAddr2);
buildInfo.mAddrs.mDestination.SetExtended(extAddr2);
break;
}
@@ -335,10 +335,10 @@ void TestMacHeader(void)
case kNoPanId:
break;
case kUsePanId1:
frameInfo.mPanIds.SetSource(kPanId1);
buildInfo.mPanIds.SetSource(kPanId1);
break;
case kUsePanId2:
frameInfo.mPanIds.SetSource(kPanId2);
buildInfo.mPanIds.SetSource(kPanId2);
break;
}
@@ -347,20 +347,20 @@ void TestMacHeader(void)
case kNoPanId:
break;
case kUsePanId1:
frameInfo.mPanIds.SetDestination(kPanId1);
buildInfo.mPanIds.SetDestination(kPanId1);
break;
case kUsePanId2:
frameInfo.mPanIds.SetDestination(kPanId2);
buildInfo.mPanIds.SetDestination(kPanId2);
break;
}
frameInfo.mType = Mac::Frame::kTypeData;
frameInfo.mVersion = testCase.mVersion;
frameInfo.mSecurityLevel = testCase.mSecurity;
frameInfo.mKeyIdMode = testCase.mKeyIdMode;
frameInfo.mSuppressSequence = testCase.mSuppressSequence;
buildInfo.mType = Mac::Frame::kTypeData;
buildInfo.mVersion = testCase.mVersion;
buildInfo.mSecurityLevel = testCase.mSecurity;
buildInfo.mKeyIdMode = testCase.mKeyIdMode;
buildInfo.mSuppressSequence = testCase.mSuppressSequence;
frameInfo.PrepareHeadersIn(frame);
buildInfo.PrepareHeadersIn(frame);
VerifyOrQuit(frame.GetHeaderLength() == testCase.mHeaderLength);
VerifyOrQuit(frame.GetFooterLength() == testCase.mFooterLength);
@@ -376,25 +376,25 @@ void TestMacHeader(void)
VerifyOrQuit(frame.IsSrcAddrPresent() == (testCase.mSrcAddrType != kNoneAddr));
SuccessOrQuit(frame.GetSrcAddr(address));
VerifyOrQuit(CompareAddresses(address, frameInfo.mAddrs.mSource));
VerifyOrQuit(CompareAddresses(address, buildInfo.mAddrs.mSource));
VerifyOrQuit(frame.IsDstAddrPresent() == (testCase.mDstAddrType != kNoneAddr));
SuccessOrQuit(frame.GetDstAddr(address));
VerifyOrQuit(CompareAddresses(address, frameInfo.mAddrs.mDestination));
VerifyOrQuit(CompareAddresses(address, buildInfo.mAddrs.mDestination));
VerifyOrQuit(frame.IsDstPanIdPresent() == (testCase.mDstPanIdMode != kNoPanId));
if (frame.IsDstPanIdPresent())
{
SuccessOrQuit(frame.GetDstPanId(panId));
VerifyOrQuit(panId == frameInfo.mPanIds.GetDestination());
VerifyOrQuit(frameInfo.mPanIds.IsDestinationPresent());
VerifyOrQuit(panId == buildInfo.mPanIds.GetDestination());
VerifyOrQuit(buildInfo.mPanIds.IsDestinationPresent());
}
if (frame.IsSrcPanIdPresent())
{
SuccessOrQuit(frame.GetSrcPanId(panId));
VerifyOrQuit(panId == frameInfo.mPanIds.GetSource());
VerifyOrQuit(frameInfo.mPanIds.IsSourcePresent());
VerifyOrQuit(panId == buildInfo.mPanIds.GetSource());
VerifyOrQuit(buildInfo.mPanIds.IsSourcePresent());
}
if (frame.GetSecurityEnabled())
@@ -470,6 +470,88 @@ void VerifyChannelMaskContent(const Mac::ChannelMask &aMask, uint8_t *aChannels,
VerifyOrQuit(aLength == aMask.GetNumberOfChannels());
}
void TestMacHeaderIeStartEnd(void)
{
using HeaderIe = Mac::HeaderIe;
static const uint8_t kIeId1 = 0x0a;
static const uint8_t kIeId2 = 0x0b;
static const uint8_t kIeId3 = 0x0c;
static const uint8_t kContent[] = {0x11, 0x22, 0x33, 0x44, 0x55};
uint8_t buffer[256];
FrameBuilder builder;
uint16_t offset;
HeaderIe::Bookmark bookmark;
HeaderIe *ie;
uint8_t largeContent[128];
printf("TestMacHeaderIeStartEnd\n");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Normal use: Append an IE (5 bytes content)
builder.Init(buffer, sizeof(buffer));
SuccessOrQuit(HeaderIe::StartIe(builder, kIeId1, bookmark));
VerifyOrQuit(builder.GetLength() == sizeof(HeaderIe));
SuccessOrQuit(builder.AppendBytes(kContent, sizeof(kContent)));
SuccessOrQuit(HeaderIe::EndIe(builder, bookmark));
VerifyOrQuit(builder.GetLength() == sizeof(HeaderIe) + sizeof(kContent));
ie = reinterpret_cast<HeaderIe *>(buffer);
VerifyOrQuit(ie->GetId() == kIeId1);
VerifyOrQuit(ie->GetLength() == sizeof(kContent));
VerifyOrQuit(ie->GetSize() == sizeof(HeaderIe) + sizeof(kContent));
VerifyOrQuit(memcmp(ie->GetContent(), kContent, sizeof(kContent)) == 0);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Normal use: Append a new IE with empty payload (0-length IE)
offset = builder.GetLength();
SuccessOrQuit(HeaderIe::StartIe(builder, kIeId2, bookmark));
SuccessOrQuit(HeaderIe::EndIe(builder, bookmark));
// First IE should remain untouched
ie = reinterpret_cast<HeaderIe *>(buffer);
VerifyOrQuit(ie->GetId() == kIeId1);
VerifyOrQuit(ie->GetLength() == sizeof(kContent));
VerifyOrQuit(ie->GetSize() == sizeof(HeaderIe) + sizeof(kContent));
VerifyOrQuit(memcmp(ie->GetContent(), kContent, sizeof(kContent)) == 0);
// Second IE with empty content
ie = builder.Read<HeaderIe>(offset);
VerifyOrQuit(ie->GetId() == kIeId2);
VerifyOrQuit(ie->GetLength() == 0);
VerifyOrQuit(ie->GetSize() == sizeof(HeaderIe));
VerifyOrQuit(builder.GetLength() == 2 * sizeof(HeaderIe) + sizeof(kContent));
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Maximum allowed IE length (127 bytes)
memset(largeContent, 0xaa, sizeof(largeContent));
builder.Init(buffer, sizeof(buffer));
SuccessOrQuit(HeaderIe::StartIe(builder, kIeId3, bookmark));
SuccessOrQuit(builder.AppendBytes(largeContent, HeaderIe::kMaxLength));
SuccessOrQuit(HeaderIe::EndIe(builder, bookmark));
ie = builder.Read<HeaderIe>(0);
VerifyOrQuit(ie->GetId() == kIeId3);
VerifyOrQuit(ie->GetLength() == HeaderIe::kMaxLength);
VerifyOrQuit(builder.GetLength() == ie->GetSize());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Exceeding maximum length (128 bytes > 127)
builder.Init(buffer, sizeof(buffer));
SuccessOrQuit(HeaderIe::StartIe(builder, kIeId3, bookmark));
SuccessOrQuit(builder.AppendBytes(largeContent, HeaderIe::kMaxLength + 1));
VerifyOrQuit(HeaderIe::EndIe(builder, bookmark) == kErrorInvalidArgs);
}
void TestMacChannelMask(void)
{
uint8_t allChannels[] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};
@@ -782,301 +864,16 @@ 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 kMpFcfDstAddrNone = 0 << kMpFcfDstAddrShift;
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 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
Mac::Frame::kTypeMultipurpose | kMpFcfLongFrame | kMpFcfDstAddrExt | kMpFcfSrcAddrExt,
(kMpFcfPanidPresent | kMpFcfSecurityEnabled | kMpFcfSequenceSuppression | kMpFcfIePresent) >> 8,
// PAN ID
0xce, 0xfa,
// Destination Address
0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1, 0xf0,
// 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
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;
printf("TestMacWakeupFrameGeneration\n");
src.SetExtended(kSrcExtaddr);
dst.SetExtended(kDstExtaddr);
wakeupRequest.SetExtAddress(dst.GetExtended());
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.Has<Mac::RendezvousTimeIe>());
VerifyOrQuit(txFrame.Has<Mac::ConnectionIe>());
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(kKeySource);
txFrame.SetKeyId(0x1d);
txFrame.Find<Mac::RendezvousTimeIe>()->SetRendezvousTime(0xabcd);
connectionIe = txFrame.Find<Mac::ConnectionIe>();
connectionIe->SetRetryInterval(1);
connectionIe->SetRetryCount(12);
VerifyOrQuit(connectionIe->SetWakeupId(kWakeupId) == kErrorParse);
VerifyOrQuit(txFrame.Find<Mac::RendezvousTimeIe>()->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);
// 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());
// 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.Has<Mac::RendezvousTimeIe>());
VerifyOrQuit(txFrame.Has<Mac::ConnectionIe>());
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.Find<Mac::RendezvousTimeIe>()->SetRendezvousTime(0xabcd);
connectionIe = txFrame.Find<Mac::ConnectionIe>();
connectionIe->SetRetryInterval(1);
connectionIe->SetRetryCount(12);
SuccessOrQuit(connectionIe->SetWakeupId(kWakeupId));
VerifyOrQuit(txFrame.Find<Mac::RendezvousTimeIe>()->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)
{
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)
{
ot::TestMacAddress();
ot::TestMacHeader();
ot::TestMacHeaderIeStartEnd();
ot::TestMacChannelMask();
ot::TestMacFrameApi();
ot::TestMacFrameAckGeneration();
#if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
ot::TestMacWakeupFrameGeneration();
ot::TestMacWakeupFrameDetectionNegative();
#endif
printf("All tests passed\n");
return 0;
}
+1 -1
View File
@@ -457,7 +457,7 @@ OT_TOOL_WEAK otError otPlatRadioEnableCsl(otInstance *, uint32_t, otShortAddress
OT_TOOL_WEAK otError otPlatRadioResetCsl(otInstance *) { return OT_ERROR_NONE; }
OT_TOOL_WEAK void otPlatRadioUpdateCslSampleTime(otInstance *, uint32_t) {}
OT_TOOL_WEAK void otPlatRadioUpdateCslSampleTime(otInstance *, otRadioTime32) {}
OT_TOOL_WEAK uint8_t otPlatRadioGetCslAccuracy(otInstance *)
{