1 /* 2 * Copyright (c) 2021, 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 /** 30 * @file 31 * This file includes definitions to support History Tracker module. 32 */ 33 34 #ifndef HISTORY_TRACKER_HPP_ 35 #define HISTORY_TRACKER_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE 40 41 #include <openthread/history_tracker.h> 42 #include <openthread/platform/radio.h> 43 44 #include "common/clearable.hpp" 45 #include "common/locator.hpp" 46 #include "common/non_copyable.hpp" 47 #include "common/notifier.hpp" 48 #include "common/timer.hpp" 49 #include "net/socket.hpp" 50 #include "thread/mesh_forwarder.hpp" 51 #include "thread/mle.hpp" 52 #include "thread/mle_types.hpp" 53 #include "thread/neighbor_table.hpp" 54 55 namespace ot { 56 namespace Utils { 57 58 /** 59 * This class implements History Tracker. 60 * 61 */ 62 class HistoryTracker : public InstanceLocator, private NonCopyable 63 { 64 friend class ot::MeshForwarder; 65 friend class ot::Notifier; 66 friend class ot::Mle::Mle; 67 friend class ot::NeighborTable; 68 69 public: 70 /** 71 * This constant specifies the maximum age of entries which is 49 days (value in msec). 72 * 73 * Entries older than the max age will give this value as their age. 74 * 75 */ 76 static constexpr uint32_t kMaxAge = OT_HISTORY_TRACKER_MAX_AGE; 77 78 /** 79 * This constant specifies the recommend string size to represent an entry age 80 * 81 */ 82 static constexpr uint16_t kEntryAgeStringSize = OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE; 83 84 /** 85 * This type represents an iterator to iterate through a history list. 86 * 87 */ 88 class Iterator : public otHistoryTrackerIterator 89 { 90 friend class HistoryTracker; 91 92 public: 93 /** 94 * This method initializes an `Iterator` 95 * 96 * An iterator MUST be initialized before it is used. An iterator can be initialized again to start from 97 * the beginning of the list. 98 * 99 */ Init(void)100 void Init(void) { ResetEntryNumber(), SetInitTime(); } 101 102 private: GetEntryNumber(void) const103 uint16_t GetEntryNumber(void) const { return mData16; } ResetEntryNumber(void)104 void ResetEntryNumber(void) { mData16 = 0; } IncrementEntryNumber(void)105 void IncrementEntryNumber(void) { mData16++; } GetInitTime(void) const106 TimeMilli GetInitTime(void) const { return TimeMilli(mData32); } SetInitTime(void)107 void SetInitTime(void) { mData32 = TimerMilli::GetNow().GetValue(); } 108 }; 109 110 /** 111 * This type represents Thread network info. 112 * 113 */ 114 typedef otHistoryTrackerNetworkInfo NetworkInfo; 115 116 /** 117 * This type represents a RX/TX IPv6 message info. 118 * 119 */ 120 typedef otHistoryTrackerMessageInfo MessageInfo; 121 122 /** 123 * This type represents a neighbor info. 124 * 125 */ 126 typedef otHistoryTrackerNeighborInfo NeighborInfo; 127 128 /** 129 * This constructor initializes the `HistoryTracker`. 130 * 131 * @param[in] aInstance A reference to the OpenThread instance. 132 * 133 */ 134 explicit HistoryTracker(Instance &aInstance); 135 136 /** 137 * This method iterates over the entries in the network info history list. 138 * 139 * @param[inout] aIterator An iterator. MUST be initialized. 140 * @param[out] aEntryAge A reference to a variable to output the entry's age. 141 * Age is provided as the duration (in milliseconds) from when entry was recorded to 142 * @p aIterator initialization time. It is set to `kMaxAge` for entries older than max age. 143 * 144 * @returns A pointer to `NetworkInfo` entry or `nullptr` if no more entries in the list. 145 * 146 */ IterateNetInfoHistory(Iterator & aIterator,uint32_t & aEntryAge) const147 const NetworkInfo *IterateNetInfoHistory(Iterator &aIterator, uint32_t &aEntryAge) const 148 { 149 return mNetInfoHistory.Iterate(aIterator, aEntryAge); 150 } 151 152 /** 153 * This method iterates over the entries in the RX history list. 154 * 155 * @param[inout] aIterator An iterator. MUST be initialized. 156 * @param[out] aEntryAge A reference to a variable to output the entry's age. 157 * Age is provided as the duration (in milliseconds) from when entry was recorded to 158 * @p aIterator initialization time. It is set to `kMaxAge` for entries older than max age. 159 * 160 * @returns A pointer to `MessageInfo` entry or `nullptr` if no more entries in the list. 161 * 162 */ IterateRxHistory(Iterator & aIterator,uint32_t & aEntryAge) const163 const MessageInfo *IterateRxHistory(Iterator &aIterator, uint32_t &aEntryAge) const 164 { 165 return mRxHistory.Iterate(aIterator, aEntryAge); 166 } 167 168 /** 169 * This method iterates over the entries in the TX history list. 170 * 171 * @param[inout] aIterator An iterator. MUST be initialized. 172 * @param[out] aEntryAge A reference to a variable to output the entry's age. 173 * Age is provided as the duration (in milliseconds) from when entry was recorded to 174 * @p aIterator initialization time. It is set to `kMaxAge` for entries older than max age. 175 * 176 * @returns A pointer to `MessageInfo` entry or `nullptr` if no more entries in the list. 177 * 178 */ IterateTxHistory(Iterator & aIterator,uint32_t & aEntryAge) const179 const MessageInfo *IterateTxHistory(Iterator &aIterator, uint32_t &aEntryAge) const 180 { 181 return mTxHistory.Iterate(aIterator, aEntryAge); 182 } 183 IterateNeighborHistory(Iterator & aIterator,uint32_t & aEntryAge) const184 const NeighborInfo *IterateNeighborHistory(Iterator &aIterator, uint32_t &aEntryAge) const 185 { 186 return mNeighborHistory.Iterate(aIterator, aEntryAge); 187 } 188 189 /** 190 * This static method converts a given entry age to a human-readable string. 191 * 192 * The entry age string follows the format "<hh>:<mm>:<ss>.<mmmm>" for hours, minutes, seconds and millisecond 193 * (if shorter than one day) or "<dd> days <hh>:<mm>:<ss>.<mmmm>" (if longer than one day). 194 * 195 * If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be 196 * truncated but the outputted string is always null-terminated. 197 * 198 * @param[in] aEntryAge The entry age (duration in msec). 199 * @param[out] aBuffer A pointer to a char array to output the string (MUST NOT be NULL). 200 * @param[in] aSize The size of @p aBuffer (in bytes). Recommended to use `OT_IP6_ADDRESS_STRING_SIZE`. 201 * 202 */ 203 static void EntryAgeToString(uint32_t aEntryAge, char *aBuffer, uint16_t aSize); 204 205 private: 206 static constexpr uint32_t kOneSecondInMsec = 1000; 207 static constexpr uint32_t kOneMinuteInMsec = 60 * kOneSecondInMsec; 208 static constexpr uint32_t kOneHourInMsec = 60 * kOneMinuteInMsec; 209 static constexpr uint32_t kOneDayInMsec = 24 * kOneHourInMsec; 210 211 // `Timestamp` uses `uint32_t` value. `2^32` msec is 49 days, 17 212 // hours, 2 minutes and 47 seconds and 296 msec. We use 49 days 213 // as `kMaxAge` and check for aged entries every 16 hours. 214 215 static constexpr uint32_t kAgeCheckPeriod = 16 * kOneHourInMsec; 216 217 static constexpr uint16_t kNetInfoListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_INFO_LIST_SIZE; 218 static constexpr uint16_t kRxListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_RX_LIST_SIZE; 219 static constexpr uint16_t kTxListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_TX_LIST_SIZE; 220 static constexpr uint16_t kNeighborListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_NEIGHBOR_LIST_SIZE; 221 222 static constexpr int8_t kInvalidRss = OT_RADIO_RSSI_INVALID; 223 static constexpr uint16_t kInvalidRloc16 = Mac::kShortAddrInvalid; 224 225 typedef otHistoryTrackerNeighborEvent NeighborEvent; 226 227 static constexpr NeighborEvent kNeighborAdded = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_ADDED; 228 static constexpr NeighborEvent kNeighborRemoved = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_REMOVED; 229 static constexpr NeighborEvent kNeighborChanged = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_CHANGED; 230 static constexpr NeighborEvent kNeighborRestoring = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING; 231 232 class Timestamp 233 { 234 public: 235 void SetToNow(void); 236 uint32_t GetDurationTill(TimeMilli aTime) const; IsDistantPast(void) const237 bool IsDistantPast(void) const { return (mTime.GetValue() == kDistantPast); } MarkAsDistantPast(void)238 void MarkAsDistantPast(void) { return mTime.SetValue(kDistantPast); } 239 240 private: 241 static constexpr uint32_t kDistantPast = 0; 242 243 TimeMilli mTime; 244 }; 245 246 // An ordered list of timestamped items (base class of `EntryList<Entry, kSize>`). 247 class List : private NonCopyable 248 { 249 public: 250 void Clear(void); GetSize(void) const251 uint16_t GetSize(void) const { return mSize; } 252 253 protected: 254 List(void); 255 uint16_t Add(uint16_t aMaxSize, Timestamp aTimestamps[]); 256 void UpdateAgedEntries(uint16_t aMaxSize, Timestamp aTimestamps[]); 257 uint16_t MapEntryNumberToListIndex(uint16_t aEntryNumber, uint16_t aMaxSize) const; 258 Error Iterate(uint16_t aMaxSize, 259 const Timestamp aTimestamps[], 260 Iterator & aIterator, 261 uint16_t & aListIndex, 262 uint32_t & aEntryAge) const; 263 264 private: 265 uint16_t mStartIndex; 266 uint16_t mSize; 267 }; 268 269 // A history list (with given max size) of timestamped `Entry` items. 270 template <typename Entry, uint16_t kMaxSize> class EntryList : public List 271 { 272 public: 273 // Adds a new entry to the list or overwrites the oldest entry 274 // if list is full. First version returns a pointer to the 275 // new `Entry` (for caller to populate). Second version copies 276 // the given `aEntry`. AddNewEntry(void)277 Entry *AddNewEntry(void) { return &mEntries[Add(kMaxSize, mTimestamps)]; } AddNewEntry(const Entry & aEntry)278 void AddNewEntry(const Entry &aEntry) { mEntries[Add(kMaxSize, mTimestamps)] = aEntry; } 279 UpdateAgedEntries(void)280 void UpdateAgedEntries(void) { List::UpdateAgedEntries(kMaxSize, mTimestamps); } 281 Iterate(Iterator & aIterator,uint32_t & aEntryAge) const282 const Entry *Iterate(Iterator &aIterator, uint32_t &aEntryAge) const 283 { 284 uint16_t index; 285 286 return (List::Iterate(kMaxSize, mTimestamps, aIterator, index, aEntryAge) == kErrorNone) ? &mEntries[index] 287 : nullptr; 288 } 289 290 private: 291 Timestamp mTimestamps[kMaxSize]; 292 Entry mEntries[kMaxSize]; 293 }; 294 295 // Partial specialization for `kMaxSize` zero. 296 template <typename Entry> class EntryList<Entry, 0> : private NonCopyable 297 { 298 public: Clear(void)299 void Clear(void) {} GetSize(void) const300 uint16_t GetSize(void) const { return 0; } AddNewEntry(void)301 Entry * AddNewEntry(void) { return nullptr; } AddNewEntry(const Entry &)302 void AddNewEntry(const Entry &) {} Iterate(Iterator &,uint32_t &) const303 const Entry *Iterate(Iterator &, uint32_t &) const { return nullptr; } RemoveAgedEntries(void)304 void RemoveAgedEntries(void) {} 305 }; 306 307 enum MessageType : uint8_t 308 { 309 kRxMessage, 310 kTxMessage, 311 }; 312 RecordRxMessage(const Message & aMessage,const Mac::Address & aMacSource)313 void RecordRxMessage(const Message &aMessage, const Mac::Address &aMacSource) 314 { 315 RecordMessage(aMessage, aMacSource, kRxMessage); 316 } 317 RecordTxMessage(const Message & aMessage,const Mac::Address & aMacDest)318 void RecordTxMessage(const Message &aMessage, const Mac::Address &aMacDest) 319 { 320 RecordMessage(aMessage, aMacDest, kTxMessage); 321 } 322 323 void RecordNetworkInfo(void); 324 void RecordMessage(const Message &aMessage, const Mac::Address &aMacAddress, MessageType aType); 325 void RecordNeighborEvent(NeighborTable::Event aEvent, const NeighborTable::EntryInfo &aInfo); 326 void HandleNotifierEvents(Events aEvents); 327 static void HandleTimer(Timer &aTimer); 328 void HandleTimer(void); 329 330 EntryList<NetworkInfo, kNetInfoListSize> mNetInfoHistory; 331 EntryList<MessageInfo, kRxListSize> mRxHistory; 332 EntryList<MessageInfo, kTxListSize> mTxHistory; 333 EntryList<NeighborInfo, kNeighborListSize> mNeighborHistory; 334 TimerMilli mTimer; 335 }; 336 337 } // namespace Utils 338 } // namespace ot 339 340 #endif // OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE 341 342 #endif // HISTORY_TRACKER_HPP_ 343