Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <assert.h>
19 : #include <string.h>
20 :
21 : #include <lib/support/ThreadOperationalDataset.h>
22 :
23 : namespace chip {
24 : namespace Thread {
25 :
26 : /**
27 : * Thread Operational Dataset TLV is defined in Thread Specification as the following format:
28 : *
29 : * +---------+---------+-------------------------+
30 : * | uint8_t | uint8_t | network byte order data |
31 : * | 1 byte | 1 byte | n byte (0 <= n < 255) |
32 : * +---------+---------+-------------------------+
33 : * | Type | Length | Value |
34 : * +---------+---------+-------------------------+
35 : *
36 : */
37 : class ThreadTLV final
38 : {
39 : static constexpr uint8_t kLengthEscape = 0xff; ///< This length value indicates the actual length is of two-bytes length, which
40 : ///< not allowed in Thread Operational Dataset TLVs.
41 :
42 : public:
43 : enum : uint8_t
44 : {
45 : kChannel = 0,
46 : kPanId = 1,
47 : kExtendedPanId = 2,
48 : kNetworkName = 3,
49 : kPSKc = 4,
50 : kMasterKey = 5,
51 : kMeshLocalPrefix = 7,
52 : kActiveTimestamp = 14,
53 : };
54 :
55 21 : uint8_t GetSize() const { return static_cast<uint8_t>(sizeof(*this) + GetLength()); }
56 :
57 159 : uint8_t GetType() const { return mType; }
58 :
59 11 : void SetType(uint8_t aType) { mType = aType; }
60 :
61 177 : uint8_t GetLength() const
62 : {
63 177 : assert(mLength != kLengthEscape);
64 177 : return mLength;
65 : }
66 :
67 11 : void SetLength(uint8_t aLength)
68 : {
69 11 : assert(mLength != kLengthEscape);
70 11 : mLength = aLength;
71 11 : }
72 :
73 171 : const void * GetValue() const
74 : {
75 171 : assert(mLength != kLengthEscape);
76 :
77 : static_assert(sizeof(*this) == sizeof(ThreadTLV::mType) + sizeof(ThreadTLV::mLength), "Wrong size for ThreadTLV header");
78 :
79 171 : return reinterpret_cast<const uint8_t *>(this) + sizeof(*this);
80 : }
81 :
82 14 : void * GetValue() { return const_cast<void *>(const_cast<const ThreadTLV *>(this)->GetValue()); }
83 :
84 2 : void Get64(uint64_t & aValue) const
85 : {
86 2 : assert(GetLength() >= sizeof(aValue));
87 :
88 2 : const uint8_t * p = reinterpret_cast<const uint8_t *>(GetValue());
89 2 : aValue = //
90 2 : (static_cast<uint64_t>(p[0]) << 56) | //
91 2 : (static_cast<uint64_t>(p[1]) << 48) | //
92 2 : (static_cast<uint64_t>(p[2]) << 40) | //
93 2 : (static_cast<uint64_t>(p[3]) << 32) | //
94 2 : (static_cast<uint64_t>(p[4]) << 24) | //
95 2 : (static_cast<uint64_t>(p[5]) << 16) | //
96 2 : (static_cast<uint64_t>(p[6]) << 8) | //
97 2 : (static_cast<uint64_t>(p[7]));
98 2 : }
99 :
100 2 : void Get16(uint16_t & aValue) const
101 : {
102 2 : assert(GetLength() >= sizeof(aValue));
103 :
104 2 : const uint8_t * p = static_cast<const uint8_t *>(GetValue());
105 :
106 2 : aValue = static_cast<uint16_t>(p[0] << 8 | p[1]);
107 2 : }
108 :
109 : void Get8(uint8_t & aValue) const
110 : {
111 : assert(GetLength() >= sizeof(aValue));
112 : aValue = *static_cast<const uint8_t *>(GetValue());
113 : }
114 :
115 1 : void Set64(uint64_t aValue)
116 : {
117 1 : uint8_t * value = static_cast<uint8_t *>(GetValue());
118 :
119 1 : SetLength(sizeof(aValue));
120 :
121 1 : value[0] = static_cast<uint8_t>((aValue >> 56) & 0xff);
122 1 : value[1] = static_cast<uint8_t>((aValue >> 48) & 0xff);
123 1 : value[2] = static_cast<uint8_t>((aValue >> 40) & 0xff);
124 1 : value[3] = static_cast<uint8_t>((aValue >> 32) & 0xff);
125 1 : value[4] = static_cast<uint8_t>((aValue >> 24) & 0xff);
126 1 : value[5] = static_cast<uint8_t>((aValue >> 16) & 0xff);
127 1 : value[6] = static_cast<uint8_t>((aValue >> 8) & 0xff);
128 1 : value[7] = static_cast<uint8_t>(aValue & 0xff);
129 1 : }
130 :
131 1 : void Set16(uint16_t aValue)
132 : {
133 1 : uint8_t * value = static_cast<uint8_t *>(GetValue());
134 :
135 1 : SetLength(sizeof(aValue));
136 :
137 1 : value[0] = static_cast<uint8_t>(aValue >> 8);
138 1 : value[1] = static_cast<uint8_t>(aValue & 0xff);
139 1 : }
140 :
141 : void Set8(uint8_t aValue)
142 : {
143 : SetLength(sizeof(aValue));
144 : *static_cast<uint8_t *>(GetValue()) = aValue;
145 : }
146 :
147 : void Set8(int8_t aValue)
148 : {
149 : SetLength(sizeof(aValue));
150 : *static_cast<int8_t *>(GetValue()) = aValue;
151 : }
152 :
153 9 : void SetValue(const void * aValue, uint8_t aLength)
154 : {
155 9 : SetLength(aLength);
156 9 : memcpy(GetValue(), aValue, aLength);
157 9 : }
158 :
159 138 : const ThreadTLV * GetNext() const
160 : {
161 : static_assert(alignof(ThreadTLV) == 1, "Wrong alignment for ThreadTLV header");
162 138 : return reinterpret_cast<const ThreadTLV *>(static_cast<const uint8_t *>(GetValue()) + GetLength());
163 : }
164 :
165 3 : ThreadTLV * GetNext() { return reinterpret_cast<ThreadTLV *>(static_cast<uint8_t *>(GetValue()) + GetLength()); }
166 :
167 2 : static bool IsValid(ByteSpan aData)
168 : {
169 2 : const uint8_t * const end = aData.data() + aData.size();
170 2 : const uint8_t * curr = aData.data();
171 :
172 3 : while (curr + sizeof(ThreadTLV) < end)
173 : {
174 1 : const ThreadTLV * tlv = reinterpret_cast<const ThreadTLV *>(curr);
175 :
176 1 : if (tlv->GetLength() == kLengthEscape)
177 : {
178 0 : break;
179 : }
180 :
181 1 : curr = reinterpret_cast<const uint8_t *>(tlv->GetNext());
182 : }
183 :
184 2 : return curr == end;
185 : }
186 :
187 : private:
188 : uint8_t mType;
189 : uint8_t mLength;
190 : };
191 :
192 0 : bool OperationalDataset::IsValid(ByteSpan aData)
193 : {
194 0 : return ThreadTLV::IsValid(aData);
195 : }
196 :
197 4 : CHIP_ERROR OperationalDataset::Init(ByteSpan aData)
198 : {
199 4 : if (aData.size() > sizeof(mData))
200 : {
201 1 : return CHIP_ERROR_INVALID_ARGUMENT;
202 : }
203 :
204 3 : if (aData.size() > 0)
205 : {
206 2 : if (!ThreadTLV::IsValid(aData))
207 : {
208 2 : return CHIP_ERROR_INVALID_ARGUMENT;
209 : }
210 :
211 0 : memcpy(mData, aData.data(), aData.size());
212 : }
213 :
214 1 : mLength = static_cast<uint8_t>(aData.size());
215 1 : return CHIP_NO_ERROR;
216 : }
217 :
218 3 : CHIP_ERROR OperationalDataset::GetActiveTimestamp(uint64_t & aActiveTimestamp) const
219 : {
220 3 : const ThreadTLV * tlv = Locate(ThreadTLV::kActiveTimestamp);
221 :
222 3 : if (tlv != nullptr)
223 : {
224 2 : tlv->Get64(aActiveTimestamp);
225 2 : return CHIP_NO_ERROR;
226 : }
227 :
228 1 : return CHIP_ERROR_TLV_TAG_NOT_FOUND;
229 : }
230 :
231 1 : CHIP_ERROR OperationalDataset::SetActiveTimestamp(uint64_t aActiveTimestamp)
232 : {
233 1 : ThreadTLV * tlv = MakeRoom(ThreadTLV::kActiveTimestamp, sizeof(*tlv) + sizeof(aActiveTimestamp));
234 :
235 1 : if (tlv == nullptr)
236 : {
237 0 : return CHIP_ERROR_NO_MEMORY;
238 : }
239 :
240 1 : tlv->Set64(aActiveTimestamp);
241 :
242 1 : mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
243 :
244 1 : return CHIP_NO_ERROR;
245 : }
246 :
247 3 : CHIP_ERROR OperationalDataset::GetChannel(uint16_t & aChannel) const
248 : {
249 3 : const ThreadTLV * tlv = Locate(ThreadTLV::kChannel);
250 :
251 3 : if (tlv != nullptr)
252 : {
253 2 : const uint8_t * value = reinterpret_cast<const uint8_t *>(tlv->GetValue());
254 2 : aChannel = static_cast<uint16_t>((value[1] << 8) | value[2]);
255 2 : return CHIP_NO_ERROR;
256 : }
257 :
258 1 : return CHIP_ERROR_TLV_TAG_NOT_FOUND;
259 : }
260 :
261 1 : CHIP_ERROR OperationalDataset::SetChannel(uint16_t aChannel)
262 : {
263 1 : uint8_t value[] = { 0, static_cast<uint8_t>(aChannel >> 8), static_cast<uint8_t>(aChannel & 0xff) };
264 1 : ThreadTLV * tlv = MakeRoom(ThreadTLV::kChannel, sizeof(*tlv) + sizeof(value));
265 :
266 1 : if (tlv == nullptr)
267 : {
268 0 : return CHIP_ERROR_NO_MEMORY;
269 : }
270 :
271 1 : tlv->SetValue(value, sizeof(value));
272 :
273 1 : mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
274 :
275 1 : return CHIP_NO_ERROR;
276 : }
277 :
278 3 : CHIP_ERROR OperationalDataset::GetExtendedPanId(uint8_t (&aExtendedPanId)[kSizeExtendedPanId]) const
279 : {
280 3 : ByteSpan extPanIdSpan;
281 3 : CHIP_ERROR error = GetExtendedPanIdAsByteSpan(extPanIdSpan);
282 :
283 3 : if (error != CHIP_NO_ERROR)
284 : {
285 1 : return error;
286 : }
287 :
288 2 : memcpy(aExtendedPanId, extPanIdSpan.data(), extPanIdSpan.size());
289 2 : return CHIP_NO_ERROR;
290 : }
291 :
292 4 : CHIP_ERROR OperationalDataset::GetExtendedPanIdAsByteSpan(ByteSpan & span) const
293 : {
294 4 : const ThreadTLV * tlv = Locate(ThreadTLV::kExtendedPanId);
295 :
296 4 : if (tlv == nullptr)
297 : {
298 1 : return CHIP_ERROR_TLV_TAG_NOT_FOUND;
299 : }
300 :
301 3 : if (tlv->GetLength() != kSizeExtendedPanId)
302 : {
303 0 : return CHIP_ERROR_INVALID_TLV_ELEMENT;
304 : }
305 :
306 3 : span = ByteSpan(static_cast<const uint8_t *>(tlv->GetValue()), tlv->GetLength());
307 3 : return CHIP_NO_ERROR;
308 : }
309 :
310 1 : CHIP_ERROR OperationalDataset::SetExtendedPanId(const uint8_t (&aExtendedPanId)[kSizeExtendedPanId])
311 : {
312 1 : ThreadTLV * tlv = MakeRoom(ThreadTLV::kExtendedPanId, sizeof(*tlv) + sizeof(aExtendedPanId));
313 :
314 1 : if (tlv == nullptr)
315 : {
316 0 : return CHIP_ERROR_NO_MEMORY;
317 : }
318 :
319 1 : tlv->SetValue(aExtendedPanId, sizeof(aExtendedPanId));
320 :
321 1 : assert(mLength + tlv->GetSize() <= sizeof(mData));
322 :
323 1 : mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
324 :
325 1 : return CHIP_NO_ERROR;
326 : }
327 :
328 5 : CHIP_ERROR OperationalDataset::GetMasterKey(uint8_t (&aMasterKey)[kSizeMasterKey]) const
329 : {
330 5 : const ThreadTLV * tlv = Locate(ThreadTLV::kMasterKey);
331 :
332 5 : if (tlv != nullptr)
333 : {
334 3 : memcpy(aMasterKey, tlv->GetValue(), sizeof(aMasterKey));
335 3 : return CHIP_NO_ERROR;
336 : }
337 :
338 2 : return CHIP_ERROR_TLV_TAG_NOT_FOUND;
339 : }
340 :
341 2 : CHIP_ERROR OperationalDataset::SetMasterKey(const uint8_t (&aMasterKey)[kSizeMasterKey])
342 : {
343 2 : ThreadTLV * tlv = MakeRoom(ThreadTLV::kMasterKey, sizeof(*tlv) + sizeof(aMasterKey));
344 :
345 2 : if (tlv == nullptr)
346 : {
347 0 : return CHIP_ERROR_NO_MEMORY;
348 : }
349 :
350 2 : tlv->SetValue(aMasterKey, sizeof(aMasterKey));
351 :
352 2 : assert(mLength + tlv->GetSize() <= sizeof(mData));
353 :
354 2 : mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
355 :
356 2 : return CHIP_NO_ERROR;
357 : }
358 :
359 3 : CHIP_ERROR OperationalDataset::GetMeshLocalPrefix(uint8_t (&aMeshLocalPrefix)[kSizeMeshLocalPrefix]) const
360 : {
361 3 : const ThreadTLV * tlv = Locate(ThreadTLV::kMeshLocalPrefix);
362 :
363 3 : if (tlv != nullptr)
364 : {
365 2 : memcpy(aMeshLocalPrefix, tlv->GetValue(), sizeof(aMeshLocalPrefix));
366 2 : return CHIP_NO_ERROR;
367 : }
368 :
369 1 : return CHIP_ERROR_TLV_TAG_NOT_FOUND;
370 : }
371 :
372 1 : CHIP_ERROR OperationalDataset::SetMeshLocalPrefix(const uint8_t (&aMeshLocalPrefix)[kSizeMeshLocalPrefix])
373 : {
374 1 : ThreadTLV * tlv = MakeRoom(ThreadTLV::kMeshLocalPrefix, sizeof(*tlv) + sizeof(aMeshLocalPrefix));
375 :
376 1 : if (tlv == nullptr)
377 : {
378 0 : return CHIP_ERROR_NO_MEMORY;
379 : }
380 :
381 1 : tlv->SetValue(aMeshLocalPrefix, sizeof(aMeshLocalPrefix));
382 :
383 1 : mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
384 :
385 1 : return CHIP_NO_ERROR;
386 : }
387 :
388 3 : CHIP_ERROR OperationalDataset::GetNetworkName(char (&aNetworkName)[kSizeNetworkName + 1]) const
389 : {
390 3 : const ThreadTLV * tlv = Locate(ThreadTLV::kNetworkName);
391 :
392 3 : if (tlv != nullptr)
393 : {
394 2 : memcpy(aNetworkName, tlv->GetValue(), tlv->GetLength());
395 2 : aNetworkName[tlv->GetLength()] = '\0';
396 2 : return CHIP_NO_ERROR;
397 : }
398 :
399 1 : return CHIP_ERROR_TLV_TAG_NOT_FOUND;
400 : }
401 :
402 4 : CHIP_ERROR OperationalDataset::SetNetworkName(const char * aNetworkName)
403 : {
404 4 : size_t len = strlen(aNetworkName);
405 :
406 4 : if (len > kSizeNetworkName || len == 0)
407 : {
408 2 : return CHIP_ERROR_INVALID_STRING_LENGTH;
409 : }
410 :
411 2 : ThreadTLV * tlv = MakeRoom(ThreadTLV::kNetworkName, static_cast<uint8_t>(sizeof(*tlv) + static_cast<uint8_t>(len)));
412 :
413 2 : if (tlv == nullptr)
414 : {
415 0 : return CHIP_ERROR_NO_MEMORY;
416 : }
417 :
418 2 : tlv->SetValue(aNetworkName, static_cast<uint8_t>(len));
419 :
420 2 : mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
421 :
422 2 : return CHIP_NO_ERROR;
423 : }
424 :
425 3 : CHIP_ERROR OperationalDataset::GetPanId(uint16_t & aPanId) const
426 : {
427 3 : const ThreadTLV * tlv = Locate(ThreadTLV::kPanId);
428 :
429 3 : if (tlv != nullptr)
430 : {
431 2 : tlv->Get16(aPanId);
432 2 : return CHIP_NO_ERROR;
433 : }
434 :
435 1 : return CHIP_ERROR_TLV_TAG_NOT_FOUND;
436 : }
437 :
438 1 : CHIP_ERROR OperationalDataset::SetPanId(uint16_t aPanId)
439 : {
440 1 : ThreadTLV * tlv = MakeRoom(ThreadTLV::kPanId, sizeof(*tlv) + sizeof(aPanId));
441 :
442 1 : if (tlv == nullptr)
443 : {
444 0 : return CHIP_ERROR_NO_MEMORY;
445 : }
446 :
447 1 : tlv->Set16(aPanId);
448 :
449 1 : mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
450 :
451 1 : return CHIP_NO_ERROR;
452 : }
453 :
454 5 : CHIP_ERROR OperationalDataset::GetPSKc(uint8_t (&aPSKc)[kSizePSKc]) const
455 : {
456 5 : const ThreadTLV * tlv = Locate(ThreadTLV::kPSKc);
457 :
458 5 : if (tlv != nullptr)
459 : {
460 3 : memcpy(aPSKc, tlv->GetValue(), sizeof(aPSKc));
461 3 : return CHIP_NO_ERROR;
462 : }
463 :
464 2 : return CHIP_ERROR_TLV_TAG_NOT_FOUND;
465 : }
466 :
467 2 : CHIP_ERROR OperationalDataset::SetPSKc(const uint8_t (&aPSKc)[kSizePSKc])
468 : {
469 2 : ThreadTLV * tlv = MakeRoom(ThreadTLV::kPSKc, sizeof(*tlv) + sizeof(aPSKc));
470 :
471 2 : if (tlv == nullptr)
472 : {
473 0 : return CHIP_ERROR_NO_MEMORY;
474 : }
475 :
476 2 : tlv->SetValue(aPSKc, sizeof(aPSKc));
477 :
478 2 : mLength = static_cast<uint8_t>(mLength + tlv->GetSize());
479 :
480 2 : return CHIP_NO_ERROR;
481 : }
482 :
483 1 : void OperationalDataset::UnsetMasterKey()
484 : {
485 1 : Remove(ThreadTLV::kMasterKey);
486 1 : }
487 :
488 1 : void OperationalDataset::UnsetPSKc()
489 : {
490 1 : Remove(ThreadTLV::kPSKc);
491 1 : }
492 :
493 0 : bool OperationalDataset::IsCommissioned() const
494 : {
495 0 : return Has(ThreadTLV::kPanId) && Has(ThreadTLV::kMasterKey) && Has(ThreadTLV::kExtendedPanId) && Has(ThreadTLV::kChannel);
496 : }
497 :
498 42 : const ThreadTLV * OperationalDataset::Locate(uint8_t aType) const
499 : {
500 42 : const ThreadTLV * tlv = &Begin();
501 42 : const ThreadTLV * end = &End();
502 :
503 179 : while (tlv < end)
504 : {
505 159 : if (tlv->GetType() == aType)
506 22 : break;
507 137 : tlv = tlv->GetNext();
508 : }
509 :
510 42 : assert(tlv < reinterpret_cast<const ThreadTLV *>(&mData[sizeof(mData)]));
511 :
512 42 : return tlv != end ? tlv : nullptr;
513 : }
514 :
515 3 : void OperationalDataset::Remove(ThreadTLV & aThreadTLV)
516 : {
517 3 : uint8_t offset = static_cast<uint8_t>(reinterpret_cast<uint8_t *>(&aThreadTLV) - mData);
518 :
519 3 : if (offset < mLength && mLength >= (offset + aThreadTLV.GetSize()))
520 : {
521 3 : mLength = static_cast<uint8_t>(mLength - aThreadTLV.GetSize());
522 3 : memmove(&aThreadTLV, aThreadTLV.GetNext(), mLength - offset);
523 : }
524 3 : }
525 :
526 2 : void OperationalDataset::Remove(uint8_t aType)
527 : {
528 2 : ThreadTLV * tlv = Locate(aType);
529 :
530 2 : if (tlv != nullptr)
531 : {
532 2 : Remove(*tlv);
533 : }
534 2 : }
535 :
536 11 : ThreadTLV * OperationalDataset::MakeRoom(uint8_t aType, uint8_t aSize)
537 : {
538 11 : ThreadTLV * tlv = Locate(aType);
539 :
540 11 : size_t freeSpace = sizeof(mData) - mLength;
541 :
542 11 : if (tlv != nullptr)
543 : {
544 1 : if (freeSpace + tlv->GetSize() < aSize)
545 : {
546 0 : return nullptr;
547 : }
548 :
549 1 : Remove(*tlv);
550 : }
551 10 : else if (freeSpace < aSize)
552 : {
553 0 : return nullptr;
554 : }
555 :
556 11 : End().SetType(aType);
557 :
558 11 : return &End();
559 : }
560 :
561 : } // namespace Thread
562 : } // namespace chip
|