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