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