• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 MeshCoP Datasets manager to process commands.
32  *
33  */
34 
35 #include "meshcop/dataset_manager.hpp"
36 
37 #if OPENTHREAD_FTD
38 
39 #include <stdio.h>
40 
41 #include <openthread/platform/radio.h>
42 
43 #include "coap/coap_message.hpp"
44 #include "common/as_core_type.hpp"
45 #include "common/code_utils.hpp"
46 #include "common/debug.hpp"
47 #include "common/instance.hpp"
48 #include "common/locator_getters.hpp"
49 #include "common/log.hpp"
50 #include "common/random.hpp"
51 #include "common/timer.hpp"
52 #include "meshcop/dataset.hpp"
53 #include "meshcop/meshcop.hpp"
54 #include "meshcop/meshcop_leader.hpp"
55 #include "meshcop/meshcop_tlvs.hpp"
56 #include "thread/thread_netif.hpp"
57 #include "thread/thread_tlvs.hpp"
58 #include "thread/uri_paths.hpp"
59 
60 namespace ot {
61 namespace MeshCoP {
62 
63 RegisterLogModule("DatasetManager");
64 
AppendMleDatasetTlv(Message & aMessage) const65 Error DatasetManager::AppendMleDatasetTlv(Message &aMessage) const
66 {
67     Dataset dataset;
68 
69     IgnoreError(Read(dataset));
70 
71     return dataset.AppendMleDatasetTlv(GetType(), aMessage);
72 }
73 
HandleSet(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)74 Error DatasetManager::HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
75 {
76     Tlv                tlv;
77     uint16_t           offset                   = aMessage.GetOffset();
78     bool               isUpdateFromCommissioner = false;
79     bool               doesAffectConnectivity   = false;
80     bool               doesAffectNetworkKey     = false;
81     bool               hasNetworkKey            = false;
82     StateTlv::State    state                    = StateTlv::kReject;
83     Dataset            dataset;
84     Timestamp          activeTimestamp;
85     ChannelTlv         channel;
86     uint16_t           sessionId;
87     Ip6::NetworkPrefix meshLocalPrefix;
88     NetworkKey         networkKey;
89     uint16_t           panId;
90 
91     VerifyOrExit(Get<Mle::MleRouter>().IsLeader());
92 
93     // verify that TLV data size is less than maximum TLV value size
94     while (offset < aMessage.GetLength())
95     {
96         SuccessOrExit(aMessage.Read(offset, tlv));
97         VerifyOrExit(tlv.GetLength() <= Dataset::kMaxValueSize);
98         offset += sizeof(tlv) + tlv.GetLength();
99     }
100 
101     // verify that does not overflow dataset buffer
102     VerifyOrExit((offset - aMessage.GetOffset()) <= Dataset::kMaxSize);
103 
104     // verify the request includes a timestamp that is ahead of the locally stored value
105     SuccessOrExit(Tlv::Find<ActiveTimestampTlv>(aMessage, activeTimestamp));
106 
107     if (GetType() == Dataset::kPending)
108     {
109         Timestamp pendingTimestamp;
110 
111         SuccessOrExit(Tlv::Find<PendingTimestampTlv>(aMessage, pendingTimestamp));
112         VerifyOrExit(Timestamp::Compare(&pendingTimestamp, mLocal.GetTimestamp()) > 0);
113     }
114     else
115     {
116         VerifyOrExit(Timestamp::Compare(&activeTimestamp, mLocal.GetTimestamp()) > 0);
117     }
118 
119     // check channel
120     if (Tlv::FindTlv(aMessage, channel) == kErrorNone)
121     {
122         VerifyOrExit(channel.IsValid());
123 
124         if (channel.GetChannel() != Get<Mac::Mac>().GetPanChannel())
125         {
126             doesAffectConnectivity = true;
127         }
128     }
129 
130     // check PAN ID
131     if (Tlv::Find<PanIdTlv>(aMessage, panId) == kErrorNone && panId != Get<Mac::Mac>().GetPanId())
132     {
133         doesAffectConnectivity = true;
134     }
135 
136     // check mesh local prefix
137     if (Tlv::Find<MeshLocalPrefixTlv>(aMessage, meshLocalPrefix) == kErrorNone &&
138         meshLocalPrefix != Get<Mle::MleRouter>().GetMeshLocalPrefix())
139     {
140         doesAffectConnectivity = true;
141     }
142 
143     // check network key
144     if (Tlv::Find<NetworkKeyTlv>(aMessage, networkKey) == kErrorNone)
145     {
146         NetworkKey localNetworkKey;
147 
148         hasNetworkKey = true;
149         Get<KeyManager>().GetNetworkKey(localNetworkKey);
150 
151         if (networkKey != localNetworkKey)
152         {
153             doesAffectConnectivity = true;
154             doesAffectNetworkKey   = true;
155         }
156     }
157 
158     // check active timestamp rollback
159     if (GetType() == Dataset::kPending && (!hasNetworkKey || !doesAffectNetworkKey))
160     {
161         // no change to network key, active timestamp must be ahead
162         const Timestamp *localActiveTimestamp = Get<ActiveDatasetManager>().GetTimestamp();
163 
164         VerifyOrExit(Timestamp::Compare(&activeTimestamp, localActiveTimestamp) > 0);
165     }
166 
167     // check commissioner session id
168     if (Tlv::Find<CommissionerSessionIdTlv>(aMessage, sessionId) == kErrorNone)
169     {
170         const CommissionerSessionIdTlv *localId;
171 
172         isUpdateFromCommissioner = true;
173 
174         localId = As<CommissionerSessionIdTlv>(
175             Get<NetworkData::Leader>().GetCommissioningDataSubTlv(Tlv::kCommissionerSessionId));
176 
177         VerifyOrExit(localId != nullptr && localId->GetCommissionerSessionId() == sessionId);
178     }
179 
180     // verify an MGMT_ACTIVE_SET.req from a Commissioner does not affect connectivity
181     VerifyOrExit(!isUpdateFromCommissioner || GetType() == Dataset::kPending || !doesAffectConnectivity);
182 
183     if (isUpdateFromCommissioner)
184     {
185         // Thread specification allows partial dataset changes for MGMT_ACTIVE_SET.req/MGMT_PENDING_SET.req
186         // from Commissioner based on existing active dataset.
187         IgnoreError(Get<ActiveDatasetManager>().Read(dataset));
188     }
189 
190     if (GetType() == Dataset::kPending || !doesAffectConnectivity)
191     {
192         offset = aMessage.GetOffset();
193 
194         while (offset < aMessage.GetLength())
195         {
196             DatasetTlv datasetTlv;
197 
198             SuccessOrExit(datasetTlv.ReadFromMessage(aMessage, offset));
199 
200             switch (datasetTlv.GetType())
201             {
202             case Tlv::kCommissionerSessionId:
203                 // do not store Commissioner Session ID TLV
204                 break;
205 
206             case Tlv::kDelayTimer:
207             {
208                 DelayTimerTlv &delayTimerTlv = As<DelayTimerTlv>(datasetTlv);
209 
210                 if (doesAffectNetworkKey && delayTimerTlv.GetDelayTimer() < DelayTimerTlv::kDelayTimerDefault)
211                 {
212                     delayTimerTlv.SetDelayTimer(DelayTimerTlv::kDelayTimerDefault);
213                 }
214                 else if (delayTimerTlv.GetDelayTimer() < Get<Leader>().GetDelayTimerMinimal())
215                 {
216                     delayTimerTlv.SetDelayTimer(Get<Leader>().GetDelayTimerMinimal());
217                 }
218             }
219 
220                 OT_FALL_THROUGH;
221 
222             default:
223                 SuccessOrExit(dataset.SetTlv(datasetTlv));
224                 break;
225             }
226 
227             offset += static_cast<uint16_t>(datasetTlv.GetSize());
228         }
229 
230         SuccessOrExit(Save(dataset));
231         Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
232     }
233     else
234     {
235         Get<PendingDatasetManager>().ApplyActiveDataset(activeTimestamp, aMessage);
236     }
237 
238     state = StateTlv::kAccept;
239 
240     // notify commissioner if update is from thread device
241     if (!isUpdateFromCommissioner)
242     {
243         const CommissionerSessionIdTlv *localSessionId;
244         Ip6::Address                    destination;
245 
246         localSessionId = As<CommissionerSessionIdTlv>(
247             Get<NetworkData::Leader>().GetCommissioningDataSubTlv(Tlv::kCommissionerSessionId));
248         VerifyOrExit(localSessionId != nullptr);
249 
250         SuccessOrExit(
251             Get<Mle::MleRouter>().GetCommissionerAloc(destination, localSessionId->GetCommissionerSessionId()));
252 
253         Get<Leader>().SendDatasetChanged(destination);
254     }
255 
256 exit:
257 
258     if (Get<Mle::MleRouter>().IsLeader())
259     {
260         SendSetResponse(aMessage, aMessageInfo, state);
261     }
262 
263     return (state == StateTlv::kAccept) ? kErrorNone : kErrorDrop;
264 }
265 
SendSetResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,StateTlv::State aState)266 void DatasetManager::SendSetResponse(const Coap::Message &   aRequest,
267                                      const Ip6::MessageInfo &aMessageInfo,
268                                      StateTlv::State         aState)
269 {
270     Error          error = kErrorNone;
271     Coap::Message *message;
272 
273     message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
274     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
275 
276     SuccessOrExit(error = Tlv::Append<StateTlv>(*message, aState));
277 
278     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
279 
280     LogInfo("sent dataset set response");
281 
282 exit:
283     FreeMessageOnError(message, error);
284 }
285 
ReadFromMessage(const Message & aMessage,uint16_t aOffset)286 Error DatasetManager::DatasetTlv::ReadFromMessage(const Message &aMessage, uint16_t aOffset)
287 {
288     Error error = kErrorNone;
289 
290     SuccessOrExit(error = aMessage.Read(aOffset, this, sizeof(Tlv)));
291     VerifyOrExit(GetLength() <= Dataset::kMaxValueSize, error = kErrorParse);
292     SuccessOrExit(error = aMessage.Read(aOffset + sizeof(Tlv), mValue, GetLength()));
293     VerifyOrExit(Tlv::IsValid(*this), error = kErrorParse);
294 
295 exit:
296     return error;
297 }
298 
GenerateLocal(void)299 Error ActiveDatasetManager::GenerateLocal(void)
300 {
301     Error   error = kErrorNone;
302     Dataset dataset;
303 
304     VerifyOrExit(Get<Mle::MleRouter>().IsAttached(), error = kErrorInvalidState);
305     VerifyOrExit(!mLocal.IsTimestampPresent(), error = kErrorAlready);
306 
307     IgnoreError(Read(dataset));
308 
309     if (dataset.GetTlv<ActiveTimestampTlv>() == nullptr)
310     {
311         Timestamp timestamp;
312 
313         timestamp.Clear();
314         IgnoreError(dataset.SetTlv(Tlv::kActiveTimestamp, timestamp));
315     }
316 
317     if (dataset.GetTlv<ChannelTlv>() == nullptr)
318     {
319         ChannelTlv tlv;
320         tlv.Init();
321         tlv.SetChannel(Get<Mac::Mac>().GetPanChannel());
322         IgnoreError(dataset.SetTlv(tlv));
323     }
324 
325     if (dataset.GetTlv<ChannelMaskTlv>() == nullptr)
326     {
327         ChannelMaskTlv tlv;
328         tlv.Init();
329         tlv.SetChannelMask(Get<Mac::Mac>().GetSupportedChannelMask().GetMask());
330         IgnoreError(dataset.SetTlv(tlv));
331     }
332 
333     if (dataset.GetTlv<ExtendedPanIdTlv>() == nullptr)
334     {
335         IgnoreError(dataset.SetTlv(Tlv::kExtendedPanId, Get<ExtendedPanIdManager>().GetExtPanId()));
336     }
337 
338     if (dataset.GetTlv<MeshLocalPrefixTlv>() == nullptr)
339     {
340         IgnoreError(dataset.SetTlv(Tlv::kMeshLocalPrefix, Get<Mle::MleRouter>().GetMeshLocalPrefix()));
341     }
342 
343     if (dataset.GetTlv<NetworkKeyTlv>() == nullptr)
344     {
345         NetworkKey networkKey;
346 
347         Get<KeyManager>().GetNetworkKey(networkKey);
348         IgnoreError(dataset.SetTlv(Tlv::kNetworkKey, networkKey));
349     }
350 
351     if (dataset.GetTlv<NetworkNameTlv>() == nullptr)
352     {
353         NameData nameData = Get<NetworkNameManager>().GetNetworkName().GetAsData();
354 
355         IgnoreError(dataset.SetTlv(Tlv::kNetworkName, nameData.GetBuffer(), nameData.GetLength()));
356     }
357 
358     if (dataset.GetTlv<PanIdTlv>() == nullptr)
359     {
360         IgnoreError(dataset.SetTlv(Tlv::kPanId, Get<Mac::Mac>().GetPanId()));
361     }
362 
363     if (dataset.GetTlv<PskcTlv>() == nullptr)
364     {
365         Pskc pskc;
366 
367         if (Get<KeyManager>().IsPskcSet())
368         {
369             Get<KeyManager>().GetPskc(pskc);
370         }
371         else
372         {
373             SuccessOrExit(error = pskc.GenerateRandom());
374         }
375 
376         IgnoreError(dataset.SetTlv(Tlv::kPskc, pskc));
377     }
378 
379     if (dataset.GetTlv<SecurityPolicyTlv>() == nullptr)
380     {
381         SecurityPolicyTlv tlv;
382 
383         tlv.Init();
384         tlv.SetSecurityPolicy(Get<KeyManager>().GetSecurityPolicy());
385         IgnoreError(dataset.SetTlv(tlv));
386     }
387 
388     SuccessOrExit(error = mLocal.Save(dataset));
389     IgnoreError(Restore());
390 
391     LogInfo("Generated local dataset");
392 
393 exit:
394     return error;
395 }
396 
StartLeader(void)397 void ActiveDatasetManager::StartLeader(void)
398 {
399     IgnoreError(GenerateLocal());
400     Get<Tmf::Agent>().AddResource(mResourceSet);
401 }
402 
StopLeader(void)403 void ActiveDatasetManager::StopLeader(void)
404 {
405     Get<Tmf::Agent>().RemoveResource(mResourceSet);
406 }
407 
HandleSet(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)408 void ActiveDatasetManager::HandleSet(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
409 {
410     static_cast<ActiveDatasetManager *>(aContext)->HandleSet(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
411 }
412 
HandleSet(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)413 void ActiveDatasetManager::HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
414 {
415     SuccessOrExit(DatasetManager::HandleSet(aMessage, aMessageInfo));
416     IgnoreError(ApplyConfiguration());
417 
418 exit:
419     return;
420 }
421 
StartLeader(void)422 void PendingDatasetManager::StartLeader(void)
423 {
424     StartDelayTimer();
425     Get<Tmf::Agent>().AddResource(mResourceSet);
426 }
427 
StopLeader(void)428 void PendingDatasetManager::StopLeader(void)
429 {
430     Get<Tmf::Agent>().RemoveResource(mResourceSet);
431 }
432 
HandleSet(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)433 void PendingDatasetManager::HandleSet(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
434 {
435     static_cast<PendingDatasetManager *>(aContext)->HandleSet(AsCoapMessage(aMessage), AsCoreType(aMessageInfo));
436 }
437 
HandleSet(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)438 void PendingDatasetManager::HandleSet(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
439 {
440     SuccessOrExit(DatasetManager::HandleSet(aMessage, aMessageInfo));
441     StartDelayTimer();
442 
443 exit:
444     return;
445 }
446 
ApplyActiveDataset(const Timestamp & aTimestamp,Coap::Message & aMessage)447 void PendingDatasetManager::ApplyActiveDataset(const Timestamp &aTimestamp, Coap::Message &aMessage)
448 {
449     uint16_t offset = aMessage.GetOffset();
450     Dataset  dataset;
451 
452     VerifyOrExit(Get<Mle::MleRouter>().IsAttached());
453 
454     while (offset < aMessage.GetLength())
455     {
456         DatasetTlv datasetTlv;
457 
458         SuccessOrExit(datasetTlv.ReadFromMessage(aMessage, offset));
459         offset += static_cast<uint16_t>(datasetTlv.GetSize());
460         IgnoreError(dataset.SetTlv(datasetTlv));
461     }
462 
463     // add delay timer tlv
464     IgnoreError(dataset.SetTlv(Tlv::kDelayTimer, Get<Leader>().GetDelayTimerMinimal()));
465 
466     // add pending timestamp tlv
467     dataset.SetTimestamp(Dataset::kPending, aTimestamp);
468     IgnoreError(DatasetManager::Save(dataset));
469 
470     // reset delay timer
471     StartDelayTimer();
472 
473 exit:
474     return;
475 }
476 
477 } // namespace MeshCoP
478 } // namespace ot
479 
480 #endif // OPENTHREAD_FTD
481