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 includes definitions for MeshCoP.
32 *
33 */
34
35 #ifndef MESHCOP_HPP_
36 #define MESHCOP_HPP_
37
38 #include "openthread-core-config.h"
39
40 #include <limits.h>
41
42 #include <openthread/commissioner.h>
43 #include <openthread/instance.h>
44 #include <openthread/joiner.h>
45
46 #include "coap/coap.hpp"
47 #include "common/as_core_type.hpp"
48 #include "common/clearable.hpp"
49 #include "common/equatable.hpp"
50 #include "common/log.hpp"
51 #include "common/message.hpp"
52 #include "common/string.hpp"
53 #include "mac/mac_types.hpp"
54 #include "meshcop/meshcop_tlvs.hpp"
55
56 namespace ot {
57
58 class ThreadNetif;
59
60 namespace MeshCoP {
61
62 /**
63 * Represents a Joiner PSKd.
64 *
65 */
66 class JoinerPskd : public otJoinerPskd, public Clearable<JoinerPskd>, public Unequatable<JoinerPskd>
67 {
68 public:
69 static constexpr uint8_t kMinLength = 6; ///< Min PSKd string length (excludes null char)
70 static constexpr uint8_t kMaxLength = OT_JOINER_MAX_PSKD_LENGTH; ///< Max PSKd string length (excludes null char)
71
72 /**
73 * Indicates whether the PSKd if well-formed and valid.
74 *
75 * Per Thread specification, a Joining Device Credential is encoded as uppercase alphanumeric characters
76 * (base32-thread: 0-9, A-Z excluding I, O, Q, and Z for readability) with a minimum length of 6 such characters
77 * and a maximum length of 32 such characters.
78 *
79 * @returns TRUE if the PSKd is valid, FALSE otherwise.
80 *
81 */
IsValid(void) const82 bool IsValid(void) const { return IsPskdValid(m8); }
83
84 /**
85 * Sets the joiner PSKd from a given C string.
86 *
87 * @param[in] aPskdString A pointer to the PSKd C string array.
88 *
89 * @retval kErrorNone The PSKd was updated successfully.
90 * @retval kErrorInvalidArgs The given PSKd C string is not valid.
91 *
92 */
93 Error SetFrom(const char *aPskdString);
94
95 /**
96 * Gets the PSKd as a null terminated C string.
97 *
98 * Must be used after the PSKd is validated, otherwise its behavior is undefined.
99 *
100 * @returns The PSKd as a C string.
101 *
102 */
GetAsCString(void) const103 const char *GetAsCString(void) const { return m8; }
104
105 /**
106 * Gets the PSKd string length.
107 *
108 * Must be used after the PSKd is validated, otherwise its behavior is undefined.
109 *
110 * @returns The PSKd string length.
111 *
112 */
GetLength(void) const113 uint8_t GetLength(void) const { return static_cast<uint8_t>(StringLength(m8, kMaxLength + 1)); }
114
115 /**
116 * Overloads operator `==` to evaluate whether or not two PSKds are equal.
117 *
118 * @param[in] aOther The other PSKd to compare with.
119 *
120 * @retval TRUE If the two are equal.
121 * @retval FALSE If the two are not equal.
122 *
123 */
124 bool operator==(const JoinerPskd &aOther) const;
125
126 /**
127 * Indicates whether a given PSKd string if well-formed and valid.
128 *
129 * @param[in] aPskdString A pointer to a PSKd string array.
130 *
131 * @sa IsValid()
132 *
133 * @returns TRUE if @p aPskdString is valid, FALSE otherwise.
134 *
135 */
136 static bool IsPskdValid(const char *aPskdString);
137 };
138
139 /**
140 * Represents a Joiner Discerner.
141 *
142 */
143 class JoinerDiscerner : public otJoinerDiscerner, public Unequatable<JoinerDiscerner>
144 {
145 friend class SteeringData;
146
147 public:
148 static constexpr uint8_t kMaxLength = OT_JOINER_MAX_DISCERNER_LENGTH; ///< Max length of a Discerner in bits.
149
150 static constexpr uint16_t kInfoStringSize = 45; ///< Size of `InfoString` to use with `ToString()
151
152 /**
153 * Defines the fixed-length `String` object returned from `ToString()`.
154 *
155 */
156 typedef String<kInfoStringSize> InfoString;
157
158 /**
159 * Clears the Joiner Discerner.
160 *
161 */
Clear(void)162 void Clear(void) { mLength = 0; }
163
164 /**
165 * Indicates whether the Joiner Discerner is empty (no value set).
166 *
167 * @returns TRUE if empty, FALSE otherwise.
168 *
169 */
IsEmpty(void) const170 bool IsEmpty(void) const { return mLength == 0; }
171
172 /**
173 * Gets the Joiner Discerner's value.
174 *
175 * @returns The Joiner Discerner value.
176 *
177 */
GetValue(void) const178 uint64_t GetValue(void) const { return mValue; }
179
180 /**
181 * Gets the Joiner Discerner's length (in bits).
182 *
183 * @return The Joiner Discerner length.
184 *
185 */
GetLength(void) const186 uint8_t GetLength(void) const { return mLength; }
187
188 /**
189 * Indicates whether the Joiner Discerner is valid (i.e. it not empty and its length is within
190 * valid range).
191 *
192 * @returns TRUE if Joiner Discerner is valid, FALSE otherwise.
193 *
194 */
IsValid(void) const195 bool IsValid(void) const { return (0 < mLength) && (mLength <= kMaxLength); }
196
197 /**
198 * Generates a Joiner ID from the Discerner.
199 *
200 * @param[out] aJoinerId A reference to `Mac::ExtAddress` to output the generated Joiner ID.
201 *
202 */
203 void GenerateJoinerId(Mac::ExtAddress &aJoinerId) const;
204
205 /**
206 * Indicates whether a given Joiner ID matches the Discerner.
207 *
208 * @param[in] aJoinerId A Joiner ID to match with the Discerner.
209 *
210 * @returns TRUE if the Joiner ID matches the Discerner, FALSE otherwise.
211 *
212 */
213 bool Matches(const Mac::ExtAddress &aJoinerId) const;
214
215 /**
216 * Overloads operator `==` to evaluate whether or not two Joiner Discerner instances are equal.
217 *
218 * @param[in] aOther The other Joiner Discerner to compare with.
219 *
220 * @retval TRUE If the two are equal.
221 * @retval FALSE If the two are not equal.
222 *
223 */
224 bool operator==(const JoinerDiscerner &aOther) const;
225
226 /**
227 * Converts the Joiner Discerner to a string.
228 *
229 * @returns An `InfoString` representation of Joiner Discerner.
230 *
231 */
232 InfoString ToString(void) const;
233
234 private:
GetMask(void) const235 uint64_t GetMask(void) const { return (static_cast<uint64_t>(1ULL) << mLength) - 1; }
236 void CopyTo(Mac::ExtAddress &aExtAddress) const;
237 };
238
239 /**
240 * Represents Steering Data (bloom filter).
241 *
242 */
243 class SteeringData : public otSteeringData
244 {
245 public:
246 static constexpr uint8_t kMaxLength = OT_STEERING_DATA_MAX_LENGTH; ///< Maximum Steering Data length (in bytes).
247
248 /**
249 * Represents the hash bit index values for the bloom filter calculated from a Joiner ID.
250 *
251 * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
252 *
253 */
254 struct HashBitIndexes
255 {
256 static constexpr uint8_t kNumIndexes = 2; ///< Number of hash bit indexes.
257
258 uint16_t mIndex[kNumIndexes]; ///< The hash bit index array.
259 };
260
261 /**
262 * Initializes the Steering Data and clears the bloom filter.
263 *
264 * @param[in] aLength The Steering Data length (in bytes) - MUST be smaller than or equal to `kMaxLength`.
265 *
266 */
267 void Init(uint8_t aLength = kMaxLength);
268
269 /**
270 * Clears the bloom filter (all bits are cleared and no Joiner Id is accepted)..
271 *
272 * The Steering Data length (bloom filter length) is set to one byte with all bits cleared.
273 *
274 */
Clear(void)275 void Clear(void) { Init(1); }
276
277 /**
278 * Sets the bloom filter to permit all Joiner IDs.
279 *
280 * To permit all Joiner IDs, The Steering Data length (bloom filter length) is set to one byte with all bits set.
281 *
282 */
283 void SetToPermitAllJoiners(void);
284
285 /**
286 * Returns the Steering Data length (in bytes).
287 *
288 * @returns The Steering Data length (in bytes).
289 *
290 */
GetLength(void) const291 uint8_t GetLength(void) const { return mLength; }
292
293 /**
294 * Gets the Steering Data buffer (bloom filter).
295 *
296 * @returns A pointer to the Steering Data buffer.
297 *
298 */
GetData(void) const299 const uint8_t *GetData(void) const { return m8; }
300
301 /**
302 * Gets the Steering Data buffer (bloom filter).
303 *
304 * @returns A pointer to the Steering Data buffer.
305 *
306 */
GetData(void)307 uint8_t *GetData(void) { return m8; }
308
309 /**
310 * Updates the bloom filter adding the given Joiner ID.
311 *
312 * @param[in] aJoinerId The Joiner ID to add to bloom filter.
313 *
314 */
315 void UpdateBloomFilter(const Mac::ExtAddress &aJoinerId);
316
317 /**
318 * Updates the bloom filter adding a given Joiner Discerner.
319 *
320 * @param[in] aDiscerner The Joiner Discerner to add to bloom filter.
321 *
322 */
323 void UpdateBloomFilter(const JoinerDiscerner &aDiscerner);
324
325 /**
326 * Indicates whether the bloom filter is empty (all the bits are cleared).
327 *
328 * @returns TRUE if the bloom filter is empty, FALSE otherwise.
329 *
330 */
IsEmpty(void) const331 bool IsEmpty(void) const { return DoesAllMatch(0); }
332
333 /**
334 * Indicates whether the bloom filter permits all Joiner IDs (all the bits are set).
335 *
336 * @returns TRUE if the bloom filter permits all Joiners IDs, FALSE otherwise.
337 *
338 */
PermitsAllJoiners(void) const339 bool PermitsAllJoiners(void) const { return (mLength > 0) && DoesAllMatch(kPermitAll); }
340
341 /**
342 * Indicates whether the bloom filter contains a given Joiner ID.
343 *
344 * @param[in] aJoinerId A Joiner ID.
345 *
346 * @returns TRUE if the bloom filter contains @p aJoinerId, FALSE otherwise.
347 *
348 */
349 bool Contains(const Mac::ExtAddress &aJoinerId) const;
350
351 /**
352 * Indicates whether the bloom filter contains a given Joiner Discerner.
353 *
354 * @param[in] aDiscerner A Joiner Discerner.
355 *
356 * @returns TRUE if the bloom filter contains @p aDiscerner, FALSE otherwise.
357 *
358 */
359 bool Contains(const JoinerDiscerner &aDiscerner) const;
360
361 /**
362 * Indicates whether the bloom filter contains the hash bit indexes (derived from a Joiner ID).
363 *
364 * @param[in] aIndexes A hash bit index structure (derived from a Joiner ID).
365 *
366 * @returns TRUE if the bloom filter contains the Joiner ID mapping to @p aIndexes, FALSE otherwise.
367 *
368 */
369 bool Contains(const HashBitIndexes &aIndexes) const;
370
371 /**
372 * Calculates the bloom filter hash bit indexes from a given Joiner ID.
373 *
374 * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
375 *
376 * @param[in] aJoinerId The Joiner ID to calculate the hash bit indexes.
377 * @param[out] aIndexes A reference to a `HashBitIndexes` structure to output the calculated index values.
378 *
379 */
380 static void CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes);
381
382 /**
383 * Calculates the bloom filter hash bit indexes from a given Joiner Discerner.
384 *
385 * The first hash bit index is derived using CRC16-CCITT and second one using CRC16-ANSI.
386 *
387 * @param[in] aDiscerner The Joiner Discerner to calculate the hash bit indexes.
388 * @param[out] aIndexes A reference to a `HashBitIndexes` structure to output the calculated index values.
389 *
390 */
391 static void CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, HashBitIndexes &aIndexes);
392
393 private:
394 static constexpr uint8_t kPermitAll = 0xff;
395
GetNumBits(void) const396 uint8_t GetNumBits(void) const { return (mLength * CHAR_BIT); }
397
BitIndex(uint8_t aBit) const398 uint8_t BitIndex(uint8_t aBit) const { return (mLength - 1 - (aBit / CHAR_BIT)); }
BitFlag(uint8_t aBit) const399 uint8_t BitFlag(uint8_t aBit) const { return static_cast<uint8_t>(1U << (aBit % CHAR_BIT)); }
400
GetBit(uint8_t aBit) const401 bool GetBit(uint8_t aBit) const { return (m8[BitIndex(aBit)] & BitFlag(aBit)) != 0; }
SetBit(uint8_t aBit)402 void SetBit(uint8_t aBit) { m8[BitIndex(aBit)] |= BitFlag(aBit); }
ClearBit(uint8_t aBit)403 void ClearBit(uint8_t aBit) { m8[BitIndex(aBit)] &= ~BitFlag(aBit); }
404
405 bool DoesAllMatch(uint8_t aMatch) const;
406 void UpdateBloomFilter(const HashBitIndexes &aIndexes);
407 };
408
409 /**
410 * Generates PSKc.
411 *
412 * PSKc is used to establish the Commissioner Session.
413 *
414 * @param[in] aPassPhrase The commissioning passphrase.
415 * @param[in] aNetworkName The network name for PSKc computation.
416 * @param[in] aExtPanId The extended PAN ID for PSKc computation.
417 * @param[out] aPskc A reference to a PSKc where the generated PSKc will be placed.
418 *
419 * @retval kErrorNone Successfully generate PSKc.
420 * @retval kErrorInvalidArgs If the length of passphrase is out of range.
421 *
422 */
423 Error GeneratePskc(const char *aPassPhrase,
424 const NetworkName &aNetworkName,
425 const ExtendedPanId &aExtPanId,
426 Pskc &aPskc);
427
428 /**
429 * Computes the Joiner ID from a factory-assigned IEEE EUI-64.
430 *
431 * @param[in] aEui64 The factory-assigned IEEE EUI-64.
432 * @param[out] aJoinerId The Joiner ID.
433 *
434 */
435 void ComputeJoinerId(const Mac::ExtAddress &aEui64, Mac::ExtAddress &aJoinerId);
436
437 /**
438 * Gets the border agent RLOC.
439 *
440 * @param[in] aNetIf A reference to the thread interface.
441 * @param[out] aRloc Border agent RLOC.
442 *
443 * @retval kErrorNone Successfully got the Border Agent Rloc.
444 * @retval kErrorNotFound Border agent is not available.
445 *
446 */
447 Error GetBorderAgentRloc(ThreadNetif &aNetIf, uint16_t &aRloc);
448
449 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
450 /**
451 * Emits a log message indicating an error during a MeshCoP action.
452 *
453 * Note that log message is emitted only if there is an error, i.e. @p aError is not `kErrorNone`. The log
454 * message will have the format "Failed to {aActionText} : {ErrorString}".
455 *
456 * @param[in] aActionText A string representing the failed action.
457 * @param[in] aError The error in sending the message.
458 *
459 */
460 void LogError(const char *aActionText, Error aError);
461 #else
LogError(const char *,Error)462 inline void LogError(const char *, Error) {}
463 #endif
464
465 } // namespace MeshCoP
466
467 DefineCoreType(otJoinerPskd, MeshCoP::JoinerPskd);
468 DefineCoreType(otJoinerDiscerner, MeshCoP::JoinerDiscerner);
469 DefineCoreType(otSteeringData, MeshCoP::SteeringData);
470
471 } // namespace ot
472
473 #endif // MESHCOP_HPP_
474