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