[low-power] implement enhanced-ack based probing (#5780)

This commit implements Enhanced-ACK Probing (on simulation platform).

- Add a new public API otLinkMetricsConfigEnhAckProbing which sends
  Link Metrics Management Request to configure the probing. This is
  called on Probing Initiator side.

- Add a new radio platform API otPlatRadioConfigureEnhAckProbing. This
  API should be called on Probing Subject side when handling the
  requests from Initiators. This API notifies the radio to start/stop
  aggregating link metrics info and include the data into Vendor IE in
  enhanced-ACK for the specific neighbor. As discussed in #5746, the
  code for doing such thing should be put in radio driver.

- Add a util module util/link_metrics, which provides a group of APIs
  to implement Probing Subject side logic for Enh-ACK Probing. Any
  platform could use this module to implement the feature easily in
  radio driver.

- Add new util APIs in util/mac_frame to generate Enh-ACK Probing IE
  (Vendor IE with Thread OUI and SubType = 0) and set value for this
  IE.

- Update the implementation in simulation/radio.c to support Probing
  Subject side logic for Enh-ACK Probing, using APIs in
  util/link_metrics and util/mac_frame.

- Add a test
  v1_2_LowPower_7_1_01_SingleProbeLinkMetricsWithEnhancedAcks.py for
  testing.

Misc:

  - Add check for all the public Link Metrics APIs (Initiator side) to
    ensure that the Subject is a neighbor of the Initiator. If the
    address is not link-local or the neighbor is not found, an error
    UNKNOWN_NEIGHBOR would be returned.

  - Update PrepareEmptyFrame so that when it's called for reference
    device, its frame version would be set to 2015.
This commit is contained in:
Li Cao
2020-12-10 23:31:41 -08:00
committed by GitHub
parent 02f7dbb42b
commit ae07fe27ff
33 changed files with 1877 additions and 176 deletions
+12
View File
@@ -1287,3 +1287,15 @@ void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTi
sCslSampleTime = aCslSampleTime;
}
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otError otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,
otLinkMetrics aLinkMetrics,
const otShortAddress aShortAddress,
const otExtAddress * aExtAddress)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
#endif
+65 -15
View File
@@ -41,6 +41,7 @@
#include "common/code_utils.hpp"
#include "utils/code_utils.h"
#include "utils/link_metrics.h"
#include "utils/mac_frame.h"
#include "utils/soft_source_match_table.h"
@@ -92,6 +93,9 @@ static void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFra
static void radioSendMessage(otInstance *aInstance);
static void radioSendAck(void);
static void radioProcessFrame(otInstance *aInstance);
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetricsIeDataLen);
#endif
static otRadioState sState = OT_RADIO_STATE_DISABLED;
static struct RadioMessage sReceiveMessage;
@@ -130,9 +134,8 @@ static uint8_t sAckIeDataLength = 0;
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
static const uint8_t sCslIeHeader[OT_IE_HEADER_SIZE] = {CSL_IE_HEADER_BYTES_LO, CSL_IE_HEADER_BYTES_HI};
static uint32_t sCslSampleTime;
static uint32_t sCslPeriod;
static uint32_t sCslSampleTime;
static uint32_t sCslPeriod;
#endif
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
@@ -373,6 +376,10 @@ void platformRadioInit(void)
{
sChannelMaxTransmitPower[i] = OT_RADIO_POWER_INVALID;
}
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otLinkMetricsInit(SIM_RECEIVE_SENSITIVITY);
#endif
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -860,6 +867,26 @@ void radioSendAck(void)
// Use enh-ack for 802.15.4-2015 frames
if (otMacFrameIsVersion2015(&sReceiveFrame))
{
uint8_t linkMetricsDataLen = 0;
uint8_t *dataPtr = NULL;
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
uint8_t linkMetricsData[OT_ENH_PROBING_IE_DATA_MAX_SIZE];
otMacAddress macAddress;
otEXPECT(otMacFrameGetSrcAddr(&sReceiveFrame, &macAddress) == OT_ERROR_NONE);
linkMetricsDataLen = otLinkMetricsEnhAckGenData(&macAddress, sReceiveFrame.mInfo.mRxInfo.mLqi,
sReceiveFrame.mInfo.mRxInfo.mRssi, linkMetricsData);
if (linkMetricsDataLen > 0)
{
dataPtr = linkMetricsData;
}
#endif
sAckIeDataLength = generateAckIeData(dataPtr, linkMetricsDataLen);
otEXPECT(otMacFrameGenerateEnhAck(&sReceiveFrame, sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending,
sAckIeData, sAckIeDataLength, &sAckFrame) == OT_ERROR_NONE);
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -892,7 +919,9 @@ exit:
void radioProcessFrame(otInstance *aInstance)
{
otError error = OT_ERROR_NONE;
otError error = OT_ERROR_NONE;
otMacAddress macAddress;
OT_UNUSED_VARIABLE(macAddress);
sReceiveFrame.mInfo.mRxInfo.mRssi = -20;
sReceiveFrame.mInfo.mRxInfo.mLqi = OT_RADIO_LQI_NONE;
@@ -905,6 +934,10 @@ void radioProcessFrame(otInstance *aInstance)
otEXPECT_ACTION(otMacFrameDoesAddrMatch(&sReceiveFrame, sPanid, sShortAddress, &sExtAddress),
error = OT_ERROR_ABORT);
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otEXPECT_ACTION(otMacFrameGetSrcAddr(&sReceiveFrame, &macAddress) == OT_ERROR_NONE, error = OT_ERROR_PARSE);
#endif
// generate acknowledgment
if (otMacFrameIsAckRequested(&sReceiveFrame))
{
@@ -1104,26 +1137,33 @@ uint64_t otPlatRadioGetNow(otInstance *aInstance)
return otPlatTimeGet();
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
static otError updateIeData(otInstance *aInstance)
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetricsIeDataLen)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aLinkMetricsIeData);
OT_UNUSED_VARIABLE(aLinkMetricsIeDataLen);
otError error = OT_ERROR_NONE;
uint8_t offset = 0;
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (sCslPeriod > 0)
{
memcpy(sAckIeData, sCslIeHeader, OT_IE_HEADER_SIZE);
offset += OT_IE_HEADER_SIZE + OT_CSL_IE_SIZE; // reserve space for CSL IE
offset += otMacFrameGenerateCslIeTemplate(sAckIeData);
}
#endif
sAckIeDataLength = offset;
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
if (aLinkMetricsIeData != NULL && aLinkMetricsIeDataLen > 0)
{
offset += otMacFrameGenerateEnhAckProbingIe(sAckIeData, aLinkMetricsIeData, aLinkMetricsIeDataLen);
}
#endif
return error;
return offset;
}
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, const otExtAddress *aExtAddr)
{
OT_UNUSED_VARIABLE(aInstance);
@@ -1133,8 +1173,6 @@ otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, const o
sCslPeriod = aCslPeriod;
error = updateIeData(aInstance);
return error;
}
@@ -1186,3 +1224,15 @@ otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aCh
exit:
return error;
}
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otError otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,
otLinkMetrics aLinkMetrics,
const otShortAddress aShortAddress,
const otExtAddress * aExtAddress)
{
OT_UNUSED_VARIABLE(aInstance);
return otLinkMetricsConfigureEnhAckProbing(aShortAddress, aExtAddress, aLinkMetrics);
}
#endif
+1
View File
@@ -28,6 +28,7 @@
add_library(openthread-platform-utils OBJECT
debug_uart.c
link_metrics.cpp
logging_rtt.c
mac_frame.cpp
otns_utils.cpp
+2
View File
@@ -40,6 +40,8 @@ libopenthread_platform_utils_a_CPPFLAGS = \
libopenthread_platform_utils_a_SOURCES = \
code_utils.h \
debug_uart.c \
link_metrics.cpp \
link_metrics.h \
logging_rtt.c \
logging_rtt.h \
mac_frame.cpp \
+239
View File
@@ -0,0 +1,239 @@
/*
* Copyright (c) 2020, 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.
*/
#include "link_metrics.h"
#include <openthread/link_metrics.h>
#include "common/clearable.hpp"
#include "common/linked_list.hpp"
#include "common/pool.hpp"
#include "thread/link_quality.hpp"
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
using namespace ot;
static int8_t sNoiseFloor; ///< The noise floor used by Link Metrics. It should be set to the platform's
///< noise floor (measured noise floor, receiver sensitivity or a constant).
class LinkMetricsDataInfo : public LinkedListEntry<LinkMetricsDataInfo>, public Clearable<LinkMetricsDataInfo>
{
friend class LinkedList<LinkMetricsDataInfo>;
friend class LinkedListEntry<LinkMetricsDataInfo>;
public:
/**
* Construtor.
*
*/
LinkMetricsDataInfo(void) { Clear(); };
/**
* Set the information for this object.
*
* @param[in] aLinkMetrics Flags specifying what metrics to query.
* @param[in] aShortAddress Short Address of the Probing Initiator tracked by this object.
* @param[in] aExtAddress A reference to the Extended Address of the Probing Initiator tracked by this
* object.
*
*/
void Set(otLinkMetrics aLinkMetrics, otShortAddress aShortAddress, const otExtAddress &aExtAddress)
{
mLinkMetrics = aLinkMetrics;
mShortAddress = aShortAddress;
memcpy(mExtAddress.m8, aExtAddress.m8, sizeof(aExtAddress));
}
/**
* This method gets Link Metrics data stored in this object.
*
* TODO: Currently the order of Link Metircs data is fixed. Will update it to follow the order specified in TLV.
*
* @param[in] aLqi LQI value of the acknowledeged frame.
* @param[in] aRssi RSSI value of the acknowledged frame.
* @param[out] aData A pointer to the output buffer. @p aData MUST NOT be `nullptr`. The buffer must have
* at least 2 bytes (per spec 4.11.3.4.4.6). Otherwise the behavior would be undefined.
*
* @returns The number of bytes written. `0` on failure.
*
*/
uint8_t GetEnhAckData(uint8_t aLqi, int8_t aRssi, uint8_t *aData) const
{
enum
{
kEnhAckProbingDataMaxLen = 2,
};
uint8_t bytes = 0;
VerifyOrExit(aData != nullptr);
if (mLinkMetrics.mLqi)
{
aData[bytes++] = aLqi;
}
if (mLinkMetrics.mLinkMargin)
{
aData[bytes++] = static_cast<uint8_t>(GetLinkMargin(aRssi) * 255 /
130); // Linear scale Link Margin from [0, 130] to [0, 255]
}
if (bytes < kEnhAckProbingDataMaxLen && mLinkMetrics.mRssi)
{
aData[bytes++] =
static_cast<uint8_t>((aRssi + 130) * 255 / 130); // Linear scale RSSI from [-130, 0] to [0, 255]
}
exit:
return bytes;
}
/**
* This method gets the metrics configured for the Enhanced-ACK Based Probing.
*
* @returns The metrics configured.
*
*/
otLinkMetrics GetLinkMetrics(void) const { return mLinkMetrics; }
private:
uint8_t GetLinkMargin(int8_t aRssi) const { return LinkQualityInfo::ConvertRssToLinkMargin(sNoiseFloor, aRssi); }
bool Matches(const otShortAddress &aShortAddress) const { return mShortAddress == aShortAddress; };
bool Matches(const otExtAddress &aExtAddress) const
{
return memcmp(&mExtAddress, &aExtAddress, sizeof(otExtAddress)) == 0;
};
LinkMetricsDataInfo *mNext;
otLinkMetrics mLinkMetrics;
otShortAddress mShortAddress;
otExtAddress mExtAddress;
};
enum
{
kMaxEnhAckProbingInitiator = 10,
};
typedef Pool<LinkMetricsDataInfo, kMaxEnhAckProbingInitiator> LinkMetricsDataInfoPool;
typedef LinkedList<LinkMetricsDataInfo> LinkMetricsDataInfoList;
static LinkMetricsDataInfoPool &GetLinkMetricsDataInfoPool(void)
{
static LinkMetricsDataInfoPool sDataInfoPool;
return sDataInfoPool;
}
static LinkMetricsDataInfoList &GetLinkMetricsDataInfoActiveList(void)
{
static LinkMetricsDataInfoList sDataInfoActiveList;
return sDataInfoActiveList;
}
static inline bool IsLinkMetricsClear(otLinkMetrics aLinkMetrics)
{
return !aLinkMetrics.mPduCount && !aLinkMetrics.mLqi && !aLinkMetrics.mLinkMargin && !aLinkMetrics.mRssi;
}
void otLinkMetricsInit(int8_t aNoiseFloor)
{
sNoiseFloor = aNoiseFloor;
}
otError otLinkMetricsConfigureEnhAckProbing(otShortAddress aShortAddress,
const otExtAddress *aExtAddress,
otLinkMetrics aLinkMetrics)
{
otError error = OT_ERROR_NONE;
LinkMetricsDataInfo *dataInfo = nullptr;
VerifyOrExit(aExtAddress != nullptr, error = OT_ERROR_INVALID_ARGS);
if (IsLinkMetricsClear(aLinkMetrics)) ///< Remove the entry
{
dataInfo = GetLinkMetricsDataInfoActiveList().RemoveMatching(aShortAddress);
VerifyOrExit(dataInfo != nullptr, error = OT_ERROR_NOT_FOUND);
GetLinkMetricsDataInfoPool().Free(*dataInfo);
}
else
{
dataInfo = GetLinkMetricsDataInfoActiveList().FindMatching(aShortAddress);
if (dataInfo == nullptr)
{
dataInfo = GetLinkMetricsDataInfoPool().Allocate();
VerifyOrExit(dataInfo != nullptr, error = OT_ERROR_NO_BUFS);
dataInfo->Clear();
GetLinkMetricsDataInfoActiveList().Push(*dataInfo);
}
// Overwrite the previous configuration if it already existed.
dataInfo->Set(aLinkMetrics, aShortAddress, *aExtAddress);
}
exit:
return error;
}
LinkMetricsDataInfo *GetLinkMetricsInfoByMacAddress(const otMacAddress *aMacAddress)
{
LinkMetricsDataInfo *dataInfo = nullptr;
VerifyOrExit(aMacAddress != nullptr);
if (aMacAddress->mType == OT_MAC_ADDRESS_TYPE_SHORT)
{
dataInfo = GetLinkMetricsDataInfoActiveList().FindMatching(aMacAddress->mAddress.mShortAddress);
}
else if (aMacAddress->mType == OT_MAC_ADDRESS_TYPE_EXTENDED)
{
dataInfo = GetLinkMetricsDataInfoActiveList().FindMatching(aMacAddress->mAddress.mExtAddress);
}
exit:
return dataInfo;
}
uint8_t otLinkMetricsEnhAckGenData(const otMacAddress *aMacAddress, uint8_t aLqi, int8_t aRssi, uint8_t *aData)
{
uint8_t bytes = 0;
LinkMetricsDataInfo *dataInfo = GetLinkMetricsInfoByMacAddress(aMacAddress);
VerifyOrExit(dataInfo != nullptr);
bytes = dataInfo->GetEnhAckData(aLqi, aRssi, aData);
exit:
return bytes;
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright (c) 2020, 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
* @brief
* This file defines the link metrics interface for OpenThread platform radio drivers.
*
* APIs defined in this module could be used by a platform to implement Enhanced-ACK Based Probing feature
* (Probing Subject side) in its radio driver.
*
*/
#ifndef OPENTHREAD_UTILS_LINK_METRICS_H
#define OPENTHREAD_UTILS_LINK_METRICS_H
#include <openthread/link_metrics.h>
#include "mac_frame.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* This method initializes the Link Metrics util module.
*
* @param[in] aNoiseFloor The noise floor used by Link Metrics. It should be set to the platform's
* noise floor (measured noise floor, receiver sensitivity or a constant).
*
*/
void otLinkMetricsInit(int8_t aNoiseFloor);
/**
* This method sets/clears Enhanced-ACK Based Probing for a specific Initiator.
*
* This method can start/stop Enhanced-ACK Based Probing for a neighbor that has the address @p aShortAddress and
* @p aExtAddress. Once the Probing is started, the device would record the Link Metrics data of link layer frames
* sent from that neighbor and include the data into header IE in Enhanced-ACK sent to that neighbor.
*
* @param[in] aShortAddress The short address of the Initiator.
* @param[in] aExtAddress A pointer to the extended address of the Initiator.
* @param[in] aLinkMetrics Flags specifying what metrics to query (Pdu Count would be omitted). When
* @p aLinkMetrics is eqaul to `0`, this method clears the Initiator.
*
* @retval OT_ERROR_NONE Successfully configured the Enhanced-ACK Based Probing.
* @retval OT_ERROR_INVALID_ARGS @p aExtAddress is `nullptr`.
* @retval OT_ERROR_NOT_FOUND The Initiator indicated by @p aShortAddress is not found when trying to clear.
* @retval OT_ERROR_NO_BUFS No more Initiator can be supported.
*
*/
otError otLinkMetricsConfigureEnhAckProbing(otShortAddress aShortAddress,
const otExtAddress *aExtAddress,
otLinkMetrics aLinkMetrics);
/**
* This method generates the Link Metrics data (assessed for the acknowledged frame) bytes that would be included in
* Vendor-Specific IE.
*
* This method first checks what Link Metrics are specified by the Initiator indicated by @p aMacAddress. And then
* write the values to @p aData.
*
* @param[in] aMacAddress The Mac address of the Initiator.
* @param[in] aLqi LQI value of the acknowledged frame.
* @param[in] aRssi RSSI value of the acknowledged frame.
* @param[out] aData A pointer to the buffer where the data would be written to. The caller should make
* sure that the size of the buffer is not less than the size of Link Metrics data
* configured before.
*
* @returns The size of data read. Would be `0` if the Initiator is not found or @p aData is invalid.
*
*/
uint8_t otLinkMetricsEnhAckGenData(const otMacAddress *aMacAddress, uint8_t aLqi, int8_t aRssi, uint8_t *aData);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // OPENTHREAD_UTILS_LINK_METRICS_H
+44
View File
@@ -205,3 +205,47 @@ void otMacFrameSetFrameCounter(otRadioFrame *aFrame, uint32_t aFrameCounter)
{
static_cast<Mac::Frame *>(aFrame)->SetFrameCounter(aFrameCounter);
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
uint8_t otMacFrameGenerateCslIeTemplate(uint8_t *aDest)
{
assert(aDest != nullptr);
reinterpret_cast<Mac::HeaderIe *>(aDest)->SetId(Mac::Frame::kHeaderIeCsl);
reinterpret_cast<Mac::HeaderIe *>(aDest)->SetLength(sizeof(Mac::CslIe));
return sizeof(Mac::HeaderIe) + sizeof(Mac::CslIe);
}
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
uint8_t otMacFrameGenerateEnhAckProbingIe(uint8_t *aDest, const uint8_t *aIeData, uint8_t aIeDataLength)
{
uint8_t len = sizeof(Mac::VendorIeHeader) + aIeDataLength;
assert(aDest != nullptr);
reinterpret_cast<Mac::HeaderIe *>(aDest)->SetId(Mac::Frame::kHeaderIeVendor);
reinterpret_cast<Mac::HeaderIe *>(aDest)->SetLength(len);
aDest += sizeof(Mac::HeaderIe);
reinterpret_cast<Mac::VendorIeHeader *>(aDest)->SetVendorOui(Mac::ThreadIe::kVendorOuiThreadCompanyId);
reinterpret_cast<Mac::VendorIeHeader *>(aDest)->SetSubType(Mac::ThreadIe::kEnhAckProbingIe);
if (aIeData != nullptr)
{
aDest += sizeof(Mac::VendorIeHeader);
memcpy(aDest, aIeData, aIeDataLength);
}
return sizeof(Mac::HeaderIe) + len;
}
void otMacFrameSetEnhAckProbingIe(otRadioFrame *aFrame, const uint8_t *aData, uint8_t aDataLen)
{
assert(aFrame != nullptr && aData != nullptr);
reinterpret_cast<Mac::Frame *>(aFrame)->SetEnhAckProbingIe(aData, aDataLen);
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
+37
View File
@@ -283,6 +283,43 @@ uint32_t otMacFrameGetFrameCounter(otRadioFrame *aFrame);
*/
void otMacFrameSetFrameCounter(otRadioFrame *aFrame, uint32_t aFrameCounter);
/**
* Write CSL IE to a buffer (without setting IE value).
*
* @param[out] aDest A pointer to the output buffer.
*
* @returns The total count of bytes (total length of CSL IE) written to the buffer.
*
*/
uint8_t otMacFrameGenerateCslIeTemplate(uint8_t *aDest);
/**
* Write Enh-ACK Probing IE (Vendor IE with THREAD OUI) to a buffer.
*
* @p aIeData could be `NULL`. If @p aIeData is `NULL`, this method generates the IE with the data unset. This allows
* users to generate the pattern first and update value later. (For example, using `otMacFrameSetEnhAckProbingIe`)
*
* @param[out] aDest A pointer to the output buffer.
* @param[in] aIeData A pointer to the Link Metrics data.
* @param[in] aIeDataLength The length of Link Metrics data value. Should be `1` or `2`. (Per spec 4.11.3.4.4.6)
*
* @returns The total count of bytes (total length of the Vendor IE) written to the buffer.
*
*/
uint8_t otMacFrameGenerateEnhAckProbingIe(uint8_t *aDest, const uint8_t *aIeData, uint8_t aIeDataLength);
/**
* Sets the data value of Enh-ACK Probing IE (Vendor IE with THREAD OUI) in a frame.
*
* If no Enh-ACK Probing IE is found in @p aFrame, nothing would be done.
*
* @param[in] aFrame The target frame that contains the IE. MUST NOT be `NULL`.
* @param[in] aData A pointer to the data value. MUST NOT be `NULL`.
* @param[in] aDataLen The length of @p aData.
*
*/
void otMacFrameSetEnhAckProbingIe(otRadioFrame *aFrame, const uint8_t *aData, uint8_t aDataLen);
#ifdef __cplusplus
} // extern "C"
#endif
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (54)
#define OPENTHREAD_API_VERSION (55)
/**
* @addtogroup api-instance
+71 -21
View File
@@ -39,6 +39,7 @@
#include <openthread/ip6.h>
#include <openthread/message.h>
#include <openthread/platform/radio.h>
#ifdef __cplusplus
extern "C" {
@@ -54,18 +55,6 @@ extern "C" {
*
*/
/**
* This structure represents what metrics are specified to query.
*
*/
typedef struct otLinkMetrics
{
bool mPduCount : 1;
bool mLqi : 1;
bool mLinkMargin : 1;
bool mRssi : 1;
} otLinkMetrics;
/**
* This structure represents the result (value) for a Link Metrics query.
*
@@ -92,11 +81,23 @@ typedef struct otLinkMetricsSeriesFlags
bool mMacAck : 1; ///< MAC Ack.
} otLinkMetricsSeriesFlags;
/**
* Enhanced-ACK Flags.
*
* These are used in Enhanced-ACK Based Probing to indicate whether to register or clear the probing.
*
*/
typedef enum otLinkMetricsEnhAckFlags
{
OT_LINK_METRICS_ENH_ACK_CLEAR = 0, ///< Clear.
OT_LINK_METRICS_ENH_ACK_REGISTER = 1, ///< Register.
} otLinkMetricsEnhAckFlags;
/**
* Link Metrics Status values.
*
*/
typedef enum otLinkMetricsStatus : uint8_t
typedef enum otLinkMetricsStatus
{
OT_LINK_METRICS_STATUS_SUCCESS = 0,
OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES = 1,
@@ -129,6 +130,20 @@ typedef void (*otLinkMetricsReportCallback)(const otIp6Address * aSource,
*/
typedef void (*otLinkMetricsMgmtResponseCallback)(const otIp6Address *aSource, uint8_t aStatus, void *aContext);
/**
* This function pointer is called when Enh-ACK Probing IE is received.
*
* @param[in] aShortAddress The Mac short address of the Probing Subject.
* @param[in] aExtAddress A pointer to the Mac extended address of the Probing Subject.
* @param[in] aMetricsValues A pointer to the Link Metrics values obtained from the IE.
* @param[in] aContext A pointer to application-specific context.
*
*/
typedef void (*otLinkMetricsEnhAckProbingIeReportCallback)(otShortAddress aShortAddress,
const otExtAddress * aExtAddress,
const otLinkMetricsValues *aMetricsValues,
void * aContext);
/**
* This function sends an MLE Data Request to query Link Metrics.
*
@@ -141,8 +156,10 @@ typedef void (*otLinkMetricsMgmtResponseCallback)(const otIp6Address *aSource, u
* @param[in] aCallback A pointer to a function that is called when Link Metrics report is received.
* @param[in] aCallbackContext A pointer to application-specific context.
*
* @retval OT_ERROR_NONE Successfully sent a Link Metrics query message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Data Request message.
* @retval OT_ERROR_NONE Successfully sent a Link Metrics query message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Data Request message.
* @retval OT_ERROR_UNKNOWN_NEIGHBOR @p aDestination is not link-local or the neighbor is not found.
* @retval OT_ERROR_NOT_CAPABLE The neighbor is not a Thread 1.2 device and does not support Link Metrics.
*
*/
otError otLinkMetricsQuery(otInstance * aInstance,
@@ -165,9 +182,11 @@ otError otLinkMetricsQuery(otInstance * aInstance,
* received.
* @param[in] aCallbackContext A pointer to application-specific context.
*
* @retval OT_ERROR_NONE Successfully sent a Link Metrics Management Request message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Metrics Management Request message.
* @retval OT_ERROR_INVALID_ARGS @p aSeriesId is not within the valid range.
* @retval OT_ERROR_NONE Successfully sent a Link Metrics Management Request message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Metrics Management Request message.
* @retval OT_ERROR_INVALID_ARGS @p aSeriesId is not within the valid range.
* @retval OT_ERROR_UNKNOWN_NEIGHBOR @p aDestination is not link-local or the neighbor is not found.
* @retval OT_ERROR_NOT_CAPABLE The neighbor is not a Thread 1.2 device and does not support Link Metrics.
*
*/
otError otLinkMetricsConfigForwardTrackingSeries(otInstance * aInstance,
@@ -178,6 +197,35 @@ otError otLinkMetricsConfigForwardTrackingSeries(otInstance *
otLinkMetricsMgmtResponseCallback aCallback,
void * aCallbackContext);
/**
* This function sends an MLE Link Metrics Management Request to configure/clear an Enhanced-ACK Based Probing.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDestination A pointer to the destination address.
* @param[in] aEnhAckFlags Enh-ACK Flags to indicate whether to register or clear the probing. `0` to clear and
* `1` to register. Other values are reserved.
* @param[in] aLinkMetricsFlags A pointer to flags specifying what metrics to query. Should be `NULL` when
* `aEnhAckFlags` is `0`.
* @param[in] aCallback A pointer to a function that is called when an Enhanced Ack with Link Metrics is
* received.
* @param[in] aCallbackContext A pointer to application-specific context.
*
* @retval OT_ERROR_NONE Successfully sent a Link Metrics Management Request message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Metrics Management Request message.
* @retval OT_ERROR_INVALID_ARGS @p aEnhAckFlags is not a valid value or @p aLinkMetricsFlags isn't correct.
* @retval OT_ERROR_UNKNOWN_NEIGHBOR @p aDestination is not link-local or the neighbor is not found.
* @retval OT_ERROR_NOT_CAPABLE The neighbor is not a Thread 1.2 device and does not support Link Metrics.
*
*/
otError otLinkMetricsConfigEnhAckProbing(otInstance * aInstance,
const otIp6Address * aDestination,
otLinkMetricsEnhAckFlags aEnhAckFlags,
const otLinkMetrics * aLinkMetricsFlags,
otLinkMetricsMgmtResponseCallback aCallback,
void * aCallbackContext,
otLinkMetricsEnhAckProbingIeReportCallback aEnhAckCallback,
void * aEnhAckCallbackContext);
/**
* This function sends an MLE Link Probe message.
*
@@ -186,9 +234,11 @@ otError otLinkMetricsConfigForwardTrackingSeries(otInstance *
* @param[in] aSeriesId The Series ID [1, 254] which the Probe message aims at.
* @param[in] aLength The length of the data payload in Link Probe TLV, [0, 64] (per Thread 1.2 spec, 4.4.37).
*
* @retval OT_ERROR_NONE Successfully sent a Link Probe message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Probe message.
* @retval OT_ERROR_INVALID_ARGS @p aSeriesId or @p aLength is not within the valid range.
* @retval OT_ERROR_NONE Successfully sent a Link Probe message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Probe message.
* @retval OT_ERROR_INVALID_ARGS @p aSeriesId or @p aLength is not within the valid range.
* @retval OT_ERROR_UNKNOWN_NEIGHBOR @p aDestination is not link-local or the neighbor is not found.
* @retval OT_ERROR_NOT_CAPABLE The neighbor is not a Thread 1.2 device and does not support Link Metrics.
*
*/
otError otLinkMetricsSendLinkProbe(otInstance * aInstance,
+42 -3
View File
@@ -151,9 +151,10 @@ typedef uint16_t otShortAddress;
*/
enum
{
OT_IE_HEADER_SIZE = 2, ///< Size of IE header in bytes.
OT_CSL_IE_SIZE = 4, ///< Size of CSL IE content in bytes.
OT_ACK_IE_MAX_SIZE = 16, ///< Max length for header IE in ACK.
OT_IE_HEADER_SIZE = 2, ///< Size of IE header in bytes.
OT_CSL_IE_SIZE = 4, ///< Size of CSL IE content in bytes.
OT_ACK_IE_MAX_SIZE = 16, ///< Max length for header IE in ACK.
OT_ENH_PROBING_IE_DATA_MAX_SIZE = 2, ///< Max length of Link Metrics data in Vendor-Specific IE.
};
#define CSL_IE_HEADER_BYTES_LO 0x04 ///< Fixed CSL IE header first byte
@@ -323,6 +324,19 @@ typedef struct otRadioCoexMetrics
bool mStopped; ///< Stats collection stopped due to saturation.
} otRadioCoexMetrics;
/**
* This structure represents what metrics are specified to query.
*
*/
typedef struct otLinkMetrics
{
bool mPduCount : 1; ///< Pdu count.
bool mLqi : 1; ///< Link Quality Indicator.
bool mLinkMargin : 1; ///< Link Margin.
bool mRssi : 1; ///< Received Signal Strength Indicator.
bool mReserved : 1; ///< Reserved, this is for reference device.
} otLinkMetrics;
/**
* @}
*
@@ -964,6 +978,31 @@ void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTi
*/
otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower);
/**
* Enable/disable or update Enhanced-ACK Based Probing in radio for a specific Initiator.
*
* After Enhanced-ACK Based Probing is configured by a specific Probing Initiator, the Enhanced-ACK sent to that
* node should include Vendor-Specific IE containing Link Metrics data. This method informs the radio to start/stop to
* collect Link Metrics data and include Vendor-Specific IE that containing the data in Enhanced-ACK sent to that
* Probing Initiator.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aLinkMetrics This parameter specifies what metrics to query. Per spec 4.11.3.4.4.6, at most 2 metrics
* can be specified. The probing would be disabled if @p `aLinkMetrics` is bitwise 0.
* @param[in] aShortAddr The short address of the Probing Initiator.
* @param[in] aExtAddr The extended source address of the Probing Initiator. @p aExtAddr MUST NOT be `NULL`.
*
* @retval OT_ERROR_NONE Successfully configured the Enhanced-ACK Based Probing.
* @retval OT_ERROR_INVALID_ARGS @p aExtAddress is `NULL`.
* @retval OT_ERROR_NOT_FOUND The Initiator indicated by @p aShortAddress is not found when trying to clear.
* @retval OT_ERROR_NO_BUFS No more Initiator can be supported.
*
*/
otError otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,
otLinkMetrics aLinkMetrics,
otShortAddress aShortAddress,
const otExtAddress *aExtAddress);
/**
* @}
*
+37 -1
View File
@@ -58,7 +58,7 @@ Done
- [keysequence](#keysequence-counter)
- [leaderdata](#leaderdata)
- [leaderweight](#leaderweight)
- [linkmetrics](#linkmetrics-mgmt-ipaddr-forward-seriesid-ldraxpqmr)
- [linkmetrics](#linkmetrics-mgmt-ipaddr-enhanced-ack-clear)
- [linkquality](#linkquality-extaddr)
- [log](#log-filename-filename)
- [mac](#mac-retries-direct)
@@ -1126,6 +1126,42 @@ Set the Thread Leader Weight.
Done
```
### linkmetrics mgmt \<ipaddr\> enhanced-ack clear
Send a Link Metrics Management Request to clear an Enhanced-ACK Based Probing.
- ipaddr: Peer address (SHOULD be link local address of the neighboring device).
```bash
> linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack clear
Done
> Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2
Status: Success
```
### linkmetrics mgmt \<ipaddr\> enhanced-ack register [qmr][r]
Send a Link Metrics Management Request to register an Enhanced-ACK Based Probing.
- ipaddr: Peer address.
- qmr: This specifies what metrics to query. At most two options are allowed to select (per spec 4.11.3.4.4.6).
- q: Layer 2 LQI.
- m: Link Margin.
- r: RSSI.
- r: This is optional and only used for reference devices. When this option is specified, Type/Average Enum of each Type Id Flags would be set to `reserved`. This is used to verify the Probing Subject correctly handles invalid Type Id Flags. This is only available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
```bash
> linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack register qm
Done
> Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2
Status: Success
> linkmetrics mgmt fe80:0:0:0:3092:f334:1455:1ad2 enhanced-ack register qm r
Done
> Received Link Metrics Management Response from: fe80:0:0:0:3092:f334:1455:1ad2
Status: Cannot support new series
```
### linkmetrics mgmt \<ipaddr\> forward \<seriesid\> [ldraX][pqmr]
Send a Link Metrics Management Request to configure a Forward Tracking Series.
+84 -22
View File
@@ -1950,38 +1950,43 @@ void Interpreter::HandleLinkMetricsReport(const otIp6Address * aAddress,
static_cast<Interpreter *>(aContext)->HandleLinkMetricsReport(aAddress, aMetricsValues, aStatus);
}
void Interpreter::HandleLinkMetricsReport(const otIp6Address * aAddress,
const otLinkMetricsValues *aMetricsValues,
uint8_t aStatus)
void Interpreter::PrintLinkMetricsValue(const otLinkMetricsValues *aMetricsValues)
{
const char kLinkMetricsTypeCount[] = "(Count/Summation)";
const char kLinkMetricsTypeAverage[] = "(Exponential Moving Average)";
if (aMetricsValues->mMetrics.mPduCount)
{
OutputLine(" - PDU Counter: %d %s", aMetricsValues->mPduCountValue, kLinkMetricsTypeCount);
}
if (aMetricsValues->mMetrics.mLqi)
{
OutputLine(" - LQI: %d %s", aMetricsValues->mLqiValue, kLinkMetricsTypeAverage);
}
if (aMetricsValues->mMetrics.mLinkMargin)
{
OutputLine(" - Margin: %d (dB) %s", aMetricsValues->mLinkMarginValue, kLinkMetricsTypeAverage);
}
if (aMetricsValues->mMetrics.mRssi)
{
OutputLine(" - RSSI: %d (dBm) %s", aMetricsValues->mRssiValue, kLinkMetricsTypeAverage);
}
}
void Interpreter::HandleLinkMetricsReport(const otIp6Address * aAddress,
const otLinkMetricsValues *aMetricsValues,
uint8_t aStatus)
{
OutputFormat("Received Link Metrics Report from: ");
OutputIp6Address(*aAddress);
OutputLine("");
if (aMetricsValues != nullptr)
{
if (aMetricsValues->mMetrics.mPduCount)
{
OutputLine(" - PDU Counter: %d %s", aMetricsValues->mPduCountValue, kLinkMetricsTypeCount);
}
if (aMetricsValues->mMetrics.mLqi)
{
OutputLine(" - LQI: %d %s", aMetricsValues->mLqiValue, kLinkMetricsTypeAverage);
}
if (aMetricsValues->mMetrics.mLinkMargin)
{
OutputLine(" - Margin: %d (dB) %s", aMetricsValues->mLinkMarginValue, kLinkMetricsTypeAverage);
}
if (aMetricsValues->mMetrics.mRssi)
{
OutputLine(" - RSSI: %d (dBm) %s", aMetricsValues->mRssiValue, kLinkMetricsTypeAverage);
}
PrintLinkMetricsValue(aMetricsValues);
}
else
{
@@ -2003,6 +2008,29 @@ void Interpreter::HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, ui
OutputLine("Status: %s", LinkMetricsStatusToStr(aStatus));
}
void Interpreter::HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress,
const otExtAddress * aExtAddress,
const otLinkMetricsValues *aMetricsValues,
void * aContext)
{
static_cast<Interpreter *>(aContext)->HandleLinkMetricsEnhAckProbingIe(aShortAddress, aExtAddress, aMetricsValues);
}
void Interpreter::HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress,
const otExtAddress * aExtAddress,
const otLinkMetricsValues *aMetricsValues)
{
OutputFormat("Received Link Metrics data in Enh Ack from neighbor, short address:0x%02x , extended address:",
aShortAddress);
OutputExtAddress(*aExtAddress);
OutputLine("");
if (aMetricsValues != nullptr)
{
PrintLinkMetricsValue(aMetricsValues);
}
}
const char *Interpreter::LinkMetricsStatusToStr(uint8_t aStatus)
{
uint8_t strIndex = 0;
@@ -2193,6 +2221,40 @@ otError Interpreter::ProcessLinkMetricsMgmt(uint8_t aArgsLength, char *aArgs[])
clear ? nullptr : &linkMetrics,
&Interpreter::HandleLinkMetricsMgmtResponse, this);
}
else if (strcmp(aArgs[1], "enhanced-ack") == 0)
{
otLinkMetricsEnhAckFlags enhAckFlags;
otLinkMetrics linkMetrics;
otLinkMetrics * pLinkMetrics = &linkMetrics;
VerifyOrExit(aArgsLength >= 3);
if (strcmp(aArgs[2], "clear") == 0)
{
enhAckFlags = OT_LINK_METRICS_ENH_ACK_CLEAR;
pLinkMetrics = nullptr;
}
else if (strcmp(aArgs[2], "register") == 0)
{
enhAckFlags = OT_LINK_METRICS_ENH_ACK_REGISTER;
VerifyOrExit(aArgsLength >= 4);
SuccessOrExit(error = ParseLinkMetricsFlags(linkMetrics, aArgs[3]));
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
if (aArgsLength > 4 && strcmp(aArgs[4], "r") == 0)
{
linkMetrics.mReserved = true;
}
#endif
}
else
{
ExitNow();
}
error = otLinkMetricsConfigEnhAckProbing(mInstance, &address, enhAckFlags, pLinkMetrics,
&Interpreter::HandleLinkMetricsMgmtResponse, this,
&Interpreter::HandleLinkMetricsEnhAckProbingIe, this);
}
exit:
return error;
+12 -1
View File
@@ -558,6 +558,8 @@ private:
void HandleSntpResponse(uint64_t aTime, otError aResult);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
void PrintLinkMetricsValue(const otLinkMetricsValues *aMetricsValues);
static void HandleLinkMetricsReport(const otIp6Address * aAddress,
const otLinkMetricsValues *aMetricsValues,
uint8_t aStatus,
@@ -571,8 +573,17 @@ private:
void HandleLinkMetricsMgmtResponse(const otIp6Address *aAddress, uint8_t aStatus);
static void HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress,
const otExtAddress * aExtAddress,
const otLinkMetricsValues *aMetricsValues,
void * aContext);
void HandleLinkMetricsEnhAckProbingIe(otShortAddress aShortAddress,
const otExtAddress * aExtAddress,
const otLinkMetricsValues *aMetricsValues);
const char *LinkMetricsStatusToStr(uint8_t aStatus);
#endif
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
static Interpreter &GetOwner(OwnerLocator &aOwnerLocator);
+20
View File
@@ -74,6 +74,26 @@ otError otLinkMetricsConfigForwardTrackingSeries(otInstance *
static_cast<const Ip6::Address &>(*aDestination), aSeriesId, aSeriesFlags, aLinkMetricsFlags);
}
otError otLinkMetricsConfigEnhAckProbing(otInstance * aInstance,
const otIp6Address * aDestination,
const otLinkMetricsEnhAckFlags aEnhAckFlags,
const otLinkMetrics * aLinkMetricsFlags,
otLinkMetricsMgmtResponseCallback aCallback,
void * aCallbackContext,
otLinkMetricsEnhAckProbingIeReportCallback aEnhAckCallback,
void * aEnhAckCallbackContext)
{
OT_ASSERT(aDestination != nullptr);
static_cast<Instance *>(aInstance)->Get<LinkMetrics>().SetLinkMetricsMgmtResponseCallback(aCallback,
aCallbackContext);
static_cast<Instance *>(aInstance)->Get<LinkMetrics>().SetLinkMetricsEnhAckProbingCallback(aEnhAckCallback,
aEnhAckCallbackContext);
return static_cast<Instance *>(aInstance)->Get<LinkMetrics>().SendMgmtRequestEnhAckProbing(
static_cast<const Ip6::Address &>(*aDestination), aEnhAckFlags, aLinkMetricsFlags);
}
otError otLinkMetricsSendLinkProbe(otInstance * aInstance,
const otIp6Address *aDestination,
uint8_t aSeriesId,
+33
View File
@@ -1409,6 +1409,7 @@ void Mac::RecordFrameTransmitStatus(const TxFrame &aFrame,
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
neighbor->AggregateLinkMetrics(/* aSeriesId */ 0, aAckFrame->GetType(), aAckFrame->GetLqi(),
aAckFrame->GetRssi());
ProcessEnhAckProbing(*aAckFrame, *neighbor);
#endif
#if OPENTHREAD_FTD
if (aAckFrame->GetVersion() == Frame::kFcfFrameVersion2015)
@@ -2577,6 +2578,31 @@ exit:
}
#endif // !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
void Mac::ProcessEnhAckProbing(const RxFrame &aFrame, const Neighbor &aNeighbor)
{
enum
{
kEnhAckProbingIeMaxLen = 2,
};
const HeaderIe *enhAckProbingIe =
reinterpret_cast<const HeaderIe *>(aFrame.GetThreadIe(ThreadIe::kEnhAckProbingIe));
const uint8_t *data =
reinterpret_cast<const uint8_t *>(enhAckProbingIe) + sizeof(HeaderIe) + sizeof(VendorIeHeader);
uint8_t dataLen = 0;
VerifyOrExit(enhAckProbingIe != nullptr);
dataLen = enhAckProbingIe->GetLength() - sizeof(VendorIeHeader);
VerifyOrExit(dataLen <= kEnhAckProbingIeMaxLen);
Get<LinkMetrics>().ProcessEnhAckIeData(data, dataLen, aNeighbor);
exit:
return;
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
#if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
otError Mac::AppendHeaderIe(bool aIsTimeSync, TxFrame &aFrame) const
{
@@ -2668,6 +2694,13 @@ void Mac::UpdateFrameControlField(const Neighbor *aNeighbor, bool aIsTimeSync, u
}
else
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
if (aNeighbor != nullptr && aNeighbor->IsEnhAckProbingActive())
{
aFcf |= Frame::kFcfFrameVersion2015; ///< Set version to 2015 to fetch Link Metrics data in Enh-ACK.
}
else
#endif
#endif
{
aFcf |= Frame::kFcfFrameVersion2006;
+3
View File
@@ -864,6 +864,9 @@ private:
#if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
void ProcessCsl(const RxFrame &aFrame, const Address &aSrcAddr);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
void ProcessEnhAckProbing(const RxFrame &aFrame, const Neighbor &aNeighbor);
#endif
static const char *OperationToString(Operation aOperation);
+46 -1
View File
@@ -824,7 +824,6 @@ uint8_t Frame::FindPayloadIndex(void) const
const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
index += sizeof(HeaderIe);
VerifyOrExit(index + footerLength <= mLength, index = kInvalidIndex);
index += ie->GetLength();
@@ -933,6 +932,41 @@ const uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const
exit:
return header;
}
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
const uint8_t *Frame::GetThreadIe(uint8_t aSubType) const
{
uint8_t index = FindHeaderIeIndex();
uint8_t payloadIndex = FindPayloadIndex();
const uint8_t *header = nullptr;
// `FindPayloadIndex()` verifies that Header IE(s) in frame (if present)
// are well-formed.
VerifyOrExit((index != kInvalidIndex) && (payloadIndex != kInvalidIndex));
while (index <= payloadIndex)
{
const HeaderIe *ie = reinterpret_cast<const HeaderIe *>(&mPsdu[index]);
if (ie->GetId() == kHeaderIeVendor)
{
const VendorIeHeader *vendorIe =
reinterpret_cast<const VendorIeHeader *>(reinterpret_cast<const uint8_t *>(ie) + sizeof(HeaderIe));
if (vendorIe->GetVendorOui() == ThreadIe::kVendorOuiThreadCompanyId && vendorIe->GetSubType() == aSubType)
{
header = &mPsdu[index];
ExitNow();
}
}
index += sizeof(HeaderIe) + ie->GetLength();
}
exit:
return header;
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -951,6 +985,17 @@ exit:
}
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
void Frame::SetEnhAckProbingIe(const uint8_t *aValue, uint8_t aLen)
{
uint8_t *cur = GetThreadIe(ThreadIe::kEnhAckProbingIe);
OT_ASSERT(cur != nullptr);
memcpy(cur + sizeof(HeaderIe) + sizeof(VendorIeHeader), aValue, aLen);
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
const TimeIe *Frame::GetTimeIe(void) const
{
+58 -1
View File
@@ -135,7 +135,7 @@ private:
} OT_TOOL_PACKED_END;
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
/**
* This class implements vendor specific Header IE generation and parsing.
*
@@ -186,6 +186,7 @@ private:
uint8_t mSubType;
} OT_TOOL_PACKED_END;
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
/**
* This class implements Time Header IE generation and parsing.
*
@@ -252,6 +253,24 @@ private:
} OT_TOOL_PACKED_END;
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
class ThreadIe
{
public:
enum : uint32_t
{
kVendorOuiThreadCompanyId = 0xeab89b,
};
enum SubType : uint8_t
{
kEnhAckProbingIe = 0x00,
};
};
#endif
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
/**
* This class implements IEEE 802.15.4 MAC frame generation and parsing.
*
@@ -938,6 +957,33 @@ public:
*/
const uint8_t *GetHeaderIe(uint8_t aIeId) const;
/**
* This method returns a pointer to a specific Thread IE.
*
* A Thread IE is a vendor specific IE with Vendor OUI as `kVendorOuiThreadCompanyId`.
*
* @param[in] aSubType The sub type of the Thread IE.
*
* @returns A pointer to the Thread IE, nullptr if not found.
*
*/
uint8_t *GetThreadIe(uint8_t aSubType)
{
return const_cast<uint8_t *>(const_cast<const Frame *>(this)->GetThreadIe(aSubType));
}
/**
* This method returns a pointer to a specific Thread IE.
*
* A Thread IE is a vendor specific IE with Vendor OUI as `kVendorOuiThreadCompanyId`.
*
* @param[in] aSubType The sub type of the Thread IE.
*
* @returns A pointer to the Thread IE, nullptr if not found.
*
*/
const uint8_t *GetThreadIe(uint8_t aSubType) const;
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
/**
* This method finds CSL IE in the frame and modify its content.
@@ -949,6 +995,17 @@ public:
void SetCslIe(uint16_t aCslPeriod, uint16_t aCslPhase);
#endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
/**
* This method finds Enhanced ACK Probing (Vendor Specific) IE and set its value.
*
* @param[in] aValue A pointer to the value to set.
* @param[in] aLen The length of @p aValue.
*
*/
void SetEnhAckProbingIe(const uint8_t *aValue, uint8_t aLen);
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
#endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
#if OPENTHREAD_CONFIG_MULTI_RADIO
+30
View File
@@ -564,6 +564,36 @@ public:
*/
uint32_t GetPreferredChannelMask(void);
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
/**
* This method enables/disables or updates Enhanced-ACK Based Probing in radio for a specific Initiator.
*
* After Enhanced-ACK Based Probing is configured by a specific Probing Initiator, the Enhanced-ACK sent to that
* node should include Vendor-Specific IE containing Link Metrics data. This method informs the radio to
* starts/stops to collect Link Metrics data and include Vendor-Specific IE that containing the data
* in Enhanced-ACK sent to that Probing Initiator.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aDataLength Length of Link Metrics data in the Vendor-Specific IE. Per spec 4.11.3.4.4.6,
* @p aDataLength should only be 1 or 2. The probing would be disabled if `aDataLength` is
* `0`.
* @param[in] aShortAddr The short address of the the probing Initiator.
* @param[in] aExtAddr The extended source address of the probing Initiator.
*
* @retval OT_ERROR_NONE Successfully enable/disable or update Enhanced-ACK Based Probing for a specific
* Initiator.
* @retval OT_ERROR_INVALID_ARGS @p aDataLength or @p aExtAddr is not valid.
* @retval OT_ERROR_NOT_SUPPORTED Radio driver doesn't support Enhanced-ACK Probing.
*
*/
otError ConfigureEnhAckProbing(otLinkMetrics aLinkMetrics,
const Mac::ShortAddress &aShortAddress,
const Mac::ExtAddress & aExtAddress)
{
return otPlatRadioConfigureEnhAckProbing(GetInstancePtr(), aLinkMetrics, aShortAddress, &aExtAddress);
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
/**
* This method checks if a given channel is valid as a CSL channel.
*
+189 -72
View File
@@ -39,6 +39,7 @@
#include "common/instance.hpp"
#include "common/locator-getters.hpp"
#include "common/logging.hpp"
#include "thread/neighbor_table.hpp"
#include "link_metrics_tlvs.hpp"
@@ -118,6 +119,10 @@ otError LinkMetrics::LinkMetricsQuery(const Ip6::Address & aDestination,
otError error;
LinkMetricsTypeIdFlags typeIdFlags[kMaxTypeIdFlags];
uint8_t typeIdFlagsCount = 0;
Neighbor * neighbor = GetNeighborFromLinkLocalAddr(aDestination);
VerifyOrExit(neighbor != nullptr, error = OT_ERROR_UNKNOWN_NEIGHBOR);
VerifyOrExit(neighbor->IsThreadVersion1p2(), error = OT_ERROR_NOT_CAPABLE);
if (aLinkMetricsFlags != nullptr)
{
@@ -146,6 +151,10 @@ otError LinkMetrics::SendMgmtRequestForwardTrackingSeries(const Ip6::Address &
SeriesFlags *seriesFlags = reinterpret_cast<SeriesFlags *>(subTlvs + sizeof(Tlv) + sizeof(aSeriesId));
uint8_t typeIdFlagsOffset = sizeof(Tlv) + sizeof(uint8_t) * 2;
uint8_t typeIdFlagsCount = 0;
Neighbor * neighbor = GetNeighborFromLinkLocalAddr(aDestination);
VerifyOrExit(neighbor != nullptr, error = OT_ERROR_UNKNOWN_NEIGHBOR);
VerifyOrExit(neighbor->IsThreadVersion1p2(), error = OT_ERROR_NOT_CAPABLE);
// Directly transform `aLinkMetricsFlags` into LinkMetricsTypeIdFlags and put them into `subTlvs`
if (aLinkMetricsFlags != nullptr)
@@ -164,23 +173,7 @@ otError LinkMetrics::SendMgmtRequestForwardTrackingSeries(const Ip6::Address &
memcpy(subTlvs + sizeof(Tlv), &aSeriesId, sizeof(aSeriesId));
seriesFlags->Clear();
if (aSeriesFlags.mLinkProbe)
{
seriesFlags->SetLinkProbeFlag();
}
if (aSeriesFlags.mMacData)
{
seriesFlags->SetMacDataFlag();
}
if (aSeriesFlags.mMacDataRequest)
{
seriesFlags->SetMacDataRequestFlag();
}
if (aSeriesFlags.mMacAck)
{
seriesFlags->SetMacAckFlag();
}
seriesFlags->SetFromOtSeriesFlags(aSeriesFlags);
error = Get<Mle::MleRouter>().SendLinkMetricsManagementRequest(aDestination, subTlvs,
forwardProbingRegistrationSubTlv->GetSize());
@@ -191,10 +184,57 @@ exit:
return error;
}
otError LinkMetrics::SendMgmtRequestEnhAckProbing(const Ip6::Address & aDestination,
const otLinkMetricsEnhAckFlags aEnhAckFlags,
const otLinkMetrics * aLinkMetricsFlags)
{
otError error = OT_ERROR_NONE;
EnhAckLinkMetricsConfigurationSubTlv enhAckLinkMetricsConfigurationSubTlv;
Mac::Address macAddress;
Neighbor * neighbor = GetNeighborFromLinkLocalAddr(aDestination);
VerifyOrExit(neighbor != nullptr, error = OT_ERROR_UNKNOWN_NEIGHBOR);
VerifyOrExit(neighbor->IsThreadVersion1p2(), error = OT_ERROR_NOT_CAPABLE);
if (aEnhAckFlags == OT_LINK_METRICS_ENH_ACK_CLEAR)
{
VerifyOrExit(aLinkMetricsFlags == nullptr, error = OT_ERROR_INVALID_ARGS);
}
enhAckLinkMetricsConfigurationSubTlv.SetEnhAckFlags(aEnhAckFlags);
if (aLinkMetricsFlags != nullptr)
{
enhAckLinkMetricsConfigurationSubTlv.SetTypeIdFlags(aLinkMetricsFlags);
}
error = Get<Mle::MleRouter>().SendLinkMetricsManagementRequest(
aDestination, reinterpret_cast<const uint8_t *>(&enhAckLinkMetricsConfigurationSubTlv),
enhAckLinkMetricsConfigurationSubTlv.GetSize());
if (aLinkMetricsFlags != nullptr)
{
neighbor->SetEnhAckProbingMetrics(*aLinkMetricsFlags);
}
else
{
otLinkMetrics linkMetrics;
memset(&linkMetrics, 0, sizeof(linkMetrics));
neighbor->SetEnhAckProbingMetrics(linkMetrics);
}
exit:
return error;
}
otError LinkMetrics::SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t aLength)
{
otError error = OT_ERROR_NONE;
uint8_t buf[kLinkProbeMaxLen];
otError error = OT_ERROR_NONE;
uint8_t buf[kLinkProbeMaxLen];
Neighbor *neighbor = GetNeighborFromLinkLocalAddr(aDestination);
VerifyOrExit(neighbor != nullptr, error = OT_ERROR_UNKNOWN_NEIGHBOR);
VerifyOrExit(neighbor->IsThreadVersion1p2(), error = OT_ERROR_NOT_CAPABLE);
VerifyOrExit(aLength <= LinkMetrics::kLinkProbeMaxLen && aSeriesId != kQueryIdSingleProbe &&
aSeriesId != kSeriesIdAllSeries,
@@ -272,13 +312,13 @@ otError LinkMetrics::AppendLinkMetricsReport(Message &aMessage, const Message &a
LinkMetricsSeriesInfo *seriesInfo = aNeighbor.GetForwardTrackingSeriesInfo(queryId);
if (seriesInfo == nullptr)
{
SuccessOrExit(
error = AppendStatusSubTlvToMessage(aMessage, length, OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED));
SuccessOrExit(error =
AppendStatusSubTlvToMessage(aMessage, length, kLinkMetricsStatusSeriesIdNotRecognized));
}
else if (seriesInfo->GetPduCount() == 0)
{
SuccessOrExit(error = AppendStatusSubTlvToMessage(aMessage, length,
OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED));
SuccessOrExit(
error = AppendStatusSubTlvToMessage(aMessage, length, kLinkMetricsStatusNoMatchingFramesReceived));
}
else
{
@@ -303,19 +343,21 @@ exit:
return error;
}
otError LinkMetrics::HandleLinkMetricsManagementRequest(const Message & aMessage,
Neighbor & aNeighbor,
otLinkMetricsStatus &aStatus)
otError LinkMetrics::HandleLinkMetricsManagementRequest(const Message & aMessage,
Neighbor & aNeighbor,
LinkMetricsStatus &aStatus)
{
otError error = OT_ERROR_NONE;
Tlv tlv;
uint8_t seriesId;
SeriesFlags seriesFlags;
otLinkMetrics linkMetrics;
bool hasForwardProbingRegistrationTlv = false;
uint16_t offset;
uint16_t length;
uint16_t index = 0;
otError error = OT_ERROR_NONE;
Tlv tlv;
uint8_t seriesId;
SeriesFlags seriesFlags;
LinkMetricsEnhAckFlags enhAckFlags;
otLinkMetrics linkMetrics;
bool hasForwardProbingRegistrationTlv = false;
bool hasEnhAckProbingTlv = false;
uint16_t offset;
uint16_t length;
uint16_t index = 0;
SuccessOrExit(error = Tlv::FindTlvValueOffset(aMessage, Mle::Tlv::Type::kLinkMetricsManagement, offset, length));
@@ -329,7 +371,7 @@ otError LinkMetrics::HandleLinkMetricsManagementRequest(const Message & aMe
switch (tlv.GetType())
{
case kForwardProbingRegistration:
VerifyOrExit(!hasForwardProbingRegistrationTlv, error = OT_ERROR_PARSE);
VerifyOrExit(!hasForwardProbingRegistrationTlv && !hasEnhAckProbingTlv, error = OT_ERROR_PARSE);
VerifyOrExit(tlv.GetLength() >= sizeof(seriesId) + sizeof(seriesFlags), error = OT_ERROR_PARSE);
SuccessOrExit(aMessage.Read(pos, seriesId));
pos += sizeof(seriesId);
@@ -340,6 +382,16 @@ otError LinkMetrics::HandleLinkMetricsManagementRequest(const Message & aMe
hasForwardProbingRegistrationTlv = true;
break;
case kEnhancedACKConfiguration:
VerifyOrExit(!hasForwardProbingRegistrationTlv && !hasEnhAckProbingTlv, error = OT_ERROR_PARSE);
VerifyOrExit(tlv.GetLength() >= sizeof(LinkMetricsEnhAckFlags), error = OT_ERROR_PARSE);
SuccessOrExit(aMessage.Read(pos, enhAckFlags));
pos += sizeof(enhAckFlags);
SuccessOrExit(error = ReadTypeIdFlagsFromMessage(
aMessage, pos, static_cast<uint16_t>(offset + index + tlv.GetSize()), linkMetrics));
hasEnhAckProbingTlv = true;
break;
default:
break;
}
@@ -351,6 +403,10 @@ otError LinkMetrics::HandleLinkMetricsManagementRequest(const Message & aMe
{
aStatus = ConfigureForwardTrackingSeries(seriesId, seriesFlags, linkMetrics, aNeighbor);
}
else if (hasEnhAckProbingTlv)
{
aStatus = ConfigureEnhAckProbing(enhAckFlags, linkMetrics, aNeighbor);
}
exit:
return error;
@@ -358,13 +414,13 @@ exit:
otError LinkMetrics::HandleLinkMetricsManagementResponse(const Message &aMessage, const Ip6::Address &aAddress)
{
otError error = OT_ERROR_NONE;
Tlv tlv;
uint16_t offset;
uint16_t length;
uint16_t index = 0;
otLinkMetricsStatus status;
bool hasStatus = false;
otError error = OT_ERROR_NONE;
Tlv tlv;
uint16_t offset;
uint16_t length;
uint16_t index = 0;
LinkMetricsStatus status;
bool hasStatus = false;
VerifyOrExit(mLinkMetricsMgmtResponseCallback != nullptr);
@@ -412,7 +468,7 @@ void LinkMetrics::HandleLinkMetricsReport(const Message & aMessage,
LinkMetricsTypeIdFlags typeIdFlags;
bool hasStatus = false;
bool hasReport = false;
otLinkMetricsStatus status;
LinkMetricsStatus status;
OT_UNUSED_VARIABLE(error);
@@ -536,6 +592,42 @@ void LinkMetrics::SetLinkMetricsMgmtResponseCallback(otLinkMetricsMgmtResponseCa
mLinkMetricsMgmtResponseCallbackContext = aCallbackContext;
}
void LinkMetrics::SetLinkMetricsEnhAckProbingCallback(otLinkMetricsEnhAckProbingIeReportCallback aCallback,
void * aCallbackContext)
{
mLinkMetricsEnhAckProbingIeReportCallback = aCallback;
mLinkMetricsEnhAckProbingIeReportCallbackContext = aCallbackContext;
}
void LinkMetrics::ProcessEnhAckIeData(const uint8_t *aData, uint8_t aLen, const Neighbor &aNeighbor)
{
otLinkMetricsValues linkMetricsValues;
uint8_t idx = 0;
VerifyOrExit(mLinkMetricsEnhAckProbingIeReportCallback != nullptr);
linkMetricsValues.mMetrics = aNeighbor.GetEnhAckProbingMetrics();
if (linkMetricsValues.mMetrics.mLqi && idx < aLen)
{
linkMetricsValues.mLqiValue = aData[idx++];
}
if (linkMetricsValues.mMetrics.mLinkMargin && idx < aLen)
{
linkMetricsValues.mLinkMarginValue = aData[idx++];
}
if (linkMetricsValues.mMetrics.mRssi && idx < aLen)
{
linkMetricsValues.mRssiValue = aData[idx++];
}
mLinkMetricsEnhAckProbingIeReportCallback(aNeighbor.GetRloc16(), &aNeighbor.GetExtAddress(), &linkMetricsValues,
mLinkMetricsEnhAckProbingIeReportCallbackContext);
exit:
return;
}
otError LinkMetrics::SendLinkMetricsQuery(const Ip6::Address & aDestination,
uint8_t aSeriesId,
const LinkMetricsTypeIdFlags *aTypeIdFlags,
@@ -585,14 +677,14 @@ exit:
return error;
}
otLinkMetricsStatus LinkMetrics::ConfigureForwardTrackingSeries(uint8_t aSeriesId,
const SeriesFlags & aSeriesFlags,
const otLinkMetrics &aLinkMetrics,
Neighbor & aNeighbor)
LinkMetrics::LinkMetricsStatus LinkMetrics::ConfigureForwardTrackingSeries(uint8_t aSeriesId,
const SeriesFlags & aSeriesFlags,
const otLinkMetrics &aLinkMetrics,
Neighbor & aNeighbor)
{
otLinkMetricsStatus status = OT_LINK_METRICS_STATUS_SUCCESS;
LinkMetricsStatus status = kLinkMetricsStatusSuccess;
VerifyOrExit(0 < aSeriesId, status = OT_LINK_METRICS_STATUS_OTHER_ERROR);
VerifyOrExit(0 < aSeriesId, status = kLinkMetricsStatusOtherError);
if (aSeriesFlags.GetRawValue() == 0) // Remove the series
{
if (aSeriesId == kSeriesIdAllSeries) // Remove all
@@ -602,16 +694,16 @@ otLinkMetricsStatus LinkMetrics::ConfigureForwardTrackingSeries(uint8_t
else
{
LinkMetricsSeriesInfo *seriesInfo = aNeighbor.RemoveForwardTrackingSeriesInfo(aSeriesId);
VerifyOrExit(seriesInfo != nullptr, status = OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED);
VerifyOrExit(seriesInfo != nullptr, status = kLinkMetricsStatusSeriesIdNotRecognized);
mLinkMetricsSeriesInfoPool.Free(*seriesInfo);
}
}
else // Add a new series
{
LinkMetricsSeriesInfo *seriesInfo = aNeighbor.GetForwardTrackingSeriesInfo(aSeriesId);
VerifyOrExit(seriesInfo == nullptr, status = OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED);
VerifyOrExit(seriesInfo == nullptr, status = kLinkMetricsStatusSeriesIdAlreadyRegistered);
seriesInfo = mLinkMetricsSeriesInfoPool.Allocate();
VerifyOrExit(seriesInfo != nullptr, status = OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES);
VerifyOrExit(seriesInfo != nullptr, status = kLinkMetricsStatusCannotSupportNewSeries);
seriesInfo->Init(aSeriesId, aSeriesFlags, aLinkMetrics);
@@ -622,32 +714,53 @@ exit:
return status;
}
uint8_t LinkMetrics::TypeIdFlagsFromLinkMetricsFlags(LinkMetricsTypeIdFlags *aTypeIdFlags,
const otLinkMetrics & aLinkMetricsFlags)
LinkMetrics::LinkMetricsStatus LinkMetrics::ConfigureEnhAckProbing(LinkMetricsEnhAckFlags aEnhAckFlags,
const otLinkMetrics & aLinkMetrics,
Neighbor & aNeighbor)
{
uint8_t count = 0;
LinkMetricsStatus status = kLinkMetricsStatusSuccess;
otError error = OT_ERROR_NONE;
if (aLinkMetricsFlags.mPduCount)
VerifyOrExit(!aLinkMetrics.mReserved, status = kLinkMetricsStatusCannotSupportNewSeries);
if (aEnhAckFlags == kEnhAckRegister)
{
aTypeIdFlags[count++].SetRawValue(kTypeIdFlagPdu);
VerifyOrExit(!aLinkMetrics.mPduCount, status = kLinkMetricsStatusOtherError);
VerifyOrExit(aLinkMetrics.mLqi || aLinkMetrics.mLinkMargin || aLinkMetrics.mRssi,
status = kLinkMetricsStatusOtherError);
VerifyOrExit(!(aLinkMetrics.mLqi && aLinkMetrics.mLinkMargin && aLinkMetrics.mRssi),
status = kLinkMetricsStatusOtherError);
error = Get<Radio>().ConfigureEnhAckProbing(aLinkMetrics, aNeighbor.GetRloc16(), aNeighbor.GetExtAddress());
}
else if (aEnhAckFlags == kEnhAckClear)
{
VerifyOrExit(!aLinkMetrics.mLqi && !aLinkMetrics.mLinkMargin && !aLinkMetrics.mRssi,
status = kLinkMetricsStatusOtherError);
error = Get<Radio>().ConfigureEnhAckProbing(aLinkMetrics, aNeighbor.GetRloc16(), aNeighbor.GetExtAddress());
}
else
{
status = kLinkMetricsStatusOtherError;
}
if (aLinkMetricsFlags.mLqi)
{
aTypeIdFlags[count++].SetRawValue(kTypeIdFlagLqi);
}
VerifyOrExit(error == OT_ERROR_NONE, status = kLinkMetricsStatusOtherError);
if (aLinkMetricsFlags.mLinkMargin)
{
aTypeIdFlags[count++].SetRawValue(kTypeIdFlagLinkMargin);
}
exit:
return status;
}
if (aLinkMetricsFlags.mRssi)
{
aTypeIdFlags[count++].SetRawValue(kTypeIdFlagRssi);
}
Neighbor *LinkMetrics::GetNeighborFromLinkLocalAddr(const Ip6::Address &aDestination)
{
Neighbor * neighbor = nullptr;
Mac::Address macAddress;
return count;
VerifyOrExit(aDestination.IsLinkLocal());
aDestination.GetIid().ConvertToMacAddress(macAddress);
neighbor = Get<NeighborTable>().FindNeighbor(macAddress);
exit:
return neighbor;
}
otError LinkMetrics::ReadTypeIdFlagsFromMessage(const Message &aMessage,
@@ -692,6 +805,10 @@ otError LinkMetrics::ReadTypeIdFlagsFromMessage(const Message &aMessage,
{
pos += sizeof(uint8_t); // Skip the additional second flags byte.
}
else
{
aLinkMetrics.mReserved = true;
}
break;
}
}
@@ -750,7 +867,7 @@ exit:
return error;
}
otError LinkMetrics::AppendStatusSubTlvToMessage(Message &aMessage, uint8_t &aLength, otLinkMetricsStatus aStatus)
otError LinkMetrics::AppendStatusSubTlvToMessage(Message &aMessage, uint8_t &aLength, LinkMetricsStatus aStatus)
{
otError error = OT_ERROR_NONE;
Tlv statusTlv;
+67 -28
View File
@@ -167,6 +167,16 @@ class LinkMetrics : public InstanceLocator, private NonCopyable
friend class Neighbor;
public:
enum LinkMetricsStatus : uint8_t
{
kLinkMetricsStatusSuccess = OT_LINK_METRICS_STATUS_SUCCESS,
kLinkMetricsStatusCannotSupportNewSeries = OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES,
kLinkMetricsStatusSeriesIdAlreadyRegistered = OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED,
kLinkMetricsStatusSeriesIdNotRecognized = OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED,
kLinkMetricsStatusNoMatchingFramesReceived = OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED,
kLinkMetricsStatusOtherError = OT_LINK_METRICS_STATUS_OTHER_ERROR,
};
/**
* This constructor initializes an instance of the LinkMetrics class.
*
@@ -184,9 +194,10 @@ public:
* @param[in] aSeriesId The Series ID to query, 0 for single probe.
* @param[in] aLinkMetricsFlags A pointer to flags specifying what metrics to query.
*
* @retval OT_ERROR_NONE Successfully sent a Link Metrics query message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Data Request message.
* @retval OT_ERROR_INVALID_ARGS TypeIdFlags are not valid or exceed the count limit.
* @retval OT_ERROR_NONE Successfully sent a Link Metrics query message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Data Request message.
* @retval OT_ERROR_INVALID_ARGS TypeIdFlags are not valid or exceed the count limit.
* @retval OT_ERROR_UNKNOWN_NEIGHBOR @p aDestination is not link-local or the neighbor is not found.
*
*/
otError LinkMetricsQuery(const Ip6::Address & aDestination,
@@ -202,9 +213,11 @@ public:
* accounted.
* @param[in] aLinkMetricsFlags A pointer to flags specifying what metrics to query.
*
* @retval OT_ERROR_NONE Successfully sent a Link Metrics Management Request message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Metrics Management Request message.
* @retval OT_ERROR_INVALID_ARGS @p aSeriesId is not within the valid range.
* @retval OT_ERROR_NONE Successfully sent a Link Metrics Management Request message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Metrics Management Request
* message.
* @retval OT_ERROR_INVALID_ARGS @p aSeriesId is not within the valid range.
* @retval OT_ERROR_UNKNOWN_NEIGHBOR @p aDestination is not link-local or the neighbor is not found.
*
*/
otError SendMgmtRequestForwardTrackingSeries(const Ip6::Address & aDestination,
@@ -212,6 +225,26 @@ public:
const otLinkMetricsSeriesFlags &aSeriesFlags,
const otLinkMetrics * aLinkMetricsFlags);
/**
* This method sends an MLE Link Metrics Management Request to configure/clear a Enhanced-ACK Based Probing.
*
* @param[in] aDestination A reference to the IPv6 address of the destination.
* @param[in] aEnhAckFlags Enh-ACK Flags to indicate whether to register or clear the probing. `0` to clear
* and `1` to register. Other values are reserved.
* @param[in] aLinkMetricsFlags A pointer to flags specifying what metrics to query. Should be `NULL` when
* `aEnhAckFlags` is `0`.
*
* @retval OT_ERROR_NONE Successfully sent a Link Metrics Management Request message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Metrics Management Request
* message.
* @retval OT_ERROR_INVALID_ARGS @p aEnhAckFlags is not a valid value or @p aLinkMetricsFlags isn't correct.
* @retval OT_ERROR_UNKNOWN_NEIGHBOR @p aDestination is not link-local or the neighbor is not found.
*
*/
otError SendMgmtRequestEnhAckProbing(const Ip6::Address & aDestination,
otLinkMetricsEnhAckFlags aEnhAckFlags,
const otLinkMetrics * aLinkMetricsFlags);
/**
* This method sends an MLE Link Probe message.
*
@@ -219,9 +252,10 @@ public:
* @param[in] aSeriesId The Series ID which the Probe message targets at.
* @param[in] aLength The length of the data payload in Link Probe TLV, [0, 64].
*
* @retval OT_ERROR_NONE Successfully sent a Link Probe message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Probe message.
* @retval OT_ERROR_INVALID_ARGS @p aSeriesId or @p aLength is not within the valid range.
* @retval OT_ERROR_NONE Successfully sent a Link Probe message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Link Probe message.
* @retval OT_ERROR_INVALID_ARGS @p aSeriesId or @p aLength is not within the valid range.
* @retval OT_ERROR_UNKNOWN_NEIGHBOR @p aDestination is not link-local or the neighbor is not found.
*
*/
otError SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t aLength);
@@ -251,9 +285,9 @@ public:
* @retval OT_ERROR_PARSE Cannot parse sub-TLVs from @p aMessage successfully.
*
*/
otError HandleLinkMetricsManagementRequest(const Message & aMessage,
Neighbor & aNeighbor,
otLinkMetricsStatus &aStatus);
otError HandleLinkMetricsManagementRequest(const Message & aMessage,
Neighbor & aNeighbor,
LinkMetricsStatus &aStatus);
/**
* This method handles the received Link Metrics Management Response contained in @p aMessage.
@@ -312,6 +346,11 @@ public:
*/
void SetLinkMetricsMgmtResponseCallback(otLinkMetricsMgmtResponseCallback aCallback, void *aCallbackContext);
void SetLinkMetricsEnhAckProbingCallback(otLinkMetricsEnhAckProbingIeReportCallback aCallback,
void * aCallbackContext);
void ProcessEnhAckIeData(const uint8_t *aData, uint8_t aLen, const Neighbor &aNeighbor);
private:
/**
* TypeIdFlagPdu: 0x0_1_000_000 -> 0x40 ==> L bit set, type = 0 (count/summation), metric-enum = 0 (PDU rxed).
@@ -324,11 +363,6 @@ private:
{
kMaxTypeIdFlags = 4,
kTypeIdFlagPdu = 0x40,
kTypeIdFlagLqi = 0x09,
kTypeIdFlagLinkMargin = 0x0a,
kTypeIdFlagRssi = 0x0b,
kMaxSeriesSupported =
OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED, ///< Max number of LinkMetricsSeriesInfo that could
///< be allocated by the pool.
@@ -340,10 +374,12 @@ private:
kLinkProbeMaxLen = 64, ///< Max length of data payload in Link Probe TLV.
};
otLinkMetricsReportCallback mLinkMetricsReportCallback;
void * mLinkMetricsReportCallbackContext;
otLinkMetricsMgmtResponseCallback mLinkMetricsMgmtResponseCallback;
void * mLinkMetricsMgmtResponseCallbackContext;
otLinkMetricsReportCallback mLinkMetricsReportCallback;
void * mLinkMetricsReportCallbackContext;
otLinkMetricsMgmtResponseCallback mLinkMetricsMgmtResponseCallback;
void * mLinkMetricsMgmtResponseCallbackContext;
otLinkMetricsEnhAckProbingIeReportCallback mLinkMetricsEnhAckProbingIeReportCallback;
void * mLinkMetricsEnhAckProbingIeReportCallbackContext;
Pool<LinkMetricsSeriesInfo, kMaxSeriesSupported> mLinkMetricsSeriesInfoPool;
@@ -352,13 +388,16 @@ private:
const LinkMetricsTypeIdFlags *aTypeIdFlags,
uint8_t aTypeIdFlagsCount);
otLinkMetricsStatus ConfigureForwardTrackingSeries(uint8_t aSeriesId,
const SeriesFlags & aSeriesFlags,
const otLinkMetrics &aLinkMetrics,
Neighbor & aNeighbor);
LinkMetricsStatus ConfigureForwardTrackingSeries(uint8_t aSeriesId,
const SeriesFlags & aSeriesFlags,
const otLinkMetrics &aLinkMetrics,
Neighbor & aNeighbor);
static uint8_t TypeIdFlagsFromLinkMetricsFlags(LinkMetricsTypeIdFlags *aTypeIdFlags,
const otLinkMetrics & aLinkMetricsFlags);
LinkMetricsStatus ConfigureEnhAckProbing(LinkMetricsEnhAckFlags aEnhAckFlags,
const otLinkMetrics & aLinkMetrics,
Neighbor & aNeighbor);
Neighbor *GetNeighborFromLinkLocalAddr(const Ip6::Address &aDestination);
static otError ReadTypeIdFlagsFromMessage(const Message &aMessage,
uint8_t aStartPos,
@@ -367,7 +406,7 @@ private:
static otError AppendReportSubTlvToMessage(Message &aMessage, uint8_t &aLength, const otLinkMetricsValues &aValues);
static otError AppendStatusSubTlvToMessage(Message &aMessage, uint8_t &aLength, otLinkMetricsStatus aStatus);
static otError AppendStatusSubTlvToMessage(Message &aMessage, uint8_t &aLength, LinkMetricsStatus aStatus);
};
/**
+149
View File
@@ -70,6 +70,18 @@ enum Type : uint8_t
kEnhancedACKConfiguration = 7, ///< Enhanced ACK Configuration Sub-TLV
};
/**
* Valid values for Link Metrics Type Id Flags.
*
*/
enum
{
kTypeIdFlagPdu = 0x40,
kTypeIdFlagLqi = 0x09,
kTypeIdFlagLinkMargin = 0x0a,
kTypeIdFlagRssi = 0x0b,
};
/**
* This class defines Link Metrics Query ID TLV constants and types.
*
@@ -83,6 +95,11 @@ typedef UintTlvInfo<kLinkMetricsQueryId, uint8_t> LinkMetricsQueryIdTlv;
OT_TOOL_PACKED_BEGIN class LinkMetricsTypeIdFlags
{
public:
enum : uint8_t
{
kTypeEnumReserved = 2,
};
/**
* Default constructor.
*
@@ -355,6 +372,33 @@ public:
*/
SeriesFlags(const SeriesFlags &aSeriesFlags) { mSeriesFlags = aSeriesFlags.mSeriesFlags; }
/**
* This method sets the values of this object from a `otLinkMetricsSeriesFlags` object.
*
* @param[in] aSeriesFlags The `otLinkMetricsSeriesFlags` object.
*
*/
void SetFromOtSeriesFlags(const otLinkMetricsSeriesFlags aSeriesFlags)
{
Clear();
if (aSeriesFlags.mLinkProbe)
{
SetLinkProbeFlag();
}
if (aSeriesFlags.mMacData)
{
SetMacDataFlag();
}
if (aSeriesFlags.mMacDataRequest)
{
SetMacDataRequestFlag();
}
if (aSeriesFlags.mMacAck)
{
SetMacAckFlag();
}
}
/**
* This method clears the Link Probe flag.
*
@@ -469,6 +513,111 @@ private:
uint8_t mSeriesFlags;
} OT_TOOL_PACKED_END;
enum LinkMetricsEnhAckFlags : uint8_t
{
kEnhAckClear = OT_LINK_METRICS_ENH_ACK_CLEAR, ///< Clear.
kEnhAckRegister = OT_LINK_METRICS_ENH_ACK_REGISTER, ///< Register.
};
static uint8_t TypeIdFlagsFromLinkMetricsFlags(LinkMetricsTypeIdFlags *aTypeIdFlags,
const otLinkMetrics & aLinkMetricsFlags)
{
uint8_t count = 0;
if (aLinkMetricsFlags.mPduCount)
{
aTypeIdFlags[count++].SetRawValue(kTypeIdFlagPdu);
}
if (aLinkMetricsFlags.mLqi)
{
aTypeIdFlags[count++].SetRawValue(kTypeIdFlagLqi);
}
if (aLinkMetricsFlags.mLinkMargin)
{
aTypeIdFlags[count++].SetRawValue(kTypeIdFlagLinkMargin);
}
if (aLinkMetricsFlags.mRssi)
{
aTypeIdFlags[count++].SetRawValue(kTypeIdFlagRssi);
}
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
if (aLinkMetricsFlags.mReserved)
{
for (uint8_t i = 0; i < count; i++)
{
aTypeIdFlags[i].SetTypeEnum(LinkMetricsTypeIdFlags::kTypeEnumReserved);
}
}
#endif
return count;
}
OT_TOOL_PACKED_BEGIN
class EnhAckLinkMetricsConfigurationSubTlv : public Tlv
{
public:
/**
* Default constructor
*
*/
EnhAckLinkMetricsConfigurationSubTlv(void) { Init(); }
/**
* This method initializes the TLV.
*
*/
void Init(void)
{
SetType(kEnhancedACKConfiguration);
SetLength(sizeof(LinkMetricsEnhAckFlags));
}
/**
* This method sets Enhanced ACK Flags.
*
* @param[in] aEnhAckFlags The value of Enhanced ACK Flags.
*
*/
void SetEnhAckFlags(otLinkMetricsEnhAckFlags aEnhAckFlags)
{
memcpy(mSubTlvs + kEnhAckFlagsOffset, &aEnhAckFlags, sizeof(aEnhAckFlags));
}
/**
* This method sets Type Id Flags.
*
* @param[in] aLinkMetricsFlags A pointer to a `otLinkMetrics` representing the Type Id Flags.
*
*/
void SetTypeIdFlags(const otLinkMetrics *aLinkMetricsFlags)
{
uint8_t typeIdFlagsCount;
OT_ASSERT(aLinkMetricsFlags != nullptr);
typeIdFlagsCount = TypeIdFlagsFromLinkMetricsFlags(
reinterpret_cast<LinkMetricsTypeIdFlags *>(mSubTlvs + kTypeIdFlagsOffset), *aLinkMetricsFlags);
OT_ASSERT(typeIdFlagsCount <= kMaxTypeIdFlagsEnhAck);
SetLength(sizeof(LinkMetricsEnhAckFlags) + sizeof(LinkMetricsTypeIdFlags) * typeIdFlagsCount);
}
private:
enum
{
kMaxTypeIdFlagsEnhAck = 3,
kEnhAckFlagsOffset = 0,
kTypeIdFlagsOffset = sizeof(LinkMetricsTypeIdFlags),
};
uint8_t mSubTlvs[sizeof(LinkMetricsEnhAckFlags) + sizeof(LinkMetricsTypeIdFlags) * kMaxTypeIdFlagsEnhAck];
} OT_TOOL_PACKED_END;
} // namespace ot
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
+1 -1
View File
@@ -173,7 +173,7 @@ void MeshForwarder::PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address &
fcf |= (aMacDest.IsShort()) ? Mac::Frame::kFcfDstAddrShort : Mac::Frame::kFcfDstAddrExt;
fcf |= (macSource.IsShort()) ? Mac::Frame::kFcfSrcAddrShort : Mac::Frame::kFcfSrcAddrExt;
Get<Mac::Mac>().UpdateFrameControlField(nullptr, false, fcf);
Get<Mac::Mac>().UpdateFrameControlField(Get<NeighborTable>().FindNeighbor(aMacDest), false, fcf);
aFrame.InitMacHeader(fcf, Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32);
+5 -5
View File
@@ -2454,7 +2454,7 @@ exit:
}
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otError Mle::SendLinkMetricsManagementResponse(const Ip6::Address &aDestination, otLinkMetricsStatus aStatus)
otError Mle::SendLinkMetricsManagementResponse(const Ip6::Address &aDestination, LinkMetrics::LinkMetricsStatus aStatus)
{
otError error = OT_ERROR_NONE;
Message *message;
@@ -2498,7 +2498,7 @@ otError Mle::SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId,
exit:
return error;
}
#endif
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otError Mle::SendMessage(Message &aMessage, const Ip6::Address &aDestination)
{
@@ -3823,8 +3823,8 @@ void Mle::HandleLinkMetricsManagementRequest(const Message & aMessage,
const Ip6::MessageInfo &aMessageInfo,
Neighbor * aNeighbor)
{
otError error = OT_ERROR_NONE;
otLinkMetricsStatus status;
otError error = OT_ERROR_NONE;
LinkMetrics::LinkMetricsStatus status;
Log(kMessageReceive, kTypeLinkMetricsManagementRequest, aMessageInfo.GetPeerAddr());
@@ -3867,7 +3867,7 @@ void Mle::HandleLinkProbe(const Message &aMessage, const Ip6::MessageInfo &aMess
exit:
LogProcessError(kTypeLinkProbe, error);
}
#endif
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
void Mle::ProcessAnnounce(void)
{
+1 -1
View File
@@ -1746,7 +1746,7 @@ private:
bool PrepareAnnounceState(void);
void SendAnnounce(uint8_t aChannel, bool aOrphanAnnounce, const Ip6::Address &aDestination);
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otError SendLinkMetricsManagementResponse(const Ip6::Address &aDestination, otLinkMetricsStatus aStatus);
otError SendLinkMetricsManagementResponse(const Ip6::Address &aDestination, LinkMetrics::LinkMetricsStatus aStatus);
#endif
uint32_t Reattach(void);
+47 -3
View File
@@ -558,6 +558,14 @@ public:
*/
bool IsThreadVersion1p1(void) const { return mState != kStateInvalid && mVersion == OT_THREAD_VERSION_1_1; }
/**
* This method indicates whether or not it is a valid Thread 1.2 neighbor.
*
* @returns TRUE if it is a valid Thread 1.2 neighbor, FALSE otherwise.
*
*/
bool IsThreadVersion1p2(void) const { return mState != kStateInvalid && mVersion == OT_THREAD_VERSION_1_2; }
/**
* This method indicates whether Enhanced Keep-Alive is supported or not.
*
@@ -703,12 +711,43 @@ public:
LinkMetricsSeriesInfo *RemoveForwardTrackingSeriesInfo(const uint8_t &aSeriesId);
/**
* This method removes all the Series and return the data structures to the Pool
* This method removes all the Series and return the data structures to the Pool.
*
*/
void RemoveAllForwardTrackingSeriesInfo(void);
#endif
/**
* This method gets the Enh-ACK Probing metrics (this `Neighbor` object is the Probing Subject).
*
* @returns Enh-ACK Probing metrics configured.
*
*/
const otLinkMetrics &GetEnhAckProbingMetrics(void) const { return mEnhAckProbingMetrics; }
/**
* This method sets the Enh-ACK Probing metrics (this `Neighbor` object is the Probing Subject).
*
* @param[in] aEnhAckProbingMetrics The metrics value to set.
*
*/
void SetEnhAckProbingMetrics(const otLinkMetrics &aEnhAckProbingMetrics)
{
mEnhAckProbingMetrics = aEnhAckProbingMetrics;
}
/**
* This method indicates if Enh-ACK Probing is configured and active for this `Neighbor` object.
*
* @retval TRUE Enh-ACK Probing is configured and active for this `Neighbor`.
* @retval FALSE Otherwise.
*
*/
bool IsEnhAckProbingActive(void) const
{
return (mEnhAckProbingMetrics.mLqi != 0) || (mEnhAckProbingMetrics.mLinkMargin != 0) ||
(mEnhAckProbingMetrics.mRssi != 0);
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
/**
* This method converts a given `State` to a human-readable string.
@@ -766,7 +805,12 @@ private:
LinkQualityInfo mLinkInfo; ///< Link quality info (contains average RSS, link margin and link quality)
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
LinkedList<LinkMetricsSeriesInfo> mLinkMetricsSeriesInfoList; ///< A list of Link Metrics Forward Tracking Series
///< that is being tracked for this neighbor.
///< that is being tracked for this neighbor. Note
///< that this device is the Subject and this
///< this neighbor is the Initiator.
otLinkMetrics mEnhAckProbingMetrics; ///< Metrics configured for Enh-ACK Based Probing at the Probing Subject
///< (this neighbor). Note that this device is the Initiator and this neighbor
///< is the Subject.
#endif
};
+13
View File
@@ -1936,6 +1936,19 @@ class NodeImpl:
self.send_command(cmd)
self._expect('Done')
def link_metrics_mgmt_req_enhanced_ack_based_probing(self,
dst_addr: str,
enable: bool,
metrics_flags: str,
ext_flags=''):
cmd = "linkmetrics mgmt %s enhanced-ack" % (dst_addr)
if enable:
cmd = cmd + (" register %s %s" % (metrics_flags, ext_flags))
else:
cmd = cmd + " clear"
self.send_command(cmd)
self._expect('Done')
def link_metrics_mgmt_req_forward_tracking_series(self, dst_addr: str, series_id: int, series_flags: str,
metrics_flags: str):
cmd = "linkmetrics mgmt %s forward %d %s %s" % (dst_addr, series_id, series_flags, metrics_flags)
@@ -230,6 +230,10 @@ NWD_SERVICE_TLV = 4
NWD_SERVER_TLV = 5
NWD_COMMISSIONING_DATA_TLV = 6
# Link Metrics TLVs
LM_FORWARD_PROBING_REGISTRATION_SUB_TLV = 3
LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV = 7
# DUA related constants
ADDRESS_QUERY_INITIAL_RETRY_DELAY = 15
@@ -312,6 +316,11 @@ TIMEOUT_REGISTER_MA = 5
MAC_FRAME_VERSION_2006 = 1
MAC_FRAME_VERSION_2015 = 2
# 802.15.4 Frame Type
MAC_FRAME_TYPE_DATA = 0x1
MAC_FRAME_TYPE_ACK = 0x2
MAC_FRAME_TYPE_MAC_CMD = 0x3
# CSL
CSL_DEFAULT_PERIOD = 3125 # 0.5s, 3125 in units of ten symbols
CSL_DEFAULT_PERIOD_IN_SECOND = 0.5
@@ -340,6 +349,12 @@ LINK_METRICS_METRIC_TYPE_ENUM_LQI = 1
LINK_METRICS_METRIC_TYPE_ENUM_LINK_MARGIN = 2
LINK_METRICS_METRIC_TYPE_ENUM_RSSI = 3
LINK_METRICS_ENH_ACK_PROBING_CLEAR = 0
LINK_METRICS_ENH_ACK_PROBING_REGISTER = 1
# THREAD_COMPANY_ID
THREAD_IEEE_802154_COMPANY_ID = 0xEAB89B
if __name__ == '__main__':
from pktverify.addrs import Ipv6Addr
@@ -275,6 +275,7 @@ _LAYER_FIELDS = {
'wpan.channel': _auto,
'wpan.header_ie.id': _list(_auto),
'wpan.header_ie.csl.period': _auto,
'wpan.payload_ie.vendor.oui': _auto,
# MLE
'mle.cmd': _auto,
@@ -320,13 +321,16 @@ _LAYER_FIELDS = {
'mle.tlv.addr16': _auto,
'mle.tlv.channel': _auto,
'mle.tlv.addr_reg_iid': _list(_auto),
'mle.tlv.link_enh_ack_flags': _auto,
'mle.tlv.link_forward_series': _list(_auto),
'mle.tlv.link_requested_type_id_flags': _list(_hex),
'mle.tlv.link_sub_tlv': _auto,
'mle.tlv.link_status_sub_tlv': _auto,
'mle.tlv.query_id': _auto,
'mle.tlv.metric_type_id_flags.type': _list(_hex),
'mle.tlv.metric_type_id_flags.metric': _list(_hex),
'mle.tlv.metric_type_id_flags.l': _list(_hex),
'mle.tlv.link_requested_type_id_flags': _bytes,
# IP
'ip.version': _auto,
@@ -436,6 +436,34 @@ class PacketFilter(object):
"""
return self.filter(attrgetter('wpan'), **kwargs)
def filter_wpan_ack(self, **kwargs):
"""
Create a new PacketFilter for filter WPAN ACK packets.
:param kwargs: Extra arguments for `filter`.
:return: The new PacketFilter to filter WPAN packets.
"""
return self.filter(lambda p: p.wpan.frame_type == consts.MAC_FRAME_TYPE_ACK, **kwargs)
def filter_wpan_data(self, **kwargs):
"""
Create a new PacketFilter for filter WPAN data packets.
:param kwargs: Extra arguments for `filter`.
:return: The new PacketFilter to filter WPAN packets.
"""
return self.filter(lambda p: p.wpan.frame_type == consts.MAC_FRAME_TYPE_DATA, **kwargs)
def filter_wpan_seq(self, seq, **kwargs):
"""
Create a new PacketFilter for filter WPAN packets of a sequence number.
:param seq: The sequence number to filter.
:param kwargs: Extra arguments for `filter`.
:return: The new PacketFilter to filter WPAN packets.
"""
return self.filter(lambda p: p.wpan.seq_no == seq, **kwargs)
def filter_wpan_version(self, version: int, **kwargs):
"""
Create a new PacketFilter for filter WPAN packets of a given version.
@@ -476,6 +504,12 @@ class PacketFilter(object):
def filter_dst16(self, rloc16: int, **kwargs):
return self.filter(lambda p: p.lowpan.mesh.dest16 == rloc16 or p.wpan.dst16 == rloc16, **kwargs)
def filter_wpan_ie_present(self, **kwargs):
return self.filter(lambda p: p.wpan.ie_present == 1)
def filter_wpan_ie_not_present(self, **kwargs):
return self.filter(lambda p: p.wpan.ie_present == 0)
def filter_ping_request(self, identifier=None, **kwargs):
return self.filter(
lambda p: p.icmpv6.is_ping_request and (identifier is None or p.icmpv6.echo.identifier == identifier),
@@ -0,0 +1,390 @@
#!/usr/bin/env python3
#
# Copyright (c) 2020, 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.
#
import unittest
from config import ADDRESS_TYPE
from pktverify import consts
import thread_cert
LEADER = 1
SED_1 = 2
SSED_1 = 3
POLL_PERIOD = 3000 # 3s
class LowPower_7_1_01(thread_cert.TestCase):
TOPOLOGY = {
LEADER: {
'version': '1.2',
'name': 'LEADER',
'mode': 'rdn',
'panid': 0xface,
'allowlist': [SED_1, SSED_1],
},
SED_1: {
'version': '1.2',
'name': 'SED_1',
'mode': '-',
'panid': 0xface,
'allowlist': [LEADER],
},
SSED_1: {
'version': '1.2',
'name': 'SSED_1',
'mode': '-',
'panid': 0xface,
'allowlist': [LEADER],
}
}
"""All nodes are created with default configurations"""
def test(self):
self.nodes[LEADER].start()
self.simulator.go(5)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[SED_1].set_pollperiod(POLL_PERIOD)
self.nodes[SED_1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SED_1].get_state(), 'child')
self.nodes[SSED_1].set_csl_period(consts.CSL_DEFAULT_PERIOD)
self.nodes[SSED_1].start()
self.simulator.go(5)
self.assertEqual(self.nodes[SSED_1].get_state(), 'child')
leader_addr = self.nodes[LEADER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL)
# Step 3 - Verify connectivity by instructing each device to sending an ICMPv6 Echo Request to the DUT
self.assertTrue(self.nodes[SED_1].ping(leader_addr, timeout=POLL_PERIOD))
self.assertTrue(self.nodes[SSED_1].ping(leader_addr))
self.simulator.go(5)
# Step 4 - SED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
# Request to the DUT
# MLE Link Metrics Management TLV Payload:
# - Enhanced ACK Configuration Sub-TLV
# -- Enh-ACK Flags = 1 (register a configuration)
# -- Concatenation of Link Metric Type ID Flags = 0x00:
# --- Item1: (0)(0)(001)(010) = 0x0a
# ---- E = 0
# ---- L = 0
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
# ---- Metrics Enum = 2 (Link Margin)
self.nodes[SED_1].link_metrics_mgmt_req_enhanced_ack_based_probing(leader_addr, True, 'm')
self.simulator.go(5)
# Step 6 - SSED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
# Request to the DUT
# MLE Link Metrics Management TLV Payload:
# - Enhanced ACK Configuration Sub-TLV
# -- Enh-ACK Flags = 1 (register a configuration)
# -- Concatenation of Link Metric Type ID Flags = 0x00:
# --- Item1: (0)(0)(001)(010) = 0x0a
# --- Item2: (0)(0)(001)(011) = 0x0b
# ---- E = 0
# ---- L = 0
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
# ---- Metrics Enum = 2 (Link Margin)
# ---- Metrics Enum = 3 (RSSI)
self.nodes[SSED_1].link_metrics_mgmt_req_enhanced_ack_based_probing(leader_addr, True, 'mr')
self.simulator.go(5)
# Step 8 - SSED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
# message to 0b10
self.nodes[SSED_1].send_mac_emptydata()
self.simulator.go(5)
# Step 10 - SED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
# message # to 0b10
self.nodes[SED_1].send_mac_emptydata()
self.simulator.go(5)
# Step 12 - SSED_1 clears its Enhanced ACK link metrics configuration by # sending a Link Metrics Management
# Request to the DUT
# Enh-ACK Flags = 0 (clear enhanced ACK link metric config)
self.nodes[SSED_1].link_metrics_mgmt_req_enhanced_ack_based_probing(leader_addr, False, '')
self.simulator.go(5)
# Step 14 - SSED_1 Sends a MLE Data Message with setting Frame Version subfield within the MAC header of the
# message to 0b10
self.nodes[SSED_1].send_mac_emptydata()
self.simulator.go(5)
# Step 16 - This step verifies that Enhanced ACKs cannot be enabled while requesting 3 metric types by
# instructing the device to send the following Link Metrics Management Request to the DUT
# MLE Link Metrics Management TLV Payload:
# - Enhanced ACK Configuration Sub-TLV
# -- Enh-ACK Flags = 1 (register a configuration)
# -- Concatenation of Link Metric Type ID Flags = 0x00:
# --- Item1: (0)(0)(001)(001) = 0x09
# --- Item2: (0)(0)(001)(010) = 0x0a
# --- Item3: (0)(0)(001)(011) = 0x0b
# ---- E = 0
# ---- L = 0
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
# ---- Metrics Enum = 1 (Layer 2 LQI)
# ---- Metrics Enum = 2 (Link Margin)
# ---- Metrics Enum = 3 (RSSI)
self.nodes[SSED_1].link_metrics_mgmt_req_enhanced_ack_based_probing(leader_addr, True, 'qmr')
self.simulator.go(5)
# Step 18 - This step verifies that Enhanced ACKs cannot be enabled while requesting a reserved Type/Average
# enum of value 2 by instructing the device to send the following Link Metrics Management Request to the DUT
# MLE Link Metrics Management TLV Payload:
# - Enhanced ACK Configuration Sub-TLV
# -- Enh-ACK Flags = 1 (register a configuration)
# -- Concatenation of Link Metric Type ID Flags = 0x00:
# --- Item1: (0)(0)(010)(010) = 0x12
# ---- E = 0
# ---- L = 0
# ---- Type/Average Enum = 2 (Reserved)
# ---- Metrics Enum = 2 (Link Margin)
self.nodes[SSED_1].link_metrics_mgmt_req_enhanced_ack_based_probing(leader_addr, True, 'm', 'r')
self.simulator.go(5)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
SED_1 = pv.vars['SED_1']
SSED_1 = pv.vars['SSED_1']
# Step 3 - The DUT MUST send ICMPv6 Echo Responses to both SED1 & SSED1
pkts.filter_wpan_src64(LEADER) \
.filter_wpan_dst64(SED_1) \
.filter_ping_reply() \
.must_next()
pkts.filter_wpan_src64(LEADER) \
.filter_wpan_dst64(SSED_1) \
.filter_ping_reply() \
.must_next()
# Step 4 - SED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
# Request to the DUT
# MLE Link Metrics Management TLV Payload:
# - Enhanced ACK Configuration Sub-TLV
# -- Enh-ACK Flags = 1 (register a configuration)
# -- Concatenation of Link Metric Type ID Flags = 0x00:
# --- Item1: (0)(0)(001)(010) = 0x0a
# ---- E = 0
# ---- L = 0
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
# ---- Metrics Enum = 2 (Link Margin)
pkts.filter_wpan_src64(SED_1) \
.filter_wpan_dst64(LEADER) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
.filter(lambda p: p.mle.tlv.link_sub_tlv == consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV) \
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '0a') \
.must_next()
# Step 5 - The DUT MUST send a Link Metrics Management Response to SED_1 containing the following TLVs:
# - MLE LInk Metrics Management TLV
# -- Link Metrics Status Sub-TLV = 0 (Success)
pkts.filter_wpan_src64(LEADER) \
.filter_wpan_dst64(SED_1) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
.must_next()
# Step 6 - SSED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
# Request to the DUT
# MLE Link Metrics Management TLV Payload:
# - Enhanced ACK Configuration Sub-TLV
# -- Enh-ACK Flags = 1 (register a configuration)
# -- Concatenation of Link Metric Type ID Flags = 0x00:
# --- Item1: (0)(0)(001)(010) = 0x0a
# --- Item2: (0)(0)(001)(011) = 0x0b
# ---- E = 0
# ---- L = 0
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
# ---- Metrics Enum = 2 (Link Margin)
# ---- Metrics Enum = 3 (RSSI)
pkts.filter_wpan_src64(SSED_1) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
.filter(lambda p: p.mle.tlv.link_sub_tlv == consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV) \
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '0a0b') \
.must_next()
# Step 7 - The DUT MUST send a Link Metrics Management Response to SSED_1
pkts.filter_wpan_src64(LEADER) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
.must_next()
# Step 8 - SSED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
# message to 0b10
pkt = pkts.filter_wpan_src64(SSED_1) \
.filter_wpan_data() \
.filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
.must_next()
ack_seq_no = pkt.wpan.seq_no
# Step 9 - The DUT MUST reply to SSED_1 with an Enhanced ACK containing the following:
# - Frame Control Field
# -- Security Enabled = True
# - Header IE
# -- Element ID = 0x00
# --- Vendor CID = 0xEAB89B (Thread Group)
# --- Vendor Specific Information
# ---- 1st byte = 0 (Enhanced ACK Link Metrics)
# ---- 2nd byte ... Link Margin data
# ---- 3rd byte ... RSSI data
pkts.filter_wpan_ack() \
.filter_wpan_seq(ack_seq_no) \
.filter(lambda p: p.wpan.payload_ie.vendor.oui == consts.THREAD_IEEE_802154_COMPANY_ID) \
.must_next()
# Step 10 - SED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
# message to 0b10
pkt = pkts.filter_wpan_src64(SED_1) \
.filter_wpan_data() \
.filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
.must_next()
ack_seq_no = pkt.wpan.seq_no
# Step 11 - The DUT MUST reply to SED_1 with an Enhanced ACK containing the following:
# - Frame Control Field
# -- Security Enabled = True
# - Header IE
# -- Element ID = 0x00
# --- Vendor CID = 0xEAB89B (Thread Group)
# --- Vendor Specific Information
# ---- 1st byte = 0 (Enhanced ACK Link Metrics)
# ---- 2nd byte ... Link Margin data
pkts.filter_wpan_ack() \
.filter_wpan_seq(ack_seq_no) \
.filter(lambda p: p.wpan.payload_ie.vendor.oui == consts.THREAD_IEEE_802154_COMPANY_ID) \
.must_next()
# Step 12 - SSED_1 clears enhanced ACK link metrics configuration by instructing it to send a Link Metrics
# Management Request to the DUT
# - MLE Link Metrics Management TLV Payload
# -- Enhanced ACK Configuration Sub-TLV
# -- Enh-ACK Flags = 0 (clear enhanced ACK link metric config)
pkts.filter_wpan_src64(SSED_1) \
.filter_wpan_dst64(LEADER) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
.filter(lambda p: p.mle.tlv.link_sub_tlv == consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV) \
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_CLEAR) \
.must_next()
# Step 13 - The DUT MUST send Link Metrics Management Response to SSED_1 containing the following:
# - MLE Link Metrics Management TLV
# -- Link Metrics Status Sub-TLV = 0 (Success)
pkts.filter_wpan_src64(LEADER) \
.filter_wpan_dst64(SSED_1) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
.must_next()
# Step 14 - SSED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
# message to 0b10
pkt = pkts.filter_wpan_src64(SSED_1) \
.filter_wpan_data() \
.filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
.must_next()
ack_seq_no = pkt.wpan.seq_no
# Step 15 - The DUT MUST NOT include a Link Metrics Report in the ACK
pkts.filter_wpan_ack() \
.filter_wpan_seq(ack_seq_no) \
.filter_wpan_ie_not_present() \
.must_next()
# Step 16 - This step verifies that Enhanced ACKS cannot be enabled while requesting 3 metric types by
# instructing the device to send the following Link Metrics Management Request to the DUT:
# MLE Link Metrics Management TLV Payload:
# - Enhanced ACK Configuration Sub-TLV
# -- Enh-ACK Flags = 1 (register a configuration)
# -- Concatenation of Link Metric Type ID Flags = 0x00:
# --- Item1: (0)(0)(001)(001) = 0x09
# --- Item2: (0)(0)(001)(010) = 0x0a
# --- Item3: (0)(0)(001)(011) = 0x0b
# ---- E = 0
# ---- L = 0
# ---- Type/Average Enum = 1 (Exponential Moving Avg)
# ---- Metrics Enum = 1 (Layer 2 LQI)
# ---- Metrics Enum = 2 (Link Margin)
# ---- Metrics Enum = 3 (RSSI)
pkts.filter_wpan_src64(SSED_1) \
.filter_wpan_dst64(LEADER) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
.filter(lambda p: p.mle.tlv.link_sub_tlv == consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV) \
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '090a0b') \
.must_next()
# Step 17 - Leader automatically responds to the invalid query from SSED_1 with a failure
# The DUT MUST send Link Metrics Management Response to SSED_1containing the following:
# - MLE Link Metrics Management TLV
# -- Link Metrics Status Sub-TLV = 254 (Failure)
pkts.filter_wpan_src64(LEADER) \
.filter_wpan_dst64(SSED_1) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_OTHER_ERROR) \
.must_next()
# Step 18 - This step verifies that Enhanced ACKs cannot be enabled while requesting a reserved Type/Average
# enum of value 2 by instructing the device to send the following Link Metrics Management Request to the DUT
# MLE Link Metrics Management TLV Payload:
# - Enhanced ACK Configuration Sub-TLV
# -- Enh-ACK Flags = 1 (register a configuration)
# -- Concatenation of Link Metric Type ID Flags = 0x00:
# --- Item1: (0)(0)(010)(010) = 0x12
# ---- E = 0
# ---- L = 0
# ---- Type/Average Enum = 2 (Reserved)
# ---- Metrics Enum = 2 (Link Margin)
pkts.filter_wpan_src64(SSED_1) \
.filter_wpan_dst64(LEADER) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
.filter(lambda p: p.mle.tlv.link_sub_tlv == consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV) \
.filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
.filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '12') \
.must_next()
# Step 19 - Leader automatically responds to the invalid query from SSED_1 with a failure
# The DUT MUST send Link Metrics Management Response to SSED_1containing the following:
# - MLE Link Metrics Management TLV
# -- Link Metrics Status Sub-TLV = 1 (Failure)
pkts.filter_wpan_src64(LEADER) \
.filter_wpan_dst64(SSED_1) \
.filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
.filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
.must_next()
if __name__ == '__main__':
unittest.main()
+21
View File
@@ -653,4 +653,25 @@ otError otPlatTrelUdp6SetTestMode(otInstance *aInstance, bool aEnable)
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otError otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,
otLinkMetrics aLinkMetrics,
const otShortAddress aShortAddress,
const otExtAddress * aExtAddress)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aLinkMetrics);
OT_UNUSED_VARIABLE(aShortAddress);
OT_UNUSED_VARIABLE(aExtAddress);
return OT_ERROR_NONE;
}
otLinkMetrics otPlatRadioGetEnhAckProbingMetrics(otInstance *aInstance, const otShortAddress aShortAddress)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aShortAddress);
}
#endif
} // extern "C"