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