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