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/log.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
50 RegisterLogModule("NetworkData");
51
52 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
53
AddOnMeshPrefix(const OnMeshPrefixConfig & aConfig)54 Error Local::AddOnMeshPrefix(const OnMeshPrefixConfig &aConfig)
55 {
56 Error error = kErrorInvalidArgs;
57
58 VerifyOrExit(aConfig.IsValid(GetInstance()));
59
60 error =
61 AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeBorderRouter, aConfig.ConvertToTlvFlags(), aConfig.mStable);
62
63 exit:
64 return error;
65 }
66
ContainsOnMeshPrefix(const Ip6::Prefix & aPrefix) const67 bool Local::ContainsOnMeshPrefix(const Ip6::Prefix &aPrefix) const
68 {
69 const PrefixTlv *tlv;
70 bool contains = false;
71
72 VerifyOrExit((tlv = FindPrefix(aPrefix)) != nullptr);
73 VerifyOrExit(tlv->FindSubTlv(NetworkDataTlv::kTypeBorderRouter) != nullptr);
74
75 contains = true;
76
77 exit:
78 return contains;
79 }
80
AddHasRoutePrefix(const ExternalRouteConfig & aConfig)81 Error Local::AddHasRoutePrefix(const ExternalRouteConfig &aConfig)
82 {
83 Error error = kErrorInvalidArgs;
84
85 VerifyOrExit(aConfig.IsValid(GetInstance()));
86
87 error = AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeHasRoute, aConfig.ConvertToTlvFlags(), aConfig.mStable);
88
89 exit:
90 return error;
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));
100
101 subTlvLength = (aSubTlvType == NetworkDataTlv::kTypeBorderRouter)
102 ? sizeof(BorderRouterTlv) + sizeof(BorderRouterEntry)
103 : sizeof(HasRouteTlv) + sizeof(HasRouteEntry);
104
105 prefixTlv = As<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 = As<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 = As<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 DumpDebg("AddPrefix", GetBytes(), GetLength());
135
136 exit:
137 return error;
138 }
139
RemovePrefix(const Ip6::Prefix & aPrefix)140 Error Local::RemovePrefix(const Ip6::Prefix &aPrefix)
141 {
142 Error error = kErrorNone;
143 PrefixTlv *tlv;
144
145 VerifyOrExit((tlv = FindPrefix(aPrefix)) != nullptr, error = kErrorNotFound);
146 RemoveTlv(tlv);
147
148 exit:
149 DumpDebg("RmvPrefix", GetBytes(), GetLength());
150 return error;
151 }
152
UpdateRloc(PrefixTlv & aPrefixTlv)153 void Local::UpdateRloc(PrefixTlv &aPrefixTlv)
154 {
155 uint16_t rloc16 = Get<Mle::MleRouter>().GetRloc16();
156
157 for (NetworkDataTlv *cur = aPrefixTlv.GetSubTlvs(); cur < aPrefixTlv.GetNext(); cur = cur->GetNext())
158 {
159 switch (cur->GetType())
160 {
161 case NetworkDataTlv::kTypeHasRoute:
162 As<HasRouteTlv>(cur)->GetEntry(0)->SetRloc(rloc16);
163 break;
164
165 case NetworkDataTlv::kTypeBorderRouter:
166 As<BorderRouterTlv>(cur)->GetEntry(0)->SetRloc(rloc16);
167 break;
168
169 default:
170 OT_ASSERT(false);
171 OT_UNREACHABLE_CODE(break);
172 }
173 }
174 }
175
176 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
177
178 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
AddService(uint32_t aEnterpriseNumber,const ServiceData & aServiceData,bool aServerStable,const ServerData & aServerData)179 Error Local::AddService(uint32_t aEnterpriseNumber,
180 const ServiceData &aServiceData,
181 bool aServerStable,
182 const ServerData & aServerData)
183 {
184 Error error = kErrorNone;
185 ServiceTlv *serviceTlv;
186 ServerTlv * serverTlv;
187 uint16_t serviceTlvSize = ServiceTlv::CalculateSize(aEnterpriseNumber, aServiceData.GetLength()) +
188 sizeof(ServerTlv) + aServerData.GetLength();
189
190 IgnoreError(RemoveService(aEnterpriseNumber, aServiceData));
191
192 VerifyOrExit(serviceTlvSize <= kMaxSize, error = kErrorNoBufs);
193
194 serviceTlv = As<ServiceTlv>(AppendTlv(serviceTlvSize));
195 VerifyOrExit(serviceTlv != nullptr, error = kErrorNoBufs);
196
197 serviceTlv->Init(/* aServiceId */ 0, aEnterpriseNumber, aServiceData);
198 serviceTlv->SetSubTlvsLength(sizeof(ServerTlv) + aServerData.GetLength());
199
200 serverTlv = As<ServerTlv>(serviceTlv->GetSubTlvs());
201 serverTlv->Init(Get<Mle::MleRouter>().GetRloc16(), aServerData);
202
203 // According to Thread spec 1.1.1, section 5.18.6 Service TLV:
204 // "The Stable flag is set if any of the included sub-TLVs have their Stable flag set."
205 // The meaning also seems to be 'if and only if'.
206 if (aServerStable)
207 {
208 serviceTlv->SetStable();
209 serverTlv->SetStable();
210 }
211
212 DumpDebg("AddService", GetBytes(), GetLength());
213
214 exit:
215 return error;
216 }
217
RemoveService(uint32_t aEnterpriseNumber,const ServiceData & aServiceData)218 Error Local::RemoveService(uint32_t aEnterpriseNumber, const ServiceData &aServiceData)
219 {
220 Error error = kErrorNone;
221 ServiceTlv *tlv;
222
223 VerifyOrExit((tlv = FindService(aEnterpriseNumber, aServiceData, kServiceExactMatch)) != nullptr,
224 error = kErrorNotFound);
225 RemoveTlv(tlv);
226
227 exit:
228 DumpDebg("RmvService", GetBytes(), GetLength());
229 return error;
230 }
231
UpdateRloc(ServiceTlv & aService)232 void Local::UpdateRloc(ServiceTlv &aService)
233 {
234 uint16_t rloc16 = Get<Mle::MleRouter>().GetRloc16();
235
236 for (NetworkDataTlv *cur = aService.GetSubTlvs(); cur < aService.GetNext(); cur = cur->GetNext())
237 {
238 switch (cur->GetType())
239 {
240 case NetworkDataTlv::kTypeServer:
241 As<ServerTlv>(cur)->SetServer16(rloc16);
242 break;
243
244 default:
245 OT_ASSERT(false);
246 OT_UNREACHABLE_CODE(break);
247 }
248 }
249 }
250
251 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
252
UpdateRloc(void)253 void Local::UpdateRloc(void)
254 {
255 for (NetworkDataTlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
256 {
257 switch (cur->GetType())
258 {
259 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
260 case NetworkDataTlv::kTypePrefix:
261 UpdateRloc(*As<PrefixTlv>(cur));
262 break;
263 #endif
264
265 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
266
267 case NetworkDataTlv::kTypeService:
268 UpdateRloc(*As<ServiceTlv>(cur));
269 break;
270 #endif
271
272 default:
273 OT_ASSERT(false);
274 OT_UNREACHABLE_CODE(break);
275 }
276 }
277 }
278
IsConsistent(void) const279 bool Local::IsConsistent(void) const
280 {
281 return Get<Leader>().ContainsEntriesFrom(*this, Get<Mle::MleRouter>().GetRloc16()) &&
282 ContainsEntriesFrom(Get<Leader>(), Get<Mle::MleRouter>().GetRloc16());
283 }
284
UpdateInconsistentServerData(Coap::ResponseHandler aHandler,void * aContext)285 Error Local::UpdateInconsistentServerData(Coap::ResponseHandler aHandler, void *aContext)
286 {
287 Error error = kErrorNone;
288 uint16_t rloc = Get<Mle::MleRouter>().GetRloc16();
289
290 #if OPENTHREAD_FTD
291 // Don't send this Server Data Notification if the device is going to upgrade to Router
292 if (Get<Mle::MleRouter>().IsExpectedToBecomeRouterSoon())
293 {
294 ExitNow(error = kErrorInvalidState);
295 }
296 #endif
297
298 UpdateRloc();
299
300 VerifyOrExit(!IsConsistent(), error = kErrorNotFound);
301
302 if (mOldRloc == rloc)
303 {
304 mOldRloc = Mac::kShortAddrInvalid;
305 }
306
307 SuccessOrExit(error = SendServerDataNotification(mOldRloc, /* aAppendNetDataTlv */ true, aHandler, aContext));
308 mOldRloc = rloc;
309
310 exit:
311 return error;
312 }
313
314 } // namespace NetworkData
315 } // namespace ot
316
317 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
318