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 "instance/instance.hpp"
39
40 namespace ot {
41 namespace NetworkData {
42
43 RegisterLogModule("NetworkData");
44
45 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
46
AddOnMeshPrefix(const OnMeshPrefixConfig & aConfig)47 Error Local::AddOnMeshPrefix(const OnMeshPrefixConfig &aConfig)
48 {
49 Error error = kErrorInvalidArgs;
50
51 VerifyOrExit(aConfig.IsValid(GetInstance()));
52
53 error =
54 AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeBorderRouter, aConfig.ConvertToTlvFlags(), aConfig.mStable);
55
56 exit:
57 return error;
58 }
59
ContainsOnMeshPrefix(const Ip6::Prefix & aPrefix) const60 bool Local::ContainsOnMeshPrefix(const Ip6::Prefix &aPrefix) const
61 {
62 const PrefixTlv *tlv;
63 bool contains = false;
64
65 VerifyOrExit((tlv = FindPrefix(aPrefix)) != nullptr);
66 VerifyOrExit(tlv->FindSubTlv(NetworkDataTlv::kTypeBorderRouter) != nullptr);
67
68 contains = true;
69
70 exit:
71 return contains;
72 }
73
AddHasRoutePrefix(const ExternalRouteConfig & aConfig)74 Error Local::AddHasRoutePrefix(const ExternalRouteConfig &aConfig)
75 {
76 Error error = kErrorInvalidArgs;
77
78 VerifyOrExit(aConfig.IsValid(GetInstance()));
79
80 error = AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeHasRoute, aConfig.ConvertToTlvFlags(), aConfig.mStable);
81
82 exit:
83 return error;
84 }
85
AddPrefix(const Ip6::Prefix & aPrefix,NetworkDataTlv::Type aSubTlvType,uint16_t aFlags,bool aStable)86 Error Local::AddPrefix(const Ip6::Prefix &aPrefix, NetworkDataTlv::Type aSubTlvType, uint16_t aFlags, bool aStable)
87 {
88 Error error = kErrorNone;
89 uint8_t subTlvLength;
90 PrefixTlv *prefixTlv;
91
92 IgnoreError(RemovePrefix(aPrefix));
93
94 subTlvLength = (aSubTlvType == NetworkDataTlv::kTypeBorderRouter)
95 ? sizeof(BorderRouterTlv) + sizeof(BorderRouterEntry)
96 : sizeof(HasRouteTlv) + sizeof(HasRouteEntry);
97
98 prefixTlv = As<PrefixTlv>(AppendTlv(sizeof(PrefixTlv) + aPrefix.GetBytesSize() + subTlvLength));
99 VerifyOrExit(prefixTlv != nullptr, error = kErrorNoBufs);
100
101 prefixTlv->Init(0, aPrefix);
102 prefixTlv->SetSubTlvsLength(subTlvLength);
103
104 if (aSubTlvType == NetworkDataTlv::kTypeBorderRouter)
105 {
106 BorderRouterTlv *brTlv = As<BorderRouterTlv>(prefixTlv->GetSubTlvs());
107 brTlv->Init();
108 brTlv->SetLength(brTlv->GetLength() + sizeof(BorderRouterEntry));
109 brTlv->GetEntry(0)->Init();
110 brTlv->GetEntry(0)->SetFlags(aFlags);
111 }
112 else // aSubTlvType is NetworkDataTlv::kTypeHasRoute
113 {
114 HasRouteTlv *hasRouteTlv = As<HasRouteTlv>(prefixTlv->GetSubTlvs());
115 hasRouteTlv->Init();
116 hasRouteTlv->SetLength(hasRouteTlv->GetLength() + sizeof(HasRouteEntry));
117 hasRouteTlv->GetEntry(0)->Init();
118 hasRouteTlv->GetEntry(0)->SetFlags(static_cast<uint8_t>(aFlags));
119 }
120
121 if (aStable)
122 {
123 prefixTlv->SetStable();
124 prefixTlv->GetSubTlvs()->SetStable();
125 }
126
127 DumpDebg("AddPrefix", GetBytes(), GetLength());
128
129 exit:
130 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
131 if (error == kErrorNoBufs)
132 {
133 Get<Notifier>().SignalNetworkDataFull();
134 }
135 #endif
136
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 }
172 }
173 }
174
175 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
176
177 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
AddService(uint32_t aEnterpriseNumber,const ServiceData & aServiceData,bool aServerStable,const ServerData & aServerData)178 Error Local::AddService(uint32_t aEnterpriseNumber,
179 const ServiceData &aServiceData,
180 bool aServerStable,
181 const ServerData &aServerData)
182 {
183 Error error = kErrorNone;
184 ServiceTlv *serviceTlv;
185 ServerTlv *serverTlv;
186 uint16_t serviceTlvSize = ServiceTlv::CalculateSize(aEnterpriseNumber, aServiceData.GetLength()) +
187 sizeof(ServerTlv) + aServerData.GetLength();
188
189 IgnoreError(RemoveService(aEnterpriseNumber, aServiceData));
190
191 VerifyOrExit(serviceTlvSize <= kMaxSize, error = kErrorNoBufs);
192
193 serviceTlv = As<ServiceTlv>(AppendTlv(serviceTlvSize));
194 VerifyOrExit(serviceTlv != nullptr, error = kErrorNoBufs);
195
196 serviceTlv->Init(/* aServiceId */ 0, aEnterpriseNumber, aServiceData);
197 serviceTlv->SetSubTlvsLength(sizeof(ServerTlv) + aServerData.GetLength());
198
199 serverTlv = As<ServerTlv>(serviceTlv->GetSubTlvs());
200 serverTlv->Init(Get<Mle::MleRouter>().GetRloc16(), aServerData);
201
202 // According to Thread spec 1.1.1, section 5.18.6 Service TLV:
203 // "The Stable flag is set if any of the included sub-TLVs have their Stable flag set."
204 // The meaning also seems to be 'if and only if'.
205 if (aServerStable)
206 {
207 serviceTlv->SetStable();
208 serverTlv->SetStable();
209 }
210
211 DumpDebg("AddService", GetBytes(), GetLength());
212
213 exit:
214 #if OPENTHREAD_CONFIG_BORDER_ROUTER_SIGNAL_NETWORK_DATA_FULL
215 if (error == kErrorNoBufs)
216 {
217 Get<Notifier>().SignalNetworkDataFull();
218 }
219 #endif
220
221 return error;
222 }
223
RemoveService(uint32_t aEnterpriseNumber,const ServiceData & aServiceData)224 Error Local::RemoveService(uint32_t aEnterpriseNumber, const ServiceData &aServiceData)
225 {
226 Error error = kErrorNone;
227 ServiceTlv *tlv;
228
229 VerifyOrExit((tlv = FindService(aEnterpriseNumber, aServiceData, kServiceExactMatch)) != nullptr,
230 error = kErrorNotFound);
231 RemoveTlv(tlv);
232
233 exit:
234 DumpDebg("RmvService", GetBytes(), GetLength());
235 return error;
236 }
237
UpdateRloc(ServiceTlv & aService)238 void Local::UpdateRloc(ServiceTlv &aService)
239 {
240 uint16_t rloc16 = Get<Mle::MleRouter>().GetRloc16();
241
242 for (NetworkDataTlv *cur = aService.GetSubTlvs(); cur < aService.GetNext(); cur = cur->GetNext())
243 {
244 switch (cur->GetType())
245 {
246 case NetworkDataTlv::kTypeServer:
247 As<ServerTlv>(cur)->SetServer16(rloc16);
248 break;
249
250 default:
251 OT_ASSERT(false);
252 }
253 }
254 }
255
256 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
257
UpdateRloc(void)258 void Local::UpdateRloc(void)
259 {
260 for (NetworkDataTlv *cur = GetTlvsStart(); cur < GetTlvsEnd(); cur = cur->GetNext())
261 {
262 switch (cur->GetType())
263 {
264 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
265 case NetworkDataTlv::kTypePrefix:
266 UpdateRloc(*As<PrefixTlv>(cur));
267 break;
268 #endif
269
270 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
271
272 case NetworkDataTlv::kTypeService:
273 UpdateRloc(*As<ServiceTlv>(cur));
274 break;
275 #endif
276
277 default:
278 OT_ASSERT(false);
279 }
280 }
281 }
282
283 } // namespace NetworkData
284 } // namespace ot
285
286 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE || OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE
287