1 /*
2 * Copyright (c) 2016, 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 the local Thread Network Data.
32 */
33
34 #include "network_data_local.hpp"
35
36 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
37
38 #include "common/code_utils.hpp"
39 #include "common/debug.hpp"
40 #include "common/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/logging.hpp"
43 #include "mac/mac_types.hpp"
44 #include "thread/mle_types.hpp"
45 #include "thread/thread_netif.hpp"
46
47 namespace ot {
48 namespace NetworkData {
49
Local(Instance & aInstance)50 Local::Local(Instance &aInstance)
51 : NetworkData(aInstance, kTypeLocal)
52 , mOldRloc(Mac::kShortAddrInvalid)
53 {
54 }
55
56 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
57
AddOnMeshPrefix(const OnMeshPrefixConfig & aConfig)58 Error Local::AddOnMeshPrefix(const OnMeshPrefixConfig &aConfig)
59 {
60 Error error = kErrorInvalidArgs;
61
62 VerifyOrExit(aConfig.IsValid(GetInstance()));
63
64 error =
65 AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeBorderRouter, aConfig.ConvertToTlvFlags(), aConfig.mStable);
66
67 exit:
68 return error;
69 }
70
RemoveOnMeshPrefix(const Ip6::Prefix & aPrefix)71 Error Local::RemoveOnMeshPrefix(const Ip6::Prefix &aPrefix)
72 {
73 return RemovePrefix(aPrefix, NetworkDataTlv::kTypeBorderRouter);
74 }
75
AddHasRoutePrefix(const ExternalRouteConfig & aConfig)76 Error Local::AddHasRoutePrefix(const ExternalRouteConfig &aConfig)
77 {
78 Error error = kErrorInvalidArgs;
79
80 VerifyOrExit(aConfig.IsValid(GetInstance()));
81
82 error = AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeHasRoute, aConfig.ConvertToTlvFlags(), aConfig.mStable);
83
84 exit:
85 return error;
86 }
87
RemoveHasRoutePrefix(const Ip6::Prefix & aPrefix)88 Error Local::RemoveHasRoutePrefix(const Ip6::Prefix &aPrefix)
89 {
90 return RemovePrefix(aPrefix, NetworkDataTlv::kTypeHasRoute);
91 }
92
AddPrefix(const Ip6::Prefix & aPrefix,NetworkDataTlv::Type aSubTlvType,uint16_t aFlags,bool aStable)93 Error Local::AddPrefix(const Ip6::Prefix &aPrefix, NetworkDataTlv::Type aSubTlvType, uint16_t aFlags, bool aStable)
94 {
95 Error error = kErrorNone;
96 uint8_t subTlvLength;
97 PrefixTlv *prefixTlv;
98
99 IgnoreError(RemovePrefix(aPrefix, aSubTlvType));
100
101 subTlvLength = (aSubTlvType == NetworkDataTlv::kTypeBorderRouter)
102 ? sizeof(BorderRouterTlv) + sizeof(BorderRouterEntry)
103 : sizeof(HasRouteTlv) + sizeof(HasRouteEntry);
104
105 prefixTlv = static_cast<PrefixTlv *>(AppendTlv(sizeof(PrefixTlv) + aPrefix.GetBytesSize() + subTlvLength));
106 VerifyOrExit(prefixTlv != nullptr, error = kErrorNoBufs);
107
108 prefixTlv->Init(0, aPrefix);
109 prefixTlv->SetSubTlvsLength(subTlvLength);
110
111 if (aSubTlvType == NetworkDataTlv::kTypeBorderRouter)
112 {
113 BorderRouterTlv *brTlv = static_cast<BorderRouterTlv *>(prefixTlv->GetSubTlvs());
114 brTlv->Init();
115 brTlv->SetLength(brTlv->GetLength() + sizeof(BorderRouterEntry));
116 brTlv->GetEntry(0)->Init();
117 brTlv->GetEntry(0)->SetFlags(aFlags);
118 }
119 else // aSubTlvType is NetworkDataTlv::kTypeHasRoute
120 {
121 HasRouteTlv *hasRouteTlv = static_cast<HasRouteTlv *>(prefixTlv->GetSubTlvs());
122 hasRouteTlv->Init();
123 hasRouteTlv->SetLength(hasRouteTlv->GetLength() + sizeof(HasRouteEntry));
124 hasRouteTlv->GetEntry(0)->Init();
125 hasRouteTlv->GetEntry(0)->SetFlags(static_cast<uint8_t>(aFlags));
126 }
127
128 if (aStable)
129 {
130 prefixTlv->SetStable();
131 prefixTlv->GetSubTlvs()->SetStable();
132 }
133
134 otDumpDebgNetData("add prefix done", mTlvs, mLength);
135
136 exit:
137 return error;
138 }
139
RemovePrefix(const Ip6::Prefix & aPrefix,NetworkDataTlv::Type aSubTlvType)140 Error Local::RemovePrefix(const Ip6::Prefix &aPrefix, NetworkDataTlv::Type aSubTlvType)
141 {
142 Error error = kErrorNone;
143 PrefixTlv *tlv;
144
145 VerifyOrExit((tlv = FindPrefix(aPrefix)) != nullptr, error = kErrorNotFound);
146 VerifyOrExit(tlv->FindSubTlv(aSubTlvType) != nullptr, error = kErrorNotFound);
147 RemoveTlv(tlv);
148
149 exit:
150 otDumpDebgNetData("remove done", mTlvs, mLength);
151 return error;
152 }
153
UpdateRloc(PrefixTlv & aPrefixTlv)154 void Local::UpdateRloc(PrefixTlv &aPrefixTlv)
155 {
156 uint16_t rloc16 = Get<Mle::MleRouter>().GetRloc16();
157
158 for (NetworkDataTlv *cur = aPrefixTlv.GetSubTlvs(); cur < aPrefixTlv.GetNext(); cur = cur->GetNext())
159 {
160 switch (cur->GetType())
161 {
162 case NetworkDataTlv::kTypeHasRoute:
163 static_cast<HasRouteTlv *>(cur)->GetEntry(0)->SetRloc(rloc16);
164 break;
165
166 case NetworkDataTlv::kTypeBorderRouter:
167 static_cast<BorderRouterTlv *>(cur)->GetEntry(0)->SetRloc(rloc16);
168 break;
169
170 default:
171 OT_ASSERT(false);
172 OT_UNREACHABLE_CODE(break);
173 }
174 }
175 }
176
IsOnMeshPrefixConsistent(void) const177 bool Local::IsOnMeshPrefixConsistent(void) const
178 {
179 return (Get<Leader>().ContainsOnMeshPrefixes(*this, Get<Mle::MleRouter>().GetRloc16()) &&
180 ContainsOnMeshPrefixes(Get<Leader>(), Get<Mle::MleRouter>().GetRloc16()));
181 }
182
IsExternalRouteConsistent(void) const183 bool Local::IsExternalRouteConsistent(void) const
184 {
185 return (Get<Leader>().ContainsExternalRoutes(*this, Get<Mle::MleRouter>().GetRloc16()) &&
186 ContainsExternalRoutes(Get<Leader>(), Get<Mle::MleRouter>().GetRloc16()));
187 }
188
189 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
190
191 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
AddService(uint32_t aEnterpriseNumber,const uint8_t * aServiceData,uint8_t aServiceDataLength,bool aServerStable,const uint8_t * aServerData,uint8_t aServerDataLength)192 Error Local::AddService(uint32_t aEnterpriseNumber,
193 const uint8_t *aServiceData,
194 uint8_t aServiceDataLength,
195 bool aServerStable,
196 const uint8_t *aServerData,
197 uint8_t aServerDataLength)
198 {
199 Error error = kErrorNone;
200 ServiceTlv *serviceTlv;
201 ServerTlv * serverTlv;
202 uint16_t serviceTlvSize =
203 ServiceTlv::CalculateSize(aEnterpriseNumber, aServiceDataLength) + sizeof(ServerTlv) + aServerDataLength;
204
205 IgnoreError(RemoveService(aEnterpriseNumber, aServiceData, aServiceDataLength));
206
207 VerifyOrExit(serviceTlvSize <= kMaxSize, error = kErrorNoBufs);
208
209 serviceTlv = static_cast<ServiceTlv *>(AppendTlv(serviceTlvSize));
210 VerifyOrExit(serviceTlv != nullptr, error = kErrorNoBufs);
211
212 serviceTlv->Init(/* aServiceId */ 0, aEnterpriseNumber, aServiceData, aServiceDataLength);
213 serviceTlv->SetSubTlvsLength(sizeof(ServerTlv) + aServerDataLength);
214
215 serverTlv = static_cast<ServerTlv *>(serviceTlv->GetSubTlvs());
216
217 serverTlv->Init(Get<Mle::MleRouter>().GetRloc16(), aServerData, aServerDataLength);
218
219 // According to Thread spec 1.1.1, section 5.18.6 Service TLV:
220 // "The Stable flag is set if any of the included sub-TLVs have their Stable flag set."
221 // The meaning also seems to be 'if and only if'.
222 if (aServerStable)
223 {
224 serviceTlv->SetStable();
225 serverTlv->SetStable();
226 }
227
228 otDumpDebgNetData("add service done", mTlvs, mLength);
229
230 exit:
231 return error;
232 }
233
RemoveService(uint32_t aEnterpriseNumber,const uint8_t * aServiceData,uint8_t aServiceDataLength)234 Error Local::RemoveService(uint32_t aEnterpriseNumber, const uint8_t *aServiceData, uint8_t aServiceDataLength)
235 {
236 Error error = kErrorNone;
237 ServiceTlv *tlv;
238
239 VerifyOrExit((tlv = FindService(aEnterpriseNumber, aServiceData, aServiceDataLength, kServiceExactMatch)) !=
240 nullptr,
241 error = kErrorNotFound);
242 RemoveTlv(tlv);
243
244 exit:
245 otDumpDebgNetData("remove service done", mTlvs, mLength);
246 return error;
247 }
248
UpdateRloc(ServiceTlv & aService)249 void Local::UpdateRloc(ServiceTlv &aService)
250 {
251 uint16_t rloc16 = Get<Mle::MleRouter>().GetRloc16();
252
253 for (NetworkDataTlv *cur = aService.GetSubTlvs(); cur < aService.GetNext(); cur = cur->GetNext())
254 {
255 switch (cur->GetType())
256 {
257 case NetworkDataTlv::kTypeServer:
258 static_cast<ServerTlv *>(cur)->SetServer16(rloc16);
259 break;
260
261 default:
262 OT_ASSERT(false);
263 OT_UNREACHABLE_CODE(break);
264 }
265 }
266 }
267
IsServiceConsistent(void) const268 bool Local::IsServiceConsistent(void) const
269 {
270 return (Get<Leader>().ContainsServices(*this, Get<Mle::MleRouter>().GetRloc16()) &&
271 ContainsServices(Get<Leader>(), Get<Mle::MleRouter>().GetRloc16()));
272 }
273
274 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
275
UpdateRloc(void)276 void Local::UpdateRloc(void)
277 {
278 for (NetworkDataTlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
279 {
280 switch (cur->GetType())
281 {
282 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
283 case NetworkDataTlv::kTypePrefix:
284 UpdateRloc(*static_cast<PrefixTlv *>(cur));
285 break;
286 #endif
287
288 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
289
290 case NetworkDataTlv::kTypeService:
291 UpdateRloc(*static_cast<ServiceTlv *>(cur));
292 break;
293 #endif
294
295 default:
296 OT_ASSERT(false);
297 OT_UNREACHABLE_CODE(break);
298 }
299 }
300 }
301
UpdateInconsistentServerData(Coap::ResponseHandler aHandler,void * aContext)302 Error Local::UpdateInconsistentServerData(Coap::ResponseHandler aHandler, void *aContext)
303 {
304 Error error = kErrorNone;
305 uint16_t rloc = Get<Mle::MleRouter>().GetRloc16();
306 bool isConsistent = true;
307
308 #if OPENTHREAD_FTD
309 // Don't send this Server Data Notification if the device is going to upgrade to Router
310 if (Get<Mle::MleRouter>().IsExpectedToBecomeRouterSoon())
311 {
312 ExitNow(error = kErrorInvalidState);
313 }
314 #endif
315
316 UpdateRloc();
317
318 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
319 isConsistent = isConsistent && IsOnMeshPrefixConsistent() && IsExternalRouteConsistent();
320 #endif
321 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
322 isConsistent = isConsistent && IsServiceConsistent();
323 #endif
324
325 VerifyOrExit(!isConsistent, error = kErrorNotFound);
326
327 if (mOldRloc == rloc)
328 {
329 mOldRloc = Mac::kShortAddrInvalid;
330 }
331
332 SuccessOrExit(error = SendServerDataNotification(mOldRloc, aHandler, aContext));
333 mOldRloc = rloc;
334
335 exit:
336 return error;
337 }
338
339 } // namespace NetworkData
340 } // namespace ot
341
342 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
343