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 /**
30  * @file
31  *   This file implements transmissions of SVR_DATA.ntf messages to the Leader.
32  */
33 
34 #include "network_data_notifier.hpp"
35 
36 #if OPENTHREAD_FTD || OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
37 
38 #include "common/code_utils.hpp"
39 #include "common/instance.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/log.hpp"
42 #include "thread/network_data_leader.hpp"
43 #include "thread/network_data_local.hpp"
44 #include "thread/tmf.hpp"
45 #include "thread/uri_paths.hpp"
46 
47 namespace ot {
48 namespace NetworkData {
49 
50 RegisterLogModule("NetworkData");
51 
Notifier(Instance & aInstance)52 Notifier::Notifier(Instance &aInstance)
53     : InstanceLocator(aInstance)
54     , mTimer(aInstance)
55     , mSynchronizeDataTask(aInstance)
56     , mNextDelay(0)
57     , mOldRloc(Mac::kShortAddrInvalid)
58     , mWaitingForResponse(false)
59 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
60     , mDidRequestRouterRoleUpgrade(false)
61     , mRouterRoleUpgradeTimeout(0)
62 #endif
63 {
64 }
65 
HandleServerDataUpdated(void)66 void Notifier::HandleServerDataUpdated(void)
67 {
68 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
69     mDidRequestRouterRoleUpgrade = false;
70     ScheduleRouterRoleUpgradeIfEligible();
71 #endif
72 
73     mNextDelay = 0;
74     mSynchronizeDataTask.Post();
75 }
76 
SynchronizeServerData(void)77 void Notifier::SynchronizeServerData(void)
78 {
79     Error error = kErrorNotFound;
80 
81     VerifyOrExit(Get<Mle::MleRouter>().IsAttached() && !mWaitingForResponse);
82 
83     VerifyOrExit((mNextDelay == 0) || !mTimer.IsRunning());
84 
85 #if OPENTHREAD_FTD
86     mNextDelay = kDelayRemoveStaleChildren;
87     error      = RemoveStaleChildEntries();
88     VerifyOrExit(error == kErrorNotFound);
89 #endif
90 
91 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
92     mNextDelay = kDelaySynchronizeServerData;
93     error      = UpdateInconsistentData();
94     VerifyOrExit(error == kErrorNotFound);
95 #endif
96 
97 exit:
98     switch (error)
99     {
100     case kErrorNone:
101         mWaitingForResponse = true;
102         break;
103     case kErrorNoBufs:
104         mTimer.Start(kDelayNoBufs);
105         break;
106 #if OPENTHREAD_FTD
107     case kErrorInvalidState:
108         mTimer.Start(Time::SecToMsec(Get<Mle::MleRouter>().GetRouterSelectionJitterTimeout() + 1));
109         break;
110 #endif
111     case kErrorNotFound:
112         break;
113     default:
114         OT_ASSERT(false);
115     }
116 }
117 
118 #if OPENTHREAD_FTD
RemoveStaleChildEntries(void)119 Error Notifier::RemoveStaleChildEntries(void)
120 {
121     // Check if there is any stale child entry in network data and send
122     // a "Server Data" notification to leader to remove it.
123     //
124     // - `kErrorNone` when a stale child entry was found and successfully
125     //    sent a "Server Data" notification to leader.
126     // - `kErrorNoBufs` if could not allocate message to send message.
127     // - `kErrorNotFound` if no stale child entries were found.
128 
129     Error    error    = kErrorNotFound;
130     Iterator iterator = kIteratorInit;
131     uint16_t rloc16;
132 
133     VerifyOrExit(Get<Mle::MleRouter>().IsRouterOrLeader());
134 
135     while (Get<Leader>().GetNextServer(iterator, rloc16) == kErrorNone)
136     {
137         if (!Mle::IsActiveRouter(rloc16) && Mle::RouterIdMatch(Get<Mle::MleRouter>().GetRloc16(), rloc16) &&
138             Get<ChildTable>().FindChild(rloc16, Child::kInStateValid) == nullptr)
139         {
140             error = SendServerDataNotification(rloc16);
141             ExitNow();
142         }
143     }
144 
145 exit:
146     return error;
147 }
148 #endif // OPENTHREAD_FTD
149 
150 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
UpdateInconsistentData(void)151 Error Notifier::UpdateInconsistentData(void)
152 {
153     Error    error      = kErrorNone;
154     uint16_t deviceRloc = Get<Mle::MleRouter>().GetRloc16();
155 
156 #if OPENTHREAD_FTD
157     // Don't send this Server Data Notification if the device is going
158     // to upgrade to Router.
159 
160     if (Get<Mle::MleRouter>().IsExpectedToBecomeRouterSoon())
161     {
162         ExitNow(error = kErrorInvalidState);
163     }
164 #endif
165 
166     Get<Local>().UpdateRloc();
167 
168     if (Get<Leader>().ContainsEntriesFrom(Get<Local>(), deviceRloc) &&
169         Get<Local>().ContainsEntriesFrom(Get<Leader>(), deviceRloc))
170     {
171         ExitNow(error = kErrorNotFound);
172     }
173 
174     if (mOldRloc == deviceRloc)
175     {
176         mOldRloc = Mac::kShortAddrInvalid;
177     }
178 
179     SuccessOrExit(error = SendServerDataNotification(mOldRloc, &Get<Local>()));
180     mOldRloc = deviceRloc;
181 
182 exit:
183     return error;
184 }
185 #endif // #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
186 
SendServerDataNotification(uint16_t aOldRloc16,const NetworkData * aNetworkData)187 Error Notifier::SendServerDataNotification(uint16_t aOldRloc16, const NetworkData *aNetworkData)
188 {
189     Error            error = kErrorNone;
190     Coap::Message   *message;
191     Tmf::MessageInfo messageInfo(GetInstance());
192 
193     message = Get<Tmf::Agent>().NewPriorityConfirmablePostMessage(kUriServerData);
194     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
195 
196     if (aNetworkData != nullptr)
197     {
198         ThreadTlv tlv;
199 
200         tlv.SetType(ThreadTlv::kThreadNetworkData);
201         tlv.SetLength(aNetworkData->GetLength());
202         SuccessOrExit(error = message->Append(tlv));
203         SuccessOrExit(error = message->AppendBytes(aNetworkData->GetBytes(), aNetworkData->GetLength()));
204     }
205 
206     if (aOldRloc16 != Mac::kShortAddrInvalid)
207     {
208         SuccessOrExit(error = Tlv::Append<ThreadRloc16Tlv>(*message, aOldRloc16));
209     }
210 
211     IgnoreError(messageInfo.SetSockAddrToRlocPeerAddrToLeaderAloc());
212     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, messageInfo, HandleCoapResponse, this));
213 
214     LogInfo("Sent %s", UriToString<kUriServerData>());
215 
216 exit:
217     FreeMessageOnError(message, error);
218     return error;
219 }
220 
HandleNotifierEvents(Events aEvents)221 void Notifier::HandleNotifierEvents(Events aEvents)
222 {
223     if (aEvents.ContainsAny(kEventThreadRoleChanged | kEventThreadChildRemoved))
224     {
225         mNextDelay = 0;
226     }
227 
228 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
229     if (aEvents.Contains(kEventThreadPartitionIdChanged))
230     {
231         mDidRequestRouterRoleUpgrade = false;
232     }
233 
234     if (aEvents.ContainsAny(kEventThreadRoleChanged | kEventThreadNetdataChanged | kEventThreadPartitionIdChanged))
235     {
236         ScheduleRouterRoleUpgradeIfEligible();
237     }
238 #endif
239 
240     if (aEvents.ContainsAny(kEventThreadNetdataChanged | kEventThreadRoleChanged | kEventThreadChildRemoved))
241     {
242         SynchronizeServerData();
243     }
244 }
245 
HandleTimer(void)246 void Notifier::HandleTimer(void) { SynchronizeServerData(); }
247 
HandleCoapResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,Error aResult)248 void Notifier::HandleCoapResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, Error aResult)
249 {
250     OT_UNUSED_VARIABLE(aMessage);
251     OT_UNUSED_VARIABLE(aMessageInfo);
252 
253     static_cast<Notifier *>(aContext)->HandleCoapResponse(aResult);
254 }
255 
HandleCoapResponse(Error aResult)256 void Notifier::HandleCoapResponse(Error aResult)
257 {
258     mWaitingForResponse = false;
259 
260     switch (aResult)
261     {
262     case kErrorNone:
263         mTimer.Start(mNextDelay + 1);
264         break;
265 
266     case kErrorResponseTimeout:
267     case kErrorAbort:
268         SynchronizeServerData();
269         break;
270 
271     default:
272         OT_ASSERT(false);
273     }
274 }
275 
276 #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
277 
IsEligibleForRouterRoleUpgradeAsBorderRouter(void) const278 bool Notifier::IsEligibleForRouterRoleUpgradeAsBorderRouter(void) const
279 {
280     bool     isEligible = false;
281     uint16_t rloc16     = Get<Mle::Mle>().GetRloc16();
282     uint8_t  activeRouterCount;
283 
284     VerifyOrExit(Get<Mle::MleRouter>().IsRouterEligible());
285 
286     // RouterUpgradeThreshold can be explicitly set to zero in some of
287     // cert tests to disallow device to become router.
288 
289     VerifyOrExit(Get<Mle::MleRouter>().GetRouterUpgradeThreshold() != 0);
290 
291     // Check that we are a border router providing IP connectivity and already
292     // in the leader's network data and therefore eligible to request router
293     // role upgrade with `kBorderRouterRequest` status.
294 
295     VerifyOrExit(Get<Local>().ContainsBorderRouterWithRloc(rloc16) &&
296                  Get<Leader>().ContainsBorderRouterWithRloc(rloc16));
297 
298     activeRouterCount = Get<RouterTable>().GetActiveRouterCount();
299     VerifyOrExit((activeRouterCount >= Get<Mle::MleRouter>().GetRouterUpgradeThreshold()) &&
300                  (activeRouterCount < Mle::kMaxRouters));
301 
302     VerifyOrExit(Get<Leader>().CountBorderRouters(kRouterRoleOnly) < Mle::kRouterUpgradeBorderRouterRequestThreshold);
303     isEligible = true;
304 
305 exit:
306     return isEligible;
307 }
308 
ScheduleRouterRoleUpgradeIfEligible(void)309 void Notifier::ScheduleRouterRoleUpgradeIfEligible(void)
310 {
311     // We allow device to request router role upgrade using status
312     // reason `kBorderRouterRequest` once while its local network data
313     // remains unchanged. This ensures if the leader is running an
314     // older version of Thread stack which does not support
315     // `kBorderRouterRequest` reason, we do not keep trying (on no
316     // response). The boolean `mDidRequestRouterRoleUpgrade` tracks
317     // this. It is set to `false` when local network data gets changed
318     // or when partition ID gets changed (indicating a potential
319     // leader change).
320 
321     VerifyOrExit(!mDidRequestRouterRoleUpgrade);
322 
323     VerifyOrExit(Get<Mle::MleRouter>().IsChild());
324     VerifyOrExit(IsEligibleForRouterRoleUpgradeAsBorderRouter() && (mRouterRoleUpgradeTimeout == 0));
325 
326     mRouterRoleUpgradeTimeout = Random::NonCrypto::GetUint8InRange(1, kRouterRoleUpgradeMaxTimeout + 1);
327     Get<TimeTicker>().RegisterReceiver(TimeTicker::kNetworkDataNotifier);
328 
329 exit:
330     return;
331 }
332 
HandleTimeTick(void)333 void Notifier::HandleTimeTick(void)
334 {
335     VerifyOrExit(mRouterRoleUpgradeTimeout > 0);
336 
337     mRouterRoleUpgradeTimeout--;
338 
339     if (mRouterRoleUpgradeTimeout == 0)
340     {
341         Get<TimeTicker>().UnregisterReceiver(TimeTicker::kNetworkDataNotifier);
342 
343         // Check that we are still eligible for requesting router role
344         // upgrade (note that state can change since the last time we
345         // checked and registered to receive time ticks).
346 
347         if (Get<Mle::MleRouter>().IsChild() && IsEligibleForRouterRoleUpgradeAsBorderRouter())
348         {
349             LogInfo("Requesting router role as BR");
350             mDidRequestRouterRoleUpgrade = true;
351             IgnoreError(Get<Mle::MleRouter>().BecomeRouter(ThreadStatusTlv::kBorderRouterRequest));
352         }
353     }
354 exit:
355     return;
356 }
357 #endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE &&
358        // OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
359 
360 } // namespace NetworkData
361 } // namespace ot
362 
363 #endif // OPENTHREAD_FTD || OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
364