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 : #pragma once
19 :
20 : #include <stdint.h>
21 : #include <stdio.h>
22 : #include <stdlib.h>
23 :
24 : #include <lib/core/CHIPCore.h>
25 : #include <lib/support/Span.h>
26 :
27 : namespace chip {
28 : namespace Thread {
29 :
30 : class ThreadTLV;
31 :
32 : inline constexpr size_t kChannel_NotSpecified = UINT8_MAX;
33 : inline constexpr size_t kPANId_NotSpecified = UINT16_MAX;
34 :
35 : /// The maximum size of a Thread operational dataset.
36 : inline constexpr size_t kSizeOperationalDataset = 254;
37 :
38 : inline constexpr size_t kSizeNetworkName = 16;
39 : inline constexpr size_t kSizeExtendedPanId = 8;
40 : inline constexpr size_t kSizeMasterKey = 16;
41 : inline constexpr size_t kSizeMeshLocalPrefix = 8;
42 : inline constexpr size_t kSizePSKc = 16;
43 :
44 : class OperationalDataset;
45 :
46 : /**
47 : * This class provides a read-only view of a Thread operational dataset.
48 : * The underlying data is not owned by this class, and must remain valid for the lifetime of the view.
49 : */
50 : class OperationalDatasetView
51 : {
52 : public:
53 : OperationalDatasetView() = default;
54 :
55 : /**
56 : * Initializes the dataset view with the given data.
57 : * The data itself is not copied, so it must remain valid for the lifetime of the view.
58 : *
59 : * @param[in] aData The data to interpret as a Thread operational dataset.
60 : *
61 : * @retval CHIP_NO_ERROR Successfully initialized the dataset.
62 : * @retval CHIP_ERROR_INVALID_ARGUMENT The dataset length @p aLength is too long or @p data is corrupted.
63 : */
64 : CHIP_ERROR Init(ByteSpan aData);
65 :
66 : /**
67 : * Returns the ByteSpan underlying this view.
68 : */
69 27 : ByteSpan AsByteSpan() const { return mData; }
70 :
71 : /**
72 : * Retrieves the Active Timestamp from the dataset.
73 : *
74 : * @param[out] aActiveTimestamp A reference to receive the active timestamp.
75 : *
76 : * @retval CHIP_NO_ERROR Successfully retrieved the active timestamp.
77 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread active timestamp is not present in the dataset.
78 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
79 : */
80 : CHIP_ERROR GetActiveTimestamp(uint64_t & aActiveTimestamp) const;
81 :
82 : /**
83 : * Retrieves the channel number from the dataset.
84 : *
85 : * Note that the underlying TLV consists of a 1 byte Channel Page, and a 2 byte Channel Number.
86 : * The Channel Page is not returned, as zero is currently the only valid value.
87 : * A non-zero Channel Page is treated as a CHIP_ERROR_INVALID_TLV_ELEMENT error
88 : *
89 : * @param[out] aChannel A reference to receive the channel.
90 : *
91 : * @retval CHIP_NO_ERROR Successfully retrieved the channel.
92 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread channel is not present in the dataset.
93 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
94 : */
95 : CHIP_ERROR GetChannel(uint16_t & aChannel) const;
96 :
97 : /**
98 : * Retrieves the Extended PAN ID from the dataset.
99 : *
100 : * @param[out] aExtendedPanId A reference to receive the extended PAN ID.
101 : *
102 : * @retval CHIP_NO_ERROR Successfully retrieved the extended PAN ID.
103 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread extended PAN ID is not present in the dataset.
104 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
105 : */
106 : CHIP_ERROR GetExtendedPanId(uint8_t (&aExtendedPanId)[kSizeExtendedPanId]) const;
107 :
108 : /**
109 : * Retrieves the Extended PAN ID from the dataset, interpreted as a big endian number.
110 : * @retval CHIP_NO_ERROR Successfully retrieved the extended PAN ID.
111 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread extended PAN ID is not present in the dataset.
112 : */
113 : CHIP_ERROR GetExtendedPanId(uint64_t & extendedPanId) const;
114 :
115 : /**
116 : * Retrieves a ByteSpan pointing to the Extended PAN ID within the dataset.
117 : * This can be used to pass the extended PAN ID to a cluster command without the use of external memory.
118 : *
119 : * Note: The returned span points must not be dereferenced beyond the lifetime of this object.
120 : *
121 : * @param[out] span A reference to receive the location of the extended PAN ID.
122 : *
123 : * @retval CHIP_NO_ERROR Successfully retrieved the extended PAN ID.
124 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread extended PAN ID is not present in the dataset.
125 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
126 : */
127 : CHIP_ERROR GetExtendedPanIdAsByteSpan(ByteSpan & span) const;
128 :
129 : /**
130 : * Retrieves the Master Key from the dataset.
131 : *
132 : * @param[out] aMasterKey A reference to receive the master key.
133 : *
134 : * @retval CHIP_NO_ERROR Successfully retrieved the master key.
135 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread master key is not present in the dataset.
136 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
137 : */
138 : CHIP_ERROR GetMasterKey(uint8_t (&aMasterKey)[kSizeMasterKey]) const;
139 :
140 : /**
141 : * Retrieves the Mesh Local Prefix from the dataset.
142 : *
143 : * @param[out] aMeshLocalPrefix A reference to receive the mesh local prefix.
144 : *
145 : * @retval CHIP_NO_ERROR Successfully retrieved the mesh local prefix.
146 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread mesh local prefix is not present in the dataset.
147 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
148 : */
149 : CHIP_ERROR GetMeshLocalPrefix(uint8_t (&aMeshLocalPrefix)[kSizeMeshLocalPrefix]) const;
150 :
151 : /**
152 : * Retrieves the Network Name from the dataset.
153 : *
154 : * @param[out] aNetworkName A reference to receive the Thread network name.
155 : *
156 : * @retval CHIP_NO_ERROR Successfully retrieved the network name.
157 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread network name is not present in the dataset.
158 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
159 : */
160 : CHIP_ERROR GetNetworkName(char (&aNetworkName)[kSizeNetworkName + 1]) const;
161 :
162 : /**
163 : * Retrieves the PAN ID from the dataset.
164 : *
165 : * @param[out] aPanId A reference to receive the PAN ID.
166 : *
167 : * @retval CHIP_NO_ERROR Successfully retrieved the PAN ID.
168 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread PAN ID is not present in the dataset.
169 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
170 : */
171 : CHIP_ERROR GetPanId(uint16_t & aPanId) const;
172 :
173 : /**
174 : * Retrieves the Pre-Shared Key for the Commissioner (PSKc) from the dataset.
175 : *
176 : * @param[out] aPSKc A reference to receive the PSKc.
177 : *
178 : * @retval CHIP_NO_ERROR Successfully retrieved the PSKc.
179 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND Thread PSKc is not present in the dataset.
180 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT If the TLV element is invalid.
181 : */
182 : CHIP_ERROR GetPSKc(uint8_t (&aPSKc)[kSizePSKc]) const;
183 :
184 : /**
185 : * Retrieves a ByteSpan pointing to the Channel Mask within the dataset.
186 : *
187 : * Note: The returned span must not be dereferenced beyond the lifetime of this object.
188 : *
189 : * @retval CHIP_NO_ERROR on success.
190 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND if the channel mask is not present in the dataset.
191 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT if the TLV element is invalid.
192 : */
193 : CHIP_ERROR GetChannelMask(ByteSpan & aChannelMask) const;
194 :
195 : /**
196 : * Retrieves the Security Policy from the dataset.
197 : *
198 : * @retval CHIP_NO_ERROR on success.
199 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND if no security policy is present in the dataset.
200 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT if the TLV element is invalid.
201 : */
202 : CHIP_ERROR GetSecurityPolicy(uint32_t & aSecurityPolicy) const;
203 :
204 : /**
205 : * Retrieves the Delay Timer from the dataset.
206 : *
207 : * @retval CHIP_NO_ERROR on success.
208 : * @retval CHIP_ERROR_TLV_TAG_NOT_FOUND if no security policy is present in the dataset.
209 : * @retval CHIP_ERROR_INVALID_TLV_ELEMENT if the TLV element is invalid.
210 : */
211 : CHIP_ERROR GetDelayTimer(uint32_t & aDelayMillis) const;
212 :
213 : /**
214 : * Returns true if the dataset contains the required TLV elements for creating a Thread network.
215 : * The required elements are: PAN ID, Extended PAN ID, Channel, and Master Key.
216 : */
217 : bool IsCommissioned() const;
218 :
219 : /**
220 : * This method checks if the dataset is empty.
221 : */
222 2 : bool IsEmpty() const { return mData.empty(); }
223 :
224 : /**
225 : * This method checks whether @p aData contains a valid sequence of Thread TLV elements.
226 : *
227 : * @note This method only verifies the overall TLV format, not the correctness of individual TLV elements.
228 : */
229 : static bool IsValid(ByteSpan aData);
230 :
231 : private:
232 : friend class OperationalDataset;
233 :
234 : ByteSpan mData;
235 :
236 175 : OperationalDatasetView(uint8_t * buffer) : mData(ByteSpan(buffer, 0)) {}
237 :
238 : const ThreadTLV * Locate(uint8_t aType) const;
239 0 : bool Has(uint8_t aType) const { return Locate(aType) != nullptr; }
240 : };
241 :
242 : /**
243 : * This class provides methods to manipulate a Thread operational dataset.
244 : * It maintains an internal buffer sized to accommodate the maximum possible dataset size.
245 : */
246 : class OperationalDataset : public OperationalDatasetView
247 : {
248 : public:
249 175 : OperationalDataset() : OperationalDatasetView(mBuffer) {}
250 :
251 : // Delegate copy construction and assignment to the overloads taking an OperationalDatasetView.
252 1 : OperationalDataset(const OperationalDataset & other) : OperationalDataset(static_cast<const OperationalDatasetView &>(other)) {}
253 1 : OperationalDataset & operator=(const OperationalDataset & other)
254 : {
255 1 : return *this = static_cast<const OperationalDatasetView &>(other);
256 : }
257 :
258 1 : OperationalDataset(const OperationalDatasetView & view) : OperationalDatasetView(view) { CopyData(); }
259 2 : OperationalDataset & operator=(const OperationalDatasetView & view)
260 : {
261 2 : static_cast<OperationalDatasetView &>(*this) = view;
262 2 : CopyData();
263 2 : return *this;
264 : }
265 :
266 : /**
267 : * Initializes the dataset by copying the provided data into an internal buffer.
268 : *
269 : * @param[in] aData The data to interpret as a Thread operational dataset.
270 : *
271 : * @retval CHIP_NO_ERROR Successfully initialized the dataset.
272 : * @retval CHIP_ERROR_INVALID_ARGUMENT The dataset length @p aLength is too long or @p data is corrupted.
273 : */
274 : CHIP_ERROR Init(ByteSpan aData);
275 :
276 : /**
277 : * Sets the Active Timestamp in the dataset.
278 : *
279 : * @param[in] aActiveTimestamp The Thread active timestamp.
280 : *
281 : * @retval CHIP_NO_ERROR Successfully set the active timestamp.
282 : * @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread active timestamp.
283 : */
284 : CHIP_ERROR SetActiveTimestamp(uint64_t aActiveTimestamp);
285 :
286 : /**
287 : * Sets the Channel Number in the dataset.
288 : *
289 : * Note that the underlying TLV consists of a 1 byte Channel Page, and a 2 byte Channel Number.
290 : * The Channel Page is always set to zero, as it is currently the only valid value.
291 : *
292 : * @param[in] aChannel The Thread channel.
293 : *
294 : * @retval CHIP_NO_ERROR Successfully set the channel.
295 : * @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread channel.
296 : */
297 : CHIP_ERROR SetChannel(uint16_t aChannel);
298 :
299 : /**
300 : * Sets the Extended PAN ID in the dataset.
301 : *
302 : * @param[in] aExtendedPanId The Thread extended PAN ID.
303 : *
304 : * @retval CHIP_NO_ERROR Successfully set the extended PAN ID.
305 : * @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread extended PAN ID.
306 : */
307 : CHIP_ERROR SetExtendedPanId(const uint8_t (&aExtendedPanId)[kSizeExtendedPanId]);
308 :
309 : /**
310 : * Sets the Master Key in the dataset.
311 : *
312 : * @param[in] aMasterKey The Thread master key.
313 : *
314 : * @retval CHIP_NO_ERROR Successfully set the master key.
315 : * @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread master key.
316 : */
317 : CHIP_ERROR SetMasterKey(const uint8_t (&aMasterKey)[kSizeMasterKey]);
318 :
319 : /**
320 : * Removes the Master Key from the dataset.
321 : */
322 : void UnsetMasterKey();
323 :
324 : /**
325 : * Sets the Mesh Local Prefix in the dataset.
326 : *
327 : * @param[in] aMeshLocalPrefix The Thread mesh local prefix.
328 : *
329 : * @retval CHIP_NO_ERROR Successfully set the Thread mesh local prefix.
330 : * @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread mesh local prefix.
331 : */
332 : CHIP_ERROR SetMeshLocalPrefix(const uint8_t (&aMeshLocalPrefix)[kSizeMeshLocalPrefix]);
333 :
334 : /**
335 : * Sets the Network Name in the dataset. The name must be a non-empty string
336 : * with a maximum length of 16 characters (kSizeNetworkName).
337 : *
338 : * @param[in] aNetworkName The Thread network name.
339 : *
340 : * @retval CHIP_NO_ERROR Successfully set the network name.
341 : * @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread network name.
342 : */
343 : CHIP_ERROR SetNetworkName(const char * aNetworkName);
344 :
345 : /**
346 : * Sets the PAN ID in the dataset.
347 : *
348 : * @param[in] aPanId The Thread PAN ID.
349 : *
350 : * @retval CHIP_NO_ERROR Successfully set the PAN ID.
351 : * @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread PAN ID.
352 : */
353 : CHIP_ERROR SetPanId(uint16_t aPanId);
354 :
355 : /**
356 : * Sets the Pre-Shared Key for the Commissioner (PSKc) in the dataset.
357 : *
358 : * @param[in] aPSKc The Thread PSKc.
359 : *
360 : * @retval CHIP_NO_ERROR Successfully set the PSKc.
361 : * @retval CHIP_ERROR_NO_MEMORY Insufficient memory in the dataset for setting Thread PSKc.
362 : */
363 : CHIP_ERROR SetPSKc(const uint8_t (&aPSKc)[kSizePSKc]);
364 :
365 : /**
366 : * Removes the Pre-Shared Key for the Commissioner (PSKc) from the dataset.
367 : */
368 : void UnsetPSKc();
369 :
370 : /**
371 : * Sets the Channel Mask in the dataset. This value is a non-empty sequence of sub-TLVs as defined in the Thread specification.
372 : *
373 : * @retval CHIP_NO_ERROR on success.
374 : * @retval CHIP_ERROR_NO_MEMORY if there is insufficient space within the dataset.
375 : */
376 : CHIP_ERROR SetChannelMask(ByteSpan aChannelMask);
377 :
378 : /**
379 : * Sets the Security Policy in the dataset.
380 : *
381 : * @retval CHIP_NO_ERROR on success.
382 : * @retval CHIP_ERROR_NO_MEMORY if there is insufficient space within the dataset.
383 : */
384 : CHIP_ERROR SetSecurityPolicy(uint32_t aSecurityPolicy);
385 :
386 : /**
387 : * Sets the Delay Timer value in the dataset.
388 : *
389 : * @retval CHIP_NO_ERROR on success.
390 : * @retval CHIP_ERROR_NO_MEMORY if there is insufficient space within the dataset.
391 : */
392 : CHIP_ERROR SetDelayTimer(uint32_t aDelayMillis);
393 :
394 : /**
395 : * This method clears all data stored in the dataset.
396 : */
397 2 : void Clear() { mData = ByteSpan(mBuffer, 0); }
398 :
399 : /**
400 : * Returns a ByteSpan view of the current state of the dataset.
401 : * The byte span is only valid as long the OperationalDataset object is alive and not modified.
402 : */
403 19 : ByteSpan AsByteSpan() const { return this->OperationalDatasetView::AsByteSpan(); }
404 :
405 : private:
406 : uint8_t mBuffer[kSizeOperationalDataset];
407 :
408 : void CopyData();
409 : void CopyDataIfNecessary();
410 : void Remove(uint8_t aType);
411 : void Remove(ThreadTLV * aTlv);
412 : ThreadTLV * InsertOrReplace(uint8_t aType, size_t aValueSize);
413 : };
414 :
415 : } // namespace Thread
416 : } // namespace chip
|