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/locator_getters.hpp"
48 #include "common/log.hpp"
49 #include "common/random.hpp"
50 #include "common/timer.hpp"
51 #include "instance/instance.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     ChannelTlvValue    channelValue;
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     if (Tlv::Find<ChannelTlv>(aMessage, channelValue) == kErrorNone)
120     {
121         VerifyOrExit(channelValue.IsValid());
122 
123         if (channelValue.GetChannel() != Get<Mac::Mac>().GetPanChannel())
124         {
125             doesAffectConnectivity = true;
126         }
127     }
128 
129     // check PAN ID
130     if (Tlv::Find<PanIdTlv>(aMessage, panId) == kErrorNone && panId != Get<Mac::Mac>().GetPanId())
131     {
132         doesAffectConnectivity = true;
133     }
134 
135     // check mesh local prefix
136     if (Tlv::Find<MeshLocalPrefixTlv>(aMessage, meshLocalPrefix) == kErrorNone &&
137         meshLocalPrefix != Get<Mle::MleRouter>().GetMeshLocalPrefix())
138     {
139         doesAffectConnectivity = true;
140     }
141 
142     // check network key
143     if (Tlv::Find<NetworkKeyTlv>(aMessage, networkKey) == kErrorNone)
144     {
145         NetworkKey localNetworkKey;
146 
147         hasNetworkKey = true;
148         Get<KeyManager>().GetNetworkKey(localNetworkKey);
149 
150         if (networkKey != localNetworkKey)
151         {
152             doesAffectConnectivity = true;
153             doesAffectNetworkKey   = true;
154         }
155     }
156 
157     // check active timestamp rollback
158     if (GetType() == Dataset::kPending && (!hasNetworkKey || !doesAffectNetworkKey))
159     {
160         // no change to network key, active timestamp must be ahead
161         const Timestamp *localActiveTimestamp = Get<ActiveDatasetManager>().GetTimestamp();
162 
163         VerifyOrExit(Timestamp::Compare(&activeTimestamp, localActiveTimestamp) > 0);
164     }
165 
166     // check commissioner session id
167     if (Tlv::Find<CommissionerSessionIdTlv>(aMessage, sessionId) == kErrorNone)
168     {
169         uint16_t localSessionId;
170 
171         isUpdateFromCommissioner = true;
172 
173         SuccessOrExit(Get<NetworkData::Leader>().FindCommissioningSessionId(localSessionId));
174         VerifyOrExit(localSessionId == sessionId);
175     }
176 
177     // verify an MGMT_ACTIVE_SET.req from a Commissioner does not affect connectivity
178     VerifyOrExit(!isUpdateFromCommissioner || GetType() == Dataset::kPending || !doesAffectConnectivity);
179 
180     if (isUpdateFromCommissioner)
181     {
182         // Thread specification allows partial dataset changes for MGMT_ACTIVE_SET.req/MGMT_PENDING_SET.req
183         // from Commissioner based on existing active dataset.
184         IgnoreError(Get<ActiveDatasetManager>().Read(dataset));
185     }
186 
187     if (GetType() == Dataset::kPending || !doesAffectConnectivity)
188     {
189         offset = aMessage.GetOffset();
190 
191         while (offset < aMessage.GetLength())
192         {
193             DatasetTlv datasetTlv;
194 
195             SuccessOrExit(datasetTlv.ReadFromMessage(aMessage, offset));
196 
197             switch (datasetTlv.GetType())
198             {
199             case Tlv::kCommissionerSessionId:
200                 // do not store Commissioner Session ID TLV
201                 break;
202 
203             case Tlv::kDelayTimer:
204             {
205                 uint32_t delayTimer = datasetTlv.ReadValueAs<DelayTimerTlv>();
206 
207                 if (doesAffectNetworkKey && delayTimer < kDefaultDelayTimer)
208                 {
209                     delayTimer = kDefaultDelayTimer;
210                 }
211                 else
212                 {
213                     delayTimer = Max(delayTimer, Get<Leader>().GetDelayTimerMinimal());
214                 }
215 
216                 datasetTlv.WriteValueAs<DelayTimerTlv>(delayTimer);
217             }
218 
219                 OT_FALL_THROUGH;
220 
221             default:
222                 SuccessOrExit(dataset.WriteTlv(datasetTlv));
223                 break;
224             }
225 
226             offset += static_cast<uint16_t>(datasetTlv.GetSize());
227         }
228 
229         SuccessOrExit(Save(dataset));
230         Get<NetworkData::Leader>().IncrementVersionAndStableVersion();
231     }
232     else
233     {
234         Get<PendingDatasetManager>().ApplyActiveDataset(activeTimestamp, aMessage);
235     }
236 
237     state = StateTlv::kAccept;
238 
239     // notify commissioner if update is from thread device
240     if (!isUpdateFromCommissioner)
241     {
242         uint16_t     localSessionId;
243         Ip6::Address destination;
244 
245         SuccessOrExit(Get<NetworkData::Leader>().FindCommissioningSessionId(localSessionId));
246         SuccessOrExit(Get<Mle::MleRouter>().GetCommissionerAloc(destination, localSessionId));
247         Get<Leader>().SendDatasetChanged(destination);
248     }
249 
250 exit:
251 
252     if (Get<Mle::MleRouter>().IsLeader())
253     {
254         SendSetResponse(aMessage, aMessageInfo, state);
255     }
256 
257     return (state == StateTlv::kAccept) ? kErrorNone : kErrorDrop;
258 }
259 
SendSetResponse(const Coap::Message & aRequest,const Ip6::MessageInfo & aMessageInfo,StateTlv::State aState)260 void DatasetManager::SendSetResponse(const Coap::Message    &aRequest,
261                                      const Ip6::MessageInfo &aMessageInfo,
262                                      StateTlv::State         aState)
263 {
264     Error          error = kErrorNone;
265     Coap::Message *message;
266 
267     message = Get<Tmf::Agent>().NewPriorityResponseMessage(aRequest);
268     VerifyOrExit(message != nullptr, error = kErrorNoBufs);
269 
270     SuccessOrExit(error = Tlv::Append<StateTlv>(*message, aState));
271 
272     SuccessOrExit(error = Get<Tmf::Agent>().SendMessage(*message, aMessageInfo));
273 
274     LogInfo("sent dataset set response");
275 
276 exit:
277     FreeMessageOnError(message, error);
278 }
279 
ReadFromMessage(const Message & aMessage,uint16_t aOffset)280 Error DatasetManager::DatasetTlv::ReadFromMessage(const Message &aMessage, uint16_t aOffset)
281 {
282     Error error = kErrorNone;
283 
284     SuccessOrExit(error = aMessage.Read(aOffset, this, sizeof(Tlv)));
285     VerifyOrExit(GetLength() <= Dataset::kMaxValueSize, error = kErrorParse);
286     SuccessOrExit(error = aMessage.Read(aOffset + sizeof(Tlv), mValue, GetLength()));
287     VerifyOrExit(Tlv::IsValid(*this), error = kErrorParse);
288 
289 exit:
290     return error;
291 }
292 
293 #if OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT
GenerateLocal(void)294 Error ActiveDatasetManager::GenerateLocal(void)
295 {
296     Error   error = kErrorNone;
297     Dataset dataset;
298 
299     VerifyOrExit(Get<Mle::MleRouter>().IsAttached(), error = kErrorInvalidState);
300     VerifyOrExit(!mLocal.IsTimestampPresent(), error = kErrorAlready);
301 
302     IgnoreError(Read(dataset));
303 
304     if (!dataset.Contains<ActiveTimestampTlv>())
305     {
306         Timestamp timestamp;
307 
308         timestamp.Clear();
309         IgnoreError(dataset.Write<ActiveTimestampTlv>(timestamp));
310     }
311 
312     if (!dataset.Contains<ChannelTlv>())
313     {
314         ChannelTlvValue channelValue;
315 
316         channelValue.SetChannelAndPage(Get<Mac::Mac>().GetPanChannel());
317         IgnoreError(dataset.Write<ChannelTlv>(channelValue));
318     }
319 
320     if (!dataset.Contains<ChannelMaskTlv>())
321     {
322         ChannelMaskTlv::Value value;
323 
324         ChannelMaskTlv::PrepareValue(value, Get<Mac::Mac>().GetSupportedChannelMask().GetMask());
325         IgnoreError(dataset.WriteTlv(Tlv::kChannelMask, value.mData, value.mLength));
326     }
327 
328     if (!dataset.Contains<ExtendedPanIdTlv>())
329     {
330         IgnoreError(dataset.Write<ExtendedPanIdTlv>(Get<ExtendedPanIdManager>().GetExtPanId()));
331     }
332 
333     if (!dataset.Contains<MeshLocalPrefixTlv>())
334     {
335         IgnoreError(dataset.Write<MeshLocalPrefixTlv>(Get<Mle::MleRouter>().GetMeshLocalPrefix()));
336     }
337 
338     if (!dataset.Contains<NetworkKeyTlv>())
339     {
340         NetworkKey networkKey;
341 
342         Get<KeyManager>().GetNetworkKey(networkKey);
343         IgnoreError(dataset.Write<NetworkKeyTlv>(networkKey));
344     }
345 
346     if (!dataset.Contains<NetworkNameTlv>())
347     {
348         NameData nameData = Get<NetworkNameManager>().GetNetworkName().GetAsData();
349 
350         IgnoreError(dataset.WriteTlv(Tlv::kNetworkName, nameData.GetBuffer(), nameData.GetLength()));
351     }
352 
353     if (!dataset.Contains<PanIdTlv>())
354     {
355         IgnoreError(dataset.Write<PanIdTlv>(Get<Mac::Mac>().GetPanId()));
356     }
357 
358     if (!dataset.Contains<PskcTlv>())
359     {
360         Pskc pskc;
361 
362         if (Get<KeyManager>().IsPskcSet())
363         {
364             Get<KeyManager>().GetPskc(pskc);
365         }
366         else
367         {
368             SuccessOrExit(error = pskc.GenerateRandom());
369         }
370 
371         IgnoreError(dataset.Write<PskcTlv>(pskc));
372     }
373 
374     if (!dataset.Contains<SecurityPolicyTlv>())
375     {
376         SecurityPolicyTlv tlv;
377 
378         tlv.Init();
379         tlv.SetSecurityPolicy(Get<KeyManager>().GetSecurityPolicy());
380         IgnoreError(dataset.WriteTlv(tlv));
381     }
382 
383     SuccessOrExit(error = mLocal.Save(dataset));
384     IgnoreError(Restore());
385 
386     LogInfo("Generated local dataset");
387 
388 exit:
389     return error;
390 }
391 
StartLeader(void)392 void ActiveDatasetManager::StartLeader(void) { IgnoreError(GenerateLocal()); }
393 #else  // OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT
StartLeader(void)394 void ActiveDatasetManager::StartLeader(void) {}
395 #endif // OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT
396 
397 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)398 void ActiveDatasetManager::HandleTmf<kUriActiveSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
399 {
400     VerifyOrExit(Get<Mle::Mle>().IsLeader());
401     SuccessOrExit(DatasetManager::HandleSet(aMessage, aMessageInfo));
402     IgnoreError(ApplyConfiguration());
403 
404 exit:
405     return;
406 }
407 
StartLeader(void)408 void PendingDatasetManager::StartLeader(void) { StartDelayTimer(); }
409 
410 template <>
HandleTmf(Coap::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)411 void PendingDatasetManager::HandleTmf<kUriPendingSet>(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
412 {
413     VerifyOrExit(Get<Mle::Mle>().IsLeader());
414     SuccessOrExit(DatasetManager::HandleSet(aMessage, aMessageInfo));
415     StartDelayTimer();
416 
417 exit:
418     return;
419 }
420 
ApplyActiveDataset(const Timestamp & aTimestamp,Coap::Message & aMessage)421 void PendingDatasetManager::ApplyActiveDataset(const Timestamp &aTimestamp, Coap::Message &aMessage)
422 {
423     uint16_t offset = aMessage.GetOffset();
424     Dataset  dataset;
425 
426     VerifyOrExit(Get<Mle::MleRouter>().IsAttached());
427 
428     while (offset < aMessage.GetLength())
429     {
430         DatasetTlv datasetTlv;
431 
432         SuccessOrExit(datasetTlv.ReadFromMessage(aMessage, offset));
433         offset += static_cast<uint16_t>(datasetTlv.GetSize());
434         IgnoreError(dataset.WriteTlv(datasetTlv));
435     }
436 
437     IgnoreError(dataset.Write<DelayTimerTlv>(Get<Leader>().GetDelayTimerMinimal()));
438 
439     dataset.SetTimestamp(Dataset::kPending, aTimestamp);
440     IgnoreError(DatasetManager::Save(dataset));
441 
442     StartDelayTimer();
443 
444 exit:
445     return;
446 }
447 
448 } // namespace MeshCoP
449 } // namespace ot
450 
451 #endif // OPENTHREAD_FTD
452