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/as_core_type.hpp" 45 #include "common/clearable.hpp" 46 #include "common/locator.hpp" 47 #include "common/non_copyable.hpp" 48 #include "common/notifier.hpp" 49 #include "common/timer.hpp" 50 #include "net/netif.hpp" 51 #include "net/socket.hpp" 52 #include "thread/mesh_forwarder.hpp" 53 #include "thread/mle.hpp" 54 #include "thread/mle_types.hpp" 55 #include "thread/neighbor_table.hpp" 56 #include "thread/network_data.hpp" 57 58 namespace ot { 59 namespace Utils { 60 61 #ifdef OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA 62 #error "OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA should not be defined directly." \ 63 "It is derived from other configs: on-mesh prefix and external route history list sizes" 64 #endif 65 66 #define OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA \ 67 ((OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE > 0) || \ 68 (OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE > 0)) 69 70 /** 71 * This class implements History Tracker. 72 * 73 */ 74 class HistoryTracker : public InstanceLocator, private NonCopyable 75 { 76 friend class ot::MeshForwarder; 77 friend class ot::Notifier; 78 friend class ot::Mle::Mle; 79 friend class ot::NeighborTable; 80 friend class ot::Ip6::Netif; 81 82 public: 83 /** 84 * This constant specifies the maximum age of entries which is 49 days (value in msec). 85 * 86 * Entries older than the max age will give this value as their age. 87 * 88 */ 89 static constexpr uint32_t kMaxAge = OT_HISTORY_TRACKER_MAX_AGE; 90 91 /** 92 * This constant specifies the recommend string size to represent an entry age 93 * 94 */ 95 static constexpr uint16_t kEntryAgeStringSize = OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE; 96 97 /** 98 * This type represents an iterator to iterate through a history list. 99 * 100 */ 101 class Iterator : public otHistoryTrackerIterator 102 { 103 friend class HistoryTracker; 104 105 public: 106 /** 107 * This method initializes an `Iterator` 108 * 109 * An iterator MUST be initialized before it is used. An iterator can be initialized again to start from 110 * the beginning of the list. 111 * 112 */ Init(void)113 void Init(void) { ResetEntryNumber(), SetInitTime(); } 114 115 private: GetEntryNumber(void) const116 uint16_t GetEntryNumber(void) const { return mData16; } ResetEntryNumber(void)117 void ResetEntryNumber(void) { mData16 = 0; } IncrementEntryNumber(void)118 void IncrementEntryNumber(void) { mData16++; } GetInitTime(void) const119 TimeMilli GetInitTime(void) const { return TimeMilli(mData32); } SetInitTime(void)120 void SetInitTime(void) { mData32 = TimerMilli::GetNow().GetValue(); } 121 }; 122 123 typedef otHistoryTrackerNetworkInfo NetworkInfo; ///< Thread network info. 124 typedef otHistoryTrackerUnicastAddressInfo UnicastAddressInfo; ///< Unicast IPv6 address info. 125 typedef otHistoryTrackerMulticastAddressInfo MulticastAddressInfo; ///< Multicast IPv6 address info. 126 typedef otHistoryTrackerMessageInfo MessageInfo; ///< RX/TX IPv6 message info. 127 typedef otHistoryTrackerNeighborInfo NeighborInfo; ///< Neighbor info. 128 typedef otHistoryTrackerOnMeshPrefixInfo OnMeshPrefixInfo; ///< Network Data on mesh prefix info. 129 typedef otHistoryTrackerExternalRouteInfo ExternalRouteInfo; ///< Network Data external route info 130 131 /** 132 * This constructor initializes the `HistoryTracker`. 133 * 134 * @param[in] aInstance A reference to the OpenThread instance. 135 * 136 */ 137 explicit HistoryTracker(Instance &aInstance); 138 139 /** 140 * This method iterates over the entries in the network info history list. 141 * 142 * @param[in,out] aIterator An iterator. MUST be initialized. 143 * @param[out] aEntryAge A reference to a variable to output the entry's age. 144 * Age is provided as the duration (in milliseconds) from when entry was recorded to 145 * @p aIterator initialization time. It is set to `kMaxAge` for entries older than max 146 * age. 147 * 148 * @returns A pointer to `NetworkInfo` entry or `nullptr` if no more entries in the list. 149 * 150 */ IterateNetInfoHistory(Iterator & aIterator,uint32_t & aEntryAge) const151 const NetworkInfo *IterateNetInfoHistory(Iterator &aIterator, uint32_t &aEntryAge) const 152 { 153 return mNetInfoHistory.Iterate(aIterator, aEntryAge); 154 } 155 156 /** 157 * This method iterates over the entries in the unicast address history list. 158 * 159 * @param[in,out] aIterator An iterator. MUST be initialized. 160 * @param[out] aEntryAge A reference to a variable to output the entry's age. 161 * Age is provided as the duration (in milliseconds) from when entry was recorded to 162 * @p aIterator initialization time. It is set to `kMaxAge` for entries older than max 163 * age. 164 * 165 * @returns A pointer to `UnicastAddress` entry or `nullptr` if no more entries in the list. 166 * 167 */ IterateUnicastAddressHistory(Iterator & aIterator,uint32_t & aEntryAge) const168 const UnicastAddressInfo *IterateUnicastAddressHistory(Iterator &aIterator, uint32_t &aEntryAge) const 169 { 170 return mUnicastAddressHistory.Iterate(aIterator, aEntryAge); 171 } 172 173 /** 174 * This method iterates over the entries in the multicast address history list. 175 * 176 * @param[in,out] aIterator An iterator. MUST be initialized. 177 * @param[out] aEntryAge A reference to a variable to output the entry's age. 178 * Age is provided as the duration (in milliseconds) from when entry was recorded to 179 * @p aIterator initialization time. It is set to `kMaxAge` for entries older than max 180 * age. 181 * 182 * @returns A pointer to `MulticastAddress` entry or `nullptr` if no more entries in the list. 183 * 184 */ IterateMulticastAddressHistory(Iterator & aIterator,uint32_t & aEntryAge) const185 const MulticastAddressInfo *IterateMulticastAddressHistory(Iterator &aIterator, uint32_t &aEntryAge) const 186 { 187 return mMulticastAddressHistory.Iterate(aIterator, aEntryAge); 188 } 189 190 /** 191 * This method iterates over the entries in the RX history list. 192 * 193 * @param[in,out] aIterator An iterator. MUST be initialized. 194 * @param[out] aEntryAge A reference to a variable to output the entry's age. 195 * Age is provided as the duration (in milliseconds) from when entry was recorded to 196 * @p aIterator initialization time. It is set to `kMaxAge` for entries older than max 197 * age. 198 * 199 * @returns A pointer to `MessageInfo` entry or `nullptr` if no more entries in the list. 200 * 201 */ IterateRxHistory(Iterator & aIterator,uint32_t & aEntryAge) const202 const MessageInfo *IterateRxHistory(Iterator &aIterator, uint32_t &aEntryAge) const 203 { 204 return mRxHistory.Iterate(aIterator, aEntryAge); 205 } 206 207 /** 208 * This method iterates over the entries in the TX history list. 209 * 210 * @param[in,out] aIterator An iterator. MUST be initialized. 211 * @param[out] aEntryAge A reference to a variable to output the entry's age. 212 * Age is provided as the duration (in milliseconds) from when entry was recorded to 213 * @p aIterator initialization time. It is set to `kMaxAge` for entries older than max 214 * age. 215 * 216 * @returns A pointer to `MessageInfo` entry or `nullptr` if no more entries in the list. 217 * 218 */ IterateTxHistory(Iterator & aIterator,uint32_t & aEntryAge) const219 const MessageInfo *IterateTxHistory(Iterator &aIterator, uint32_t &aEntryAge) const 220 { 221 return mTxHistory.Iterate(aIterator, aEntryAge); 222 } 223 IterateNeighborHistory(Iterator & aIterator,uint32_t & aEntryAge) const224 const NeighborInfo *IterateNeighborHistory(Iterator &aIterator, uint32_t &aEntryAge) const 225 { 226 return mNeighborHistory.Iterate(aIterator, aEntryAge); 227 } 228 IterateOnMeshPrefixHistory(Iterator & aIterator,uint32_t & aEntryAge) const229 const OnMeshPrefixInfo *IterateOnMeshPrefixHistory(Iterator &aIterator, uint32_t &aEntryAge) const 230 { 231 return mOnMeshPrefixHistory.Iterate(aIterator, aEntryAge); 232 } 233 IterateExternalRouteHistory(Iterator & aIterator,uint32_t & aEntryAge) const234 const ExternalRouteInfo *IterateExternalRouteHistory(Iterator &aIterator, uint32_t &aEntryAge) const 235 { 236 return mExternalRouteHistory.Iterate(aIterator, aEntryAge); 237 } 238 239 /** 240 * This static method converts a given entry age to a human-readable string. 241 * 242 * The entry age string follows the format "<hh>:<mm>:<ss>.<mmmm>" for hours, minutes, seconds and millisecond 243 * (if shorter than one day) or "<dd> days <hh>:<mm>:<ss>.<mmmm>" (if longer than one day). 244 * 245 * If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be 246 * truncated but the outputted string is always null-terminated. 247 * 248 * @param[in] aEntryAge The entry age (duration in msec). 249 * @param[out] aBuffer A pointer to a char array to output the string (MUST NOT be NULL). 250 * @param[in] aSize The size of @p aBuffer (in bytes). Recommended to use `OT_IP6_ADDRESS_STRING_SIZE`. 251 * 252 */ 253 static void EntryAgeToString(uint32_t aEntryAge, char *aBuffer, uint16_t aSize); 254 255 private: 256 // `Timestamp` uses `uint32_t` value. `2^32` msec is 49 days, 17 257 // hours, 2 minutes and 47 seconds and 296 msec. We use 49 days 258 // as `kMaxAge` and check for aged entries every 16 hours. 259 260 static constexpr uint32_t kAgeCheckPeriod = 16 * Time::kOneHourInMsec; 261 262 static constexpr uint16_t kNetInfoListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_INFO_LIST_SIZE; 263 static constexpr uint16_t kUnicastAddrListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_UNICAST_ADDRESS_LIST_SIZE; 264 static constexpr uint16_t kMulticastAddrListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_MULTICAST_ADDRESS_LIST_SIZE; 265 static constexpr uint16_t kRxListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_RX_LIST_SIZE; 266 static constexpr uint16_t kTxListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_TX_LIST_SIZE; 267 static constexpr uint16_t kNeighborListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_NEIGHBOR_LIST_SIZE; 268 static constexpr uint16_t kOnMeshPrefixListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE; 269 static constexpr uint16_t kExternalRouteListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE; 270 271 typedef otHistoryTrackerAddressEvent AddressEvent; 272 273 static constexpr AddressEvent kAddressAdded = OT_HISTORY_TRACKER_ADDRESS_EVENT_ADDED; 274 static constexpr AddressEvent kAddressRemoved = OT_HISTORY_TRACKER_ADDRESS_EVENT_REMOVED; 275 276 static constexpr int8_t kInvalidRss = OT_RADIO_RSSI_INVALID; 277 static constexpr uint16_t kInvalidRloc16 = Mac::kShortAddrInvalid; 278 279 typedef otHistoryTrackerNeighborEvent NeighborEvent; 280 281 static constexpr NeighborEvent kNeighborAdded = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_ADDED; 282 static constexpr NeighborEvent kNeighborRemoved = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_REMOVED; 283 static constexpr NeighborEvent kNeighborChanged = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_CHANGED; 284 static constexpr NeighborEvent kNeighborRestoring = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING; 285 286 typedef otHistoryTrackerNetDataEvent NetDataEvent; 287 288 static constexpr NetDataEvent kNetDataEntryAdded = OT_HISTORY_TRACKER_NET_DATA_ENTRY_ADDED; 289 static constexpr NetDataEvent kNetDataEntryRemoved = OT_HISTORY_TRACKER_NET_DATA_ENTRY_REMOVED; 290 291 class Timestamp 292 { 293 public: 294 void SetToNow(void); 295 uint32_t GetDurationTill(TimeMilli aTime) const; IsDistantPast(void) const296 bool IsDistantPast(void) const { return (mTime.GetValue() == kDistantPast); } MarkAsDistantPast(void)297 void MarkAsDistantPast(void) { return mTime.SetValue(kDistantPast); } 298 299 private: 300 static constexpr uint32_t kDistantPast = 0; 301 302 TimeMilli mTime; 303 }; 304 305 // An ordered list of timestamped items (base class of `EntryList<Entry, kSize>`). 306 class List : private NonCopyable 307 { 308 public: 309 void Clear(void); GetSize(void) const310 uint16_t GetSize(void) const { return mSize; } 311 312 protected: 313 List(void); 314 uint16_t Add(uint16_t aMaxSize, Timestamp aTimestamps[]); 315 void UpdateAgedEntries(uint16_t aMaxSize, Timestamp aTimestamps[]); 316 uint16_t MapEntryNumberToListIndex(uint16_t aEntryNumber, uint16_t aMaxSize) const; 317 Error Iterate(uint16_t aMaxSize, 318 const Timestamp aTimestamps[], 319 Iterator & aIterator, 320 uint16_t & aListIndex, 321 uint32_t & aEntryAge) const; 322 323 private: 324 uint16_t mStartIndex; 325 uint16_t mSize; 326 }; 327 328 // A history list (with given max size) of timestamped `Entry` items. 329 template <typename Entry, uint16_t kMaxSize> class EntryList : public List 330 { 331 public: 332 // Adds a new entry to the list or overwrites the oldest entry 333 // if list is full. First version returns a pointer to the 334 // new `Entry` (for caller to populate). Second version copies 335 // the given `aEntry`. AddNewEntry(void)336 Entry *AddNewEntry(void) { return &mEntries[Add(kMaxSize, mTimestamps)]; } AddNewEntry(const Entry & aEntry)337 void AddNewEntry(const Entry &aEntry) { mEntries[Add(kMaxSize, mTimestamps)] = aEntry; } 338 UpdateAgedEntries(void)339 void UpdateAgedEntries(void) { List::UpdateAgedEntries(kMaxSize, mTimestamps); } 340 Iterate(Iterator & aIterator,uint32_t & aEntryAge) const341 const Entry *Iterate(Iterator &aIterator, uint32_t &aEntryAge) const 342 { 343 uint16_t index; 344 345 return (List::Iterate(kMaxSize, mTimestamps, aIterator, index, aEntryAge) == kErrorNone) ? &mEntries[index] 346 : nullptr; 347 } 348 349 private: 350 Timestamp mTimestamps[kMaxSize]; 351 Entry mEntries[kMaxSize]; 352 }; 353 354 // Partial specialization for `kMaxSize` zero. 355 template <typename Entry> class EntryList<Entry, 0> : private NonCopyable 356 { 357 public: Clear(void)358 void Clear(void) {} GetSize(void) const359 uint16_t GetSize(void) const { return 0; } AddNewEntry(void)360 Entry * AddNewEntry(void) { return nullptr; } AddNewEntry(const Entry &)361 void AddNewEntry(const Entry &) {} Iterate(Iterator &,uint32_t &) const362 const Entry *Iterate(Iterator &, uint32_t &) const { return nullptr; } RemoveAgedEntries(void)363 void RemoveAgedEntries(void) {} 364 }; 365 366 enum MessageType : uint8_t 367 { 368 kRxMessage, 369 kTxMessage, 370 }; 371 RecordRxMessage(const Message & aMessage,const Mac::Address & aMacSource)372 void RecordRxMessage(const Message &aMessage, const Mac::Address &aMacSource) 373 { 374 RecordMessage(aMessage, aMacSource, kRxMessage); 375 } 376 RecordTxMessage(const Message & aMessage,const Mac::Address & aMacDest)377 void RecordTxMessage(const Message &aMessage, const Mac::Address &aMacDest) 378 { 379 RecordMessage(aMessage, aMacDest, kTxMessage); 380 } 381 382 void RecordNetworkInfo(void); 383 void RecordMessage(const Message &aMessage, const Mac::Address &aMacAddress, MessageType aType); 384 void RecordNeighborEvent(NeighborTable::Event aEvent, const NeighborTable::EntryInfo &aInfo); 385 void RecordAddressEvent(Ip6::Netif::AddressEvent aEvent, const Ip6::Netif::UnicastAddress &aUnicastAddress); 386 void RecordAddressEvent(Ip6::Netif::AddressEvent aEvent, 387 const Ip6::Netif::MulticastAddress &aMulticastAddress, 388 Ip6::Netif::AddressOrigin aAddressOrigin); 389 void HandleNotifierEvents(Events aEvents); 390 static void HandleTimer(Timer &aTimer); 391 void HandleTimer(void); 392 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA 393 void RecordNetworkDataChange(void); 394 void RecordOnMeshPrefixEvent(NetDataEvent aEvent, const NetworkData::OnMeshPrefixConfig &aPrefix); 395 void RecordExternalRouteEvent(NetDataEvent aEvent, const NetworkData::ExternalRouteConfig &aRoute); 396 #endif 397 398 EntryList<NetworkInfo, kNetInfoListSize> mNetInfoHistory; 399 EntryList<UnicastAddressInfo, kUnicastAddrListSize> mUnicastAddressHistory; 400 EntryList<MulticastAddressInfo, kMulticastAddrListSize> mMulticastAddressHistory; 401 EntryList<MessageInfo, kRxListSize> mRxHistory; 402 EntryList<MessageInfo, kTxListSize> mTxHistory; 403 EntryList<NeighborInfo, kNeighborListSize> mNeighborHistory; 404 EntryList<OnMeshPrefixInfo, kOnMeshPrefixListSize> mOnMeshPrefixHistory; 405 EntryList<ExternalRouteInfo, kExternalRouteListSize> mExternalRouteHistory; 406 407 TimerMilli mTimer; 408 409 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA 410 NetworkData::MutableNetworkData mPreviousNetworkData; 411 412 uint8_t mNetworkDataTlvBuffer[NetworkData::NetworkData::kMaxSize]; 413 #endif 414 }; 415 416 } // namespace Utils 417 418 DefineCoreType(otHistoryTrackerIterator, Utils::HistoryTracker::Iterator); 419 DefineCoreType(otHistoryTrackerNetworkInfo, Utils::HistoryTracker::NetworkInfo); 420 DefineCoreType(otHistoryTrackerMessageInfo, Utils::HistoryTracker::MessageInfo); 421 DefineCoreType(otHistoryTrackerNeighborInfo, Utils::HistoryTracker::NeighborInfo); 422 DefineCoreType(otHistoryTrackerOnMeshPrefixInfo, Utils::HistoryTracker::OnMeshPrefixInfo); 423 DefineCoreType(otHistoryTrackerExternalRouteInfo, Utils::HistoryTracker::ExternalRouteInfo); 424 425 } // namespace ot 426 427 #endif // OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE 428 429 #endif // HISTORY_TRACKER_HPP_ 430