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