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