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