• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "link_metrics.h"
30 
31 #include <openthread/link_metrics.h>
32 
33 #include "common/clearable.hpp"
34 #include "common/linked_list.hpp"
35 #include "common/pool.hpp"
36 #include "thread/link_quality.hpp"
37 
38 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
39 
40 using namespace ot;
41 
42 static int8_t sNoiseFloor; ///< The noise floor used by Link Metrics. It should be set to the platform's
43                            ///< noise floor (measured noise floor, receiver sensitivity or a constant).
44 
45 class LinkMetricsDataInfo : public LinkedListEntry<LinkMetricsDataInfo>, public Clearable<LinkMetricsDataInfo>
46 {
47     friend class LinkedList<LinkMetricsDataInfo>;
48     friend class LinkedListEntry<LinkMetricsDataInfo>;
49 
50 public:
51     /**
52      * Constructor.
53      */
LinkMetricsDataInfo(void)54     LinkMetricsDataInfo(void) { Clear(); };
55 
56     /**
57      * Set the information for this object.
58      *
59      * @param[in]  aLinkMetrics     Flags specifying what metrics to query.
60      * @param[in]  aShortAddress    Short Address of the Probing Initiator tracked by this object.
61      * @param[in]  aExtAddress      A reference to the Extended Address of the Probing Initiator tracked by this
62      *                              object.
63      */
Set(otLinkMetrics aLinkMetrics,otShortAddress aShortAddress,const otExtAddress & aExtAddress)64     void Set(otLinkMetrics aLinkMetrics, otShortAddress aShortAddress, const otExtAddress &aExtAddress)
65     {
66         mLinkMetrics  = aLinkMetrics;
67         mShortAddress = aShortAddress;
68         memcpy(mExtAddress.m8, aExtAddress.m8, sizeof(aExtAddress));
69     }
70 
71     /**
72      * Gets Link Metrics data stored in this object.
73      *
74      * TODO: Currently the order of Link Metircs data is fixed. Will update it to follow the order specified in TLV.
75      *
76      * @param[in]   aLqi     LQI value of the acknowledeged frame.
77      * @param[in]   aRssi    RSSI value of the acknowledged frame.
78      * @param[out]  aData    A pointer to the output buffer. @p aData MUST NOT be `nullptr`. The buffer must have
79      *                       at least 2 bytes (per spec 4.11.3.4.4.6). Otherwise the behavior would be undefined.
80      *
81      * @returns  The number of bytes written. `0` on failure.
82      */
GetEnhAckData(uint8_t aLqi,int8_t aRssi,uint8_t * aData) const83     uint8_t GetEnhAckData(uint8_t aLqi, int8_t aRssi, uint8_t *aData) const
84     {
85         enum
86         {
87             kEnhAckProbingDataMaxLen = 2,
88         };
89 
90         uint8_t bytes = 0;
91 
92         VerifyOrExit(aData != nullptr);
93 
94         if (mLinkMetrics.mLqi)
95         {
96             aData[bytes++] = aLqi;
97         }
98         if (mLinkMetrics.mLinkMargin)
99         {
100             aData[bytes++] = static_cast<uint8_t>(GetLinkMargin(aRssi) * 255 /
101                                                   130); // Linear scale Link Margin from [0, 130] to [0, 255]
102         }
103         if (bytes < kEnhAckProbingDataMaxLen && mLinkMetrics.mRssi)
104         {
105             aData[bytes++] =
106                 static_cast<uint8_t>((aRssi + 130) * 255 / 130); // Linear scale RSSI from [-130, 0] to [0, 255]
107         }
108 
109     exit:
110         return bytes;
111     }
112 
113     /**
114      * Gets the length of Link Metrics Data.
115      *
116      * @returns  The number of bytes for the data.
117      */
GetEnhAckDataLen() const118     uint8_t GetEnhAckDataLen() const
119     {
120         return static_cast<uint8_t>(mLinkMetrics.mLqi) + static_cast<uint8_t>(mLinkMetrics.mLinkMargin) +
121                static_cast<uint8_t>(mLinkMetrics.mRssi);
122     }
123 
124     /**
125      * Gets the metrics configured for the Enhanced-ACK Based Probing.
126      *
127      * @returns  The metrics configured.
128      */
GetLinkMetrics(void) const129     otLinkMetrics GetLinkMetrics(void) const { return mLinkMetrics; }
130 
131 private:
GetLinkMargin(int8_t aRssi) const132     uint8_t GetLinkMargin(int8_t aRssi) const { return ComputeLinkMargin(sNoiseFloor, aRssi); }
133 
Matches(const otShortAddress & aShortAddress) const134     bool Matches(const otShortAddress &aShortAddress) const { return mShortAddress == aShortAddress; };
135 
Matches(const otExtAddress & aExtAddress) const136     bool Matches(const otExtAddress &aExtAddress) const
137     {
138         return memcmp(&mExtAddress, &aExtAddress, sizeof(otExtAddress)) == 0;
139     };
140 
141     LinkMetricsDataInfo *mNext;
142 
143     otLinkMetrics mLinkMetrics;
144 
145     otShortAddress mShortAddress;
146     otExtAddress   mExtAddress;
147 };
148 
149 enum
150 {
151     kMaxEnhAckProbingInitiator = OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED,
152 };
153 
154 typedef Pool<LinkMetricsDataInfo, kMaxEnhAckProbingInitiator> LinkMetricsDataInfoPool;
155 
156 typedef LinkedList<LinkMetricsDataInfo> LinkMetricsDataInfoList;
157 
GetLinkMetricsDataInfoPool(void)158 static LinkMetricsDataInfoPool &GetLinkMetricsDataInfoPool(void)
159 {
160     static LinkMetricsDataInfoPool sDataInfoPool;
161     return sDataInfoPool;
162 }
163 
GetLinkMetricsDataInfoActiveList(void)164 static LinkMetricsDataInfoList &GetLinkMetricsDataInfoActiveList(void)
165 {
166     static LinkMetricsDataInfoList sDataInfoActiveList;
167     return sDataInfoActiveList;
168 }
169 
IsLinkMetricsClear(otLinkMetrics aLinkMetrics)170 static inline bool IsLinkMetricsClear(otLinkMetrics aLinkMetrics)
171 {
172     return !aLinkMetrics.mPduCount && !aLinkMetrics.mLqi && !aLinkMetrics.mLinkMargin && !aLinkMetrics.mRssi;
173 }
174 
otLinkMetricsInit(int8_t aNoiseFloor)175 void otLinkMetricsInit(int8_t aNoiseFloor)
176 {
177     sNoiseFloor = aNoiseFloor;
178     otLinkMetricsResetEnhAckProbing();
179 }
180 
otLinkMetricsConfigureEnhAckProbing(otShortAddress aShortAddress,const otExtAddress * aExtAddress,otLinkMetrics aLinkMetrics)181 otError otLinkMetricsConfigureEnhAckProbing(otShortAddress      aShortAddress,
182                                             const otExtAddress *aExtAddress,
183                                             otLinkMetrics       aLinkMetrics)
184 {
185     otError              error    = OT_ERROR_NONE;
186     LinkMetricsDataInfo *dataInfo = nullptr;
187 
188     VerifyOrExit(aExtAddress != nullptr, error = OT_ERROR_INVALID_ARGS);
189 
190     if (IsLinkMetricsClear(aLinkMetrics)) ///< Remove the entry
191     {
192         dataInfo = GetLinkMetricsDataInfoActiveList().RemoveMatching(aShortAddress);
193         VerifyOrExit(dataInfo != nullptr, error = OT_ERROR_NOT_FOUND);
194         GetLinkMetricsDataInfoPool().Free(*dataInfo);
195     }
196     else
197     {
198         dataInfo = GetLinkMetricsDataInfoActiveList().FindMatching(aShortAddress);
199 
200         if (dataInfo == nullptr)
201         {
202             dataInfo = GetLinkMetricsDataInfoPool().Allocate();
203             VerifyOrExit(dataInfo != nullptr, error = OT_ERROR_NO_BUFS);
204             dataInfo->Clear();
205             GetLinkMetricsDataInfoActiveList().Push(*dataInfo);
206         }
207 
208         // Overwrite the previous configuration if it already existed.
209         dataInfo->Set(aLinkMetrics, aShortAddress, *aExtAddress);
210     }
211 
212 exit:
213     return error;
214 }
215 
GetLinkMetricsInfoByMacAddress(const otMacAddress * aMacAddress)216 LinkMetricsDataInfo *GetLinkMetricsInfoByMacAddress(const otMacAddress *aMacAddress)
217 {
218     LinkMetricsDataInfo *dataInfo = nullptr;
219 
220     VerifyOrExit(aMacAddress != nullptr);
221 
222     if (aMacAddress->mType == OT_MAC_ADDRESS_TYPE_SHORT)
223     {
224         dataInfo = GetLinkMetricsDataInfoActiveList().FindMatching(aMacAddress->mAddress.mShortAddress);
225     }
226     else if (aMacAddress->mType == OT_MAC_ADDRESS_TYPE_EXTENDED)
227     {
228         dataInfo = GetLinkMetricsDataInfoActiveList().FindMatching(aMacAddress->mAddress.mExtAddress);
229     }
230 
231 exit:
232     return dataInfo;
233 }
234 
otLinkMetricsEnhAckGenData(const otMacAddress * aMacAddress,uint8_t aLqi,int8_t aRssi,uint8_t * aData)235 uint8_t otLinkMetricsEnhAckGenData(const otMacAddress *aMacAddress, uint8_t aLqi, int8_t aRssi, uint8_t *aData)
236 {
237     uint8_t              bytes    = 0;
238     LinkMetricsDataInfo *dataInfo = GetLinkMetricsInfoByMacAddress(aMacAddress);
239 
240     VerifyOrExit(dataInfo != nullptr);
241 
242     bytes = dataInfo->GetEnhAckData(aLqi, aRssi, aData);
243 
244 exit:
245     return bytes;
246 }
247 
otLinkMetricsEnhAckGetDataLen(const otMacAddress * aMacAddress)248 uint8_t otLinkMetricsEnhAckGetDataLen(const otMacAddress *aMacAddress)
249 {
250     uint8_t              len      = 0;
251     LinkMetricsDataInfo *dataInfo = GetLinkMetricsInfoByMacAddress(aMacAddress);
252 
253     VerifyOrExit(dataInfo != nullptr);
254     len = dataInfo->GetEnhAckDataLen();
255 
256 exit:
257     return len;
258 }
259 
otLinkMetricsResetEnhAckProbing(void)260 void otLinkMetricsResetEnhAckProbing(void)
261 {
262     GetLinkMetricsDataInfoActiveList().Clear();
263     GetLinkMetricsDataInfoPool().FreeAll();
264 }
265 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
266