mirror of
https://github.com/espressif/openthread.git
synced 2026-08-02 09:07:47 +00:00
[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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
+390
@@ -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()
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user