1 /*
2  *  Copyright (c) 2016-2017, 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 for a Thread `Neighbor`.
32  */
33 
34 #include "neighbor.hpp"
35 
36 #include "common/array.hpp"
37 #include "common/code_utils.hpp"
38 #include "common/debug.hpp"
39 #include "common/locator_getters.hpp"
40 #include "common/num_utils.hpp"
41 #include "instance/instance.hpp"
42 
43 namespace ot {
44 
SetState(State aState)45 void Neighbor::SetState(State aState)
46 {
47     VerifyOrExit(mState != aState);
48     mState = static_cast<uint8_t>(aState);
49 
50 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
51     if (mState == kStateValid)
52     {
53         mConnectionStart = Uptime::MsecToSec(Get<Uptime>().GetUptime());
54     }
55 #endif
56 
57 exit:
58     return;
59 }
60 
61 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
GetConnectionTime(void) const62 uint32_t Neighbor::GetConnectionTime(void) const
63 {
64     return IsStateValid() ? Uptime::MsecToSec(Get<Uptime>().GetUptime()) - mConnectionStart : 0;
65 }
66 #endif
67 
Matches(const Neighbor & aNeighbor) const68 bool Neighbor::AddressMatcher::Matches(const Neighbor &aNeighbor) const
69 {
70     bool matches = false;
71 
72     VerifyOrExit(aNeighbor.MatchesFilter(mStateFilter));
73 
74     if (mShortAddress != Mac::kShortAddrInvalid)
75     {
76         VerifyOrExit(mShortAddress == aNeighbor.GetRloc16());
77     }
78 
79     if (mExtAddress != nullptr)
80     {
81         VerifyOrExit(*mExtAddress == aNeighbor.GetExtAddress());
82     }
83 
84     matches = true;
85 
86 exit:
87     return matches;
88 }
89 
SetFrom(const Neighbor & aNeighbor)90 void Neighbor::Info::SetFrom(const Neighbor &aNeighbor)
91 {
92     Clear();
93 
94     mExtAddress       = aNeighbor.GetExtAddress();
95     mAge              = Time::MsecToSec(TimerMilli::GetNow() - aNeighbor.GetLastHeard());
96     mRloc16           = aNeighbor.GetRloc16();
97     mLinkFrameCounter = aNeighbor.GetLinkFrameCounters().GetMaximum();
98     mMleFrameCounter  = aNeighbor.GetMleFrameCounter();
99     mLinkQualityIn    = aNeighbor.GetLinkQualityIn();
100     mAverageRssi      = aNeighbor.GetLinkInfo().GetAverageRss();
101     mLastRssi         = aNeighbor.GetLinkInfo().GetLastRss();
102     mLinkMargin       = aNeighbor.GetLinkInfo().GetLinkMargin();
103     mFrameErrorRate   = aNeighbor.GetLinkInfo().GetFrameErrorRate();
104     mMessageErrorRate = aNeighbor.GetLinkInfo().GetMessageErrorRate();
105     mRxOnWhenIdle     = aNeighbor.IsRxOnWhenIdle();
106     mFullThreadDevice = aNeighbor.IsFullThreadDevice();
107     mFullNetworkData  = (aNeighbor.GetNetworkDataType() == NetworkData::kFullSet);
108     mVersion          = aNeighbor.GetVersion();
109 #if OPENTHREAD_CONFIG_UPTIME_ENABLE
110     mConnectionTime = aNeighbor.GetConnectionTime();
111 #endif
112 }
113 
Init(Instance & aInstance)114 void Neighbor::Init(Instance &aInstance)
115 {
116     InstanceLocatorInit::Init(aInstance);
117     mLinkInfo.Init(aInstance);
118     SetState(kStateInvalid);
119 }
120 
IsStateValidOrAttaching(void) const121 bool Neighbor::IsStateValidOrAttaching(void) const
122 {
123     bool rval = false;
124 
125     switch (GetState())
126     {
127     case kStateInvalid:
128     case kStateParentRequest:
129     case kStateParentResponse:
130         break;
131 
132     case kStateRestored:
133     case kStateChildIdRequest:
134     case kStateLinkRequest:
135     case kStateChildUpdateRequest:
136     case kStateValid:
137         rval = true;
138         break;
139     }
140 
141     return rval;
142 }
143 
MatchesFilter(StateFilter aFilter) const144 bool Neighbor::MatchesFilter(StateFilter aFilter) const
145 {
146     bool matches = false;
147 
148     switch (aFilter)
149     {
150     case kInStateValid:
151         matches = IsStateValid();
152         break;
153 
154     case kInStateValidOrRestoring:
155         matches = IsStateValidOrRestoring();
156         break;
157 
158     case kInStateChildIdRequest:
159         matches = IsStateChildIdRequest();
160         break;
161 
162     case kInStateValidOrAttaching:
163         matches = IsStateValidOrAttaching();
164         break;
165 
166     case kInStateInvalid:
167         matches = IsStateInvalid();
168         break;
169 
170     case kInStateAnyExceptInvalid:
171         matches = !IsStateInvalid();
172         break;
173 
174     case kInStateAnyExceptValidOrRestoring:
175         matches = !IsStateValidOrRestoring();
176         break;
177 
178     case kInStateAny:
179         matches = true;
180         break;
181     }
182 
183     return matches;
184 }
185 
186 #if OPENTHREAD_CONFIG_MULTI_RADIO
SetLastRxFragmentTag(uint16_t aTag)187 void Neighbor::SetLastRxFragmentTag(uint16_t aTag)
188 {
189     mLastRxFragmentTag     = (aTag == 0) ? 0xffff : aTag;
190     mLastRxFragmentTagTime = TimerMilli::GetNow();
191 }
192 
IsLastRxFragmentTagSet(void) const193 bool Neighbor::IsLastRxFragmentTagSet(void) const
194 {
195     return (mLastRxFragmentTag != 0) && (TimerMilli::GetNow() <= mLastRxFragmentTagTime + kLastRxFragmentTagTimeout);
196 }
197 #endif
198 
199 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
AggregateLinkMetrics(uint8_t aSeriesId,uint8_t aFrameType,uint8_t aLqi,int8_t aRss)200 void Neighbor::AggregateLinkMetrics(uint8_t aSeriesId, uint8_t aFrameType, uint8_t aLqi, int8_t aRss)
201 {
202     for (LinkMetrics::SeriesInfo &entry : mLinkMetricsSeriesInfoList)
203     {
204         if (aSeriesId == 0 || aSeriesId == entry.GetSeriesId())
205         {
206             entry.AggregateLinkMetrics(aFrameType, aLqi, aRss);
207         }
208     }
209 }
210 
GetForwardTrackingSeriesInfo(const uint8_t & aSeriesId)211 LinkMetrics::SeriesInfo *Neighbor::GetForwardTrackingSeriesInfo(const uint8_t &aSeriesId)
212 {
213     return mLinkMetricsSeriesInfoList.FindMatching(aSeriesId);
214 }
215 
AddForwardTrackingSeriesInfo(LinkMetrics::SeriesInfo & aSeriesInfo)216 void Neighbor::AddForwardTrackingSeriesInfo(LinkMetrics::SeriesInfo &aSeriesInfo)
217 {
218     mLinkMetricsSeriesInfoList.Push(aSeriesInfo);
219 }
220 
RemoveForwardTrackingSeriesInfo(const uint8_t & aSeriesId)221 LinkMetrics::SeriesInfo *Neighbor::RemoveForwardTrackingSeriesInfo(const uint8_t &aSeriesId)
222 {
223     return mLinkMetricsSeriesInfoList.RemoveMatching(aSeriesId);
224 }
225 
RemoveAllForwardTrackingSeriesInfo(void)226 void Neighbor::RemoveAllForwardTrackingSeriesInfo(void)
227 {
228     while (!mLinkMetricsSeriesInfoList.IsEmpty())
229     {
230         LinkMetrics::SeriesInfo *seriesInfo = mLinkMetricsSeriesInfoList.Pop();
231         Get<LinkMetrics::Subject>().Free(*seriesInfo);
232     }
233 }
234 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
235 
StateToString(State aState)236 const char *Neighbor::StateToString(State aState)
237 {
238     static const char *const kStateStrings[] = {
239         "Invalid",        // (0) kStateInvalid
240         "Restored",       // (1) kStateRestored
241         "ParentReq",      // (2) kStateParentRequest
242         "ParentRes",      // (3) kStateParentResponse
243         "ChildIdReq",     // (4) kStateChildIdRequest
244         "LinkReq",        // (5) kStateLinkRequest
245         "ChildUpdateReq", // (6) kStateChildUpdateRequest
246         "Valid",          // (7) kStateValid
247     };
248 
249     static_assert(0 == kStateInvalid, "kStateInvalid value is incorrect");
250     static_assert(1 == kStateRestored, "kStateRestored value is incorrect");
251     static_assert(2 == kStateParentRequest, "kStateParentRequest value is incorrect");
252     static_assert(3 == kStateParentResponse, "kStateParentResponse value is incorrect");
253     static_assert(4 == kStateChildIdRequest, "kStateChildIdRequest value is incorrect");
254     static_assert(5 == kStateLinkRequest, "kStateLinkRequest value is incorrect");
255     static_assert(6 == kStateChildUpdateRequest, "kStateChildUpdateRequest value is incorrect");
256     static_assert(7 == kStateValid, "kStateValid value is incorrect");
257 
258     return kStateStrings[aState];
259 }
260 
261 } // namespace ot
262