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